@mintjamsinc/ichigojs 0.1.7 → 0.1.9
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 +72 -4
- package/dist/ichigo.esm.js +339 -9
- package/dist/ichigo.esm.js.map +1 -1
- package/dist/ichigo.esm.min.js +1 -1
- package/dist/ichigo.esm.min.js.map +1 -1
- package/dist/ichigo.umd.js +339 -9
- package/dist/ichigo.umd.js.map +1 -1
- package/dist/ichigo.umd.min.js +1 -1
- package/dist/ichigo.umd.min.js.map +1 -1
- package/dist/types/ichigo/directives/StandardDirectiveName.d.ts +15 -1
- package/dist/types/ichigo/directives/VBindDirective.d.ts +9 -0
- package/dist/types/ichigo/directives/VConditionalDirective.d.ts +5 -0
- package/dist/types/ichigo/directives/VDirectiveManager.d.ts +18 -0
- package/dist/types/ichigo/directives/VDirectiveParserRegistry.d.ts +4 -0
- package/dist/types/ichigo/directives/VIntersectionDirective.d.ts +91 -0
- package/dist/types/ichigo/directives/VOnDirective.d.ts +1 -1
- package/dist/types/ichigo/directives/VPerformanceDirective.d.ts +105 -0
- package/dist/types/ichigo/directives/VResizeDirective.d.ts +5 -0
- package/dist/types/ichigo/util/ExpressionUtils.d.ts +3 -0
- package/dist/types/ichigo/util/LogLevel.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -16,8 +16,9 @@ A simple and intuitive reactive framework. Lightweight, fast, and user-friendly
|
|
16
16
|
- 📦 **Lightweight** - Minimal bundle size
|
17
17
|
- 🚀 **High Performance** - Efficient batched updates via microtask queue
|
18
18
|
- 💪 **TypeScript** - Written in TypeScript with full type support
|
19
|
-
- 🎨 **Directives** - `v-if`, `v-for`, `v-show`, `v-bind`, `v-on`, `v-model`, `v-resize`
|
19
|
+
- 🎨 **Directives** - `v-if`, `v-for`, `v-show`, `v-bind`, `v-on`, `v-model`, `v-resize`, `v-intersection`
|
20
20
|
- 📐 **Resize Observer** - Monitor element size changes with `v-resize` directive
|
21
|
+
- 👁️ **Intersection Observer** - Detect element visibility with `v-intersection` directive
|
21
22
|
|
22
23
|
## Installation
|
23
24
|
|
@@ -199,9 +200,76 @@ methods: {
|
|
199
200
|
}
|
200
201
|
```
|
201
202
|
|
203
|
+
**With custom options:**
|
204
|
+
|
205
|
+
```html
|
206
|
+
<div v-resize="onResize"
|
207
|
+
:options.resize="{box: 'border-box'}">
|
208
|
+
Observe border-box dimensions
|
209
|
+
</div>
|
210
|
+
```
|
211
|
+
|
212
|
+
You can also use `:options` for generic options:
|
213
|
+
|
214
|
+
```html
|
215
|
+
<div v-resize="onResize"
|
216
|
+
:options="{box: 'content-box'}">
|
217
|
+
Resizable content
|
218
|
+
</div>
|
219
|
+
```
|
220
|
+
|
202
221
|
**Features:**
|
203
222
|
- Native ResizeObserver API for efficient resize detection
|
204
|
-
-
|
223
|
+
- Custom box model via `:options.resize` or `:options`
|
224
|
+
- Automatic cleanup in destroy phase
|
225
|
+
- Access to element, VNode, and userData via `$ctx`
|
226
|
+
|
227
|
+
#### v-intersection
|
228
|
+
|
229
|
+
Detect element visibility using IntersectionObserver:
|
230
|
+
|
231
|
+
```html
|
232
|
+
<div v-intersection="onIntersection" class="observable-box">
|
233
|
+
I'm {{ isVisible ? 'VISIBLE' : 'NOT VISIBLE' }}
|
234
|
+
</div>
|
235
|
+
```
|
236
|
+
|
237
|
+
```javascript
|
238
|
+
methods: {
|
239
|
+
onIntersection(entries, $ctx) {
|
240
|
+
const entry = entries[0];
|
241
|
+
this.isVisible = entry.isIntersecting;
|
242
|
+
this.intersectionRatio = entry.intersectionRatio;
|
243
|
+
|
244
|
+
// Access element through $ctx
|
245
|
+
console.log('Element:', $ctx.element);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
```
|
249
|
+
|
250
|
+
**With custom options:**
|
251
|
+
|
252
|
+
```html
|
253
|
+
<div v-intersection="onIntersection"
|
254
|
+
:options.intersection="{threshold: 0.5, rootMargin: '0px'}">
|
255
|
+
Triggers at 50% visibility
|
256
|
+
</div>
|
257
|
+
```
|
258
|
+
|
259
|
+
You can also use `:options` for generic options:
|
260
|
+
|
261
|
+
```html
|
262
|
+
<div v-intersection="onIntersection"
|
263
|
+
:options="{threshold: 0.5}">
|
264
|
+
Observable content
|
265
|
+
</div>
|
266
|
+
```
|
267
|
+
|
268
|
+
**Features:**
|
269
|
+
- Native IntersectionObserver API for efficient visibility detection
|
270
|
+
- Custom threshold and rootMargin options via `:options.intersection` or `:options`
|
271
|
+
- Automatic cleanup in destroy phase
|
272
|
+
- Perfect for lazy loading, infinite scroll, and animation triggers
|
205
273
|
- Access to element, VNode, and userData via `$ctx`
|
206
274
|
|
207
275
|
#### Lifecycle Hooks
|
@@ -226,7 +294,7 @@ Lifecycle hooks allow you to run code at specific stages of an element's lifecyc
|
|
226
294
|
- `@mounted` - Called after the element is inserted into the DOM
|
227
295
|
- `@update` - Called before the element is updated
|
228
296
|
- `@updated` - Called after the element is updated
|
229
|
-
- `@unmount` - Called before
|
297
|
+
- `@unmount` - Called before VNode cleanup begins
|
230
298
|
- `@unmounted` - Called after VNode cleanup is complete (element reference still available)
|
231
299
|
|
232
300
|
**Lifecycle Context (`$ctx`):**
|
@@ -292,7 +360,7 @@ methods: {
|
|
292
360
|
};
|
293
361
|
|
294
362
|
$ctx.userData.set('myResource', resource);
|
295
|
-
// resource.close() will be called automatically
|
363
|
+
// resource.close() will be called automatically during destroy phase
|
296
364
|
}
|
297
365
|
}
|
298
366
|
```
|
package/dist/ichigo.esm.js
CHANGED
@@ -3,6 +3,10 @@ class VComponentRegistry {
|
|
3
3
|
}
|
4
4
|
|
5
5
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
6
|
+
/**
|
7
|
+
* Registry for managing directive parsers.
|
8
|
+
* This class allows registering, unregistering, and finding directive parsers.
|
9
|
+
*/
|
6
10
|
class VDirectiveParserRegistry {
|
7
11
|
/**
|
8
12
|
* The list of registered directive parsers.
|
@@ -43,17 +47,31 @@ class VDirectiveParserRegistry {
|
|
43
47
|
}
|
44
48
|
|
45
49
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
50
|
+
/**
|
51
|
+
* Standard directive names used in the framework.
|
52
|
+
*/
|
46
53
|
var StandardDirectiveName;
|
47
54
|
(function (StandardDirectiveName) {
|
55
|
+
/** Conditional rendering directives (if). */
|
48
56
|
StandardDirectiveName["V_IF"] = "v-if";
|
57
|
+
/** Conditional rendering directives (else if). */
|
49
58
|
StandardDirectiveName["V_ELSE_IF"] = "v-else-if";
|
59
|
+
/** Conditional rendering directives (else). */
|
50
60
|
StandardDirectiveName["V_ELSE"] = "v-else";
|
61
|
+
/** Conditional rendering directives (show). */
|
51
62
|
StandardDirectiveName["V_SHOW"] = "v-show";
|
63
|
+
/** List rendering directives. */
|
52
64
|
StandardDirectiveName["V_FOR"] = "v-for";
|
65
|
+
/** Event handling directives. */
|
53
66
|
StandardDirectiveName["V_ON"] = "v-on";
|
67
|
+
/** Attribute binding directives. */
|
54
68
|
StandardDirectiveName["V_BIND"] = "v-bind";
|
69
|
+
/** Two-way data binding directives. */
|
55
70
|
StandardDirectiveName["V_MODEL"] = "v-model";
|
71
|
+
/** Slot content insertion directives. */
|
56
72
|
StandardDirectiveName["V_RESIZE"] = "v-resize";
|
73
|
+
/** Intersection observer directives. */
|
74
|
+
StandardDirectiveName["V_INTERSECTION"] = "v-intersection";
|
57
75
|
})(StandardDirectiveName || (StandardDirectiveName = {}));
|
58
76
|
|
59
77
|
// This file was generated. Do not modify manually!
|
@@ -6574,6 +6592,9 @@ base.MethodDefinition = base.PropertyDefinition = base.Property = function (node
|
|
6574
6592
|
};
|
6575
6593
|
|
6576
6594
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
6595
|
+
/**
|
6596
|
+
* Utility class for analyzing JavaScript expressions to extract variable and function dependencies.
|
6597
|
+
*/
|
6577
6598
|
class ExpressionUtils {
|
6578
6599
|
/**
|
6579
6600
|
* Extracts variable and function names used in the expression.
|
@@ -6868,6 +6889,19 @@ class VBindDirective {
|
|
6868
6889
|
get isKey() {
|
6869
6890
|
return (this.#attributeName === 'key');
|
6870
6891
|
}
|
6892
|
+
/**
|
6893
|
+
* Indicates if this directive is binding the "options" attribute or any of its sub-properties (e.g., "options.intersection").
|
6894
|
+
* The "options" attribute is special and is used for passing options to certain directives like VIntersectionDirective.
|
6895
|
+
*/
|
6896
|
+
get isOptions() {
|
6897
|
+
return (this.#attributeName === 'options' || this.#attributeName?.startsWith('options.') === true);
|
6898
|
+
}
|
6899
|
+
/**
|
6900
|
+
* Gets the name of the attribute being bound (e.g., "src", "class", "options", "options.intersection").
|
6901
|
+
*/
|
6902
|
+
get attributeName() {
|
6903
|
+
return this.#attributeName;
|
6904
|
+
}
|
6871
6905
|
/**
|
6872
6906
|
* Gets the original expression string from the directive.
|
6873
6907
|
*/
|
@@ -6920,8 +6954,8 @@ class VBindDirective {
|
|
6920
6954
|
* Renders the bound attribute by evaluating the expression and updating the DOM element.
|
6921
6955
|
*/
|
6922
6956
|
#render() {
|
6923
|
-
//
|
6924
|
-
if (this.isKey) {
|
6957
|
+
// Do nothing for special attributes
|
6958
|
+
if (this.isKey || this.isOptions) {
|
6925
6959
|
return;
|
6926
6960
|
}
|
6927
6961
|
const element = this.#vNode.node;
|
@@ -7365,16 +7399,47 @@ class VBindings {
|
|
7365
7399
|
}
|
7366
7400
|
|
7367
7401
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
7402
|
+
/**
|
7403
|
+
* Manages directives associated with a virtual node (VNode).
|
7404
|
+
* This class is responsible for parsing, storing, and managing the lifecycle of directives.
|
7405
|
+
* It also provides access to bindings preparers and DOM updaters from the associated directives.
|
7406
|
+
*/
|
7368
7407
|
class VDirectiveManager {
|
7369
7408
|
/**
|
7370
7409
|
* The virtual node to which this directive handler is associated.
|
7371
7410
|
*/
|
7372
7411
|
#vNode;
|
7412
|
+
/**
|
7413
|
+
* The list of directives associated with the virtual node.
|
7414
|
+
* This may be undefined if there are no directives.
|
7415
|
+
*/
|
7373
7416
|
#directives;
|
7417
|
+
/**
|
7418
|
+
* The anchor comment node used for certain directives (e.g., v-if, v-for).
|
7419
|
+
* This may be undefined if no directive requires an anchor.
|
7420
|
+
*/
|
7374
7421
|
#anchorNode;
|
7422
|
+
/**
|
7423
|
+
* The list of bindings preparers from the associated directives.
|
7424
|
+
* This may be undefined if no directive provides a bindings preparer.
|
7425
|
+
*/
|
7375
7426
|
#bindingsPreparers;
|
7427
|
+
/**
|
7428
|
+
* The list of DOM updaters from the associated directives.
|
7429
|
+
* This may be undefined if no directive provides a DOM updater.
|
7430
|
+
*/
|
7376
7431
|
#domUpdaters;
|
7432
|
+
/**
|
7433
|
+
* The directive that binds the ":key" or "v-bind:key" attribute, if any.
|
7434
|
+
* This directive is special and is used for optimizing rendering of lists.
|
7435
|
+
* If no such directive exists, this is undefined.
|
7436
|
+
*/
|
7377
7437
|
#keyDirective;
|
7438
|
+
/**
|
7439
|
+
* A cache of VBindDirectives for options specific to certain directives.
|
7440
|
+
* The keys are directive names (e.g., 'options', 'options.intersection').
|
7441
|
+
*/
|
7442
|
+
#optionsDirectives = {};
|
7378
7443
|
constructor(vNode) {
|
7379
7444
|
// Directives can only be associated with element nodes
|
7380
7445
|
if (vNode.nodeType !== Node.ELEMENT_NODE) {
|
@@ -7432,6 +7497,35 @@ class VDirectiveManager {
|
|
7432
7497
|
get keyDirective() {
|
7433
7498
|
return this.#keyDirective;
|
7434
7499
|
}
|
7500
|
+
/**
|
7501
|
+
* Gets a record of VBindDirectives for options specific to certain directives.
|
7502
|
+
* The keys are directive names (e.g., 'options', 'options.intersection').
|
7503
|
+
*/
|
7504
|
+
get optionsDirectives() {
|
7505
|
+
return this.#optionsDirectives;
|
7506
|
+
}
|
7507
|
+
/**
|
7508
|
+
* Gets the VBindDirective for options specific to the given directive name.
|
7509
|
+
* Searches in order: `:options.{directive}` -> `:options`
|
7510
|
+
*
|
7511
|
+
* @param directive The directive name (e.g., 'intersection', 'resize')
|
7512
|
+
* @returns The VBindDirective instance or undefined
|
7513
|
+
*/
|
7514
|
+
optionsDirective(directive) {
|
7515
|
+
if (!this.#directives || this.#directives.length === 0) {
|
7516
|
+
return undefined;
|
7517
|
+
}
|
7518
|
+
// Search for `:options.{directive}` or `v-bind:options.{directive}` first
|
7519
|
+
const specificAttrName = `options.${directive}`;
|
7520
|
+
if (this.#optionsDirectives[specificAttrName]) {
|
7521
|
+
return this.#optionsDirectives[specificAttrName];
|
7522
|
+
}
|
7523
|
+
// Fallback: search for `:options` or `v-bind:options`
|
7524
|
+
if (this.#optionsDirectives['options']) {
|
7525
|
+
return this.#optionsDirectives['options'];
|
7526
|
+
}
|
7527
|
+
return undefined;
|
7528
|
+
}
|
7435
7529
|
/**
|
7436
7530
|
* Cleans up any resources used by the directive handler.
|
7437
7531
|
*/
|
@@ -7491,6 +7585,10 @@ class VDirectiveManager {
|
|
7491
7585
|
if (directive.name === StandardDirectiveName.V_BIND && directive.isKey) {
|
7492
7586
|
this.#keyDirective = directive;
|
7493
7587
|
}
|
7588
|
+
// If this is an options binding directive, cache it
|
7589
|
+
if (directive.name === StandardDirectiveName.V_BIND && directive.isOptions) {
|
7590
|
+
this.#optionsDirectives[directive.name] = directive;
|
7591
|
+
}
|
7494
7592
|
}
|
7495
7593
|
}
|
7496
7594
|
// Sort directives by priority: v-for > v-if > v-else-if > v-else > v-show > others
|
@@ -8233,6 +8331,11 @@ class VConditionalDirectiveContext {
|
|
8233
8331
|
}
|
8234
8332
|
|
8235
8333
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
8334
|
+
/**
|
8335
|
+
* Base class for conditional directives such as v-if, v-else-if, and v-else.
|
8336
|
+
* This class manages the rendering of the associated virtual node based on the evaluation of the directive's condition.
|
8337
|
+
* It also coordinates with other related conditional directives to ensure only one block is rendered at a time.
|
8338
|
+
*/
|
8236
8339
|
class VConditionalDirective {
|
8237
8340
|
/**
|
8238
8341
|
* The virtual node to which this directive is applied.
|
@@ -8978,6 +9081,209 @@ class VIfDirective extends VConditionalDirective {
|
|
8978
9081
|
}
|
8979
9082
|
}
|
8980
9083
|
|
9084
|
+
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
9085
|
+
/**
|
9086
|
+
* Directive for observing element intersection with viewport or ancestor elements using IntersectionObserver.
|
9087
|
+
* The `v-intersection` directive allows you to respond to changes in an element's visibility.
|
9088
|
+
*
|
9089
|
+
* Example usage:
|
9090
|
+
* <div v-intersection="handleIntersection">Observable content</div>
|
9091
|
+
* <div v-intersection="handleIntersection" :options.intersection="{threshold: 0.5}">Observable content</div>
|
9092
|
+
*
|
9093
|
+
* The handler receives IntersectionObserverEntry array as the first argument and $ctx as the second:
|
9094
|
+
* handleIntersection(entries, $ctx) {
|
9095
|
+
* const entry = entries[0];
|
9096
|
+
* if (entry.isIntersecting) {
|
9097
|
+
* console.log('Element is visible!');
|
9098
|
+
* }
|
9099
|
+
* }
|
9100
|
+
*
|
9101
|
+
* Options can be provided via :options or :options.intersection attribute:
|
9102
|
+
* :options="{root: null, threshold: 0.5, rootMargin: '0px'}"
|
9103
|
+
* :options.intersection="{root: null, threshold: 0.5, rootMargin: '0px'}"
|
9104
|
+
*
|
9105
|
+
* This directive is useful for lazy-loading, infinite scrolling, animation triggers,
|
9106
|
+
* and other features that depend on element visibility.
|
9107
|
+
*/
|
9108
|
+
class VIntersectionDirective {
|
9109
|
+
/**
|
9110
|
+
* The virtual node to which this directive is applied.
|
9111
|
+
*/
|
9112
|
+
#vNode;
|
9113
|
+
/**
|
9114
|
+
* A list of variable and function names used in the directive's expression.
|
9115
|
+
*/
|
9116
|
+
#dependentIdentifiers;
|
9117
|
+
/**
|
9118
|
+
* The intersection handler wrapper function.
|
9119
|
+
*/
|
9120
|
+
#handlerWrapper;
|
9121
|
+
/**
|
9122
|
+
* The IntersectionObserver instance.
|
9123
|
+
*/
|
9124
|
+
#intersectionObserver;
|
9125
|
+
/**
|
9126
|
+
* @param context The context for parsing the directive.
|
9127
|
+
*/
|
9128
|
+
constructor(context) {
|
9129
|
+
this.#vNode = context.vNode;
|
9130
|
+
// Parse the expression to extract identifiers and create the handler wrapper
|
9131
|
+
const expression = context.attribute.value;
|
9132
|
+
if (expression) {
|
9133
|
+
this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
|
9134
|
+
this.#handlerWrapper = this.#createIntersectionHandlerWrapper(expression);
|
9135
|
+
}
|
9136
|
+
// Remove the directive attribute from the element
|
9137
|
+
this.#vNode.node.removeAttribute(context.attribute.name);
|
9138
|
+
}
|
9139
|
+
/**
|
9140
|
+
* @inheritdoc
|
9141
|
+
*/
|
9142
|
+
get name() {
|
9143
|
+
return StandardDirectiveName.V_INTERSECTION;
|
9144
|
+
}
|
9145
|
+
/**
|
9146
|
+
* @inheritdoc
|
9147
|
+
*/
|
9148
|
+
get vNode() {
|
9149
|
+
return this.#vNode;
|
9150
|
+
}
|
9151
|
+
/**
|
9152
|
+
* @inheritdoc
|
9153
|
+
*/
|
9154
|
+
get needsAnchor() {
|
9155
|
+
return false;
|
9156
|
+
}
|
9157
|
+
/**
|
9158
|
+
* @inheritdoc
|
9159
|
+
*/
|
9160
|
+
get bindingsPreparer() {
|
9161
|
+
return undefined;
|
9162
|
+
}
|
9163
|
+
/**
|
9164
|
+
* @inheritdoc
|
9165
|
+
*/
|
9166
|
+
get domUpdater() {
|
9167
|
+
return undefined;
|
9168
|
+
}
|
9169
|
+
/**
|
9170
|
+
* @inheritdoc
|
9171
|
+
*/
|
9172
|
+
get templatize() {
|
9173
|
+
return false;
|
9174
|
+
}
|
9175
|
+
/**
|
9176
|
+
* @inheritdoc
|
9177
|
+
*/
|
9178
|
+
get dependentIdentifiers() {
|
9179
|
+
return this.#dependentIdentifiers ?? [];
|
9180
|
+
}
|
9181
|
+
/**
|
9182
|
+
* @inheritdoc
|
9183
|
+
*/
|
9184
|
+
get onMount() {
|
9185
|
+
return undefined;
|
9186
|
+
}
|
9187
|
+
/**
|
9188
|
+
* @inheritdoc
|
9189
|
+
*/
|
9190
|
+
get onMounted() {
|
9191
|
+
if (!this.#handlerWrapper) {
|
9192
|
+
return undefined;
|
9193
|
+
}
|
9194
|
+
const element = this.#vNode.node;
|
9195
|
+
const handler = this.#handlerWrapper;
|
9196
|
+
return () => {
|
9197
|
+
// Get options from :options.intersection or :options directive
|
9198
|
+
let optionsDirective = this.#vNode.directiveManager?.optionsDirective('intersection');
|
9199
|
+
// Evaluate the options expression
|
9200
|
+
let options;
|
9201
|
+
if (optionsDirective && optionsDirective.expression) {
|
9202
|
+
// Evaluate the options expression
|
9203
|
+
const identifiers = optionsDirective.dependentIdentifiers;
|
9204
|
+
const values = identifiers.map(id => this.#vNode.bindings?.get(id));
|
9205
|
+
const args = identifiers.join(", ");
|
9206
|
+
const funcBody = `return (${optionsDirective.expression});`;
|
9207
|
+
const func = new Function(args, funcBody);
|
9208
|
+
options = func(...values);
|
9209
|
+
}
|
9210
|
+
// Create IntersectionObserver and start observing
|
9211
|
+
this.#intersectionObserver = new IntersectionObserver((entries) => {
|
9212
|
+
handler(entries);
|
9213
|
+
}, options);
|
9214
|
+
this.#intersectionObserver.observe(element);
|
9215
|
+
};
|
9216
|
+
}
|
9217
|
+
/**
|
9218
|
+
* @inheritdoc
|
9219
|
+
*/
|
9220
|
+
get onUpdate() {
|
9221
|
+
return undefined;
|
9222
|
+
}
|
9223
|
+
/**
|
9224
|
+
* @inheritdoc
|
9225
|
+
*/
|
9226
|
+
get onUpdated() {
|
9227
|
+
return undefined;
|
9228
|
+
}
|
9229
|
+
/**
|
9230
|
+
* @inheritdoc
|
9231
|
+
*/
|
9232
|
+
get onUnmount() {
|
9233
|
+
return undefined;
|
9234
|
+
}
|
9235
|
+
/**
|
9236
|
+
* @inheritdoc
|
9237
|
+
*/
|
9238
|
+
get onUnmounted() {
|
9239
|
+
return undefined;
|
9240
|
+
}
|
9241
|
+
/**
|
9242
|
+
* @inheritdoc
|
9243
|
+
*/
|
9244
|
+
destroy() {
|
9245
|
+
// Disconnect the IntersectionObserver when the directive is destroyed
|
9246
|
+
if (this.#intersectionObserver) {
|
9247
|
+
this.#intersectionObserver.disconnect();
|
9248
|
+
this.#intersectionObserver = undefined;
|
9249
|
+
}
|
9250
|
+
}
|
9251
|
+
/**
|
9252
|
+
* Creates a wrapper function for intersection handlers.
|
9253
|
+
* @param expression The expression string to evaluate.
|
9254
|
+
* @returns A function that handles the intersection event.
|
9255
|
+
*/
|
9256
|
+
#createIntersectionHandlerWrapper(expression) {
|
9257
|
+
const identifiers = this.#dependentIdentifiers ?? [];
|
9258
|
+
const vNode = this.#vNode;
|
9259
|
+
// Return a function that handles the intersection event with proper scope
|
9260
|
+
return (entries) => {
|
9261
|
+
const bindings = vNode.bindings;
|
9262
|
+
const $ctx = {
|
9263
|
+
element: vNode.node,
|
9264
|
+
vnode: vNode,
|
9265
|
+
userData: vNode.userData
|
9266
|
+
};
|
9267
|
+
// If the expression is just a method name, call it with bindings as 'this'
|
9268
|
+
const trimmedExpr = expression.trim();
|
9269
|
+
if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
|
9270
|
+
const methodName = trimmedExpr;
|
9271
|
+
const originalMethod = bindings?.get(methodName);
|
9272
|
+
// Call the method with bindings as 'this' context
|
9273
|
+
// Pass entries as first argument and $ctx as second argument
|
9274
|
+
return originalMethod(entries, $ctx);
|
9275
|
+
}
|
9276
|
+
// For inline expressions, evaluate normally
|
9277
|
+
// Note: inline expressions receive entries and $ctx as parameters
|
9278
|
+
const values = identifiers.map(id => vNode.bindings?.get(id));
|
9279
|
+
const args = [...identifiers, 'entries', '$ctx'].join(", ");
|
9280
|
+
const funcBody = `return (${expression});`;
|
9281
|
+
const func = new Function(args, funcBody);
|
9282
|
+
return func.call(bindings?.raw, ...values, entries, $ctx);
|
9283
|
+
};
|
9284
|
+
}
|
9285
|
+
}
|
9286
|
+
|
8981
9287
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
8982
9288
|
/**
|
8983
9289
|
* Directive for two-way data binding on form input elements.
|
@@ -9303,7 +9609,7 @@ class VModelDirective {
|
|
9303
9609
|
* @mounted="onMounted" - Called after the element is inserted into the DOM
|
9304
9610
|
* @update="onUpdate" - Called before the element is updated
|
9305
9611
|
* @updated="onUpdated" - Called after the element is updated
|
9306
|
-
* @unmount="onUnmount" - Called before
|
9612
|
+
* @unmount="onUnmount" - Called before VNode cleanup begins
|
9307
9613
|
* @unmounted="onUnmounted" - Called after VNode cleanup is complete (element reference still available)
|
9308
9614
|
*
|
9309
9615
|
* This directive is essential for handling user interactions and lifecycle events in your application.
|
@@ -9622,6 +9928,7 @@ class VOnDirective {
|
|
9622
9928
|
*
|
9623
9929
|
* Example usage:
|
9624
9930
|
* <div v-resize="handleResize">Resizable content</div>
|
9931
|
+
* <div v-resize="handleResize" :options.resize="{box: 'border-box'}">Resizable content</div>
|
9625
9932
|
*
|
9626
9933
|
* The handler receives ResizeObserverEntry array as the first argument and $ctx as the second:
|
9627
9934
|
* handleResize(entries, $ctx) {
|
@@ -9629,6 +9936,10 @@ class VOnDirective {
|
|
9629
9936
|
* console.log(`Size: ${width}x${height}`);
|
9630
9937
|
* }
|
9631
9938
|
*
|
9939
|
+
* Options can be provided via :options or :options.resize attribute:
|
9940
|
+
* :options="{box: 'border-box'}"
|
9941
|
+
* :options.resize="{box: 'content-box'}"
|
9942
|
+
*
|
9632
9943
|
* This directive is useful for responsive layouts, charts, and other components
|
9633
9944
|
* that need to adapt to size changes.
|
9634
9945
|
*/
|
@@ -9721,11 +10032,24 @@ class VResizeDirective {
|
|
9721
10032
|
const element = this.#vNode.node;
|
9722
10033
|
const handler = this.#handlerWrapper;
|
9723
10034
|
return () => {
|
10035
|
+
// Get options from :options.resize or :options directive
|
10036
|
+
let optionsDirective = this.#vNode.directiveManager?.optionsDirective('resize');
|
10037
|
+
// Evaluate the options expression
|
10038
|
+
let options;
|
10039
|
+
if (optionsDirective && optionsDirective.expression) {
|
10040
|
+
// Evaluate the options expression
|
10041
|
+
const identifiers = optionsDirective.dependentIdentifiers;
|
10042
|
+
const values = identifiers.map(id => this.#vNode.bindings?.get(id));
|
10043
|
+
const args = identifiers.join(", ");
|
10044
|
+
const funcBody = `return (${optionsDirective.expression});`;
|
10045
|
+
const func = new Function(args, funcBody);
|
10046
|
+
options = func(...values);
|
10047
|
+
}
|
9724
10048
|
// Create ResizeObserver and start observing
|
9725
10049
|
this.#resizeObserver = new ResizeObserver((entries) => {
|
9726
10050
|
handler(entries);
|
9727
10051
|
});
|
9728
|
-
this.#resizeObserver.observe(element);
|
10052
|
+
this.#resizeObserver.observe(element, options);
|
9729
10053
|
};
|
9730
10054
|
}
|
9731
10055
|
/**
|
@@ -10025,7 +10349,9 @@ class VStandardDirectiveParser {
|
|
10025
10349
|
context.attribute.name === StandardDirectiveName.V_MODEL ||
|
10026
10350
|
context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".") ||
|
10027
10351
|
// v-resize
|
10028
|
-
context.attribute.name === StandardDirectiveName.V_RESIZE
|
10352
|
+
context.attribute.name === StandardDirectiveName.V_RESIZE ||
|
10353
|
+
// v-intersection
|
10354
|
+
context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
|
10029
10355
|
return true;
|
10030
10356
|
}
|
10031
10357
|
return false;
|
@@ -10068,6 +10394,10 @@ class VStandardDirectiveParser {
|
|
10068
10394
|
if (context.attribute.name === StandardDirectiveName.V_RESIZE) {
|
10069
10395
|
return new VResizeDirective(context);
|
10070
10396
|
}
|
10397
|
+
// v-intersection
|
10398
|
+
if (context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
|
10399
|
+
return new VIntersectionDirective(context);
|
10400
|
+
}
|
10071
10401
|
throw new Error(`The attribute "${context.attribute.name}" cannot be parsed by ${this.name}.`);
|
10072
10402
|
}
|
10073
10403
|
}
|
@@ -10078,13 +10408,13 @@ class VStandardDirectiveParser {
|
|
10078
10408
|
*/
|
10079
10409
|
var LogLevel;
|
10080
10410
|
(function (LogLevel) {
|
10081
|
-
|
10411
|
+
/** Debug level */
|
10082
10412
|
LogLevel["DEBUG"] = "debug";
|
10083
|
-
|
10413
|
+
/** Info level */
|
10084
10414
|
LogLevel["INFO"] = "info";
|
10085
|
-
|
10415
|
+
/** Warning level */
|
10086
10416
|
LogLevel["WARN"] = "warn";
|
10087
|
-
|
10417
|
+
/** Error level */
|
10088
10418
|
LogLevel["ERROR"] = "error";
|
10089
10419
|
})(LogLevel || (LogLevel = {}));
|
10090
10420
|
|