All files / custom-element/mixins/core VirtualDomMixin.ts

21.88% Statements 7/32
0% Branches 0/16
27.27% Functions 3/11
23.33% Lines 7/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105  2x 2x             2x   2x                         4x       5x                                                                                                                                                       2x
import { NodePatchingData } from "../../../renderer/NodePatcher";
import { mountNodes } from "../../../renderer/mountNodes";
import { updateNodes } from "../../../renderer/updateNodes";
 
/**
 * Updates the element using a virtual DOM approach
 * @param Base 
 * @returns 
 */
const VirtualDomMixin = Base =>
 
    class VirtualDom extends Base {
 
        didMountCallback() { }
 
        willUpdateCallback() { };
 
        didUpdateCallback() { };
 
        willUnmountCallback() { };
 
        /**
         * The old patching node data to patch against
         */
        private _oldPatchingData: NodePatchingData | NodePatchingData[] = null;
 
        protected updateDom() {
 
            let newPatchingData: NodePatchingData | NodePatchingData[] = this.render();
 
            if (newPatchingData !== null) { // Only if there is something to render
 
                newPatchingData = this.beforeRender(newPatchingData); // Modify the original patching data if needed
            }
 
            const {
                document,
                _oldPatchingData
            } = this;
 
            if (_oldPatchingData === null) {
 
                if (newPatchingData !== null) { // Mount
 
                    mountNodes(document, newPatchingData);
 
                    this._waitForChildrenToMount();
                }
                // else newPatchingData === null - Nothing to do
            }
            else { // this._oldPatchingData !== null
 
                if (newPatchingData !== null) { // Update
 
                    this.willUpdateCallback();
 
                    updateNodes(document, _oldPatchingData, newPatchingData);
 
                    this._waitForChildrenToUpdate();
                }
                else { // newPatchingData === null - Unmount
 
                    this.willUnmountCallback?.();
 
                    (this.document as HTMLElement).replaceChildren(); // Remove all the existing children
 
                    this.stylesAdded = false; // Need to re-add the styles
                }
            }
 
            this._oldPatchingData = newPatchingData;
        }
 
        /**
         * Wait for the children to mount before this (parent)
         */
        private async _waitForChildrenToMount() {
 
            const updatePromises = [...this.adoptedChildren].map(child => (child as any)._updatePromise);
 
            if (updatePromises.length > 0) {
 
                await Promise.all(updatePromises);
            }
 
            this.didMountCallback();
        }
 
        /**
         * Wait for the children to update before this (parent)
         */
        private async _waitForChildrenToUpdate() {
 
            const updatePromises = [...this.adoptedChildren].map(child => (child as any)._updatePromise);
 
            if (updatePromises.length > 0) {
 
                await Promise.all(updatePromises);
            }
 
            this.didUpdateCallback();
        }
    }
 
export default VirtualDomMixin;