@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.
- 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.esm.js
CHANGED
@@ -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
|
-
|
7656
|
-
|
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
|
-
//
|
7663
|
-
|
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
|
-
//
|
7674
|
-
|
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
|
-
|
7874
|
-
|
7875
|
-
//
|
7876
|
-
if (!this.#
|
7877
|
-
this.#
|
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
|
7880
|
-
|
7881
|
-
|
7882
|
-
if (
|
7883
|
-
|
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
|
-
|
7888
|
-
|
7889
|
-
|
7890
|
-
|
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
|
-
|
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
|
-
|
7918
|
-
|
7919
|
-
//
|
7920
|
-
if (!this.#
|
7921
|
-
this.#
|
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
|
7924
|
-
|
7925
|
-
|
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
|
-
|
7929
|
-
|
7930
|
-
|
7931
|
-
|
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
|
-
|
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
|
-
|
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
|
-
*
|
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
|
-
//
|
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
|
-
*
|
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
|
-
#
|
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
|
*/
|