mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2026-02-03 00:06:50 +08:00
Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2479c47d2 | ||
|
|
0e94d9c4e7 | ||
|
|
d47d3d60ae | ||
|
|
f2a97b6dcb | ||
|
|
70b99b44c6 | ||
|
|
0c481cb29a | ||
|
|
d92f84f5c3 | ||
|
|
6fe56c3abc | ||
|
|
6578a8d867 | ||
|
|
b6303de61f | ||
|
|
4e888c5e91 | ||
|
|
d9c9e40800 | ||
|
|
6996e59871 | ||
|
|
35f26a4882 | ||
|
|
e1c146d66e | ||
|
|
c4382e586d | ||
|
|
ff69ff516b | ||
|
|
3c71de374c | ||
|
|
57a1240505 | ||
|
|
6f3d749f19 | ||
|
|
a0dd220b1b | ||
|
|
30bbf0a44f | ||
|
|
5a11fa9b1d | ||
|
|
39830f3ca0 | ||
|
|
ef91217dd2 | ||
|
|
020fa57a97 | ||
|
|
acd511de86 | ||
|
|
e4c0a1a767 | ||
|
|
49a24dad17 | ||
|
|
80ae730f4b | ||
|
|
44347b8450 | ||
|
|
2ac055b8d2 | ||
|
|
9f772a1b28 | ||
|
|
6df471aff7 | ||
|
|
315ddc3892 | ||
|
|
68cbe73b23 | ||
|
|
1cf6f3884f | ||
|
|
1bfe7bac85 | ||
|
|
cb44bdaaf1 | ||
|
|
15f8ef056b | ||
|
|
5b608d4f71 | ||
|
|
0c49b12341 | ||
|
|
dcfd0f160d | ||
|
|
7206558540 | ||
|
|
d1cdbd2d11 | ||
|
|
6cf99720c4 | ||
|
|
86caf021fa | ||
|
|
6c3df6725b | ||
|
|
fb3daa3e7a | ||
|
|
06f36cffda | ||
|
|
38eb1d4975 | ||
|
|
eab836e4e9 | ||
|
|
e2ff5e29c4 | ||
|
|
4a8bc0e16d | ||
|
|
9c896fd2f5 | ||
|
|
9a6fae4968 | ||
|
|
a921edd637 | ||
|
|
0471e84958 | ||
|
|
757504d929 | ||
|
|
b013025762 | ||
|
|
ae993c4a58 | ||
|
|
587933f14b | ||
|
|
1e21d0e759 | ||
|
|
775c4866b3 | ||
|
|
e2e7dbd571 | ||
|
|
2b1a875f01 | ||
|
|
c4713082f8 | ||
|
|
1282464e3b | ||
|
|
368cf1588d | ||
|
|
997e448ed2 | ||
|
|
460cd8753d | ||
|
|
2c0bce1d93 | ||
|
|
d5caa8161c | ||
|
|
ce24a1b5e0 | ||
|
|
3f465f2514 | ||
|
|
91b66183cb | ||
|
|
a71bf0c81d | ||
|
|
9e7bc9f303 | ||
|
|
b03864d0e5 | ||
|
|
be0f4a016d | ||
|
|
3472031203 | ||
|
|
7c5def8e40 | ||
|
|
2af26a861f | ||
|
|
7ed08cff0d | ||
|
|
8c2ad22c48 | ||
|
|
c6e96c5fa4 | ||
|
|
71b451f02a | ||
|
|
9aa1490087 | ||
|
|
f1b6d5cbd8 | ||
|
|
46302acff0 | ||
|
|
a43b32954d | ||
|
|
3764e7b6f9 | ||
|
|
17ac7b56de | ||
|
|
991a5c58c8 | ||
|
|
a7323fa8ce | ||
|
|
45396c0a0f | ||
|
|
116f90910d | ||
|
|
14c7d33664 | ||
|
|
7906ff209f | ||
|
|
e2522931a7 | ||
|
|
a9b475782f | ||
|
|
49f3357975 | ||
|
|
bddc1ccdf1 | ||
|
|
735928e7fc | ||
|
|
b6130d2834 | ||
|
|
949876e7f4 | ||
|
|
fd82ea8f3f | ||
|
|
7c4c40cfd4 | ||
|
|
4505438932 | ||
|
|
6280875f4c | ||
|
|
46c809cbf9 | ||
|
|
f71917377f | ||
|
|
3321b92f73 | ||
|
|
bb830ad60a | ||
|
|
978f969634 | ||
|
|
be7365ec64 | ||
|
|
f16798e1b0 | ||
|
|
1824635d47 | ||
|
|
50d08c848f | ||
|
|
300ea34eea | ||
|
|
85a467b6a6 | ||
|
|
9467e4ffe3 | ||
|
|
7cfaf5e1c0 | ||
|
|
24497cfd97 | ||
|
|
6203c9cbd1 | ||
|
|
27cf742fd1 | ||
|
|
760def8e49 | ||
|
|
bbaae9bdb4 | ||
|
|
baedb1dff4 | ||
|
|
7f52cb603c | ||
|
|
ef4d072708 | ||
|
|
52ebbe6198 | ||
|
|
f7c46fad05 | ||
|
|
ec4864ad2a | ||
|
|
da7112ea2b | ||
|
|
7d4e17f405 | ||
|
|
c40472f505 | ||
|
|
fa5e9c55c4 | ||
|
|
a3c7c75455 | ||
|
|
a4ca5df208 | ||
|
|
f75194bfd1 | ||
|
|
ebfc849029 | ||
|
|
9f842afa91 | ||
|
|
d63f03afb7 | ||
|
|
80801cb254 | ||
|
|
b626a0750b | ||
|
|
ec2c4545ea | ||
|
|
b201c68cb2 | ||
|
|
0c9d843040 | ||
|
|
3c29289a11 | ||
|
|
767b11f092 | ||
|
|
d8dda787ae | ||
|
|
aa689d67cf | ||
|
|
64dbe67c7b | ||
|
|
5fae64363d | ||
|
|
1d01e3e433 | ||
|
|
a3240e4315 | ||
|
|
0872203d9e | ||
|
|
5912880ae5 | ||
|
|
84bda916ef | ||
|
|
95ba625268 | ||
|
|
a9d56531d9 | ||
|
|
9a848dc9fe | ||
|
|
c48517520b | ||
|
|
91db170318 | ||
|
|
d1aff62d67 | ||
|
|
c627b05971 | ||
|
|
a21d490505 | ||
|
|
696e641519 | ||
|
|
6a95ba8959 | ||
|
|
9e3618fcea | ||
|
|
4d0860fa91 | ||
|
|
78f01d4675 | ||
|
|
4440b26a88 | ||
|
|
41c76b1b6e | ||
|
|
d2a271c9f3 | ||
|
|
a5af9cd47c | ||
|
|
1dcb7972f4 | ||
|
|
771ef9876f | ||
|
|
2a042fbaff | ||
|
|
b2591e38e8 | ||
|
|
fc9054010c | ||
|
|
ff2435abd8 | ||
|
|
66491c60e5 | ||
|
|
1f4b7c2fac | ||
|
|
1ff5759591 | ||
|
|
9517ea3e34 | ||
|
|
98d5da1475 | ||
|
|
fbdee610cd | ||
|
|
234373e228 | ||
|
|
e0e932cc06 | ||
|
|
6c5d6719b4 | ||
|
|
554dfcb76b | ||
|
|
a5b2fc2329 | ||
|
|
ea11244926 | ||
|
|
4852400915 | ||
|
|
5ee4f3fb28 | ||
|
|
fbc04e9e28 | ||
|
|
52dedb669a | ||
|
|
d52d580f7a | ||
|
|
1513110de2 | ||
|
|
c271643857 | ||
|
|
475c4efc14 | ||
|
|
2c7424c449 | ||
|
|
ac2bfe14b0 | ||
|
|
ea61995b4c | ||
|
|
36bd9b157c | ||
|
|
48bf0c2d13 | ||
|
|
a6db341a23 | ||
|
|
3e479d55e1 | ||
|
|
db753d7d38 | ||
|
|
d812186910 | ||
|
|
976a234874 | ||
|
|
3624ff0d04 | ||
|
|
5185977bcf | ||
|
|
d8ec56bfd0 | ||
|
|
6bf2267c54 | ||
|
|
c9213b0673 | ||
|
|
e70de0275f | ||
|
|
68b4298a34 | ||
|
|
76e6a29a36 | ||
|
|
c786c169f6 | ||
|
|
1940d6db03 | ||
|
|
cda06005e5 | ||
|
|
97448f126a | ||
|
|
a782deefea | ||
|
|
33bcf47f71 | ||
|
|
c6af491793 | ||
|
|
baa56f1feb | ||
|
|
b2189c17a7 | ||
|
|
ea26742914 | ||
|
|
af09aa885e | ||
|
|
4413e199cc | ||
|
|
57217d3025 | ||
|
|
987a1348a4 | ||
|
|
4d45bbdc90 | ||
|
|
de9565165d | ||
|
|
a3471aa0c0 | ||
|
|
8df40bc678 | ||
|
|
a4d376f289 | ||
|
|
9f8380d2da | ||
|
|
034dadcaf2 | ||
|
|
34d6d6a3f7 | ||
|
|
ba9c9a6a4e |
1
.github/pull_request_template.md
vendored
1
.github/pull_request_template.md
vendored
@@ -5,4 +5,3 @@ A few sentences describing the overall goals of the pull request's commits.
|
||||
## Checks
|
||||
|
||||
- [ ] Tests ( `npm run test -- --coverage` ) Coverage at `./coverage/lcov-report/index.html` should be 100%
|
||||
- [ ] Documentation ( `npm run docs` ) Coverage at `./docs/source.html` should be 100%
|
||||
44
.github/workflows/main.yml
vendored
Normal file
44
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Build
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x]
|
||||
os: [ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
- name: npm install, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm run start -- --testMode
|
||||
npm run demo
|
||||
npm run coverage
|
||||
- uses: codecov/codecov-action@v1.0.2
|
||||
with:
|
||||
token: ${{secrets.CODECOV_TOKEN}}
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Discord notification
|
||||
if: success()
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@master
|
||||
with:
|
||||
args: 'simple-keyboard - CI Build Passed'
|
||||
|
||||
- name: Discord notification
|
||||
if: failure()
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
uses: Ilshidur/action-discord@master
|
||||
with:
|
||||
args: 'simple-keyboard - CI Build Failed'
|
||||
|
||||
44
.github/workflows/publish.yml
vendored
Normal file
44
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
- run: npm install
|
||||
- run: npm run test -- --coverage --watchAll=false
|
||||
|
||||
- name: Setup GIT
|
||||
run: |
|
||||
git config --local --list
|
||||
git checkout master
|
||||
git config user.email "$GH_EMAIL"
|
||||
git config user.name "Francisco Hodge"
|
||||
env:
|
||||
GH_EMAIL: ${{secrets.GH_EMAIL}}
|
||||
|
||||
- name: Bump version
|
||||
run: |
|
||||
git reset --hard
|
||||
npm version patch
|
||||
npm run build
|
||||
git add . || true
|
||||
git commit -m "Build update" || true
|
||||
git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
|
||||
- name: npm publish
|
||||
run: |
|
||||
npm config set //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN
|
||||
npm run trypublish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
|
||||
35
README.md
35
README.md
@@ -2,18 +2,21 @@
|
||||
<a href="https://simple-keyboard.com/demo">
|
||||
<img alt="simple-keyboard: Javscript Virtual Keyboard" src="https://i.imgur.com/Po6659n.gif">
|
||||
</a>
|
||||
|
||||
|
||||
<a href="https://www.npmjs.com/package/simple-keyboard">
|
||||
<img src="https://badgen.net/npm/v/simple-keyboard?color=blue" alt="npm version">
|
||||
</a>
|
||||
|
||||
<a href="https://bundlephobia.com/result?p=simple-keyboard">
|
||||
<img src="https://badgen.net/bundlephobia/minzip/simple-keyboard/?color=green" alt="install size">
|
||||
<a href="https://github.com/hodgef/simple-keyboard/actions">
|
||||
<img alt="Build Status" src="https://github.com/hodgef/simple-keyboard/workflows/Build/badge.svg?color=green" />
|
||||
</a>
|
||||
|
||||
<a href="https://github.com/hodgef/simple-keyboard/actions">
|
||||
<img alt="Publish Status" src="https://github.com/hodgef/simple-keyboard/workflows/Publish/badge.svg?color=green" />
|
||||
</a>
|
||||
|
||||
<a href="https://travis-ci.org/hodgef/simple-keyboard">
|
||||
<img src="https://api.travis-ci.org/hodgef/simple-keyboard.svg?branch=master"
|
||||
alt="build status">
|
||||
<a href="https://bundlephobia.com/result?p=simple-keyboard">
|
||||
<img src="https://badgen.net/bundlephobia/minzip/simple-keyboard/?color=green" alt="install size">
|
||||
</a>
|
||||
|
||||
<a href="https://david-dm.org/hodgef/simple-keyboard">
|
||||
@@ -38,7 +41,7 @@ Check out the [Getting Started](https://simple-keyboard.com/getting-started) doc
|
||||
## 📖 Documentation
|
||||
Check out the [simple-keyboard documentation](https://simple-keyboard.com/documentation) site.
|
||||
|
||||
Feel free to browse the [Q&A / Use-cases](https://simple-keyboard.com/qa-use-cases/) page for advanced use-cases.
|
||||
Feel free to browse the [Questions & Answers (FAQ)](https://simple-keyboard.com/qa-use-cases/) page for common use-cases.
|
||||
|
||||
|
||||
### To run demo on your own computer
|
||||
@@ -58,6 +61,24 @@ Feel free to browse the [Q&A / Use-cases](https://simple-keyboard.com/qa-use-cas
|
||||
|
||||
<a href="http://franciscohodge.com/simple-keyboard/chat/join" title="Join our Discord chat" target="_blank"><img src="https://franciscohodge.com/project-pages/simple-keyboard/images/discord.png" align="center" width="200"></a>
|
||||
|
||||
## ✳️ Modules
|
||||
|
||||
You can extend simple-keyboard's functionality with [modules](https://franciscohodge.com/projects/simple-keyboard/modules/). Such as:
|
||||
|
||||
* [Autocorrect](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-autocorrect/)
|
||||
* [Input Mask](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-input-mask/)
|
||||
* [Key Navigation](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-key-navigation/)
|
||||
* [Swipe Keyboard](https://franciscohodge.com/projects/simple-keyboard/demo-showcase/module-swipe-keyboard/)
|
||||
|
||||
Want to create your own module? Check out the [Modules page](https://franciscohodge.com/projects/simple-keyboard/modules/) for instructions.
|
||||
|
||||
## 🎯 Compatibility
|
||||
|
||||
> Simple-keyboard is intended for modern, standards-compliant browsers.
|
||||
> Internet Explorer is sadly not one of them, and since its market-share is negligible (~2% for IE11), resources won't be spent in trying to support it.
|
||||
>
|
||||
> To learn more about the rationale for not supporting IE, check out [this link](https://techcommunity.microsoft.com/t5/Windows-IT-Pro-Blog/The-perils-of-using-Internet-Explorer-as-your-default-browser/ba-p/331732).
|
||||
|
||||
## ✅ Contributing
|
||||
|
||||
PR's and issues are welcome. Feel free to submit any issues you have at:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
*
|
||||
* simple-keyboard v2.26.0
|
||||
* simple-keyboard v2.27.1
|
||||
* https://github.com/hodgef/simple-keyboard
|
||||
*
|
||||
* Copyright (c) Francisco Hodge (https://github.com/hodgef)
|
||||
@@ -8,5 +8,5 @@
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* 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-container,.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-row>div:last-child{margin-right:0}.simple-keyboard .hg-row .hg-button-container{display:flex}.simple-keyboard .hg-button{display:inline-block;flex-grow:1;cursor:pointer}.simple-keyboard .hg-button span{pointer-events:none}.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-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-container,.simple-keyboard .hg-row .hg-button:not(:last-child){margin-right:5px}.simple-keyboard .hg-row>div:last-child{margin-right:0}.simple-keyboard .hg-row .hg-button-container{display:flex}.simple-keyboard .hg-button{display:inline-block;flex-grow:1;cursor:pointer}.simple-keyboard .hg-button span{pointer-events:none}.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;-webkit-tap-highlight-color:rgba(0,0,0,0)}.simple-keyboard.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.simple-keyboard button.hg-button{border-width:0;outline:0;font-size:inherit}.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 */
|
||||
File diff suppressed because one or more lines are too long
5
build/index.d.ts
vendored
5
build/index.d.ts
vendored
@@ -178,11 +178,6 @@ declare module 'simple-keyboard' {
|
||||
* Executes the callback function on input change. Returns the input object with all defined inputs.
|
||||
*/
|
||||
onChangeAll?: (inputs: any) => any;
|
||||
|
||||
/**
|
||||
* Executes the callback function on key release.
|
||||
*/
|
||||
onKeyReleased?: () => void;
|
||||
}
|
||||
|
||||
class Keyboard {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -394,6 +394,8 @@ module.exports = function(webpackEnv) {
|
||||
require.resolve('babel-preset-react-app/dependencies'),
|
||||
{ helpers: true },
|
||||
],
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
|
||||
@@ -428,6 +428,8 @@ module.exports = function(webpackEnv) {
|
||||
require.resolve('babel-preset-react-app/dependencies'),
|
||||
{ helpers: true },
|
||||
],
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
|
||||
@@ -1,579 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const isWsl = require('is-wsl');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const resolve = require('resolve');
|
||||
const PnpWebpackPlugin = require('pnp-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const safePostCssParser = require('postcss-safe-parser');
|
||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||
const paths = require('./paths');
|
||||
const modules = require('./modules');
|
||||
const getClientEnvironment = require('./env');
|
||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
|
||||
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const getPackageJson = require('./getPackageJson');
|
||||
|
||||
const postcssNormalize = require('postcss-normalize');
|
||||
|
||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||
const shouldUseSourceMap = false;
|
||||
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
|
||||
// makes for a smoother build process.
|
||||
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
||||
|
||||
// Check if TypeScript is setup
|
||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||
|
||||
// style files regexes
|
||||
const cssRegex = /\.css$/;
|
||||
const cssModuleRegex = /\.module\.css$/;
|
||||
const sassRegex = /\.(scss|sass)$/;
|
||||
const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||
|
||||
const {
|
||||
version,
|
||||
name,
|
||||
license,
|
||||
repository,
|
||||
author,
|
||||
} = getPackageJson('version', 'name', 'license', 'repository', 'author');
|
||||
|
||||
const banner = `
|
||||
${name} v${version} (Non-minified build)
|
||||
${repository.url}
|
||||
|
||||
Copyright (c) ${author.replace(/ *\<[^)]*\> */g, " ")}
|
||||
|
||||
This source code is licensed under the ${license} license found in the
|
||||
LICENSE file in the root directory of this source tree.
|
||||
`;
|
||||
|
||||
// This is the production and development configuration.
|
||||
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
|
||||
module.exports = function(webpackEnv) {
|
||||
const isEnvDevelopment = webpackEnv === 'development';
|
||||
const isEnvProduction = webpackEnv === 'production';
|
||||
|
||||
// Webpack uses `publicPath` to determine where the app is being served from.
|
||||
// It requires a trailing slash, or the file assets will get an incorrect path.
|
||||
// In development, we always serve from the root. This makes config easier.
|
||||
const publicPath = isEnvProduction
|
||||
? paths.servedPath
|
||||
: isEnvDevelopment && '/';
|
||||
// Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
const shouldUseRelativeAssetPaths = publicPath === './';
|
||||
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
|
||||
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||||
const publicUrl = isEnvProduction
|
||||
? publicPath.slice(0, -1)
|
||||
: isEnvDevelopment && '';
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
const loaders = [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: Object.assign(
|
||||
{},
|
||||
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined
|
||||
),
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
options: cssOptions,
|
||||
},
|
||||
{
|
||||
// Options for PostCSS as we reference these options twice
|
||||
// Adds vendor prefixing based on your specified browser support in
|
||||
// package.json
|
||||
loader: require.resolve('postcss-loader'),
|
||||
options: {
|
||||
// Necessary for external CSS imports to work
|
||||
// https://github.com/facebook/create-react-app/issues/2677
|
||||
ident: 'postcss',
|
||||
plugins: () => [
|
||||
require('postcss-flexbugs-fixes'),
|
||||
require('postcss-preset-env')({
|
||||
autoprefixer: {
|
||||
flexbox: 'no-2009',
|
||||
},
|
||||
stage: 3,
|
||||
}),
|
||||
// Adds PostCSS Normalize as the reset css with default options,
|
||||
// so that it honors browserslist config in package.json
|
||||
// which in turn let's users customize the target behavior as per their needs.
|
||||
postcssNormalize(),
|
||||
],
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
},
|
||||
].filter(Boolean);
|
||||
if (preProcessor) {
|
||||
loaders.push({
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
});
|
||||
}
|
||||
return loaders;
|
||||
};
|
||||
|
||||
return {
|
||||
mode: 'production',
|
||||
// Stop compilation early in production
|
||||
bail: true,
|
||||
devtool: false,
|
||||
// These are the "entry points" to our application.
|
||||
// This means they will be the "root" imports that are included in JS bundle.
|
||||
entry: [paths.appLibIndexJs],
|
||||
output: {
|
||||
// The build folder.
|
||||
path: paths.appBuild,
|
||||
// Add /* filename */ comments to generated require()s in the output.
|
||||
pathinfo: isEnvDevelopment,
|
||||
// There will be one main bundle, and one file per asynchronous chunk.
|
||||
// In development, it does not produce real files.
|
||||
filename: 'simple-keyboard.js',
|
||||
// TODO: remove this when upgrading to webpack 5
|
||||
futureEmitAssets: true,
|
||||
// There are also additional JS chunk files if you use code splitting.
|
||||
chunkFilename: 'index.[chunkhash:8].chunk.js',
|
||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||
// We use "/" in development.
|
||||
publicPath: publicPath,
|
||||
library: "SimpleKeyboard",
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||
devtoolModuleFilenameTemplate: info =>
|
||||
path
|
||||
.relative(paths.appSrcLib, info.absoluteResourcePath)
|
||||
.replace(/\\/g, '/'),
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
// we specify a custom UglifyJsPlugin here to get source maps in production
|
||||
new UglifyJsPlugin({
|
||||
cache: false,
|
||||
parallel: false,
|
||||
uglifyOptions: {
|
||||
output: {
|
||||
comments: true,
|
||||
beautify: true,
|
||||
braces: true,
|
||||
indent_level: 2
|
||||
},
|
||||
mangle: false,
|
||||
compress: false
|
||||
},
|
||||
// Use multi-process parallel running to improve the build speed
|
||||
// Default number of concurrent runs: os.cpus().length - 1
|
||||
// Disabled on WSL (Windows Subsystem for Linux) due to an issue with Terser
|
||||
// https://github.com/webpack-contrib/terser-webpack-plugin/issues/21
|
||||
parallel: !isWsl,
|
||||
// Enable file caching
|
||||
cache: true,
|
||||
sourceMap: false,
|
||||
}),
|
||||
new webpack.BannerPlugin({
|
||||
banner: banner,
|
||||
entryOnly: true
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessorOptions: {
|
||||
parser: safePostCssParser,
|
||||
map: shouldUseSourceMap
|
||||
? {
|
||||
// `inline: false` forces the sourcemap to be output into a
|
||||
// separate file
|
||||
inline: false,
|
||||
// `annotation: true` appends the sourceMappingURL to the end of
|
||||
// the css file, helping the browser find the sourcemap
|
||||
annotation: true,
|
||||
}
|
||||
: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
// Automatically split vendor and commons
|
||||
// https://twitter.com/wSokra/status/969633336732905474
|
||||
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
|
||||
splitChunks: {
|
||||
//chunks: 'all',
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
// Keep the runtime chunk separated to enable long term caching
|
||||
// https://twitter.com/wSokra/status/969679223278505985
|
||||
runtimeChunk: false,
|
||||
},
|
||||
resolve: {
|
||||
// This allows you to set a fallback for where Webpack should look for modules.
|
||||
// We placed these paths second because we want `node_modules` to "win"
|
||||
// if there are any conflicts. This matches Node resolution mechanism.
|
||||
// https://github.com/facebook/create-react-app/issues/253
|
||||
modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []),
|
||||
// These are the reasonable defaults supported by the Node ecosystem.
|
||||
// We also include JSX as a common component filename extension to support
|
||||
// some tools, although we do not recommend using it, see:
|
||||
// https://github.com/facebook/create-react-app/issues/290
|
||||
// `web` extension prefixes have been added for better support
|
||||
// for React Native Web.
|
||||
extensions: paths.moduleFileExtensions
|
||||
.map(ext => `.${ext}`)
|
||||
.filter(ext => useTypeScript || !ext.includes('ts')),
|
||||
alias: {
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||
'react-native': 'react-native-web',
|
||||
},
|
||||
plugins: [
|
||||
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
|
||||
// guards against forgotten dependencies and such.
|
||||
PnpWebpackPlugin,
|
||||
// Prevents users from importing files from outside of src/ (or node_modules/).
|
||||
// This often causes confusion because we only process files within src/ with babel.
|
||||
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
|
||||
// please link the files into your node_modules/ and let module-resolution kick in.
|
||||
// Make sure your source files are compiled, as they will not be processed in any way.
|
||||
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [
|
||||
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
|
||||
// from the current package.
|
||||
PnpWebpackPlugin.moduleLoader(module),
|
||||
],
|
||||
},
|
||||
module: {
|
||||
strictExportPresence: true,
|
||||
rules: [
|
||||
// Disable require.ensure as it's not a standard language feature.
|
||||
{ parser: { requireEnsure: false } },
|
||||
|
||||
// First, run the linter.
|
||||
// It's important to do this before Babel processes the JS.
|
||||
{
|
||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||
enforce: 'pre',
|
||||
use: [
|
||||
{
|
||||
options: {
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
|
||||
},
|
||||
loader: require.resolve('eslint-loader'),
|
||||
},
|
||||
],
|
||||
include: paths.appSrcLib,
|
||||
},
|
||||
{
|
||||
// "oneOf" will traverse all following loaders until one will
|
||||
// match the requirements. When no loader matches it will fall
|
||||
// back to the "file" loader at the end of the loader list.
|
||||
oneOf: [
|
||||
// "url" loader works like "file" loader except that it embeds assets
|
||||
// smaller than specified limit in bytes as data URLs to avoid requests.
|
||||
// A missing `test` is equivalent to a match.
|
||||
{
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
// Process application JS with Babel.
|
||||
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
|
||||
{
|
||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||
include: paths.appSrcLib,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
customize: require.resolve(
|
||||
'babel-preset-react-app/webpack-overrides'
|
||||
),
|
||||
|
||||
plugins: [
|
||||
[
|
||||
require.resolve('babel-plugin-named-asset-import'),
|
||||
{
|
||||
loaderMap: {
|
||||
svg: {
|
||||
ReactComponent: '@svgr/webpack?-prettier,-svgo,+ref![path]',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
// This is a feature of `babel-loader` for webpack (not Babel itself).
|
||||
// It enables caching results in ./node_modules/.cache/babel-loader/
|
||||
// directory for faster rebuilds.
|
||||
cacheDirectory: true,
|
||||
cacheCompression: true,
|
||||
compact: true,
|
||||
},
|
||||
},
|
||||
// Process any JS outside of the app with Babel.
|
||||
// Unlike the application JS, we only compile the standard ES features.
|
||||
{
|
||||
test: /\.(js|mjs)$/,
|
||||
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
compact: false,
|
||||
presets: [
|
||||
[
|
||||
require.resolve('babel-preset-react-app/dependencies'),
|
||||
{ helpers: true },
|
||||
],
|
||||
],
|
||||
cacheDirectory: true,
|
||||
cacheCompression: true,
|
||||
|
||||
// If an error happens in a package, it's possible to be
|
||||
// because it was compiled. Thus, we don't want the browser
|
||||
// debugger to show the original code. Instead, the code
|
||||
// being evaluated would be much more helpful.
|
||||
sourceMaps: false,
|
||||
},
|
||||
},
|
||||
// "postcss" loader applies autoprefixer to our CSS.
|
||||
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
||||
// "style" loader turns CSS into JS modules that inject <style> tags.
|
||||
// In production, we use MiniCSSExtractPlugin to extract that CSS
|
||||
// to a file, but in development "style" loader enables hot editing
|
||||
// of CSS.
|
||||
// By default we support CSS Modules with the extension .module.css
|
||||
{
|
||||
test: cssRegex,
|
||||
exclude: cssModuleRegex,
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
}),
|
||||
// Don't consider CSS imports dead code even if the
|
||||
// containing package claims to have no side effects.
|
||||
// Remove this when webpack adds a warning or an error for this.
|
||||
// See https://github.com/webpack/webpack/issues/6571
|
||||
sideEffects: true,
|
||||
},
|
||||
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
|
||||
// using the extension .module.css
|
||||
{
|
||||
test: cssModuleRegex,
|
||||
use: getStyleLoaders({
|
||||
importLoaders: 1,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
}),
|
||||
},
|
||||
// Opt-in support for SASS (using .scss or .sass extensions).
|
||||
// By default we support SASS Modules with the
|
||||
// extensions .module.scss or .module.sass
|
||||
{
|
||||
test: sassRegex,
|
||||
exclude: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
// Don't consider CSS imports dead code even if the
|
||||
// containing package claims to have no side effects.
|
||||
// Remove this when webpack adds a warning or an error for this.
|
||||
// See https://github.com/webpack/webpack/issues/6571
|
||||
sideEffects: true,
|
||||
},
|
||||
// Adds support for CSS Modules, but using SASS
|
||||
// using the extension .module.scss or .module.sass
|
||||
{
|
||||
test: sassModuleRegex,
|
||||
use: getStyleLoaders(
|
||||
{
|
||||
importLoaders: 2,
|
||||
sourceMap: shouldUseSourceMap,
|
||||
modules: true,
|
||||
getLocalIdent: getCSSModuleLocalIdent,
|
||||
},
|
||||
'sass-loader'
|
||||
),
|
||||
},
|
||||
// "file" loader makes sure those assets get served by WebpackDevServer.
|
||||
// When you `import` an asset, you get its (virtual) filename.
|
||||
// In production, they would get copied to the `build` folder.
|
||||
// This loader doesn't use a "test" so it will catch all modules
|
||||
// that fall through the other loaders.
|
||||
{
|
||||
loader: require.resolve('file-loader'),
|
||||
// Exclude `js` files to keep "css" loader working as it injects
|
||||
// its runtime that would otherwise be processed through "file" loader.
|
||||
// Also exclude `html` and `json` extensions so they get processed
|
||||
// by webpacks internal loaders.
|
||||
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
|
||||
options: {
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
// ** STOP ** Are you adding a new loader?
|
||||
// Make sure to add the new loader(s) before the "file" loader.
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Generates an `index.html` file with the <script> injected.
|
||||
/*new HtmlWebpackPlugin(
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
inject: true,
|
||||
template: paths.appHtml,
|
||||
},
|
||||
isEnvProduction
|
||||
? {
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
),*/
|
||||
// Inlines the webpack runtime script. This script is too small to warrant
|
||||
// a network request.
|
||||
shouldInlineRuntimeChunk &&
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
|
||||
// Makes some environment variables available in index.html.
|
||||
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
|
||||
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
// In production, it will be an empty string unless you specify "homepage"
|
||||
// in `package.json`, in which case it will be the pathname of that URL.
|
||||
// In development, this will be an empty string.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
new ModuleNotFoundPlugin(paths.appPath),
|
||||
// Makes some environment variables available to the JS code, for example:
|
||||
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
|
||||
// It is absolutely essential that NODE_ENV is set to production
|
||||
// during a production build.
|
||||
// Otherwise React will be compiled in the very slow development mode.
|
||||
new webpack.DefinePlugin(env.stringified),
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
// both options are optional
|
||||
filename: 'css/simple-keyboard.css',
|
||||
chunkFilename: 'css/index.[contenthash:8].chunk.css',
|
||||
}),
|
||||
// Generate a manifest file which contains a mapping of all asset filenames
|
||||
// to their corresponding output file so that tools can pick it up without
|
||||
// having to parse `index.html`.
|
||||
/*new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
generate: (seed, files) => {
|
||||
const manifestFiles = files.reduce(function(manifest, file) {
|
||||
manifest[file.name] = file.path;
|
||||
return manifest;
|
||||
}, seed);
|
||||
|
||||
return {
|
||||
files: manifestFiles,
|
||||
};
|
||||
},
|
||||
}),*/
|
||||
// Moment.js is an extremely popular library that bundles large locale files
|
||||
// by default due to how Webpack interprets its code. This is a practical
|
||||
// solution that requires the user to opt into importing specific locales.
|
||||
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
|
||||
// You can remove this if you don't use Moment.js:
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Generate a service worker script that will precache, and keep up to date,
|
||||
// the HTML & assets that are part of the Webpack build.
|
||||
/*isEnvProduction &&
|
||||
new WorkboxWebpackPlugin.GenerateSW({
|
||||
clientsClaim: true,
|
||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
||||
importWorkboxFrom: 'cdn',
|
||||
navigateFallback: publicUrl + '/index.html',
|
||||
navigateFallbackBlacklist: [
|
||||
// Exclude URLs starting with /_, as they're likely an API call
|
||||
new RegExp('^/_'),
|
||||
// Exclude URLs containing a dot, as they're likely a resource in
|
||||
// public/ and not a SPA route
|
||||
new RegExp('/[^/]+\\.[^/]+$'),
|
||||
],
|
||||
}),*/
|
||||
// TypeScript type checking
|
||||
useTypeScript &&
|
||||
new ForkTsCheckerWebpackPlugin({
|
||||
typescript: resolve.sync('typescript', {
|
||||
basedir: paths.appNodeModules,
|
||||
}),
|
||||
async: false,
|
||||
useTypescriptIncrementalApi: true,
|
||||
checkSyntacticErrors: true,
|
||||
tsconfig: paths.appTsConfig,
|
||||
reportFiles: [
|
||||
'**',
|
||||
'!**/__tests__/**',
|
||||
'!**/?(*.)(spec|test).*',
|
||||
'!**/src/setupProxy.*',
|
||||
'!**/src/setupTests.*',
|
||||
],
|
||||
watch: paths.appSrcLib,
|
||||
silent: true,
|
||||
// The formatter is invoked directly in WebpackDevServerUtils during development
|
||||
formatter: isEnvProduction ? typescriptFormatter : undefined,
|
||||
}),
|
||||
].filter(Boolean),
|
||||
// Some libraries import Node modules but don't use them in the browser.
|
||||
// Tell Webpack to provide empty mocks for them so importing them works.
|
||||
node: {
|
||||
module: 'empty',
|
||||
dgram: 'empty',
|
||||
dns: 'mock',
|
||||
fs: 'empty',
|
||||
http2: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
child_process: 'empty',
|
||||
},
|
||||
// Turn off performance processing because we utilize
|
||||
// our own hints via the FileSizeReporter
|
||||
performance: false,
|
||||
};
|
||||
};
|
||||
3007
package-lock.json
generated
3007
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-keyboard",
|
||||
"version": "2.26.0",
|
||||
"version": "2.27.1",
|
||||
"description": "On-screen Javascript Virtual Keyboard",
|
||||
"main": "build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
@@ -10,7 +10,8 @@
|
||||
"demo": "node scripts/demo.js",
|
||||
"test": "node scripts/test.js",
|
||||
"coverage": "node scripts/test.js --coverage --watchAll=false",
|
||||
"prepare": "npm run build"
|
||||
"prepare": "npm run build",
|
||||
"trypublish": "npm publish || true"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -39,65 +40,67 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.5.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.4.4",
|
||||
"@svgr/webpack": "4.3.2",
|
||||
"@babel/core": "7.7.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.0",
|
||||
"@babel/preset-env": "^7.7.1",
|
||||
"@babel/preset-react": "^7.7.0",
|
||||
"@svgr/webpack": "4.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "1.13.0",
|
||||
"@typescript-eslint/parser": "1.13.0",
|
||||
"babel-eslint": "10.0.2",
|
||||
"babel-eslint": "10.0.3",
|
||||
"babel-jest": "^24.8.0",
|
||||
"babel-loader": "8.0.6",
|
||||
"babel-plugin-named-asset-import": "^0.3.3",
|
||||
"babel-preset-react-app": "^9.0.1",
|
||||
"camelcase": "^5.2.0",
|
||||
"case-sensitive-paths-webpack-plugin": "2.2.0",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"css-loader": "2.1.1",
|
||||
"dotenv": "6.2.0",
|
||||
"dotenv-expand": "4.2.0",
|
||||
"eslint": "^6.1.0",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"css-loader": "3.2.0",
|
||||
"dotenv": "8.2.0",
|
||||
"dotenv-expand": "5.1.0",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-react-app": "^5.0.1",
|
||||
"eslint-loader": "2.2.1",
|
||||
"eslint-loader": "3.0.2",
|
||||
"eslint-plugin-flowtype": "3.13.0",
|
||||
"eslint-plugin-import": "2.18.2",
|
||||
"eslint-plugin-jsx-a11y": "6.2.3",
|
||||
"eslint-plugin-react": "7.14.3",
|
||||
"eslint-plugin-react-hooks": "^1.6.1",
|
||||
"file-loader": "3.0.1",
|
||||
"fs-extra": "7.0.1",
|
||||
"html-webpack-plugin": "4.0.0-beta.5",
|
||||
"eslint-plugin-react": "7.16.0",
|
||||
"eslint-plugin-react-hooks": "^2.2.0",
|
||||
"file-loader": "4.2.0",
|
||||
"fs-extra": "8.1.0",
|
||||
"html-webpack-plugin": "4.0.0-beta.8",
|
||||
"identity-obj-proxy": "3.0.0",
|
||||
"is-wsl": "^1.1.0",
|
||||
"jest": "24.8.0",
|
||||
"is-wsl": "^2.1.0",
|
||||
"jest": "24.9.0",
|
||||
"jest-environment-jsdom-fourteen": "0.1.0",
|
||||
"jest-resolve": "24.9.0",
|
||||
"jest-watch-typeahead": "0.3.1",
|
||||
"mini-css-extract-plugin": "0.5.0",
|
||||
"jest-watch-typeahead": "0.4.0",
|
||||
"mini-css-extract-plugin": "0.8.0",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.3",
|
||||
"pnp-webpack-plugin": "1.5.0",
|
||||
"prettier": "^1.17.0",
|
||||
"prettier-webpack-plugin": "^1.2.0",
|
||||
"postcss-flexbugs-fixes": "4.1.0",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-normalize": "7.0.1",
|
||||
"postcss-normalize": "8.0.1",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"postcss-safe-parser": "4.0.1",
|
||||
"react": "^16.9.0",
|
||||
"react": "^16.11.0",
|
||||
"react-app-polyfill": "^1.0.2",
|
||||
"react-dev-utils": "^9.0.3",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-dom": "^16.11.0",
|
||||
"resolve": "1.12.0",
|
||||
"resolve-url-loader": "3.1.0",
|
||||
"sass-loader": "7.2.0",
|
||||
"sass-loader": "7.3.1",
|
||||
"semver": "6.3.0",
|
||||
"style-loader": "1.0.0",
|
||||
"terser-webpack-plugin": "1.4.1",
|
||||
"ts-pnp": "1.1.2",
|
||||
"terser-webpack-plugin": "2.2.1",
|
||||
"ts-pnp": "1.1.4",
|
||||
"uglifyjs-webpack-plugin": "^2.1.2",
|
||||
"url-loader": "2.1.0",
|
||||
"webpack": "4.39.1",
|
||||
"webpack-dev-server": "3.2.1",
|
||||
"webpack-manifest-plugin": "2.0.4",
|
||||
"url-loader": "2.2.0",
|
||||
"webpack": "4.41.2",
|
||||
"webpack-dev-server": "3.9.0",
|
||||
"webpack-manifest-plugin": "2.2.0",
|
||||
"workbox-webpack-plugin": "4.3.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
@@ -170,7 +173,8 @@
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"react-app"
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
|
||||
@@ -106,8 +106,8 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
throw new Error('Failed to compile');
|
||||
process.exit(1);
|
||||
}
|
||||
)
|
||||
|
||||
@@ -106,8 +106,8 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
throw new Error('Failed to compile');
|
||||
process.exit(1);
|
||||
}
|
||||
)
|
||||
|
||||
@@ -139,6 +139,8 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
stats = stats.toJson();
|
||||
|
||||
if (stats.errors && stats.errors.length > 0) {
|
||||
devServer.close();
|
||||
process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
75
src/demo/MultipleKeyboardsDestroyDemo.js
Normal file
75
src/demo/MultipleKeyboardsDestroyDemo.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import Keyboard from "../lib";
|
||||
import "./css/MultipleKeyboardsDestroyDemo.css";
|
||||
|
||||
const setDOM = () => {
|
||||
document.querySelector("#root").innerHTML = `
|
||||
<input class="input" placeholder="Tap on the virtual keyboard to start" />
|
||||
<div class="simple-keyboard"></div>
|
||||
|
||||
<input class="input2" placeholder="Tap on the virtual keyboard to start" />
|
||||
<div class="keyboard2"></div>
|
||||
`;
|
||||
};
|
||||
|
||||
class Demo {
|
||||
constructor() {
|
||||
setDOM();
|
||||
|
||||
/**
|
||||
* Demo Start
|
||||
*/
|
||||
this.keyboard = new Keyboard({
|
||||
onChange: input => this.onChange(input),
|
||||
onKeyPress: button => this.onKeyPress(button),
|
||||
debug: true
|
||||
});
|
||||
|
||||
this.keyboard2 = new Keyboard(".keyboard2", {
|
||||
theme: "simple-keyboard hg-theme-default",
|
||||
onChange: input => this.onChange(input, "input2"),
|
||||
onKeyPress: button => this.onKeyPress(button, "keyboard2"),
|
||||
debug: true
|
||||
});
|
||||
|
||||
console.log(this.keyboard);
|
||||
setTimeout(this.keyboard.destroy, 10000);
|
||||
|
||||
/**
|
||||
* Update simple-keyboard when input is changed directly
|
||||
*/
|
||||
document.querySelector(".input").addEventListener("input", event => {
|
||||
this.keyboard.setInput(event.target.value);
|
||||
});
|
||||
|
||||
document.querySelector(".input2").addEventListener("input", event => {
|
||||
this.keyboard2.setInput(event.target.value);
|
||||
});
|
||||
}
|
||||
|
||||
onChange(input, inputClass) {
|
||||
document.querySelector(`.${inputClass || "input"}`).value = input;
|
||||
console.log("Input changed", input);
|
||||
}
|
||||
|
||||
onKeyPress(button, keyboardInstanceKey) {
|
||||
console.log("Button pressed", button);
|
||||
|
||||
/**
|
||||
* If you want to handle the shift and caps lock buttons
|
||||
*/
|
||||
if (button === "{shift}" || button === "{lock}")
|
||||
this.handleShift(keyboardInstanceKey);
|
||||
}
|
||||
|
||||
handleShift(keyboardInstanceKey) {
|
||||
let keyboard = this[keyboardInstanceKey || "keyboard"];
|
||||
let currentLayout = keyboard.options.layoutName;
|
||||
let shiftToggle = currentLayout === "default" ? "shift" : "default";
|
||||
|
||||
keyboard.setOptions({
|
||||
layoutName: shiftToggle
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Demo;
|
||||
12
src/demo/css/MultipleKeyboardsDestroyDemo.css
Normal file
12
src/demo/css/MultipleKeyboardsDestroyDemo.css
Normal file
@@ -0,0 +1,12 @@
|
||||
input {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
padding: 20px;
|
||||
font-size: 20px;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.simple-keyboard {
|
||||
max-width: 850px;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import "./css/index.css";
|
||||
import BasicDemo from "./BasicDemo";
|
||||
//import FullKeyboardDemo from "./FullKeyboardDemo";
|
||||
//import ButtonThemeDemo from "./ButtonThemeDemo";
|
||||
//import MultipleKeyboardsDemo from "./MultipleKeyboardsDestroyDemo";
|
||||
|
||||
/**
|
||||
* Selected demo
|
||||
|
||||
67
src/demo/tests/MultipleKeyboardsDestroyDemo.test.js
Normal file
67
src/demo/tests/MultipleKeyboardsDestroyDemo.test.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import TestUtility from '../../utils/TestUtility';
|
||||
import MultipleKeyboardsDestroyDemo from '../MultipleKeyboardsDestroyDemo';
|
||||
|
||||
let testUtil = new TestUtility();
|
||||
|
||||
it('Demo will load', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
});
|
||||
|
||||
it('Demo onDOMLoaded will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
expect(demo.keyboard).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
demo.onChange("test");
|
||||
demo.keyboard2.getButtonElement("q").click();
|
||||
|
||||
expect(document.body.querySelector('.input').value).toBe("test");
|
||||
expect(document.body.querySelector('.input2').value).toBe("q");
|
||||
});
|
||||
|
||||
it('Demo onChange will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
demo.keyboard.getButtonElement("q").onclick();
|
||||
|
||||
expect(document.body.querySelector('.input').value).toBe("q");
|
||||
});
|
||||
|
||||
it('Demo input change will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
document.body.querySelector('.input').value = "test";
|
||||
document.body.querySelector('.input').dispatchEvent(new Event('input'));
|
||||
|
||||
document.body.querySelector('.input2').value = "test2";
|
||||
document.body.querySelector('.input2').dispatchEvent(new Event('input'));
|
||||
|
||||
expect(demo.keyboard.getInput()).toBe("test");
|
||||
expect(demo.keyboard2.getInput()).toBe("test2");
|
||||
});
|
||||
|
||||
it('Demo handleShiftButton will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let demo = new MultipleKeyboardsDestroyDemo();
|
||||
|
||||
demo.keyboard.getButtonElement("{shift}")[0].onclick();
|
||||
expect(demo.keyboard.options.layoutName).toBe("shift");
|
||||
|
||||
demo.keyboard.getButtonElement("{shift}")[0].onclick();
|
||||
expect(demo.keyboard.options.layoutName).toBe("default");
|
||||
});
|
||||
5
src/lib/@types/index.d.ts
vendored
5
src/lib/@types/index.d.ts
vendored
@@ -178,11 +178,6 @@ declare module 'simple-keyboard' {
|
||||
* Executes the callback function on input change. Returns the input object with all defined inputs.
|
||||
*/
|
||||
onChangeAll?: (inputs: any) => any;
|
||||
|
||||
/**
|
||||
* Executes the callback function on key release.
|
||||
*/
|
||||
onKeyReleased?: () => void;
|
||||
}
|
||||
|
||||
class Keyboard {
|
||||
|
||||
@@ -69,6 +69,11 @@ html {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.simple-keyboard.hg-theme-default .hg-button.hg-activeButton {
|
||||
background: #efefef;
|
||||
}
|
||||
|
||||
/* When using option "useButtonTag" */
|
||||
|
||||
@@ -129,15 +129,13 @@ class SimpleKeyboard {
|
||||
if (!window["SimpleKeyboardInstances"])
|
||||
window["SimpleKeyboardInstances"] = {};
|
||||
|
||||
window["SimpleKeyboardInstances"][
|
||||
this.utilities.camelCase(this.keyboardDOMClass)
|
||||
] = this;
|
||||
this.currentInstanceName = this.utilities.camelCase(this.keyboardDOMClass);
|
||||
window["SimpleKeyboardInstances"][this.currentInstanceName] = this;
|
||||
|
||||
/**
|
||||
* Instance vars
|
||||
*/
|
||||
this.allKeyboardInstances = window["SimpleKeyboardInstances"];
|
||||
this.currentInstanceName = this.utilities.camelCase(this.keyboardDOMClass);
|
||||
this.keyboardInstanceNames = Object.keys(window["SimpleKeyboardInstances"]);
|
||||
this.isFirstKeyboardInstance =
|
||||
this.keyboardInstanceNames[0] === this.currentInstanceName;
|
||||
@@ -230,7 +228,7 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
*/
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input);
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
|
||||
|
||||
/**
|
||||
* Calling onChange
|
||||
@@ -261,6 +259,11 @@ class SimpleKeyboard {
|
||||
if (this.options.preventMouseDownDefault) e.preventDefault();
|
||||
if (this.options.stopMouseDownPropagation) e.stopPropagation();
|
||||
|
||||
/**
|
||||
* Add active class
|
||||
*/
|
||||
if (e) e.target.classList.add(this.activeButtonClass);
|
||||
|
||||
/**
|
||||
* @type {boolean} Whether the mouse is being held onKeyPress
|
||||
*/
|
||||
@@ -297,6 +300,13 @@ class SimpleKeyboard {
|
||||
* Handles button mouseup
|
||||
*/
|
||||
handleButtonMouseUp(button) {
|
||||
/**
|
||||
* Remove active class
|
||||
*/
|
||||
this.recurseButtons(buttonElement => {
|
||||
buttonElement.classList.remove(this.activeButtonClass);
|
||||
});
|
||||
|
||||
this.isMouseHold = false;
|
||||
if (this.holdInteractionTimeout) clearTimeout(this.holdInteractionTimeout);
|
||||
|
||||
@@ -307,6 +317,16 @@ class SimpleKeyboard {
|
||||
this.options.onKeyReleased(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles container mousedown
|
||||
*/
|
||||
handleKeyboardContainerMouseDown(e) {
|
||||
/**
|
||||
* Handle event options
|
||||
*/
|
||||
if (this.options.preventMouseDownDefault) e.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles button hold
|
||||
*/
|
||||
@@ -353,7 +373,7 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
*/
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input);
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,7 +386,7 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
*/
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input);
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
|
||||
|
||||
return this.input[inputName];
|
||||
}
|
||||
@@ -383,7 +403,7 @@ class SimpleKeyboard {
|
||||
/**
|
||||
* Enforce syncInstanceInputs, if set
|
||||
*/
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs(this.input);
|
||||
if (this.options.syncInstanceInputs) this.syncInstanceInputs();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -432,7 +452,7 @@ class SimpleKeyboard {
|
||||
|
||||
/**
|
||||
* Remove all keyboard rows and reset keyboard values.
|
||||
* Used interally between re-renders.
|
||||
* Used internally between re-renders.
|
||||
*/
|
||||
clear() {
|
||||
this.keyboardDOM.innerHTML = "";
|
||||
@@ -713,22 +733,77 @@ class SimpleKeyboard {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an operation on each button
|
||||
*/
|
||||
recurseButtons(fn) {
|
||||
if (!fn) return false;
|
||||
|
||||
Object.keys(this.buttonElements).forEach(buttonName =>
|
||||
this.buttonElements[buttonName].forEach(fn)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy keyboard listeners and DOM elements
|
||||
*/
|
||||
destroy() {
|
||||
if (this.options.debug)
|
||||
console.log(
|
||||
`Destroying simple-keyboard instance: ${this.currentInstanceName}`
|
||||
);
|
||||
|
||||
/**
|
||||
* Remove listeners
|
||||
* Remove document listeners
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Clear DOM
|
||||
* Remove buttons
|
||||
*/
|
||||
this.clear();
|
||||
let deleteButton = buttonElement => {
|
||||
buttonElement.onpointerdown = null;
|
||||
buttonElement.onpointerup = null;
|
||||
buttonElement.onpointercancel = null;
|
||||
buttonElement.ontouchstart = null;
|
||||
buttonElement.ontouchend = null;
|
||||
buttonElement.ontouchcancel = null;
|
||||
buttonElement.onclick = null;
|
||||
buttonElement.onmousedown = null;
|
||||
buttonElement.onmouseup = null;
|
||||
|
||||
buttonElement.remove();
|
||||
buttonElement = null;
|
||||
};
|
||||
|
||||
this.recurseButtons(deleteButton);
|
||||
|
||||
this.buttonElements = null;
|
||||
this.recurseButtons = null;
|
||||
deleteButton = null;
|
||||
|
||||
/**
|
||||
* Remove wrapper events
|
||||
*/
|
||||
this.keyboardDOM.onpointerdown = null;
|
||||
this.keyboardDOM.ontouchstart = null;
|
||||
this.keyboardDOM.onmousedown = null;
|
||||
|
||||
this.keyboardDOM.remove();
|
||||
this.keyboardDOM = null;
|
||||
|
||||
/**
|
||||
* Remove instance
|
||||
*/
|
||||
window["SimpleKeyboardInstances"][this.currentInstanceName] = null;
|
||||
delete window["SimpleKeyboardInstances"][this.currentInstanceName];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1166,6 +1241,8 @@ class SimpleKeyboard {
|
||||
buttonDOM.setAttribute(attribute, value);
|
||||
});
|
||||
|
||||
this.activeButtonClass = "hg-activeButton";
|
||||
|
||||
/**
|
||||
* Handle button click event
|
||||
*/
|
||||
@@ -1182,8 +1259,12 @@ class SimpleKeyboard {
|
||||
this.handleButtonClicked(button);
|
||||
this.handleButtonMouseDown(button, e);
|
||||
};
|
||||
buttonDOM.onpointerup = () => this.handleButtonMouseUp(button);
|
||||
buttonDOM.onpointercancel = () => this.handleButtonMouseUp(button);
|
||||
buttonDOM.onpointerup = () => {
|
||||
this.handleButtonMouseUp(button);
|
||||
};
|
||||
buttonDOM.onpointercancel = () => {
|
||||
this.handleButtonMouseUp(button);
|
||||
};
|
||||
} else {
|
||||
/**
|
||||
* Fallback for browsers not supporting PointerEvents
|
||||
@@ -1196,8 +1277,12 @@ class SimpleKeyboard {
|
||||
this.handleButtonClicked(button);
|
||||
this.handleButtonMouseDown(button, e);
|
||||
};
|
||||
buttonDOM.ontouchend = () => this.handleButtonMouseUp(button);
|
||||
buttonDOM.ontouchcancel = () => this.handleButtonMouseUp(button);
|
||||
buttonDOM.ontouchend = () => {
|
||||
this.handleButtonMouseUp(button);
|
||||
};
|
||||
buttonDOM.ontouchcancel = () => {
|
||||
this.handleButtonMouseUp(button);
|
||||
};
|
||||
} else {
|
||||
/**
|
||||
* Handle mouse events
|
||||
@@ -1206,8 +1291,12 @@ class SimpleKeyboard {
|
||||
this.isMouseHold = false;
|
||||
this.handleButtonClicked(button);
|
||||
};
|
||||
buttonDOM.onmousedown = e => this.handleButtonMouseDown(button, e);
|
||||
buttonDOM.onmouseup = () => this.handleButtonMouseUp(button);
|
||||
buttonDOM.onmousedown = e => {
|
||||
this.handleButtonMouseDown(button, e);
|
||||
};
|
||||
buttonDOM.onmouseup = () => {
|
||||
this.handleButtonMouseUp(button);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1271,7 +1360,7 @@ class SimpleKeyboard {
|
||||
this.initialized = true;
|
||||
|
||||
/**
|
||||
* Handling onpointerup
|
||||
* Handling parent events
|
||||
*/
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
@@ -1280,17 +1369,24 @@ class SimpleKeyboard {
|
||||
!useMouseEvents
|
||||
) {
|
||||
document.onpointerup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onpointerdown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (useTouchEvents) {
|
||||
/**
|
||||
* Handling ontouchend, ontouchcancel
|
||||
*/
|
||||
document.ontouchend = () => this.handleButtonMouseUp();
|
||||
document.ontouchcancel = () => this.handleButtonMouseUp();
|
||||
|
||||
this.keyboardDOM.ontouchstart = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
} else if (!useTouchEvents) {
|
||||
/**
|
||||
* Handling mouseup
|
||||
*/
|
||||
document.onmouseup = () => this.handleButtonMouseUp();
|
||||
this.keyboardDOM.onmousedown = e =>
|
||||
this.handleKeyboardContainerMouseDown(e);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1228,10 +1228,16 @@ it('Keyboard destroy will work', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let keyboard = new Keyboard();
|
||||
|
||||
keyboard.destroy();
|
||||
expect(keyboard.keyboardDOM).toBe(null);
|
||||
});
|
||||
|
||||
expect(keyboard.keyboardDOM.innerHTML).toBeFalsy();
|
||||
it('Keyboard destroy will work with debug option', () => {
|
||||
testUtil.setDOM();
|
||||
|
||||
let keyboard = new Keyboard({ debug: true });
|
||||
keyboard.destroy();
|
||||
expect(keyboard.keyboardDOM).toBe(null);
|
||||
});
|
||||
|
||||
it('Keyboard disableButtonHold will work', () => {
|
||||
@@ -1325,4 +1331,10 @@ it('Keyboard buttonAttribute will warn about invalid entries', () => {
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Keyboard recurseButtons will not work without a valid param', () => {
|
||||
testUtil.setDOM();
|
||||
let keyboard = new Keyboard();
|
||||
expect(keyboard.recurseButtons()).toBe(false);
|
||||
});
|
||||
|
||||
@@ -304,7 +304,7 @@ class Utilities {
|
||||
let options = this.getOptions();
|
||||
let maxLength = options.maxLength;
|
||||
let currentInput = inputObj[options.inputName];
|
||||
let condition = currentInput.length === maxLength;
|
||||
let condition = updatedInput.length - 1 >= maxLength;
|
||||
|
||||
if (
|
||||
/**
|
||||
@@ -376,6 +376,7 @@ class Utilities {
|
||||
*/
|
||||
|
||||
static bindMethods(myClass, instance) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for (let myMethod of Object.getOwnPropertyNames(myClass.prototype)) {
|
||||
let excludeMethod =
|
||||
myMethod === "constructor" || myMethod === "bindMethods";
|
||||
|
||||
@@ -379,7 +379,7 @@ it('Keyboard handleMaxLength will work with numeric maxLength', () => {
|
||||
|
||||
let output = keyboard.utilities.handleMaxLength(keyboard.input, "testq");
|
||||
|
||||
expect(output).toBeFalsy();
|
||||
expect(output).toBe(true);
|
||||
});
|
||||
|
||||
it('Keyboard handleMaxLength wont work with non numeric or object maxLength', () => {
|
||||
@@ -490,4 +490,4 @@ it('Keyboard camelCase will work with empty strings', () => {
|
||||
testUtil.setDOM();
|
||||
let keyboard = new Keyboard();
|
||||
expect(keyboard.utilities.camelCase()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user