All files / src/components/Mirror Mirror.tsx

100% Statements 46/46
86.67% Branches 13/15
100% Functions 18/18
100% Lines 38/38

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 962x 2x                       16x     15x 15x 14x 16x       14x   1x           23x 23x 23x     23x 27x 2x   23x 27x 2x     2x 2x 2x 2x         38x 38x     38x 38x           15x 23x     23x           177x 100x 100x     15x 38x 44x                   15x 61x   2x  
import * as React from 'react';
import { FormContext, FormApi } from '../Form';
 
export interface MirrorInstance {
    props: MirrorProps;
    reflect: Mirror['reflect'];
}
 
export interface MirrorProps {
    name: string | string[];
    children: (values: { [key: string]: any }) => any;
}
 
export class Mirror extends React.Component<MirrorProps> {
    formApi: FormApi;
 
    public componentDidMount() {
        if (this.isInsideForm()) {
            this.getNames().forEach((name) =>
                this.formApi.registerMirror(name, this),
            );
 
            // Defer an update so we can get loaded values
            setTimeout(this.reflect, 0);
        } else {
            console.error(
                'Mirrors must be placed inside of a <Form/> component.',
            );
        }
    }
 
    public componentDidUpdate(prevProps: MirrorProps) {
        const names = this.getNames();
        const prevNames = this.getNames(prevProps);
 
        // Unregister names no longer included
        prevNames
            .filter((name) => !names.includes(name))
            .forEach((name) => this.formApi.unregisterMirror(name, this));
        // Register names that were not included before
        names
            .filter((name) => !prevNames.includes(name))
            .forEach((name) => this.formApi.registerMirror(name, this));
    }
 
    public componentWillUnmount() {
        Eif (this.isInsideForm()) {
            this.getNames().forEach((name) =>
                this.formApi.unregisterMirror(name, this),
            );
        }
    }
 
    render() {
        return (
            <FormContext.Consumer>
                {(api: FormApi) => {
                    this.formApi = api;
                    return this.props.children(this.getValues());
                }}
            </FormContext.Consumer>
        );
    }
 
    reflect = (): Promise<void> => {
        return new Promise((resolve) => {
            // Document check is done to prevent a jest unit test error where
            // the document may be cleaned up before forceUpdate is called
            typeof document !== 'undefined'
                ? this.forceUpdate(resolve)
                : Promise.resolve();
        });
    };
 
    getNames = (props: MirrorProps = this.props): string[] => {
        const { name } = props;
        return Array.isArray(name) ? name : [name];
    };
 
    getValues = () => {
        return this.getNames().reduce(
            (output, name) => ({
                ...output,
                [name]: this.isInsideForm()
                    ? this.formApi.getValue(name)
                    : undefined,
            }),
            {},
        );
    };
 
    isInsideForm = (): boolean => {
        return !!this.formApi;
    };
}