mirror of
https://github.com/hodgef/simple-keyboard.git
synced 2026-02-03 00:06:50 +08:00
Compare commits
269 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 | ||
|
|
d186fb1e09 | ||
|
|
29677485a9 | ||
|
|
37ade80dd6 | ||
|
|
eab88f7de3 | ||
|
|
26e6747b0f | ||
|
|
88c462ddf3 | ||
|
|
5452367733 | ||
|
|
bdbf82828d | ||
|
|
e4b3622291 | ||
|
|
181dd240a0 | ||
|
|
628d27cf18 | ||
|
|
de8dd3f204 | ||
|
|
c696606b11 | ||
|
|
9e17a1e0df | ||
|
|
d1c9a0ead7 | ||
|
|
b054ee45a3 | ||
|
|
c459ab60c1 | ||
|
|
f2c690e010 | ||
|
|
e567c3f19b | ||
|
|
e6f8f47975 | ||
|
|
f251e6ee35 | ||
|
|
2113229d61 | ||
|
|
460633a00d | ||
|
|
16f26bd6d9 | ||
|
|
5239521964 |
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}}
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,6 +17,7 @@
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.vscode
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
|
||||
69
README.md
69
README.md
@@ -1,14 +1,37 @@
|
||||
<div align="center">
|
||||
<a href="https://simple-keyboard.com/demo" title="View Demo" target="_blank"><img src="https://franciscohodge.com/project-pages/simple-keyboard/images/simplekeyboard-banner_B.png" align="center" width="100%"></a>
|
||||
<a href="https://simple-keyboard.com/demo" title="View Demo" target="_blank"><img src="https://franciscohodge.com/project-pages/simple-keyboard/images/skdemo-4x2.gif" align="center" width="100%"></a>
|
||||
<blockquote>The easily customisable and responsive on-screen virtual keyboard for Javascript projects.</blockquote>
|
||||
<a href="https://www.npmjs.com/package/simple-keyboard" target="_blank"><img src="https://img.shields.io/npm/v/simple-keyboard.svg?style=flat" alt="npm version"></a>
|
||||
<a href="https://travis-ci.org/hodgef/simple-keyboard" target="_blank"><img src="https://travis-ci.org/hodgef/simple-keyboard.svg?branch=master" alt="Build Status"></a>
|
||||
<img src="https://img.shields.io/david/hodgef/js-library-boilerplate.svg" />
|
||||
<a href="https://codecov.io/gh/hodgef/simple-keyboard" target="_blank"><img src="https://img.shields.io/codecov/c/github/hodgef/simple-keyboard/master.svg?style=flat" alt="Coverage Status"></a>
|
||||
<a href="https://www.codacy.com/app/hodgef/simple-keyboard?utm_source=github.com&utm_medium=referral&utm_content=hodgef/simple-keyboard&utm_campaign=Badge_Grade" target="_blank"><img src="https://api.codacy.com/project/badge/Grade/5778fccc6a894701853d9a1f2fb44a76" alt="Codacy Badge"></a>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<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://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://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">
|
||||
<img src="https://badgen.net/david/dep/hodgef/simple-keyboard" alt="coverage">
|
||||
</a>
|
||||
|
||||
<a href="https://codecov.io/gh/hodgef/simple-keyboard">
|
||||
<img src="https://badgen.net/codecov/c/github/hodgef/simple-keyboard" alt="coverage">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
> The slick virtual keyboard for Javascript. Compatible with your JS, React, Angular or Vue projects.
|
||||
|
||||
## 🚀 Demo
|
||||
[Demo Showcase (Vanilla, Angular, React, Vue)](https://simple-keyboard.com/demo)
|
||||
|
||||
## 📦 Installation & Usage
|
||||
You can use simple-keyboard as a `<script>` tag from a CDN, or install it from npm.
|
||||
@@ -18,11 +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.
|
||||
|
||||
## 🚀 Demo
|
||||
|
||||
[https://simple-keyboard.com/demo](https://simple-keyboard.com/demo)
|
||||
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
|
||||
@@ -42,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,10 +0,0 @@
|
||||
console.log('\x1b[36m%s\x1b[0m', `
|
||||
______________________________________\n`);
|
||||
|
||||
console.log('\x1b[33m%s\x1b[0m', `Thank you for installing simple-keyboard !`);
|
||||
|
||||
console.log('\x1b[36m%s\x1b[0m', `
|
||||
Please consider starring the repository so others can also find it.
|
||||
https://github.com/hodgef/simple-keyboard/stargazers
|
||||
______________________________________
|
||||
`);
|
||||
@@ -1,6 +1,6 @@
|
||||
/*!
|
||||
*
|
||||
* simple-keyboard v2.25.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
@@ -1,11 +0,0 @@
|
||||
/*!
|
||||
*
|
||||
* simple-keyboard v2.25.0 (Non-minified build)
|
||||
* https://github.com/hodgef/simple-keyboard
|
||||
*
|
||||
* Copyright (c) Francisco Hodge (https://github.com/hodgef)
|
||||
*
|
||||
* 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}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const camelcase = require('camelcase');
|
||||
|
||||
// This is a custom Jest transformer turning file imports into filenames.
|
||||
// http://facebook.github.io/jest/docs/en/webpack.html
|
||||
@@ -10,19 +11,27 @@ module.exports = {
|
||||
const assetFilename = JSON.stringify(path.basename(filename));
|
||||
|
||||
if (filename.match(/\.svg$/)) {
|
||||
// Based on how SVGR generates a component name:
|
||||
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
|
||||
const pascalCaseFileName = camelcase(path.parse(filename).name, {
|
||||
pascalCase: true,
|
||||
});
|
||||
const componentName = `Svg${pascalCaseFileName}`;
|
||||
return `const React = require('react');
|
||||
module.exports = {
|
||||
__esModule: true,
|
||||
default: ${assetFilename},
|
||||
ReactComponent: React.forwardRef((props, ref) => ({
|
||||
$$typeof: Symbol.for('react.element'),
|
||||
type: 'svg',
|
||||
ref: ref,
|
||||
key: null,
|
||||
props: Object.assign({}, props, {
|
||||
children: ${assetFilename}
|
||||
})
|
||||
})),
|
||||
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
|
||||
return {
|
||||
$$typeof: Symbol.for('react.element'),
|
||||
type: 'svg',
|
||||
ref: ref,
|
||||
key: null,
|
||||
props: Object.assign({}, props, {
|
||||
children: ${assetFilename}
|
||||
})
|
||||
};
|
||||
}),
|
||||
};`;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
const chalk = require('react-dev-utils/chalk');
|
||||
const resolve = require('resolve');
|
||||
|
||||
/**
|
||||
* Get the baseUrl of a compilerOptions object.
|
||||
@@ -63,7 +64,10 @@ function getModules() {
|
||||
// TypeScript project and set up the config
|
||||
// based on tsconfig.json
|
||||
if (hasTsConfig) {
|
||||
config = require(paths.appTsConfig);
|
||||
const ts = require(resolve.sync('typescript', {
|
||||
basedir: paths.appNodeModules,
|
||||
}));
|
||||
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
|
||||
// Otherwise we'll check if there is jsconfig.json
|
||||
// for non TS projects.
|
||||
} else if (hasJsConfig) {
|
||||
|
||||
35
config/pnpTs.js
Normal file
35
config/pnpTs.js
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
const { resolveModuleName } = require('ts-pnp');
|
||||
|
||||
exports.resolveModuleName = (
|
||||
typescript,
|
||||
moduleName,
|
||||
containingFile,
|
||||
compilerOptions,
|
||||
resolutionHost
|
||||
) => {
|
||||
return resolveModuleName(
|
||||
moduleName,
|
||||
containingFile,
|
||||
compilerOptions,
|
||||
resolutionHost,
|
||||
typescript.resolveModuleName
|
||||
);
|
||||
};
|
||||
|
||||
exports.resolveTypeReferenceDirective = (
|
||||
typescript,
|
||||
moduleName,
|
||||
containingFile,
|
||||
compilerOptions,
|
||||
resolutionHost
|
||||
) => {
|
||||
return resolveModuleName(
|
||||
moduleName,
|
||||
containingFile,
|
||||
compilerOptions,
|
||||
resolutionHost,
|
||||
typescript.resolveTypeReferenceDirective
|
||||
);
|
||||
};
|
||||
@@ -25,15 +25,23 @@ 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 getPackageJson = require('./getPackageJson');
|
||||
const eslint = require('eslint');
|
||||
|
||||
const postcssNormalize = require('postcss-normalize');
|
||||
|
||||
const appPackageJson = require(paths.appPackageJson);
|
||||
|
||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== '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';
|
||||
|
||||
const imageInlineSizeLimit = parseInt(
|
||||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||
);
|
||||
|
||||
// Check if TypeScript is setup
|
||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||
|
||||
@@ -46,6 +54,7 @@ const sassModuleRegex = /\.module\.(scss|sass)$/;
|
||||
// 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.
|
||||
@@ -66,12 +75,10 @@ module.exports = function(webpackEnv) {
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
const loaders = [
|
||||
isEnvDevelopment && require.resolve('style-loader'),
|
||||
isEnvProduction && {
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: Object.assign(
|
||||
{},
|
||||
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined
|
||||
),
|
||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
@@ -104,12 +111,20 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
].filter(Boolean);
|
||||
if (preProcessor) {
|
||||
loaders.push({
|
||||
loader: require.resolve(preProcessor),
|
||||
loaders.push(
|
||||
{
|
||||
loader: require.resolve('resolve-url-loader'),
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return loaders;
|
||||
};
|
||||
@@ -118,10 +133,26 @@ module.exports = function(webpackEnv) {
|
||||
mode: 'production',
|
||||
// Stop compilation early in production
|
||||
bail: isEnvProduction,
|
||||
devtool: shouldUseSourceMap ? 'source-map' : false,
|
||||
devtool: isEnvProduction
|
||||
? shouldUseSourceMap
|
||||
? 'source-map'
|
||||
: false
|
||||
: isEnvDevelopment && 'cheap-module-source-map',
|
||||
// These are the "entry points" to our application.
|
||||
// This means they will be the "root" imports that are included in JS bundle.
|
||||
entry: isEnvProduction ? [paths.appDemoIndexJs] : [
|
||||
// Include an alternative client for WebpackDevServer. A client's job is to
|
||||
// connect to WebpackDevServer by a socket and get notified about changes.
|
||||
// When you save a file, the client will either apply hot updates (in case
|
||||
// of CSS changes), or refresh the page (in case of JS changes). When you
|
||||
// make a syntax error, this client will display a syntax error overlay.
|
||||
// Note: instead of the default WebpackDevServer client, we use a custom one
|
||||
// to bring better experience for Create React App users. You can replace
|
||||
// the line below with these two lines if you prefer the stock client:
|
||||
// require.resolve('webpack-dev-server/client') + '?/',
|
||||
// require.resolve('webpack/hot/dev-server'),
|
||||
isEnvDevelopment &&
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
// Finally, this is your app's code:
|
||||
paths.appDemoIndexJs,
|
||||
// We include the app code last so that if there is a runtime error during
|
||||
@@ -132,6 +163,7 @@ module.exports = function(webpackEnv) {
|
||||
// The build folder.
|
||||
path: isEnvProduction ? paths.appDemo : undefined,
|
||||
// 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: 'index.js',
|
||||
@@ -148,7 +180,11 @@ module.exports = function(webpackEnv) {
|
||||
path
|
||||
.relative(paths.appSrcDemo, info.absoluteResourcePath)
|
||||
.replace(/\\/g, '/')
|
||||
: null,
|
||||
: isEnvDevelopment &&
|
||||
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
||||
// Prevents conflicts when multiple Webpack runtimes (from different apps)
|
||||
// are used on the same page.
|
||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
||||
},
|
||||
optimization: {
|
||||
minimize: isEnvProduction,
|
||||
@@ -157,8 +193,8 @@ module.exports = function(webpackEnv) {
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
parse: {
|
||||
// we want terser to parse ecma 8 code. However, we don't want it
|
||||
// to apply any minfication steps that turns valid ecma 5 code
|
||||
// We want terser to parse ecma 8 code. However, we don't want it
|
||||
// to apply any minification steps that turns valid ecma 5 code
|
||||
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||
// sections only apply transformations that are ecma 5 safe
|
||||
// https://github.com/facebook/create-react-app/pull/4234
|
||||
@@ -174,7 +210,7 @@ module.exports = function(webpackEnv) {
|
||||
comparisons: false,
|
||||
// Disabled because of an issue with Terser breaking valid code:
|
||||
// https://github.com/facebook/create-react-app/issues/5250
|
||||
// Pending futher investigation:
|
||||
// Pending further investigation:
|
||||
// https://github.com/terser-js/terser/issues/120
|
||||
inline: 2,
|
||||
},
|
||||
@@ -236,7 +272,9 @@ module.exports = function(webpackEnv) {
|
||||
// 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 || []),
|
||||
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:
|
||||
@@ -286,6 +324,7 @@ module.exports = function(webpackEnv) {
|
||||
options: {
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
resolvePluginsRelativeTo: __dirname,
|
||||
|
||||
},
|
||||
loader: require.resolve('eslint-loader'),
|
||||
@@ -305,7 +344,7 @@ module.exports = function(webpackEnv) {
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
limit: imageInlineSizeLimit,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
@@ -461,24 +500,34 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
plugins: [
|
||||
// Generates an `index.html` file with the <script> injected.
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: paths.appHtml,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
removeStyleLinkTypeAttributes: true,
|
||||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
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.
|
||||
isEnvProduction &&
|
||||
shouldInlineRuntimeChunk &&
|
||||
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime~.+[.]js/]),
|
||||
// Makes some environment variables available in index.html.
|
||||
@@ -497,6 +546,18 @@ module.exports = function(webpackEnv) {
|
||||
// during a production build.
|
||||
// Otherwise React will be compiled in the very slow development mode.
|
||||
new webpack.DefinePlugin(env.stringified),
|
||||
// This is necessary to emit hot updates (currently CSS only):
|
||||
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
|
||||
// Watcher doesn't work well if you mistype casing in a path so we use
|
||||
// a plugin that prints an error when you attempt to do this.
|
||||
// See https://github.com/facebook/create-react-app/issues/240
|
||||
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
||||
// If you require a missing module and then `npm install` it, you still have
|
||||
// to restart the development server for Webpack to discover it. This plugin
|
||||
// makes the discovery automatic so you don't have to restart.
|
||||
// See https://github.com/facebook/create-react-app/issues/186
|
||||
isEnvDevelopment &&
|
||||
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
|
||||
isEnvProduction &&
|
||||
new MiniCssExtractPlugin({
|
||||
// Options similar to the same options in webpackOptions.output
|
||||
@@ -551,6 +612,12 @@ module.exports = function(webpackEnv) {
|
||||
}),
|
||||
useTypescriptIncrementalApi: true,
|
||||
checkSyntacticErrors: true,
|
||||
resolveModuleNameModule: process.versions.pnp
|
||||
? `${__dirname}/pnpTs.js`
|
||||
: undefined,
|
||||
resolveTypeReferenceDirectiveModule: process.versions.pnp
|
||||
? `${__dirname}/pnpTs.js`
|
||||
: undefined,
|
||||
tsconfig: paths.appTsConfig,
|
||||
reportFiles: [
|
||||
'**',
|
||||
|
||||
@@ -13,7 +13,9 @@ const TerserPlugin = require('terser-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const safePostCssParser = require('postcss-safe-parser');
|
||||
const ManifestPlugin = require('webpack-manifest-plugin');
|
||||
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
|
||||
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
|
||||
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
|
||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
||||
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
|
||||
@@ -26,15 +28,22 @@ const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const getPackageJson = require('./getPackageJson');
|
||||
const PrettierPlugin = require("prettier-webpack-plugin");
|
||||
const eslint = require('eslint');
|
||||
|
||||
const postcssNormalize = require('postcss-normalize');
|
||||
|
||||
const appPackageJson = require(paths.appPackageJson);
|
||||
|
||||
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||||
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== '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';
|
||||
|
||||
const imageInlineSizeLimit = parseInt(
|
||||
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
|
||||
);
|
||||
|
||||
// Check if TypeScript is setup
|
||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||
|
||||
@@ -93,10 +102,7 @@ module.exports = function(webpackEnv) {
|
||||
isEnvDevelopment && require.resolve('style-loader'),
|
||||
isEnvProduction && {
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: Object.assign(
|
||||
{},
|
||||
shouldUseRelativeAssetPaths ? { publicPath: '../../' } : undefined
|
||||
),
|
||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
@@ -129,12 +135,20 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
].filter(Boolean);
|
||||
if (preProcessor) {
|
||||
loaders.push({
|
||||
loader: require.resolve(preProcessor),
|
||||
loaders.push(
|
||||
{
|
||||
loader: require.resolve('resolve-url-loader'),
|
||||
options: {
|
||||
sourceMap: isEnvProduction && shouldUseSourceMap,
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
loader: require.resolve(preProcessor),
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return loaders;
|
||||
};
|
||||
@@ -199,6 +213,9 @@ module.exports = function(webpackEnv) {
|
||||
.replace(/\\/g, '/')
|
||||
: isEnvDevelopment &&
|
||||
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
||||
// Prevents conflicts when multiple Webpack runtimes (from different apps)
|
||||
// are used on the same page.
|
||||
jsonpFunction: `webpackJsonp${appPackageJson.name}`,
|
||||
},
|
||||
optimization: {
|
||||
minimize: isEnvProduction,
|
||||
@@ -207,8 +224,8 @@ module.exports = function(webpackEnv) {
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
parse: {
|
||||
// we want terser to parse ecma 8 code. However, we don't want it
|
||||
// to apply any minfication steps that turns valid ecma 5 code
|
||||
// We want terser to parse ecma 8 code. However, we don't want it
|
||||
// to apply any minification steps that turns valid ecma 5 code
|
||||
// into invalid ecma 5 code. This is why the 'compress' and 'output'
|
||||
// sections only apply transformations that are ecma 5 safe
|
||||
// https://github.com/facebook/create-react-app/pull/4234
|
||||
@@ -224,14 +241,14 @@ module.exports = function(webpackEnv) {
|
||||
comparisons: false,
|
||||
// Disabled because of an issue with Terser breaking valid code:
|
||||
// https://github.com/facebook/create-react-app/issues/5250
|
||||
// Pending futher investigation:
|
||||
// Pending further investigation:
|
||||
// https://github.com/terser-js/terser/issues/120
|
||||
inline: 2,
|
||||
},
|
||||
mangle: {
|
||||
safari10: true,
|
||||
//keep_classnames: true,
|
||||
//keep_fnames: true,
|
||||
keep_classnames: true,
|
||||
keep_fnames: true,
|
||||
module: true
|
||||
},
|
||||
output: {
|
||||
@@ -289,7 +306,9 @@ module.exports = function(webpackEnv) {
|
||||
// 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 || []),
|
||||
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:
|
||||
@@ -339,6 +358,7 @@ module.exports = function(webpackEnv) {
|
||||
options: {
|
||||
formatter: require.resolve('react-dev-utils/eslintFormatter'),
|
||||
eslintPath: require.resolve('eslint'),
|
||||
resolvePluginsRelativeTo: __dirname,
|
||||
|
||||
},
|
||||
loader: require.resolve('eslint-loader'),
|
||||
@@ -358,7 +378,7 @@ module.exports = function(webpackEnv) {
|
||||
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
||||
loader: require.resolve('url-loader'),
|
||||
options: {
|
||||
limit: 10000,
|
||||
limit: imageInlineSizeLimit,
|
||||
name: 'static/media/[name].[hash:8].[ext]',
|
||||
},
|
||||
},
|
||||
@@ -514,12 +534,8 @@ module.exports = function(webpackEnv) {
|
||||
},
|
||||
plugins: [
|
||||
isEnvDevelopment &&
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
template: paths.appHtml,
|
||||
}),
|
||||
// Generates an `index.html` file with the <script> injected.
|
||||
/*new HtmlWebpackPlugin(
|
||||
new HtmlWebpackPlugin(
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
@@ -543,7 +559,7 @@ module.exports = function(webpackEnv) {
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
),*/
|
||||
),
|
||||
// Inlines the webpack runtime script. This script is too small to warrant
|
||||
// a network request.
|
||||
isEnvProduction &&
|
||||
@@ -639,6 +655,12 @@ module.exports = function(webpackEnv) {
|
||||
async: isEnvDevelopment,
|
||||
useTypescriptIncrementalApi: true,
|
||||
checkSyntacticErrors: true,
|
||||
resolveModuleNameModule: process.versions.pnp
|
||||
? `${__dirname}/pnpTs.js`
|
||||
: undefined,
|
||||
resolveTypeReferenceDirectiveModule: process.versions.pnp
|
||||
? `${__dirname}/pnpTs.js`
|
||||
: undefined,
|
||||
tsconfig: paths.appTsConfig,
|
||||
reportFiles: [
|
||||
'**',
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
5642
package-lock.json
generated
5642
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
101
package.json
101
package.json
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "simple-keyboard",
|
||||
"version": "2.25.0",
|
||||
"version": "2.27.1",
|
||||
"description": "On-screen Javascript Virtual Keyboard",
|
||||
"main": "build/index.js",
|
||||
"types": "build/index.d.ts",
|
||||
"scripts": {
|
||||
"start": "node scripts/start.js",
|
||||
"build": "node scripts/build.js && node scripts/buildUnminified.js",
|
||||
"build": "node scripts/build.js",
|
||||
"demo": "node scripts/demo.js",
|
||||
"test": "node scripts/test.js",
|
||||
"coverage": "node scripts/test.js --coverage --watchAll=false",
|
||||
"postinstall": "node bin/postinstall",
|
||||
"prepare": "npm run build"
|
||||
"prepare": "npm run build",
|
||||
"trypublish": "npm publish || true"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -40,81 +40,76 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.5.5",
|
||||
"@babel/plugin-proposal-class-properties": "^7.4.4",
|
||||
"@babel/preset-env": "^7.4.4",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/runtime": "7.5.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-jest": "24.8.0",
|
||||
"babel-eslint": "10.0.3",
|
||||
"babel-jest": "^24.8.0",
|
||||
"babel-loader": "8.0.6",
|
||||
"babel-plugin-named-asset-import": "^0.3.2",
|
||||
"babel-preset-react-app": "^9.0.0",
|
||||
"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",
|
||||
"copy-webpack-plugin": "^5.0.5",
|
||||
"css-loader": "3.2.0",
|
||||
"dotenv": "8.0.0",
|
||||
"dotenv": "8.2.0",
|
||||
"dotenv-expand": "5.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-react-app": "^4.0.1",
|
||||
"eslint-loader": "2.2.1",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-react-app": "^5.0.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.5.0",
|
||||
"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": "^2.0.0",
|
||||
"jest": "24.8.0",
|
||||
"is-wsl": "^2.1.0",
|
||||
"jest": "24.9.0",
|
||||
"jest-environment-jsdom-fourteen": "0.1.0",
|
||||
"jest-resolve": "24.8.0",
|
||||
"jest-watch-typeahead": "0.3.1",
|
||||
"jest-resolve": "24.9.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": "8.0.1",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"postcss-safe-parser": "4.0.1",
|
||||
"prettier": "^1.17.0",
|
||||
"prettier-webpack-plugin": "^1.2.0",
|
||||
"react": "^16.8.6",
|
||||
"react-app-polyfill": "^1.0.1",
|
||||
"react-dev-utils": "^9.0.1",
|
||||
"react-dom": "^16.8.6",
|
||||
"react": "^16.11.0",
|
||||
"react-app-polyfill": "^1.0.2",
|
||||
"react-dev-utils": "^9.0.3",
|
||||
"react-dom": "^16.11.0",
|
||||
"resolve": "1.12.0",
|
||||
"sass-loader": "7.2.0",
|
||||
"resolve-url-loader": "3.1.0",
|
||||
"sass-loader": "7.3.1",
|
||||
"semver": "6.3.0",
|
||||
"style-loader": "1.0.0",
|
||||
"terser-webpack-plugin": "1.4.1",
|
||||
"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.8.0",
|
||||
"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": {
|
||||
"extends": "react-app",
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React",
|
||||
"version": "detect"
|
||||
}
|
||||
}
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
@@ -124,20 +119,25 @@
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"roots": [
|
||||
"<rootDir>/src"
|
||||
],
|
||||
"collectCoverageFrom": [
|
||||
"src/**/*.{js,jsx,ts,tsx}",
|
||||
"!src/**/index.js",
|
||||
"!src/**/*.d.ts",
|
||||
"!src/lib/index.js",
|
||||
"!src/demo/index.js",
|
||||
"!src/utils/**",
|
||||
"!src/**/*.d.ts",
|
||||
"!**/tests/**"
|
||||
],
|
||||
"resolver": "jest-pnp-resolver",
|
||||
"setupFiles": [
|
||||
"react-app-polyfill/jsdom"
|
||||
],
|
||||
"setupFilesAfterEnv": [],
|
||||
"testMatch": [
|
||||
"<rootDir>/src/**/tests/**/*.{js,jsx,ts,tsx}"
|
||||
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
|
||||
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
|
||||
],
|
||||
"testEnvironment": "jest-environment-jsdom-fourteen",
|
||||
"transform": {
|
||||
@@ -178,10 +178,7 @@
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{
|
||||
"loose": true
|
||||
}
|
||||
"@babel/plugin-proposal-class-properties"
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// Do this as the first thing so that any code reading it knows the right env.
|
||||
process.env.BABEL_ENV = 'production';
|
||||
process.env.NODE_ENV = 'production';
|
||||
|
||||
// Makes the script crash on unhandled rejections instead of silently
|
||||
// ignoring them. In the future, promise rejections that are not handled will
|
||||
// terminate the Node.js process with a non-zero exit code.
|
||||
process.on('unhandledRejection', err => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
// Ensure environment variables are read.
|
||||
require('../config/env');
|
||||
|
||||
|
||||
const path = require('path');
|
||||
const chalk = require('react-dev-utils/chalk');
|
||||
const fs = require('fs-extra');
|
||||
const webpack = require('webpack');
|
||||
const configFactory = require('../config/webpack.config.unminified');
|
||||
const paths = require('../config/paths');
|
||||
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
||||
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
|
||||
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
||||
const printBuildError = require('react-dev-utils/printBuildError');
|
||||
|
||||
const measureFileSizesBeforeBuild =
|
||||
FileSizeReporter.measureFileSizesBeforeBuild;
|
||||
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
||||
const useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
|
||||
// These sizes are pretty large. We'll warn for bundles exceeding them.
|
||||
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
|
||||
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
|
||||
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
// Warn and crash if required files are missing
|
||||
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Generate configuration
|
||||
const config = configFactory('production');
|
||||
|
||||
// We require that you explicitly set browsers and do not fall back to
|
||||
// browserslist defaults.
|
||||
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
|
||||
checkBrowsers(paths.appPath, isInteractive)
|
||||
.then(() => {
|
||||
// First, read the current file sizes in build directory.
|
||||
// This lets us display how much they changed later.
|
||||
return measureFileSizesBeforeBuild(paths.appBuild);
|
||||
})
|
||||
.then(previousFileSizes => {
|
||||
// Remove all content but keep the directory so that
|
||||
// if you're in it, you don't end up in Trash
|
||||
//fs.emptyDirSync(paths.appBuild);
|
||||
// Merge with the public folder
|
||||
//copyPublicFolder();
|
||||
// Start the webpack build
|
||||
return build(previousFileSizes);
|
||||
})
|
||||
.then(
|
||||
({ stats, previousFileSizes, warnings }) => {
|
||||
if (warnings.length) {
|
||||
console.log(chalk.yellow('Compiled with warnings.\n'));
|
||||
console.log(warnings.join('\n\n'));
|
||||
console.log(
|
||||
'\nSearch for the ' +
|
||||
chalk.underline(chalk.yellow('keywords')) +
|
||||
' to learn more about each warning.'
|
||||
);
|
||||
console.log(
|
||||
'To ignore, add ' +
|
||||
chalk.cyan('// eslint-disable-next-line') +
|
||||
' to the line before.\n'
|
||||
);
|
||||
} else {
|
||||
console.log(chalk.green('Compiled successfully.\n'));
|
||||
}
|
||||
|
||||
console.log('File sizes after gzip:\n');
|
||||
printFileSizesAfterBuild(
|
||||
stats,
|
||||
previousFileSizes,
|
||||
paths.appBuild,
|
||||
WARN_AFTER_BUNDLE_GZIP_SIZE,
|
||||
WARN_AFTER_CHUNK_GZIP_SIZE
|
||||
);
|
||||
console.log();
|
||||
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicPath = config.output.publicPath;
|
||||
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||
printHostingInstructions(
|
||||
appPackage,
|
||||
publicUrl,
|
||||
publicPath,
|
||||
buildFolder,
|
||||
useYarn
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
printBuildError(err);
|
||||
process.exit(1);
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
if (err && err.message) {
|
||||
console.log(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Create the production build and print the deployment instructions.
|
||||
function build(previousFileSizes) {
|
||||
console.log('Creating a non-minified production build...');
|
||||
// We used to support resolving modules according to `NODE_PATH`.
|
||||
// This now has been deprecated in favor of jsconfig/tsconfig.json
|
||||
// This lets you use absolute paths in imports inside large monorepos:
|
||||
if (process.env.NODE_PATH) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'Setting NODE_PATH to resolve modules absolutely has been deprecated in favor of setting baseUrl in jsconfig.json (or tsconfig.json if you are using TypeScript) and will be removed in a future major release of create-react-app.'
|
||||
)
|
||||
);
|
||||
console.log();
|
||||
}
|
||||
|
||||
const compiler = webpack(config);
|
||||
return new Promise((resolve, reject) => {
|
||||
compiler.run((err, stats) => {
|
||||
let messages;
|
||||
if (err) {
|
||||
if (!err.message) {
|
||||
return reject(err);
|
||||
}
|
||||
messages = formatWebpackMessages({
|
||||
errors: [err.message],
|
||||
warnings: [],
|
||||
});
|
||||
} else {
|
||||
messages = formatWebpackMessages(
|
||||
stats.toJson({ all: false, warnings: true, errors: true })
|
||||
);
|
||||
}
|
||||
if (messages.errors.length) {
|
||||
// Only keep the first error. Others are often indicative
|
||||
// of the same problem, but confuse the reader with noise.
|
||||
if (messages.errors.length > 1) {
|
||||
messages.errors.length = 1;
|
||||
}
|
||||
return reject(new Error(messages.errors.join('\n\n')));
|
||||
}
|
||||
if (
|
||||
process.env.CI &&
|
||||
(typeof process.env.CI !== 'string' ||
|
||||
process.env.CI.toLowerCase() !== 'false') &&
|
||||
messages.warnings.length
|
||||
) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'\nTreating warnings as errors because process.env.CI = true.\n' +
|
||||
'Most CI servers set it automatically.\n'
|
||||
)
|
||||
);
|
||||
return reject(new Error(messages.warnings.join('\n\n')));
|
||||
}
|
||||
|
||||
return resolve({
|
||||
stats,
|
||||
previousFileSizes,
|
||||
warnings: messages.warnings,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function copyPublicFolder() {
|
||||
fs.copySync(paths.appPublic, paths.appBuild, {
|
||||
dereference: true,
|
||||
filter: file => file !== paths.appHtml,
|
||||
});
|
||||
}
|
||||
@@ -106,7 +106,7 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
);
|
||||
},
|
||||
err => {
|
||||
console.log(chalk.red('Failed to compile.\n'));
|
||||
console.error('Failed to compile');
|
||||
printBuildError(err);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ function isInMercurialRepository() {
|
||||
// Watch unless on CI or explicitly running all tests
|
||||
if (
|
||||
!process.env.CI &&
|
||||
argv.indexOf('--watchAll') === -1
|
||||
argv.indexOf('--watchAll') === -1 &&
|
||||
argv.indexOf('--watchAll=false') === -1
|
||||
) {
|
||||
// https://github.com/facebook/create-react-app/issues/5210
|
||||
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
|
||||
|
||||
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");
|
||||
});
|
||||
@@ -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