@mintjamsinc/ichigojs 0.1.6 → 0.1.7
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 +50 -6
- package/dist/ichigo.esm.js +203 -7
- 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 +203 -7
- 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 +2 -1
- package/dist/types/ichigo/directives/VDirective.d.ts +2 -1
- package/dist/types/ichigo/directives/VOnDirective.d.ts +1 -1
- package/dist/types/ichigo/directives/VResizeDirective.d.ts +84 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -16,7 +16,8 @@ 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`
|
19
|
+
- 🎨 **Directives** - `v-if`, `v-for`, `v-show`, `v-bind`, `v-on`, `v-model`, `v-resize`
|
20
|
+
- 📐 **Resize Observer** - Monitor element size changes with `v-resize` directive
|
20
21
|
|
21
22
|
## Installation
|
22
23
|
|
@@ -160,6 +161,49 @@ Event handling with modifiers:
|
|
160
161
|
|
161
162
|
Supported modifiers: `.stop`, `.prevent`, `.capture`, `.self`, `.once`
|
162
163
|
|
164
|
+
**Event Handlers with Context:**
|
165
|
+
|
166
|
+
All event handlers receive the event as the first parameter and `$ctx` as the second parameter:
|
167
|
+
|
168
|
+
```javascript
|
169
|
+
methods: {
|
170
|
+
handleClick(event, $ctx) {
|
171
|
+
// event - the DOM event object
|
172
|
+
// $ctx.element - the DOM element
|
173
|
+
// $ctx.vnode - the VNode instance
|
174
|
+
// $ctx.userData - Proxy-free storage
|
175
|
+
}
|
176
|
+
}
|
177
|
+
```
|
178
|
+
|
179
|
+
#### v-resize
|
180
|
+
|
181
|
+
Monitor element size changes using ResizeObserver:
|
182
|
+
|
183
|
+
```html
|
184
|
+
<div v-resize="onResize" class="resizable-box">
|
185
|
+
{{ width }}px × {{ height }}px
|
186
|
+
</div>
|
187
|
+
```
|
188
|
+
|
189
|
+
```javascript
|
190
|
+
methods: {
|
191
|
+
onResize(entries, $ctx) {
|
192
|
+
const entry = entries[0];
|
193
|
+
this.width = Math.round(entry.contentRect.width);
|
194
|
+
this.height = Math.round(entry.contentRect.height);
|
195
|
+
|
196
|
+
// Access element through $ctx
|
197
|
+
console.log('Element:', $ctx.element);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
```
|
201
|
+
|
202
|
+
**Features:**
|
203
|
+
- Native ResizeObserver API for efficient resize detection
|
204
|
+
- Automatic cleanup when element is removed
|
205
|
+
- Access to element, VNode, and userData via `$ctx`
|
206
|
+
|
163
207
|
#### Lifecycle Hooks
|
164
208
|
|
165
209
|
Lifecycle hooks allow you to run code at specific stages of an element's lifecycle. Each hook receives a **lifecycle context** (`$ctx`) with access to the element, VNode, and userData storage.
|
@@ -183,7 +227,7 @@ Lifecycle hooks allow you to run code at specific stages of an element's lifecyc
|
|
183
227
|
- `@update` - Called before the element is updated
|
184
228
|
- `@updated` - Called after the element is updated
|
185
229
|
- `@unmount` - Called before the element is removed from the DOM
|
186
|
-
- `@unmounted` - Called after
|
230
|
+
- `@unmounted` - Called after VNode cleanup is complete (element reference still available)
|
187
231
|
|
188
232
|
**Lifecycle Context (`$ctx`):**
|
189
233
|
|
@@ -195,7 +239,7 @@ Every lifecycle hook receives a context object with:
|
|
195
239
|
|
196
240
|
**userData Storage:**
|
197
241
|
|
198
|
-
`$ctx.userData` is a safe space to store data associated with the element's lifecycle. It's not affected by
|
242
|
+
`$ctx.userData` is a safe space to store data associated with the element's lifecycle. It's not affected by the reactive proxy system, making it perfect for storing third-party library instances.
|
199
243
|
|
200
244
|
```javascript
|
201
245
|
methods: {
|
@@ -255,12 +299,12 @@ methods: {
|
|
255
299
|
|
256
300
|
**Cleanup Order:**
|
257
301
|
|
258
|
-
1. `@unmount` hook fires
|
302
|
+
1. `@unmount` hook fires (element still in DOM)
|
259
303
|
2. `userData` auto-cleanup (close() methods called)
|
260
|
-
3. Child nodes destroyed
|
304
|
+
3. Child nodes destroyed recursively
|
261
305
|
4. Dependencies unregistered
|
262
306
|
5. Directive manager cleanup
|
263
|
-
6. `@unmounted` hook fires
|
307
|
+
6. `@unmounted` hook fires (element removed from DOM, but reference still available in `$ctx.element`)
|
264
308
|
|
265
309
|
**Works with v-if and v-for:**
|
266
310
|
|
package/dist/ichigo.esm.js
CHANGED
@@ -53,6 +53,7 @@ var StandardDirectiveName;
|
|
53
53
|
StandardDirectiveName["V_ON"] = "v-on";
|
54
54
|
StandardDirectiveName["V_BIND"] = "v-bind";
|
55
55
|
StandardDirectiveName["V_MODEL"] = "v-model";
|
56
|
+
StandardDirectiveName["V_RESIZE"] = "v-resize";
|
56
57
|
})(StandardDirectiveName || (StandardDirectiveName = {}));
|
57
58
|
|
58
59
|
// This file was generated. Do not modify manually!
|
@@ -9303,7 +9304,7 @@ class VModelDirective {
|
|
9303
9304
|
* @update="onUpdate" - Called before the element is updated
|
9304
9305
|
* @updated="onUpdated" - Called after the element is updated
|
9305
9306
|
* @unmount="onUnmount" - Called before the element is removed from the DOM
|
9306
|
-
* @unmounted="onUnmounted" - Called after
|
9307
|
+
* @unmounted="onUnmounted" - Called after VNode cleanup is complete (element reference still available)
|
9307
9308
|
*
|
9308
9309
|
* This directive is essential for handling user interactions and lifecycle events in your application.
|
9309
9310
|
* Note that the methods referenced in the directive should be defined in the component's methods object.
|
@@ -9579,7 +9580,7 @@ class VOnDirective {
|
|
9579
9580
|
};
|
9580
9581
|
}
|
9581
9582
|
/**
|
9582
|
-
* Creates a wrapper function for DOM event handlers (with event
|
9583
|
+
* Creates a wrapper function for DOM event handlers (with event and $ctx parameters).
|
9583
9584
|
* @param expression The expression string to evaluate.
|
9584
9585
|
* @returns A function that handles the event.
|
9585
9586
|
*/
|
@@ -9589,21 +9590,210 @@ class VOnDirective {
|
|
9589
9590
|
// Return a function that handles the event with proper scope
|
9590
9591
|
return (event) => {
|
9591
9592
|
const bindings = vNode.bindings;
|
9593
|
+
const $ctx = {
|
9594
|
+
element: vNode.node,
|
9595
|
+
vnode: vNode,
|
9596
|
+
userData: vNode.userData
|
9597
|
+
};
|
9598
|
+
// If the expression is just a method name, call it with bindings as 'this'
|
9599
|
+
const trimmedExpr = expression.trim();
|
9600
|
+
if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
|
9601
|
+
const methodName = trimmedExpr;
|
9602
|
+
const originalMethod = bindings?.get(methodName);
|
9603
|
+
// Call the method with bindings as 'this' context
|
9604
|
+
// Pass event as first argument and $ctx as second argument
|
9605
|
+
return originalMethod(event, $ctx);
|
9606
|
+
}
|
9607
|
+
// For inline expressions, evaluate normally
|
9608
|
+
// Note: inline expressions receive event and $ctx as parameters
|
9609
|
+
const values = identifiers.map(id => vNode.bindings?.get(id));
|
9610
|
+
const args = [...identifiers, 'event', '$ctx'].join(", ");
|
9611
|
+
const funcBody = `return (${expression});`;
|
9612
|
+
const func = new Function(args, funcBody);
|
9613
|
+
return func.call(bindings?.raw, ...values, event, $ctx);
|
9614
|
+
};
|
9615
|
+
}
|
9616
|
+
}
|
9617
|
+
|
9618
|
+
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
9619
|
+
/**
|
9620
|
+
* Directive for observing element resize events using ResizeObserver.
|
9621
|
+
* The `v-resize` directive allows you to respond to changes in an element's size.
|
9622
|
+
*
|
9623
|
+
* Example usage:
|
9624
|
+
* <div v-resize="handleResize">Resizable content</div>
|
9625
|
+
*
|
9626
|
+
* The handler receives ResizeObserverEntry array as the first argument and $ctx as the second:
|
9627
|
+
* handleResize(entries, $ctx) {
|
9628
|
+
* const { width, height } = entries[0].contentRect;
|
9629
|
+
* console.log(`Size: ${width}x${height}`);
|
9630
|
+
* }
|
9631
|
+
*
|
9632
|
+
* This directive is useful for responsive layouts, charts, and other components
|
9633
|
+
* that need to adapt to size changes.
|
9634
|
+
*/
|
9635
|
+
class VResizeDirective {
|
9636
|
+
/**
|
9637
|
+
* The virtual node to which this directive is applied.
|
9638
|
+
*/
|
9639
|
+
#vNode;
|
9640
|
+
/**
|
9641
|
+
* A list of variable and function names used in the directive's expression.
|
9642
|
+
*/
|
9643
|
+
#dependentIdentifiers;
|
9644
|
+
/**
|
9645
|
+
* The resize handler wrapper function.
|
9646
|
+
*/
|
9647
|
+
#handlerWrapper;
|
9648
|
+
/**
|
9649
|
+
* The ResizeObserver instance.
|
9650
|
+
*/
|
9651
|
+
#resizeObserver;
|
9652
|
+
/**
|
9653
|
+
* @param context The context for parsing the directive.
|
9654
|
+
*/
|
9655
|
+
constructor(context) {
|
9656
|
+
this.#vNode = context.vNode;
|
9657
|
+
// Parse the expression to extract identifiers and create the handler wrapper
|
9658
|
+
const expression = context.attribute.value;
|
9659
|
+
if (expression) {
|
9660
|
+
this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
|
9661
|
+
this.#handlerWrapper = this.#createResizeHandlerWrapper(expression);
|
9662
|
+
}
|
9663
|
+
// Remove the directive attribute from the element
|
9664
|
+
this.#vNode.node.removeAttribute(context.attribute.name);
|
9665
|
+
}
|
9666
|
+
/**
|
9667
|
+
* @inheritdoc
|
9668
|
+
*/
|
9669
|
+
get name() {
|
9670
|
+
return StandardDirectiveName.V_RESIZE;
|
9671
|
+
}
|
9672
|
+
/**
|
9673
|
+
* @inheritdoc
|
9674
|
+
*/
|
9675
|
+
get vNode() {
|
9676
|
+
return this.#vNode;
|
9677
|
+
}
|
9678
|
+
/**
|
9679
|
+
* @inheritdoc
|
9680
|
+
*/
|
9681
|
+
get needsAnchor() {
|
9682
|
+
return false;
|
9683
|
+
}
|
9684
|
+
/**
|
9685
|
+
* @inheritdoc
|
9686
|
+
*/
|
9687
|
+
get bindingsPreparer() {
|
9688
|
+
return undefined;
|
9689
|
+
}
|
9690
|
+
/**
|
9691
|
+
* @inheritdoc
|
9692
|
+
*/
|
9693
|
+
get domUpdater() {
|
9694
|
+
return undefined;
|
9695
|
+
}
|
9696
|
+
/**
|
9697
|
+
* @inheritdoc
|
9698
|
+
*/
|
9699
|
+
get templatize() {
|
9700
|
+
return false;
|
9701
|
+
}
|
9702
|
+
/**
|
9703
|
+
* @inheritdoc
|
9704
|
+
*/
|
9705
|
+
get dependentIdentifiers() {
|
9706
|
+
return this.#dependentIdentifiers ?? [];
|
9707
|
+
}
|
9708
|
+
/**
|
9709
|
+
* @inheritdoc
|
9710
|
+
*/
|
9711
|
+
get onMount() {
|
9712
|
+
return undefined;
|
9713
|
+
}
|
9714
|
+
/**
|
9715
|
+
* @inheritdoc
|
9716
|
+
*/
|
9717
|
+
get onMounted() {
|
9718
|
+
if (!this.#handlerWrapper) {
|
9719
|
+
return undefined;
|
9720
|
+
}
|
9721
|
+
const element = this.#vNode.node;
|
9722
|
+
const handler = this.#handlerWrapper;
|
9723
|
+
return () => {
|
9724
|
+
// Create ResizeObserver and start observing
|
9725
|
+
this.#resizeObserver = new ResizeObserver((entries) => {
|
9726
|
+
handler(entries);
|
9727
|
+
});
|
9728
|
+
this.#resizeObserver.observe(element);
|
9729
|
+
};
|
9730
|
+
}
|
9731
|
+
/**
|
9732
|
+
* @inheritdoc
|
9733
|
+
*/
|
9734
|
+
get onUpdate() {
|
9735
|
+
return undefined;
|
9736
|
+
}
|
9737
|
+
/**
|
9738
|
+
* @inheritdoc
|
9739
|
+
*/
|
9740
|
+
get onUpdated() {
|
9741
|
+
return undefined;
|
9742
|
+
}
|
9743
|
+
/**
|
9744
|
+
* @inheritdoc
|
9745
|
+
*/
|
9746
|
+
get onUnmount() {
|
9747
|
+
return undefined;
|
9748
|
+
}
|
9749
|
+
/**
|
9750
|
+
* @inheritdoc
|
9751
|
+
*/
|
9752
|
+
get onUnmounted() {
|
9753
|
+
return undefined;
|
9754
|
+
}
|
9755
|
+
/**
|
9756
|
+
* @inheritdoc
|
9757
|
+
*/
|
9758
|
+
destroy() {
|
9759
|
+
// Disconnect the ResizeObserver when the directive is destroyed
|
9760
|
+
if (this.#resizeObserver) {
|
9761
|
+
this.#resizeObserver.disconnect();
|
9762
|
+
this.#resizeObserver = undefined;
|
9763
|
+
}
|
9764
|
+
}
|
9765
|
+
/**
|
9766
|
+
* Creates a wrapper function for resize handlers.
|
9767
|
+
* @param expression The expression string to evaluate.
|
9768
|
+
* @returns A function that handles the resize event.
|
9769
|
+
*/
|
9770
|
+
#createResizeHandlerWrapper(expression) {
|
9771
|
+
const identifiers = this.#dependentIdentifiers ?? [];
|
9772
|
+
const vNode = this.#vNode;
|
9773
|
+
// Return a function that handles the resize event with proper scope
|
9774
|
+
return (entries) => {
|
9775
|
+
const bindings = vNode.bindings;
|
9776
|
+
const $ctx = {
|
9777
|
+
element: vNode.node,
|
9778
|
+
vnode: vNode,
|
9779
|
+
userData: vNode.userData
|
9780
|
+
};
|
9592
9781
|
// If the expression is just a method name, call it with bindings as 'this'
|
9593
9782
|
const trimmedExpr = expression.trim();
|
9594
9783
|
if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
|
9595
9784
|
const methodName = trimmedExpr;
|
9596
9785
|
const originalMethod = bindings?.get(methodName);
|
9597
9786
|
// Call the method with bindings as 'this' context
|
9598
|
-
//
|
9599
|
-
return originalMethod(
|
9787
|
+
// Pass entries as first argument and $ctx as second argument
|
9788
|
+
return originalMethod(entries, $ctx);
|
9600
9789
|
}
|
9601
9790
|
// For inline expressions, evaluate normally
|
9791
|
+
// Note: inline expressions receive entries and $ctx as parameters
|
9602
9792
|
const values = identifiers.map(id => vNode.bindings?.get(id));
|
9603
|
-
const args = identifiers.join(", ");
|
9793
|
+
const args = [...identifiers, 'entries', '$ctx'].join(", ");
|
9604
9794
|
const funcBody = `return (${expression});`;
|
9605
9795
|
const func = new Function(args, funcBody);
|
9606
|
-
return func.call(bindings?.raw, ...values,
|
9796
|
+
return func.call(bindings?.raw, ...values, entries, $ctx);
|
9607
9797
|
};
|
9608
9798
|
}
|
9609
9799
|
}
|
@@ -9833,7 +10023,9 @@ class VStandardDirectiveParser {
|
|
9833
10023
|
context.attribute.name.startsWith(":") ||
|
9834
10024
|
// v-model, v-model.<modifier>
|
9835
10025
|
context.attribute.name === StandardDirectiveName.V_MODEL ||
|
9836
|
-
context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".")
|
10026
|
+
context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".") ||
|
10027
|
+
// v-resize
|
10028
|
+
context.attribute.name === StandardDirectiveName.V_RESIZE) {
|
9837
10029
|
return true;
|
9838
10030
|
}
|
9839
10031
|
return false;
|
@@ -9872,6 +10064,10 @@ class VStandardDirectiveParser {
|
|
9872
10064
|
context.attribute.name.startsWith(StandardDirectiveName.V_MODEL + ".")) {
|
9873
10065
|
return new VModelDirective(context);
|
9874
10066
|
}
|
10067
|
+
// v-resize
|
10068
|
+
if (context.attribute.name === StandardDirectiveName.V_RESIZE) {
|
10069
|
+
return new VResizeDirective(context);
|
10070
|
+
}
|
9875
10071
|
throw new Error(`The attribute "${context.attribute.name}" cannot be parsed by ${this.name}.`);
|
9876
10072
|
}
|
9877
10073
|
}
|