@mintjamsinc/ichigojs 0.1.8 → 0.1.10

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 CHANGED
@@ -16,9 +16,10 @@ 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`, `v-intersection`
19
+ - 🎨 **Directives** - `v-if`, `v-for`, `v-show`, `v-bind`, `v-on`, `v-model`, `v-resize`, `v-intersection`, `v-performance`
20
20
  - 📐 **Resize Observer** - Monitor element size changes with `v-resize` directive
21
21
  - 👁️ **Intersection Observer** - Detect element visibility with `v-intersection` directive
22
+ - ⚡ **Performance Observer** - Monitor performance metrics with `v-performance` directive
22
23
 
23
24
  ## Installation
24
25
 
@@ -200,8 +201,27 @@ methods: {
200
201
  }
201
202
  ```
202
203
 
204
+ **With custom options:**
205
+
206
+ ```html
207
+ <div v-resize="onResize"
208
+ :options.resize="{box: 'border-box'}">
209
+ Observe border-box dimensions
210
+ </div>
211
+ ```
212
+
213
+ You can also use `:options` for generic options:
214
+
215
+ ```html
216
+ <div v-resize="onResize"
217
+ :options="{box: 'content-box'}">
218
+ Resizable content
219
+ </div>
220
+ ```
221
+
203
222
  **Features:**
204
223
  - Native ResizeObserver API for efficient resize detection
224
+ - Custom box model via `:options.resize` or `:options`
205
225
  - Automatic cleanup in destroy phase
206
226
  - Access to element, VNode, and userData via `$ctx`
207
227
 
@@ -253,6 +273,56 @@ You can also use `:options` for generic options:
253
273
  - Perfect for lazy loading, infinite scroll, and animation triggers
254
274
  - Access to element, VNode, and userData via `$ctx`
255
275
 
276
+ #### v-performance
277
+
278
+ Monitor performance metrics using PerformanceObserver:
279
+
280
+ ```html
281
+ <div v-performance="onPerformance">
282
+ Performance monitoring
283
+ </div>
284
+ ```
285
+
286
+ ```javascript
287
+ methods: {
288
+ onPerformance(entries, observer, options, $ctx) {
289
+ entries.getEntries().forEach(entry => {
290
+ console.log(`${entry.name}: ${entry.duration}ms`);
291
+ });
292
+
293
+ // Access dropped entries count if available
294
+ if (options?.droppedEntriesCount) {
295
+ console.log(`Dropped: ${options.droppedEntriesCount}`);
296
+ }
297
+ }
298
+ }
299
+ ```
300
+
301
+ **With custom options:**
302
+
303
+ ```html
304
+ <div v-performance="onPerformance"
305
+ :options.performance="{entryTypes: ['measure', 'mark']}">
306
+ Observe only measures and marks
307
+ </div>
308
+ ```
309
+
310
+ You can also use `:options` for generic options:
311
+
312
+ ```html
313
+ <div v-performance="onPerformance"
314
+ :options="{type: 'navigation', buffered: true}">
315
+ Performance monitoring
316
+ </div>
317
+ ```
318
+
319
+ **Features:**
320
+ - Native PerformanceObserver API for monitoring performance metrics
321
+ - Custom entry types and options via `:options.performance` or `:options`
322
+ - Automatic cleanup in destroy phase
323
+ - Monitor marks, measures, navigation, resource timing, and more
324
+ - Access to element, VNode, and userData via `$ctx`
325
+
256
326
  #### Lifecycle Hooks
257
327
 
258
328
  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.
@@ -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,18 +47,33 @@ 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
+ /** Resize observer directives. */
56
72
  StandardDirectiveName["V_RESIZE"] = "v-resize";
73
+ /** Intersection observer directives. */
57
74
  StandardDirectiveName["V_INTERSECTION"] = "v-intersection";
75
+ /** Performance observer directives. */
76
+ StandardDirectiveName["V_PERFORMANCE"] = "v-performance";
58
77
  })(StandardDirectiveName || (StandardDirectiveName = {}));
59
78
 
60
79
  // This file was generated. Do not modify manually!
@@ -6575,6 +6594,9 @@ base.MethodDefinition = base.PropertyDefinition = base.Property = function (node
6575
6594
  };
6576
6595
 
