mongaku/mongaku

View on GitHub
src/views/shared/Select.js

Summary

Maintainability
F
5 days
Test Coverage
// @flow

const React = require("react");

import type {Context} from "../types.js";
const {childContextTypes} = require("../Wrapper.js");

type Props = {
    name: string,
    options: Array<{
        value: string,
        label: string,
    }>,
    value?: string | Array<string>,
    multi?: boolean,
    create?: boolean,
    clearable?: boolean,
    placeholder?: string,
    cache?: boolean,
    loadOptions?: (input: string) => Promise<*>,
    onChange?: (value: string | Array<string>) => void,
};

class SimpleSelect extends React.Component<Props> {
    handleChange(e: SyntheticInputEvent<HTMLSelectElement>) {
        if (!(e.target instanceof HTMLSelectElement)) {
            return;
        }

        const {multi, onChange} = this.props;
        let {value} = e.target;
        const {options} = e.target;

        if (multi) {
            value = Array.prototype.slice
                .call(options)
                .filter(option => option.selected)
                .map(option => option.value);
        }

        if (onChange) {
            onChange(value);
        }
    }

    render() {
        const {
            name,
            multi,
            options,
            value,
            clearable,
            placeholder,
        } = this.props;

        return (
            <select
                name={name}
                multiple={multi}
                value={value}
                onChange={e => this.handleChange(e)}
                className="form-control"
            >
                {clearable && !multi && <option value="">{placeholder}</option>}
                {options.map(({value, label}) => (
                    <option key={value} value={value}>
                        {label}
                    </option>
                ))}
            </select>
        );
    }
}

class MultiSelect extends React.Component<
    Props,
    {
        searchValue?: string,
        loading: boolean,
        options?: Array<{
            value: string,
            label: string,
        }>,
        error?: Error,
    },
