/*!
 * 
 *   simple-keyboard v2.15.2 (Non-minified build)
 *   https://github.com/hodgef/simple-keyboard
 * 
 *   Copyright (c) Francisco Hodge (https://github.com/hodgef)
 * 
 *   This source code is licensed under a dual license system (MIT or GPL-3.0), as found in the
 *   LICENSE file in the root directory of this source tree.
 *   
 */
(function webpackUniversalModuleDefinition(root, factory) {
  if (typeof exports === "object" && typeof module === "object") {
    module.exports = factory();
  } else if (typeof define === "function" && define.amd) {
    define("SimpleKeyboard", [], factory);
  } else if (typeof exports === "object") {
    exports["SimpleKeyboard"] = factory();
  } else {
    root["SimpleKeyboard"] = factory();
  }
})(window, function() {
  /******/
  return function(modules) {
    // webpackBootstrap
    /******/ // The module cache
    /******/ var installedModules = {};
    /******/
    /******/ // The require function
    /******/    function __webpack_require__(moduleId) {
      /******/
      /******/ // Check if module is in cache
      /******/ if (installedModules[moduleId]) {
        /******/ return installedModules[moduleId].exports;
        /******/      }
      /******/ // Create a new module (and put it into the cache)
      /******/      var module = installedModules[moduleId] = {
        /******/ i: moduleId,
        /******/ l: false,
        /******/ exports: {}
        /******/      };
      /******/
      /******/ // Execute the module function
      /******/      modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
      /******/
      /******/ // Flag the module as loaded
      /******/      module.l = true;
      /******/
      /******/ // Return the exports of the module
      /******/      return module.exports;
      /******/    }
    /******/
    /******/
    /******/ // expose the modules object (__webpack_modules__)
    /******/    __webpack_require__.m = modules;
    /******/
    /******/ // expose the module cache
    /******/    __webpack_require__.c = installedModules;
    /******/
    /******/ // define getter function for harmony exports
    /******/    __webpack_require__.d = function(exports, name, getter) {
      /******/ if (!__webpack_require__.o(exports, name)) {
        /******/ Object.defineProperty(exports, name, {
          enumerable: true,
          get: getter
        });
        /******/      }
      /******/    };
    /******/
    /******/ // define __esModule on exports
    /******/    __webpack_require__.r = function(exports) {
      /******/ if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
        /******/ Object.defineProperty(exports, Symbol.toStringTag, {
          value: "Module"
        });
        /******/      }
      /******/      Object.defineProperty(exports, "__esModule", {
        value: true
      });
      /******/    };
    /******/
    /******/ // create a fake namespace object
    /******/ // mode & 1: value is a module id, require it
    /******/ // mode & 2: merge all properties of value into the ns
    /******/ // mode & 4: return value when already ns object
    /******/ // mode & 8|1: behave like require
    /******/    __webpack_require__.t = function(value, mode) {
      /******/ if (mode & 1) {
        value = __webpack_require__(value);
        /******/      }
      if (mode & 8) {
        return value;
        /******/      }
      if (mode & 4 && typeof value === "object" && value && value.__esModule) {
        return value;
        /******/      }
      var ns = Object.create(null);
      /******/      __webpack_require__.r(ns);
      /******/      Object.defineProperty(ns, "default", {
        enumerable: true,
        value: value
      });
      /******/      if (mode & 2 && typeof value != "string") {
        for (var key in value) {
          __webpack_require__.d(ns, key, function(key) {
            return value[key];
          }.bind(null, key));
          /******/        }
      }
      return ns;
      /******/    };
    /******/
    /******/ // getDefaultExport function for compatibility with non-harmony modules
    /******/    __webpack_require__.n = function(module) {
      /******/ var getter = module && module.__esModule ? 
      /******/ function getDefault() {
        return module["default"];
      } : 
      /******/ function getModuleExports() {
        return module;
      };
      /******/      __webpack_require__.d(getter, "a", getter);
      /******/      return getter;
      /******/    };
    /******/
    /******/ // Object.prototype.hasOwnProperty.call
    /******/    __webpack_require__.o = function(object, property) {
      return Object.prototype.hasOwnProperty.call(object, property);
    };
    /******/
    /******/ // __webpack_public_path__
    /******/    __webpack_require__.p = "";
    /******/
    /******/
    /******/ // Load entry module and return exports
    /******/    return __webpack_require__(__webpack_require__.s = 0);
    /******/  }
  /************************************************************************/
  /******/ ([ 
  /* 0 */
  /***/ function(module, exports, __webpack_require__) {
    module.exports = __webpack_require__(2);
    /***/  }, 
  /* 1 */
  /***/ function(module, exports, __webpack_require__) {
    // extracted by mini-css-extract-plugin
    /***/}, 
  /* 2 */
  /***/ function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    // EXTERNAL MODULE: ./src/lib/components/Keyboard.css
        var Keyboard = __webpack_require__(1);
    // CONCATENATED MODULE: ./src/lib/services/PhysicalKeyboard.js
        function _classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
      }
    }
    function _defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) {
          descriptor.writable = true;
        }
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }
    function _createClass(Constructor, protoProps, staticProps) {
      if (protoProps) {
        _defineProperties(Constructor.prototype, protoProps);
      }
      if (staticProps) {
        _defineProperties(Constructor, staticProps);
      }
      return Constructor;
    }
    /**
 * Physical Keyboard Service
 */    var PhysicalKeyboard = /* */ function() {
      /**
   * Creates an instance of the PhysicalKeyboard service
   */ function PhysicalKeyboard(simpleKeyboardInstance) {
        _classCallCheck(this, PhysicalKeyboard);
        /**
     * @type {object} A simple-keyboard instance
     */        this.simpleKeyboardInstance = simpleKeyboardInstance;
        /**
     * Bindings
     */        this.initKeyboardListener = this.initKeyboardListener.bind(this);
        this.getSimpleKeyboardLayoutKey = this.getSimpleKeyboardLayoutKey.bind(this);
        /**
     * Initialize key listeners
     */        this.initKeyboardListener();
      }
      /**
   * Initializes key event listeners
   */      _createClass(PhysicalKeyboard, [ {
        key: "initKeyboardListener",
        value: function initKeyboardListener() {
          var _this = this;
 // Adding button style on keydown
                    document.addEventListener("keydown", function(event) {
            if (_this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
              var buttonPressed = _this.getSimpleKeyboardLayoutKey(event);
              _this.simpleKeyboardInstance.dispatch(function(instance) {
                var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
                if (buttonDOM) {
                  buttonDOM.style.backgroundColor = _this.simpleKeyboardInstance.options.physicalKeyboardHighlightBgColor || "#9ab4d0";
                  buttonDOM.style.color = _this.simpleKeyboardInstance.options.physicalKeyboardHighlightTextColor || "white";
                }
              });
            }
          });
 // Removing button style on keyup
                    document.addEventListener("keyup", function(event) {
            if (_this.simpleKeyboardInstance.options.physicalKeyboardHighlight) {
              var buttonPressed = _this.getSimpleKeyboardLayoutKey(event);
              _this.simpleKeyboardInstance.dispatch(function(instance) {
                var buttonDOM = instance.getButtonElement(buttonPressed) || instance.getButtonElement("{".concat(buttonPressed, "}"));
                if (buttonDOM && buttonDOM.removeAttribute) {
                  buttonDOM.removeAttribute("style");
                }
              });
            }
          });
        }
        /**
   * Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format
   * @param  {object} event The KeyboardEvent
   */      }, {
        key: "getSimpleKeyboardLayoutKey",
        value: function getSimpleKeyboardLayoutKey(event) {
          var output;
          if (event.code.includes("Numpad") || event.code.includes("Shift") || event.code.includes("Space") || event.code.includes("Backspace") || event.code.includes("Control") || event.code.includes("Alt") || event.code.includes("Meta")) {
            output = event.code;
          } else {
            output = event.key;
          }
          /**
     * If button is not uppercase, casting to lowercase
     */          if (output !== output.toUpperCase() || event.code[0] === "F" && Number.isInteger(Number(event.code[1])) && event.code.length <= 3) {
            output = output.toLowerCase();
          }
          return output;
        }
      } ]);
      return PhysicalKeyboard;
    }();
 /* harmony default export */    var services_PhysicalKeyboard = PhysicalKeyboard;
    // CONCATENATED MODULE: ./src/lib/services/KeyboardLayout.js
        function KeyboardLayout_classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
      }
    }
    function KeyboardLayout_defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) {
          descriptor.writable = true;
        }
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }
    function KeyboardLayout_createClass(Constructor, protoProps, staticProps) {
      if (protoProps) {
        KeyboardLayout_defineProperties(Constructor.prototype, protoProps);
      }
      if (staticProps) {
        KeyboardLayout_defineProperties(Constructor, staticProps);
      }
      return Constructor;
    }
    /**
 * Keyboard Layout Service
 */    var KeyboardLayout = /* */ function() {
      function KeyboardLayout() {
        KeyboardLayout_classCallCheck(this, KeyboardLayout);
      }
      KeyboardLayout_createClass(KeyboardLayout, null, [ {
        key: "getDefaultLayout",
        /**
   * Get default simple-keyboard layout
   * @return {object} The default layout (US-QWERTY)
   */ value: function getDefaultLayout() {
          return {
            default: [ "` 1 2 3 4 5 6 7 8 9 0 - = {bksp}", "{tab} q w e r t y u i o p [ ] \\", "{lock} a s d f g h j k l ; ' {enter}", "{shift} z x c v b n m , . / {shift}", ".com @ {space}" ],
            shift: [ "~ ! @ # $ % ^ & * ( ) _ + {bksp}", "{tab} Q W E R T Y U I O P { } |", '{lock} A S D F G H J K L : " {enter}', "{shift} Z X C V B N M < > ? {shift}", ".com @ {space}" ]
          };
        }
      } ]);
      return KeyboardLayout;
    }();
 /* harmony default export */    var services_KeyboardLayout = KeyboardLayout;
    // CONCATENATED MODULE: ./src/lib/services/Utilities.js
        function _typeof(obj) {
      if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
        _typeof = function _typeof(obj) {
          return typeof obj;
        };
      } else {
        _typeof = function _typeof(obj) {
          return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
        };
      }
      return _typeof(obj);
    }
    function Utilities_classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
      }
    }
    function Utilities_defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) {
          descriptor.writable = true;
        }
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }
    function Utilities_createClass(Constructor, protoProps, staticProps) {
      if (protoProps) {
        Utilities_defineProperties(Constructor.prototype, protoProps);
      }
      if (staticProps) {
        Utilities_defineProperties(Constructor, staticProps);
      }
      return Constructor;
    }
    /**
 * Utility Service
 */    var Utilities = /* */ function() {
      /**
   * Creates an instance of the Utility service
   */ function Utilities(simpleKeyboardInstance) {
        Utilities_classCallCheck(this, Utilities);
        /**
     * @type {object} A simple-keyboard instance
     */        this.simpleKeyboardInstance = simpleKeyboardInstance;
        /**
     * Bindings
     */        this.getButtonClass = this.getButtonClass.bind(this);
        this.getButtonDisplayName = this.getButtonDisplayName.bind(this);
        this.getUpdatedInput = this.getUpdatedInput.bind(this);
        this.updateCaretPos = this.updateCaretPos.bind(this);
        this.updateCaretPosAction = this.updateCaretPosAction.bind(this);
        this.isMaxLengthReached = this.isMaxLengthReached.bind(this);
        this.camelCase = this.camelCase.bind(this);
        this.countInArray = this.countInArray.bind(this);
      }
      /**
   * Adds default classes to a given button
   *
   * @param  {string} button The button's layout name
   * @return {string} The classes to be added to the button
   */      Utilities_createClass(Utilities, [ {
        key: "getButtonClass",
        value: function getButtonClass(button) {
          var buttonTypeClass = button.includes("{") && button.includes("}") && button !== "{//}" ? "functionBtn" : "standardBtn";
          var buttonWithoutBraces = button.replace("{", "").replace("}", "");
          var buttonNormalized = "";
          if (buttonTypeClass !== "standardBtn") {
            buttonNormalized = " hg-button-".concat(buttonWithoutBraces);
          }
          return "hg-".concat(buttonTypeClass).concat(buttonNormalized);
        }
        /**
   * Default button display labels
   */      }, {
        key: "getDefaultDiplay",
        value: function getDefaultDiplay() {
          return {
            "{bksp}": "backspace",
            "{backspace}": "backspace",
            "{enter}": "< enter",
            "{shift}": "shift",
            "{shiftleft}": "shift",
            "{shiftright}": "shift",
            "{alt}": "alt",
            "{s}": "shift",
            "{tab}": "tab",
            "{lock}": "caps",
            "{capslock}": "caps",
            "{accept}": "Submit",
            "{space}": " ",
            "{//}": " ",
            "{esc}": "esc",
            "{escape}": "esc",
            "{f1}": "f1",
            "{f2}": "f2",
            "{f3}": "f3",
            "{f4}": "f4",
            "{f5}": "f5",
            "{f6}": "f6",
            "{f7}": "f7",
            "{f8}": "f8",
            "{f9}": "f9",
            "{f10}": "f10",
            "{f11}": "f11",
            "{f12}": "f12",
            "{numpaddivide}": "/",
            "{numlock}": "lock",
            "{arrowup}": "↑",
            "{arrowleft}": "←",
            "{arrowdown}": "↓",
            "{arrowright}": "→",
            "{prtscr}": "print",
            "{scrolllock}": "scroll",
            "{pause}": "pause",
            "{insert}": "ins",
            "{home}": "home",
            "{pageup}": "up",
            "{delete}": "del",
            "{end}": "end",
            "{pagedown}": "down",
            "{numpadmultiply}": "*",
            "{numpadsubtract}": "-",
            "{numpadadd}": "+",
            "{numpadenter}": "enter",
            "{period}": ".",
            "{numpaddecimal}": ".",
            "{numpad0}": "0",
            "{numpad1}": "1",
            "{numpad2}": "2",
            "{numpad3}": "3",
            "{numpad4}": "4",
            "{numpad5}": "5",
            "{numpad6}": "6",
            "{numpad7}": "7",
            "{numpad8}": "8",
            "{numpad9}": "9"
          };
        }
        /**
   * Returns the display (label) name for a given button
   *
   * @param  {string} button The button's layout name
   * @param  {object} display The provided display option
   * @param  {boolean} mergeDisplay Whether the provided param value should be merged with the default one.
   */      }, {
        key: "getButtonDisplayName",
        value: function getButtonDisplayName(button, display, mergeDisplay) {
          if (mergeDisplay) {
            display = Object.assign({}, this.getDefaultDiplay(), display);
          } else {
            display = display || this.getDefaultDiplay();
          }
          return display[button] || button;
        }
        /**
   * Returns the updated input resulting from clicking a given button
   *
   * @param  {string} button The button's layout name
   * @param  {string} input The input string
   * @param  {object} options The simple-keyboard options object
   * @param  {number} caretPos The cursor's current position
   * @param  {boolean} moveCaret Whether to update simple-keyboard's cursor
   */      }, {
        key: "getUpdatedInput",
        value: function getUpdatedInput(button, input, options, caretPos, moveCaret) {
          var output = input;
          if ((button === "{bksp}" || button === "{backspace}") && output.length > 0) {
            output = this.removeAt(output, caretPos, moveCaret);
          } else if (button === "{space}") {
            output = this.addStringAt(output, " ", caretPos, moveCaret);
          } else if (button === "{tab}" && !(typeof options.tabCharOnTab === "boolean" && options.tabCharOnTab === false)) {
            output = this.addStringAt(output, "\t", caretPos, moveCaret);
          } else if ((button === "{enter}" || button === "{numpadenter}") && options.newLineOnEnter) {
            output = this.addStringAt(output, "\n", caretPos, moveCaret);
          } else if (button.includes("numpad") && Number.isInteger(Number(button[button.length - 2]))) {
            output = this.addStringAt(output, button[button.length - 2], caretPos, moveCaret);
          } else if (button === "{numpaddivide}") {
            output = this.addStringAt(output, "/", caretPos, moveCaret);
          } else if (button === "{numpadmultiply}") {
            output = this.addStringAt(output, "*", caretPos, moveCaret);
          } else if (button === "{numpadsubtract}") {
            output = this.addStringAt(output, "-", caretPos, moveCaret);
          } else if (button === "{numpadadd}") {
            output = this.addStringAt(output, "+", caretPos, moveCaret);
          } else if (button === "{numpaddecimal}") {
            output = this.addStringAt(output, ".", caretPos, moveCaret);
          } else if (button === "{" || button === "}") {
            output = this.addStringAt(output, button, caretPos, moveCaret);
          } else if (!button.includes("{") && !button.includes("}")) {
            output = this.addStringAt(output, button, caretPos, moveCaret);
          }
          return output;
        }
        /**
   * Moves the cursor position by a given amount
   *
   * @param  {number} length Represents by how many characters the input should be moved
   * @param  {boolean} minus Whether the cursor should be moved to the left or not.
   */      }, {
        key: "updateCaretPos",
        value: function updateCaretPos(length, minus) {
          var newCaretPos = this.updateCaretPosAction(this.simpleKeyboardInstance, length, minus);
          if (this.simpleKeyboardInstance.options.syncInstanceInputs) {
            this.simpleKeyboardInstance.dispatch(function(instance) {
              instance.caretPosition = newCaretPos;
            });
          }
        }
        /**
   * Action method of updateCaretPos
   *
   * @param  {object} instance The instance whose position should be updated
   * @param  {number} length Represents by how many characters the input should be moved
   * @param  {boolean} minus Whether the cursor should be moved to the left or not.
   */      }, {
        key: "updateCaretPosAction",
        value: function updateCaretPosAction(instance, length, minus) {
          if (minus) {
            if (instance.caretPosition > 0) {
              instance.caretPosition = instance.caretPosition - length;
            }
          } else {
            instance.caretPosition = instance.caretPosition + length;
          }
          if (this.simpleKeyboardInstance.options.debug) {
            console.log("Caret at:", instance.caretPosition, "(".concat(instance.keyboardDOMClass, ")"));
          }
          return instance.caretPosition;
        }
        /**
   * Adds a string to the input at a given position
   *
   * @param  {string} source The source input
   * @param  {string} string The string to add
   * @param  {number} position The (cursor) position where the string should be added
   * @param  {boolean} moveCaret Whether to update simple-keyboard's cursor
   */      }, {
        key: "addStringAt",
        value: function addStringAt(source, string, position, moveCaret) {
          var output;
          if (!position && position !== 0) {
            output = source + string;
          } else {
            output = [ source.slice(0, position), string, source.slice(position) ].join("");
            /**
       * Avoid caret position change when maxLength is set
       */            if (!this.isMaxLengthReached()) {
              if (moveCaret) {
                this.updateCaretPos(string.length);
              }
            }
          }
          return output;
        }
        /**
   * Removes an amount of characters at a given position
   *
   * @param  {string} source The source input
   * @param  {number} position The (cursor) position from where the characters should be removed
   * @param  {boolean} moveCaret Whether to update simple-keyboard's cursor
   */      }, {
        key: "removeAt",
        value: function removeAt(source, position, moveCaret) {
          if (this.simpleKeyboardInstance.caretPosition === 0) {
            return source;
          }
          var output;
          var prevTwoChars;
          var emojiMatched;
          var emojiMatchedReg = /([\uD800-\uDBFF][\uDC00-\uDFFF])/g;
          /**
     * Emojis are made out of two characters, so we must take a custom approach to trim them.
     * For more info: https://mathiasbynens.be/notes/javascript-unicode
     */          if (position && position >= 0) {
            prevTwoChars = source.substring(position - 2, position);
            emojiMatched = prevTwoChars.match(emojiMatchedReg);
            if (emojiMatched) {
              output = source.substr(0, position - 2) + source.substr(position);
              if (moveCaret) {
                this.updateCaretPos(2, true);
              }
            } else {
              output = source.substr(0, position - 1) + source.substr(position);
              if (moveCaret) {
                this.updateCaretPos(1, true);
              }
            }
          } else {
            prevTwoChars = source.slice(-2);
            emojiMatched = prevTwoChars.match(emojiMatchedReg);
            if (emojiMatched) {
              output = source.slice(0, -2);
              if (moveCaret) {
                this.updateCaretPos(2, true);
              }
            } else {
              output = source.slice(0, -1);
              if (moveCaret) {
                this.updateCaretPos(1, true);
              }
            }
          }
          return output;
        }
        /**
   * Determines whether the maxLength has been reached. This function is called when the maxLength option it set.
   *
   * @param  {object} inputObj
   * @param  {object} options
   * @param  {string} updatedInput
   */      }, {
        key: "handleMaxLength",
        value: function handleMaxLength(inputObj, options, updatedInput) {
          var maxLength = options.maxLength;
          var currentInput = inputObj[options.inputName];
          var condition = currentInput.length === maxLength;
          if (
          /**
       * If pressing this button won't add more characters
       * We exit out of this limiter function
       */ updatedInput.length <= currentInput.length) {
            return false;
          }
          if (Number.isInteger(maxLength)) {
            if (options.debug) {
              console.log("maxLength (num) reached:", condition);
            }
            if (condition) {
              /**
         * @type {boolean} Boolean value that shows whether maxLength has been reached
         */ this.maxLengthReached = true;
              return true;
            } else {
              this.maxLengthReached = false;
              return false;
            }
          }
          if (_typeof(maxLength) === "object") {
            var _condition = currentInput.length === maxLength[options.inputName];
            if (options.debug) {
              console.log("maxLength (obj) reached:", _condition);
            }
            if (_condition) {
              this.maxLengthReached = true;
              return true;
            } else {
              this.maxLengthReached = false;
              return false;
            }
          }
        }
        /**
   * Gets the current value of maxLengthReached
   */      }, {
        key: "isMaxLengthReached",
        value: function isMaxLengthReached() {
          return Boolean(this.maxLengthReached);
        }
        /**
   * Transforms an arbitrary string to camelCase
   *
   * @param  {string} string The string to transform.
   */      }, {
        key: "camelCase",
        value: function camelCase(string) {
          return string.toLowerCase().trim().split(/[.\-_\s]/g).reduce(function(string, word) {
            return word.length ? string + word[0].toUpperCase() + word.slice(1) : string;
          });
        }
        /**
   * Counts the number of duplicates in a given array
   *
   * @param  {Array} array The haystack to search in
   * @param  {string} value The needle to search for
   */      }, {
        key: "countInArray",
        value: function countInArray(array, value) {
          return array.reduce(function(n, x) {
            return n + (x === value);
          }, 0);
        }
      } ]);
      return Utilities;
    }();
 /* harmony default export */    var services_Utilities = Utilities;
    // CONCATENATED MODULE: ./src/lib/components/Keyboard.js
        function Keyboard_typeof(obj) {
      if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
        Keyboard_typeof = function _typeof(obj) {
          return typeof obj;
        };
      } else {
        Keyboard_typeof = function _typeof(obj) {
          return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
        };
      }
      return Keyboard_typeof(obj);
    }
    function Keyboard_classCallCheck(instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
      }
    }
    function Keyboard_defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) {
          descriptor.writable = true;
        }
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }
    function Keyboard_createClass(Constructor, protoProps, staticProps) {
      if (protoProps) {
        Keyboard_defineProperties(Constructor.prototype, protoProps);
      }
      if (staticProps) {
        Keyboard_defineProperties(Constructor, staticProps);
      }
      return Constructor;
    }
    function _defineProperty(obj, key, value) {
      if (key in obj) {
        Object.defineProperty(obj, key, {
          value: value,
          enumerable: true,
          configurable: true,
          writable: true
        });
      } else {
        obj[key] = value;
      }
      return obj;
    }
 // Services
    /**
 * Root class for simple-keyboard
 * This class:
 * - Parses the options
 * - Renders the rows and buttons
 * - Handles button functionality
 */    var Keyboard_SimpleKeyboard = /* */ function() {
      /**
   * Creates an instance of SimpleKeyboard
   * @param {Array} params If first parameter is a string, it is considered the container class. The second parameter is then considered the options object. If first parameter is an object, it is considered the options object.
   */ function SimpleKeyboard() {
        var _this = this;
        Keyboard_classCallCheck(this, SimpleKeyboard);
        _defineProperty(this, "setOptions", function(option) {
          option = option || {};
          _this.options = Object.assign(_this.options, option);
          _this.render();
        });
        _defineProperty(this, "registerModule", function(name, initCallback) {
          if (!_this.modules[name]) {
            _this.modules[name] = {};
          }
          initCallback(_this.modules[name]);
        });
        _defineProperty(this, "getModuleProp", function(name, prop) {
          if (!_this.modules[name]) {
            return false;
          }
          return _this.modules[name][prop];
        });
        _defineProperty(this, "getModulesList", function() {
          return Object.keys(_this.modules);
        });
        var keyboardDOMQuery = typeof (arguments.length <= 0 ? undefined : arguments[0]) === "string" ? arguments.length <= 0 ? undefined : arguments[0] : ".simple-keyboard";
        var options = Keyboard_typeof(arguments.length <= 0 ? undefined : arguments[0]) === "object" ? arguments.length <= 0 ? undefined : arguments[0] : arguments.length <= 1 ? undefined : arguments[1];
        if (!options) {
          options = {};
          /**
     * Initializing Utilities
     */        }
        this.utilities = new services_Utilities(this);
        /**
     * Processing options
     */        this.keyboardDOM = document.querySelector(keyboardDOMQuery);
        /**
     * @type {object}
     * @property {object} layout Modify the keyboard layout.
     * @property {string} layoutName Specifies which layout should be used.
     * @property {object} display Replaces variable buttons (such as {bksp}) with a human-friendly name (e.g.: “backspace”).
     * @property {boolean} mergeDisplay By default, when you set the display property, you replace the default one. This setting merges them instead.
     * @property {string} theme A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space.
     * @property {Array} buttonTheme A prop to add your own css classes to one or several buttons.
     * @property {boolean} debug Runs a console.log every time a key is pressed. Displays the buttons pressed and the current input.
     * @property {boolean} newLineOnEnter Specifies whether clicking the “ENTER” button will input a newline (\n) or not.
     * @property {boolean} tabCharOnTab Specifies whether clicking the “TAB” button will input a tab character (\t) or not.
     * @property {string} inputName Allows you to use a single simple-keyboard instance for several inputs.
     * @property {number} maxLength Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute.
     * @property {object} maxLength Restrains simple-keyboard’s individual inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute.
     * @property {boolean} syncInstanceInputs When set to true, this option synchronizes the internal input of every simple-keyboard instance.
     * @property {boolean} physicalKeyboardHighlight Enable highlighting of keys pressed on physical keyboard.
     * @property {boolean} preventMouseDownDefault Calling preventDefault for the mousedown events keeps the focus on the input.
     * @property {string} physicalKeyboardHighlightTextColor Define the text color that the physical keyboard highlighted key should have.
     * @property {string} physicalKeyboardHighlightBgColor Define the background color that the physical keyboard highlighted key should have.
     * @property {function(button: string):string} onKeyPress Executes the callback function on key press. Returns button layout name (i.e.: “{shift}”).
     * @property {function(input: string):string} onChange Executes the callback function on input change. Returns the current input’s string.
     * @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
     * @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
     * @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs.
     * @property {boolean} useButtonTag Render buttons as a button element instead of a div element.
     * @property {boolean} disableCaretPositioning A prop to ensure characters are always be added/removed at the end of the string.
     * @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern.
     */        this.options = options;
        this.options.layoutName = this.options.layoutName || "default";
        this.options.theme = this.options.theme || "hg-theme-default";
        this.options.inputName = this.options.inputName || "default";
        this.options.preventMouseDownDefault = this.options.preventMouseDownDefault || false;
        /**
     * @type {object} Classes identifying loaded plugins
     */        this.keyboardPluginClasses = "";
        /**
     * Bindings
     */        this.handleButtonClicked = this.handleButtonClicked.bind(this);
        this.syncInstanceInputs = this.syncInstanceInputs.bind(this);
        this.clearInput = this.clearInput.bind(this);
        this.getInput = this.getInput.bind(this);
        this.setInput = this.setInput.bind(this);
        this.replaceInput = this.replaceInput.bind(this);
        this.clear = this.clear.bind(this);
        this.dispatch = this.dispatch.bind(this);
        this.addButtonTheme = this.addButtonTheme.bind(this);
        this.removeButtonTheme = this.removeButtonTheme.bind(this);
        this.getButtonElement = this.getButtonElement.bind(this);
        this.handleCaret = this.handleCaret.bind(this);
        this.caretEventHandler = this.caretEventHandler.bind(this);
        this.onInit = this.onInit.bind(this);
        this.onRender = this.onRender.bind(this);
        this.render = this.render.bind(this);
        this.loadModules = this.loadModules.bind(this);
        this.handleButtonMouseUp = this.handleButtonMouseUp.bind(this);
        this.handleButtonMouseDown = this.handleButtonMouseDown.bind(this);
        this.handleButtonHold = this.handleButtonHold.bind(this);
        this.onModulesLoaded = this.onModulesLoaded.bind(this);
        this.inputPatternIsValid = this.inputPatternIsValid.bind(this);
        /**
     * simple-keyboard uses a non-persistent internal input to keep track of the entered string (the variable `keyboard.input`).
     * This removes any dependency to input DOM elements. You can type and directly display the value in a div element, for example.
     * @example
     * // To get entered input
     * let input = keyboard.getInput();
     *
     * // To clear entered input.
     * keyboard.clearInput();
     *
     * @type {object}
     * @property {object} default Default SimpleKeyboard internal input.
     * @property {object} myInputName Example input that can be set through `options.inputName:"myInputName"`.
     */        this.input = {};
        this.input[this.options.inputName] = "";
        /**
     * @type {string} DOM class of the keyboard wrapper, normally "simple-keyboard" by default.
     */        this.keyboardDOMClass = keyboardDOMQuery.split(".").join("");
        /**
     * @type {object} Contains the DOM elements of every rendered button, the key being the button's layout name (e.g.: "{enter}").
     */        this.buttonElements = {};
        /**
     * Rendering keyboard
     */        if (this.keyboardDOM) {
          this.render();
        } else {
          console.warn('"'.concat(keyboardDOMQuery, '" was not found in the DOM.'));
          throw new Error("KEYBOARD_DOM_ERROR");
        }
        /**
     * Saving instance
     * This enables multiple simple-keyboard support with easier management
     */        if (!window["SimpleKeyboardInstances"]) {
          window["SimpleKeyboardInstances"] = {};
        }
        window["SimpleKeyboardInstances"][this.utilities.camelCase(this.keyboardDOMClass)] = this;
        /**
     * Physical Keyboard support
     */        this.physicalKeyboardInterface = new services_PhysicalKeyboard(this);
        /**
     * Modules
     */        this.modules = {};
        this.loadModules();
      }
      /**
   * Handles clicks made to keyboard buttons
   * @param  {string} button The button's layout name.
   */      Keyboard_createClass(SimpleKeyboard, [ {
        key: "handleButtonClicked",
        value: function handleButtonClicked(button) {
          var debug = this.options.debug;
          /**
     * Ignoring placeholder buttons
     */          if (button === "{//}") {
            return false;
            /**
     * Calling onKeyPress
     */          }
          if (typeof this.options.onKeyPress === "function") {
            this.options.onKeyPress(button);
          }
          if (!this.input[this.options.inputName]) {
            this.input[this.options.inputName] = "";
          }
          var updatedInput = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.options, this.caretPosition);
          if (// If input will change as a result of this button press
          this.input[this.options.inputName] !== updatedInput && (// This pertains to the "inputPattern" option:
          // If inputPattern isn't set
          !this.options.inputPattern || // Or, if it is set and if the pattern is valid - we proceed.
          this.options.inputPattern && this.inputPatternIsValid(updatedInput))) {
            /**
       * If maxLength and handleMaxLength yield true, halting
       */ if (this.options.maxLength && this.utilities.handleMaxLength(this.input, this.options, updatedInput)) {
              return false;
            }
            this.input[this.options.inputName] = this.utilities.getUpdatedInput(button, this.input[this.options.inputName], this.options, this.caretPosition, true);
            if (debug) {
              console.log("Input changed:", this.input);
              /**
       * Enforce syncInstanceInputs, if set
       */            }
            if (this.options.syncInstanceInputs) {
              this.syncInstanceInputs(this.input);
              /**
       * Calling onChange
       */            }
            if (typeof this.options.onChange === "function") {
              this.options.onChange(this.input[this.options.inputName]);
            }
          }
          if (debug) {
            console.log("Key pressed:", button);
          }
        }
        /**
   * Handles button mousedown
   */ /* istanbul ignore next */      }, {
        key: "handleButtonMouseDown",
        value: function handleButtonMouseDown(button, e) {
          var _this2 = this;
          /**
     * @type {boolean} Whether the mouse is being held onKeyPress
     */          this.isMouseHold = true;
          if (this.holdInteractionTimeout) {
            clearTimeout(this.holdInteractionTimeout);
          }
          if (this.holdTimeout) {
            clearTimeout(this.holdTimeout);
            /**
     * @type {object} Time to wait until a key hold is detected
     */          }
          this.holdTimeout = setTimeout(function() {
            if (_this2.isMouseHold && (!button.includes("{") && !button.includes("}") || button === "{bksp}" || button === "{space}" || button === "{tab}")) {
              if (_this2.options.debug) {
                console.log("Button held:", button);
              }
              _this2.handleButtonHold(button, e);
            }
            clearTimeout(_this2.holdTimeout);
          }, 500);
        }
        /**
   * Handles button mouseup
   */      }, {
        key: "handleButtonMouseUp",
        value: function handleButtonMouseUp() {
          this.isMouseHold = false;
          if (this.holdInteractionTimeout) {
            clearTimeout(this.holdInteractionTimeout);
          }
        }
        /**
   * Handles button hold
   */ /* istanbul ignore next */      }, {
        key: "handleButtonHold",
        value: function handleButtonHold(button) {
          var _this3 = this;
          if (this.holdInteractionTimeout) {
            clearTimeout(this.holdInteractionTimeout);
            /**
     * @type {object} Timeout dictating the speed of key hold iterations
     */          }
          this.holdInteractionTimeout = setTimeout(function() {
            if (_this3.isMouseHold) {
              _this3.handleButtonClicked(button);
              _this3.handleButtonHold(button);
            } else {
              clearTimeout(_this3.holdInteractionTimeout);
            }
          }, 100);
        }
        /**
   * Send a command to all simple-keyboard instances (if you have several instances).
   */      }, {
        key: "syncInstanceInputs",
        value: function syncInstanceInputs() {
          var _this4 = this;
          this.dispatch(function(instance) {
            instance.replaceInput(_this4.input);
          });
        }
        /**
   * Clear the keyboard’s input.
   * @param {string} [inputName] optional - the internal input to select
   */      }, {
        key: "clearInput",
        value: function clearInput(inputName) {
          inputName = inputName || this.options.inputName;
          this.input[inputName] = "";
          /**
     * Enforce syncInstanceInputs, if set
     */          if (this.options.syncInstanceInputs) {
            this.syncInstanceInputs(this.input);
          }
        }
        /**
   * Get the keyboard’s input (You can also get it from the onChange prop).
   * @param  {string} [inputName] optional - the internal input to select
   */      }, {
        key: "getInput",
        value: function getInput(inputName) {
          inputName = inputName || this.options.inputName;
          /**
     * Enforce syncInstanceInputs, if set
     */          if (this.options.syncInstanceInputs) {
            this.syncInstanceInputs(this.input);
          }
          return this.input[this.options.inputName];
        }
        /**
   * Set the keyboard’s input.
   * @param  {string} input the input value
   * @param  {string} inputName optional - the internal input to select
   */      }, {
        key: "setInput",
        value: function setInput(input, inputName) {
          inputName = inputName || this.options.inputName;
          this.input[inputName] = input;
          /**
     * Enforce syncInstanceInputs, if set
     */          if (this.options.syncInstanceInputs) {
            this.syncInstanceInputs(this.input);
          }
        }
        /**
   * Replace the input object (`keyboard.input`)
   * @param  {object} inputObj The input object
   */      }, {
        key: "replaceInput",
        value: function replaceInput(inputObj) {
          this.input = inputObj;
        }
        /**
   * Set new option or modify existing ones after initialization.
   * @param  {object} option The option to set
   */      }, {
        key: "clear",
        /**
   * Remove all keyboard rows and reset keyboard values.
   * Used interally between re-renders.
   */ value: function clear() {
          this.keyboardDOM.innerHTML = "";
          this.keyboardDOM.className = this.keyboardDOMClass;
          this.buttonElements = {};
        }
        /**
   * Send a command to all simple-keyboard instances at once (if you have multiple instances).
   * @param  {function(instance: object, key: string)} callback Function to run on every instance
   */      }, {
        key: "dispatch",
        value: function dispatch(callback) {
          if (!window["SimpleKeyboardInstances"]) {
            console.warn("SimpleKeyboardInstances is not defined. Dispatch cannot be called.");
            throw new Error("INSTANCES_VAR_ERROR");
          }
          return Object.keys(window["SimpleKeyboardInstances"]).forEach(function(key) {
            callback(window["SimpleKeyboardInstances"][key], key);
          });
        }
        /**
   * Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button.
   * @param  {string} buttons List of buttons to select (separated by a space).
   * @param  {string} className Classes to give to the selected buttons (separated by space).
   */      }, {
        key: "addButtonTheme",
        value: function addButtonTheme(buttons, className) {
          var _this5 = this;
          if (!className || !buttons) {
            return false;
          }
          buttons.split(" ").forEach(function(button) {
            className.split(" ").forEach(function(classNameItem) {
              if (!_this5.options.buttonTheme) {
                _this5.options.buttonTheme = [];
              }
              var classNameFound = false;
              /**
         * If class is already defined, we add button to class definition
         */              _this5.options.buttonTheme.map(function(buttonTheme) {
                if (buttonTheme.class.split(" ").includes(classNameItem)) {
                  classNameFound = true;
                  var buttonThemeArray = buttonTheme.buttons.split(" ");
                  if (!buttonThemeArray.includes(button)) {
                    classNameFound = true;
                    buttonThemeArray.push(button);
                    buttonTheme.buttons = buttonThemeArray.join(" ");
                  }
                }
                return buttonTheme;
              });
              /**
         * If class is not defined, we create a new entry
         */              if (!classNameFound) {
                _this5.options.buttonTheme.push({
                  class: classNameItem,
                  buttons: buttons
                });
              }
            });
          });
          this.render();
        }
        /**
   * Removes/Amends an entry to the `buttonTheme`. Basically a way to remove a class previously added to a button through buttonTheme or addButtonTheme.
   * @param  {string} buttons List of buttons to select (separated by a space).
   * @param  {string} className Classes to give to the selected buttons (separated by space).
   */      }, {
        key: "removeButtonTheme",
        value: function removeButtonTheme(buttons, className) {
          var _this6 = this;
          /**
     * When called with empty parameters, remove all button themes
     */          if (!buttons && !className) {
            this.options.buttonTheme = [];
            this.render();
            return false;
          }
          /**
     * If buttons are passed and buttonTheme has items
     */          if (buttons && Array.isArray(this.options.buttonTheme) && this.options.buttonTheme.length) {
            var buttonArray = buttons.split(" ");
            buttonArray.forEach(function(button, key) {
              _this6.options.buttonTheme.map(function(buttonTheme, index) {
                /**
           * If className is set, we affect the buttons only for that class
           * Otherwise, we afect all classes
           */ if (className && className.includes(buttonTheme.class) || !className) {
                  var filteredButtonArray = buttonTheme.buttons.split(" ").filter(function(item) {
                    return item !== button;
                  });
                  /**
             * If buttons left, return them, otherwise, remove button Theme
             */                  if (filteredButtonArray.length) {
                    buttonTheme.buttons = filteredButtonArray.join(" ");
                  } else {
                    _this6.options.buttonTheme.splice(index, 1);
                    buttonTheme = null;
                  }
                }
                return buttonTheme;
              });
            });
            this.render();
          }
        }
        /**
   * Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned.
   * @param  {string} button The button layout name to select
   */      }, {
        key: "getButtonElement",
        value: function getButtonElement(button) {
          var output;
          var buttonArr = this.buttonElements[button];
          if (buttonArr) {
            if (buttonArr.length > 1) {
              output = buttonArr;
            } else {
              output = buttonArr[0];
            }
          }
          return output;
        }
        /**
   * This handles the "inputPattern" option
   * by checking if the provided inputPattern passes
   */      }, {
        key: "inputPatternIsValid",
        value: function inputPatternIsValid(inputVal) {
          var inputPatternRaw = this.options.inputPattern;
          var inputPattern;
          /**
     * Check if input pattern is global or targeted to individual inputs
     */          if (inputPatternRaw instanceof RegExp) {
            inputPattern = inputPatternRaw;
          } else {
            inputPattern = inputPatternRaw[this.options.inputName];
          }
          if (inputPattern && inputVal) {
            var didInputMatch = inputPattern.test(inputVal);
            if (this.options.debug) {
              console.log('inputPattern ("'.concat(inputPattern, '"): ').concat(didInputMatch ? "passed" : "did not pass!"));
            }
            return didInputMatch;
          } else {
            /**
       * inputPattern doesn't seem to be set for the current input, or input is empty. Pass.
       */ return true;
          }
        }
        /**
   * Retrieves the current cursor position within a input or textarea (if any)
   */      }, {
        key: "handleCaret",
        value: function handleCaret() {
          /**
     * Only first instance should insall the caret handling events
     */ this.caretPosition = null;
          var simpleKeyboardInstances = window["SimpleKeyboardInstances"];
          if (simpleKeyboardInstances && Object.keys(simpleKeyboardInstances)[0] === this.utilities.camelCase(this.keyboardDOMClass) || !simpleKeyboardInstances) {
            if (this.options.debug) {
              console.log("Caret handling started (".concat(this.keyboardDOMClass, ")"));
            }
            document.addEventListener("keyup", this.caretEventHandler);
            document.addEventListener("mouseup", this.caretEventHandler);
            document.addEventListener("touchend", this.caretEventHandler);
          }
        }
        /**
   * Called by {@link handleCaret} when an event that warrants a cursor position update is triggered
   */      }, {
        key: "caretEventHandler",
        value: function caretEventHandler(event) {
          var targetTagName;
          if (event.target.tagName) {
            targetTagName = event.target.tagName.toLowerCase();
          }
          this.dispatch(function(instance) {
            if (instance.isMouseHold) {
              instance.isMouseHold = false;
            }
            if ((targetTagName === "textarea" || targetTagName === "input") && !instance.options.disableCaretPositioning) {
              /**
         * Tracks current cursor position
         * As keys are pressed, text will be added/removed at that position within the input.
         */ instance.caretPosition = event.target.selectionStart;
              if (instance.options.debug) {
                console.log("Caret at: ", event.target.selectionStart, event.target.tagName.toLowerCase(), "(".concat(instance.keyboardDOMClass, ")"));
              }
            } else if (instance.options.disableCaretPositioning) {
              /**
         * If we toggled off disableCaretPositioning, we must ensure caretPosition doesn't persist once reactivated.
         */ instance.caretPosition = null;
            }
          });
        }
        /**
   * Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
   */      }, {
        key: "onInit",
        value: function onInit() {
          if (this.options.debug) {
            console.log("".concat(this.keyboardDOMClass, " Initialized"));
          }
          /**
     * Caret handling
     */          this.handleCaret();
          if (typeof this.options.onInit === "function") {
            this.options.onInit();
          }
        }
        /**
   * Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
   */      }, {
        key: "onRender",
        value: function onRender() {
          if (typeof this.options.onRender === "function") {
            this.options.onRender();
          }
        }
        /**
   * Executes the callback function once all modules have been loaded
   */      }, {
        key: "onModulesLoaded",
        value: function onModulesLoaded() {
          if (typeof this.options.onModulesLoaded === "function") {
            this.options.onModulesLoaded();
          }
        }
        /**
   * Register module
   */      }, {
        key: "loadModules",
        /**
   * Load modules
   */ value: function loadModules() {
          var _this7 = this;
          if (Array.isArray(this.options.modules)) {
            this.options.modules.forEach(function(Module) {
              var module = new Module();
 /* istanbul ignore next */              if (module.constructor.name && module.constructor.name !== "Function") {
                var classStr = "module-".concat(_this7.utilities.camelCase(module.constructor.name));
                _this7.keyboardPluginClasses = _this7.keyboardPluginClasses + " ".concat(classStr);
              }
              module.init(_this7);
            });
            this.keyboardPluginClasses = this.keyboardPluginClasses + " modules-loaded";
            this.render();
            this.onModulesLoaded();
          }
        }
        /**
   * Get module prop
   */      }, {
        key: "render",
        /**
   * Renders rows and buttons as per options
   */ value: function render() {
          var _this8 = this;
          /**
     * Clear keyboard
     */          this.clear();
          var layoutClass = "hg-layout-".concat(this.options.layoutName);
          var layout = this.options.layout || services_KeyboardLayout.getDefaultLayout();
          var useTouchEvents = this.options.useTouchEvents || false;
          /**
     * Account for buttonTheme, if set
     */          var buttonThemesParsed = {};
          if (Array.isArray(this.options.buttonTheme)) {
            this.options.buttonTheme.forEach(function(themeObj) {
              if (themeObj.buttons && themeObj.class) {
                var themeButtons;
                if (typeof themeObj.buttons === "string") {
                  themeButtons = themeObj.buttons.split(" ");
                }
                if (themeButtons) {
                  themeButtons.forEach(function(themeButton) {
                    var themeParsed = buttonThemesParsed[themeButton];
 // If the button has already been added
                                        if (themeParsed) {
                      // Making sure we don't add duplicate classes, even when buttonTheme has duplicates
                      if (!_this8.utilities.countInArray(themeParsed.split(" "), themeObj.class)) {
                        buttonThemesParsed[themeButton] = "".concat(themeParsed, " ").concat(themeObj.class);
                      }
                    } else {
                      buttonThemesParsed[themeButton] = themeObj.class;
                    }
                  });
                }
              } else {
                console.warn('buttonTheme row is missing the "buttons" or the "class". Please check the documentation.');
              }
            });
          }
          /**
     * Adding themeClass, layoutClass to keyboardDOM
     */          this.keyboardDOM.className += " ".concat(this.options.theme, " ").concat(layoutClass, " ").concat(this.keyboardPluginClasses);
          /**
     * Iterating through each row
     */          layout[this.options.layoutName].forEach(function(row, rIndex) {
            var rowArray = row.split(" ");
            /**
       * Creating empty row
       */            var rowDOM = document.createElement("div");
            rowDOM.className += "hg-row";
            /**
       * Iterating through each button in row
       */            rowArray.forEach(function(button, bIndex) {
              var fctBtnClass = _this8.utilities.getButtonClass(button);
              var buttonThemeClass = buttonThemesParsed[button];
              var buttonDisplayName = _this8.utilities.getButtonDisplayName(button, _this8.options.display, _this8.options.mergeDisplay);
              /**
         * Creating button
         */              var buttonType = _this8.options.useButtonTag ? "button" : "div";
              var buttonDOM = document.createElement(buttonType);
              buttonDOM.className += "hg-button ".concat(fctBtnClass).concat(buttonThemeClass ? " " + buttonThemeClass : "");
              if (useTouchEvents) {
                buttonDOM.ontouchstart = function(e) {
                  _this8.handleButtonClicked(button);
                  _this8.handleButtonMouseDown(button, e);
                };
                buttonDOM.ontouchend = function(e) {
                  return _this8.handleButtonMouseUp();
                };
                buttonDOM.ontouchcancel = function(e) {
                  return _this8.handleButtonMouseUp();
                };
              } else {
                buttonDOM.onclick = function() {
                  _this8.isMouseHold = false;
                  _this8.handleButtonClicked(button);
                };
                buttonDOM.onmousedown = function(e) {
                  if (_this8.options.preventMouseDownDefault) {
                    e.preventDefault();
                  }
                  _this8.handleButtonMouseDown(button, e);
                };
              }
              /**
         * Adding identifier
         */              buttonDOM.setAttribute("data-skBtn", button);
              /**
         * Adding unique id
         * Since there's no limit on spawning same buttons, the unique id ensures you can style every button
         */              var buttonUID = "".concat(_this8.options.layoutName, "-r").concat(rIndex, "b").concat(bIndex);
              buttonDOM.setAttribute("data-skBtnUID", buttonUID);
              /**
         * Adding display label
         */              buttonDOM.setAttribute("data-displayLabel", buttonDisplayName);
              /**
         * Adding button label to button
         */              var buttonSpanDOM = document.createElement("span");
              buttonSpanDOM.innerHTML = buttonDisplayName;
              buttonDOM.appendChild(buttonSpanDOM);
              /**
         * Adding to buttonElements
         */              if (!_this8.buttonElements[button]) {
                _this8.buttonElements[button] = [];
              }
              _this8.buttonElements[button].push(buttonDOM);
              /**
         * Appending button to row
         */              rowDOM.appendChild(buttonDOM);
            });
            /**
       * Appending row to keyboard
       */            _this8.keyboardDOM.appendChild(rowDOM);
          });
          /**
     * Calling onRender
     */          this.onRender();
          if (!this.initialized) {
            /**
       * Ensures that onInit is only called once per instantiation
       */ this.initialized = true;
            /**
       * Handling mouseup
       */            if (!useTouchEvents) {
              document.onmouseup = function() {
                return _this8.handleButtonMouseUp();
              };
            }
            /**
       * Calling onInit
       */            this.onInit();
          }
        }
      } ]);
      return SimpleKeyboard;
    }();
 /* harmony default export */    var components_Keyboard = Keyboard_SimpleKeyboard;
    // CONCATENATED MODULE: ./src/lib/index.js
    /* harmony default export */    var lib = __webpack_exports__["default"] = components_Keyboard;
    /***/  }
  /******/ ]);
});