@mintjamsinc/ichigojs 0.1.21 → 0.1.23
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/README.md +45 -0
- package/dist/ichigo.esm.js +149 -17
- package/dist/ichigo.esm.js.map +1 -1
- package/dist/ichigo.esm.min.js +1 -2
- package/dist/ichigo.esm.min.js.map +1 -1
- package/dist/ichigo.umd.js +149 -16
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -2
- package/dist/ichigo.umd.min.js.map +1 -1
- package/dist/types/ichigo/VApplication.d.ts +16 -5
- package/dist/types/ichigo/VApplicationInit.d.ts +25 -0
- package/dist/types/ichigo/VBindings.d.ts +7 -0
- package/dist/types/ichigo/util/ReactiveProxy.d.ts +29 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/ichigo.umd.js
CHANGED
|
@@ -7423,6 +7423,16 @@
|
|
|
7423
7423
|
* This prevents creating multiple proxies for the same object accessed from different paths.
|
|
7424
7424
|
*/
|
|
7425
7425
|
static proxyCache = new WeakMap();
|
|
7426
|
+
/**
|
|
7427
|
+
* A WeakMap to track which objects are proxies, mapping proxy -> original target.
|
|
7428
|
+
* This prevents double-wrapping of already proxied objects.
|
|
7429
|
+
*/
|
|
7430
|
+
static proxyToTarget = new WeakMap();
|
|
7431
|
+
/**
|
|
7432
|
+
* A WeakSet to track objects marked as "raw" (non-reactive).
|
|
7433
|
+
* These objects will not be wrapped with Proxy.
|
|
7434
|
+
*/
|
|
7435
|
+
static rawObjects = new WeakSet();
|
|
7426
7436
|
/**
|
|
7427
7437
|
* Creates a reactive proxy for the given object.
|
|
7428
7438
|
* The proxy will call the onChange callback whenever a property is modified.
|
|
@@ -7437,9 +7447,19 @@
|
|
|
7437
7447
|
if (typeof target !== 'object' || target === null) {
|
|
7438
7448
|
return target;
|
|
7439
7449
|
}
|
|
7450
|
+
// Don't wrap objects marked as raw (non-reactive)
|
|
7451
|
+
if (this.rawObjects.has(target)) {
|
|
7452
|
+
return target;
|
|
7453
|
+
}
|
|
7440
7454
|
// Don't wrap built-in objects that have internal slots
|
|
7441
7455
|
// These objects require their methods to be called with the correct 'this' context
|
|
7442
|
-
|
|
7456
|
+
// Use Object.prototype.toString for more reliable type checking
|
|
7457
|
+
const typeTag = Object.prototype.toString.call(target);
|
|
7458
|
+
if (typeTag === '[object Date]' || typeTag === '[object RegExp]' || typeTag === '[object Error]') {
|
|
7459
|
+
return target;
|
|
7460
|
+
}
|
|
7461
|
+
// Check if the target is already a proxy - if so, return it as-is to prevent double-wrapping
|
|
7462
|
+
if (this.proxyToTarget.has(target)) {
|
|
7443
7463
|
return target;
|
|
7444
7464
|
}
|
|
7445
7465
|
// Check if we already have a proxy for this target with this path
|
|
@@ -7460,8 +7480,14 @@
|
|
|
7460
7480
|
const value = Reflect.get(obj, key);
|
|
7461
7481
|
// If the value is an object or array, make it reactive too
|
|
7462
7482
|
if (typeof value === 'object' && value !== null) {
|
|
7483
|
+
// Don't wrap objects marked as raw (non-reactive)
|
|
7484
|
+
if (ReactiveProxy.rawObjects.has(value)) {
|
|
7485
|
+
return value;
|
|
7486
|
+
}
|
|
7463
7487
|
// Don't wrap built-in objects that have internal slots
|
|
7464
|
-
|
|
7488
|
+
// Use Object.prototype.toString for more reliable type checking
|
|
7489
|
+
const valueTypeTag = Object.prototype.toString.call(value);
|
|
7490
|
+
if (valueTypeTag === '[object Date]' || valueTypeTag === '[object RegExp]' || valueTypeTag === '[object Error]') {
|
|
7465
7491
|
return value;
|
|
7466
7492
|
}
|
|
7467
7493
|
// Build the nested path
|
|
@@ -7474,7 +7500,7 @@
|
|
|
7474
7500
|
const arrayMutationMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
|
|
7475
7501
|
if (arrayMutationMethods.includes(key)) {
|
|
7476
7502
|
return function (...args) {
|
|
7477
|
-
const result = value.apply(
|
|
7503
|
+
const result = value.apply(obj, args);
|
|
7478
7504
|
onChange(path || undefined);
|
|
7479
7505
|
return result;
|
|
7480
7506
|
};
|
|
@@ -7503,6 +7529,8 @@
|
|
|
7503
7529
|
});
|
|
7504
7530
|
// Cache the proxy for this path
|
|
7505
7531
|
pathMap.set(path, proxy);
|
|
7532
|
+
// Track that this proxy wraps the target to prevent double-wrapping
|
|
7533
|
+
this.proxyToTarget.set(proxy, target);
|
|
7506
7534
|
return proxy;
|
|
7507
7535
|
}
|
|
7508
7536
|
/**
|
|
@@ -7526,6 +7554,32 @@
|
|
|
7526
7554
|
// In a full implementation, we'd need to store a reverse mapping
|
|
7527
7555
|
return obj;
|
|
7528
7556
|
}
|
|
7557
|
+
/**
|
|
7558
|
+
* Marks an object as "raw" (non-reactive).
|
|
7559
|
+
* Objects marked as raw will not be wrapped with Proxy when accessed from reactive objects.
|
|
7560
|
+
* This is useful for objects that should not be reactive, such as:
|
|
7561
|
+
* - Objects with private fields (class instances with # fields)
|
|
7562
|
+
* - Third-party library instances
|
|
7563
|
+
* - Objects used only for method calls
|
|
7564
|
+
*
|
|
7565
|
+
* @param obj The object to mark as raw.
|
|
7566
|
+
* @returns The same object (for chaining).
|
|
7567
|
+
*/
|
|
7568
|
+
static markRaw(obj) {
|
|
7569
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
7570
|
+
this.rawObjects.add(obj);
|
|
7571
|
+
}
|
|
7572
|
+
return obj;
|
|
7573
|
+
}
|
|
7574
|
+
/**
|
|
7575
|
+
* Checks if an object is marked as raw (non-reactive).
|
|
7576
|
+
*
|
|
7577
|
+
* @param obj The object to check.
|
|
7578
|
+
* @returns True if the object is marked as raw, false otherwise.
|
|
7579
|
+
*/
|
|
7580
|
+
static isRaw(obj) {
|
|
7581
|
+
return typeof obj === 'object' && obj !== null && this.rawObjects.has(obj);
|
|
7582
|
+
}
|
|
7529
7583
|
}
|
|
7530
7584
|
|
|
7531
7585
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
|
@@ -7559,6 +7613,10 @@
|
|
|
7559
7613
|
* Cache for array lengths to detect length changes when the same object reference is used.
|
|
7560
7614
|
*/
|
|
7561
7615
|
#lengthCache = new Map();
|
|
7616
|
+
/**
|
|
7617
|
+
* Flag to suppress onChange callbacks temporarily.
|
|
7618
|
+
*/
|
|
7619
|
+
#suppressOnChange = false;
|
|
7562
7620
|
/**
|
|
7563
7621
|
* Creates a new instance of VBindings.
|
|
7564
7622
|
* @param parent The parent bindings, if any.
|
|
@@ -7597,7 +7655,9 @@
|
|
|
7597
7655
|
this.#logger?.debug(`Binding changed: ${path}`);
|
|
7598
7656
|
this.#changes.add(path);
|
|
7599
7657
|
}
|
|
7600
|
-
this.#
|
|
7658
|
+
if (!this.#suppressOnChange) {
|
|
7659
|
+
this.#onChange?.(changedPath);
|
|
7660
|
+
}
|
|
7601
7661
|
}, key);
|
|
7602
7662
|
}
|
|
7603
7663
|
const oldValue = Reflect.get(target, key);
|
|
@@ -7622,7 +7682,9 @@
|
|
|
7622
7682
|
this.#logger.debug(`Binding set on ${target === obj ? 'local' : 'parent'}: ${key}: ${oldValuePreview} -> ${newValuePreview}`);
|
|
7623
7683
|
}
|
|
7624
7684
|
this.#changes.add(key);
|
|
7625
|
-
this.#
|
|
7685
|
+
if (!this.#suppressOnChange) {
|
|
7686
|
+
this.#onChange?.(key);
|
|
7687
|
+
}
|
|
7626
7688
|
}
|
|
7627
7689
|
return result;
|
|
7628
7690
|
},
|
|
@@ -7709,6 +7771,21 @@
|
|
|
7709
7771
|
remove(key) {
|
|
7710
7772
|
delete this.#local[key];
|
|
7711
7773
|
}
|
|
7774
|
+
/**
|
|
7775
|
+
* Sets a binding value without triggering onChange callback.
|
|
7776
|
+
* This is useful for internal updates that shouldn't trigger reactivity.
|
|
7777
|
+
* @param key The binding name.
|
|
7778
|
+
* @param value The binding value.
|
|
7779
|
+
*/
|
|
7780
|
+
setSilent(key, value) {
|
|
7781
|
+
this.#suppressOnChange = true;
|
|
7782
|
+
try {
|
|
7783
|
+
this.#local[key] = value;
|
|
7784
|
+
}
|
|
7785
|
+
finally {
|
|
7786
|
+
this.#suppressOnChange = false;
|
|
7787
|
+
}
|
|
7788
|
+
}
|
|
7712
7789
|
}
|
|
7713
7790
|
|
|
7714
7791
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
|
@@ -9230,7 +9307,10 @@
|
|
|
9230
9307
|
vApplication: this.#vNode.vApplication,
|
|
9231
9308
|
parentVNode: this.#vNode.parentVNode,
|
|
9232
9309
|
bindings,
|
|
9233
|
-
dependentIdentifiers: [
|
|
9310
|
+
dependentIdentifiers: [
|
|
9311
|
+
`${this.#sourceName}[${context.index}]`,
|
|
9312
|
+
...this.#vNode.vApplication.resolveDependentIdentifiers(this.#sourceName, context.item)
|
|
9313
|
+
],
|
|
9234
9314
|
});
|
|
9235
9315
|
newRenderedItems.set(key, vNode);
|
|
9236
9316
|
vNode.forceUpdate();
|
|
@@ -11078,6 +11158,10 @@
|
|
|
11078
11158
|
* The application options.
|
|
11079
11159
|
*/
|
|
11080
11160
|
#options;
|
|
11161
|
+
/**
|
|
11162
|
+
* The parent application, if any.
|
|
11163
|
+
*/
|
|
11164
|
+
#parentApplication;
|
|
11081
11165
|
/**
|
|
11082
11166
|
* The global directive parser registry.
|
|
11083
11167
|
*/
|
|
@@ -11116,12 +11200,12 @@
|
|
|
11116
11200
|
#updateScheduled = false;
|
|
11117
11201
|
/**
|
|
11118
11202
|
* Creates an instance of the virtual application.
|
|
11119
|
-
* @param
|
|
11120
|
-
* @param directiveParserRegistry The global directive parser registry.
|
|
11121
|
-
* @param componentRegistry The global component registry.
|
|
11203
|
+
* @param args The initialization arguments for the application.
|
|
11122
11204
|
*/
|
|
11123
|
-
constructor(
|
|
11205
|
+
constructor(args) {
|
|
11206
|
+
const { options, parentApplication: parentApplication, directiveParserRegistry, componentRegistry } = args;
|
|
11124
11207
|
this.#options = options;
|
|
11208
|
+
this.#parentApplication = parentApplication;
|
|
11125
11209
|
this.#directiveParserRegistry = directiveParserRegistry;
|
|
11126
11210
|
this.#componentRegistry = componentRegistry;
|
|
11127
11211
|
// Initialize log manager and logger
|
|
@@ -11134,6 +11218,12 @@
|
|
|
11134
11218
|
// Initialize bindings from data, computed, and methods
|
|
11135
11219
|
this.#initializeBindings();
|
|
11136
11220
|
}
|
|
11221
|
+
/**
|
|
11222
|
+
* Gets the parent application, if any.
|
|
11223
|
+
*/
|
|
11224
|
+
get parentApplication() {
|
|
11225
|
+
return this.#parentApplication;
|
|
11226
|
+
}
|
|
11137
11227
|
/**
|
|
11138
11228
|
* Gets the global directive parser registry.
|
|
11139
11229
|
*/
|
|
@@ -11213,7 +11303,12 @@
|
|
|
11213
11303
|
* @returns The created child application instance.
|
|
11214
11304
|
*/
|
|
11215
11305
|
createChildApp(options) {
|
|
11216
|
-
return new VApplication(
|
|
11306
|
+
return new VApplication({
|
|
11307
|
+
options,
|
|
11308
|
+
parentApplication: this,
|
|
11309
|
+
directiveParserRegistry: this.#directiveParserRegistry,
|
|
11310
|
+
componentRegistry: this.#componentRegistry
|
|
11311
|
+
});
|
|
11217
11312
|
}
|
|
11218
11313
|
/**
|
|
11219
11314
|
* Cleans the element by removing unnecessary whitespace text nodes.
|
|
@@ -11245,6 +11340,26 @@
|
|
|
11245
11340
|
}
|
|
11246
11341
|
}
|
|
11247
11342
|
}
|
|
11343
|
+
/**
|
|
11344
|
+
* Computes dependent identifiers for a given computed property and value.
|
|
11345
|
+
* This is used to track dependencies in directives like v-for.
|
|
11346
|
+
* @param computedName The name of the computed property.
|
|
11347
|
+
* @param value The value to check for dependencies.
|
|
11348
|
+
* @returns An array of dependent identifiers.
|
|
11349
|
+
*/
|
|
11350
|
+
resolveDependentIdentifiers(computedName, value) {
|
|
11351
|
+
const identifiers = [];
|
|
11352
|
+
for (const dep of this.#computedDependencies[computedName] || []) {
|
|
11353
|
+
const depValue = this.#bindings?.get(dep);
|
|
11354
|
+
if (Array.isArray(depValue)) {
|
|
11355
|
+
const idx = depValue.indexOf(value);
|
|
11356
|
+
if (idx !== -1) {
|
|
11357
|
+
identifiers.push(`${dep}[${idx}]`);
|
|
11358
|
+
}
|
|
11359
|
+
}
|
|
11360
|
+
}
|
|
11361
|
+
return identifiers;
|
|
11362
|
+
}
|
|
11248
11363
|
/**
|
|
11249
11364
|
* Initializes bindings from data, computed properties, and methods.
|
|
11250
11365
|
* @returns The initialized bindings object.
|
|
@@ -11259,6 +11374,7 @@
|
|
|
11259
11374
|
});
|
|
11260
11375
|
// Inject utility methods into bindings
|
|
11261
11376
|
this.#bindings.set('$nextTick', (callback) => this.#nextTick(callback));
|
|
11377
|
+
this.#bindings.set('$markRaw', (obj) => ReactiveProxy.markRaw(obj));
|
|
11262
11378
|
// Add methods
|
|
11263
11379
|
if (this.#options.methods) {
|
|
11264
11380
|
for (const [key, method] of Object.entries(this.#options.methods)) {
|
|
@@ -11273,7 +11389,13 @@
|
|
|
11273
11389
|
}
|
|
11274
11390
|
// Add data properties
|
|
11275
11391
|
if (this.#options.data) {
|
|
11276
|
-
|
|
11392
|
+
// Create a $ctx context object with utility functions for data()
|
|
11393
|
+
// This provides the same $markRaw access as in lifecycle hooks (@mount, etc.)
|
|
11394
|
+
const $ctx = {
|
|
11395
|
+
$markRaw: (obj) => ReactiveProxy.markRaw(obj)
|
|
11396
|
+
};
|
|
11397
|
+
// Call data() with $ctx as 'this'
|
|
11398
|
+
const data = this.#options.data.call($ctx);
|
|
11277
11399
|
if (data && typeof data === 'object') {
|
|
11278
11400
|
for (const [key, value] of Object.entries(data)) {
|
|
11279
11401
|
this.#bindings.set(key, value);
|
|
@@ -11356,9 +11478,15 @@
|
|
|
11356
11478
|
try {
|
|
11357
11479
|
const oldValue = this.#bindings?.get(key);
|
|
11358
11480
|
const newValue = computedFn.call(this.#bindings?.raw);
|
|
11359
|
-
//
|
|
11360
|
-
|
|
11361
|
-
|
|
11481
|
+
// Check if the value actually changed
|
|
11482
|
+
let hasChanged = oldValue !== newValue;
|
|
11483
|
+
// For arrays, always update (VBindings will detect length changes via its length cache)
|
|
11484
|
+
if (!hasChanged && Array.isArray(newValue)) {
|
|
11485
|
+
hasChanged = true;
|
|
11486
|
+
}
|
|
11487
|
+
if (hasChanged) {
|
|
11488
|
+
// Use setSilent to avoid triggering onChange during computed property updates
|
|
11489
|
+
this.#bindings?.setSilent(key, newValue);
|
|
11362
11490
|
allChanges.add(key);
|
|
11363
11491
|
}
|
|
11364
11492
|
}
|
|
@@ -11447,10 +11575,15 @@
|
|
|
11447
11575
|
* @returns The created virtual application instance.
|
|
11448
11576
|
*/
|
|
11449
11577
|
static createApp(options) {
|
|
11450
|
-
return new VApplication(
|
|
11578
|
+
return new VApplication({
|
|
11579
|
+
options,
|
|
11580
|
+
directiveParserRegistry: this.#directiveParserRegistry,
|
|
11581
|
+
componentRegistry: this.#componentRegistry
|
|
11582
|
+
});
|
|
11451
11583
|
}
|
|
11452
11584
|
}
|
|
11453
11585
|
|
|
11586
|
+
exports.ReactiveProxy = ReactiveProxy;
|
|
11454
11587
|
exports.VComponent = VComponent;
|
|
11455
11588
|
exports.VComponentRegistry = VComponentRegistry;
|
|
11456
11589
|
exports.VDOM = VDOM;
|