@mintjamsinc/ichigojs 0.1.3 → 0.1.4

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.
@@ -6873,6 +6873,42 @@ class VBindDirective {
6873
6873
  get expression() {
6874
6874
  return this.#expression;
6875
6875
  }
6876
+ /**
6877
+ * @inheritdoc
6878
+ */
6879
+ get onMount() {
6880
+ return undefined;
6881
+ }
6882
+ /**
6883
+ * @inheritdoc
6884
+ */
6885
+ get onMounted() {
6886
+ return undefined;
6887
+ }
6888
+ /**
6889
+ * @inheritdoc
6890
+ */
6891
+ get onUpdate() {
6892
+ return undefined;
6893
+ }
6894
+ /**
6895
+ * @inheritdoc
6896
+ */
6897
+ get onUpdated() {
6898
+ return undefined;
6899
+ }
6900
+ /**
6901
+ * @inheritdoc
6902
+ */
6903
+ get onUnmount() {
6904
+ return undefined;
6905
+ }
6906
+ /**
6907
+ * @inheritdoc
6908
+ */
6909
+ get onUnmounted() {
6910
+ return undefined;
6911
+ }
6876
6912
  /**
6877
6913
  * @inheritdoc
6878
6914
  */
@@ -7631,6 +7667,11 @@ class VNode {
7631
7667
  * This is optional and may be undefined if there are no dependencies.
7632
7668
  */
7633
7669
  #closers;
7670
+ /**
7671
+ * Indicates whether this node has been templatized by a directive.
7672
+ * This is optional and may be undefined if the node has not been templatized.
7673
+ */
7674
+ #templatized;
7634
7675
  /**
7635
7676
  * Creates an instance of the virtual node.
7636
7677
  * @param args The initialization arguments for the virtual node.
@@ -7644,23 +7685,31 @@ class VNode {
7644
7685
  this.#bindings = args.bindings;
7645
7686
  this.#initDependentIdentifiers = args.dependentIdentifiers;
7646
7687
  this.#parentVNode?.addChild(this);
7647
- // If the node is a text node, check for expressions and create a text evaluator
7648
7688
  if (this.#nodeType === Node.TEXT_NODE) {
7689
+ // If the node is a text node, check for expressions and create a text evaluator
7649
7690
  const text = this.#node;
7650
7691
  // Create a text evaluator if the text contains expressions
7651
7692
  if (VTextEvaluator.containsExpression(text.data)) {
7652
7693
  this.#textEvaluator = new VTextEvaluator(text.data, this.#vApplication.functionDependencies);
7653
7694
  }
7654
7695
  }
7655
- // If the node is an element, initialize directives and child nodes
7656
- if (this.#nodeType === Node.ELEMENT_NODE && this.#node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
7696
+ else if (this.#nodeType === Node.ELEMENT_NODE) {
7697
+ // If the node is an element, initialize directives and child nodes
7657
7698
  this.#node;
7658
7699
  // Initialize child virtual nodes
7659
7700
  this.#childVNodes = [];
7660
7701
  // Initialize directive manager
7661
7702
  this.#directiveManager = new VDirectiveManager(this);
7662
- // For non-v-for elements, recursively create VNode instances for child nodes
7663
- if (!this.#directiveManager.directives?.some(d => d.templatize)) {
7703
+ // Determine if any directive requires template preservation
7704
+ this.#templatized = this.#directiveManager.directives?.some(d => d.templatize) ?? false;
7705
+ // If no directive requires template preservation, call onMount for directives that do not templatize
7706
+ if (!this.#templatized) {
7707
+ this.#directiveManager.directives?.forEach(d => {
7708
+ d.onMount?.();
7709
+ });
7710
+ }
7711
+ // Create child virtual nodes if template preservation is not required
7712
+ if (!this.#templatized) {
7664
7713
  for (const childNode of Array.from(this.#node.childNodes)) {
7665
7714
  new VNode({
7666
7715
  node: childNode,
@@ -7669,11 +7718,18 @@ class VNode {
7669
7718
  });
7670
7719
  }
7671
7720
  }
7721
+ // After creating child nodes, call onMounted for directives that do not templatize
7722
+ if (!this.#templatized) {
7723
+ // animation frame to ensure DOM is updated
7724
+ requestAnimationFrame(() => {
7725
+ this.#directiveManager?.directives?.forEach(d => {
7726
+ d.onMounted?.();
7727
+ });
7728
+ });
7729
+ }
7672
7730
  }
7673
- // If there is a parent virtual node, add this node as a dependency
7674
- if (this.#parentVNode) {
7675
- this.#closers = this.#parentVNode.addDependent(this);
7676
- }
7731
+ // Register this node as a dependent of the parent node, if any
7732
+ this.#closers = this.#parentVNode?.addDependent(this);
7677
7733
  }
7678
7734
  /**
7679
7735
  * The application instance associated with this virtual node.
@@ -7859,8 +7915,8 @@ class VNode {
7859
7915
  */
7860
7916
  update() {
7861
7917
  const changes = this.bindings?.changes || [];
7862
- // If this is a text node with a text evaluator, update its content if needed
7863
7918
  if (this.#nodeType === Node.TEXT_NODE && this.#textEvaluator) {
7919
+ // If this is a text node with a text evaluator, update its content if needed
7864
7920
  // Check if any of the identifiers are in the changed identifiers
7865
7921
  const changed = this.#textEvaluator.identifiers.some(id => changes.includes(id));
7866
7922
  // If the text node has changed, update its content
@@ -7868,38 +7924,52 @@ class VNode {
7868
7924
  const text = this.#node;
7869
7925
  text.data = this.#textEvaluator.evaluate(this.bindings);
7870
7926
  }
7871
- return;
7872
7927
  }
7873
- // Prepare new bindings using directive bindings preparers, if any
7874
- if (this.#directiveManager?.bindingsPreparers) {
7875
- // Ensure local bindings are initialized
7876
- if (!this.#bindings) {
7877
- this.#bindings = new VBindings({ parent: this.bindings });
7928
+ else if (this.#nodeType === Node.ELEMENT_NODE) {
7929
+ // If this is an element node, update directives and child nodes
7930
+ // If no directive requires template preservation, call onUpdate for directives that do not templatize
7931
+ if (!this.#templatized) {
7932
+ this.#directiveManager?.directives?.forEach(d => {
7933
+ d.onUpdate?.();
7934
+ });
7878
7935
  }
7879
- // Prepare bindings for each preparer if relevant identifiers have changed
7880
- for (const preparer of this.#directiveManager.bindingsPreparers) {
7881
- const changed = preparer.dependentIdentifiers.some(id => changes.includes(id));
7882
- if (changed) {
7883
- preparer.prepareBindings();
7936
+ // Prepare new bindings using directive bindings preparers, if any
7937
+ if (this.#directiveManager?.bindingsPreparers) {
7938
+ // Ensure local bindings are initialized
7939
+ if (!this.#bindings) {
7940
+ this.#bindings = new VBindings({ parent: this.bindings });
7941
+ }
7942
+ // Prepare bindings for each preparer if relevant identifiers have changed
7943
+ for (const preparer of this.#directiveManager.bindingsPreparers) {
7944
+ const changed = preparer.dependentIdentifiers.some(id => changes.includes(id));
7945
+ if (changed) {
7946
+ preparer.prepareBindings();
7947
+ }
7884
7948
  }
7885
7949
  }
7886
- }
7887
- // Apply DOM updaters from directives, if any
7888
- if (this.#directiveManager?.domUpdaters) {
7889
- for (const updater of this.#directiveManager.domUpdaters) {
7890
- const changed = updater.dependentIdentifiers.some(id => changes.includes(id));
7950
+ // Apply DOM updaters from directives, if any
7951
+ if (this.#directiveManager?.domUpdaters) {
7952
+ for (const updater of this.#directiveManager.domUpdaters) {
7953
+ const changed = updater.dependentIdentifiers.some(id => changes.includes(id));
7954
+ if (changed) {
7955
+ updater.applyToDOM();
7956
+ }
7957
+ }
7958
+ }
7959
+ // Recursively update dependent virtual nodes
7960
+ this.#dependents?.forEach(dependentNode => {
7961
+ const changed = dependentNode.dependentIdentifiers.some(id => changes.includes(id));
7891
7962
  if (changed) {
7892
- updater.applyToDOM();
7963
+ dependentNode.update();
7893
7964
  }
7965
+ });
7966
+ // If no directive requires template preservation, call onUpdated for directives that do not templatize
7967
+ if (!this.#templatized) {
7968
+ this.#directiveManager?.directives?.forEach(d => {
7969
+ d.onUpdated?.();
7970
+ });
7894
7971
  }
7895
7972
  }
7896
- // Recursively update dependent virtual nodes
7897
- this.#dependents?.forEach(dependentNode => {
7898
- const changed = dependentNode.dependentIdentifiers.some(id => changes.includes(id));
7899
- if (changed) {
7900
- dependentNode.update();
7901
- }
7902
- });
7903
7973
  }
