All files / custom-element/mixins VirtualDomMixin.ts

90% Statements 27/30
57.14% Branches 8/14
90.91% Functions 10/11
89.29% Lines 25/28

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 106 107 108 109 110  11x             11x   11x                         73x       88x                     82x         82x   82x   60x   60x   60x           22x   22x   22x   22x                       82x               60x   60x   2x     60x               22x   22x   2x     22x       11x
import { NodePatchingData } from "../../renderer/NodePatcher";
import { render } from "../../renderer/renderer";
 
/**
 * 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 = null;
 
        protected updateDom() {
 
            let newPatchingData: NodePatchingData = this.render();
 
            // if (Array.isArray(newPatchingData)) { // An array of results was returned from an map -> html call
 
            //     const wrapperNode = new DocumentFragment();
 
            //     newPatchingData.forEach(r => wrapperNode.insertBefore(r, null));
 
            //     newPatchingData = wrapperNode;
            // }
 
            newPatchingData = this.beforeRender(newPatchingData); // Modify the original patching data if needed
 
            const {
                document,
                _oldPatchingData
            } = this;
 
            if (_oldPatchingData === null) {
 
                Eif (newPatchingData !== null) { // Mount
 
                    render(document, null, newPatchingData);
 
                    this._waitForChildrenToMount();
                }
                // else newPatchingData === null - Nothing to do
            }
            else { // this._oldPatchingData !== null
 
                Eif (newPatchingData !== null) { // Update
 
                    this.willUpdateCallback();
 
                    render(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;