diff --git a/.eslintrc.json b/.eslintrc.json index a736dc9f..d614b0b2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,7 +1,6 @@ { "parser": "@typescript-eslint/parser", "parserOptions": { - "project": "./tsconfig.json", "ecmaVersion": 6, "sourceType": "module", "ecmaFeatures": { diff --git a/build/css/index.css b/build/css/index.css index c1ea7bf2..2c4af004 100644 --- a/build/css/index.css +++ b/build/css/index.css @@ -8,4 +8,4 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - */.hg-theme-default{width:100%;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation}.hg-theme-default .hg-button span{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;outline:0;font-size:inherit}.hg-theme-default{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;background-color:#ececec;padding:5px;border-radius:5px}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px} \ No newline at end of file + */.hg-theme-default{width:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box;overflow:hidden;touch-action:manipulation;font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;background-color:#ececec;padding:5px;border-radius:5px}.hg-theme-default .hg-button span{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;outline:0;font-size:inherit}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{box-shadow:0 0 3px -1px rgba(0,0,0,.3);height:40px;border-radius:5px;box-sizing:border-box;padding:5px;background:#fff;border-bottom:1px solid #b5b5b5;cursor:pointer;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-standardBtn{width:20px}.hg-theme-default .hg-button.hg-functionBtn .hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}.hg-candidate-box{display:inline-flex;border-radius:5px;position:absolute;background:#ececec;border-bottom:2px solid #b5b5b5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;min-width:272px;transform:translateY(-100%);margin-top:-10px}ul.hg-candidate-box-list{display:flex;list-style:none;padding:0;margin:0;flex:1}li.hg-candidate-box-list-item{height:40px;width:40px;display:flex;align-items:center;justify-content:center}li.hg-candidate-box-list-item:hover{background:rgba(0,0,0,.03);cursor:pointer}li.hg-candidate-box-list-item:active{background:rgba(0,0,0,.1)}.hg-candidate-box-prev:before{content:"◄"}.hg-candidate-box-next:before{content:"►"}.hg-candidate-box-next,.hg-candidate-box-prev{display:flex;align-items:center;padding:0 10px;background:#d0d0d0;color:#969696;cursor:pointer}.hg-candidate-box-next{border-top-right-radius:5px;border-bottom-right-radius:5px}.hg-candidate-box-prev{border-top-left-radius:5px;border-bottom-left-radius:5px}.hg-candidate-box-btn-active{color:#444} \ No newline at end of file diff --git a/build/css/index.css.map b/build/css/index.css.map deleted file mode 100644 index 892df734..00000000 --- a/build/css/index.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["index.css","webpack://./src/lib/components/Keyboard.css"],"names":[],"mappings":"AAAA;;;;;;;;;;EAUE,CCNF,kBACE,UAAW,CACX,gBAAiB,CACjB,qBAAsB,CACtB,eAAgB,CAChB,yBACF,CAEA,kCACE,mBACF,CAGA,mCACE,cAAe,CACf,SAAU,CACV,iBACF,CAEA,kBACE,4GAC+C,CAC/C,wBAAyB,CACzB,WAAY,CACZ,iBACF,CAEA,6BACE,oBAAqB,CACrB,WAEF,CAEA,0BACE,YACF,CAEA,2CACE,iBACF,CAMA,qGACE,gBACF,CAEA,yCACE,cACF,CAEA,+CACE,YACF,CAEA,6BACE,sCAA+C,CAC/C,WAAY,CACZ,iBAAkB,CAClB,qBAAsB,CACtB,WAAY,CACZ,eAAiB,CACjB,+BAAgC,CAChC,cAAe,CACf,YAAa,CACb,kBAAmB,CACnB,sBAAuB,CACvB,yCACF,CAEA,6CACE,kBACF,CAEA,+CACE,WAAY,CACZ,WAAY,CACZ,kBAAmB,CACnB,YAAa,CACb,sBACF,CAMA,oGACE,WACF,CAEA,+CACE,WACF,CAEA,2CACE,cACF,CAEA,yDACE,cACF,CAEA,+CACE,4BAAiC,CACjC,UACF,CAEA,+DACE,cACF,CAEA,4DACE,cACF","file":"index.css","sourcesContent":["/*!\n * \n * simple-keyboard v3.0.0-beta.0\n * https://github.com/hodgef/simple-keyboard\n *\n * Copyright (c) Francisco Hodge (https://github.com/hodgef) and project contributors.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n */\n/**\r\n * simple-keyboard\r\n * Theme: hg-theme-default\r\n */\r\n.hg-theme-default {\r\n width: 100%;\r\n user-select: none;\r\n box-sizing: border-box;\r\n overflow: hidden;\r\n touch-action: manipulation;\r\n}\r\n\r\n.hg-theme-default .hg-button span {\r\n pointer-events: none;\r\n}\r\n\r\n/* When using option \"useButtonTag\" */\r\n.hg-theme-default button.hg-button {\r\n border-width: 0;\r\n outline: 0;\r\n font-size: inherit;\r\n}\r\n\r\n.hg-theme-default {\r\n font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\",\r\n Helvetica, Arial, \"Lucida Grande\", sans-serif;\r\n background-color: #ececec;\r\n padding: 5px;\r\n border-radius: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-button {\r\n display: inline-block;\r\n flex-grow: 1;\r\n cursor: pointer;\r\n}\r\n\r\n.hg-theme-default .hg-row {\r\n display: flex;\r\n}\r\n\r\n.hg-theme-default .hg-row:not(:last-child) {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button:not(:last-child) {\r\n margin-right: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button-container {\r\n margin-right: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row > div:last-child {\r\n margin-right: 0;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button-container {\r\n display: flex;\r\n}\r\n\r\n.hg-theme-default .hg-button {\r\n box-shadow: 0px 0px 3px -1px rgba(0, 0, 0, 0.3);\r\n height: 40px;\r\n border-radius: 5px;\r\n box-sizing: border-box;\r\n padding: 5px;\r\n background: white;\r\n border-bottom: 1px solid #b5b5b5;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-activeButton {\r\n background: #efefef;\r\n}\r\n\r\n.hg-theme-default.hg-layout-numeric .hg-button {\r\n width: 33.3%;\r\n height: 60px;\r\n align-items: center;\r\n display: flex;\r\n justify-content: center;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpadadd {\r\n height: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpadenter {\r\n height: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpad0 {\r\n width: 105px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-com {\r\n max-width: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn.hg-button-at {\r\n max-width: 45px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-selectedButton {\r\n background: rgba(5, 25, 70, 0.53);\r\n color: white;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\".com\"] {\r\n max-width: 82px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\"@\"] {\r\n max-width: 60px;\r\n}\r\n\n","/**\r\n * simple-keyboard\r\n * Theme: hg-theme-default\r\n */\r\n.hg-theme-default {\r\n width: 100%;\r\n user-select: none;\r\n box-sizing: border-box;\r\n overflow: hidden;\r\n touch-action: manipulation;\r\n}\r\n\r\n.hg-theme-default .hg-button span {\r\n pointer-events: none;\r\n}\r\n\r\n/* When using option \"useButtonTag\" */\r\n.hg-theme-default button.hg-button {\r\n border-width: 0;\r\n outline: 0;\r\n font-size: inherit;\r\n}\r\n\r\n.hg-theme-default {\r\n font-family: \"HelveticaNeue-Light\", \"Helvetica Neue Light\", \"Helvetica Neue\",\r\n Helvetica, Arial, \"Lucida Grande\", sans-serif;\r\n background-color: #ececec;\r\n padding: 5px;\r\n border-radius: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-button {\r\n display: inline-block;\r\n flex-grow: 1;\r\n cursor: pointer;\r\n}\r\n\r\n.hg-theme-default .hg-row {\r\n display: flex;\r\n}\r\n\r\n.hg-theme-default .hg-row:not(:last-child) {\r\n margin-bottom: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button:not(:last-child) {\r\n margin-right: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button-container {\r\n margin-right: 5px;\r\n}\r\n\r\n.hg-theme-default .hg-row > div:last-child {\r\n margin-right: 0;\r\n}\r\n\r\n.hg-theme-default .hg-row .hg-button-container {\r\n display: flex;\r\n}\r\n\r\n.hg-theme-default .hg-button {\r\n box-shadow: 0px 0px 3px -1px rgba(0, 0, 0, 0.3);\r\n height: 40px;\r\n border-radius: 5px;\r\n box-sizing: border-box;\r\n padding: 5px;\r\n background: white;\r\n border-bottom: 1px solid #b5b5b5;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-activeButton {\r\n background: #efefef;\r\n}\r\n\r\n.hg-theme-default.hg-layout-numeric .hg-button {\r\n width: 33.3%;\r\n height: 60px;\r\n align-items: center;\r\n display: flex;\r\n justify-content: center;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpadadd {\r\n height: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpadenter {\r\n height: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-numpad0 {\r\n width: 105px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-button-com {\r\n max-width: 85px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn.hg-button-at {\r\n max-width: 45px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-selectedButton {\r\n background: rgba(5, 25, 70, 0.53);\r\n color: white;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\".com\"] {\r\n max-width: 82px;\r\n}\r\n\r\n.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=\"@\"] {\r\n max-width: 60px;\r\n}\r\n"]} diff --git a/build/index.d.ts b/build/index.d.ts deleted file mode 100644 index f27283b5..00000000 --- a/build/index.d.ts +++ /dev/null @@ -1,618 +0,0 @@ -declare module "services/KeyboardLayout" { - export const getDefaultLayout: () => { - default: string[]; - shift: string[]; - }; -} -declare module "interfaces" { - export interface KeyboardLayoutObject { - [key: string]: string[]; - } - export interface KeyboardButtonTheme { - class: string; - buttons: string; - } - export interface KeyboardButtonAttributes { - attribute: string; - value: string; - buttons: string; - } - export interface KeyboardInput { - [key: string]: string; - } - export type KeyboardButton = HTMLDivElement | HTMLButtonElement; - export type KeyboardHandlerEvent = PointerEvent & TouchEvent & KeyboardEvent & { - target: HTMLDivElement | HTMLInputElement; - }; - export interface KeyboardButtonElements { - [key: string]: KeyboardButton[]; - } - export interface UtilitiesParams { - getOptions: () => KeyboardOptions; - getCaretPosition: () => number; - getCaretPositionEnd: () => number; - dispatch: any; - } - export interface KeyboardOptions { - /** - * Modify the keyboard layout. - */ - layout?: KeyboardLayoutObject; - /** - * Specifies which layout should be used. - */ - layoutName?: string; - /** - * Replaces variable buttons (such as `{bksp}`) with a human-friendly name (e.g.: `backspace`). - */ - display?: { - [button: string]: string; - }; - /** - * By default, when you set the display property, you replace the default one. This setting merges them instead. - */ - mergeDisplay?: boolean; - /** - * A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space. - */ - theme?: string; - /** - * A prop to add your own css classes to one or several buttons. - */ - buttonTheme?: KeyboardButtonTheme[]; - /** - * A prop to add your own attributes to one or several buttons. - */ - buttonAttributes?: KeyboardButtonAttributes[]; - /** - * Runs a `console.log` every time a key is pressed. Displays the buttons pressed and the current input. - */ - debug?: boolean; - /** - * Specifies whether clicking the "ENTER" button will input a newline (`\n`) or not. - */ - newLineOnEnter?: boolean; - /** - * Specifies whether clicking the "TAB" button will input a tab character (`\t`) or not. - */ - tabCharOnTab?: boolean; - /** - * Allows you to use a single simple-keyboard instance for several inputs. - */ - inputName?: string; - /** - * `number`: Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute. - * - * `{ [inputName: string]: number }`: Restrains simple-keyboard’s individual inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute. - */ - maxLength?: any; - /** - * When set to true, this option synchronizes the internal input of every simple-keyboard instance. - */ - syncInstanceInputs?: boolean; - /** - * Enable highlighting of keys pressed on physical keyboard. - */ - physicalKeyboardHighlight?: boolean; - /** - * Presses keys highlighted by physicalKeyboardHighlight - */ - physicalKeyboardHighlightPress?: boolean; - /** - * Define the text color that the physical keyboard highlighted key should have. - */ - physicalKeyboardHighlightTextColor?: string; - /** - * Define the background color that the physical keyboard highlighted key should have. - */ - physicalKeyboardHighlightBgColor?: string; - /** - * Calling preventDefault for the mousedown events keeps the focus on the input. - */ - preventMouseDownDefault?: boolean; - /** - * Calling preventDefault for the mouseup events. - */ - preventMouseUpDefault?: boolean; - /** - * Stops pointer down events on simple-keyboard buttons from bubbling to parent elements. - */ - stopMouseDownPropagation?: boolean; - /** - * Stops pointer up events on simple-keyboard buttons from bubbling to parent elements. - */ - stopMouseUpPropagation?: boolean; - /** - * Render buttons as a button element instead of a div element. - */ - useButtonTag?: boolean; - /** - * A prop to ensure characters are always be added/removed at the end of the string. - */ - disableCaretPositioning?: boolean; - /** - * Restrains input(s) change to the defined regular expression pattern. - */ - inputPattern?: any; - /** - * Instructs simple-keyboard to use touch events instead of click events. - */ - useTouchEvents?: boolean; - /** - * Enable useTouchEvents automatically when touch device is detected. - */ - autoUseTouchEvents?: boolean; - /** - * Opt out of PointerEvents handling, falling back to the prior mouse event logic. - */ - useMouseEvents?: boolean; - /** - * Disable button hold action. - */ - disableButtonHold?: boolean; - /** - * Adds unicode right-to-left control characters to input return values. - */ - rtl?: boolean; - /** - * Module options can have any format - */ - [name: string]: any; - } -} -declare module "services/Utilities" { - import { KeyboardInput } from "interfaces"; - import { KeyboardOptions, UtilitiesParams } from "interfaces"; - /** - * Utility Service - */ - class Utilities { - getOptions: () => KeyboardOptions; - getCaretPosition: () => number; - getCaretPositionEnd: () => number; - dispatch: any; - maxLengthReached: boolean; - /** - * Creates an instance of the Utility service - */ - constructor({ getOptions, getCaretPosition, getCaretPositionEnd, dispatch, }: UtilitiesParams); - /** - * 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 - */ - getButtonClass(button: string): string; - /** - * Default button display labels - */ - getDefaultDiplay(): { - "{bksp}": string; - "{backspace}": string; - "{enter}": string; - "{shift}": string; - "{shiftleft}": string; - "{shiftright}": string; - "{alt}": string; - "{s}": string; - "{tab}": string; - "{lock}": string; - "{capslock}": string; - "{accept}": string; - "{space}": string; - "{//}": string; - "{esc}": string; - "{escape}": string; - "{f1}": string; - "{f2}": string; - "{f3}": string; - "{f4}": string; - "{f5}": string; - "{f6}": string; - "{f7}": string; - "{f8}": string; - "{f9}": string; - "{f10}": string; - "{f11}": string; - "{f12}": string; - "{numpaddivide}": string; - "{numlock}": string; - "{arrowup}": string; - "{arrowleft}": string; - "{arrowdown}": string; - "{arrowright}": string; - "{prtscr}": string; - "{scrolllock}": string; - "{pause}": string; - "{insert}": string; - "{home}": string; - "{pageup}": string; - "{delete}": string; - "{end}": string; - "{pagedown}": string; - "{numpadmultiply}": string; - "{numpadsubtract}": string; - "{numpadadd}": string; - "{numpadenter}": string; - "{period}": string; - "{numpaddecimal}": string; - "{numpad0}": string; - "{numpad1}": string; - "{numpad2}": string; - "{numpad3}": string; - "{numpad4}": string; - "{numpad5}": string; - "{numpad6}": string; - "{numpad7}": string; - "{numpad8}": string; - "{numpad9}": string; - }; - /** - * 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. - */ - getButtonDisplayName(button: string, display: KeyboardOptions["display"], mergeDisplay: boolean): string; - /** - * 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 {number} caretPos The cursor's current position - * @param {number} caretPosEnd The cursor's current end position - * @param {boolean} moveCaret Whether to update simple-keyboard's cursor - */ - getUpdatedInput(button: string, input: string, caretPos: number, caretPosEnd?: number, moveCaret?: boolean): string; - /** - * 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. - */ - updateCaretPos(length: number, minus?: boolean): void; - /** - * Action method of updateCaretPos - * - * @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. - */ - updateCaretPosAction(length: number, minus?: boolean): number; - /** - * Adds a string to the input at a given position - * - * @param {string} source The source input - * @param {string} str 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 - */ - addStringAt(source: string, str: string, position?: number, positionEnd?: number, moveCaret?: boolean): string; - /** - * 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 - */ - removeAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string; - /** - * Determines whether the maxLength has been reached. This function is called when the maxLength option it set. - * - * @param {object} inputObj - * @param {string} updatedInput - */ - handleMaxLength(inputObj: KeyboardInput, updatedInput: string): boolean; - /** - * Gets the current value of maxLengthReached - */ - isMaxLengthReached(): boolean; - /** - * Determines whether a touch device is being used - */ - isTouchDevice(): number | true; - /** - * Determines whether pointer events are supported - */ - pointerEventsSupported(): { - new (type: string, eventInitDict?: PointerEventInit): PointerEvent; - prototype: PointerEvent; - }; - /** - * Bind all methods in a given class - */ - static bindMethods(myClass: any, instance: any): void; - /** - * Transforms an arbitrary string to camelCase - * - * @param {string} str The string to transform. - */ - camelCase(str: string): string; - static noop: () => void; - } - export default Utilities; -} -declare module "services/PhysicalKeyboard" { - import { KeyboardOptions, UtilitiesParams } from "interfaces"; - /** - * Physical Keyboard Service - */ - class PhysicalKeyboard { - getOptions: () => KeyboardOptions; - dispatch: any; - /** - * Creates an instance of the PhysicalKeyboard service - */ - constructor({ dispatch, getOptions }: Partial); - handleHighlightKeyDown(event: KeyboardEvent): void; - handleHighlightKeyUp(event: KeyboardEvent): void; - /** - * Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format - * @param {object} event The KeyboardEvent - */ - getSimpleKeyboardLayoutKey(event: KeyboardEvent): string; - } - export default PhysicalKeyboard; -} -declare module "components/Keyboard" { - import "./Keyboard.css"; - import PhysicalKeyboard from "services/PhysicalKeyboard"; - import { KeyboardOptions, KeyboardInput, KeyboardButtonElements, KeyboardHandlerEvent, KeyboardButton } from "interfaces"; - /** - * Root class for simple-keyboard - * This class: - * - Parses the options - * - Renders the rows and buttons - * - Handles button functionality - */ - class SimpleKeyboard { - input: KeyboardInput; - options: KeyboardOptions; - utilities: any; - caretPosition: number; - caretPositionEnd: number; - keyboardDOM: KeyboardButton; - keyboardPluginClasses: string; - keyboardDOMClass: string; - buttonElements: KeyboardButtonElements; - currentInstanceName: string; - allKeyboardInstances: { - [key: string]: SimpleKeyboard; - }; - keyboardInstanceNames: string[]; - isFirstKeyboardInstance: boolean; - physicalKeyboard: PhysicalKeyboard; - modules: { - [key: string]: any; - }; - activeButtonClass: string; - holdInteractionTimeout: number; - holdTimeout: number; - isMouseHold: boolean; - initialized: boolean; - /** - * 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. - */ - constructor(...params: []); - /** - * parseParams - */ - handleParams: (params: any[]) => { - keyboardDOMClass: string; - keyboardDOM: KeyboardButton; - options: Partial; - }; - /** - * Getters - */ - getOptions: () => KeyboardOptions; - getCaretPosition: () => number; - getCaretPositionEnd: () => number; - /** - * Changes the internal caret position - * @param {number} position The caret's start position - * @param {number} positionEnd The caret's end position - */ - setCaretPosition(position: number, endPosition?: number): void; - /** - * Handles clicks made to keyboard buttons - * @param {string} button The button's layout name. - */ - handleButtonClicked(button: string): void; - /** - * Handles button mousedown - */ - handleButtonMouseDown(button: string, e: KeyboardHandlerEvent): void; - /** - * Handles button mouseup - */ - handleButtonMouseUp(button?: string, e?: KeyboardHandlerEvent): void; - /** - * Handles container mousedown - */ - handleKeyboardContainerMouseDown(e: KeyboardHandlerEvent): void; - /** - * Handles button hold - */ - handleButtonHold(button: string): void; - /** - * Send a command to all simple-keyboard instances (if you have several instances). - */ - syncInstanceInputs(): void; - /** - * Clear the keyboard’s input. - * @param {string} [inputName] optional - the internal input to select - */ - clearInput(inputName: string): void; - /** - * Get the keyboard’s input (You can also get it from the onChange prop). - * @param {string} [inputName] optional - the internal input to select - */ - getInput(inputName: string, skipSync?: boolean): string; - /** - * Get all simple-keyboard inputs - */ - getAllInputs(): KeyboardInput; - /** - * Set the keyboard’s input. - * @param {string} input the input value - * @param {string} inputName optional - the internal input to select - */ - setInput(input: string, inputName: string): void; - /** - * Replace the input object (`keyboard.input`) - * @param {object} inputObj The input object - */ - replaceInput(inputObj: KeyboardInput): void; - /** - * Set new option or modify existing ones after initialization. - * @param {object} options The options to set - */ - setOptions(options?: {}): void; - /** - * Detecting changes to non-function options - * This allows us to ascertain whether a button re-render is needed - */ - changedOptions(newOptions: Partial): string[]; - /** - * Executing actions depending on changed options - * @param {object} options The options to set - */ - onSetOptions(options: Partial): void; - /** - * Remove all keyboard rows and reset keyboard values. - * Used internally between re-renders. - */ - clear(): void; - /** - * 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 - */ - dispatch(callback: (instance: SimpleKeyboard, key?: string) => void): void; - /** - * 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). - */ - addButtonTheme(buttons: string, className: string): void; - /** - * 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). - */ - removeButtonTheme(buttons: string, className: string): void; - /** - * 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 - */ - getButtonElement(button: string): KeyboardButton | KeyboardButton[]; - /** - * This handles the "inputPattern" option - * by checking if the provided inputPattern passes - */ - inputPatternIsValid(inputVal: string): boolean; - /** - * Handles simple-keyboard event listeners - */ - setEventListeners(): void; - /** - * Event Handler: KeyUp - */ - handleKeyUp(event: KeyboardHandlerEvent): void; - /** - * Event Handler: KeyDown - */ - handleKeyDown(event: KeyboardHandlerEvent): void; - /** - * Event Handler: MouseUp - */ - handleMouseUp(event: KeyboardHandlerEvent): void; - /** - * Event Handler: TouchEnd - */ - handleTouchEnd(event: KeyboardHandlerEvent): void; - /** - * Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered - */ - caretEventHandler(event: KeyboardHandlerEvent): void; - /** - * Execute an operation on each button - */ - recurseButtons(fn: any): void; - /** - * Destroy keyboard listeners and DOM elements - */ - destroy(): void; - /** - * Process buttonTheme option - */ - getButtonThemeClasses(button: string): string[]; - /** - * Process buttonAttributes option - */ - setDOMButtonAttributes(button: string, callback: any): void; - onTouchDeviceDetected(): void; - /** - * Disabling contextual window for hg-button - */ - disableContextualWindow(): void; - /** - * Process autoTouchEvents option - */ - processAutoTouchEvents(): void; - /** - * Executes the callback function once simple-keyboard is rendered for the first time (on initialization). - */ - onInit(): void; - /** - * Executes the callback function before a simple-keyboard render. - */ - beforeFirstRender(): void; - /** - * Executes the callback function before a simple-keyboard render. - */ - beforeRender(): void; - /** - * Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts). - */ - onRender(): void; - /** - * Executes the callback function once all modules have been loaded - */ - onModulesLoaded(): void; - /** - * Register module - */ - registerModule: (name: string, initCallback: any) => void; - /** - * Load modules - */ - loadModules(): void; - /** - * Get module prop - */ - getModuleProp(name: string, prop: string): any; - /** - * getModulesList - */ - getModulesList(): string[]; - /** - * Parse Row DOM containers - */ - parseRowDOMContainers(rowDOM: HTMLDivElement, rowIndex: number, containerStartIndexes: number[], containerEndIndexes: number[]): HTMLDivElement; - /** - * getKeyboardClassString - */ - getKeyboardClassString: (...baseDOMClasses: any[]) => string; - /** - * Renders rows and buttons as per options - */ - render(): void; - } - export default SimpleKeyboard; -} -declare module "index" { - import SimpleKeyboard from "components/Keyboard"; - export default SimpleKeyboard; -} diff --git a/build/index.js b/build/index.js index 071f9a58..b4af5c47 100644 --- a/build/index.js +++ b/build/index.js @@ -9,5 +9,4 @@ * LICENSE file in the root directory of this source tree. * */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SimpleKeyboard=e():t.SimpleKeyboard=e()}(self,(function(){return(()=>{"use strict";var t={d:(e,n)=>{for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{default:()=>g});function n(t,e){var n;if("undefined"==typeof Symbol||null==t[Symbol.iterator]){if(Array.isArray(t)||(n=function(t,e){if(!t)return;if("string"==typeof t)return o(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);"Object"===n&&t.constructor&&(n=t.constructor.name);if("Map"===n||"Set"===n)return Array.from(t);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(t,e)}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var i=0,s=function(){};return{s,n:function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,r=!0,u=!1;return{s:function(){n=t[Symbol.iterator]()},n:function(){var t=n.next();return r=t.done,t},e:function(t){u=!0,a=t},f:function(){try{r||null==n.return||n.return()}finally{if(u)throw a}}}}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n3&&void 0!==arguments[3]?arguments[3]:n,i=arguments.length>4&&void 0!==arguments[4]&&arguments[4],s=this.getOptions(),a=[n,o,i],r=e;return("{bksp}"===t||"{backspace}"===t)&&r.length>0?r=this.removeAt.apply(this,[r].concat(a)):"{space}"===t?r=this.addStringAt.apply(this,[r," "].concat(a)):"{tab}"!==t||"boolean"==typeof s.tabCharOnTab&&!1===s.tabCharOnTab?"{enter}"!==t&&"{numpadenter}"!==t||!s.newLineOnEnter?t.includes("numpad")&&Number.isInteger(Number(t[t.length-2]))?r=this.addStringAt.apply(this,[r,t[t.length-2]].concat(a)):"{numpaddivide}"===t?r=this.addStringAt.apply(this,[r,"/"].concat(a)):"{numpadmultiply}"===t?r=this.addStringAt.apply(this,[r,"*"].concat(a)):"{numpadsubtract}"===t?r=this.addStringAt.apply(this,[r,"-"].concat(a)):"{numpadadd}"===t?r=this.addStringAt.apply(this,[r,"+"].concat(a)):"{numpaddecimal}"===t?r=this.addStringAt.apply(this,[r,"."].concat(a)):"{"===t||"}"===t?r=this.addStringAt.apply(this,[r,t].concat(a)):t.includes("{")||t.includes("}")||(r=this.addStringAt.apply(this,[r,t].concat(a))):r=this.addStringAt.apply(this,[r,"\n"].concat(a)):r=this.addStringAt.apply(this,[r,"\t"].concat(a)),r}},{key:"updateCaretPos",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=this.updateCaretPosAction(t,e);this.dispatch((function(t){t.setCaretPosition(n)}))}},{key:"updateCaretPosAction",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=this.getOptions(),o=this.getCaretPosition();return e?o>0&&(o-=t):o+=t,n.debug&&console.log("Caret at:",o),o}},{key:"addStringAt",value:function(t,e){var n,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t.length,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:t.length,s=arguments.length>4&&void 0!==arguments[4]&&arguments[4];return o||0===o?(n=[t.slice(0,o),e,t.slice(i)].join(""),this.isMaxLengthReached()||s&&this.updateCaretPos(e.length)):n=t+e,n}},{key:"removeAt",value:function(t){var e,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t.length,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t.length,i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(0===n&&0===o)return t;if(n===o){var s=/([\uD800-\uDBFF][\uDC00-\uDFFF])/g;n&&n>=0?t.substring(n-2,n).match(s)?(e=t.substr(0,n-2)+t.substr(n),i&&this.updateCaretPos(2,!0)):(e=t.substr(0,n-1)+t.substr(n),i&&this.updateCaretPos(1,!0)):t.slice(-2).match(s)?(e=t.slice(0,-2),i&&this.updateCaretPos(2,!0)):(e=t.slice(0,-1),i&&this.updateCaretPos(1,!0))}else e=t.slice(0,n)+t.slice(o),i&&this.dispatch((function(t){t.setCaretPosition(n)}));return e}},{key:"handleMaxLength",value:function(t,e){var n=this.getOptions(),o=n.maxLength,s=t[n.inputName],a=e.length-1>=o;if(e.length<=s.length)return!1;if(Number.isInteger(o))return n.debug&&console.log("maxLength (num) reached:",a),a?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1);if("object"===i(o)){var r=e.length-1>=o[n.inputName];return n.debug&&console.log("maxLength (obj) reached:",r),r?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1)}}},{key:"isMaxLengthReached",value:function(){return Boolean(this.maxLengthReached)}},{key:"isTouchDevice",value:function(){return"ontouchstart"in window||navigator.maxTouchPoints}},{key:"pointerEventsSupported",value:function(){return window.PointerEvent}},{key:"camelCase",value:function(t){if(t)return t.toLowerCase().trim().split(/[.\-_\s]/g).reduce((function(t,e){return e.length?t+e[0].toUpperCase()+e.slice(1):t}))}}])&&s(e.prototype,o),r&&s(e,r),t}();a(r,"noop",(function(){}));const u=r;function c(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,o=new Array(e);n1&&void 0!==arguments[1]?arguments[1]:t;this.caretPosition=t,this.caretPositionEnd=e}},{key:"handleButtonClicked",value:function(t){var e=this.options.debug;if("{//}"!==t){"function"==typeof this.options.onKeyPress&&this.options.onKeyPress(t),this.input[this.options.inputName]||(this.input[this.options.inputName]="");var n=this.utilities.getUpdatedInput(t,this.input[this.options.inputName],this.caretPosition,this.caretPositionEnd);if(this.input[this.options.inputName]!==n&&(!this.options.inputPattern||this.options.inputPattern&&this.inputPatternIsValid(n))){if(this.options.maxLength&&this.utilities.handleMaxLength(this.input,n))return;this.input[this.options.inputName]=this.utilities.getUpdatedInput(t,this.input[this.options.inputName],this.caretPosition,this.caretPositionEnd,!0),e&&console.log("Input changed:",this.getAllInputs()),this.options.debug&&console.log("Caret at: ",this.getCaretPosition(),this.getCaretPositionEnd(),"(".concat(this.keyboardDOMClass,")")),this.options.syncInstanceInputs&&this.syncInstanceInputs(),"function"==typeof this.options.onChange&&this.options.onChange(this.getInput(this.options.inputName,!0)),"function"==typeof this.options.onChangeAll&&this.options.onChangeAll(this.getAllInputs())}e&&console.log("Key pressed:",t)}}},{key:"handleButtonMouseDown",value:function(t,e){var n=this;e&&(this.options.preventMouseDownDefault&&e.preventDefault(),this.options.stopMouseDownPropagation&&e.stopPropagation(),e.target.classList.add(this.activeButtonClass)),this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdTimeout&&clearTimeout(this.holdTimeout),this.isMouseHold=!0,this.options.disableButtonHold||(this.holdTimeout=window.setTimeout((function(){(n.isMouseHold&&(!t.includes("{")&&!t.includes("}")||"{delete}"===t||"{backspace}"===t||"{bksp}"===t||"{space}"===t||"{tab}"===t)||"{arrowright}"===t||"{arrowleft}"===t||"{arrowup}"===t||"{arrowdown}"===t)&&(n.options.debug&&console.log("Button held:",t),n.handleButtonHold(t)),clearTimeout(n.holdTimeout)}),500))}},{key:"handleButtonMouseUp",value:function(t,e){var n=this;e&&(this.options.preventMouseUpDefault&&e.preventDefault(),this.options.stopMouseUpPropagation&&e.stopPropagation()),this.recurseButtons((function(t){t.classList.remove(n.activeButtonClass)})),this.isMouseHold=!1,this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),t&&"function"==typeof this.options.onKeyReleased&&this.options.onKeyReleased(t)}},{key:"handleKeyboardContainerMouseDown",value:function(t){this.options.preventMouseDownDefault&&t.preventDefault()}},{key:"handleButtonHold",value:function(t){var e=this;this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdInteractionTimeout=window.setTimeout((function(){e.isMouseHold?(e.handleButtonClicked(t),e.handleButtonHold(t)):clearTimeout(e.holdInteractionTimeout)}),100)}},{key:"syncInstanceInputs",value:function(){var t=this;this.dispatch((function(e){e.replaceInput(t.input),e.setCaretPosition(t.caretPosition,t.caretPositionEnd)}))}},{key:"clearInput",value:function(t){t=t||this.options.inputName,this.input[t]="",this.setCaretPosition(0),this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"getInput",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];if(t=t||this.options.inputName,this.options.syncInstanceInputs&&!e&&this.syncInstanceInputs(),this.options.rtl){var n=this.input[t].replace("‫","").replace("‬","");return"‫"+n+"‬"}return this.input[t]}},{key:"getAllInputs",value:function(){var t=this,e={};return Object.keys(this.input).forEach((function(n){e[n]=t.getInput(n,!0)})),e}},{key:"setInput",value:function(t,e){e=e||this.options.inputName,this.input[e]=t,this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"replaceInput",value:function(t){this.input=t}},{key:"setOptions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=this.changedOptions(t);this.options=Object.assign(this.options,t),e.length&&(this.options.debug&&console.log("changedOptions",e),this.onSetOptions(t),this.render())}},{key:"changedOptions",value:function(t){var e=this;return Object.keys(t).filter((function(n){return JSON.stringify(t[n])!==JSON.stringify(e.options[n])}))}},{key:"onSetOptions",value:function(t){t.inputName&&(this.options.debug&&console.log("inputName changed. caretPosition reset."),this.setCaretPosition(null))}},{key:"clear",value:function(){this.keyboardDOM.innerHTML="",this.keyboardDOM.className=this.keyboardDOMClass,this.buttonElements={}}},{key:"dispatch",value:function(t){if(!window.SimpleKeyboardInstances)throw console.warn("SimpleKeyboardInstances is not defined. Dispatch cannot be called."),new Error("INSTANCES_VAR_ERROR");return Object.keys(window.SimpleKeyboardInstances).forEach((function(e){t(window.SimpleKeyboardInstances[e],e)}))}},{key:"addButtonTheme",value:function(t,e){var n=this;e&&t&&(t.split(" ").forEach((function(o){e.split(" ").forEach((function(e){n.options.buttonTheme||(n.options.buttonTheme=[]);var i=!1;n.options.buttonTheme.map((function(t){if(t.class.split(" ").includes(e)){i=!0;var n=t.buttons.split(" ");n.includes(o)||(i=!0,n.push(o),t.buttons=n.join(" "))}return t})),i||n.options.buttonTheme.push({class:e,buttons:t})}))})),this.render())}},{key:"removeButtonTheme",value:function(t,e){var n=this;if(!t&&!e)return this.options.buttonTheme=[],void this.render();t&&Array.isArray(this.options.buttonTheme)&&this.options.buttonTheme.length&&(t.split(" ").forEach((function(t){n.options.buttonTheme.map((function(o,i){if(e&&e.includes(o.class)||!e){var s=o.buttons.split(" ").filter((function(e){return e!==t}));s.length?o.buttons=s.join(" "):(n.options.buttonTheme.splice(i,1),o=null)}return o}))})),this.render())}},{key:"getButtonElement",value:function(t){var e,n=this.buttonElements[t];return n&&(e=n.length>1?n:n[0]),e}},{key:"inputPatternIsValid",value:function(t){var e,n=this.options.inputPattern;if((e=n instanceof RegExp?n:n[this.options.inputName])&&t){var o=e.test(t);return this.options.debug&&console.log('inputPattern ("'.concat(e,'"): ').concat(o?"passed":"did not pass!")),o}return!0}},{key:"setEventListeners",value:function(){!this.isFirstKeyboardInstance&&this.allKeyboardInstances||(this.options.debug&&console.log("Caret handling started (".concat(this.keyboardDOMClass,")")),document.addEventListener("keyup",this.handleKeyUp),document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("mouseup",this.handleMouseUp),document.addEventListener("touchend",this.handleTouchEnd))}},{key:"handleKeyUp",value:function(t){this.caretEventHandler(t),this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyUp(t)}},{key:"handleKeyDown",value:function(t){this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyDown(t)}},{key:"handleMouseUp",value:function(t){this.caretEventHandler(t)}},{key:"handleTouchEnd",value:function(t){this.caretEventHandler(t)}},{key:"caretEventHandler",value:function(t){var e;t.target.tagName&&(e=t.target.tagName.toLowerCase()),this.dispatch((function(n){var o=t.target===n.keyboardDOM||t.target&&n.keyboardDOM.contains(t.target);n.isMouseHold&&(n.isMouseHold=!1),"textarea"!==e&&"input"!==e||!("selectionStart"in t.target)||!("selectionEnd"in t.target)||n.options.disableCaretPositioning?!n.options.disableCaretPositioning&&o||n.setCaretPosition(null):(n.setCaretPosition(t.target.selectionStart,t.target.selectionEnd),n.options.debug&&console.log("Caret at: ",n.getCaretPosition(),n.getCaretPositionEnd(),t&&t.target.tagName.toLowerCase(),"(".concat(n.keyboardDOMClass,")")))}))}},{key:"recurseButtons",value:function(t){var e=this;t&&Object.keys(this.buttonElements).forEach((function(n){return e.buttonElements[n].forEach(t)}))}},{key:"destroy",value:function(){this.options.debug&&console.log("Destroying simple-keyboard instance: ".concat(this.currentInstanceName)),document.removeEventListener("keyup",this.handleKeyUp),document.removeEventListener("keydown",this.handleKeyDown),document.removeEventListener("mouseup",this.handleMouseUp),document.removeEventListener("touchend",this.handleTouchEnd),document.onpointerup=null,document.ontouchend=null,document.ontouchcancel=null,document.onmouseup=null;var t=function(t){t.onpointerdown=null,t.onpointerup=null,t.onpointercancel=null,t.ontouchstart=null,t.ontouchend=null,t.ontouchcancel=null,t.onclick=null,t.onmousedown=null,t.onmouseup=null,t.remove(),t=null};this.recurseButtons(t),this.recurseButtons=null,t=null,this.keyboardDOM.onpointerdown=null,this.keyboardDOM.ontouchstart=null,this.keyboardDOM.onmousedown=null,this.clear(),window.SimpleKeyboardInstances[this.currentInstanceName]=null,delete window.SimpleKeyboardInstances[this.currentInstanceName],this.initialized=!1}},{key:"getButtonThemeClasses",value:function(t){var e=this.options.buttonTheme,n=[];return Array.isArray(e)&&e.forEach((function(e){if(e.class&&"string"==typeof e.class&&e.buttons&&"string"==typeof e.buttons){var o=e.class.split(" ");e.buttons.split(" ").includes(t)&&(n=[].concat(d(n),d(o)))}else console.warn('Incorrect "buttonTheme". Please check the documentation.',e)})),n}},{key:"setDOMButtonAttributes",value:function(t,e){var n=this.options.buttonAttributes;Array.isArray(n)&&n.forEach((function(n){n.attribute&&"string"==typeof n.attribute&&n.value&&"string"==typeof n.value&&n.buttons&&"string"==typeof n.buttons?n.buttons.split(" ").includes(t)&&e(n.attribute,n.value):console.warn('Incorrect "buttonAttributes". Please check the documentation.',n)}))}},{key:"onTouchDeviceDetected",value:function(){this.processAutoTouchEvents(),this.disableContextualWindow()}},{key:"disableContextualWindow",value:function(){window.oncontextmenu=function(t){if(t.target.classList.contains("hg-button"))return t.preventDefault(),t.stopPropagation(),!1}}},{key:"processAutoTouchEvents",value:function(){this.options.autoUseTouchEvents&&(this.options.useTouchEvents=!0,this.options.debug&&console.log("autoUseTouchEvents: Touch device detected, useTouchEvents enabled."))}},{key:"onInit",value:function(){this.options.debug&&console.log("".concat(this.keyboardDOMClass," Initialized")),this.setEventListeners(),"function"==typeof this.options.onInit&&this.options.onInit()}},{key:"beforeFirstRender",value:function(){this.utilities.isTouchDevice()&&this.onTouchDeviceDetected(),"function"==typeof this.options.beforeFirstRender&&this.options.beforeFirstRender(),this.isFirstKeyboardInstance&&this.utilities.pointerEventsSupported()&&!this.options.useTouchEvents&&!this.options.useMouseEvents&&this.options.debug&&console.log("Using PointerEvents as it is supported by this browser"),this.options.useTouchEvents&&this.options.debug&&console.log("useTouchEvents has been enabled. Only touch events will be used.")}},{key:"beforeRender",value:function(){"function"==typeof this.options.beforeRender&&this.options.beforeRender()}},{key:"onRender",value:function(){"function"==typeof this.options.onRender&&this.options.onRender()}},{key:"onModulesLoaded",value:function(){"function"==typeof this.options.onModulesLoaded&&this.options.onModulesLoaded(this)}},{key:"loadModules",value:function(){var t=this;Array.isArray(this.options.modules)&&(this.options.modules.forEach((function(e){(new e).init(t)})),this.keyboardPluginClasses="modules-loaded",this.render(),this.onModulesLoaded())}},{key:"getModuleProp",value:function(t,e){return!!this.modules[t]&&this.modules[t][e]}},{key:"getModulesList",value:function(){return Object.keys(this.modules)}},{key:"parseRowDOMContainers",value:function(t,e,n,o){var i=this,s=Array.from(t.children),a=0;return s.length&&n.forEach((function(n,r){var u=o[r];if(!(u&&u>n))return!1;var c=n-a,l=u-a,h=document.createElement("div");h.className+="hg-button-container";var d="".concat(i.options.layoutName,"-r").concat(e,"c").concat(r);h.setAttribute("data-skUID",d);var p=s.splice(c,l-c+1);a=l-c,p.forEach((function(t){return h.appendChild(t)})),s.splice(c,0,h),t.innerHTML="",s.forEach((function(e){return t.appendChild(e)})),i.options.debug&&console.log("rowDOMContainer",p,c,l,a+1)})),t}},{key:"render",value:function(){var t=this;this.clear(),this.initialized||this.beforeFirstRender(),this.beforeRender();var e="hg-layout-".concat(this.options.layoutName),n=this.options.layout||{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}"]},o=this.options.useTouchEvents||!1,i=o?"hg-touch-events":"",s=this.options.useMouseEvents||!1,a=this.options.disableRowButtonContainers;this.keyboardDOM.className=this.getKeyboardClassString(this.options.theme,e,this.keyboardPluginClasses,i),n[this.options.layoutName].forEach((function(e,n){var i=e.split(" "),r=document.createElement("div");r.className+="hg-row";var u=[],c=[];i.forEach((function(e,i){var l,h=!a&&"string"==typeof e&&e.length>1&&0===e.indexOf("["),p=!a&&"string"==typeof e&&e.length>1&&e.indexOf("]")===e.length-1;h&&(u.push(i),e=e.replace(/\[/g,"")),p&&(c.push(i),e=e.replace(/\]/g,""));var f=t.utilities.getButtonClass(e),y=t.utilities.getButtonDisplayName(e,t.options.display,t.options.mergeDisplay),m=t.options.useButtonTag?"button":"div",g=document.createElement(m);g.className+="hg-button ".concat(f),(l=g.classList).add.apply(l,d(t.getButtonThemeClasses(e))),t.setDOMButtonAttributes(e,(function(t,e){g.setAttribute(t,e)})),t.activeButtonClass="hg-activeButton",!t.utilities.pointerEventsSupported()||o||s?o?(g.ontouchstart=function(n){t.handleButtonClicked(e),t.handleButtonMouseDown(e,n)},g.ontouchend=function(n){t.handleButtonMouseUp(e,n)},g.ontouchcancel=function(n){t.handleButtonMouseUp(e,n)}):(g.onclick=function(){t.isMouseHold=!1,t.handleButtonClicked(e)},g.onmousedown=function(n){t.handleButtonMouseDown(e,n)},g.onmouseup=function(n){t.handleButtonMouseUp(e,n)}):(g.onpointerdown=function(n){t.handleButtonClicked(e),t.handleButtonMouseDown(e,n)},g.onpointerup=function(n){t.handleButtonMouseUp(e,n)},g.onpointercancel=function(n){t.handleButtonMouseUp(e,n)}),g.setAttribute("data-skBtn",e);var b="".concat(t.options.layoutName,"-r").concat(n,"b").concat(i);g.setAttribute("data-skBtnUID",b);var v=document.createElement("span");v.innerHTML=y,g.appendChild(v),t.buttonElements[e]||(t.buttonElements[e]=[]),t.buttonElements[e].push(g),r.appendChild(g)})),r=t.parseRowDOMContainers(r,n,u,c),t.keyboardDOM.appendChild(r)})),this.onRender(),this.initialized||(this.initialized=!0,!this.utilities.pointerEventsSupported()||o||s?o?(document.ontouchend=function(){return t.handleButtonMouseUp()},document.ontouchcancel=function(){return t.handleButtonMouseUp()},this.keyboardDOM.ontouchstart=function(e){return t.handleKeyboardContainerMouseDown(e)}):o||(document.onmouseup=function(){return t.handleButtonMouseUp()},this.keyboardDOM.onmousedown=function(e){return t.handleKeyboardContainerMouseDown(e)}):(document.onpointerup=function(){return t.handleButtonMouseUp()},this.keyboardDOM.onpointerdown=function(e){return t.handleKeyboardContainerMouseDown(e)}),this.onInit())}}])&&y(e.prototype,n),o&&y(e,o),t}();return e})()})); -//# sourceMappingURL=index.js.map \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SimpleKeyboard=e():t.SimpleKeyboard=e()}(this,(function(){return function(){var t={3099:function(t){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},6077:function(t,e,n){var o=n(111);t.exports=function(t){if(!o(t)&&null!==t)throw TypeError("Can't set "+String(t)+" as a prototype");return t}},1223:function(t,e,n){var o=n(5112),r=n(30),i=n(3070),a=o("unscopables"),s=Array.prototype;null==s[a]&&i.f(s,a,{configurable:!0,value:r(null)}),t.exports=function(t){s[a][t]=!0}},1530:function(t,e,n){"use strict";var o=n(8710).charAt;t.exports=function(t,e,n){return e+(n?o(t,e).length:1)}},9670:function(t,e,n){var o=n(111);t.exports=function(t){if(!o(t))throw TypeError(String(t)+" is not an object");return t}},8533:function(t,e,n){"use strict";var o=n(2092).forEach,r=n(9341)("forEach");t.exports=r?[].forEach:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}},8457:function(t,e,n){"use strict";var o=n(9974),r=n(7908),i=n(3411),a=n(7659),s=n(7466),u=n(6135),c=n(1246);t.exports=function(t){var e,n,l,f,p,d,h=r(t),v="function"==typeof this?this:Array,g=arguments.length,y=g>1?arguments[1]:void 0,m=void 0!==y,b=c(h),x=0;if(m&&(y=o(y,g>2?arguments[2]:void 0,2)),null==b||v==Array&&a(b))for(n=new v(e=s(h.length));e>x;x++)d=m?y(h[x],x):h[x],u(n,x,d);else for(p=(f=b.call(h)).next,n=new v;!(l=p.call(f)).done;x++)d=m?i(f,y,[l.value,x],!0):l.value,u(n,x,d);return n.length=x,n}},1318:function(t,e,n){var o=n(5656),r=n(7466),i=n(1400),a=function(t){return function(e,n,a){var s,u=o(e),c=r(u.length),l=i(a,c);if(t&&n!=n){for(;c>l;)if((s=u[l++])!=s)return!0}else for(;c>l;l++)if((t||l in u)&&u[l]===n)return t||l||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},2092:function(t,e,n){var o=n(9974),r=n(8361),i=n(7908),a=n(7466),s=n(5417),u=[].push,c=function(t){var e=1==t,n=2==t,c=3==t,l=4==t,f=6==t,p=7==t,d=5==t||f;return function(h,v,g,y){for(var m,b,x=i(h),w=r(x),E=o(v,g,3),O=a(w.length),S=0,k=y||s,I=e?k(h,O):n||p?k(h,0):void 0;O>S;S++)if((d||S in w)&&(b=E(m=w[S],S,x),t))if(e)I[S]=b;else if(b)switch(t){case 3:return!0;case 5:return m;case 6:return S;case 2:u.call(I,m)}else switch(t){case 4:return!1;case 7:u.call(I,m)}return f?-1:c||l?l:I}};t.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterOut:c(7)}},1194:function(t,e,n){var o=n(7293),r=n(5112),i=n(7392),a=r("species");t.exports=function(t){return i>=51||!o((function(){var e=[];return(e.constructor={})[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},9341:function(t,e,n){"use strict";var o=n(7293);t.exports=function(t,e){var n=[][t];return!!n&&o((function(){n.call(null,e||function(){throw 1},1)}))}},3671:function(t,e,n){var o=n(3099),r=n(7908),i=n(8361),a=n(7466),s=function(t){return function(e,n,s,u){o(n);var c=r(e),l=i(c),f=a(c.length),p=t?f-1:0,d=t?-1:1;if(s<2)for(;;){if(p in l){u=l[p],p+=d;break}if(p+=d,t?p<0:f<=p)throw TypeError("Reduce of empty array with no initial value")}for(;t?p>=0:f>p;p+=d)p in l&&(u=n(u,l[p],p,c));return u}};t.exports={left:s(!1),right:s(!0)}},5417:function(t,e,n){var o=n(111),r=n(3157),i=n(5112)("species");t.exports=function(t,e){var n;return r(t)&&("function"!=typeof(n=t.constructor)||n!==Array&&!r(n.prototype)?o(n)&&null===(n=n[i])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===e?0:e)}},3411:function(t,e,n){var o=n(9670),r=n(9212);t.exports=function(t,e,n,i){try{return i?e(o(n)[0],n[1]):e(n)}catch(e){throw r(t),e}}},7072:function(t,e,n){var o=n(5112)("iterator"),r=!1;try{var i=0,a={next:function(){return{done:!!i++}},return:function(){r=!0}};a[o]=function(){return this},Array.from(a,(function(){throw 2}))}catch(t){}t.exports=function(t,e){if(!e&&!r)return!1;var n=!1;try{var i={};i[o]=function(){return{next:function(){return{done:n=!0}}}},t(i)}catch(t){}return n}},4326:function(t){var e={}.toString;t.exports=function(t){return e.call(t).slice(8,-1)}},648:function(t,e,n){var o=n(1694),r=n(4326),i=n(5112)("toStringTag"),a="Arguments"==r(function(){return arguments}());t.exports=o?r:function(t){var e,n,o;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),i))?n:a?r(e):"Object"==(o=r(e))&&"function"==typeof e.callee?"Arguments":o}},9920:function(t,e,n){var o=n(6656),r=n(3887),i=n(1236),a=n(3070);t.exports=function(t,e){for(var n=r(e),s=a.f,u=i.f,c=0;c=74)&&(o=a.match(/Chrome\/(\d+)/))&&(r=o[1]),t.exports=r&&+r},748:function(t){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},2109:function(t,e,n){var o=n(7854),r=n(1236).f,i=n(8880),a=n(1320),s=n(3505),u=n(9920),c=n(4705);t.exports=function(t,e){var n,l,f,p,d,h=t.target,v=t.global,g=t.stat;if(n=v?o:g?o[h]||s(h,{}):(o[h]||{}).prototype)for(l in e){if(p=e[l],f=t.noTargetGet?(d=r(n,l))&&d.value:n[l],!c(v?l:h+(g?".":"#")+l,t.forced)&&void 0!==f){if(typeof p==typeof f)continue;u(p,f)}(t.sham||f&&f.sham)&&i(p,"sham",!0),a(n,l,p,t)}}},7293:function(t){t.exports=function(t){try{return!!t()}catch(t){return!0}}},7007:function(t,e,n){"use strict";n(4916);var o=n(1320),r=n(7293),i=n(5112),a=n(2261),s=n(8880),u=i("species"),c=!r((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")})),l="$0"==="a".replace(/./,"$0"),f=i("replace"),p=!!/./[f]&&""===/./[f]("a","$0"),d=!r((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));t.exports=function(t,e,n,f){var h=i(t),v=!r((function(){var e={};return e[h]=function(){return 7},7!=""[t](e)})),g=v&&!r((function(){var e=!1,n=/a/;return"split"===t&&((n={}).constructor={},n.constructor[u]=function(){return n},n.flags="",n[h]=/./[h]),n.exec=function(){return e=!0,null},n[h](""),!e}));if(!v||!g||"replace"===t&&(!c||!l||p)||"split"===t&&!d){var y=/./[h],m=n(h,""[t],(function(t,e,n,o,r){return e.exec===a?v&&!r?{done:!0,value:y.call(e,n,o)}:{done:!0,value:t.call(n,e,o)}:{done:!1}}),{REPLACE_KEEPS_$0:l,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:p}),b=m[0],x=m[1];o(String.prototype,t,b),o(RegExp.prototype,h,2==e?function(t,e){return x.call(t,this,e)}:function(t){return x.call(t,this)})}f&&s(RegExp.prototype[h],"sham",!0)}},9974:function(t,e,n){var o=n(3099);t.exports=function(t,e,n){if(o(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,o){return t.call(e,n,o)};case 3:return function(n,o,r){return t.call(e,n,o,r)}}return function(){return t.apply(e,arguments)}}},5005:function(t,e,n){var o=n(857),r=n(7854),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(o[t])||i(r[t]):o[t]&&o[t][e]||r[t]&&r[t][e]}},1246:function(t,e,n){var o=n(648),r=n(7497),i=n(5112)("iterator");t.exports=function(t){if(null!=t)return t[i]||t["@@iterator"]||r[o(t)]}},647:function(t,e,n){var o=n(7908),r=Math.floor,i="".replace,a=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,s=/\$([$&'`]|\d{1,2})/g;t.exports=function(t,e,n,u,c,l){var f=n+t.length,p=u.length,d=s;return void 0!==c&&(c=o(c),d=a),i.call(l,d,(function(o,i){var a;switch(i.charAt(0)){case"$":return"$";case"&":return t;case"`":return e.slice(0,n);case"'":return e.slice(f);case"<":a=c[i.slice(1,-1)];break;default:var s=+i;if(0===s)return o;if(s>p){var l=r(s/10);return 0===l?o:l<=p?void 0===u[l-1]?i.charAt(1):u[l-1]+i.charAt(1):o}a=u[s-1]}return void 0===a?"":a}))}},7854:function(t,e,n){var o=function(t){return t&&t.Math==Math&&t};t.exports=o("object"==typeof globalThis&&globalThis)||o("object"==typeof window&&window)||o("object"==typeof self&&self)||o("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},6656:function(t){var e={}.hasOwnProperty;t.exports=function(t,n){return e.call(t,n)}},3501:function(t){t.exports={}},490:function(t,e,n){var o=n(5005);t.exports=o("document","documentElement")},4664:function(t,e,n){var o=n(9781),r=n(7293),i=n(317);t.exports=!o&&!r((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},8361:function(t,e,n){var o=n(7293),r=n(4326),i="".split;t.exports=o((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==r(t)?i.call(t,""):Object(t)}:Object},9587:function(t,e,n){var o=n(111),r=n(7674);t.exports=function(t,e,n){var i,a;return r&&"function"==typeof(i=e.constructor)&&i!==n&&o(a=i.prototype)&&a!==n.prototype&&r(t,a),t}},2788:function(t,e,n){var o=n(5465),r=Function.toString;"function"!=typeof o.inspectSource&&(o.inspectSource=function(t){return r.call(t)}),t.exports=o.inspectSource},9909:function(t,e,n){var o,r,i,a=n(8536),s=n(7854),u=n(111),c=n(8880),l=n(6656),f=n(5465),p=n(6200),d=n(3501),h=s.WeakMap;if(a){var v=f.state||(f.state=new h),g=v.get,y=v.has,m=v.set;o=function(t,e){return e.facade=t,m.call(v,t,e),e},r=function(t){return g.call(v,t)||{}},i=function(t){return y.call(v,t)}}else{var b=p("state");d[b]=!0,o=function(t,e){return e.facade=t,c(t,b,e),e},r=function(t){return l(t,b)?t[b]:{}},i=function(t){return l(t,b)}}t.exports={set:o,get:r,has:i,enforce:function(t){return i(t)?r(t):o(t,{})},getterFor:function(t){return function(e){var n;if(!u(e)||(n=r(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},7659:function(t,e,n){var o=n(5112),r=n(7497),i=o("iterator"),a=Array.prototype;t.exports=function(t){return void 0!==t&&(r.Array===t||a[i]===t)}},3157:function(t,e,n){var o=n(4326);t.exports=Array.isArray||function(t){return"Array"==o(t)}},4705:function(t,e,n){var o=n(7293),r=/#|\.prototype\./,i=function(t,e){var n=s[a(t)];return n==c||n!=u&&("function"==typeof e?o(e):!!e)},a=i.normalize=function(t){return String(t).replace(r,".").toLowerCase()},s=i.data={},u=i.NATIVE="N",c=i.POLYFILL="P";t.exports=i},8730:function(t,e,n){var o=n(111),r=Math.floor;t.exports=function(t){return!o(t)&&isFinite(t)&&r(t)===t}},111:function(t){t.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},1913:function(t){t.exports=!1},7850:function(t,e,n){var o=n(111),r=n(4326),i=n(5112)("match");t.exports=function(t){var e;return o(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==r(t))}},9212:function(t,e,n){var o=n(9670);t.exports=function(t){var e=t.return;if(void 0!==e)return o(e.call(t)).value}},3383:function(t,e,n){"use strict";var o,r,i,a=n(7293),s=n(9518),u=n(8880),c=n(6656),l=n(5112),f=n(1913),p=l("iterator"),d=!1;[].keys&&("next"in(i=[].keys())?(r=s(s(i)))!==Object.prototype&&(o=r):d=!0);var h=null==o||a((function(){var t={};return o[p].call(t)!==t}));h&&(o={}),f&&!h||c(o,p)||u(o,p,(function(){return this})),t.exports={IteratorPrototype:o,BUGGY_SAFARI_ITERATORS:d}},7497:function(t){t.exports={}},133:function(t,e,n){var o=n(5268),r=n(7392),i=n(7293);t.exports=!!Object.getOwnPropertySymbols&&!i((function(){return!Symbol.sham&&(o?38===r:r>37&&r<41)}))},8536:function(t,e,n){var o=n(7854),r=n(2788),i=o.WeakMap;t.exports="function"==typeof i&&/native code/.test(r(i))},3929:function(t,e,n){var o=n(7850);t.exports=function(t){if(o(t))throw TypeError("The method doesn't accept regular expressions");return t}},1574:function(t,e,n){"use strict";var o=n(9781),r=n(7293),i=n(1956),a=n(5181),s=n(5296),u=n(7908),c=n(8361),l=Object.assign,f=Object.defineProperty;t.exports=!l||r((function(){if(o&&1!==l({b:1},l(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},n=Symbol(),r="abcdefghijklmnopqrst";return t[n]=7,r.split("").forEach((function(t){e[t]=t})),7!=l({},t)[n]||i(l({},e)).join("")!=r}))?function(t,e){for(var n=u(t),r=arguments.length,l=1,f=a.f,p=s.f;r>l;)for(var d,h=c(arguments[l++]),v=f?i(h).concat(f(h)):i(h),g=v.length,y=0;g>y;)d=v[y++],o&&!p.call(h,d)||(n[d]=h[d]);return n}:l},30:function(t,e,n){var o,r=n(9670),i=n(6048),a=n(748),s=n(3501),u=n(490),c=n(317),l=n(6200),f=l("IE_PROTO"),p=function(){},d=function(t){return" - - - \ No newline at end of file diff --git a/demo/main.css b/demo/main.css deleted file mode 100644 index 575ed60e..00000000 --- a/demo/main.css +++ /dev/null @@ -1,12 +0,0 @@ -input { - width: 100%; - height: 100px; - padding: 20px; - font-size: 20px; - border: none; - box-sizing: border-box; -} - -.simple-keyboard { - max-width: 850px; -} diff --git a/demo/main.js b/demo/main.js deleted file mode 100644 index 764546fe..00000000 --- a/demo/main.js +++ /dev/null @@ -1,38 +0,0 @@ -const Keyboard = window.SimpleKeyboard.default; - -const keyboard = new Keyboard({ - onChange: input => onChange(input), - onKeyPress: button => onKeyPress(button) -}); - -/** - * Update simple-keyboard when input is changed directly - */ -document.querySelector(".input").addEventListener("input", event => { - keyboard.setInput(event.target.value); -}); - -console.log(keyboard); - -function onChange(input) { - document.querySelector(".input").value = input; - console.log("Input changed", input); -} - -function onKeyPress(button) { - console.log("Button pressed", button); - - /** - * If you want to handle the shift and caps lock buttons - */ - if (button === "{shift}" || button === "{lock}") handleShift(); -} - -function handleShift() { - const currentLayout = keyboard.options.layoutName; - const shiftToggle = currentLayout === "default" ? "shift" : "default"; - - keyboard.setOptions({ - layoutName: shiftToggle - }); -} diff --git a/package-lock.json b/package-lock.json index 083c6e45..1cc509cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -988,6 +988,14 @@ "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + } } }, "@babel/preset-env": { @@ -1967,6 +1975,12 @@ "@types/node": "*" } }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, "@types/http-proxy": { "version": "1.17.5", "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz", @@ -2000,6 +2014,16 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "26.0.20", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", + "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", + "dev": true, + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -2018,6 +2042,12 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "@types/prettier": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.2.tgz", @@ -2645,6 +2675,20 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "autoprefixer": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.2.5.tgz", + "integrity": "sha512-7H4AJZXvSsn62SqZyJCP+1AWwOuoYpUfK6ot9vm0e87XD6mT8lDywc9D9OTJPMULyGcvmIxzTAMeG2Cc+YX+fA==", + "dev": true, + "requires": { + "browserslist": "^4.16.3", + "caniuse-lite": "^1.0.30001196", + "colorette": "^1.2.2", + "fraction.js": "^4.0.13", + "normalize-range": "^0.1.2", + "postcss-value-parser": "^4.1.0" + } + }, "available-typed-arrays": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", @@ -3408,6 +3452,24 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", @@ -3602,6 +3664,23 @@ } } }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -3810,9 +3889,9 @@ "dev": true }, "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.1.tgz", + "integrity": "sha512-gSjRvzkxQc1zjM/5paAmL4idJBFzuJoo+jDjF1tStYFMV2ERfD02HhahhCGXUyHxQRG4yFKVSdO6g62eoRMcDg==", "dev": true }, "core-js-compat": { @@ -4533,6 +4612,15 @@ "esutils": "^2.0.2" } }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, "dom-serializer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", @@ -4574,6 +4662,15 @@ } } }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, "domutils": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", @@ -4584,6 +4681,24 @@ "domelementtype": "1" } }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -5668,6 +5783,12 @@ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", "dev": true }, + "fraction.js": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.13.tgz", + "integrity": "sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA==", + "dev": true + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -5944,6 +6065,12 @@ } } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", @@ -6007,6 +6134,94 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + } + } + }, + "html-webpack-plugin": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.3.0.tgz", + "integrity": "sha512-BjtSQCy5J0e9EDV+NZ4i+w36N9avXfQDF4QoAV9YAECG50x6/2tfJkFb0ws9eTcszLdyg4vs6FI6hMgVzVoQqw==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "html-minifier-terser": "^5.0.1", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^2.0.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -8297,6 +8512,12 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "dev": true + }, "last-call-webpack-plugin": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", @@ -8414,6 +8635,23 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", "dev": true }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8702,9 +8940,9 @@ "dev": true }, "nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz", + "integrity": "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==", "dev": true }, "nanomatch": { @@ -8750,6 +8988,24 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "node-forge": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", @@ -8819,6 +9075,12 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", @@ -9130,6 +9392,24 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9163,6 +9443,24 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -9283,9 +9581,9 @@ "dev": true }, "postcss": { - "version": "8.2.7", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.7.tgz", - "integrity": "sha512-DsVLH3xJzut+VT+rYr0mtvOtpTjSyqDwPf5EZWXcb0uAKfitGpTY9Ec+afi2+TgdN8rWS9Cs88UDYehKo/RvOw==", + "version": "8.2.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.8.tgz", + "integrity": "sha512-1F0Xb2T21xET7oQV9eKuctbM9S7BC0fetoHCc4H13z0PT6haiRLP4T0ZY4XWh7iLP0usgqykT6p9B2RtOf4FPw==", "dev": true, "requires": { "colorette": "^1.2.2", @@ -9579,6 +9877,41 @@ } } }, + "postcss-loader": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-5.2.0.tgz", + "integrity": "sha512-uSuCkENFeUaOYsKrXm0eNNgVIxc71z8RcckLMbVw473rGojFnrUeqEz6zBgXsH2q1EIzXnO/4pEz9RhALjlITA==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.4", + "semver": "^7.3.4" + }, + "dependencies": { + "cosmiconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", + "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "postcss-merge-longhand": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", @@ -10559,6 +10892,16 @@ "integrity": "sha512-icoIPxDpOo/q7SUCHSW152dCr83z7QS/6s2V3phweKu1bfJcXSObVAq/Z8OeSX7ykuXrcV2UpZbfljRI2rIOMg==", "dev": true }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", @@ -10882,12 +11225,48 @@ } } }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, + "renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", + "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "dev": true, + "requires": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", @@ -12582,6 +12961,12 @@ "object.getownpropertydescriptors": "^2.1.0" } }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -13117,6 +13502,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, "yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", diff --git a/package.json b/package.json index 35860ee2..4ac29ee2 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "3.0.0", "description": "On-screen Javascript Virtual Keyboard", "main": "build/index.js", - "types": "build/index.d.ts", + "types": "build/types/index.d.ts", "scripts": { - "start": "webpack serve", + "start": "webpack serve --config webpack.config.demo.js", "build": "webpack && tsc", "test": "jest --silent", "coverage": "npm run test -- --coverage", @@ -45,17 +45,23 @@ "@babel/plugin-transform-typescript": "^7.13.0", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.13.9", + "@types/jest": "^26.0.20", "@typescript-eslint/eslint-plugin": "^4.16.1", "@typescript-eslint/parser": "^4.16.1", + "autoprefixer": "^10.2.5", "babel-eslint": "^10.1.0", "babel-loader": "^8.2.2", "babel-preset-minify": "^0.5.0", + "core-js": "^3.9.1", "css-loader": "^5.1.1", "eslint": "^7.21.0", "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.3.0", "jest": "^26.6.3", "mini-css-extract-plugin": "^1.3.9", "optimize-css-assets-webpack-plugin": "^5.0.4", + "postcss": "^8.2.8", + "postcss-loader": "^5.2.0", "prettier": "^2.2.1", "prettier-webpack-plugin": "^1.2.0", "style-loader": "^2.0.0", @@ -74,6 +80,7 @@ "src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts", "!src/lib/index.js", + "!src/lib/polyfills.js", "!src/demo/index.js", "!src/utils/**", "!src/**/*.d.ts", diff --git a/src/demo/BasicDemo.js b/src/demo/BasicDemo.js index 5acee933..ced4c18d 100644 --- a/src/demo/BasicDemo.js +++ b/src/demo/BasicDemo.js @@ -2,7 +2,7 @@ import Keyboard from "../lib"; import "./css/BasicDemo.css"; const setDOM = () => { - document.querySelector("#root").innerHTML = ` + document.querySelector("body").innerHTML = `
`; diff --git a/src/demo/ButtonThemeDemo.js b/src/demo/ButtonThemeDemo.js index 2ca3d738..7c68ce87 100644 --- a/src/demo/ButtonThemeDemo.js +++ b/src/demo/ButtonThemeDemo.js @@ -2,7 +2,7 @@ import Keyboard from "../lib"; import "./css/ButtonThemeDemo.css"; const setDOM = () => { - document.querySelector("#root").innerHTML = ` + document.querySelector("body").innerHTML = `
`; diff --git a/src/demo/DOMElementDemo.js b/src/demo/DOMElementDemo.js index e8a10804..637e6c54 100644 --- a/src/demo/DOMElementDemo.js +++ b/src/demo/DOMElementDemo.js @@ -4,7 +4,7 @@ import "./css/DOMElementDemo.css"; class Demo { constructor() { const rootDOM = - document.querySelector("#root") || document.createElement("div"); + document.querySelector("body") || document.createElement("div"); const keyboard1DOM = document.createElement("div"); keyboard1DOM.className = "my-keyboard"; diff --git a/src/demo/FullKeyboardDemo.js b/src/demo/FullKeyboardDemo.js index 2fd05f3c..1ee501d6 100644 --- a/src/demo/FullKeyboardDemo.js +++ b/src/demo/FullKeyboardDemo.js @@ -2,7 +2,7 @@ import Keyboard from "../lib"; import "./css/FullKeyboardDemo.css"; const setDOM = () => { - document.querySelector("#root").innerHTML = ` + document.querySelector("body").innerHTML = `
diff --git a/src/demo/MultipleKeyboardsDestroyDemo.js b/src/demo/MultipleKeyboardsDestroyDemo.js index 49058b18..648ae22c 100644 --- a/src/demo/MultipleKeyboardsDestroyDemo.js +++ b/src/demo/MultipleKeyboardsDestroyDemo.js @@ -2,7 +2,7 @@ import Keyboard from "../lib"; import "./css/MultipleKeyboardsDestroyDemo.css"; const setDOM = () => { - document.querySelector("#root").innerHTML = ` + document.querySelector("body").innerHTML = `
diff --git a/src/demo/RTLDemo.js b/src/demo/RTLDemo.js index 0c89dc4d..89c87a97 100644 --- a/src/demo/RTLDemo.js +++ b/src/demo/RTLDemo.js @@ -2,7 +2,7 @@ import Keyboard from "../lib"; import "./css/RTLDemo.css"; const setDOM = () => { - document.querySelector("#root").innerHTML = ` + document.querySelector("body").innerHTML = `
`; diff --git a/src/lib/components/Keyboard.css b/src/lib/components/css/Keyboard.css similarity index 93% rename from src/lib/components/Keyboard.css rename to src/lib/components/css/Keyboard.css index 72dbbca7..c9deb475 100644 --- a/src/lib/components/Keyboard.css +++ b/src/lib/components/css/Keyboard.css @@ -8,6 +8,11 @@ box-sizing: border-box; overflow: hidden; touch-action: manipulation; + font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", + Helvetica, Arial, "Lucida Grande", sans-serif; + background-color: #ececec; + padding: 5px; + border-radius: 5px; } .hg-theme-default .hg-button span { @@ -21,14 +26,6 @@ font-size: inherit; } -.hg-theme-default { - font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", - Helvetica, Arial, "Lucida Grande", sans-serif; - background-color: #ececec; - padding: 5px; - border-radius: 5px; -} - .hg-theme-default .hg-button { display: inline-block; flex-grow: 1; @@ -74,7 +71,14 @@ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } -.hg-theme-default .hg-button.hg-activeButton { +.hg-theme-default .hg-button.hg-standardBtn { + width: 20px; +} + +.hg-theme-default + .hg-button.hg-functionBtn + .hg-theme-default + .hg-button.hg-activeButton { background: #efefef; } diff --git a/src/lib/components/tests/Keyboard.test.js b/src/lib/components/tests/Keyboard.test.js index 71b0b647..43e223fd 100644 --- a/src/lib/components/tests/Keyboard.test.js +++ b/src/lib/components/tests/Keyboard.test.js @@ -1,7 +1,17 @@ import Keyboard from '../Keyboard'; -import { setDOM, clearDOM, testLayoutStdButtons, iterateButtons, triggerDocumentPointerUp, triggerDocumentPointerDown } from '../../../utils/TestUtility'; +import { setDOM, clearDOM, testLayoutStdButtons, triggerDocumentPointerUp } from '../../../utils/TestUtility'; + +beforeEach(() => { + setDOM(); +}); + +afterEach(() => { + clearDOM(); +}); it('Keyboard will not render without target element', () => { + clearDOM(); + try { new Keyboard(); expect(true).toBe(false); @@ -10,18 +20,29 @@ it('Keyboard will not render without target element', () => { } }); -it('Keyboard will run without options', () => { - // Prepare target DOM element - setDOM(); +describe('When window is undefined', () => { + const { window } = global; + beforeAll(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + delete global.window; + }); + afterAll(() => { + global.window = window; + }); + + it('Keyboard will return early if window is undefined', () => { + const keyboard = new Keyboard(); + expect(keyboard.initialized).toBeUndefined(); + }); +}); +it('Keyboard will run without options', () => { // No options new Keyboard(); }); it('Keyboard will run with empty options', () => { - // Prepare target DOM element - setDOM(); - // No options new Keyboard({}); }); @@ -101,9 +122,7 @@ it('Keyboard setOptions will work without a param', () => { }); it('Keyboard empty buttons wont do anything as expected', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ layout: { default: [ "{//} {button} d", @@ -116,9 +135,7 @@ it('Keyboard empty buttons wont do anything as expected', () => { }); it('Keyboard onKeyPress will work', () => { - setDOM(); - - let pressed = false; + let pressed = false; const keyboard = new Keyboard({ onKeyPress: () => { @@ -133,13 +150,11 @@ it('Keyboard onKeyPress will work', () => { }); it('Keyboard standard function buttons will not change input', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ useButtonTag: true }); - iterateButtons((button) => { + keyboard.recurseButtons((button) => { if(button.getAttribute("data-skbtn") === "{shift}"){ button.onclick(); } @@ -189,9 +204,7 @@ it('Keyboard syncInstanceInputs will work', () => { }); it('Keyboard onChange will work', () => { - setDOM(); - - let output = false; + let output = false; const keyboard = new Keyboard({ onChange: (input) => { @@ -206,9 +219,7 @@ it('Keyboard onChange will work', () => { }); it('Keyboard onChangeAll will work', () => { - setDOM(); - - let output; + let output; const keyboard = new Keyboard({ onChangeAll: (input) => { @@ -223,9 +234,7 @@ it('Keyboard onChangeAll will work', () => { }); it('Keyboard clearInput will work', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); /** * Avoid setInput for this test @@ -267,9 +276,7 @@ it('Keyboard clearInput will work with syncInstanceInputs', () => { }); it('Keyboard setInput will work', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.setInput("hello"); @@ -297,9 +304,7 @@ it('Keyboard setInput will work with syncInstanceInputs', () => { }); it('Keyboard dispatch will work', () => { - setDOM(); - - document.body.innerHTML = ` + document.body.innerHTML = `
`; @@ -322,9 +327,7 @@ it('Keyboard dispatch will work', () => { }); it('Keyboard dispatch will not work without SimpleKeyboardInstances', () => { - setDOM(); - - document.body.innerHTML = ` + document.body.innerHTML = `
`; @@ -353,27 +356,21 @@ it('Keyboard dispatch will not work without SimpleKeyboardInstances', () => { }); it('Keyboard addButtonTheme will work', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.addButtonTheme("q", "test"); expect(keyboard.options.buttonTheme[0].class).toBe("test"); }); it('Keyboard addButtonTheme will not work without params', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); const returnVal = keyboard.addButtonTheme(); expect(returnVal).toBeFalsy(); }); it('Keyboard addButtonTheme will amend a buttonTheme', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -388,9 +385,7 @@ it('Keyboard addButtonTheme will amend a buttonTheme', () => { }); it('Keyboard addButtonTheme will create a buttonTheme', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "blurb", @@ -405,9 +400,7 @@ it('Keyboard addButtonTheme will create a buttonTheme', () => { }); it('Keyboard addButtonTheme will ignore a repeated buttonTheme', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -422,9 +415,7 @@ it('Keyboard addButtonTheme will ignore a repeated buttonTheme', () => { }); it('Keyboard addButtonTheme will amend a buttonTheme', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -440,9 +431,7 @@ it('Keyboard addButtonTheme will amend a buttonTheme', () => { it('Keyboard removeButtonTheme without params will remove all button themes', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -458,9 +447,7 @@ it('Keyboard removeButtonTheme without params will remove all button themes', () it('Keyboard removeButtonTheme will work', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -475,9 +462,7 @@ it('Keyboard removeButtonTheme will work', () => { }); it('Keyboard removeButtonTheme will work wihtout a class', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -492,9 +477,7 @@ it('Keyboard removeButtonTheme will work wihtout a class', () => { }); it('Keyboard removeButtonTheme will do nothing without a button param', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -509,9 +492,7 @@ it('Keyboard removeButtonTheme will do nothing without a button param', () => { }); it('Keyboard removeButtonTheme does nothing if req button doesnt have a buttonTheme', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -526,9 +507,7 @@ it('Keyboard removeButtonTheme does nothing if req button doesnt have a buttonTh }); it('Keyboard removeButtonTheme does nothing if buttonTheme class does not exist', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "testy", @@ -543,9 +522,7 @@ it('Keyboard removeButtonTheme does nothing if buttonTheme class does not exist' }); it('Keyboard removeButtonTheme does nothing if buttonTheme doesnt have the requested buttons', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ buttonTheme: [ { class: "test", @@ -560,9 +537,7 @@ it('Keyboard removeButtonTheme does nothing if buttonTheme doesnt have the reque }); it('Keyboard getButtonElement will not return anything if empty match', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ layout: { default: [ "{//} {button} d", @@ -575,17 +550,13 @@ it('Keyboard getButtonElement will not return anything if empty match', () => { }); it('Keyboard getButtonElement will return multiple matched buttons', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); expect(keyboard.getButtonElement("{shift}").length).toBe(2); }); it('Keyboard will receive physical keyboard events', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ debug: true, physicalKeyboardHighlight: true }); @@ -602,9 +573,7 @@ it('Keyboard will receive physical keyboard events', () => { }); it('Keyboard caretEventHandler will detect input, textarea focus', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); const myInput = document.createElement('input'); keyboard.caretEventHandler({ @@ -619,9 +588,7 @@ it('Keyboard caretEventHandler will detect input, textarea focus', () => { }); it('Keyboard caretEventHandler will not set caretPosition on disableCaretPositioning', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); const myInput = document.createElement('input'); keyboard.caretEventHandler({ @@ -650,9 +617,7 @@ it('Keyboard caretEventHandler will not set caretPosition on disableCaretPositio }); it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.isMouseHold = true; @@ -668,9 +633,7 @@ it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', ( }); it('Keyboard caretEventHandler will work with debug', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ debug: true }); @@ -693,9 +656,7 @@ it('Keyboard caretEventHandler will work with debug', () => { }); it('Keyboard onInit will work', () => { - setDOM(); - - let passed = false; + let passed = false; new Keyboard({ onInit: () => { @@ -707,9 +668,7 @@ it('Keyboard onInit will work', () => { }); it('Keyboard onRender will work', () => { - setDOM(); - - let passed = false; + let passed = false; new Keyboard({ onRender: () => { @@ -721,9 +680,7 @@ it('Keyboard onRender will work', () => { }); it('Keyboard buttonTheme that is invalid will be ignored and not throw', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonTheme: [ { class: null, @@ -734,9 +691,7 @@ it('Keyboard buttonTheme that is invalid will be ignored and not throw', () => { }); it('Keyboard buttonTheme buttons that are invalid will be ignored and not throw', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonTheme: [ { class: null, @@ -747,9 +702,7 @@ it('Keyboard buttonTheme buttons that are invalid will be ignored and not throw' }); it('Keyboard buttonTheme will be ignored if buttons param not a string', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonTheme: [ { class: "test", @@ -762,9 +715,7 @@ it('Keyboard buttonTheme will be ignored if buttons param not a string', () => { }); it('Keyboard buttonTheme will be ignored if already added', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonTheme: [ { class: "test", @@ -791,9 +742,7 @@ it('Keyboard buttonTheme will be ignored if already added', () => { }); it('Keyboard can set a module', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.registerModule( "test", @@ -806,9 +755,7 @@ it('Keyboard can set a module', () => { }); it('Keyboard registerModule will return current module tree', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.modules.test = { testy: "test" @@ -826,9 +773,7 @@ it('Keyboard registerModule will return current module tree', () => { }); it('Keyboard can set a module by amending the modules tree', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.modules = { testman: { @@ -847,17 +792,13 @@ it('Keyboard can set a module by amending the modules tree', () => { }); it('Keyboard will not retrieve an option for an inexistent module', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); expect(keyboard.getModuleProp("test", "foo")).toBeFalsy(); }); it('Keyboard will get a list of modules', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.registerModule( "test", @@ -870,9 +811,7 @@ it('Keyboard will get a list of modules', () => { }); it('Keyboard loadModules will load a simple module', () => { - setDOM(); - - class myClass { + class myClass { init = (module) => { module.foo = "bar"; }; @@ -886,9 +825,7 @@ it('Keyboard loadModules will load a simple module', () => { }); it('Keyboard handleButtonMouseUp will set isMouseHold to false', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.isMouseHold = true; @@ -900,9 +837,7 @@ it('Keyboard handleButtonMouseUp will set isMouseHold to false', () => { }); it('Keyboard handleButtonMouseUp clear holdInteractionTimeout', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.isMouseHold = true; keyboard.holdInteractionTimeout = setTimeout(() => {}, 10000); @@ -913,9 +848,7 @@ it('Keyboard handleButtonMouseUp clear holdInteractionTimeout', () => { }); it('Keyboard handleButtonMouseDown will work', () => { - setDOM(); - - const keyboard = new Keyboard({ useMouseEvents: true }); + const keyboard = new Keyboard({ useMouseEvents: true }); console.log(keyboard.getButtonElement("q")) keyboard.getButtonElement("q").onclick(); @@ -927,9 +860,7 @@ it('Keyboard handleButtonMouseDown will work', () => { }); it('Keyboard handleButtonMouseDown will work with preventMouseDownDefault', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ preventMouseDownDefault: true, stopMouseDownPropagation: true }); @@ -958,9 +889,7 @@ it('Keyboard handleButtonMouseDown will work with preventMouseDownDefault', () = }); it('Keyboard handleButtonMouseUp will work with preventMouseUpDefault and stopMouseUpPropagation', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ preventMouseUpDefault: true, stopMouseUpPropagation: true }); @@ -987,9 +916,7 @@ it('Keyboard handleButtonMouseUp will work with preventMouseUpDefault and stopMo }); it('Keyboard onModulesLoaded will work', () => { - setDOM(); - - class myClass { + class myClass { init = (module) => { module.foo = "bar"; }; @@ -1010,9 +937,7 @@ it('Keyboard onModulesLoaded will work', () => { }); it('Keyboard inputPattern will work globally', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ inputPattern: /^\d+$/, useMouseEvents: true }); @@ -1027,9 +952,7 @@ it('Keyboard inputPattern will work globally', () => { }); it('Keyboard inputPattern will work by input name', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ debug: true, inputName: "test1", inputPattern: { @@ -1054,9 +977,7 @@ it('Keyboard inputPattern will work by input name', () => { }); it('Keyboard processAutoTouchEvents will work', () => { - setDOM(); - - navigator.maxTouchPoints = true; + navigator.maxTouchPoints = true; const keyboard = new Keyboard({ autoUseTouchEvents: true @@ -1066,9 +987,7 @@ it('Keyboard processAutoTouchEvents will work', () => { }); it('Keyboard processAutoTouchEvents will work with debugging enabled', () => { - setDOM(); - - navigator.maxTouchPoints = true; + navigator.maxTouchPoints = true; const keyboard = new Keyboard({ autoUseTouchEvents: true, @@ -1079,9 +998,7 @@ it('Keyboard processAutoTouchEvents will work with debugging enabled', () => { }); it('Keyboard beforeFirstRender method will work', () => { - setDOM(); - - let timesCalled = 0; + let timesCalled = 0; const keyboard = new Keyboard({ beforeFirstRender: () => { @@ -1100,9 +1017,7 @@ it('Keyboard beforeFirstRender method will work', () => { }); it('Keyboard beforeFirstRender will show PointerEvents warning', () => { - setDOM(); - - let timesCalled = 0; + let timesCalled = 0; window.PointerEvent = window.PointerEvent ? window.PointerEvent : () => {}; @@ -1117,9 +1032,7 @@ it('Keyboard beforeFirstRender will show PointerEvents warning', () => { }); it('Keyboard beforeRender method will work', () => { - setDOM(); - - let timesCalled = 0; + let timesCalled = 0; const keyboard = new Keyboard({ beforeRender: () => { @@ -1138,9 +1051,7 @@ it('Keyboard beforeRender method will work', () => { }); it('Keyboard parseRowDOMContainers will work', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ layout: { 'default': [ '` [1 2 3 4 5 6 7 8 9] 0 - = {bksp}', @@ -1171,9 +1082,7 @@ it('Keyboard parseRowDOMContainers will work', () => { }); it('Keyboard parseRowDOMContainers will ignore empty rows', () => { - setDOM(); - - let failed = false; + let failed = false; try { const keyboard = new Keyboard(); @@ -1189,9 +1098,7 @@ it('Keyboard parseRowDOMContainers will ignore empty rows', () => { it('Keyboard parseRowDOMContainers will ignore missing endIndex or endIndex before startIndex', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ layout: { 'default': [ '` [1 2 3 4 5 6 7 8 9 0 - = {bksp}', @@ -1206,9 +1113,7 @@ it('Keyboard parseRowDOMContainers will ignore missing endIndex or endIndex befo }); it('Keyboard disableRowButtonContainers will bypass parseRowDOMContainers', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ disableRowButtonContainers: true, layout: { 'default': [ @@ -1234,9 +1139,7 @@ it('Keyboard disableRowButtonContainers will bypass parseRowDOMContainers', () = }); it('Keyboard inputName change will trigget caretPosition reset', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.setCaretPosition(0); @@ -1257,9 +1160,7 @@ it('Keyboard inputName change will trigget caretPosition reset', () => { }); it('Keyboard destroy will work', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.destroy(); expect(keyboard.keyboardDOM.innerHTML).toBe(""); @@ -1280,17 +1181,13 @@ it('Keyboard destroy will work', () => { }); it('Keyboard destroy will work with debug option', () => { - setDOM(); - - const keyboard = new Keyboard({ debug: true }); + const keyboard = new Keyboard({ debug: true }); keyboard.destroy(); expect(keyboard.keyboardDOM.innerHTML).toBe(""); }); it('Keyboard disableButtonHold will work', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ disableButtonHold: true }); @@ -1298,9 +1195,7 @@ it('Keyboard disableButtonHold will work', () => { }); it('Keyboard caretEventHandler will be triggered on mouseup and ontouchend', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ disableCaretPositioning: true }); @@ -1323,9 +1218,7 @@ it('Keyboard caretEventHandler will be triggered on mouseup and ontouchend', () }); it('Keyboard onKeyReleased will work', () => { - setDOM(); - - let pressed = false; + let pressed = false; let firedTimes = 0; let buttonPressed; @@ -1347,9 +1240,7 @@ it('Keyboard onKeyReleased will work', () => { }); it('Keyboard buttonAttribute will work', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonAttributes: [ { attribute: "aria-label", @@ -1361,9 +1252,7 @@ it('Keyboard buttonAttribute will work', () => { }); it('Keyboard buttonAttribute will warn about invalid entries', () => { - setDOM(); - - new Keyboard({ + new Keyboard({ buttonAttributes: [ { attribute: false, @@ -1403,16 +1292,12 @@ it('Keyboard will work with a DOM element param with class', () => { }); it('Keyboard handleKeyboardContainerMouseDown will work', () => { - setDOM(); - - const keyboard = new Keyboard(); + const keyboard = new Keyboard(); keyboard.keyboardDOM.onpointerdown(); }); it('Keyboard handleKeyboardContainerMouseDown will respect preventMouseDownDefault', () => { - setDOM(); - - let works = false; + let works = false; const keyboard = new Keyboard({ preventMouseDownDefault: true }); keyboard.keyboardDOM.onpointerdown({ preventDefault: () => { works = true @@ -1422,9 +1307,7 @@ it('Keyboard handleKeyboardContainerMouseDown will respect preventMouseDownDefau }); it('Keyboard caret positioning will work', () => { - setDOM(); - - const keyboard = new Keyboard({ + const keyboard = new Keyboard({ onKeyPress: (button) => { if (button === "{shift}" || button === "{lock}") handleShift(); else if (keyboard.options.layoutName === "shift") handleShift(); @@ -1449,4 +1332,23 @@ it('Keyboard caret positioning will work', () => { keyboard.getButtonElement("l").onpointerdown(); expect(keyboard.getInput()).toBe("hEllo"); +}); + +it('Keyboard excludeFromLayout will work', () => { + const keyboard = new Keyboard(); + + expect(keyboard.getButtonElement("a")).toBeDefined(); + + keyboard.setOptions({ + excludeFromLayout: { + default: ["a"] + } + }); + + expect(keyboard.getButtonElement("a")).toBeUndefined(); +}); + +it('Keyboard onSetOptions can be called without changedOptions param', () => { + const keyboard = new Keyboard(); + expect(keyboard.onSetOptions()).toBeUndefined(); }); \ No newline at end of file diff --git a/src/lib/interfaces.ts b/src/lib/interfaces.ts index 4d0338fa..0f35b602 100644 --- a/src/lib/interfaces.ts +++ b/src/lib/interfaces.ts @@ -1,3 +1,7 @@ +/* eslint-disable no-unused-vars */ +import SimpleKeyboard from "./components/Keyboard"; +import Utilities from "./services/Utilities"; + export interface KeyboardLayoutObject { [key: string]: string[]; } @@ -17,11 +21,33 @@ export interface KeyboardInput { [key: string]: string } -export type KeyboardButton = HTMLDivElement | HTMLButtonElement; +export type KeyboardParams = [KeyboardOptions] | [string | HTMLDivElement, KeyboardOptions]; + +export type CandidateBoxParams = { + utilities: Utilities +} + +export type CandidateBoxShowParams = { + candidateValue: string, + targetElement: KeyboardElement, + // eslint-disable-next-line no-unused-vars + onSelect: (selectedCandidate: string) => void +} + +export type CandidateBoxRenderParams = { + candidateListPages: string[][], + targetElement: KeyboardElement, + pageIndex: number; + nbPages: number; + // eslint-disable-next-line no-unused-vars + onItemSelected: (selectedCandidate: string) => void +} + +export type KeyboardElement = HTMLDivElement | HTMLButtonElement; export type KeyboardHandlerEvent = PointerEvent & TouchEvent & KeyboardEvent & { target: HTMLDivElement | HTMLInputElement }; export interface KeyboardButtonElements { - [key: string]: KeyboardButton[] + [key: string]: KeyboardElement[] } export interface UtilitiesParams { @@ -179,6 +205,36 @@ export interface KeyboardOptions { */ rtl?: boolean; + /** + * Enable input method editor candidate list support. + */ + enableLayoutCandidates?: boolean; + + /** + * Character suggestions to be shown on certain key presses + */ + layoutCandidates?: { [key: string]: string }; + + /** + * Exclude buttons from layout + */ + excludeFromLayout?: { [key: string]: string[] }; + + /** + * Determine size of layout candidate list + */ + layoutCandidatesPageSize?: number; + + /** + * Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts). + */ + onRender?: (instance?: SimpleKeyboard) => void; + + /** + * Executes the callback function once simple-keyboard is rendered for the first time (on initialization). + */ + onInit?: (instance?: SimpleKeyboard) => void; + /** * Module options can have any format */ diff --git a/src/lib/services/Utilities.ts b/src/lib/services/Utilities.ts index f732b477..bb8cf810 100644 --- a/src/lib/services/Utilities.ts +++ b/src/lib/services/Utilities.ts @@ -31,17 +31,26 @@ class Utilities { Utilities.bindMethods(Utilities, this); } + /** + * Retrieve button type + * + * @param {string} button The button's layout name + * @return {string} The button type + */ + getButtonType(button: string): string { + return button.includes("{") && button.includes("}") && button !== "{//}" + ? "functionBtn" + : "standardBtn"; + } + /** * 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 */ - getButtonClass(button: string) { - const buttonTypeClass = - button.includes("{") && button.includes("}") && button !== "{//}" - ? "functionBtn" - : "standardBtn"; + getButtonClass(button: string): string { + const buttonTypeClass = this.getButtonType(button); const buttonWithoutBraces = button.replace("{", "").replace("}", ""); let buttonNormalized = ""; @@ -418,7 +427,7 @@ class Utilities { * Determines whether pointer events are supported */ pointerEventsSupported() { - return window.PointerEvent; + return !!window.PointerEvent; } /** @@ -453,6 +462,18 @@ class Utilities { ); } + /** + * Split array into chunks + */ + chunkArray(arr: T[], size: number): T[][] { + return [...Array(Math.ceil(arr.length / size))].map((_, i) => + arr.slice(size * i, size + size * i) + ); + } + + /** + * Reusable empty function + */ static noop = () => {}; } diff --git a/src/lib/services/tests/Utilities.test.js b/src/lib/services/tests/Utilities.test.js index d7ecff5c..d2b9f622 100644 --- a/src/lib/services/tests/Utilities.test.js +++ b/src/lib/services/tests/Utilities.test.js @@ -17,11 +17,11 @@ it('Keyboard mergeDisplay will work', () => { it('Keyboard function buttons will work', () => { setDOM(); - new Keyboard(); + const keyboard = new Keyboard(); - testLayoutFctButtons((fctBtnCount, fctBtnHasOnclickCount) => { + testLayoutFctButtons(keyboard, (fctBtnCount, fctBtnHasOnclickCount) => { expect(fctBtnCount).toBe(fctBtnHasOnclickCount); - }); + }, keyboard); }); it('Keyboard {bksp} button will work', () => { diff --git a/src/utils/TestUtility.js b/src/utils/TestUtility.js index 0904006d..8a92251f 100644 --- a/src/utils/TestUtility.js +++ b/src/utils/TestUtility.js @@ -44,7 +44,7 @@ let stdBtnCount = 0; let fullInput = ''; - iterateButtons((button) => { + keyboard.recurseButtons((button) => { const label = button.getAttribute("data-skbtn"); if(label.includes("{")) @@ -89,11 +89,11 @@ /** * Test if function buttons are interactive (have an onclick) */ - export const testLayoutFctButtons = (callback) => { + export const testLayoutFctButtons = (keyboard, callback) => { let fctBtnCount = 0; let fctBtnHasOnclickCount = 0; - iterateButtons((button) => { + keyboard.recurseButtons((button) => { const label = button.getAttribute("data-skbtn"); if(!label.includes("{") && !label.includes("}")) @@ -110,19 +110,6 @@ }); } - /** - * Iterates on the keyboard buttons - */ - export const iterateButtons = (callback, selector) => { - const rows = document.body.querySelector(selector || '.simple-keyboard').children; - - Array.from(rows).forEach(row => { - Array.from(row.children).forEach((button) => { - callback(button); - }); - }); - } - /** * Remove RTL control chars */ diff --git a/tsconfig.json b/tsconfig.json index 9f05a761..d2b216b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "noImplicitAny": true, - "outFile": "build/index.d.ts", + "outDir": "build/types", "module": "esnext", "target": "es5", "allowJs": true, @@ -9,9 +9,10 @@ "declaration": true, "emitDeclarationOnly": true, "suppressImplicitAnyIndexErrors": true, - "lib": ["es2018", "dom"], + "lib": ["es2020", "dom"], "moduleResolution": "node", + "downlevelIteration": true }, "include": ["src/lib"], - "exclude": ["src/**/tests"], + "exclude": ["src/lib/**/tests"], } \ No newline at end of file diff --git a/webpack.config.demo.js b/webpack.config.demo.js new file mode 100644 index 00000000..cb915a38 --- /dev/null +++ b/webpack.config.demo.js @@ -0,0 +1,51 @@ +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + mode: "development", + devtool: 'cheap-module-source-map', + entry: './src/demo/index.js', + output: { + filename: 'index.js' + }, + optimization: { + minimize: false, + }, + devServer: { + open: true, + hot: true, + host: "localhost", + port: 9000 + }, + module: { + rules: [ + { + test: /\.(m|j|t)s$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + MiniCssExtractPlugin.loader, + { loader: "css-loader", options: { sourceMap: true } }, + ], + }, + { + test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/, + use: ['url-loader'], + } + ] + }, + plugins: [ + new MiniCssExtractPlugin({ + filename: 'css/index.css' + }), + new HtmlWebpackPlugin(), + ], + resolve: { + extensions: ['.ts', '.js', '.json'] + } +}; \ No newline at end of file