7904
7974
  /**
7905
7975
  * Forces an update of the virtual node and its children, regardless of changed identifiers.
@@ -7908,33 +7978,47 @@ class VNode {
7908
7978
  * This is useful when an immediate update is needed, bypassing the usual change detection.
7909
7979
  */
7910
7980
  forceUpdate() {
7911
- // If this is a text node with a text evaluator, update its content if needed
7912
7981
  if (this.#nodeType === Node.TEXT_NODE && this.#textEvaluator) {
7982
+ // If this is a text node with a text evaluator, update its content if needed
7913
7983
  const text = this.#node;
7914
7984
  text.data = this.#textEvaluator.evaluate(this.bindings);
7915
- return;
7916
7985
  }
7917
- // Prepare new bindings using directive bindings preparers, if any
7918
- if (this.#directiveManager?.bindingsPreparers) {
7919
- // Ensure local bindings are initialized
7920
- if (!this.#bindings) {
7921
- this.#bindings = new VBindings({ parent: this.bindings });
7986
+ else if (this.#nodeType === Node.ELEMENT_NODE) {
7987
+ // If this is an element node, update directives and child nodes
7988
+ // If no directive requires template preservation, call onUpdate for directives that do not templatize
7989
+ if (!this.#templatized) {
7990
+ this.#directiveManager?.directives?.forEach(d => {
7991
+ d.onUpdate?.();
7992
+ });
7922
7993
  }
7923
- // Prepare bindings for each preparer if relevant identifiers have changed
7924
- for (const preparer of this.#directiveManager.bindingsPreparers) {
7925
- preparer.prepareBindings();
7994
+ // Prepare new bindings using directive bindings preparers, if any
7995
+ if (this.#directiveManager?.bindingsPreparers) {
7996
+ // Ensure local bindings are initialized
7997
+ if (!this.#bindings) {
7998
+ this.#bindings = new VBindings({ parent: this.bindings });
7999
+ }
8000
+ // Prepare bindings for each preparer if relevant identifiers have changed
8001
+ for (const preparer of this.#directiveManager.bindingsPreparers) {
8002
+ preparer.prepareBindings();
8003
+ }
7926
8004
  }
7927
- }
7928
- // Apply DOM updaters from directives, if any
7929
- if (this.#directiveManager?.domUpdaters) {
7930
- for (const updater of this.#directiveManager.domUpdaters) {
7931
- updater.applyToDOM();
8005
+ // Apply DOM updaters from directives, if any
8006
+ if (this.#directiveManager?.domUpdaters) {
8007
+ for (const updater of this.#directiveManager.domUpdaters) {
8008
+ updater.applyToDOM();
8009
+ }
8010
+ }
8011
+ // Recursively update child virtual nodes
8012
+ this.#childVNodes?.forEach(childVNode => {
8013
+ childVNode.forceUpdate();
8014
+ });
8015
+ // If no directive requires template preservation, call onUpdated for directives that do not templatize
8016
+ if (!this.#templatized) {
8017
+ this.#directiveManager?.directives?.forEach(d => {
8018
+ d.onUpdated?.();
8019
+ });
7932
8020
  }