> {
    constructor(props) {
        super(props);
        this.state = {
            loading: false,
        };
        this.labelCache = {};
        if (props.cache) {
            this.queryCache = {};
        }
    }

    componentDidMount() {
        this.boundHandleBlur = (e: Event) => this.handleBlur(e);
        document.addEventListener("focusin", this.boundHandleBlur);
        document.addEventListener("click", this.boundHandleBlur);
    }

    componentWillUnmount() {
        document.removeEventListener("focusin", this.boundHandleBlur);
        document.removeEventListener("click", this.boundHandleBlur);
    }

    context: Context;
    control: ?HTMLElement;
    input: ?HTMLInputElement;
    boundHandleBlur: (e: Event) => void;
    labelCache: {
        [value: string]: string,
    };
    queryCache: {
        [query: string]: Array<{
            value: string,
            label: string,
        }>,
    };
    handleBlur(e: Event) {
        const {target} = e;
        const {searchValue} = this.state;

        if (
            searchValue !== undefined &&
            (!target ||
                (target instanceof Node &&
                    this.control &&
                    !this.control.contains(target) &&
                    document.documentElement &&
                    document.documentElement.contains(target)))
        ) {
            this.closeMenu();
        }
    }

    getNameByValue(value: string): string {
        if (this.labelCache[value]) {
            return this.labelCache[value];
        }

        const {options} = this.props;
        const result = options.find(option => option.value === value);

        if (result) {
            return result.label;
        }

        return value;
    }

    addValue(addedValue: string, addedLabel: string) {
        const {onChange, value} = this.props;
        if ((!value || Array.isArray(value)) && onChange) {
            this.labelCache[addedValue] = addedLabel;
            onChange(
                value
                    ? value.includes(addedValue)
                        ? value
                        : value.concat(addedValue)
                    : [addedValue],
            );
            this.clear();
            if (this.input) {
                this.input.focus();
            }
            this.handleInput("");
        }
    }

    removeValue(removedValue: string) {
        const {onChange, value} = this.props;
        if (value && Array.isArray(value) && onChange) {
            onChange(value.filter(value => value !== removedValue));
        }
    }

    clear() {
        if (this.input) {
            this.input.value = "";
        }
        this.setState({searchValue: ""});
    }

    getFilteredOptions() {
        const {value} = this.props;
        const {options} = this.state;

        if (!options) {
            return [];
        }

        return options.filter(
            option => !value || !value.includes(option.value),
        );
    }

    handleKey(e: SyntheticKeyboardEvent<HTMLInputElement>) {
        if (
            e.target instanceof HTMLInputElement &&
            (e.key === "Enter" || e.key === "Tab")
        ) {
            const {create} = this.props;
            const {searchValue} = this.state;
            const {value} = e.target;
            if (value) {
                const options = this.getFilteredOptions();
                if (options.length > 0) {
                    this.addValue(options[0].value, options[0].label);
                } else if (create && searchValue) {
                    this.addValue(searchValue, searchValue);
                }
                e.preventDefault();
            }
        }
    }

    handleInput(searchValue: string) {
        const {loadOptions, options} = this.props;

        this.setState({
            searchValue,
            error: undefined,
            options: undefined,
            loading: false,
        });

        if (searchValue === undefined) {
            return;
        }

        if (loadOptions) {
            if (this.queryCache && this.queryCache[searchValue]) {
                return this.setState({
                    options: this.queryCache[searchValue],
                });
            }

            this.setState({loading: true});

            loadOptions(searchValue)
                .then(options => {
                    if (this.state.searchValue === searchValue) {
                        this.queryCache[searchValue] = options;
                        this.setState({options, loading: false});
                    }
                })
                .catch(error => {
                    if (this.state.searchValue === searchValue) {
                        this.setState({error, loading: false});
                    }
                });
        } else {
            const search = new RegExp(
                latinize(searchValue)
                    .split("")
                    .map(char => (/\W/.test(char) ? `\\${char}` : char))
                    .join(".*"),
                "i",
            );

            this.setState({
                options: options.filter(option =>
                    search.test(latinize(option.label)),
                ),
            });
        }
    }

    closeMenu() {
        this.setState({searchValue: undefined});
    }

    renderMenu() {
        const {create} = this.props;
        const {searchValue, options, error} = this.state;
        const {gettext, format} = this.context;

        if (searchValue === undefined) {
            return null;
        }

        if (error) {
            return (
                <div style={{marginTop: "8px"}}>
                    <span className="label label-danger">
                        {gettext("Error loading options.")}
                    </span>
                </div>
            );
        }

        if (!options) {
            return (
                <div style={{marginTop: "8px"}}>
                    <span className="label label-default">
                        {gettext("Loading...")}
                    </span>
                </div>
            );
        }

        const filteredOptions = this.getFilteredOptions();

        if (filteredOptions.length === 0 && !create) {
            return (
                <div style={{marginTop: "8px"}}>
                    <span className="label label-default">
                        {gettext("No results found.")}
                    </span>
                </div>
            );
        }

        return (
            <ul
                className="dropdown-menu"
                style={{
                    display: "block",
                    position: "static",
                    width: "100%",
                    height: "150px",
                    overflow: "auto",
                    boxShadow: "none",
                    marginTop: "8px",
                }}
            >
                {filteredOptions.map((option, i) => (
                    <li
                        key={option.value}
                        className={i === 0 && searchValue ? "active" : ""}
                    >
                        <a
                            href="javascript: void(0)"
                            onClick={e => {
                                e.preventDefault();
                                this.addValue(option.value, option.label);
                            }}
                        >
                            {option.label}
                        </a>
                    </li>
                ))}
                {create &&
                    searchValue && (
                        <li
                            className={
                                filteredOptions.length === 0 ? "active" : ""
                            }
                        >
                            <a
                                href="javascript: void(0)"
                                onClick={e => {
                                    e.preventDefault();
                                    this.addValue(searchValue, searchValue);
                                }}
                            >
                                {format(gettext("Add %(value)s..."), {
                                    value: searchValue,
                                })}
                            </a>
                        </li>
                    )}
            </ul>
        );
    }

    renderValue() {
        const {name, value} = this.props;

        if (!value || !Array.isArray(value) || value.length === 0) {
            return null;
        }

        return (
            <div>
                {value.map(value => (
                    <span key={value}>
                        <input type="hidden" name={name} value={value} />
                        <button
                            type="button"
                            className="btn btn-default btn-xs"
                            onClick={() => this.removeValue(value)}
                            style={{marginTop: "8px"}}
                        >
                            <span
                                className="glyphicon glyphicon-remove"
                                aria-hidden="true"
                            />{" "}
                            {this.getNameByValue(value)}
                        </button>{" "}
                    </span>
                ))}
            </div>
        );
    }

    render() {
        const {placeholder} = this.props;

        return (
            <div
                ref={r => {
                    this.control = r;
                }}
            >
                <div>
                    <input
                        ref={r => {
                            this.input = r;
                        }}
                        type="text"
                        placeholder={placeholder}
                        className="form-control"
                        onKeyDown={e => this.handleKey(e)}
                        onInput={e => this.handleInput(e.target.value)}
                        onFocus={e => this.handleInput(e.target.value)}
                    />
                </div>
                {this.renderMenu()}
                {this.renderValue()}
            </div>
        );
    }
}

