Compare commits

...
38 Commits
Author SHA1 Message Date
Francisco Hodge effee00b87 Added new inputPattern option 2019-01-24 23:04:59 -05:00
Francisco Hodge 90b408eff6 Tests update 2019-01-24 23:03:48 -05:00
Francisco Hodge 21fa732b1f Types update 2019-01-24 23:03:23 -05:00
Francisco Hodge 80f4307c36 Build update 2019-01-24 23:03:14 -05:00
Francisco Hodge 681bb3d0ee npm update 2019-01-24 23:02:59 -05:00
Francisco Hodge e1fa685c6c Merge branch 'master' of https://github.com/hodgef/simple-keyboard 2019-01-17 18:37:07 -05:00
Francisco Hodge 2de7154128 npm update 2019-01-17 18:36:48 -05:00
Francisco Hodge c9afe43f5b Build update 2019-01-17 18:36:36 -05:00
Francisco Hodge c59f819db9 Tests update 2019-01-17 18:36:19 -05:00
Francisco Hodge 1f9efb0c66 Ensure caretPosition is unset on disableCaretPositioning 2019-01-17 18:36:09 -05:00
Francisco HodgeandGitHub 32cbce8c8a Update issue templates 2019-01-17 09:20:47 -05:00
Francisco Hodge 6c2236f762 Adding types for disableCaretPositioning option 2019-01-16 19:38:42 -05:00
Francisco Hodge 23a50e6f44 Updated devDependencies 2019-01-06 15:44:07 -05:00
Francisco Hodge c316d493c7 Tests update 2018-12-27 13:46:15 -05:00
Francisco Hodge 70e7635f25 npm update 2018-12-27 13:38:38 -05:00
Francisco HodgeandGitHub f5b73b09e7 Merge pull request #45 from mkusher/patch-1
fixed camelCase function
2018-12-27 13:33:09 -05:00
Aleh KashnikauandGitHub 7432e01740 fixed camelCase function
Added check for empty word
2018-12-27 21:29:05 +03:00
Francisco Hodge 459ab71c45 npm update 2018-12-24 13:31:13 -05:00
Francisco Hodge a5c177e41c Specifying layout class on keyboard element 2018-12-24 13:30:52 -05:00
Francisco Hodge d382945de7 Updated devDependencies 2018-12-23 17:42:02 -05:00
Francisco Hodge 4335f477a1 Adding new option: useButtonTag 2018-12-14 00:28:18 -05:00
Francisco Hodge d03f00c0d1 Updated devDependencies 2018-12-08 15:49:33 -05:00
Francisco HodgeandGitHub 9cea07dd41 Merge pull request #41 from armno/fix-incorrect-return-type-definition
[Angular] Fix return type of getButtonElement()
2018-12-04 20:11:10 -05:00
Francisco Hodge efe18e7240 Build update 2018-12-04 20:06:52 -05:00
Francisco Hodge 82e242a806 Modified getInput return type 2018-12-04 20:06:32 -05:00
Armno 4a9d485d5b add return type for getButtonElement in type definition file 2018-12-04 10:42:05 +07:00
Francisco Hodge 6ffd2e77ad Improved Angular types support 2018-12-02 14:48:46 -05:00
Francisco Hodge 7753bc5ba3 Build update 2018-11-28 09:04:10 -05:00
Francisco HodgeandGitHub 9c4fa00363 Merge pull request #40 from armno/master
Add type definition file for TypeScript
2018-11-28 08:58:36 -05:00
Francisco Hodge 251af057d8 npm update 2018-11-28 08:53:06 -05:00
Francisco Hodge e60574d56d Build update 2018-11-28 08:52:58 -05:00
Francisco Hodge b3b482e864 Copy index.d.ts to build folder on build 2018-11-28 08:52:27 -05:00
Armno ff037ad5b7 remove exporting KeyboardOptions interface 2018-11-28 12:43:13 +07:00
Armno ede2ce04b1 add overloaded constructor type definition 2018-11-28 11:56:00 +07:00
Armno 10380099e6 add more types 2018-11-28 11:20:32 +07:00
Armno 058b6774da Merge remote-tracking branch 'upstream/master' 2018-11-28 09:17:25 +07:00
Armno b5cbfa780b add public methods type definitions 2018-11-27 23:43:20 +07:00
Armno 5c40dd3109 WIP: create type definition file 2018-11-27 19:57:08 +07:00
19 changed files with 1831 additions and 1231 deletions
+4 -1
View File
@@ -1,6 +1,9 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help improve simple-keyboard about: Create a report to help improve simple-keyboard
title: ''
labels: ''
assignees: hodgef
--- ---
@@ -8,7 +11,7 @@ about: Create a report to help improve simple-keyboard
As some bugs have been addressed in later versions, please ensure you are running the latest. As some bugs have been addressed in later versions, please ensure you are running the latest.
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is. Providing a [sandbox example](https://codesandbox.io/s/vanilla) or code depicting the issue is important, as this will help us reproduce the issue.
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
@@ -1,6 +1,9 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea you'd like to see in simple-keyboard about: Suggest an idea you'd like to see in simple-keyboard
title: ''
labels: ''
assignees: ''
--- ---
+2 -2
View File
@@ -1,6 +1,6 @@
/*! /*!
* *
* simple-keyboard v2.11.5 * simple-keyboard v2.14.0
* https://github.com/hodgef/simple-keyboard * https://github.com/hodgef/simple-keyboard
* *
* Copyright (c) Francisco Hodge (https://github.com/hodgef) * Copyright (c) Francisco Hodge (https://github.com/hodgef)
@@ -8,5 +8,5 @@
* This source code is licensed under the MIT license found in the * This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
* *
*/body,html{margin:0;padding:0}.simple-keyboard{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;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}.simple-keyboard .hg-row{display:flex}.simple-keyboard .hg-row:not(:last-child){margin-bottom:5px}.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-button{display:inline-block;flex-grow:1;cursor:pointer}.hg-standardBtn{max-width:100px}.simple-keyboard.hg-theme-default{background-color:rgba(0,0,0,.1);padding:5px;border-radius:5px}.simple-keyboard.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}.simple-keyboard.hg-theme-default .hg-button:active{background:#e4e4e4}.simple-keyboard.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadadd,.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.simple-keyboard.hg-theme-default .hg-button.hg-button-com{max-width:85px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px} */body,html{margin:0;padding:0}.simple-keyboard{font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;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}.simple-keyboard .hg-row{display:flex}.simple-keyboard .hg-row:not(:last-child){margin-bottom:5px}.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-button{display:inline-block;flex-grow:1;cursor:pointer}.hg-standardBtn{max-width:100px}.simple-keyboard.hg-theme-default{background-color:rgba(0,0,0,.1);padding:5px;border-radius:5px}.simple-keyboard.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}.simple-keyboard button.hg-button{border-width:0;outline:0;font-size:inherit}.simple-keyboard.hg-theme-default .hg-button:active{background:#e4e4e4}.simple-keyboard.hg-theme-default.hg-layout-numeric .hg-button{width:33.3%;height:60px;align-items:center;display:flex;justify-content:center}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadadd,.simple-keyboard.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.simple-keyboard.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.simple-keyboard.hg-theme-default .hg-button.hg-button-com{max-width:85px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.simple-keyboard.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}
/*# sourceMappingURL=index.css.map */ /*# sourceMappingURL=index.css.map */
File diff suppressed because one or more lines are too long
+199
View File
@@ -0,0 +1,199 @@
declare module 'simple-keyboard' {
interface KeyboardLayoutObject {
default: string[];
shift?: string[];
}
interface KeyboardButtonTheme {
class: string;
buttons: string;
}
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[];
/**
* 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 elements maxlengthattribute.
*
* `{ [inputName: string]: number }`: Restrains simple-keyboards individual inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*/
maxLength?:
| number
| {
[inputName: string]: number;
};
/**
* 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;
/**
* Calling preventDefault for the mousedown events keeps the focus on the input.
*/
preventMouseDownDefault?: 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;
/**
* 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;
/**
* Executes the callback function on key press. Returns button layout name (i.e.: "{shift}").
*/
onKeyPress?: (button: string) => any;
/**
* Executes the callback function on input change. Returns the current input's string.
*/
onChange?: (input: string) => any;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender?: () => void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit?: () => void;
/**
* Executes the callback function on input change. Returns the input object with all defined inputs.
*/
onChangeAll?: (inputs: any) => any;
}
class Keyboard {
constructor(selector: string, options: KeyboardOptions);
constructor(options: KeyboardOptions);
options: KeyboardOptions;
/**
* 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;
/**
* Clear the keyboard's input.
*
* @param {string} [inputName] optional - the internal input to select
*/
clearInput(inputName?: string): void;
/**
* Get the keyboards input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select
*/
getInput(inputName?: string): string;
/**
* Set the keyboards input.
* @param {string} input the input value
* @param {string} inputName optional - the internal input to select
*/
setInput(input: string, inputName?: string): void;
/**
* Set new option or modify existing ones after initialization.
* @param {KeyboardOptions} option The option to set
*/
setOptions(options: KeyboardOptions): 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: any, key: string) => void): 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): HTMLElement | HTMLElement[];
}
export default Keyboard;
}
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -79,6 +79,7 @@ module.exports = {
appPackageJson: resolveApp('package.json'), appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'), appSrc: resolveApp('src'),
appSrcLib: resolveApp('src/lib'), appSrcLib: resolveApp('src/lib'),
appSrcLibTypes: resolveApp('src/lib/@types'),
appSrcDemo: resolveApp('src/demo'), appSrcDemo: resolveApp('src/demo'),
appTsConfig: resolveApp('tsconfig.json'), appTsConfig: resolveApp('tsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'), yarnLockFile: resolveApp('yarn.lock'),
+7
View File
@@ -21,6 +21,7 @@ const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin-alt');
const typescriptFormatter = require('react-dev-utils/typescriptFormatter'); const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const getPackageJson = require('./getPackageJson'); const getPackageJson = require('./getPackageJson');
@@ -510,6 +511,12 @@ module.exports = {
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js: // You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new CopyWebpackPlugin([
{
from: `${paths.appSrcLibTypes}`,
to: paths.appLayoutsBuild
}
]),
// Generate a service worker script that will precache, and keep up to date, // Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the Webpack build. // the HTML & assets that are part of the Webpack build.
/*new WorkboxWebpackPlugin.GenerateSW({ /*new WorkboxWebpackPlugin.GenerateSW({
+1190 -1163
View File
File diff suppressed because it is too large Load Diff
+39 -31
View File
@@ -1,8 +1,9 @@
{ {
"name": "simple-keyboard", "name": "simple-keyboard",
"version": "2.11.5", "version": "2.14.0",
"description": "On-screen Javascript Virtual Keyboard", "description": "On-screen Javascript Virtual Keyboard",
"main": "build/index.js", "main": "build/index.js",
"types": "build/index.d.ts",
"scripts": { "scripts": {
"start": "node scripts/start.js", "start": "node scripts/start.js",
"build": "node scripts/build.js", "build": "node scripts/build.js",
@@ -34,72 +35,79 @@
"touchscreen", "touchscreen",
"touch-screen", "touch-screen",
"kiosk", "kiosk",
"osk" "osk",
"js"
], ],
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/core": "7.1.6", "@babel/core": "7.2.2",
"@babel/plugin-proposal-class-properties": "^7.1.0", "@babel/plugin-proposal-class-properties": "^7.2.3",
"@babel/preset-env": "^7.1.6", "@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"@svgr/webpack": "4.1.0", "@svgr/webpack": "4.1.0",
"babel-core": "7.0.0-bridge.0", "babel-core": "7.0.0-bridge.0",
"babel-eslint": "9.0.0", "babel-eslint": "10.0.1",
"babel-jest": "23.6.0", "babel-jest": "23.6.0",
"babel-loader": "8.0.4", "babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "^0.2.3", "babel-plugin-named-asset-import": "^0.3.0",
"babel-preset-react-app": "^6.1.0", "babel-preset-react-app": "^7.0.0",
"bfj": "6.1.1", "bfj": "6.1.1",
"case-sensitive-paths-webpack-plugin": "2.1.2", "case-sensitive-paths-webpack-plugin": "2.1.2",
"chalk": "2.4.1", "chalk": "2.4.2",
"css-loader": "1.0.1", "copy-webpack-plugin": "^4.6.0",
"dotenv": "6.1.0", "css-loader": "2.1.0",
"dotenv": "6.2.0",
"dotenv-expand": "4.2.0", "dotenv-expand": "4.2.0",
"esdoc": "^1.1.0", "esdoc": "^1.1.0",
"esdoc-ecmascript-proposal-plugin": "^1.0.0", "esdoc-ecmascript-proposal-plugin": "^1.0.0",
"esdoc-standard-plugin": "^1.0.0", "esdoc-standard-plugin": "^1.0.0",
"eslint": "5.9.0", "eslint": "5.12.0",
"eslint-config-react-app": "^3.0.5", "eslint-config-react-app": "^3.0.6",
"eslint-loader": "2.1.1", "eslint-loader": "2.1.1",
"eslint-plugin-flowtype": "2.50.3", "eslint-plugin-flowtype": "3.2.0",
"eslint-plugin-import": "2.14.0", "eslint-plugin-import": "2.14.0",
"eslint-plugin-jsx-a11y": "6.1.2", "eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-react": "7.11.1", "eslint-plugin-react": "7.12.3",
"file-loader": "2.0.0", "file-loader": "3.0.1",
"fork-ts-checker-webpack-plugin-alt": "0.4.14", "fork-ts-checker-webpack-plugin-alt": "0.4.14",
"fs-extra": "7.0.1", "fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-beta.4", "html-webpack-plugin": "4.0.0-beta.5",
"identity-obj-proxy": "3.0.0", "identity-obj-proxy": "3.0.0",
"jest": "23.6.0", "jest": "23.6.0",
"jest-pnp-resolver": "1.0.2", "jest-pnp-resolver": "1.0.2",
"jest-resolve": "23.6.0", "jest-resolve": "23.6.0",
"mini-css-extract-plugin": "0.4.4", "mini-css-extract-plugin": "0.5.0",
"optimize-css-assets-webpack-plugin": "5.0.1", "optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.2.0", "pnp-webpack-plugin": "1.2.1",
"postcss-flexbugs-fixes": "4.1.0", "postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"postcss-preset-env": "6.4.0", "postcss-preset-env": "6.5.0",
"postcss-safe-parser": "4.0.1", "postcss-safe-parser": "4.0.1",
"react": "^16.6.3", "react": "^16.7.0",
"react-app-polyfill": "^0.1.3", "react-app-polyfill": "^0.2.0",
"react-dev-utils": "^6.1.1", "react-dev-utils": "^7.0.1",
"react-dom": "^16.6.1", "react-dom": "^16.7.0",
"resolve": "1.8.1", "resolve": "1.9.0",
"sass-loader": "7.1.0", "sass-loader": "7.1.0",
"style-loader": "0.23.1", "style-loader": "0.23.1",
"terser-webpack-plugin": "1.1.0", "terser-webpack-plugin": "1.2.1",
"url-loader": "1.1.2", "url-loader": "1.1.2",
"webpack": "4.26.1", "webpack": "4.28.3",
"webpack-dev-server": "3.1.10", "webpack-dev-server": "3.1.14",
"webpack-manifest-plugin": "2.0.4", "webpack-manifest-plugin": "2.0.4",
"workbox-webpack-plugin": "3.6.3" "workbox-webpack-plugin": "3.6.3"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app",
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
}
}, },
"browserslist": [ "browserslist": [
">0.2%", ">0.2%",
"not dead",
"not ie <= 11", "not ie <= 11",
"not op_mini all" "not op_mini all"
], ],
+1 -1
View File
@@ -31,7 +31,7 @@ class App {
onChange: input => this.onChange(input), onChange: input => this.onChange(input),
onKeyPress: button => this.onKeyPress(button), onKeyPress: button => this.onKeyPress(button),
newLineOnEnter: true, newLineOnEnter: true,
physicalKeyboardHighlight: true, physicalKeyboardHighlight: true
}); });
/** /**
+1 -1
View File
@@ -8,7 +8,7 @@
#root .simple-keyboard-preview { #root .simple-keyboard-preview {
background: rgba(0,0,0,0.8); background: rgba(0,0,0,0.8);
border: 20px solid rgba(0,0,0,0.1); border: 20px solid rgba(0,0,0,0.1);
height: 260px; height: 200px;
border-top-right-radius: 5px; border-top-right-radius: 5px;
border-top-left-radius: 5px; border-top-left-radius: 5px;
padding: 10px; padding: 10px;
+199
View File
@@ -0,0 +1,199 @@
declare module 'simple-keyboard' {
interface KeyboardLayoutObject {
default: string[];
shift?: string[];
}
interface KeyboardButtonTheme {
class: string;
buttons: string;
}
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[];
/**
* 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 elements maxlengthattribute.
*
* `{ [inputName: string]: number }`: Restrains simple-keyboards individual inputs to a certain length. This should be used in addition to the input elements maxlengthattribute.
*/
maxLength?:
| number
| {
[inputName: string]: number;
};
/**
* 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;
/**
* Calling preventDefault for the mousedown events keeps the focus on the input.
*/
preventMouseDownDefault?: 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;
/**
* 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;
/**
* Executes the callback function on key press. Returns button layout name (i.e.: "{shift}").
*/
onKeyPress?: (button: string) => any;
/**
* Executes the callback function on input change. Returns the current input's string.
*/
onChange?: (input: string) => any;
/**
* Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
*/
onRender?: () => void;
/**
* Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
*/
onInit?: () => void;
/**
* Executes the callback function on input change. Returns the input object with all defined inputs.
*/
onChangeAll?: (inputs: any) => any;
}
class Keyboard {
constructor(selector: string, options: KeyboardOptions);
constructor(options: KeyboardOptions);
options: KeyboardOptions;
/**
* 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;
/**
* Clear the keyboard's input.
*
* @param {string} [inputName] optional - the internal input to select
*/
clearInput(inputName?: string): void;
/**
* Get the keyboards input (You can also get it from the onChange prop).
* @param {string} [inputName] optional - the internal input to select
*/
getInput(inputName?: string): string;
/**
* Set the keyboards input.
* @param {string} input the input value
* @param {string} inputName optional - the internal input to select
*/
setInput(input: string, inputName?: string): void;
/**
* Set new option or modify existing ones after initialization.
* @param {KeyboardOptions} option The option to set
*/
setOptions(options: KeyboardOptions): 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: any, key: string) => void): 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): HTMLElement | HTMLElement[];
}
export default Keyboard;
}
+7
View File
@@ -57,6 +57,13 @@ body, html {
justify-content: center; justify-content: center;
} }
/* When using option "useButtonTag" */
.simple-keyboard button.hg-button {
border-width: 0;
outline: 0;
font-size: inherit;
}
.simple-keyboard.hg-theme-default .hg-button:active { .simple-keyboard.hg-theme-default .hg-button:active {
background: #e4e4e4; background: #e4e4e4;
} }
+78 -25
View File
@@ -18,7 +18,7 @@ class 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. * @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){ constructor(...params){
let keyboardDOMQuery = typeof params[0] === "string" ? params[0] : '.simple-keyboard'; let keyboardDOMQuery = typeof params[0] === "string" ? params[0] : ".simple-keyboard";
let options = typeof params[0] === "object" ? params[0] : params[1]; let options = typeof params[0] === "object" ? params[0] : params[1];
if(!options) if(!options)
@@ -58,6 +58,9 @@ class SimpleKeyboard {
* @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts). * @property {function} onRender Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts).
* @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization). * @property {function} onInit Executes the callback function once simple-keyboard is rendered for the first time (on initialization).
* @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs. * @property {function(inputs: object):object} onChangeAll Executes the callback function on input change. Returns the input object with all defined inputs.
* @property {boolean} useButtonTag Render buttons as a button element instead of a div element.
* @property {boolean} disableCaretPositioning A prop to ensure characters are always be added/removed at the end of the string.
* @property {object} inputPattern Restrains input(s) change to the defined regular expression pattern.
*/ */
this.options = options; this.options = options;
this.options.layoutName = this.options.layoutName || "default"; this.options.layoutName = this.options.layoutName || "default";
@@ -94,6 +97,7 @@ class SimpleKeyboard {
this.handleButtonMouseDown = this.handleButtonMouseDown.bind(this); this.handleButtonMouseDown = this.handleButtonMouseDown.bind(this);
this.handleButtonHold = this.handleButtonHold.bind(this); this.handleButtonHold = this.handleButtonHold.bind(this);
this.onModulesLoaded = this.onModulesLoaded.bind(this); this.onModulesLoaded = this.onModulesLoaded.bind(this);
this.inputPatternIsValid = this.inputPatternIsValid.bind(this);
/** /**
* simple-keyboard uses a non-persistent internal input to keep track of the entered string (the variable `keyboard.input`). * simple-keyboard uses a non-persistent internal input to keep track of the entered string (the variable `keyboard.input`).
@@ -179,7 +183,17 @@ class SimpleKeyboard {
button, this.input[this.options.inputName], this.options, this.caretPosition button, this.input[this.options.inputName], this.options, this.caretPosition
); );
if(this.input[this.options.inputName] !== updatedInput){ if(
// If input will change as a result of this button press
this.input[this.options.inputName] !== updatedInput &&
// This pertains to the "inputPattern" option:
(
// If inputPattern isn't set
!this.options.inputPattern ||
// Or, if it is set and if the pattern is valid - we proceed.
(this.options.inputPattern && this.inputPatternIsValid(updatedInput))
)
){
/** /**
* If maxLength and handleMaxLength yield true, halting * If maxLength and handleMaxLength yield true, halting
@@ -502,6 +516,39 @@ class SimpleKeyboard {
return output; return output;
} }
/**
* This handles the "inputPattern" option
* by checking if the provided inputPattern passes
*/
inputPatternIsValid(inputVal){
let inputPatternRaw = this.options.inputPattern;
let inputPattern;
/**
* Check if input pattern is global or targeted to individual inputs
*/
if(inputPatternRaw instanceof RegExp){
inputPattern = inputPatternRaw;
} else {
inputPattern = inputPatternRaw[this.options.inputName];
}
if(inputPattern && inputVal){
let didInputMatch = inputPattern.test(inputVal);
if(this.options.debug){
console.log(`inputPattern ("${inputPattern}"): ${didInputMatch ? "passed" : "did not pass!"}`);
}
return didInputMatch;
} else {
/**
* inputPattern doesn't seem to be set for the current input, or input is empty. Pass.
*/
return true;
}
}
/** /**
* Retrieves the current cursor position within a input or textarea (if any) * Retrieves the current cursor position within a input or textarea (if any)
*/ */
@@ -540,24 +587,29 @@ class SimpleKeyboard {
this.dispatch(instance => { this.dispatch(instance => {
if(instance.isMouseHold){ if(instance.isMouseHold){
instance.isMouseHold = false; instance.isMouseHold = false;
} }
if( if(
(targetTagName === "textarea" || (targetTagName === "textarea" ||
targetTagName === "input") && targetTagName === "input") &&
!instance.options.disableCaretPositioning !instance.options.disableCaretPositioning
){ ){
/** /**
* Tracks current cursor position * Tracks current cursor position
* As keys are pressed, text will be added/removed at that position within the input. * As keys are pressed, text will be added/removed at that position within the input.
*/ */
instance.caretPosition = event.target.selectionStart; instance.caretPosition = event.target.selectionStart;
if(instance.options.debug){ if(instance.options.debug){
console.log('Caret at: ', event.target.selectionStart, event.target.tagName.toLowerCase(), `(${instance.keyboardDOMClass})`); console.log("Caret at: ", event.target.selectionStart, event.target.tagName.toLowerCase(), `(${instance.keyboardDOMClass})`);
} }
} } else if(instance.options.disableCaretPositioning){
/**
* If we toggled off disableCaretPositioning, we must ensure caretPosition doesn't persist once reactivated.
*/
instance.caretPosition = null;
}
}); });
} }
@@ -621,7 +673,7 @@ class SimpleKeyboard {
module.init(this); module.init(this);
}); });
this.keyboardPluginClasses = this.keyboardPluginClasses + ' modules-loaded'; this.keyboardPluginClasses = this.keyboardPluginClasses + " modules-loaded";
this.render(); this.render();
this.onModulesLoaded(); this.onModulesLoaded();
@@ -654,7 +706,7 @@ class SimpleKeyboard {
*/ */
this.clear(); this.clear();
let layoutClass = this.options.layout ? "hg-layout-custom" : `hg-layout-${this.options.layoutName}`; let layoutClass = `hg-layout-${this.options.layoutName}`;
let layout = this.options.layout || KeyboardLayout.getDefaultLayout(); let layout = this.options.layout || KeyboardLayout.getDefaultLayout();
let useTouchEvents = this.options.useTouchEvents || false let useTouchEvents = this.options.useTouchEvents || false
@@ -668,7 +720,7 @@ class SimpleKeyboard {
let themeButtons; let themeButtons;
if(typeof themeObj.buttons === "string"){ if(typeof themeObj.buttons === "string"){
themeButtons = themeObj.buttons.split(' '); themeButtons = themeObj.buttons.split(" ");
} }
if(themeButtons){ if(themeButtons){
@@ -701,12 +753,12 @@ class SimpleKeyboard {
* Iterating through each row * Iterating through each row
*/ */
layout[this.options.layoutName].forEach((row, rIndex) => { layout[this.options.layoutName].forEach((row, rIndex) => {
let rowArray = row.split(' '); let rowArray = row.split(" ");
/** /**
* Creating empty row * Creating empty row
*/ */
var rowDOM = document.createElement('div'); let rowDOM = document.createElement("div");
rowDOM.className += "hg-row"; rowDOM.className += "hg-row";
/** /**
@@ -720,7 +772,8 @@ class SimpleKeyboard {
/** /**
* Creating button * Creating button
*/ */
var buttonDOM = document.createElement('div'); let buttonType = this.options.useButtonTag ? "button" : "div";
let buttonDOM = document.createElement(buttonType);
buttonDOM.className += `hg-button ${fctBtnClass}${buttonThemeClass ? " "+buttonThemeClass : ""}`; buttonDOM.className += `hg-button ${fctBtnClass}${buttonThemeClass ? " "+buttonThemeClass : ""}`;
if (useTouchEvents) { if (useTouchEvents) {
@@ -761,7 +814,7 @@ class SimpleKeyboard {
/** /**
* Adding button label to button * Adding button label to button
*/ */
var buttonSpanDOM = document.createElement('span'); let buttonSpanDOM = document.createElement('span');
buttonSpanDOM.innerHTML = buttonDisplayName; buttonSpanDOM.innerHTML = buttonDisplayName;
buttonDOM.appendChild(buttonSpanDOM); buttonDOM.appendChild(buttonSpanDOM);
+81 -1
View File
@@ -137,7 +137,9 @@ it('Keyboard onKeyPress will work', () => {
it('Keyboard standard function buttons will not change input', () => { it('Keyboard standard function buttons will not change input', () => {
testUtil.setDOM(); testUtil.setDOM();
let keyboard = new Keyboard(); let keyboard = new Keyboard({
useButtonTag: true
});
testUtil.iterateButtons((button) => { testUtil.iterateButtons((button) => {
if(button.getAttribute("data-skbtn") === "{shift}"){ if(button.getAttribute("data-skbtn") === "{shift}"){
@@ -596,6 +598,42 @@ it('Keyboard caretEventHandler will detect input, textarea focus', () => {
expect(keyboard.caretPosition).toBe(3); expect(keyboard.caretPosition).toBe(3);
}); });
it('Keyboard caretEventHandler will not set caretPosition on disableCaretPositioning', () => {
testUtil.setDOM();
let keyboard = new Keyboard();
keyboard.caretEventHandler({
charCode: 0,
code: "KeyF",
key: "f",
which: 70,
target: {
tagName: "input",
selectionStart: 3
}
});
expect(keyboard.caretPosition).toBe(3);
keyboard.setOptions({
disableCaretPositioning: true
});
keyboard.caretEventHandler({
charCode: 0,
code: "KeyF",
key: "f",
which: 70,
target: {
tagName: "input",
selectionStart: 3
}
});
expect(keyboard.caretPosition).toBeFalsy();
});
it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', () => { it('Keyboard caretEventHandler ignore positioning if input, textarea is blur', () => {
testUtil.setDOM(); testUtil.setDOM();
@@ -909,4 +947,46 @@ it('Keyboard onModulesLoaded will work', () => {
}); });
expect(foo).toBe("bar"); expect(foo).toBe("bar");
});
it('Keyboard inputPattern will work globally', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
inputPattern: /^\d+$/
});
keyboard.getButtonElement("q").onclick();
expect(keyboard.getInput()).toBeFalsy();
keyboard.getButtonElement("1").onclick();
expect(keyboard.getInput()).toBe("1");
});
it('Keyboard inputPattern will work by input name', () => {
testUtil.setDOM();
let keyboard = new Keyboard({
debug: true,
inputName: "test1",
inputPattern: {
test1: /^\d+$/
}
});
keyboard.getButtonElement("q").onclick();
keyboard.getButtonElement("1").onclick();
expect(keyboard.getInput()).toBe("1");
keyboard.setOptions({
inputName: "default"
});
keyboard.getButtonElement("q").onclick();
keyboard.getButtonElement("1").onclick();
expect(keyboard.getInput()).toBe("q1");
}); });
+9 -2
View File
@@ -359,7 +359,14 @@ class Utilities {
* @param {string} string The string to transform. * @param {string} string The string to transform.
*/ */
camelCase(string){ camelCase(string){
return string.toLowerCase().trim().split(/[.\-_\s]/g).reduce((string, word) => string + word[0].toUpperCase() + word.slice(1)); return string
.toLowerCase()
.trim()
.split(/[.\-_\s]/g)
.reduce(
(string, word) =>
word.length ? string + word[0].toUpperCase() + word.slice(1) : string
);
}; };
/** /**
@@ -373,4 +380,4 @@ class Utilities {
} }
} }
export default Utilities; export default Utilities;
+6
View File
@@ -477,4 +477,10 @@ it('Keyboard removeAt will remove regular strings', () => {
keyboard.caretPosition = 6; keyboard.caretPosition = 6;
output = keyboard.utilities.removeAt("testie", 6, true); output = keyboard.utilities.removeAt("testie", 6, true);
expect(keyboard.caretPosition).toBe(5); expect(keyboard.caretPosition).toBe(5);
});
it('Keyboard will work with custom (and weird) class', () => {
testUtil.setDOM("my--weird--class");
let keyboard = new Keyboard(".my--weird--class");
expect(keyboard.keyboardDOMClass).toBe("my--weird--class");
}); });