7933
8021
  }
7934
- // Recursively update child virtual nodes
7935
- this.#childVNodes?.forEach(childVNode => {
7936
- childVNode.forceUpdate();
7937
- });
7938
8022
  }
7939
8023
  /**
7940
8024
  * Adds a child virtual node to this virtual node.
@@ -8007,6 +8091,12 @@ class VNode {
8007
8091
  * This method is called when the virtual node is no longer needed.
8008
8092
  */
8009
8093
  destroy() {
8094
+ // If no directive requires template preservation, call onUnmount for directives that do not templatize
8095
+ if (!this.#templatized) {
8096
+ this.#directiveManager?.directives?.forEach(d => {
8097
+ d.onUnmount?.();
8098
+ });
8099
+ }
8010
8100
  // Recursively destroy child nodes
8011
8101
  if (this.#childVNodes) {
8012
8102
  for (const childVNode of this.#childVNodes) {
@@ -8031,6 +8121,12 @@ class VNode {
8031
8121
  }
8032
8122
  // Clean up directive handler
8033
8123
  this.#directiveManager?.destroy();
8124
+ // If no directive requires template preservation, call onUnmounted for directives that do not templatize
8125
+ if (!this.#templatized) {
8126
+ this.#directiveManager?.directives?.forEach(d => {
8127
+ d.onUnmounted?.();
8128
+ });
8129
+ }
8034
8130
  }
