@mintjamsinc/ichigojs 0.1.3 → 0.1.5
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 +75 -1
- package/dist/ichigo.esm.js +419 -67
- 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 +419 -67
- 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/VBindDirective.d.ts +24 -0
- package/dist/types/ichigo/directives/VConditionalDirective.d.ts +24 -0
- package/dist/types/ichigo/directives/VDirective.d.ts +30 -0
- package/dist/types/ichigo/directives/VForDirective.d.ts +24 -0
- package/dist/types/ichigo/directives/VModelDirective.d.ts +24 -0
- package/dist/types/ichigo/directives/VOnDirective.d.ts +35 -2
- package/dist/types/ichigo/directives/VShowDirective.d.ts +24 -0
- package/package.json +1 -1
package/dist/ichigo.umd.js
CHANGED
@@ -6879,6 +6879,42 @@
|
|
6879
6879
|
get expression() {
|
6880
6880
|
return this.#expression;
|
6881
6881
|
}
|
6882
|
+
/**
|
6883
|
+
* @inheritdoc
|
6884
|
+
*/
|
6885
|
+
get onMount() {
|
6886
|
+
return undefined;
|
6887
|
+
}
|
6888
|
+
/**
|
6889
|
+
* @inheritdoc
|
6890
|
+
*/
|
6891
|
+
get onMounted() {
|
6892
|
+
return undefined;
|
6893
|
+
}
|
6894
|
+
/**
|
6895
|
+
* @inheritdoc
|
6896
|
+
*/
|
6897
|
+
get onUpdate() {
|
6898
|
+
return undefined;
|
6899
|
+
}
|
6900
|
+
/**
|
6901
|
+
* @inheritdoc
|
6902
|
+
*/
|
6903
|
+
get onUpdated() {
|
6904
|
+
return undefined;
|
6905
|
+
}
|
6906
|
+
/**
|
6907
|
+
* @inheritdoc
|
6908
|
+
*/
|
6909
|
+
get onUnmount() {
|
6910
|
+
return undefined;
|
6911
|
+
}
|
6912
|
+
/**
|
6913
|
+
* @inheritdoc
|
6914
|
+
*/
|
6915
|
+
get onUnmounted() {
|
6916
|
+
return undefined;
|
6917
|
+
}
|
6882
6918
|
/**
|
6883
6919
|
* @inheritdoc
|
6884
6920
|
*/
|
@@ -7637,6 +7673,11 @@
|
|
7637
7673
|
* This is optional and may be undefined if there are no dependencies.
|
7638
7674
|
*/
|
7639
7675
|
#closers;
|
7676
|
+
/**
|
7677
|
+
* Indicates whether this node has been templatized by a directive.
|
7678
|
+
* This is optional and may be undefined if the node has not been templatized.
|
7679
|
+
*/
|
7680
|
+
#templatized;
|
7640
7681
|
/**
|
7641
7682
|
* Creates an instance of the virtual node.
|
7642
7683
|
* @param args The initialization arguments for the virtual node.
|
@@ -7650,23 +7691,31 @@
|
|
7650
7691
|
this.#bindings = args.bindings;
|
7651
7692
|
this.#initDependentIdentifiers = args.dependentIdentifiers;
|
7652
7693
|
this.#parentVNode?.addChild(this);
|
7653
|
-
// If the node is a text node, check for expressions and create a text evaluator
|
7654
7694
|
if (this.#nodeType === Node.TEXT_NODE) {
|
7695
|
+
// If the node is a text node, check for expressions and create a text evaluator
|
7655
7696
|
const text = this.#node;
|
7656
7697
|
// Create a text evaluator if the text contains expressions
|
7657
7698
|
if (VTextEvaluator.containsExpression(text.data)) {
|
7658
7699
|
this.#textEvaluator = new VTextEvaluator(text.data, this.#vApplication.functionDependencies);
|
7659
7700
|
}
|
7660
7701
|
}
|
7661
|
-
|
7662
|
-
|
7702
|
+
else if (this.#nodeType === Node.ELEMENT_NODE) {
|
7703
|
+
// If the node is an element, initialize directives and child nodes
|
7663
7704
|
this.#node;
|
7664
7705
|
// Initialize child virtual nodes
|
7665
7706
|
this.#childVNodes = [];
|
7666
7707
|
// Initialize directive manager
|
7667
7708
|
this.#directiveManager = new VDirectiveManager(this);
|
7668
|
-
//
|
7669
|
-
|
7709
|
+
// Determine if any directive requires template preservation
|
7710
|
+
this.#templatized = this.#directiveManager.directives?.some(d => d.templatize) ?? false;
|
7711
|
+
// If no directive requires template preservation, call onMount for directives that do not templatize
|
7712
|
+
if (!this.#templatized) {
|
7713
|
+
this.#directiveManager.directives?.forEach(d => {
|
7714
|
+
d.onMount?.();
|
7715
|
+
});
|
7716
|
+
}
|
7717
|
+
// Create child virtual nodes if template preservation is not required
|
7718
|
+
if (!this.#templatized) {
|
7670
7719
|
for (const childNode of Array.from(this.#node.childNodes)) {
|
7671
7720
|
new VNode({
|
7672
7721
|
node: childNode,
|
@@ -7675,11 +7724,18 @@
|
|
7675
7724
|
});
|
7676
7725
|
}
|
7677
7726
|
}
|
7727
|
+
// After creating child nodes, call onMounted for directives that do not templatize
|
7728
|
+
if (!this.#templatized) {
|
7729
|
+
// animation frame to ensure DOM is updated
|
7730
|
+
requestAnimationFrame(() => {
|
7731
|
+
this.#directiveManager?.directives?.forEach(d => {
|
7732
|
+
d.onMounted?.();
|
7733
|
+
});
|
7734
|
+
});
|
7735
|
+
}
|
7678
7736
|
}
|
7679
|
-
//
|
7680
|
-
|
7681
|
-
this.#closers = this.#parentVNode.addDependent(this);
|
7682
|
-
}
|
7737
|
+
// Register this node as a dependent of the parent node, if any
|
7738
|
+
this.#closers = this.#parentVNode?.addDependent(this);
|
7683
7739
|
}
|
7684
7740
|
/**
|
7685
7741
|
* The application instance associated with this virtual node.
|
@@ -7865,8 +7921,8 @@
|
|
7865
7921
|
*/
|
7866
7922
|
update() {
|
7867
7923
|
const changes = this.bindings?.changes || [];
|
7868
|
-
// If this is a text node with a text evaluator, update its content if needed
|
7869
7924
|
if (this.#nodeType === Node.TEXT_NODE && this.#textEvaluator) {
|
7925
|
+
// If this is a text node with a text evaluator, update its content if needed
|
7870
7926
|
// Check if any of the identifiers are in the changed identifiers
|
7871
7927
|
const changed = this.#textEvaluator.identifiers.some(id => changes.includes(id));
|
7872
7928
|
// If the text node has changed, update its content
|
@@ -7874,38 +7930,52 @@
|
|
7874
7930
|
const text = this.#node;
|
7875
7931
|
text.data = this.#textEvaluator.evaluate(this.bindings);
|
7876
7932
|
}
|
7877
|
-
return;
|
7878
7933
|
}
|
7879
|
-
|
7880
|
-
|
7881
|
-
//
|
7882
|
-
if (!this.#
|
7883
|
-
this.#
|
7934
|
+
else if (this.#nodeType === Node.ELEMENT_NODE) {
|
7935
|
+
// If this is an element node, update directives and child nodes
|
7936
|
+
// If no directive requires template preservation, call onUpdate for directives that do not templatize
|
7937
|
+
if (!this.#templatized) {
|
7938
|
+
this.#directiveManager?.directives?.forEach(d => {
|
7939
|
+
d.onUpdate?.();
|
7940
|
+
});
|
7884
7941
|
}
|
7885
|
-
// Prepare bindings
|
7886
|
-
|
7887
|
-
|
7888
|
-
if (
|
7889
|
-
|
7942
|
+
// Prepare new bindings using directive bindings preparers, if any
|
7943
|
+
if (this.#directiveManager?.bindingsPreparers) {
|
7944
|
+
// Ensure local bindings are initialized
|
7945
|
+
if (!this.#bindings) {
|
7946
|
+
this.#bindings = new VBindings({ parent: this.bindings });
|
7947
|
+
}
|
7948
|
+
// Prepare bindings for each preparer if relevant identifiers have changed
|
7949
|
+
for (const preparer of this.#directiveManager.bindingsPreparers) {
|
7950
|
+
const changed = preparer.dependentIdentifiers.some(id => changes.includes(id));
|
7951
|
+
if (changed) {
|
7952
|
+
preparer.prepareBindings();
|
7953
|
+
}
|
7890
7954
|
}
|
7891
7955
|
}
|
7892
|
-
|
7893
|
-
|
7894
|
-
|
7895
|
-
|
7896
|
-
|
7956
|
+
// Apply DOM updaters from directives, if any
|
7957
|
+
if (this.#directiveManager?.domUpdaters) {
|
7958
|
+
for (const updater of this.#directiveManager.domUpdaters) {
|
7959
|
+
const changed = updater.dependentIdentifiers.some(id => changes.includes(id));
|
7960
|
+
if (changed) {
|
7961
|
+
updater.applyToDOM();
|
7962
|
+
}
|
7963
|
+
}
|
7964
|
+
}
|
7965
|
+
// Recursively update dependent virtual nodes
|
7966
|
+
this.#dependents?.forEach(dependentNode => {
|
7967
|
+
const changed = dependentNode.dependentIdentifiers.some(id => changes.includes(id));
|
7897
7968
|
if (changed) {
|
7898
|
-
|
7969
|
+
dependentNode.update();
|
7899
7970
|
}
|
7971
|
+
});
|
7972
|
+
// If no directive requires template preservation, call onUpdated for directives that do not templatize
|
7973
|
+
if (!this.#templatized) {
|
7974
|
+
this.#directiveManager?.directives?.forEach(d => {
|
7975
|
+
d.onUpdated?.();
|
7976
|
+
});
|
7900
7977
|
}
|
7901
7978
|
}
|
7902
|
-
// Recursively update dependent virtual nodes
|
7903
|
-
this.#dependents?.forEach(dependentNode => {
|
7904
|
-
const changed = dependentNode.dependentIdentifiers.some(id => changes.includes(id));
|
7905
|
-
if (changed) {
|
7906
|
-
dependentNode.update();
|
7907
|
-
}
|
7908
|
-
});
|
7909
7979
|
}
|
7910
7980
|
/**
|
7911
7981
|
* Forces an update of the virtual node and its children, regardless of changed identifiers.
|
@@ -7914,33 +7984,47 @@
|
|
7914
7984
|
* This is useful when an immediate update is needed, bypassing the usual change detection.
|
7915
7985
|
*/
|
7916
7986
|
forceUpdate() {
|
7917
|
-
// If this is a text node with a text evaluator, update its content if needed
|
7918
7987
|
if (this.#nodeType === Node.TEXT_NODE && this.#textEvaluator) {
|
7988
|
+
// If this is a text node with a text evaluator, update its content if needed
|
7919
7989
|
const text = this.#node;
|
7920
7990
|
text.data = this.#textEvaluator.evaluate(this.bindings);
|
7921
|
-
return;
|
7922
7991
|
}
|
7923
|
-
|
7924
|
-
|
7925
|
-
//
|
7926
|
-
if (!this.#
|
7927
|
-
this.#
|
7992
|
+
else if (this.#nodeType === Node.ELEMENT_NODE) {
|
7993
|
+
// If this is an element node, update directives and child nodes
|
7994
|
+
// If no directive requires template preservation, call onUpdate for directives that do not templatize
|
7995
|
+
if (!this.#templatized) {
|
7996
|
+
this.#directiveManager?.directives?.forEach(d => {
|
7997
|
+
d.onUpdate?.();
|
7998
|
+
});
|
7928
7999
|
}
|
7929
|
-
// Prepare bindings
|
7930
|
-
|
7931
|
-
|
8000
|
+
// Prepare new bindings using directive bindings preparers, if any
|
8001
|
+
if (this.#directiveManager?.bindingsPreparers) {
|
8002
|
+
// Ensure local bindings are initialized
|
8003
|
+
if (!this.#bindings) {
|
8004
|
+
this.#bindings = new VBindings({ parent: this.bindings });
|
8005
|
+
}
|
8006
|
+
// Prepare bindings for each preparer if relevant identifiers have changed
|
8007
|
+
for (const preparer of this.#directiveManager.bindingsPreparers) {
|
8008
|
+
preparer.prepareBindings();
|
8009
|
+
}
|
7932
8010
|
}
|
7933
|
-
|
7934
|
-
|
7935
|
-
|
7936
|
-
|
7937
|
-
|
8011
|
+
// Apply DOM updaters from directives, if any
|
8012
|
+
if (this.#directiveManager?.domUpdaters) {
|
8013
|
+
for (const updater of this.#directiveManager.domUpdaters) {
|
8014
|
+
updater.applyToDOM();
|
8015
|
+
}
|
8016
|
+
}
|
8017
|
+
// Recursively update child virtual nodes
|
8018
|
+
this.#childVNodes?.forEach(childVNode => {
|
8019
|
+
childVNode.forceUpdate();
|
8020
|
+
});
|
8021
|
+
// If no directive requires template preservation, call onUpdated for directives that do not templatize
|
8022
|
+
if (!this.#templatized) {
|
8023
|
+
this.#directiveManager?.directives?.forEach(d => {
|
8024
|
+
d.onUpdated?.();
|
8025
|
+
});
|
7938
8026
|
}
|
7939
8027
|
}
|
7940
|
-
// Recursively update child virtual nodes
|
7941
|
-
this.#childVNodes?.forEach(childVNode => {
|
7942
|
-
childVNode.forceUpdate();
|
7943
|
-
});
|
7944
8028
|
}
|
7945
8029
|
/**
|
7946
8030
|
* Adds a child virtual node to this virtual node.
|
@@ -8013,6 +8097,12 @@
|
|
8013
8097
|
* This method is called when the virtual node is no longer needed.
|
8014
8098
|
*/
|
8015
8099
|
destroy() {
|
8100
|
+
// If no directive requires template preservation, call onUnmount for directives that do not templatize
|
8101
|
+
if (!this.#templatized) {
|
8102
|
+
this.#directiveManager?.directives?.forEach(d => {
|
8103
|
+
d.onUnmount?.();
|
8104
|
+
});
|
8105
|
+
}
|
8016
8106
|
// Recursively destroy child nodes
|
8017
8107
|
if (this.#childVNodes) {
|
8018
8108
|
for (const childVNode of this.#childVNodes) {
|
@@ -8037,6 +8127,12 @@
|
|
8037
8127
|
}
|
8038
8128
|
// Clean up directive handler
|
8039
8129
|
this.#directiveManager?.destroy();
|
8130
|
+
// If no directive requires template preservation, call onUnmounted for directives that do not templatize
|
8131
|
+
if (!this.#templatized) {
|
8132
|
+
this.#directiveManager?.directives?.forEach(d => {
|
8133
|
+
d.onUnmounted?.();
|
8134
|
+
});
|
8135
|
+
}
|
8040
8136
|
}
|
8041
8137
|
}
|
8042
8138
|
|
@@ -8204,6 +8300,42 @@
|
|
8204
8300
|
}
|
8205
8301
|
return this.#evaluate();
|
8206
8302
|
}
|
8303
|
+
/**
|
8304
|
+
* @inheritdoc
|
8305
|
+
*/
|
8306
|
+
get onMount() {
|
8307
|
+
return undefined;
|
8308
|
+
}
|
8309
|
+
/**
|
8310
|
+
* @inheritdoc
|
8311
|
+
*/
|
8312
|
+
get onMounted() {
|
8313
|
+
return undefined;
|
8314
|
+
}
|
8315
|
+
/**
|
8316
|
+
* @inheritdoc
|
8317
|
+
*/
|
8318
|
+
get onUpdate() {
|
8319
|
+
return undefined;
|
8320
|
+
}
|
8321
|
+
/**
|
8322
|
+
* @inheritdoc
|
8323
|
+
*/
|
8324
|
+
get onUpdated() {
|
8325
|
+
return undefined;
|
8326
|
+
}
|
8327
|
+
/**
|
8328
|
+
* @inheritdoc
|
8329
|
+
*/
|
8330
|
+
get onUnmount() {
|
8331
|
+
return undefined;
|
8332
|
+
}
|
8333
|
+
/**
|
8334
|
+
* @inheritdoc
|
8335
|
+
*/
|
8336
|
+
get onUnmounted() {
|
8337
|
+
return undefined;
|
8338
|
+
}
|
8207
8339
|
/**
|
8208
8340
|
* @inheritdoc
|
8209
8341
|
*/
|
@@ -8258,8 +8390,10 @@
|
|
8258
8390
|
// Not rendered, no action needed
|
8259
8391
|
return;
|
8260
8392
|
}
|
8261
|
-
|
8393
|
+
// Destroy VNode first (calls @unmount hooks while DOM is still accessible)
|
8262
8394
|
this.#renderedVNode.destroy();
|
8395
|
+
// Then remove from DOM
|
8396
|
+
this.#renderedVNode.node.parentNode?.removeChild(this.#renderedVNode.node);
|
8263
8397
|
this.#renderedVNode = undefined;
|
8264
8398
|
}
|
8265
8399
|
/**
|
@@ -8488,16 +8622,56 @@
|
|
8488
8622
|
get dependentIdentifiers() {
|
8489
8623
|
return this.#dependentIdentifiers ?? [];
|
8490
8624
|
}
|
8625
|
+
/**
|
8626
|
+
* @inheritdoc
|
8627
|
+
*/
|
8628
|
+
get onMount() {
|
8629
|
+
return undefined;
|
8630
|
+
}
|
8631
|
+
/**
|
8632
|
+
* @inheritdoc
|
8633
|
+
*/
|
8634
|
+
get onMounted() {
|
8635
|
+
return undefined;
|
8636
|
+
}
|
8637
|
+
/**
|
8638
|
+
* @inheritdoc
|
8639
|
+
*/
|
8640
|
+
get onUpdate() {
|
8641
|
+
return undefined;
|
8642
|
+
}
|
8643
|
+
/**
|
8644
|
+
* @inheritdoc
|
8645
|
+
*/
|
8646
|
+
get onUpdated() {
|
8647
|
+
return undefined;
|
8648
|
+
}
|
8649
|
+
/**
|
8650
|
+
* @inheritdoc
|
8651
|
+
*/
|
8652
|
+
get onUnmount() {
|
8653
|
+
return undefined;
|
8654
|
+
}
|
8655
|
+
/**
|
8656
|
+
* @inheritdoc
|
8657
|
+
*/
|
8658
|
+
get onUnmounted() {
|
8659
|
+
return undefined;
|
8660
|
+
}
|
8491
8661
|
/**
|
8492
8662
|
* @inheritdoc
|
8493
8663
|
*/
|
8494
8664
|
destroy() {
|
8495
8665
|
// Clean up all rendered items
|
8666
|
+
// First destroy all VNodes (calls @unmount hooks), then remove from DOM
|
8667
|
+
for (const vNode of this.#renderedItems.values()) {
|
8668
|
+
vNode.destroy();
|
8669
|
+
}
|
8670
|
+
// Then remove DOM nodes
|
8496
8671
|
for (const vNode of this.#renderedItems.values()) {
|
8497
8672
|
if (vNode.node.parentNode) {
|
8498
8673
|
vNode.node.parentNode.removeChild(vNode.node);
|
8499
8674
|
}
|
8500
|
-
vNode.destroy();
|
8501
8675
|
}
|
8502
8676
|
this.#renderedItems.clear();
|
8503
8677
|
this.#previousIterations = [];
|
@@ -8554,14 +8728,20 @@
|
|
8554
8728
|
// Track which keys are still needed
|
8555
8729
|
const neededKeys = new Set(newIterations.map(ctx => ctx.key));
|
8556
8730
|
// Remove items that are no longer needed
|
8731
|
+
// First destroy VNodes (calls @unmount hooks while DOM is still accessible)
|
8732
|
+
const nodesToRemove = [];
|
8557
8733
|
for (const [key, vNode] of this.#renderedItems) {
|
8558
8734
|
if (!neededKeys.has(key)) {
|
8559
|
-
|
8560
|
-
vNode.node.parentNode.removeChild(vNode.node);
|
8561
|
-
}
|
8735
|
+
nodesToRemove.push(vNode);
|
8562
8736
|
vNode.destroy();
|
8563
8737
|
}
|
8564
8738
|
}
|
8739
|
+
// Then remove from DOM
|
8740
|
+
for (const vNode of nodesToRemove) {
|
8741
|
+
if (vNode.node.parentNode) {
|
8742
|
+
vNode.node.parentNode.removeChild(vNode.node);
|
8743
|
+
}
|
8744
|
+
}
|
8565
8745
|
// Add or reorder items
|
8566
8746
|
let prevNode = anchor;
|
8567
8747
|
for (const context of newIterations) {
|
@@ -8874,6 +9054,42 @@
|
|
8874
9054
|
get dependentIdentifiers() {
|
8875
9055
|
return this.#dependentIdentifiers ?? [];
|
8876
9056
|
}
|
9057
|
+
/**
|
9058
|
+
* @inheritdoc
|
9059
|
+
*/
|
9060
|
+
get onMount() {
|
9061
|
+
return undefined;
|
9062
|
+
}
|
9063
|
+
/**
|
9064
|
+
* @inheritdoc
|
9065
|
+
*/
|
9066
|
+
get onMounted() {
|
9067
|
+
return undefined;
|
9068
|
+
}
|
9069
|
+
/**
|
9070
|
+
* @inheritdoc
|
9071
|
+
*/
|
9072
|
+
get onUpdate() {
|
9073
|
+
return undefined;
|
9074
|
+
}
|
9075
|
+
/**
|
9076
|
+
* @inheritdoc
|
9077
|
+
*/
|
9078
|
+
get onUpdated() {
|
9079
|
+
return undefined;
|
9080
|
+
}
|
9081
|
+
/**
|
9082
|
+
* @inheritdoc
|
9083
|
+
*/
|
9084
|
+
get onUnmount() {
|
9085
|
+
return undefined;
|
9086
|
+
}
|
9087
|
+
/**
|
9088
|
+
* @inheritdoc
|
9089
|
+
*/
|
9090
|
+
get onUnmounted() {
|
9091
|
+
return undefined;
|
9092
|
+
}
|
8877
9093
|
/**
|
8878
9094
|
* @inheritdoc
|
8879
9095
|
*/
|
@@ -9033,7 +9249,7 @@
|
|
9033
9249
|
|
9034
9250
|
// Copyright (c) 2025 MintJams Inc. Licensed under MIT License.
|
9035
9251
|
/**
|
9036
|
-
* Directive for binding event listeners to DOM elements.
|
9252
|
+
* Directive for binding event listeners to DOM elements and lifecycle hooks.
|
9037
9253
|
* The `v-on` directive allows you to listen to DOM events and execute specified methods when those events are triggered.
|
9038
9254
|
* 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.
|
9039
9255
|
* Example usage:
|
@@ -9042,7 +9258,16 @@
|
|
9042
9258
|
* You can also use the shorthand `@event` instead of `v-on:event`. For example, `@click="handleClick"` is equivalent to `v-on:click="handleClick"`.
|
9043
9259
|
* The `v-on` directive supports event modifiers such as `.stop`, `.prevent`, `.capture`, `.self`, and `.once` to modify the behavior of the event listener.
|
9044
9260
|
* For example, `v-on:click.stop="handleClick"` will stop the event from propagating up the DOM tree.
|
9045
|
-
*
|
9261
|
+
*
|
9262
|
+
* Additionally, this directive supports lifecycle hooks:
|
9263
|
+
* @mount="onMount" - Called before the element is inserted into the DOM
|
9264
|
+
* @mounted="onMounted" - Called after the element is inserted into the DOM
|
9265
|
+
* @update="onUpdate" - Called before the element is updated
|
9266
|
+
* @updated="onUpdated" - Called after the element is updated
|
9267
|
+
* @unmount="onUnmount" - Called before the element is removed from the DOM
|
9268
|
+
* @unmounted="onUnmounted" - Called after the element is removed from the DOM
|
9269
|
+
*
|
9270
|
+
* This directive is essential for handling user interactions and lifecycle events in your application.
|
9046
9271
|
* Note that the methods referenced in the directive should be defined in the component's methods object.
|
9047
9272
|
*/
|
9048
9273
|
class VOnDirective {
|
@@ -9056,10 +9281,12 @@
|
|
9056
9281
|
#dependentIdentifiers;
|
9057
9282
|
/**
|
9058
9283
|
* The event handler wrapper function, generated once and reused.
|
9284
|
+
* For lifecycle hooks, this is a no-argument function.
|
9285
|
+
* For DOM events, this accepts an Event parameter.
|
9059
9286
|
*/
|
9060
9287
|
#handlerWrapper;
|
9061
9288
|
/**
|
9062
|
-
* The event name (e.g., "click", "input", "keydown").
|
9289
|
+
* The event name (e.g., "click", "input", "keydown") or lifecycle hook name (e.g., "mount", "mounted").
|
9063
9290
|
*/
|
9064
9291
|
#eventName;
|
9065
9292
|
/**
|
@@ -9067,9 +9294,13 @@
|
|
9067
9294
|
*/
|
9068
9295
|
#modifiers = new Set();
|
9069
9296
|
/**
|
9070
|
-
* The event listener function.
|
9297
|
+
* The event listener function for DOM events.
|
9071
9298
|
*/
|
9072
9299
|
#listener;
|
9300
|
+
/**
|
9301
|
+
* Map of lifecycle hook names to their handler functions.
|
9302
|
+
*/
|
9303
|
+
#lifecycleHooks = new Map();
|
9073
9304
|
/**
|
9074
9305
|
* @param context The context for parsing the directive.
|
9075
9306
|
*/
|
@@ -9093,10 +9324,22 @@
|
|
9093
9324
|
const expression = context.attribute.value;
|
9094
9325
|
if (expression) {
|
9095
9326
|
this.#dependentIdentifiers = ExpressionUtils.extractIdentifiers(expression, context.vNode.vApplication.functionDependencies);
|
9096
|
-
this.#handlerWrapper = this.#createHandlerWrapper(expression);
|
9097
9327
|
}
|
9098
|
-
//
|
9099
|
-
if (this.#eventName) {
|
9328
|
+
// Check if this is a lifecycle hook or a regular event
|
9329
|
+
if (this.#eventName && this.#isLifecycleHook(this.#eventName)) {
|
9330
|
+
// Create handler wrapper for lifecycle hook (no event parameter)
|
9331
|
+
if (expression) {
|
9332
|
+
const handler = this.#createLifecycleHandlerWrapper(expression);
|
9333
|
+
this.#handlerWrapper = handler;
|
9334
|
+
this.#lifecycleHooks.set(this.#eventName, handler);
|
9335
|
+
}
|
9336
|
+
}
|
9337
|
+
else if (this.#eventName) {
|
9338
|
+
// Create handler wrapper for DOM event (with event parameter)
|
9339
|
+
if (expression) {
|
9340
|
+
this.#handlerWrapper = this.#createEventHandlerWrapper(expression);
|
9341
|
+
}
|
9342
|
+
// Create and attach DOM event listener
|
9100
9343
|
this.#attachEventListener();
|
9101
9344
|
}
|
9102
9345
|
// Remove the directive attribute from the element
|
@@ -9144,6 +9387,42 @@
|
|
9144
9387
|
get dependentIdentifiers() {
|
9145
9388
|
return this.#dependentIdentifiers ?? [];
|
9146
9389
|
}
|
9390
|
+
/**
|
9391
|
+
* @inheritdoc
|
9392
|
+
*/
|
9393
|
+
get onMount() {
|
9394
|
+
return this.#lifecycleHooks.get('mount');
|
9395
|
+
}
|
9396
|
+
/**
|
9397
|
+
* @inheritdoc
|
9398
|
+
*/
|
9399
|
+
get onMounted() {
|
9400
|
+
return this.#lifecycleHooks.get('mounted');
|
9401
|
+
}
|
9402
|
+
/**
|
9403
|
+
* @inheritdoc
|
9404
|
+
*/
|
9405
|
+
get onUpdate() {
|
9406
|
+
return this.#lifecycleHooks.get('update');
|
9407
|
+
}
|
9408
|
+
/**
|
9409
|
+
* @inheritdoc
|
9410
|
+
*/
|
9411
|
+
get onUpdated() {
|
9412
|
+
return this.#lifecycleHooks.get('updated');
|
9413
|
+
}
|
9414
|
+
/**
|
9415
|
+
* @inheritdoc
|
9416
|
+
*/
|
9417
|
+
get onUnmount() {
|
9418
|
+
return this.#lifecycleHooks.get('unmount');
|
9419
|
+
}
|
9420
|
+
/**
|
9421
|
+
* @inheritdoc
|
9422
|
+
*/
|
9423
|
+
get onUnmounted() {
|
9424
|
+
return this.#lifecycleHooks.get('unmounted');
|
9425
|
+
}
|
9147
9426
|
/**
|
9148
9427
|
* @inheritdoc
|
9149
9428
|
*/
|
@@ -9220,11 +9499,48 @@
|
|
9220
9499
|
element.addEventListener(eventName, this.#listener, useCapture);
|
9221
9500
|
}
|
9222
9501
|
/**
|
9223
|
-
*
|
9502
|
+
* Checks if the event name is a lifecycle hook.
|
9503
|
+
* @param eventName The event name to check.
|
9504
|
+
* @returns True if the event name is a lifecycle hook, false otherwise.
|
9505
|
+
*/
|
9506
|
+
#isLifecycleHook(eventName) {
|
9507
|
+
return ['mount', 'mounted', 'update', 'updated', 'unmount', 'unmounted'].includes(eventName);
|
9508
|
+
}
|
9509
|
+
/**
|
9510
|
+
* Creates a wrapper function for lifecycle hooks (with element parameter).
|
9511
|
+
* @param expression The expression string to evaluate.
|
9512
|
+
* @returns A function that handles the lifecycle hook.
|
9513
|
+
*/
|
9514
|
+
#createLifecycleHandlerWrapper(expression) {
|
9515
|
+
const identifiers = this.#dependentIdentifiers ?? [];
|
9516
|
+
const vNode = this.#vNode;
|
9517
|
+
// Return a function that handles the lifecycle hook with proper scope
|
9518
|
+
return () => {
|
9519
|
+
const bindings = vNode.bindings;
|
9520
|
+
const el = vNode.node;
|
9521
|
+
// If the expression is just a method name, call it with bindings as 'this'
|
9522
|
+
const trimmedExpr = expression.trim();
|
9523
|
+
if (identifiers.includes(trimmedExpr) && typeof bindings?.get(trimmedExpr) === 'function') {
|
9524
|
+
const methodName = trimmedExpr;
|
9525
|
+
const originalMethod = bindings?.get(methodName);
|
9526
|
+
// Call the method with bindings as 'this' context and element as parameter
|
9527
|
+
// This allows the method to access the DOM element and bindings
|
9528
|
+
return originalMethod(el);
|
9529
|
+
}
|
9530
|
+
// For inline expressions, evaluate normally with element parameter
|
9531
|
+
const values = identifiers.map(id => vNode.bindings?.get(id));
|
9532
|
+
const args = [...identifiers, 'el'].join(", ");
|
9533
|
+
const funcBody = `return (${expression});`;
|
9534
|
+
const func = new Function(args, funcBody);
|
9535
|
+
return func.call(bindings?.raw, ...values, el);
|
9536
|
+
};
|
9537
|
+
}
|
9538
|
+
/**
|
9539
|
+
* Creates a wrapper function for DOM event handlers (with event parameter).
|
9224
9540
|
* @param expression The expression string to evaluate.
|
9225
9541
|
* @returns A function that handles the event.
|
9226
9542
|
*/
|
9227
|
-
#
|
9543
|
+
#createEventHandlerWrapper(expression) {
|
9228
9544
|
const identifiers = this.#dependentIdentifiers ?? [];
|
9229
9545
|
const vNode = this.#vNode;
|
9230
9546
|
// Return a function that handles the event with proper scope
|
@@ -9383,6 +9699,42 @@
|
|
9383
9699
|
// Hide the element
|
9384
9700
|
element.style.display = "none";
|
9385
9701
|
}
|
9702
|
+
/**
|
9703
|
+
* @inheritdoc
|
9704
|
+
*/
|
9705
|
+
get onMount() {
|
9706
|
+
return undefined;
|
9707
|
+
}
|
9708
|
+
/**
|
9709
|
+
* @inheritdoc
|
9710
|
+
*/
|
9711
|
+
get onMounted() {
|
9712
|
+
return undefined;
|
9713
|
+
}
|
9714
|
+
/**
|
9715
|
+
* @inheritdoc
|
9716
|
+
*/
|
9717
|
+
get onUpdate() {
|
9718
|
+
return undefined;
|
9719
|
+
}
|
9720
|
+
/**
|
9721
|
+
* @inheritdoc
|
9722
|
+
*/
|
9723
|
+
get onUpdated() {
|
9724
|
+
return undefined;
|
9725
|
+
}
|
9726
|
+
/**
|
9727
|
+
* @inheritdoc
|
9728
|
+
*/
|
9729
|
+
get onUnmount() {
|
9730
|
+
return undefined;
|
9731
|
+
}
|
9732
|
+
/**
|
9733
|
+
* @inheritdoc
|
9734
|
+
*/
|
9735
|
+
get onUnmounted() {
|
9736
|
+
return undefined;
|
9737
|
+
}
|
9386
9738
|
/**
|
9387
9739
|
* @inheritdoc
|
9388
9740
|
*/
|