MultiSelect.contextTypes = childContextTypes;

class Select extends React.Component<
    Props,
    {
        value?: string | Array<string>,
    },
> {
    constructor(props: Props) {
        super(props);
        this.state = {
            value:
                props.multi && !Array.isArray(props.value)
                    ? props.value
                        ? [props.value]
                        : []
                    : props.value,
        };
    }

    context: Context;
    handleChange(value: string | Array<string>) {
        this.setState({value});
        if (this.props.onChange) {
            this.props.onChange(value);
        }
    }

    render() {
        const {multi, create, loadOptions, placeholder} = this.props;
        const {gettext} = this.context;
        let Selector = SimpleSelect;

        if (multi || create || loadOptions) {
            Selector = MultiSelect;
        }

        return (
            <Selector
                {...this.props}
                value={this.state.value}
                onChange={value => this.handleChange(value)}
                placeholder={placeholder || gettext("Select...")}
            />
        );
    }
}

Select.contextTypes = childContextTypes;

const latinize = str => str.replace(/[^A-Za-z0-9[\] ]/g, a => latinMap[a] || a);

// prettier-ignore
const latinMap = {
    "Á": "A",
    "Ă": "A",
    "Ắ": "A",
    "Ặ": "A",
    "Ằ": "A",
    "Ẳ": "A",
    "Ẵ": "A",
    "Ǎ": "A",
    "Â": "A",
    "Ấ": "A",
    "Ậ": "A",
    "Ầ": "A",
    "Ẩ": "A",
    "Ẫ": "A",
    "Ä": "A",
    "Ǟ": "A",
    "Ȧ": "A",
    "Ǡ": "A",
    "Ạ": "A",
    "Ȁ": "A",
    "À": "A",
    "Ả": "A",
    "Ȃ": "A",
    "Ā": "A",
    "Ą": "A",
    "Å": "A",
    "Ǻ": "A",
    "Ḁ": "A",
    "Ⱥ": "A",
    "Ã": "A",
    "Ꜳ": "AA",
    "Æ": "AE",
    "Ǽ": "AE",
    "Ǣ": "AE",
    "Ꜵ": "AO",
    "Ꜷ": "AU",
    "Ꜹ": "AV",
    "Ꜻ": "AV",
    "Ꜽ": "AY",
    "Ḃ": "B",
    "Ḅ": "B",
    "Ɓ": "B",
    "Ḇ": "B",
    "Ƀ": "B",
    "Ƃ": "B",
    "Ć": "C",
    "Č": "C",
    "Ç": "C",
    "Ḉ": "C",
    "Ĉ": "C",
    "Ċ": "C",
    "Ƈ": "C",
    "Ȼ": "C",
    "Ď": "D",
    "Ḑ": "D",
    "Ḓ": "D",
    "Ḋ": "D",
    "Ḍ": "D",
    "Ɗ": "D",
    "Ḏ": "D",
    "Dz": "D",
    "Dž": "D",
    "Đ": "D",
    "Ƌ": "D",
    "DZ": "DZ",
    "DŽ": "DZ",
    "É": "E",
    "Ĕ": "E",
    "Ě": "E",
    "Ȩ": "E",
    "Ḝ": "E",
    "Ê": "E",
    "Ế": "E",
    "Ệ": "E",
    "Ề": "E",
    "Ể": "E",
    "Ễ": "E",
    "Ḙ": "E",
    "Ë": "E",
    "Ė": "E",
    "Ẹ": "E",
    "Ȅ": "E",
    "È": "E",
    "Ẻ": "E",
    "Ȇ": "E",
    "Ē": "E",
    "Ḗ": "E",
    "Ḕ": "E",
    "Ę": "E",
    "Ɇ": "E",
    "Ẽ": "E",
    "Ḛ": "E",
    "Ꝫ": "ET",
    "Ḟ": "F",
    "Ƒ": "F",
    "Ǵ": "G",
    "Ğ": "G",
    "Ǧ": "G",
    "Ģ": "G",
    "Ĝ": "G",
    "Ġ": "G",
    "Ɠ": "G",
    "Ḡ": "G",
    "Ǥ": "G",
    "Ḫ": "H",
    "Ȟ": "H",
    "Ḩ": "H",
    "Ĥ": "H",
    "Ⱨ": "H",
    "Ḧ": "H",
    "Ḣ": "H",
    "Ḥ": "H",
    "Ħ": "H",
    "Í": "I",
    "Ĭ": "I",
    "Ǐ": "I",
    "Î": "I",
    "Ï": "I",
    "Ḯ": "I",
    "İ": "I",
    "Ị": "I",
    "Ȉ": "I",
    "Ì": "I",
    "Ỉ": "I",
    "Ȋ": "I",
    "Ī": "I",
    "Į": "I",
    "Ɨ": "I",
    "Ĩ": "I",
    "Ḭ": "I",
    "Ꝺ": "D",
    "Ꝼ": "F",
    "Ᵹ": "G",
    "Ꞃ": "R",
    "Ꞅ": "S",
    "Ꞇ": "T",
    "Ꝭ": "IS",
    "Ĵ": "J",
    "Ɉ": "J",
    "Ḱ": "K",
    "Ǩ": "K",
    "Ķ": "K",
    "Ⱪ": "K",
    "Ꝃ": "K",
    "Ḳ": "K",
    "Ƙ": "K",
    "Ḵ": "K",
    "Ꝁ": "K",
    "Ꝅ": "K",
    "Ĺ": "L",
    "Ƚ": "L",
    "Ľ": "L",
    "Ļ": "L",
    "Ḽ": "L",
    "Ḷ": "L",
    "Ḹ": "L",
    "Ⱡ": "L",
    "Ꝉ": "L",
    "Ḻ": "L",
    "Ŀ": "L",
    "Ɫ": "L",
    "Lj": "L",
    "Ł": "L",
    "LJ": "LJ",
    "Ḿ": "M",
    "Ṁ": "M",
    "Ṃ": "M",
    "Ɱ": "M",
    "Ń": "N",
    "Ň": "N",
    "Ņ": "N",
    "Ṋ": "N",
    "Ṅ": "N",
    "Ṇ": "N",
    "Ǹ": "N",
    "Ɲ": "N",
    "Ṉ": "N",
    "Ƞ": "N",
    "Nj": "N",
    "Ñ": "N",
    "NJ": "NJ",
    "Ó": "O",
    "Ŏ": "O",
    "Ǒ": "O",
    "Ô": "O",
    "Ố": "O",
    "Ộ": "O",
    "Ồ": "O",
    "Ổ": "O",
    "Ỗ": "O",
    "Ö": "O",
    "Ȫ": "O",
    "Ȯ": "O",
    "Ȱ": "O",
    "Ọ": "O",
    "Ő": "O",
    "Ȍ": "O",
    "Ò": "O",
    "Ỏ": "O",
    "Ơ": "O",
    "Ớ": "O",
    "Ợ": "O",
    "Ờ": "O",
    "Ở": "O",
    "Ỡ": "O",
    "Ȏ": "O",
    "Ꝋ": "O",
    "Ꝍ": "O",
    "Ō": "O",
    "Ṓ": "O",
    "Ṑ": "O",
    "Ɵ": "O",
    "Ǫ": "O",
    "Ǭ": "O",
    "Ø": "O",
    "Ǿ": "O",
    "Õ": "O",
    "Ṍ": "O",
    "Ṏ": "O",
    "Ȭ": "O",
    "Ƣ": "OI",
    "Ꝏ": "OO",
    "Ɛ": "E",
    "Ɔ": "O",
    "Ȣ": "OU",
    "Ṕ": "P",
    "Ṗ": "P",
    "Ꝓ": "P",
    "Ƥ": "P",
    "Ꝕ": "P",
    "Ᵽ": "P",
    "Ꝑ": "P",
    "Ꝙ": "Q",
    "Ꝗ": "Q",
    "Ŕ": "R",
    "Ř": "R",
    "Ŗ": "R",
    "Ṙ": "R",
    "Ṛ": "R",
    "Ṝ": "R",
    "Ȑ": "R",
    "Ȓ": "R",
    "Ṟ": "R",
    "Ɍ": "R",
    "Ɽ": "R",
    "Ꜿ": "C",
    "Ǝ": "E",
    "Ś": "S",
    "Ṥ": "S",
    "Š": "S",
    "Ṧ": "S",
    "Ş": "S",
    "Ŝ": "S",
    "Ș": "S",
    "Ṡ": "S",
    "Ṣ": "S",
    "Ṩ": "S",
    "Ť": "T",
    "Ţ": "T",
    "Ṱ": "T",
    "Ț": "T",
    "Ⱦ": "T",
    "Ṫ": "T",
    "Ṭ": "T",
    "Ƭ": "T",
    "Ṯ": "T",
    "Ʈ": "T",
    "Ŧ": "T",
    "Ɐ": "A",
    "Ꞁ": "L",
    "Ɯ": "M",
    "Ʌ": "V",
    "Ꜩ": "TZ",
    "Ú": "U",
    "Ŭ": "U",
    "Ǔ": "U",
    "Û": "U",
    "Ṷ": "U",
    "Ü": "U",
    "Ǘ": "U",
    "Ǚ": "U",
    "Ǜ": "U",
    "Ǖ": "U",
    "Ṳ": "U",
    "Ụ": "U",
    "Ű": "U",
    "Ȕ": "U",
    "Ù": "U",
    "Ủ": "U",
    "Ư": "U",
    "Ứ": "U",
    "Ự": "U",
    "Ừ": "U",
    "Ử": "U",
    "Ữ": "U",
    "Ȗ": "U",
    "Ū": "U",
    "Ṻ": "U",
    "Ų": "U",
    "Ů": "U",
    "Ũ": "U",
    "Ṹ": "U",
    "Ṵ": "U",
    "Ꝟ": "V",
    "Ṿ": "V",
    "Ʋ": "V",
    "Ṽ": "V",
    "Ꝡ": "VY",
    "Ẃ": "W",
    "Ŵ": "W",
    "Ẅ": "W",
    "Ẇ": "W",
    "Ẉ": "W",
    "Ẁ": "W",
    "Ⱳ": "W",
    "Ẍ": "X",
    "Ẋ": "X",
    "Ý": "Y",
    "Ŷ": "Y",
    "Ÿ": "Y",
    "Ẏ": "Y",
    "Ỵ": "Y",
    "Ỳ": "Y",
    "Ƴ": "Y",
    "Ỷ": "Y",
    "Ỿ": "Y",
    "Ȳ": "Y",
    "Ɏ": "Y",
    "Ỹ": "Y",
    "Ź": "Z",
    "Ž": "Z",
    "Ẑ": "Z",
    "Ⱬ": "Z",
    "Ż": "Z",
    "Ẓ": "Z",
    "Ȥ": "Z",
    "Ẕ": "Z",
    "Ƶ": "Z",
    "IJ": "IJ",
    "Œ": "OE",
    "ᴀ": "A",
    "ᴁ": "AE",
    "ʙ": "B",
    "ᴃ": "B",
    "ᴄ": "C",
    "ᴅ": "D",
    "ᴇ": "E",
    "ꜰ": "F",
    "ɢ": "G",
    "ʛ": "G",
    "ʜ": "H",
    "ɪ": "I",
    "ʁ": "R",
    "ᴊ": "J",
    "ᴋ": "K",
    "ʟ": "L",
    "ᴌ": "L",
    "ᴍ": "M",
    "ɴ": "N",
    "ᴏ": "O",
    "ɶ": "OE",
    "ᴐ": "O",
    "ᴕ": "OU",
    "ᴘ": "P",
    "ʀ": "R",
    "ᴎ": "N",
    "ᴙ": "R",
    "ꜱ": "S",
    "ᴛ": "T",
    "ⱻ": "E",
    "ᴚ": "R",
    "ᴜ": "U",
    "ᴠ": "V",
    "ᴡ": "W",
    "ʏ": "Y",
    "ᴢ": "Z",
    "á": "a",
    "ă": "a",
    "ắ": "a",
    "ặ": "a",
    "ằ": "a",
    "ẳ": "a",
    "ẵ": "a",
    "ǎ": "a",
    "â": "a",
    "ấ": "a",
    "ậ": "a",
    "ầ": "a",
    "ẩ": "a",
    "ẫ": "a",
    "ä": "a",
    "ǟ": "a",
    "ȧ": "a",
    "ǡ": "a",
    "ạ": "a",
    "ȁ": "a",
    "à": "a",
    "ả": "a",
    "ȃ": "a",
    "ā": "a",
    "ą": "a",
    "ᶏ": "a",
    "ẚ": "a",
    "å": "a",
    "ǻ": "a",
    "ḁ": "a",
    "ⱥ": "a",
    "ã": "a",
    "ꜳ": "aa",
    "æ": "ae",
    "ǽ": "ae",
    "ǣ": "ae",
    "ꜵ": "ao",
    "ꜷ": "au",
    "ꜹ": "av",
    "ꜻ": "av",
    "ꜽ": "ay",
    "ḃ": "b",
    "ḅ": "b",
    "ɓ": "b",
    "ḇ": "b",
    "ᵬ": "b",
    "ᶀ": "b",
    "ƀ": "b",
    "ƃ": "b",
    "ɵ": "o",
    "ć": "c",
    "č": "c",
    "ç": "c",
    "ḉ": "c",
    "ĉ": "c",
    "ɕ": "c",
    "ċ": "c",
    "ƈ": "c",
    "ȼ": "c",
    "ď": "d",
    "ḑ": "d",
    "ḓ": "d",
    "ȡ": "d",
    "ḋ": "d",
    "ḍ": "d",
    "ɗ": "d",
    "ᶑ": "d",
    "ḏ": "d",
    "ᵭ": "d",
    "ᶁ": "d",
    "đ": "d",
    "ɖ": "d",
    "ƌ": "d",
    "ı": "i",
    "ȷ": "j",
    "ɟ": "j",
    "ʄ": "j",
    "dz": "dz",
    "dž": "dz",
    "é": "e",
    "ĕ": "e",
    "ě": "e",
    "ȩ": "e",
    "ḝ": "e",
    "ê": "e",
    "ế": "e",
    "ệ": "e",
    "ề": "e",
    "ể": "e",
    "ễ": "e",
    "ḙ": "e",
    "ë": "e",
    "ė": "e",
    "ẹ": "e",
    "ȅ": "e",
    "è": "e",
    "ẻ": "e",
    "ȇ": "e",
    "ē": "e",
    "ḗ": "e",
    "ḕ": "e",
    "ⱸ": "e",
    "ę": "e",
    "ᶒ": "e",
    "ɇ": "e",
    "ẽ": "e",
    "ḛ": "e",
    "ꝫ": "et",
    "ḟ": "f",
    "ƒ": "f",
    "ᵮ": "f",
    "ᶂ": "f",
    "ǵ": "g",
    "ğ": "g",
    "ǧ": "g",
    "ģ": "g",
    "ĝ": "g",
    "ġ": "g",
    "ɠ": "g",
    "ḡ": "g",
    "ᶃ": "g",
    "ǥ": "g",
    "ḫ": "h",
    "ȟ": "h",
    "ḩ": "h",
    "ĥ": "h",
    "ⱨ": "h",
    "ḧ": "h",
    "ḣ": "h",
    "ḥ": "h",
    "ɦ": "h",
    "ẖ": "h",
    "ħ": "h",
    "ƕ": "hv",
    "í": "i",
    "ĭ": "i",
    "ǐ": "i",
    "î": "i",
    "ï": "i",
    "ḯ": "i",
    "ị": "i",
    "ȉ": "i",
    "ì": "i",
    "ỉ": "i",
    "ȋ": "i",
    "ī": "i",
    "į": "i",
    "ᶖ": "i",
    "ɨ": "i",
    "ĩ": "i",
    "ḭ": "i",
    "ꝺ": "d",
    "ꝼ": "f",
    "ᵹ": "g",
    "ꞃ": "r",
    "ꞅ": "s",
    "ꞇ": "t",
    "ꝭ": "is",
    "ǰ": "j",
    "ĵ": "j",
    "ʝ": "j",
    "ɉ": "j",
    "ḱ": "k",
    "ǩ": "k",
    "ķ": "k",
    "ⱪ": "k",
    "ꝃ": "k",
    "ḳ": "k",
    "ƙ": "k",
    "ḵ": "k",
    "ᶄ": "k",
    "ꝁ": "k",
    "ꝅ": "k",
    "ĺ": "l",
    "ƚ": "l",
    "ɬ": "l",
    "ľ": "l",
    "ļ": "l",
    "ḽ": "l",
    "ȴ": "l",
    "ḷ": "l",
    "ḹ": "l",
    "ⱡ": "l",
    "ꝉ": "l",
    "ḻ": "l",
    "ŀ": "l",
    "ɫ": "l",
    "ᶅ": "l",
    "ɭ": "l",
    "ł": "l",
    "lj": "lj",
    "ſ": "s",
    "ẜ": "s",
    "ẛ": "s",
    "ẝ": "s",
    "ḿ": "m",
    "ṁ": "m",
    "ṃ": "m",
    "ɱ": "m",
    "ᵯ": "m",
    "ᶆ": "m",
    "ń": "n",
    "ň": "n",
    "ņ": "n",
    "ṋ": "n",
    "ȵ": "n",
    "ṅ": "n",
    "ṇ": "n",
    "ǹ": "n",
    "ɲ": "n",
    "ṉ": "n",
    "ƞ": "n",
    "ᵰ": "n",
    "ᶇ": "n",
    "ɳ": "n",
    "ñ": "n",
    "nj": "nj",
    "ó": "o",
    "ŏ": "o",
    "ǒ": "o",
    "ô": "o",
    "ố": "o",
    "ộ": "o",
    "ồ": "o",
    "ổ": "o",
    "ỗ": "o",
    "ö": "o",
    "ȫ": "o",
    "ȯ": "o",
    "ȱ": "o",
    "ọ": "o",
    "ő": "o",
    "ȍ": "o",
    "ò": "o",
    "ỏ": "o",
    "ơ": "o",
    "ớ": "o",
    "ợ": "o",
    "ờ": "o",
    "ở": "o",
    "ỡ": "o",
    "ȏ": "o",
    "ꝋ": "o",
    "ꝍ": "o",
    "ⱺ": "o",
    "ō": "o",
    "ṓ": "o",
    "ṑ": "o",
    "ǫ": "o",
    "ǭ": "o",
    "ø": "o",
    "ǿ": "o",
    "õ": "o",
    "ṍ": "o",
    "ṏ": "o",
    "ȭ": "o",
    "ƣ": "oi",
    "ꝏ": "oo",
    "ɛ": "e",
    "ᶓ": "e",
    "ɔ": "o",
    "ᶗ": "o",
    "ȣ": "ou",
    "ṕ": "p",
    "ṗ": "p",
    "ꝓ": "p",
    "ƥ": "p",
    "ᵱ": "p",
    "ᶈ": "p",
    "ꝕ": "p",
    "ᵽ": "p",
    "ꝑ": "p",
    "ꝙ": "q",
    "ʠ": "q",
    "ɋ": "q",
    "ꝗ": "q",
    "ŕ": "r",
    "ř": "r",
    "ŗ": "r",
    "ṙ": "r",
    "ṛ": "r",
    "ṝ": "r",
    "ȑ": "r",
    "ɾ": "r",
    "ᵳ": "r",
    "ȓ": "r",
    "ṟ": "r",
    "ɼ": "r",
    "ᵲ": "r",
    "ᶉ": "r",
    "ɍ": "r",
    "ɽ": "r",
    "ↄ": "c",
    "ꜿ": "c",
    "ɘ": "e",
    "ɿ": "r",
    "ś": "s",
    "ṥ": "s",
    "š": "s",
    "ṧ": "s",
    "ş": "s",
    "ŝ": "s",
    "ș": "s",
    "ṡ": "s",
    "ṣ": "s",
    "ṩ": "s",
    "ʂ": "s",
    "ᵴ": "s",
    "ᶊ": "s",
    "ȿ": "s",
    "ɡ": "g",
    "ᴑ": "o",
    "ᴓ": "o",
    "ᴝ": "u",
    "ť": "t",
    "ţ": "t",
    "ṱ": "t",
    "ț": "t",
    "ȶ": "t",
    "ẗ": "t",
    "ⱦ": "t",
    "ṫ": "t",
    "ṭ": "t",
    "ƭ": "t",
    "ṯ": "t",
    "ᵵ": "t",
    "ƫ": "t",
    "ʈ": "t",
    "ŧ": "t",
    "ᵺ": "th",
    "ɐ": "a",
    "ᴂ": "ae",
    "ǝ": "e",
    "ᵷ": "g",
    "ɥ": "h",
    "ʮ": "h",
    "ʯ": "h",
    "ᴉ": "i",
    "ʞ": "k",
    "ꞁ": "l",
    "ɯ": "m",
    "ɰ": "m",
    "ᴔ": "oe",
    "ɹ": "r",
    "ɻ": "r",
    "ɺ": "r",
    "ⱹ": "r",
    "ʇ": "t",
    "ʌ": "v",
    "ʍ": "w",
    "ʎ": "y",
    "ꜩ": "tz",
    "ú": "u",
    "ŭ": "u",
    "ǔ": "u",
    "û": "u",
    "ṷ": "u",
    "ü": "u",
    "ǘ": "u",
    "ǚ": "u",
    "ǜ": "u",
    "ǖ": "u",
    "ṳ": "u",
    "ụ": "u",
    "ű": "u",
    "ȕ": "u",
    "ù": "u",
    "ủ": "u",
    "ư": "u",
    "ứ": "u",
    "ự": "u",
    "ừ": "u",
    "ử": "u",
    "ữ": "u",
    "ȗ": "u",
    "ū": "u",
    "ṻ": "u",
    "ų": "u",
    "ᶙ": "u",
    "ů": "u",
    "ũ": "u",
    "ṹ": "u",
    "ṵ": "u",
    "ᵫ": "ue",
    "ꝸ": "um",
    "ⱴ": "v",
    "ꝟ": "v",
    "ṿ": "v",
    "ʋ": "v",
    "ᶌ": "v",
    "ⱱ": "v",
    "ṽ": "v",
    "ꝡ": "vy",
    "ẃ": "w",
    "ŵ": "w",
    "ẅ": "w",
    "ẇ": "w",
    "ẉ": "w",
    "ẁ": "w",
    "ⱳ": "w",
    "ẘ": "w",
    "ẍ": "x",
    "ẋ": "x",
    "ᶍ": "x",
    "ý": "y",
    "ŷ": "y",
    "ÿ": "y",
    "ẏ": "y",
    "ỵ": "y",
    "ỳ": "y",
    "ƴ": "y",
    "ỷ": "y",
    "ỿ": "y",
    "ȳ": "y",
    "ẙ": "y",
    "ɏ": "y",
    "ỹ": "y",
    "ź": "z",
    "ž": "z",
    "ẑ": "z",
    "ʑ": "z",
    "ⱬ": "z",
    "ż": "z",
    "ẓ": "z",
    "ȥ": "z",
    "ẕ": "z",
    "ᵶ": "z",
    "ᶎ": "z",
    "ʐ": "z",
    "ƶ": "z",
    "ɀ": "z",
    "ff": "ff",
    "ffi": "ffi",
    "ffl": "ffl",
    "fi": "fi",
    "fl": "fl",
    "ij": "ij",
    "œ": "oe",
    "st": "st",
    "ₐ": "a",
    "ₑ": "e",
    "ᵢ": "i",
    "ⱼ": "j",
    "ₒ": "o",
    "ᵣ": "r",
    "ᵤ": "u",
    "ᵥ": "v",
    "ₓ": "x",
};
module.exports = Select;