8035
8131
  }
8036
8132
 
@@ -8198,6 +8294,42 @@ class VConditionalDirective {
8198
8294
  }
8199
8295
  return this.#evaluate();
8200
8296
  }
8297
+ /**
8298
+ * @inheritdoc
8299
+ */
8300
+ get onMount() {
8301
+ return undefined;
8302
+ }
8303
+ /**
8304
+ * @inheritdoc
8305
+ */
8306
+ get onMounted() {
8307
+ return undefined;
8308
+ }
8309
+ /**
8310
+ * @inheritdoc
8311
+ */
8312
+ get onUpdate() {
8313
+ return undefined;
8314
+ }
8315
+ /**
8316
+ * @inheritdoc
8317
+ */
8318
+ get onUpdated() {
8319
+ return undefined;
8320
+ }
8321
+ /**
8322
+ * @inheritdoc
8323
+ */
8324
+ get onUnmount() {
8325
+ return undefined;
8326
+ }
8327
+ /**
8328
+ * @inheritdoc
8329
+ */
8330
+ get onUnmounted() {
8331
+ return undefined;
8332
+ }
8201
8333
  /**
8202
8334
  * @inheritdoc
8203
8335
  */
@@ -8252,8 +8384,10 @@ class VConditionalDirective {
8252
8384
  // Not rendered, no action needed
8253
8385
  return;
8254
8386
  }
8255
- this.#renderedVNode.node.parentNode?.removeChild(this.#renderedVNode.node);
8387
+ // Destroy VNode first (calls @unmount hooks while DOM is still accessible)
8256
8388
  this.#renderedVNode.destroy();
8389
+ // Then remove from DOM
8390
+ this.#renderedVNode.node.parentNode?.removeChild(this.#renderedVNode.node);
8257
8391
  this.#renderedVNode = undefined;
8258
8392
  }
8259
8393
  /**
@@ -8482,16 +8616,56 @@ class VForDirective {
8482
8616
  get dependentIdentifiers() {
8483
8617
  return this.#dependentIdentifiers ?? [];
8484
8618
  }
8619
+ /**
8620
+ * @inheritdoc
8621
+ */
8622
+ get onMount() {
8623
+ return undefined;
8624
+ }
8625
+ /**
8626
+ * @inheritdoc
8627
+ */
8628
+ get onMounted() {
8629
+ return undefined;
8630
+ }
8631
+ /**
8632
+ * @inheritdoc
8633
+ */
8634
+ get onUpdate() {
8635
+ return undefined;
8636
+ }
8637
+ /**
8638
+ * @inheritdoc
8639
+ */
8640
+ get onUpdated() {
8641
+ return undefined;
8642
+ }
8643
+ /**
8644
+ * @inheritdoc
8645
+ */
8646
+ get onUnmount() {
8647
+ return undefined;
8648
+ }
8649
+ /**
8650
+ * @inheritdoc
8651
+ */
8652
+ get onUnmounted() {
8653
+ return undefined;
8654
+ }
8485
8655
  /**
8486
8656
  * @inheritdoc
8487
8657
  */