6577
6596
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
6597
+ /**
6598
+ * Utility class for analyzing JavaScript expressions to extract variable and function dependencies.
6599
+ */
6578
6600
  class ExpressionUtils {
6579
6601
  /**
6580
6602
  * Extracts variable and function names used in the expression.
@@ -8311,6 +8333,11 @@ class VConditionalDirectiveContext {
8311
8333
  }
8312
8334
 
8313
8335
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
8336
+ /**
8337
+ * Base class for conditional directives such as v-if, v-else-if, and v-else.
8338
+ * This class manages the rendering of the associated virtual node based on the evaluation of the directive's condition.
8339
+ * It also coordinates with other related conditional directives to ensure only one block is rendered at a time.
8340
+ */
8314
8341
  class VConditionalDirective {
8315
8342
  /**
8316
8343
  * The virtual node to which this directive is applied.
@@ -9896,6 +9923,220 @@ class VOnDirective {
9896
9923
  }
9897
9924
  }
9898
9925
 
9926
+ // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
9927
+ /**
9928
+ * Directive for observing performance metrics using PerformanceObserver.
9929
+ * The `v-performance` directive allows you to monitor various performance entries.
9930
+ *
9931
+ * Example usage:
9932
+ * <div v-performance="handlePerformance">Performance monitoring</div>
9933
+ * <div v-performance="handlePerformance" :options.performance="{entryTypes: ['measure']}">Performance monitoring</div>
9934
+ *
9935
+ * By default (without options), it observes 'mark' and 'measure' entry types.
9936
+ *
9937
+ * The handler receives PerformanceObserverEntryList, PerformanceObserver, options (with droppedEntriesCount), and $ctx as arguments:
9938
+ * handlePerformance(entries, observer, options, $ctx) {
9939
+ * entries.getEntries().forEach(entry => {
9940
+ * console.log(`${entry.name}: ${entry.duration}ms`);
9941
+ * });
9942
+ * if (options?.droppedEntriesCount) {
9943
+ * console.log(`Dropped entries: ${options.droppedEntriesCount}`);
9944
+ * }
9945
+ * }
9946
+ *
9947
+ * Options can be provided via :options or :options.performance attribute:
9948
+ * :options="{entryTypes: ['measure', 'mark']}"
9949
+ * :options.performance="{type: 'navigation', buffered: true}"
9950
+ *
9951
+ * This directive is useful for performance monitoring, profiling, and identifying
9952
+ * performance bottlenecks in your application.
9953
+ */
9954
+ class VPerformanceDirective {
9955
+ /**
9956
+ * The virtual node to which this directive is applied.
9957
+ */
9958
+ #vNode;
9959
+ /**
9960
+ * A list of variable and function names used in the directive's expression.
9961
+ */
9962
+ #dependentIdentifiers;
9963
+ /**
9964
+ * The performance handler wrapper function.
9965
+ */
9966
+ #handlerWrapper;
9967
+ /**
9968
+ * The PerformanceObserver instance.
9969
+ */
9970
+ #performanceObserver;
9971
+ /**
9972
+ * @param context The context for parsing the directive.
9973
+ */
9974
+ constructor(context) {
9975
+ this.#vNode = context.vNode;
9976
+ // Parse the expression to extract identifiers and create the handler wrapper
9977
+ const expression = context.attribute.value;
9978
+ if (expression) {
9979
+ this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
9980
+ this.#handlerWrapper = this.#createPerformanceHandlerWrapper(expression);
9981
+ }
9982
+ // Remove the directive attribute from the element
9983
+ this.#vNode.node.removeAttribute(context.attribute.name);
9984
+ }
9985
+ /**
9986
+ * @inheritdoc
9987
+ */
9988
+ get name() {
9989
+ return StandardDirectiveName.V_PERFORMANCE;
9990
+ }
9991
+ /**
9992
+ * @inheritdoc
9993
+ */
9994
+ get vNode() {
9995
+ return this.#vNode;
9996
+ }
9997
+ /**
9998
+ * @inheritdoc
9999
+ */
10000
+ get needsAnchor() {
10001
+ return false;
10002
+ }
10003
+ /**
10004
+ * @inheritdoc
10005
+ */
10006
+ get bindingsPreparer() {
10007
+ return undefined;
10008
+ }
10009
+ /**
10010
+ * @inheritdoc
10011
+ */
10012
+ get domUpdater() {
10013
+ return undefined;
10014
+ }
10015
+ /**
10016
+ * @inheritdoc
10017
+ */
10018
+ get templatize() {
10019
+ return false;
10020
+ }
10021
+ /**
10022
+ * @inheritdoc
10023
+ */
10024
+ get dependentIdentifiers() {
10025
+ return this.#dependentIdentifiers ?? [];
10026
+ }
10027
+ /**
10028
+ * @inheritdoc
10029
+ */
10030
+ get onMount() {
10031
+ return undefined;
10032
+ }
10033
+ /**
10034
+ * @inheritdoc
10035
+ */
10036
+ get onMounted() {
10037
+ if (!this.#handlerWrapper) {
10038
+ return undefined;
10039
+ }
10040
+ const handler = this.#handlerWrapper;
10041
+ return () => {
10042
+ // Get options from :options.performance or :options directive
10043
+ let optionsDirective = this.#vNode.directiveManager?.optionsDirective('performance');
10044
+ // Evaluate the options expression
10045
+ let options;
10046
+ if (optionsDirective && optionsDirective.expression) {
10047
+ // Evaluate the options expression
10048
+ const identifiers = optionsDirective.dependentIdentifiers;
10049
+ const values = identifiers.map(id => this.#vNode.bindings?.get(id));
10050
+ const args = identifiers.join(", ");
10051
+ const funcBody = `return (${optionsDirective.expression});`;
10052
+ const func = new Function(args, funcBody);
10053
+ options = func(...values);
10054
+ }
10055
+ // Create PerformanceObserver and start observing
10056
+ // Note: The callback receives a third argument 'options' with droppedEntriesCount in modern browsers
10057
+ // TypeScript's type definition only includes 2 arguments, so we use type assertion
10058
+ this.#performanceObserver = new PerformanceObserver(((...args) => {
10059
+ const [entries, observer, callbackOptions] = args;
10060
+ handler(entries, observer, callbackOptions);
10061
+ }));
10062
+ // If no options provided, use default: observe marks and measures
10063
+ if (!options) {
10064
+ options = { entryTypes: ['mark', 'measure'] };
10065
+ }
10066
+ // Start observing with options
10067
+ this.#performanceObserver.observe(options);
10068
+ };
10069
+ }
10070
+ /**
10071
+ * @inheritdoc
10072
+ */
10073
+ get onUpdate() {
10074
+ return undefined;
10075
+ }
10076
+ /**
10077
+ * @inheritdoc
10078
+ */
10079
+ get onUpdated() {
10080
+ return undefined;
10081
+ }
10082
+ /**
10083
+ * @inheritdoc
10084
+ */
10085
+ get onUnmount() {
10086
+ return undefined;
10087
+ }
10088
+ /**
10089
+ * @inheritdoc
10090
+ */
10091
+ get onUnmounted() {
10092
+ return undefined;
10093
+ }
10094
+ /**
10095
+ * @inheritdoc
10096
+ */
10097
+ destroy() {
10098
+ // Disconnect the PerformanceObserver when the directive is destroyed
10099
+ if (this.#performanceObserver) {
10100
+ this.#performanceObserver.disconnect();
10101
+ this.#performanceObserver = undefined;
10102
+ }
10103
+ }
10104
+ /**
10105
+ * Creates a wrapper function for performance handlers.
10106
+ * @param expression The expression string to evaluate.
10107
+ * @returns A function that handles the performance event.
10108
+ */
10109
+ #createPerformanceHandlerWrapper(expression) {
10110
+ const identifiers = this.#dependentIdentifiers ?? [];
10111
+ const vNode = this.#vNode;
10112
+ // Return a function that handles the performance event with proper scope
10113
+ return (entries, observer, options) => {
10114
+ const bindings = vNode.bindings;
10115
+ const $ctx = {
10116
+ element: vNode.node,
10117
+ vnode: vNode,
10118
+ userData: vNode.userData
10119
+ };
10120
+ // If the expression is just a method name, call it with bindings as 'this'
10121
+ const trimmedExpr = expression.trim();
10122
+ if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
10123
+ const methodName = trimmedExpr;
10124
+ const originalMethod = bindings?.get(methodName);
10125
+ // Call the method with bindings as 'this' context
10126
+ // Pass entries, observer, options, and $ctx as arguments
10127
+ return originalMethod(entries, observer, options, $ctx);
10128
+ }
10129
+ // For inline expressions, evaluate normally
10130
+ // Note: inline expressions receive entries, observer, options, and $ctx as parameters
10131
+ const values = identifiers.map(id => vNode.bindings?.get(id));
10132
+ const args = [...identifiers, 'entries', 'observer', 'options', '$ctx'].join(", ");
10133
+ const funcBody = `return (${expression});`;
10134
+ const func = new Function(args, funcBody);
10135
+ return func.call(bindings?.raw, ...values, entries, observer, options, $ctx);
10136
+ };
10137
+ }
10138
+ }
10139
+
9899
10140
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
9900
10141
  /**
9901
10142
  * Directive for observing element resize events using ResizeObserver.
@@ -9903,6 +10144,7 @@ class VOnDirective {
9903
10144
  *
9904
10145
  * Example usage:
9905
10146
  * <div v-resize="handleResize">Resizable content</div>
10147
+ * <div v-resize="handleResize" :options.resize="{box: 'border-box'}">Resizable content</div>
9906
10148
  *
9907
10149
  * The handler receives ResizeObserverEntry array as the first argument and $ctx as the second:
9908
10150
  * handleResize(entries, $ctx) {
@@ -9910,6 +10152,10 @@ class VOnDirective {
9910
10152
  * console.log(`Size: ${width}x${height}`);
9911
10153
  * }
9912
10154
  *
10155
+ * Options can be provided via :options or :options.resize attribute:
10156
+ * :options="{box: 'border-box'}"
10157
+ * :options.resize="{box: 'content-box'}"
10158
+ *
9913
10159
  * This directive is useful for responsive layouts, charts, and other components
9914
10160
  * that need to adapt to size changes.
9915
10161
  */
