All files / src/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  15x             15x   15x                         81x       101x                     95x         95x   95x   68x   68x   68x           27x   27x   27x   27x                       95x               68x   68x   4x     68x               27x   27x   3x     27x       15x
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;