8488
8658
  destroy() {
8489
8659
  // Clean up all rendered items
8660
+ // First destroy all VNodes (calls @unmount hooks), then remove from DOM
8661
+ for (const vNode of this.#renderedItems.values()) {
8662
+ vNode.destroy();
8663
+ }
8664
+ // Then remove DOM nodes
8490
8665
  for (const vNode of this.#renderedItems.values()) {
8491
8666
  if (vNode.node.parentNode) {
8492
8667
  vNode.node.parentNode.removeChild(vNode.node);
8493
8668
  }
8494
- vNode.destroy();
8495
8669
  }
8496
8670
  this.#renderedItems.clear();
8497
8671
  this.#previousIterations = [];
@@ -8548,14 +8722,20 @@ class VForDirective {
8548
8722
  // Track which keys are still needed
8549
8723
  const neededKeys = new Set(newIterations.map(ctx => ctx.key));
8550
8724
  // Remove items that are no longer needed
8725
+ // First destroy VNodes (calls @unmount hooks while DOM is still accessible)
8726
+ const nodesToRemove = [];
8551
8727
  for (const [key, vNode] of this.#renderedItems) {
8552
8728
  if (!neededKeys.has(key)) {
8553
- if (vNode.node.parentNode) {
8554
- vNode.node.parentNode.removeChild(vNode.node);
8555
- }
8729
+ nodesToRemove.push(vNode);
8556
8730
  vNode.destroy();
8557
8731
  }
8558
8732
  }
8733
+ // Then remove from DOM
8734
+ for (const vNode of nodesToRemove) {
8735
+ if (vNode.node.parentNode) {
8736
+ vNode.node.parentNode.removeChild(vNode.node);
8737
+ }
8738
+ }
8559
8739
  // Add or reorder items
8560
8740
  let prevNode = anchor;
8561
8741
  for (const context of newIterations) {
@@ -8868,6 +9048,42 @@ class VModelDirective {
8868
9048
  get dependentIdentifiers() {
8869
9049
  return this.#dependentIdentifiers ?? [];
8870
9050
  }
9051
+ /**
9052
+ * @inheritdoc
9053
+ */
9054
+ get onMount() {
9055
+ return undefined;
9056
+ }
9057
+ /**
9058
+ * @inheritdoc
9059
+ */
9060
+ get onMounted() {
9061
+ return undefined;
9062
+ }
9063
+ /**
9064
+ * @inheritdoc
9065
+ */
9066
+ get onUpdate() {
9067
+ return undefined;
9068
+ }
9069
+ /**
9070
+ * @inheritdoc
9071
+ */
9072
+ get onUpdated() {
9073
+ return undefined;
9074
+ }
9075
+ /**
9076
+ * @inheritdoc
9077
+ */
9078
+ get onUnmount() {
9079
+ return undefined;
9080
+ }
9081
+ /**
9082
+ * @inheritdoc
9083
+ */
9084
+ get onUnmounted() {
9085
+ return undefined;
9086
+ }
8871
9087
  /**
8872
9088
  * @inheritdoc
8873
9089
  */
@@ -9027,7 +9243,7 @@ class VModelDirective {
9027
9243
 
9028
9244
  // Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
9029
9245
  /**
9030
- * Directive for binding event listeners to DOM elements.
9246
+ * Directive for binding event listeners to DOM elements and lifecycle hooks.
9031
9247
  * The `v-on` directive allows you to listen to DOM events and execute specified methods when those events are triggered.
9032
9248
  * The syntax for using the `v-on` directive is `v-on:event="methodName"`, where `event` is the name of the event to listen for (e.g., `click`, `mouseover`, etc.), and `methodName` is the name of the method to be called when the event occurs.
9033
9249
  * Example usage:
@@ -9036,7 +9252,16 @@ class VModelDirective {
9036
9252
  * You can also use the shorthand `@event` instead of `v-on:event`. For example, `@click="handleClick"` is equivalent to `v-on:click="handleClick"`.
9037
9253
  * The `v-on` directive supports event modifiers such as `.stop`, `.prevent`, `.capture`, `.self`, and `.once` to modify the behavior of the event listener.
9038
9254
  * For example, `v-on:click.stop="handleClick"` will stop the event from propagating up the DOM tree.
9039
- * This directive is essential for handling user interactions in your application.
9255
+ *
9256
+ * Additionally, this directive supports lifecycle hooks:
9257
+ * @mount="onMount" - Called before the element is inserted into the DOM
9258
+ * @mounted="onMounted" - Called after the element is inserted into the DOM
9259
+ * @update="onUpdate" - Called before the element is updated
9260
+ * @updated="onUpdated" - Called after the element is updated
9261
+ * @unmount="onUnmount" - Called before the element is removed from the DOM
9262
+ * @unmounted="onUnmounted" - Called after the element is removed from the DOM
9263
+ *
9264
+ * This directive is essential for handling user interactions and lifecycle events in your application.
9040
9265
  * Note that the methods referenced in the directive should be defined in the component's methods object.
9041
9266
  */
9042
9267
  class VOnDirective {
@@ -9050,10 +9275,12 @@ class VOnDirective {
9050
9275
  #dependentIdentifiers;
9051
9276
  /**
9052
9277
  * The event handler wrapper function, generated once and reused.
9278
+ * For lifecycle hooks, this is a no-argument function.
9279
+ * For DOM events, this accepts an Event parameter.
9053
9280
  */
9054
9281
  #handlerWrapper;
9055
9282
  /**
9056
- * The event name (e.g., "click", "input", "keydown").
9283
+ * The event name (e.g., "click", "input", "keydown") or lifecycle hook name (e.g., "mount", "mounted").
9057
9284
  */
9058
9285
  #eventName;
9059
9286
  /**
@@ -9061,9 +9288,13 @@ class VOnDirective {
9061
9288
  */
9062
9289
  #modifiers = new Set();
9063
9290
  /**
9064
- * The event listener function.
9291
+ * The event listener function for DOM events.
9065
9292
  */
9066
9293
  #listener;
9294
+ /**
9295
+ * Map of lifecycle hook names to their handler functions.
9296
+ */
9297
+ #lifecycleHooks = new Map();
9067
9298
  /**
9068
9299
  * @param context The context for parsing the directive.
9069
9300
  */
@@ -9087,10 +9318,22 @@ class VOnDirective {
9087
9318
  const expression = context.attribute.value;
9088
9319
  if (expression) {
9089
9320
  this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
9090
- this.#handlerWrapper = this.#createHandlerWrapper(expression);
9091
9321
  }
9092
- // Create and attach the event listener
9093
- if (this.#eventName) {
9322
+ // Check if this is a lifecycle hook or a regular event
9323
+ if (this.#eventName && this.#isLifecycleHook(this.#eventName)) {
9324
+ // Create handler wrapper for lifecycle hook (no event parameter)
9325
+ if (expression) {
9326
+ const handler = this.#createLifecycleHandlerWrapper(expression);
9327
+ this.#handlerWrapper = handler;
9328
+ this.#lifecycleHooks.set(this.#eventName, handler);
9329
+ }
9330
+ }
9331
+ else if (this.#eventName) {
9332
+ // Create handler wrapper for DOM event (with event parameter)
9333
+ if (expression) {
9334
+ this.#handlerWrapper = this.#createEventHandlerWrapper(expression);
9335
+ }
9336
+ // Create and attach DOM event listener
9094
9337
  this.#attachEventListener();
9095
9338
  }
9096
9339
  // Remove the directive attribute from the element
@@ -9138,6 +9381,42 @@ class VOnDirective {
9138
9381
  get dependentIdentifiers() {
9139
9382
  return this.#dependentIdentifiers ?? [];
9140
9383
  }
9384
+ /**
9385
+ * @inheritdoc
9386
+ */
9387
+ get onMount() {
9388
+ return this.#lifecycleHooks.get('mount');
9389
+ }
9390
+ /**
9391
+ * @inheritdoc
9392
+ */
9393
+ get onMounted() {
9394
+ return this.#lifecycleHooks.get('mounted');
9395
+ }
9396
+ /**
9397
+ * @inheritdoc
9398
+ */
9399
+ get onUpdate() {
9400
+ return this.#lifecycleHooks.get('update');
9401
+ }
9402
+ /**
9403
+ * @inheritdoc
9404
+ */
9405
+ get onUpdated() {
9406
+ return this.#lifecycleHooks.get('updated');
9407
+ }
9408
+ /**
9409
+ * @inheritdoc
9410
+ */
9411
+ get onUnmount() {
9412
+ return this.#lifecycleHooks.get('unmount');
9413
+ }
9414
+ /**
9415
+ * @inheritdoc
9416
+ */
9417
+ get onUnmounted() {
9418
+ return this.#lifecycleHooks.get('unmounted');
9419
+ }
9141
9420
  /**
9142
9421
  * @inheritdoc
9143
9422
  */
@@ -9214,11 +9493,48 @@ class VOnDirective {
9214
9493
  element.addEventListener(eventName, this.#listener, useCapture);
9215
9494
  }
9216
9495
  /**
9217
- * Creates a wrapper function for the event handler, generated once and reused.
9496
+ * Checks if the event name is a lifecycle hook.
9497
+ * @param eventName The event name to check.
9498
+ * @returns True if the event name is a lifecycle hook, false otherwise.
9499
+ */
9500
+ #isLifecycleHook(eventName) {
9501
+ return ['mount', 'mounted', 'update', 'updated', 'unmount', 'unmounted'].includes(eventName);
9502
+ }
9503
+ /**
9504
+ * Creates a wrapper function for lifecycle hooks (with element parameter).
9505
+ * @param expression The expression string to evaluate.
9506
+ * @returns A function that handles the lifecycle hook.
9507
+ */
9508
+ #createLifecycleHandlerWrapper(expression) {
9509
+ const identifiers = this.#dependentIdentifiers ?? [];
9510
+ const vNode = this.#vNode;
9511
+ // Return a function that handles the lifecycle hook with proper scope
9512
+ return () => {
9513
+ const bindings = vNode.bindings;
9514
+ const el = vNode.node;
9515
+ // If the expression is just a method name, call it with bindings as 'this'
9516
+ const trimmedExpr = expression.trim();
9517
+ if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
9518
+ const methodName = trimmedExpr;
9519
+ const originalMethod = bindings?.get(methodName);
9520
+ // Call the method with bindings as 'this' context and element as parameter
9521
+ // This allows the method to access the DOM element and bindings
9522
+ return originalMethod(el);
9523
+ }
9524
+ // For inline expressions, evaluate normally with element parameter
9525
+ const values = identifiers.map(id => vNode.bindings?.get(id));
9526
+ const args = [...identifiers, 'el'].join(", ");
9527
+ const funcBody = `return (${expression});`;
9528
+ const func = new Function(args, funcBody);
9529
+ return func.call(bindings?.raw, ...values, el);
9530
+ };
9531
+ }
9532
+ /**
9533
+ * Creates a wrapper function for DOM event handlers (with event parameter).
9218
9534
  * @param expression The expression string to evaluate.
9219
9535
  * @returns A function that handles the event.
9220
9536
  */
9221
- #createHandlerWrapper(expression) {
9537
+ #createEventHandlerWrapper(expression) {
9222
9538
  const identifiers = this.#dependentIdentifiers ?? [];
9223
9539
  const vNode = this.#vNode;
9224
9540
  // Return a function that handles the event with proper scope
@@ -9377,6 +9693,42 @@ class VShowDirective {
9377
9693
  // Hide the element
9378
9694
  element.style.display = "none";
9379
9695
  }
9696
+ /**
9697
+ * @inheritdoc
9698
+ */
9699
+ get onMount() {
9700
+ return undefined;
9701
+ }
9702
+ /**
9703
+ * @inheritdoc
9704
+ */
9705
+ get onMounted() {
9706
+ return undefined;
9707
+ }
9708
+ /**
9709
+ * @inheritdoc
9710
+ */
9711
+ get onUpdate() {
9712
+ return undefined;
9713
+ }
9714
+ /**
9715
+ * @inheritdoc
9716
+ */
9717
+ get onUpdated() {
9718
+ return undefined;
9719
+ }
9720
+ /**
9721
+ * @inheritdoc
9722
+ */
9723
+ get onUnmount() {
9724
+ return undefined;
9725
+ }
9726
+ /**
9727
+ * @inheritdoc
9728
+ */
9729
+ get onUnmounted() {
9730
+ return undefined;
9731
+ }
9380
9732
  /**
9381
9733
  * @inheritdoc
9382
9734
  */