@@ -10002,11 +10248,24 @@ class VResizeDirective {
10002
10248
  const element = this.#vNode.node;
10003
10249
  const handler = this.#handlerWrapper;
10004
10250
  return () => {
10251
+ // Get options from :options.resize or :options directive
10252
+ let optionsDirective = this.#vNode.directiveManager?.optionsDirective('resize');
10253
+ // Evaluate the options expression
10254
+ let options;
10255
+ if (optionsDirective && optionsDirective.expression) {
10256
+ // Evaluate the options expression
10257
+ const identifiers = optionsDirective.dependentIdentifiers;
10258
+ const values = identifiers.map(id => this.#vNode.bindings?.get(id));
10259
+ const args = identifiers.join(", ");
10260
+ const funcBody = `return (${optionsDirective.expression});`;
10261
+ const func = new Function(args, funcBody);
10262
+ options = func(...values);
10263
+ }
10005
10264
  // Create ResizeObserver and start observing
10006
10265
  this.#resizeObserver = new ResizeObserver((entries) => {
10007
10266
  handler(entries);
10008
10267
  });
10009
- this.#resizeObserver.observe(element);
10268
+ this.#resizeObserver.observe(element, options);
10010
10269
  };
10011
10270
  }
10012
10271
  /**
@@ -10308,7 +10567,9 @@ class VStandardDirectiveParser {
10308
10567
  // v-resize
10309
10568
  context.attribute.name === StandardDirectiveName.V_RESIZE ||
10310
10569
  // v-intersection
10311
- context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
10570
+ context.attribute.name === StandardDirectiveName.V_INTERSECTION ||
10571
+ // v-performance
10572
+ context.attribute.name === StandardDirectiveName.V_PERFORMANCE) {
10312
10573
  return true;
10313
10574
  }
10314
10575
  return false;
@@ -10355,6 +10616,10 @@ class VStandardDirectiveParser {
10355
10616
  if (context.attribute.name === StandardDirectiveName.V_INTERSECTION) {
10356
10617
  return new VIntersectionDirective(context);
10357
10618
  }
10619
+ // v-performance
10620
+ if (context.attribute.name === StandardDirectiveName.V_PERFORMANCE) {
10621
+ return new VPerformanceDirective(context);
10622
+ }
10358
10623
  throw new Error(`The attribute "${context.attribute.name}" cannot be parsed by ${this.name}.`);
10359
10624
  }
10360
10625
  }
@@ -10365,13 +10630,13 @@ class VStandardDirectiveParser {
10365
10630
  */
10366
10631
  var LogLevel;
10367
10632
  (function (LogLevel) {
10368
- // Debug level
10633
+ /** Debug level */
10369
10634
  LogLevel["DEBUG"] = "debug";
10370
- // Info level
10635
+ /** Info level */
10371
10636
  LogLevel["INFO"] = "info";
10372
- // Warning level
10637
+ /** Warning level */
10373
10638
  LogLevel["WARN"] = "warn";
10374
- // Error level
10639
+ /** Error level */
10375
10640
  LogLevel["ERROR"] = "error";
10376
10641
  })(LogLevel || (LogLevel = {}));
10377
10642