NoHomey/react-material-ui-keyboard

View on GitHub
src/KeyboardKey.tsx

Summary

Maintainability
B
4 hrs
Test Coverage
import * as React from 'react';
import * as PropTypes from 'prop-types';
import bind from 'bind-decorator';
import FlatButton from 'material-ui/FlatButton';
import Backspace from 'material-ui/svg-icons/content/backspace';
import Enter from 'material-ui/svg-icons/hardware/keyboard-return';
import Escape from 'material-ui/svg-icons/action/exit-to-app';
import Keyboard from 'material-ui/svg-icons/hardware/keyboard';
import CapsLock from 'material-ui/svg-icons/hardware/keyboard-capslock';
import Spacebar from 'material-ui/svg-icons/editor/space-bar';
import Warning from 'material-ui/svg-icons/alert/warning';
import { MuiTheme } from 'material-ui/styles';

export type KeyboardKeyPressHandler = (key: string) => void;

export interface KeyboardKeyProps {
    keyboardKey: string;
    onKeyPress: KeyboardKeyPressHandler;
    keyboardKeyWidth: number;
    keyboardKeyHeight: number;
    keyboardKeySymbolSize: number;
    disableEffects: boolean;
}

export interface KeyboardKeyContext {
    muiTheme: MuiTheme;
}

interface SpecialIcons {
    [index: string]: React.ComponentClass<any>;
}

namespace constants {
    export const one: number = 1;
    export const spacebar: string = ' ';
    export const none: string = 'none';
    export const notFound: string = 'notFound';
    export const boolTrue: boolean = true;
    export const boolFalse: boolean = false;
}

export class KeyboardKey extends React.Component<KeyboardKeyProps> {
    public context: KeyboardKeyContext;

    private static specialIcons: SpecialIcons = {
        'Enter': Enter,
        'Backspace': Backspace,
        'Escape': Escape,
        'CapsLock': CapsLock,
        'Keyboard': Keyboard,
        ' ' : Spacebar,
        'notFound': Warning
    };

    public static propTypes: React.ValidationMap<KeyboardKeyProps> = {
        keyboardKey: PropTypes.string.isRequired,
        onKeyPress: PropTypes.func.isRequired,
        keyboardKeyWidth: PropTypes.number.isRequired,
        keyboardKeyHeight: PropTypes.number.isRequired,
        keyboardKeySymbolSize: PropTypes.number.isRequired,
    };
    public static contextTypes: any = { muiTheme: PropTypes.object.isRequired };

    @bind
    private onTouchTap(): void {
        const { onKeyPress, keyboardKey } = this.props;
        if((keyboardKey.length === 1) || KeyboardKey.specialIcons.hasOwnProperty(keyboardKey)) {
            onKeyPress(keyboardKey);
        }
    }

    public constructor(props: KeyboardKeyProps, context: KeyboardKeyContext) {
        super(props);
        this.context = context;
    }

    public shouldComponentUpdate(props: KeyboardKeyProps): boolean {
        if(this.props.keyboardKey !== props.keyboardKey) {
            return constants.boolTrue;
        }
        if(this.props.keyboardKeyHeight !== props.keyboardKeyHeight) {
            return constants.boolTrue;
        }
        if(this.props.keyboardKeySymbolSize !== props.keyboardKeySymbolSize) {
            return constants.boolTrue;
        }
        if(this.props.keyboardKeyWidth !== props.keyboardKeyWidth) {
            return constants.boolTrue;
        }
        if(this.props.onKeyPress !== props.onKeyPress) {
            return constants.boolTrue;
        }
        if(this.props.disableEffects !== props.disableEffects) {
            return constants.boolTrue;
        }

        return constants.boolFalse;
    }

    public render(): JSX.Element {
        const { keyboardKey: key, keyboardKeyHeight: height, keyboardKeyWidth: width, keyboardKeySymbolSize: size, disableEffects } = this.props;
        let flatButtonProps: any = {
            style: {
                height: height,
                width: width, 
                minWidth: width
            },
            primary: constants.boolTrue,
            onTouchTap: this.onTouchTap,
            disableFocusRipple: disableEffects,
            disableKeyboardFocus: disableEffects,
            disableTouchRipple: disableEffects
        };
        if(disableEffects) {
            flatButtonProps.hoverColor = this.context.muiTheme.flatButton!.color;
        }
        if((key.length <= constants.one) && (key !== constants.spacebar)) {
            if(key.length) {
                flatButtonProps.label = key;
            } else {
                flatButtonProps.disabled = constants.boolTrue;
                flatButtonProps.label = constants.spacebar;
            }
            flatButtonProps.labelStyle = { fontSize: size, textTransform: constants.none };
        } else {
            const { specialIcons } =  KeyboardKey;
            const icon: React.ComponentClass<any> = specialIcons[specialIcons.hasOwnProperty(key) ? key : constants.notFound];
            flatButtonProps.icon = React.createElement(icon, { style: { width: size, height: size } });
        }
        return React.createElement(FlatButton,  flatButtonProps);
    }
};

export default KeyboardKey;