├── .eslintignore ├── .eslintrc.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml ├── github.md ├── pull_request_template.md ├── stale.yml └── workflows │ ├── main.yml │ ├── publish.yml │ ├── pull_request.yml │ ├── pull_request_compl.yml │ └── pull_request_dependabot.yml ├── .gitignore ├── .npmignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── build ├── components │ ├── Keyboard.d.ts │ └── KeyboardModern.d.ts ├── css │ └── index.css ├── index.d.ts ├── index.js ├── index.modern.d.ts ├── index.modern.esm.js ├── index.modern.esm.js.map ├── index.modern.js ├── index.modern.js.map ├── interfaces.d.ts ├── polyfills.d.ts └── services │ └── Utilities.d.ts ├── package-lock.json ├── package.json ├── scripts ├── generateKeyboardTypes.js ├── getPackageJson.js ├── loaderMock.js └── testMock.js ├── src ├── demo │ ├── App.tsx │ ├── css │ │ └── App.css │ ├── images │ │ ├── demo.gif │ │ ├── keyboard.PNG │ │ └── simple-keyboard.png │ └── index.tsx ├── lib │ ├── components │ │ ├── Keyboard.tsx │ │ ├── KeyboardModern.tsx │ │ └── tests │ │ │ ├── Keyboard.test.tsx │ │ │ └── KeyboardModern.test.tsx │ ├── index.modern.ts │ ├── index.ts │ ├── interfaces.d.ts │ ├── polyfills.js │ └── services │ │ └── Utilities.ts └── utils │ ├── BaseDOM.js │ └── TestUtility.js ├── tsconfig.json ├── webpack.config.demo.js ├── webpack.config.js ├── webpack.config.modern.js └── webpack.config.modern_esm.js /.eslintignore: -------------------------------------------------------------------------------- 1 | build/* 2 | /**/*.d.ts -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "ecmaVersion": 6, 5 | "sourceType": "module", 6 | "ecmaFeatures": { 7 | "modules": true, 8 | "experimentalObjectRestSpread": true 9 | } 10 | }, 11 | "plugins": ["@typescript-eslint"], 12 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 13 | "rules": { 14 | "comma-dangle": 0, 15 | "no-unused-vars": "warn", 16 | "no-unexpected-multiline": "warn", 17 | "prefer-const": "warn", 18 | "@typescript-eslint/no-empty-function": "off", 19 | "@typescript-eslint/explicit-module-boundary-types": "off", 20 | "@typescript-eslint/no-explicit-any": "off", 21 | "@typescript-eslint/no-var-requires": "off" 22 | }, 23 | "settings": {}, 24 | "env": { 25 | "browser": true, 26 | "node": true, 27 | "jasmine": true, 28 | "jest": true, 29 | "es6": true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | buy_me_a_coffee: hodgef 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help improve react-simple-keyboard 4 | title: '' 5 | labels: '' 6 | assignees: hodgef 7 | 8 | --- 9 | 10 | **React-simple-keyboard version** 11 | As some bugs have been addressed in later versions, please ensure you are running the latest. 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. Providing a [sandbox example](https://codesandbox.io/s/new) or code depicting the issue is important, as this will help us reproduce the issue. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea you'd like to see in react-simple-keyboard 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | timezone: America/Montreal 9 | open-pull-requests-limit: 10 10 | versioning-strategy: increase 11 | -------------------------------------------------------------------------------- /.github/github.md: -------------------------------------------------------------------------------- 1 | # About .github 2 | 3 | This directory handles special features to be used on react-simple-keyboard's Github repository. 4 | It is not needed for simple-keyboard to run and can be safely removed. 5 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | A few sentences describing the overall goals of the pull request's commits. 4 | 5 | ## Checks 6 | 7 | - [ ] I have read and followed the [Contributing Guidelines](https://github.com/hodgef/react-simple-keyboard/blob/master/CONTRIBUTING.md). 8 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 5 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 2 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: Stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | paths-ignore: 5 | - README.md 6 | - .gitignore 7 | - .github/** 8 | 9 | jobs: 10 | build: 11 | runs-on: ${{ matrix.os }} 12 | if: contains(github.ref, 'master') 13 | strategy: 14 | matrix: 15 | node-version: [20.x] 16 | os: [ubuntu-latest] 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: Use Node.js ${{ matrix.node_version }} 20 | uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node_version }} 23 | - name: npm install, build, and test 24 | run: | 25 | export NODE_OPTIONS=--openssl-legacy-provider 26 | npm install 27 | npm run coverage 28 | 29 | - name: Discord notification 30 | continue-on-error: true 31 | if: success() 32 | env: 33 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 34 | uses: Ilshidur/action-discord@master 35 | with: 36 | args: "react-simple-keyboard - CI Build Passed" 37 | 38 | - name: Discord notification 39 | continue-on-error: true 40 | if: failure() 41 | env: 42 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 43 | uses: Ilshidur/action-discord@master 44 | with: 45 | args: "react-simple-keyboard - CI Build Failed" 46 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths-ignore: 8 | - README.md 9 | - .gitignore 10 | - .github/** 11 | 12 | permissions: 13 | contents: write 14 | id-token: write 15 | 16 | jobs: 17 | publish: 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | node-version: [20.x] 22 | os: [ubuntu-latest] 23 | steps: 24 | - uses: actions/checkout@v1 25 | - name: Use Node.js ${{ matrix.node_version }} 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node_version }} 29 | 30 | - name: npm install, build, and test 31 | run: | 32 | export NODE_OPTIONS=--openssl-legacy-provider 33 | npm install 34 | npm run test -- --coverage --watchAll=false 35 | 36 | - name: Setup GIT 37 | run: | 38 | git reset --hard 39 | git config --local --list 40 | git checkout master 41 | git config user.email "$GH_EMAIL" 42 | git config user.name "Francisco Hodge" 43 | env: 44 | GH_EMAIL: ${{secrets.GH_EMAIL}} 45 | 46 | - name: Bump version 47 | run: | 48 | git reset --hard 49 | export NODE_OPTIONS=--openssl-legacy-provider 50 | npm version patch 51 | npm run build 52 | git add . || true 53 | git commit -m "Build update" || true 54 | git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY" 55 | env: 56 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 57 | 58 | - name: npm publish 59 | run: | 60 | export NODE_OPTIONS=--openssl-legacy-provider 61 | npm config set //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN 62 | npm publish --provenance --access public 63 | env: 64 | NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}} 65 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Build PR (Standard) 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | if: ${{ github.actor != 'dependabot[bot]' }} 9 | strategy: 10 | matrix: 11 | node-version: [20.x] 12 | os: [ubuntu-latest] 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Use Node.js ${{ matrix.node_version }} 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: ${{ matrix.node_version }} 19 | - name: npm install, build, and test 20 | run: | 21 | export NODE_OPTIONS=--openssl-legacy-provider 22 | npm install 23 | npm run coverage 24 | env: 25 | CI: true 26 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_compl.yml: -------------------------------------------------------------------------------- 1 | name: PR Compliance 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened] 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.os }} 10 | if: ${{ github.actor != 'dependabot[bot]' }} 11 | strategy: 12 | matrix: 13 | node-version: [20.x] 14 | os: [ubuntu-latest] 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Comment PR 20 | uses: thollander/actions-comment-pull-request@v2 21 | with: 22 | message: | 23 | :wave: Hello @${{ github.actor }}! Please make sure to review the [Contributing Guidelines](https://github.com/hodgef/react-simple-keyboard/blob/master/CONTRIBUTING.md) to ensure your PR is compliant. Thank you! 24 | reactions: eyes 25 | -------------------------------------------------------------------------------- /.github/workflows/pull_request_dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Build PR (Dependabot) 2 | 3 | on: pull_request_target 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | if: ${{ github.actor == 'dependabot[bot]' }} 9 | strategy: 10 | matrix: 11 | node-version: [20.x] 12 | os: [ubuntu-latest] 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | ref: ${{ github.event.pull_request.head.sha }} 17 | - name: Use Node.js ${{ matrix.node_version }} 18 | uses: actions/setup-node@v1 19 | with: 20 | node-version: ${{ matrix.node_version }} 21 | - name: npm install, build, and test 22 | run: | 23 | export NODE_OPTIONS=--openssl-legacy-provider 24 | npm install 25 | npm run coverage 26 | env: 27 | CI: true 28 | - name: Merge PR 29 | if: success() 30 | uses: "actions/github-script@v2" 31 | with: 32 | github-token: "${{ secrets.GH_KEY }}" 33 | script: | 34 | const pullRequest = context.payload.pull_request 35 | const repository = context.repo 36 | 37 | await github.pulls.merge({ 38 | merge_method: "merge", 39 | owner: repository.owner, 40 | pull_number: pullRequest.number, 41 | repo: repository.repo, 42 | }) 43 | - name: Reject PR 44 | if: failure() 45 | uses: peter-evans/close-pull@v1 46 | with: 47 | pull-request-number: ${{github.event.number}} 48 | comment: "Closing PR due to failing tests." 49 | delete-branch: true 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | .vscode 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | _git* -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # testing 5 | /tests 6 | /coverage 7 | 8 | # docs 9 | /docs 10 | 11 | # misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | /.github 18 | /demo 19 | .esdoc.json 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # Development folders and files 26 | public 27 | src 28 | scripts 29 | config 30 | .travis.yml 31 | CHANGELOG.md 32 | README.md 33 | CODE_OF_CONDUCT.md 34 | CONTRIBUTING.md 35 | tsconfig.json 36 | .eslintignore 37 | .eslintrc.json 38 | webpack.config.* 39 | babel.config.js -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource@hodgef.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before working on a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Guidelines 9 | 10 | 1. Use PRs to fix issues. New features are discouraged as they bring more maintenance burden over time. 11 | 2. Discuss the change you wish to make with the owners of this repository **before** raising a PR. If you do not discuss it beforehand, your PR might end up being rejected and your work will be lost. 12 | 3. Please ensure your proposal will not significantly change current functionality or bring along breaking changes. 13 | 4. PRs only consisting of typo fixes (or other automated contributions), will not be accepted. 14 | 5. Do not add any dependencies, libraries or external codes to the project. All the code submitted should be authored by you. 15 | 6. Avoid refactors. The changes should be succint and fix a specific issue with the least code possible. 16 | 7. Document your changes thoroughly. 17 | 8. Ensure that none of the tests fail. 18 | 9. Be reactive to any comments, reviews or change requests entered in your pull request. 19 | 10. It's up to the maintainers discretion whether the PR is accepted or rejected. Remember, the maintainer will have to maintain the code you've added (and fix any issues filed about it) for the years to come! In case of a rejection, the maintainer will explain the reasons guiding the decision. 20 | 21 | Thank you for your contributions! 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Francisco Hodge and project contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | simple-keyboard: Javscript Virtual Keyboard 3 | 4 | 5 |
Virtual Keyboard for React. Customizable, responsive and lightweight.
6 | 7 |

8 | npm version MIT license Mirroring Build Status Publish Status 9 |

10 | 11 | ## 🚀 Demo 12 | 13 | [https://simple-keyboard.com/demo](https://simple-keyboard.com/demo) 14 | 15 | ## 📦 Installation & Usage 16 | 17 | Check out the [Getting Started](https://simple-keyboard.com/react/getting-started) docs to begin. 18 | 19 | ## 📖 Documentation 20 | 21 | Check out the [simple-keyboard documentation](https://simple-keyboard.com/react/documentation) site. 22 | 23 | Feel free to browse the [Questions & Answers](https://simple-keyboard.com/qa-use-cases/) page for common use-cases. 24 | 25 | ### To run demo on your own computer 26 | 27 | - Clone this repository 28 | - `npm install` 29 | - `npm start` 30 | - Visit [http://localhost:3000/](http://localhost:3000/) 31 | 32 | ### Other versions 33 | 34 | - [Vanilla JS](https://github.com/hodgef/simple-keyboard) 35 | - [Angular](https://simple-keyboard.com/demo) 36 | - [Vue.js](https://simple-keyboard.com/demo) 37 | 38 | ### Questions? Join the chat 39 | 40 | 41 | 42 | ## 🎯 Compatibility 43 | 44 | - Internet Explorer 11 45 | - Edge (Spartan) 16+ 46 | - Edge (Anaheim/Edge Chromium) 79+ 47 | - Chrome 49+ 48 | - Safari 9+ 49 | - Firefox 57+ 50 | - iOS 9+ 51 | 52 | > Note: If you don't want to support old browsers, you can use the Modern Browsers bundle ([index.modern.js](https://github.com/hodgef/react-simple-keyboard/blob/master/build)). 53 | 54 | ## ✅ Contributing 55 | 56 | PRs and issues are welcome. Feel free to submit any issues you have at: 57 | [https://github.com/hodgef/react-simple-keyboard/issues](https://github.com/hodgef/react-simple-keyboard/issues) 58 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | "@babel/preset-react", 4 | [ 5 | "@babel/env", 6 | { 7 | corejs: "3", 8 | useBuiltIns: "entry", 9 | targets: { 10 | browsers: [ 11 | "edge >= 16", 12 | "safari >= 9", 13 | "firefox >= 57", 14 | "ie >= 11", 15 | "ios >= 9", 16 | "chrome >= 49", 17 | ], 18 | }, 19 | }, 20 | ], 21 | "@babel/preset-typescript", 22 | ], 23 | plugins: [ 24 | ["@babel/plugin-proposal-class-properties"], 25 | ["@babel/plugin-transform-typescript"], 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /build/components/Keyboard.d.ts: -------------------------------------------------------------------------------- 1 | import "simple-keyboard/build/css/index.css"; 2 | import { KeyboardReactInterface } from "../interfaces.d"; 3 | declare const KeyboardReact: (props: KeyboardReactInterface["options"]) => any; 4 | export default KeyboardReact; 5 | -------------------------------------------------------------------------------- /build/components/KeyboardModern.d.ts: -------------------------------------------------------------------------------- 1 | import "simple-keyboard/build/css/index.css"; 2 | import { KeyboardReactInterface } from "../interfaces"; 3 | declare const KeyboardReact: (props: KeyboardReactInterface["options"]) => any; 4 | export default KeyboardReact; 5 | -------------------------------------------------------------------------------- /build/css/index.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * react-simple-keyboard v3.8.80 4 | * https://github.com/hodgef/react-simple-keyboard 5 | * 6 | * Copyright (c) Francisco Hodge (https://github.com/hodgef) and project contributors. 7 | * 8 | * This source code is licensed under the MIT license found in the 9 | * LICENSE file in the root directory of this source tree. 10 | * 11 | */ 12 | /*! 13 | * 14 | * simple-keyboard v3.8.59 15 | * https://github.com/hodgef/simple-keyboard 16 | * 17 | * Copyright (c) Francisco Hodge (https://github.com/hodgef) and project contributors. 18 | * 19 | * This source code is licensed under the MIT license found in the 20 | * LICENSE file in the root directory of this source tree. 21 | * 22 | */.hg-theme-default{background-color:#ececec;border-radius:5px;box-sizing:border-box;font-family:HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;overflow:hidden;padding:5px;touch-action:manipulation;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.hg-theme-default .hg-button span,.hg-theme-default .hg-button span svg{pointer-events:none}.hg-theme-default button.hg-button{border-width:0;font-size:inherit;outline:0}.hg-theme-default .hg-button{display:inline-block;flex-grow:1}.hg-theme-default .hg-row{display:flex}.hg-theme-default .hg-row:not(:last-child){margin-bottom:5px}.hg-theme-default .hg-row .hg-button-container,.hg-theme-default .hg-row .hg-button:not(:last-child){margin-right:5px}.hg-theme-default .hg-row>div:last-child{margin-right:0}.hg-theme-default .hg-row .hg-button-container{display:flex}.hg-theme-default .hg-button{align-items:center;background:#fff;border-bottom:1px solid #b5b5b5;border-radius:5px;box-shadow:0 0 3px -1px rgba(0,0,0,.3);box-sizing:border-box;cursor:pointer;display:flex;height:40px;justify-content:center;padding:5px;-webkit-tap-highlight-color:rgba(0,0,0,0)}.hg-theme-default .hg-button.hg-standardBtn{width:20px}.hg-theme-default .hg-button.hg-activeButton{background:#efefef}.hg-theme-default.hg-layout-numeric .hg-button{align-items:center;display:flex;height:60px;justify-content:center;width:33.3%}.hg-theme-default .hg-button.hg-button-numpadadd,.hg-theme-default .hg-button.hg-button-numpadenter{height:85px}.hg-theme-default .hg-button.hg-button-numpad0{width:105px}.hg-theme-default .hg-button.hg-button-com{max-width:85px}.hg-theme-default .hg-button.hg-standardBtn.hg-button-at{max-width:45px}.hg-theme-default .hg-button.hg-selectedButton{background:rgba(5,25,70,.53);color:#fff}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn=".com"]{max-width:82px}.hg-theme-default .hg-button.hg-standardBtn[data-skbtn="@"]{max-width:60px}.hg-candidate-box{background:#ececec;border-bottom:2px solid #b5b5b5;border-radius:5px;display:inline-flex;margin-top:-10px;position:absolute;transform:translateY(-100%);-webkit-user-select:none;-moz-user-select:none;user-select:none}ul.hg-candidate-box-list{display:flex;flex:1;list-style:none;margin:0;padding:0}li.hg-candidate-box-list-item{align-items:center;display:flex;height:40px;justify-content:center;width:40px}li.hg-candidate-box-list-item:hover{background:rgba(0,0,0,.03);cursor:pointer}li.hg-candidate-box-list-item:active{background:rgba(0,0,0,.1)}.hg-candidate-box-prev:before{content:"◄"}.hg-candidate-box-next:before{content:"►"}.hg-candidate-box-next,.hg-candidate-box-prev{align-items:center;color:#969696;cursor:pointer;display:flex;padding:0 10px}.hg-candidate-box-next{border-bottom-right-radius:5px;border-top-right-radius:5px}.hg-candidate-box-prev{border-bottom-left-radius:5px;border-top-left-radius:5px}.hg-candidate-box-btn-active{color:#444} -------------------------------------------------------------------------------- /build/index.d.ts: -------------------------------------------------------------------------------- 1 | import "./polyfills"; 2 | import KeyboardReact from "./components/Keyboard"; 3 | export * from "./interfaces.d"; 4 | export { KeyboardReact }; 5 | export default KeyboardReact; 6 | -------------------------------------------------------------------------------- /build/index.modern.d.ts: -------------------------------------------------------------------------------- 1 | import KeyboardReact from "./components/KeyboardModern"; 2 | export * from "./interfaces.d"; 3 | export { KeyboardReact }; 4 | export default KeyboardReact; 5 | -------------------------------------------------------------------------------- /build/index.modern.esm.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * 3 | * react-simple-keyboard v3.8.80 (index.modern.esm.js - Modern Browsers bundle, ESM output) 4 | * https://github.com/hodgef/react-simple-keyboard 5 | * 6 | * NOTE: This modern browsers bundle (index.modern.esm.js) removes all polyfills 7 | * included in the standard version. Use this if you are supporting 8 | * modern browsers only. Otherwise, use the standard version (index.js). 9 | * 10 | * Copyright (c) Francisco Hodge (https://github.com/hodgef) and project contributors. 11 | * 12 | * This source code is licensed under the MIT license found in the 13 | * LICENSE file in the root directory of this source tree. 14 | * 15 | */ 16 | import*as t from"react";var e={651:function(t){t.exports=function(){var t={d:function(e,n){for(var o in n)t.o(n,o)&&!t.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:n[o]})},o:function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r:function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};function n(t){return function(t){if(Array.isArray(t))return i(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||o(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(t,e){if(t){if("string"==typeof t)return i(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=Array(e);n2&&void 0!==arguments[2]&&arguments[2]?Object.assign({},this.getDefaultDiplay(),e):e||this.getDefaultDiplay())[t]||t}},{key:"getUpdatedInput",value:function(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:n,i=arguments.length>4&&void 0!==arguments[4]&&arguments[4],s=this.getOptions(),a=[n,o,i],r=e;return("{bksp}"===t||"{backspace}"===t)&&r.length>0?r=this.removeAt.apply(this,[r].concat(a)):("{delete}"===t||"{forwarddelete}"===t)&&r.length>0?r=this.removeForwardsAt.apply(this,[r].concat(a)):"{space}"===t?r=this.addStringAt.apply(this,[r," "].concat(a)):"{tab}"!==t||"boolean"==typeof s.tabCharOnTab&&!1===s.tabCharOnTab?"{enter}"!==t&&"{numpadenter}"!==t||!s.newLineOnEnter?t.includes("numpad")&&Number.isInteger(Number(t[t.length-2]))?r=this.addStringAt.apply(this,[r,t[t.length-2]].concat(a)):"{numpaddivide}"===t?r=this.addStringAt.apply(this,[r,"/"].concat(a)):"{numpadmultiply}"===t?r=this.addStringAt.apply(this,[r,"*"].concat(a)):"{numpadsubtract}"===t?r=this.addStringAt.apply(this,[r,"-"].concat(a)):"{numpadadd}"===t?r=this.addStringAt.apply(this,[r,"+"].concat(a)):"{numpaddecimal}"===t?r=this.addStringAt.apply(this,[r,"."].concat(a)):"{"===t||"}"===t?r=this.addStringAt.apply(this,[r,t].concat(a)):t.includes("{")||t.includes("}")||(r=this.addStringAt.apply(this,[r,t].concat(a))):r=this.addStringAt.apply(this,[r,"\n"].concat(a)):r=this.addStringAt.apply(this,[r,"\t"].concat(a)),s.debug&&console.log("Input will be: "+r),r}},{key:"updateCaretPos",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=this.updateCaretPosAction(t,e);this.dispatch((function(t){t.setCaretPosition(n)}))}},{key:"updateCaretPosAction",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=this.getOptions(),o=this.getCaretPosition();return null!=o&&(e?o>0&&(o-=t):o+=t),n.debug&&console.log("Caret at:",o),o}},{key:"addStringAt",value:function(t,e){var n,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t.length,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:t.length,s=arguments.length>4&&void 0!==arguments[4]&&arguments[4];return o||0===o?(n=[t.slice(0,o),e,t.slice(i)].join(""),this.isMaxLengthReached()||s&&this.updateCaretPos(e.length)):n=t+e,n}},{key:"removeAt",value:function(t){var e,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t.length,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t.length,i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(0===n&&0===o)return t;if(n===o){var s=/([\uD800-\uDBFF][\uDC00-\uDFFF])/g;n&&n>=0?t.substring(n-2,n).match(s)?(e=t.substr(0,n-2)+t.substr(n),i&&this.updateCaretPos(2,!0)):(e=t.substr(0,n-1)+t.substr(n),i&&this.updateCaretPos(1,!0)):t.slice(-2).match(s)?(e=t.slice(0,-2),i&&this.updateCaretPos(2,!0)):(e=t.slice(0,-1),i&&this.updateCaretPos(1,!0))}else e=t.slice(0,n)+t.slice(o),i&&this.dispatch((function(t){t.setCaretPosition(n)}));return e}},{key:"removeForwardsAt",value:function(t){var e,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t.length,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t.length,i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];return null!=t&&t.length&&null!==n?(n===o?e=t.substring(n,n+2).match(/([\uD800-\uDBFF][\uDC00-\uDFFF])/g)?t.substr(0,n)+t.substr(n+2):t.substr(0,n)+t.substr(n+1):(e=t.slice(0,n)+t.slice(o),i&&this.dispatch((function(t){t.setCaretPosition(n)}))),e):t}},{key:"handleMaxLength",value:function(t,e){var n=this.getOptions(),o=n.maxLength,i=t[n.inputName||"default"],a=e.length-1>=o;if(e.length<=i.length)return!1;if(Number.isInteger(o))return n.debug&&console.log("maxLength (num) reached:",a),a?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1);if("object"===s(o)){var r=e.length-1>=o[n.inputName||"default"];return n.debug&&console.log("maxLength (obj) reached:",r),r?(this.maxLengthReached=!0,!0):(this.maxLengthReached=!1,!1)}}},{key:"isMaxLengthReached",value:function(){return Boolean(this.maxLengthReached)}},{key:"isTouchDevice",value:function(){return"ontouchstart"in window||navigator.maxTouchPoints}},{key:"pointerEventsSupported",value:function(){return!!window.PointerEvent}},{key:"camelCase",value:function(t){return t?t.toLowerCase().trim().split(/[.\-_\s]/g).reduce((function(t,e){return e.length?t+e[0].toUpperCase()+e.slice(1):t})):""}},{key:"chunkArray",value:function(t,e){return n(Array(Math.ceil(t.length/e))).map((function(n,o){return t.slice(e*o,e+e*o)}))}},{key:"escapeRegex",value:function(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}},{key:"getRtlOffset",value:function(t,e){var n=t,o=e.indexOf("‫");return o=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:s}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,r=!0,u=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return r=t.done,t},e:function(t){u=!0,a=t},f:function(){try{r||null==n.return||n.return()}finally{if(u)throw a}}}}(Object.getOwnPropertyNames(t.prototype));try{for(i.s();!(n=i.n()).done;){var s=n.value;"constructor"===s||"bindMethods"===s||(e[s]=e[s].bind(e))}}catch(t){i.e(t)}finally{i.f()}}}],e&&a(t.prototype,e),i&&a(t,i),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e,i}();r(l,"noop",(function(){}));var c=l;function d(t){return d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},d(t)}function h(t,e){for(var n=0;n1?null===(e=n)||void 0===e?void 0:e.toLowerCase():n}},{key:"keyCodeToKey",value:function(t){return{8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",65:"A",66:"B",67:"C",68:"D",69:"E",70:"F",71:"G",72:"H",73:"I",74:"J",75:"K",76:"L",77:"M",78:"N",79:"O",80:"P",81:"Q",82:"R",83:"S",84:"T",85:"U",86:"V",87:"W",88:"X",89:"Y",90:"Z",91:"Meta",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9",106:"NumpadMultiply",107:"NumpadAdd",109:"NumpadSubtract",110:"NumpadDecimal",111:"NumpadDivide",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"}[t]||""}}],e&&h(t.prototype,e),n&&h(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e,n}();function v(t){return v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},v(t)}function m(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:i();return r(t,e)},u.appendChild(o)}));var l=s>0,c=document.createElement("div");c.classList.add("hg-candidate-box-prev"),l&&c.classList.add("hg-candidate-box-btn-active");var d=function(){l&&n.renderPage({candidateListPages:o,targetElement:i,pageIndex:s-1,nbPages:a,onItemSelected:r})};this.options.useTouchEvents?c.ontouchstart=d:c.onclick=d,this.candidateBoxElement.appendChild(c),this.candidateBoxElement.appendChild(u);var h=st.length)&&(e=t.length);for(var n=0,o=Array(e);n1&&void 0!==arguments[1]?arguments[1]:t;this.caretPosition=t,this.caretPositionEnd=e}},{key:"getInputCandidates",value:function(t){var e=this,n=this.options,o=n.layoutCandidates,i=n.layoutCandidatesCaseSensitiveMatch;if(!o||"object"!==C(o))return{};var s=Object.keys(o).filter((function(n){var o=t.substring(0,e.getCaretPositionEnd()||0)||t,s=new RegExp("".concat(e.utilities.escapeRegex(n),"$"),i?"g":"gi");return!!E(o.matchAll(s)).length}));if(s.length>1){var a=s.sort((function(t,e){return e.length-t.length}))[0];return{candidateKey:a,candidateValue:o[a]}}if(s.length){var r=s[0];return{candidateKey:r,candidateValue:o[r]}}return{}}},{key:"showCandidatesBox",value:function(t,e,n){var o=this;this.candidateBox&&this.candidateBox.show({candidateValue:e,targetElement:n,onSelect:function(e,n){var i=o.options,s=i.layoutCandidatesCaseSensitiveMatch,a=i.disableCandidateNormalization,r=i.enableLayoutCandidatesKeyPress,u=e;a||(u=e.normalize("NFD")),"function"==typeof o.options.beforeInputUpdate&&o.options.beforeInputUpdate(o);var l=o.getInput(o.options.inputName,!0),c=o.getCaretPositionEnd()||0,d=l.substring(0,c||0)||l,h=new RegExp("".concat(o.utilities.escapeRegex(t),"$"),s?"g":"gi"),p=d.replace(h,u),f=l.replace(d,p),y=p.length-d.length,v=(c||l.length)+y;v<0&&(v=0),o.setInput(f,o.options.inputName,!0),o.setCaretPosition(v),r&&"function"==typeof o.options.onKeyPress&&o.options.onKeyPress(e,n),"function"==typeof o.options.onChange&&o.options.onChange(o.getInput(o.options.inputName,!0),n),"function"==typeof o.options.onChangeAll&&o.options.onChangeAll(o.getAllInputs(),n)}})}},{key:"handleButtonClicked",value:function(t,e){var n=this.options,o=n.inputName,i=void 0===o?this.defaultName:o,s=n.debug;if("{//}"!==t){this.input[i]||(this.input[i]=""),"function"==typeof this.options.beforeInputUpdate&&this.options.beforeInputUpdate(this);var a=this.utilities.getUpdatedInput(t,this.input[i],this.caretPosition,this.caretPositionEnd);if(this.utilities.isStandardButton(t)&&this.activeInputElement&&this.input[i]&&this.input[i]===a&&0===this.caretPosition&&this.caretPositionEnd===a.length)return this.setInput("",this.options.inputName,!0),this.setCaretPosition(0),this.activeInputElement.value="",this.activeInputElement.setSelectionRange(0,0),void this.handleButtonClicked(t,e);if("function"==typeof this.options.onKeyPress&&this.options.onKeyPress(t,e),this.input[i]!==a&&(!this.options.inputPattern||this.options.inputPattern&&this.inputPatternIsValid(a))){if(this.options.maxLength&&this.utilities.handleMaxLength(this.input,a))return;var r=this.utilities.getUpdatedInput(t,this.input[i],this.caretPosition,this.caretPositionEnd,!0);if(this.setInput(r,this.options.inputName,!0),s&&console.log("Input changed:",this.getAllInputs()),this.options.debug&&console.log("Caret at: ",this.getCaretPosition(),this.getCaretPositionEnd(),"(".concat(this.keyboardDOMClass,")"),null==e?void 0:e.type),this.options.syncInstanceInputs&&this.syncInstanceInputs(),"function"==typeof this.options.onChange&&this.options.onChange(this.getInput(this.options.inputName,!0),e),"function"==typeof this.options.onChangeAll&&this.options.onChangeAll(this.getAllInputs(),e),null!=e&&e.target&&this.options.enableLayoutCandidates){var u,l=this.getInputCandidates(a),c=l.candidateKey,d=l.candidateValue;c&&d?this.showCandidatesBox(c,d,this.keyboardDOM):null===(u=this.candidateBox)||void 0===u||u.destroy()}}this.caretPositionEnd&&this.caretPosition!==this.caretPositionEnd&&(this.setCaretPosition(this.caretPositionEnd,this.caretPositionEnd),this.activeInputElement&&this.activeInputElement.setSelectionRange(this.caretPositionEnd,this.caretPositionEnd),this.options.debug&&console.log("Caret position aligned",this.caretPosition)),s&&console.log("Key pressed:",t)}}},{key:"getMouseHold",value:function(){return this.isMouseHold}},{key:"setMouseHold",value:function(t){this.options.syncInstanceInputs?this.dispatch((function(e){e.isMouseHold=t})):this.isMouseHold=t}},{key:"handleButtonMouseDown",value:function(t,e){var n=this;e&&(this.options.preventMouseDownDefault&&e.preventDefault(),this.options.stopMouseDownPropagation&&e.stopPropagation(),e.target.classList.add(this.activeButtonClass)),this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdTimeout&&clearTimeout(this.holdTimeout),this.setMouseHold(!0),this.options.disableButtonHold||(this.holdTimeout=window.setTimeout((function(){(n.getMouseHold()&&(!t.includes("{")&&!t.includes("}")||"{delete}"===t||"{backspace}"===t||"{bksp}"===t||"{space}"===t||"{tab}"===t)||"{arrowright}"===t||"{arrowleft}"===t||"{arrowup}"===t||"{arrowdown}"===t)&&(n.options.debug&&console.log("Button held:",t),n.handleButtonHold(t)),clearTimeout(n.holdTimeout)}),500))}},{key:"handleButtonMouseUp",value:function(t,e){var n=this;e&&(this.options.preventMouseUpDefault&&e.preventDefault&&e.preventDefault(),this.options.stopMouseUpPropagation&&e.stopPropagation&&e.stopPropagation(),!(e.target===this.keyboardDOM||e.target&&this.keyboardDOM.contains(e.target)||this.candidateBox&&this.candidateBox.candidateBoxElement&&(e.target===this.candidateBox.candidateBoxElement||e.target&&this.candidateBox.candidateBoxElement.contains(e.target)))&&this.candidateBox&&this.candidateBox.destroy()),this.recurseButtons((function(t){t.classList.remove(n.activeButtonClass)})),this.setMouseHold(!1),this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),t&&"function"==typeof this.options.onKeyReleased&&this.options.onKeyReleased(t,e)}},{key:"handleKeyboardContainerMouseDown",value:function(t){this.options.preventMouseDownDefault&&t.preventDefault()}},{key:"handleButtonHold",value:function(t){var e=this;this.holdInteractionTimeout&&clearTimeout(this.holdInteractionTimeout),this.holdInteractionTimeout=window.setTimeout((function(){e.getMouseHold()?(e.handleButtonClicked(t),e.handleButtonHold(t)):clearTimeout(e.holdInteractionTimeout)}),100)}},{key:"syncInstanceInputs",value:function(){var t=this;this.dispatch((function(e){e.replaceInput(t.input),e.setCaretPosition(t.caretPosition,t.caretPositionEnd)}))}},{key:"clearInput",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.options.inputName||this.defaultName;this.input[t]="",this.setCaretPosition(0),this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"getInput",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.options.inputName||this.defaultName,e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return this.options.syncInstanceInputs&&!e&&this.syncInstanceInputs(),this.options.rtl?"‫"+this.input[t].replace("‫","").replace("‬","")+"‬":this.input[t]}},{key:"getAllInputs",value:function(){var t=this,e={};return Object.keys(this.input).forEach((function(n){e[n]=t.getInput(n,!0)})),e}},{key:"setInput",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.options.inputName||this.defaultName,n=arguments.length>2?arguments[2]:void 0;this.input[e]=t,!n&&this.options.syncInstanceInputs&&this.syncInstanceInputs()}},{key:"replaceInput",value:function(t){this.input=t}},{key:"setOptions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=this.changedOptions(t);this.options=Object.assign(this.options,t),e.length&&(this.options.debug&&console.log("changedOptions",e),this.onSetOptions(e),this.render())}},{key:"changedOptions",value:function(t){var e=this;return Object.keys(t).filter((function(n){return JSON.stringify(t[n])!==JSON.stringify(e.options[n])}))}},{key:"onSetOptions",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];t.includes("layoutName")&&this.candidateBox&&this.candidateBox.destroy(),(t.includes("layoutCandidatesPageSize")||t.includes("layoutCandidates"))&&this.candidateBox&&(this.candidateBox.destroy(),this.candidateBox=new w({utilities:this.utilities,options:this.options}))}},{key:"resetRows",value:function(){this.keyboardRowsDOM&&this.keyboardRowsDOM.remove(),this.keyboardDOM.className=this.keyboardDOMClass,this.keyboardDOM.setAttribute("data-skInstance",this.currentInstanceName),this.buttonElements={}}},{key:"dispatch",value:function(t){if(!window.SimpleKeyboardInstances)throw console.warn("SimpleKeyboardInstances is not defined. Dispatch cannot be called."),new Error("INSTANCES_VAR_ERROR");return Object.keys(window.SimpleKeyboardInstances).forEach((function(e){t(window.SimpleKeyboardInstances[e],e)}))}},{key:"addButtonTheme",value:function(t,e){var n=this;e&&t&&(t.split(" ").forEach((function(o){e.split(" ").forEach((function(e){n.options.buttonTheme||(n.options.buttonTheme=[]);var i=!1;n.options.buttonTheme.map((function(t){if(null!=t&&t.class.split(" ").includes(e)){i=!0;var n=t.buttons.split(" ");n.includes(o)||(i=!0,n.push(o),t.buttons=n.join(" "))}return t})),i||n.options.buttonTheme.push({class:e,buttons:t})}))})),this.render())}},{key:"removeButtonTheme",value:function(t,e){var n=this;if(!t&&!e)return this.options.buttonTheme=[],void this.render();t&&Array.isArray(this.options.buttonTheme)&&this.options.buttonTheme.length&&(t.split(" ").forEach((function(t){var o;null===(o=n.options)||void 0===o||null===(o=o.buttonTheme)||void 0===o||o.map((function(o,i){if(o&&e&&e.includes(o.class)||!e){var s,a,r=null===(s=o)||void 0===s?void 0:s.buttons.split(" ").filter((function(e){return e!==t}));o&&null!=r&&r.length?o.buttons=r.join(" "):(null===(a=n.options.buttonTheme)||void 0===a||a.splice(i,1),o=null)}return o}))})),this.render())}},{key:"getButtonElement",value:function(t){var e,n=this.buttonElements[t];return n&&(e=n.length>1?n:n[0]),e}},{key:"inputPatternIsValid",value:function(t){var e,n=this.options.inputPattern;if((e=n instanceof RegExp?n:n[this.options.inputName||this.defaultName])&&t){var o=e.test(t);return this.options.debug&&console.log('inputPattern ("'.concat(e,'"): ').concat(o?"passed":"did not pass!")),o}return!0}},{key:"setEventListeners",value:function(){if(this.isFirstKeyboardInstance||!this.allKeyboardInstances){this.options.debug&&console.log("Caret handling started (".concat(this.keyboardDOMClass,")"));var t=this.options.physicalKeyboardHighlightPreventDefault,e=void 0!==t&&t;document.addEventListener("keyup",this.handleKeyUp,e),document.addEventListener("keydown",this.handleKeyDown,e),document.addEventListener("mouseup",this.handleMouseUp),document.addEventListener("touchend",this.handleTouchEnd),this.options.updateCaretOnSelectionChange&&document.addEventListener("selectionchange",this.handleSelectionChange),document.addEventListener("select",this.handleSelect)}}},{key:"handleKeyUp",value:function(t){this.caretEventHandler(t),this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyUp(t)}},{key:"handleKeyDown",value:function(t){this.options.physicalKeyboardHighlight&&this.physicalKeyboard.handleHighlightKeyDown(t)}},{key:"handleMouseUp",value:function(t){this.caretEventHandler(t)}},{key:"handleTouchEnd",value:function(t){this.caretEventHandler(t)}},{key:"handleSelect",value:function(t){this.caretEventHandler(t)}},{key:"handleSelectionChange",value:function(t){navigator.userAgent.includes("Firefox")||this.caretEventHandler(t)}},{key:"caretEventHandler",value:function(t){var e,n=this;t.target.tagName&&(e=t.target.tagName.toLowerCase()),this.dispatch((function(o){var i=t.target===o.keyboardDOM||t.target&&o.keyboardDOM.contains(t.target);if(n.options.syncInstanceInputs&&Array.isArray(t.path)&&(i=t.path.some((function(t){var e;return null==t||null===(e=t.hasAttribute)||void 0===e?void 0:e.call(t,"data-skInstance")}))),("textarea"===e||"input"===e&&["text","search","url","tel","password"].includes(t.target.type))&&!o.options.disableCaretPositioning){var s=t.target.selectionStart,a=t.target.selectionEnd;o.options.rtl&&(s=o.utilities.getRtlOffset(s,o.getInput()),a=o.utilities.getRtlOffset(a,o.getInput())),o.setCaretPosition(s,a),o.activeInputElement=t.target,o.options.debug&&console.log("Caret at: ",o.getCaretPosition(),o.getCaretPositionEnd(),t&&t.target.tagName.toLowerCase(),"(".concat(o.keyboardDOMClass,")"),null==t?void 0:t.type)}else!o.options.disableCaretPositioning&&i||"selectionchange"===(null==t?void 0:t.type)||(o.setCaretPosition(null),o.activeInputElement=null,o.options.debug&&console.log('Caret position reset due to "'.concat(null==t?void 0:t.type,'" event'),t))}))}},{key:"recurseButtons",value:function(t){var e=this;t&&Object.keys(this.buttonElements).forEach((function(n){return e.buttonElements[n].forEach(t)}))}},{key:"destroy",value:function(){this.options.debug&&console.log("Destroying simple-keyboard instance: ".concat(this.currentInstanceName));var t=this.options.physicalKeyboardHighlightPreventDefault,e=void 0!==t&&t;document.removeEventListener("keyup",this.handleKeyUp,e),document.removeEventListener("keydown",this.handleKeyDown,e),document.removeEventListener("mouseup",this.handleMouseUp),document.removeEventListener("touchend",this.handleTouchEnd),document.removeEventListener("select",this.handleSelect),this.options.updateCaretOnSelectionChange&&document.removeEventListener("selectionchange",this.handleSelectionChange),document.onpointerup=null,document.ontouchend=null,document.ontouchcancel=null,document.onmouseup=null,this.recurseButtons((function(t){t&&(t.onpointerdown=null,t.onpointerup=null,t.onpointercancel=null,t.ontouchstart=null,t.ontouchend=null,t.ontouchcancel=null,t.onclick=null,t.onmousedown=null,t.onmouseup=null,t.remove(),t=null)})),this.keyboardDOM.onpointerdown=null,this.keyboardDOM.ontouchstart=null,this.keyboardDOM.onmousedown=null,this.resetRows(),this.candidateBox&&(this.candidateBox.destroy(),this.candidateBox=null),this.activeInputElement=null,this.keyboardDOM.removeAttribute("data-skInstance"),this.keyboardDOM.innerHTML="",window.SimpleKeyboardInstances[this.currentInstanceName]=null,delete window.SimpleKeyboardInstances[this.currentInstanceName],this.initialized=!1}},{key:"getButtonThemeClasses",value:function(t){var e=this.options.buttonTheme,n=[];return Array.isArray(e)&&e.forEach((function(e){if(e&&e.class&&"string"==typeof e.class&&e.buttons&&"string"==typeof e.buttons){var o=e.class.split(" ");e.buttons.split(" ").includes(t)&&(n=[].concat(E(n),E(o)))}else console.warn('Incorrect "buttonTheme". Please check the documentation.',e)})),n}},{key:"setDOMButtonAttributes",value:function(t,e){var n=this.options.buttonAttributes;Array.isArray(n)&&n.forEach((function(n){n.attribute&&"string"==typeof n.attribute&&n.value&&"string"==typeof n.value&&n.buttons&&"string"==typeof n.buttons?n.buttons.split(" ").includes(t)&&e(n.attribute,n.value):console.warn('Incorrect "buttonAttributes". Please check the documentation.',n)}))}},{key:"onTouchDeviceDetected",value:function(){this.processAutoTouchEvents(),this.disableContextualWindow()}},{key:"disableContextualWindow",value:function(){window.oncontextmenu=function(t){var e;if(null!==(e=t.target.classList)&&void 0!==e&&e.contains("hg-button"))return t.preventDefault(),t.stopPropagation(),!1}}},{key:"processAutoTouchEvents",value:function(){this.options.autoUseTouchEvents&&(this.options.useTouchEvents=!0,this.options.debug&&console.log("autoUseTouchEvents: Touch device detected, useTouchEvents enabled."))}},{key:"onInit",value:function(){this.options.debug&&console.log("".concat(this.keyboardDOMClass," Initialized")),this.setEventListeners(),"function"==typeof this.options.onInit&&this.options.onInit(this)}},{key:"beforeFirstRender",value:function(){this.utilities.isTouchDevice()&&this.onTouchDeviceDetected(),"function"==typeof this.options.beforeFirstRender&&this.options.beforeFirstRender(this),this.isFirstKeyboardInstance&&this.utilities.pointerEventsSupported()&&!this.options.useTouchEvents&&!this.options.useMouseEvents&&this.options.debug&&console.log("Using PointerEvents as it is supported by this browser"),this.options.useTouchEvents&&this.options.debug&&console.log("useTouchEvents has been enabled. Only touch events will be used.")}},{key:"beforeRender",value:function(){"function"==typeof this.options.beforeRender&&this.options.beforeRender(this)}},{key:"onRender",value:function(){"function"==typeof this.options.onRender&&this.options.onRender(this)}},{key:"onModulesLoaded",value:function(){"function"==typeof this.options.onModulesLoaded&&this.options.onModulesLoaded(this)}},{key:"loadModules",value:function(){var t=this;Array.isArray(this.options.modules)&&(this.options.modules.forEach((function(e){var n=t.utilities.isConstructor(e)?new e(t):e(t);n.init&&n.init(t)})),this.keyboardPluginClasses="modules-loaded",this.render(),this.onModulesLoaded())}},{key:"getModuleProp",value:function(t,e){return!!this.modules[t]&&this.modules[t][e]}},{key:"getModulesList",value:function(){return Object.keys(this.modules)}},{key:"parseRowDOMContainers",value:function(t,e,n,o){var i=this,s=Array.from(t.children),a=0;return s.length&&n.forEach((function(n,r){var u=o[r];if(!(u&&u>n))return!1;var l=n-a,c=u-a,d=document.createElement("div");d.className+="hg-button-container";var h="".concat(i.options.layoutName,"-r").concat(e,"c").concat(r);d.setAttribute("data-skUID",h);var p=s.splice(l,c-l+1);a+=c-l,p.forEach((function(t){return d.appendChild(t)})),s.splice(l,0,d),t.innerHTML="",s.forEach((function(e){return t.appendChild(e)})),i.options.debug&&console.log("rowDOMContainer",p,l,c,a+1)})),t}},{key:"render",value:function(){var t=this;this.resetRows(),this.initialized||this.beforeFirstRender(),this.beforeRender();var e="hg-layout-".concat(this.options.layoutName),n=this.options.layout||{default:["` 1 2 3 4 5 6 7 8 9 0 - = {bksp}","{tab} q w e r t y u i o p [ ] \\","{lock} a s d f g h j k l ; ' {enter}","{shift} z x c v b n m , . / {shift}",".com @ {space}"],shift:["~ ! @ # $ % ^ & * ( ) _ + {bksp}","{tab} Q W E R T Y U I O P { } |",'{lock} A S D F G H J K L : " {enter}',"{shift} Z X C V B N M < > ? {shift}",".com @ {space}"]},o=this.options.useTouchEvents||!1,i=o?"hg-touch-events":"",s=this.options.useMouseEvents||!1,a=this.options.disableRowButtonContainers;this.keyboardDOM.className=this.getKeyboardClassString(this.options.theme,e,this.keyboardPluginClasses,i),this.keyboardDOM.setAttribute("data-skInstance",this.currentInstanceName),this.keyboardRowsDOM=document.createElement("div"),this.keyboardRowsDOM.className="hg-rows",n[this.options.layoutName||this.defaultName].forEach((function(e,n){var i=e.split(" ");t.options.excludeFromLayout&&t.options.excludeFromLayout[t.options.layoutName||t.defaultName]&&(i=i.filter((function(e){return t.options.excludeFromLayout&&!t.options.excludeFromLayout[t.options.layoutName||t.defaultName].includes(e)})));var r=document.createElement("div");r.className+="hg-row";var u=[],l=[];i.forEach((function(e,i){var c,d=!a&&"string"==typeof e&&e.length>1&&0===e.indexOf("["),h=!a&&"string"==typeof e&&e.length>1&&e.indexOf("]")===e.length-1;d&&(u.push(i),e=e.replace(/\[/g,"")),h&&(l.push(i),e=e.replace(/\]/g,""));var p=t.utilities.getButtonClass(e),f=t.utilities.getButtonDisplayName(e,t.options.display,t.options.mergeDisplay),y=t.options.useButtonTag?"button":"div",v=document.createElement(y);v.className+="hg-button ".concat(p),(c=v.classList).add.apply(c,E(t.getButtonThemeClasses(e))),t.setDOMButtonAttributes(e,(function(t,e){v.setAttribute(t,e)})),t.activeButtonClass="hg-activeButton",!t.utilities.pointerEventsSupported()||o||s?o?(v.ontouchstart=function(n){t.handleButtonClicked(e,n),t.handleButtonMouseDown(e,n)},v.ontouchend=function(n){t.handleButtonMouseUp(e,n)},v.ontouchcancel=function(n){t.handleButtonMouseUp(e,n)}):(v.onclick=function(n){t.setMouseHold(!1),"function"==typeof t.options.onKeyReleased||t.options.useMouseEvents&&t.options.clickOnMouseDown||t.handleButtonClicked(e,n)},v.onmousedown=function(n){("function"==typeof t.options.onKeyReleased||t.options.useMouseEvents&&t.options.clickOnMouseDown)&&!t.isMouseHold&&t.handleButtonClicked(e,n),t.handleButtonMouseDown(e,n)},v.onmouseup=function(n){t.handleButtonMouseUp(e,n)}):(v.onpointerdown=function(n){t.handleButtonClicked(e,n),t.handleButtonMouseDown(e,n)},v.onpointerup=function(n){t.handleButtonMouseUp(e,n)},v.onpointercancel=function(n){t.handleButtonMouseUp(e,n)}),v.setAttribute("data-skBtn",e);var m="".concat(t.options.layoutName,"-r").concat(n,"b").concat(i);v.setAttribute("data-skBtnUID",m);var g=document.createElement("span");g.innerHTML=f,v.appendChild(g),t.buttonElements[e]||(t.buttonElements[e]=[]),t.buttonElements[e].push(v),r.appendChild(v)})),r=t.parseRowDOMContainers(r,n,u,l),t.keyboardRowsDOM.appendChild(r)})),this.keyboardDOM.appendChild(this.keyboardRowsDOM),this.onRender(),this.initialized||(this.initialized=!0,!this.utilities.pointerEventsSupported()||o||s?o?(document.ontouchend=function(e){return t.handleButtonMouseUp(void 0,e)},document.ontouchcancel=function(e){return t.handleButtonMouseUp(void 0,e)},this.keyboardDOM.ontouchstart=function(e){return t.handleKeyboardContainerMouseDown(e)}):o||(document.onmouseup=function(e){return t.handleButtonMouseUp(void 0,e)},this.keyboardDOM.onmousedown=function(e){return t.handleKeyboardContainerMouseDown(e)}):(document.onpointerup=function(e){return t.handleButtonMouseUp(void 0,e)},this.keyboardDOM.onpointerdown=function(e){return t.handleKeyboardContainerMouseDown(e)}),this.onInit())}}],e&&I(t.prototype,e),n&&I(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e,n}(),B=D,A=B;return e}()}},n={};function o(t){var i=n[t];if(void 0!==i)return i.exports;var s=n[t]={exports:{}};return e[t].call(s.exports,s,s.exports,o),s.exports}o.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);const i=(t=>{var e={};return o.d(e,t),e})({createElement:()=>t.createElement,useEffect:()=>t.useEffect,useRef:()=>t.useRef});function s(t){return s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},s(t)}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,o)}return n}function r(t){for(var e=1;e void; 6 | }; 7 | } 8 | // Generated by dts-bundle v0.7.3 9 | /** 10 | * Root class for simple-keyboard. 11 | * This class: 12 | * - Parses the options 13 | * - Renders the rows and buttons 14 | * - Handles button functionality 15 | */ 16 | export interface SimpleKeyboard { 17 | input: KeyboardInput; 18 | options: KeyboardOptions; 19 | utilities: Utilities; 20 | caretPosition: number | null; 21 | caretPositionEnd: number | null; 22 | keyboardDOM: KeyboardElement; 23 | keyboardPluginClasses: string; 24 | keyboardDOMClass: string; 25 | buttonElements: KeyboardButtonElements; 26 | currentInstanceName: string; 27 | allKeyboardInstances: { 28 | [key: string]: SimpleKeyboard; 29 | }; 30 | keyboardInstanceNames: string[]; 31 | isFirstKeyboardInstance: boolean; 32 | physicalKeyboard: PhysicalKeyboard; 33 | modules: { 34 | [key: string]: any; 35 | }; 36 | activeButtonClass: string; 37 | holdInteractionTimeout: number; 38 | holdTimeout: number; 39 | isMouseHold: boolean; 40 | initialized: boolean; 41 | candidateBox: CandidateBox | null; 42 | keyboardRowsDOM: KeyboardElement; 43 | defaultName: string; 44 | activeInputElement: HTMLInputElement | HTMLTextAreaElement | null; 45 | /** 46 | * Creates an instance of SimpleKeyboard 47 | * @param {Array} selectorOrOptions If first parameter is a string, it is considered the container class. The second parameter is then considered the options object. If first parameter is an object, it is considered the options object. 48 | */ 49 | constructor: (selectorOrOptions?: string | HTMLDivElement | KeyboardOptions, keyboardOptions?: KeyboardOptions) => any 50 | /** 51 | * parseParams 52 | */ 53 | handleParams: (selectorOrOptions?: string | HTMLDivElement | KeyboardOptions, keyboardOptions?: KeyboardOptions) => { 54 | keyboardDOMClass: string; 55 | keyboardDOM: KeyboardElement; 56 | options: Partial; 57 | }; 58 | /** 59 | * Getters 60 | */ 61 | getOptions: () => KeyboardOptions; 62 | getCaretPosition: () => number | null; 63 | getCaretPositionEnd: () => number | null; 64 | /** 65 | * Changes the internal caret position 66 | * @param {number} position The caret's start position 67 | * @param {number} positionEnd The caret's end position 68 | */ 69 | setCaretPosition(position: number | null, endPosition?: number | null): void; 70 | /** 71 | * Retrieve the candidates for a given input 72 | * @param input The input string to check 73 | */ 74 | getInputCandidates(input: string): { 75 | candidateKey: string; 76 | candidateValue: string; 77 | } | Record; 78 | /** 79 | * Shows a suggestion box with a list of candidate words 80 | * @param candidates The chosen candidates string as defined in the layoutCandidates option 81 | * @param targetElement The element next to which the candidates box will be shown 82 | */ 83 | showCandidatesBox(candidateKey: string, candidateValue: string, targetElement: KeyboardElement): void; 84 | /** 85 | * Handles clicks made to keyboard buttons 86 | * @param {string} button The button's layout name. 87 | */ 88 | handleButtonClicked(button: string, e?: KeyboardHandlerEvent): void; 89 | /** 90 | * Get mouse hold state 91 | */ 92 | getMouseHold(): boolean; 93 | /** 94 | * Mark mouse hold state as set 95 | */ 96 | setMouseHold(value: boolean): void; 97 | /** 98 | * Handles button mousedown 99 | */ 100 | handleButtonMouseDown(button: string, e: KeyboardHandlerEvent): void; 101 | /** 102 | * Handles button mouseup 103 | */ 104 | handleButtonMouseUp(button?: string, e?: KeyboardHandlerEvent): void; 105 | /** 106 | * Handles container mousedown 107 | */ 108 | handleKeyboardContainerMouseDown(e: KeyboardHandlerEvent): void; 109 | /** 110 | * Handles button hold 111 | */ 112 | handleButtonHold(button: string): void; 113 | /** 114 | * Send a command to all simple-keyboard instances (if you have several instances). 115 | */ 116 | syncInstanceInputs(): void; 117 | /** 118 | * Clear the keyboard’s input. 119 | * @param {string} [inputName] optional - the internal input to select 120 | */ 121 | clearInput(inputName?: string): void; 122 | /** 123 | * Get the keyboard’s input (You can also get it from the onChange prop). 124 | * @param {string} [inputName] optional - the internal input to select 125 | */ 126 | getInput(inputName?: string, skipSync?: boolean): string; 127 | /** 128 | * Get all simple-keyboard inputs 129 | */ 130 | getAllInputs(): KeyboardInput; 131 | /** 132 | * Set the keyboard’s input. 133 | * @param {string} input the input value 134 | * @param {string} inputName optional - the internal input to select 135 | */ 136 | setInput(input: string, inputName?: string, skipSync?: boolean): void; 137 | /** 138 | * Replace the input object (`keyboard.input`) 139 | * @param {object} inputObj The input object 140 | */ 141 | replaceInput(inputObj: KeyboardInput): void; 142 | /** 143 | * Set new option or modify existing ones after initialization. 144 | * @param {object} options The options to set 145 | */ 146 | setOptions(options?: {}): void; 147 | /** 148 | * Detecting changes to non-function options 149 | * This allows us to ascertain whether a button re-render is needed 150 | */ 151 | changedOptions(newOptions: Partial): string[]; 152 | /** 153 | * Executing actions depending on changed options 154 | * @param {object} options The options to set 155 | */ 156 | onSetOptions(changedOptions?: string[]): void; 157 | /** 158 | * Remove all keyboard rows and reset keyboard values. 159 | * Used internally between re-renders. 160 | */ 161 | resetRows(): void; 162 | /** 163 | * Send a command to all simple-keyboard instances at once (if you have multiple instances). 164 | * @param {function(instance: object, key: string)} callback Function to run on every instance 165 | */ 166 | dispatch(callback: (instance: SimpleKeyboard, key?: string) => void): void; 167 | /** 168 | * Adds/Modifies an entry to the `buttonTheme`. Basically a way to add a class to a button. 169 | * @param {string} buttons List of buttons to select (separated by a space). 170 | * @param {string} className Classes to give to the selected buttons (separated by space). 171 | */ 172 | addButtonTheme(buttons: string, className: string): void; 173 | /** 174 | * Removes/Amends an entry to the `buttonTheme`. Basically a way to remove a class previously added to a button through buttonTheme or addButtonTheme. 175 | * @param {string} buttons List of buttons to select (separated by a space). 176 | * @param {string} className Classes to give to the selected buttons (separated by space). 177 | */ 178 | removeButtonTheme(buttons: string, className: string): void; 179 | /** 180 | * Get the DOM Element of a button. If there are several buttons with the same name, an array of the DOM Elements is returned. 181 | * @param {string} button The button layout name to select 182 | */ 183 | getButtonElement(button: string): KeyboardElement | KeyboardElement[] | undefined; 184 | /** 185 | * This handles the "inputPattern" option 186 | * by checking if the provided inputPattern passes 187 | */ 188 | inputPatternIsValid(inputVal: string): boolean; 189 | /** 190 | * Handles simple-keyboard event listeners 191 | */ 192 | setEventListeners(): void; 193 | /** 194 | * Event Handler: KeyUp 195 | */ 196 | handleKeyUp(event: KeyboardHandlerEvent): void; 197 | /** 198 | * Event Handler: KeyDown 199 | */ 200 | handleKeyDown(event: KeyboardHandlerEvent): void; 201 | /** 202 | * Event Handler: MouseUp 203 | */ 204 | handleMouseUp(event: KeyboardHandlerEvent): void; 205 | /** 206 | * Event Handler: TouchEnd 207 | */ 208 | handleTouchEnd(event: KeyboardHandlerEvent): void; 209 | /** 210 | * Event Handler: Select 211 | */ 212 | handleSelect(event: KeyboardHandlerEvent): void; 213 | /** 214 | * Event Handler: SelectionChange 215 | */ 216 | handleSelectionChange(event: KeyboardHandlerEvent): void; 217 | /** 218 | * Called by {@link setEventListeners} when an event that warrants a cursor position update is triggered 219 | */ 220 | caretEventHandler(event: KeyboardHandlerEvent): void; 221 | /** 222 | * Execute an operation on each button 223 | */ 224 | recurseButtons(fn: any): void; 225 | /** 226 | * Destroy keyboard listeners and DOM elements 227 | */ 228 | destroy(): void; 229 | /** 230 | * Process buttonTheme option 231 | */ 232 | getButtonThemeClasses(button: string): string[]; 233 | /** 234 | * Process buttonAttributes option 235 | */ 236 | setDOMButtonAttributes(button: string, callback: any): void; 237 | onTouchDeviceDetected(): void; 238 | /** 239 | * Disabling contextual window for hg-button 240 | */ 241 | disableContextualWindow(): void; 242 | /** 243 | * Process autoTouchEvents option 244 | */ 245 | processAutoTouchEvents(): void; 246 | /** 247 | * Executes the callback function once simple-keyboard is rendered for the first time (on initialization). 248 | */ 249 | onInit(): void; 250 | /** 251 | * Executes the callback function before a simple-keyboard render. 252 | */ 253 | beforeFirstRender(): void; 254 | /** 255 | * Executes the callback function before a simple-keyboard render. 256 | */ 257 | beforeRender(): void; 258 | /** 259 | * Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts). 260 | */ 261 | onRender(): void; 262 | /** 263 | * Executes the callback function once all modules have been loaded 264 | */ 265 | onModulesLoaded(): void; 266 | /** 267 | * Register module 268 | */ 269 | registerModule: (name: string, initCallback: any) => void; 270 | /** 271 | * Load modules 272 | */ 273 | loadModules(): void; 274 | /** 275 | * Get module prop 276 | */ 277 | getModuleProp(name: string, prop: string): any; 278 | /** 279 | * getModulesList 280 | */ 281 | getModulesList(): string[]; 282 | /** 283 | * Parse Row DOM containers 284 | */ 285 | parseRowDOMContainers(rowDOM: HTMLDivElement, rowIndex: number, containerStartIndexes: number[], containerEndIndexes: number[]): HTMLDivElement; 286 | /** 287 | * getKeyboardClassString 288 | */ 289 | getKeyboardClassString: (...baseDOMClasses: any[]) => string; 290 | /** 291 | * Renders rows and buttons as per options 292 | */ 293 | render(): void; 294 | } 295 | export interface SKWindow extends Window { 296 | SimpleKeyboardInstances?: any; 297 | } 298 | export interface KeyboardLayoutObject { 299 | [key: string]: string[]; 300 | } 301 | export type KeyboardButtonTheme = { 302 | class: string; 303 | buttons: string; 304 | } | null; 305 | export interface KeyboardButtonAttributes { 306 | attribute: string; 307 | value: string; 308 | buttons: string; 309 | } 310 | export interface KeyboardInput { 311 | [key: string]: string; 312 | } 313 | export type CandidateBoxParams = { 314 | utilities: Utilities; 315 | options: KeyboardOptions; 316 | }; 317 | export type CandidateBoxShowParams = { 318 | candidateValue: string; 319 | targetElement: KeyboardElement; 320 | onSelect: (selectedCandidate: string, e: MouseEvent) => void; 321 | }; 322 | export type CandidateBoxRenderParams = { 323 | candidateListPages: string[][]; 324 | targetElement: KeyboardElement; 325 | pageIndex: number; 326 | nbPages: number; 327 | onItemSelected: (selectedCandidate: string, e: MouseEvent) => void; 328 | }; 329 | export type KeyboardElement = HTMLDivElement | HTMLButtonElement; 330 | export type KeyboardHandlerEvent = any; 331 | export interface KeyboardButtonElements { 332 | [key: string]: KeyboardElement[]; 333 | } 334 | export interface UtilitiesParams { 335 | getOptions: () => KeyboardOptions; 336 | getCaretPosition: () => number | null; 337 | getCaretPositionEnd: () => number | null; 338 | dispatch: any; 339 | } 340 | export interface PhysicalKeyboardParams { 341 | getOptions: () => KeyboardOptions; 342 | dispatch: any; 343 | } 344 | export interface KeyboardOptions { 345 | /** 346 | * Modify the keyboard layout. 347 | */ 348 | layout?: KeyboardLayoutObject; 349 | /** 350 | * Specifies which layout should be used. 351 | */ 352 | layoutName?: string; 353 | /** 354 | * Replaces variable buttons (such as `{bksp}`) with a human-friendly name (e.g.: `backspace`). 355 | */ 356 | display?: { 357 | [button: string]: string; 358 | }; 359 | /** 360 | * By default, when you set the display property, you replace the default one. This setting merges them instead. 361 | */ 362 | mergeDisplay?: boolean; 363 | /** 364 | * A prop to add your own css classes to the keyboard wrapper. You can add multiple classes separated by a space. 365 | */ 366 | theme?: string; 367 | /** 368 | * A prop to add your own css classes to one or several buttons. 369 | */ 370 | buttonTheme?: KeyboardButtonTheme[]; 371 | /** 372 | * A prop to add your own attributes to one or several buttons. 373 | */ 374 | buttonAttributes?: KeyboardButtonAttributes[]; 375 | /** 376 | * Runs a `console.log` every time a key is pressed. Displays the buttons pressed and the current input. 377 | */ 378 | debug?: boolean; 379 | /** 380 | * Specifies whether clicking the "ENTER" button will input a newline (`\n`) or not. 381 | */ 382 | newLineOnEnter?: boolean; 383 | /** 384 | * Specifies whether clicking the "TAB" button will input a tab character (`\t`) or not. 385 | */ 386 | tabCharOnTab?: boolean; 387 | /** 388 | * Allows you to use a single simple-keyboard instance for several inputs. 389 | */ 390 | inputName?: string; 391 | /** 392 | * `number`: Restrains all of simple-keyboard inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute. 393 | * 394 | * `{ [inputName: string]: number }`: Restrains simple-keyboard’s individual inputs to a certain length. This should be used in addition to the input element’s maxlengthattribute. 395 | */ 396 | maxLength?: any; 397 | /** 398 | * When set to true, this option synchronizes the internal input of every simple-keyboard instance. 399 | */ 400 | syncInstanceInputs?: boolean; 401 | /** 402 | * Enable highlighting of keys pressed on physical keyboard. 403 | */ 404 | physicalKeyboardHighlight?: boolean; 405 | /** 406 | * Calls handler for a button highlighted by physicalKeyboardHighlight 407 | * In other words, this calls keyboard.handleButtonClicked(buttonName) on the highlighted button 408 | */ 409 | physicalKeyboardHighlightPress?: boolean; 410 | /** 411 | * Trigger click on a button's element when using physicalKeyboardHighlightPress 412 | * In other words, this calls button.click() on the highlighted button 413 | */ 414 | physicalKeyboardHighlightPressUseClick?: boolean; 415 | /** 416 | * Whether physicalKeyboardHighlightPress should use pointer events to trigger buttons. 417 | */ 418 | physicalKeyboardHighlightPressUsePointerEvents?: boolean; 419 | /** 420 | * Define the text color that the physical keyboard highlighted key should have. 421 | */ 422 | physicalKeyboardHighlightTextColor?: string; 423 | /** 424 | * Define the background color that the physical keyboard highlighted key should have. 425 | */ 426 | physicalKeyboardHighlightBgColor?: string; 427 | /** 428 | * Whether physicalKeyboardHighlight should use preventDefault to disable default browser actions. 429 | */ 430 | physicalKeyboardHighlightPreventDefault?: boolean; 431 | /** 432 | * Calling preventDefault for the mousedown events keeps the focus on the input. 433 | */ 434 | preventMouseDownDefault?: boolean; 435 | /** 436 | * Calling preventDefault for the mouseup events. 437 | */ 438 | preventMouseUpDefault?: boolean; 439 | /** 440 | * Stops pointer down events on simple-keyboard buttons from bubbling to parent elements. 441 | */ 442 | stopMouseDownPropagation?: boolean; 443 | /** 444 | * Stops pointer up events on simple-keyboard buttons from bubbling to parent elements. 445 | */ 446 | stopMouseUpPropagation?: boolean; 447 | /** 448 | * Render buttons as a button element instead of a div element. 449 | */ 450 | useButtonTag?: boolean; 451 | /** 452 | * A prop to ensure characters are always be added/removed at the end of the string. 453 | */ 454 | disableCaretPositioning?: boolean; 455 | /** 456 | * Restrains input(s) change to the defined regular expression pattern. 457 | */ 458 | inputPattern?: any; 459 | /** 460 | * Instructs simple-keyboard to use touch events instead of click events. 461 | */ 462 | useTouchEvents?: boolean; 463 | /** 464 | * Enable useTouchEvents automatically when touch device is detected. 465 | */ 466 | autoUseTouchEvents?: boolean; 467 | /** 468 | * Opt out of PointerEvents handling, falling back to the prior mouse event logic. 469 | */ 470 | useMouseEvents?: boolean; 471 | /** 472 | * Disable button hold action. 473 | */ 474 | disableButtonHold?: boolean; 475 | /** 476 | * Adds unicode right-to-left control characters to input return values. 477 | */ 478 | rtl?: boolean; 479 | /** 480 | * Enable input method editor candidate list support. 481 | */ 482 | enableLayoutCandidates?: boolean; 483 | /** 484 | * Character suggestions to be shown on certain key presses 485 | */ 486 | layoutCandidates?: { 487 | [key: string]: string; 488 | }; 489 | /** 490 | * Exclude buttons from layout 491 | */ 492 | excludeFromLayout?: { 493 | [key: string]: string[]; 494 | }; 495 | /** 496 | * Determines size of layout candidate list 497 | */ 498 | layoutCandidatesPageSize?: number; 499 | /** 500 | * Determines whether layout candidate match should be case sensitive. 501 | */ 502 | layoutCandidatesCaseSensitiveMatch?: boolean; 503 | /** 504 | * Disables the automatic normalization for selected layout candidates 505 | */ 506 | disableCandidateNormalization?: boolean; 507 | /** 508 | * Enables onKeyPress triggering for layoutCandidate items 509 | */ 510 | enableLayoutCandidatesKeyPress?: boolean; 511 | /** 512 | * Updates caret when selectionchange event is fired 513 | */ 514 | updateCaretOnSelectionChange?: boolean; 515 | /** 516 | * When useMouseEvents is enabled, this option allows you to trigger a button click event on mousedown 517 | */ 518 | clickOnMouseDown?: boolean; 519 | /** 520 | * Executes the callback function every time simple-keyboard is rendered (e.g: when you change layouts). 521 | */ 522 | onRender?: (instance: SimpleKeyboard) => void; 523 | /** 524 | * Executes the callback function once simple-keyboard is rendered for the first time (on initialization). 525 | */ 526 | onInit?: (instance: SimpleKeyboard) => void; 527 | /** 528 | * Retrieves the current input 529 | */ 530 | onChange?: (input: string, e?: MouseEvent) => any; 531 | /** 532 | * Retrieves all inputs 533 | */ 534 | onChangeAll?: (inputObj: KeyboardInput, e?: MouseEvent) => any; 535 | /** 536 | * Retrieves the pressed key 537 | */ 538 | onKeyPress?: (button: string, e?: MouseEvent) => any; 539 | /** 540 | * Retrieves the released key 541 | */ 542 | onKeyReleased?: (button: string, e?: MouseEvent) => any; 543 | /** 544 | * Executes the callback function before an input is about to be updated 545 | */ 546 | beforeInputUpdate?: (instance: SimpleKeyboard) => void; 547 | /** 548 | * Module options can have any format 549 | */ 550 | [name: string]: any; 551 | } 552 | /** 553 | * Physical Keyboard Service 554 | */ 555 | export interface PhysicalKeyboard { 556 | getOptions: () => KeyboardOptions; 557 | dispatch: any; 558 | /** 559 | * Creates an instance of the PhysicalKeyboard service 560 | */ 561 | constructor: ({ dispatch, getOptions }: PhysicalKeyboardParams) => any 562 | handleHighlightKeyDown(e: KeyboardEvent): void; 563 | handleHighlightKeyUp(e: KeyboardEvent): void; 564 | /** 565 | * Transforms a KeyboardEvent's "key.code" string into a simple-keyboard layout format 566 | * @param {object} e The KeyboardEvent 567 | */ 568 | getSimpleKeyboardLayoutKey(e: KeyboardEvent): string; 569 | /** 570 | * Retrieve key from keyCode 571 | */ 572 | keyCodeToKey(keyCode: number): string; 573 | isModifierKey: (e: KeyboardEvent) => boolean; 574 | } 575 | /** 576 | * Utility Service 577 | */ 578 | export interface Utilities { 579 | getOptions: () => KeyboardOptions; 580 | getCaretPosition: () => number | null; 581 | getCaretPositionEnd: () => number | null; 582 | dispatch: any; 583 | maxLengthReached: boolean; 584 | /** 585 | * Creates an instance of the Utility service 586 | */ 587 | constructor: ({ getOptions, getCaretPosition, getCaretPositionEnd, dispatch, }: UtilitiesParams) => any 588 | /** 589 | * Retrieve button type 590 | * 591 | * @param {string} button The button's layout name 592 | * @return {string} The button type 593 | */ 594 | getButtonType(button: string): string; 595 | /** 596 | * Adds default classes to a given button 597 | * 598 | * @param {string} button The button's layout name 599 | * @return {string} The classes to be added to the button 600 | */ 601 | getButtonClass(button: string): string; 602 | /** 603 | * Default button display labels 604 | */ 605 | getDefaultDiplay(): { 606 | "{bksp}": string; 607 | "{backspace}": string; 608 | "{enter}": string; 609 | "{shift}": string; 610 | "{shiftleft}": string; 611 | "{shiftright}": string; 612 | "{alt}": string; 613 | "{s}": string; 614 | "{tab}": string; 615 | "{lock}": string; 616 | "{capslock}": string; 617 | "{accept}": string; 618 | "{space}": string; 619 | "{//}": string; 620 | "{esc}": string; 621 | "{escape}": string; 622 | "{f1}": string; 623 | "{f2}": string; 624 | "{f3}": string; 625 | "{f4}": string; 626 | "{f5}": string; 627 | "{f6}": string; 628 | "{f7}": string; 629 | "{f8}": string; 630 | "{f9}": string; 631 | "{f10}": string; 632 | "{f11}": string; 633 | "{f12}": string; 634 | "{numpaddivide}": string; 635 | "{numlock}": string; 636 | "{arrowup}": string; 637 | "{arrowleft}": string; 638 | "{arrowdown}": string; 639 | "{arrowright}": string; 640 | "{prtscr}": string; 641 | "{scrolllock}": string; 642 | "{pause}": string; 643 | "{insert}": string; 644 | "{home}": string; 645 | "{pageup}": string; 646 | "{delete}": string; 647 | "{forwarddelete}": string; 648 | "{end}": string; 649 | "{pagedown}": string; 650 | "{numpadmultiply}": string; 651 | "{numpadsubtract}": string; 652 | "{numpadadd}": string; 653 | "{numpadenter}": string; 654 | "{period}": string; 655 | "{numpaddecimal}": string; 656 | "{numpad0}": string; 657 | "{numpad1}": string; 658 | "{numpad2}": string; 659 | "{numpad3}": string; 660 | "{numpad4}": string; 661 | "{numpad5}": string; 662 | "{numpad6}": string; 663 | "{numpad7}": string; 664 | "{numpad8}": string; 665 | "{numpad9}": string; 666 | }; 667 | /** 668 | * Returns the display (label) name for a given button 669 | * 670 | * @param {string} button The button's layout name 671 | * @param {object} display The provided display option 672 | * @param {boolean} mergeDisplay Whether the provided param value should be merged with the default one. 673 | */ 674 | getButtonDisplayName(button: string, display: KeyboardOptions["display"], mergeDisplay?: boolean): string; 675 | /** 676 | * Returns the updated input resulting from clicking a given button 677 | * 678 | * @param {string} button The button's layout name 679 | * @param {string} input The input string 680 | * @param {number} caretPos The cursor's current position 681 | * @param {number} caretPosEnd The cursor's current end position 682 | * @param {boolean} moveCaret Whether to update simple-keyboard's cursor 683 | */ 684 | getUpdatedInput(button: string, input: string, caretPos: any, caretPosEnd?: any, moveCaret?: boolean): string; 685 | /** 686 | * Moves the cursor position by a given amount 687 | * 688 | * @param {number} length Represents by how many characters the input should be moved 689 | * @param {boolean} minus Whether the cursor should be moved to the left or not. 690 | */ 691 | updateCaretPos(length: number, minus?: boolean): void; 692 | /** 693 | * Action method of updateCaretPos 694 | * 695 | * @param {number} length Represents by how many characters the input should be moved 696 | * @param {boolean} minus Whether the cursor should be moved to the left or not. 697 | */ 698 | updateCaretPosAction(length: number, minus?: boolean): number | null; 699 | /** 700 | * Adds a string to the input at a given position 701 | * 702 | * @param {string} source The source input 703 | * @param {string} str The string to add 704 | * @param {number} position The (cursor) position where the string should be added 705 | * @param {boolean} moveCaret Whether to update simple-keyboard's cursor 706 | */ 707 | addStringAt(source: string, str: string, position?: number, positionEnd?: number, moveCaret?: boolean): string; 708 | /** 709 | * Check whether the button is a standard button 710 | */ 711 | isStandardButton: (button: string) => boolean | ""; 712 | /** 713 | * Removes an amount of characters before a given position 714 | * 715 | * @param {string} source The source input 716 | * @param {number} position The (cursor) position from where the characters should be removed 717 | * @param {boolean} moveCaret Whether to update simple-keyboard's cursor 718 | */ 719 | removeAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string; 720 | /** 721 | * Removes an amount of characters after a given position 722 | * 723 | * @param {string} source The source input 724 | * @param {number} position The (cursor) position from where the characters should be removed 725 | */ 726 | removeForwardsAt(source: string, position?: number, positionEnd?: number, moveCaret?: boolean): string; 727 | /** 728 | * Determines whether the maxLength has been reached. This function is called when the maxLength option it set. 729 | * 730 | * @param {object} inputObj 731 | * @param {string} updatedInput 732 | */ 733 | handleMaxLength(inputObj: KeyboardInput, updatedInput: string): boolean | undefined; 734 | /** 735 | * Gets the current value of maxLengthReached 736 | */ 737 | isMaxLengthReached(): boolean; 738 | /** 739 | * Determines whether a touch device is being used 740 | */ 741 | isTouchDevice(): number | true; 742 | /** 743 | * Determines whether pointer events are supported 744 | */ 745 | pointerEventsSupported(): boolean; 746 | /** 747 | * Bind all methods in a given class 748 | */ 749 | /** 750 | * Transforms an arbitrary string to camelCase 751 | * 752 | * @param {string} str The string to transform. 753 | */ 754 | camelCase(str: string): string; 755 | /** 756 | * Split array into chunks 757 | */ 758 | chunkArray(arr: T[], size: number): T[][]; 759 | /** 760 | * Escape regex input 761 | */ 762 | escapeRegex(str: string): string; 763 | /** 764 | * Calculate caret position offset when using rtl option 765 | */ 766 | getRtlOffset(index: number, input: string): number; 767 | /** 768 | * Reusable empty function 769 | */ 770 | /** 771 | * Check if a function is a constructor 772 | */ 773 | isConstructor(f: any): boolean; 774 | } 775 | export interface CandidateBox { 776 | utilities: Utilities; 777 | options: KeyboardOptions; 778 | candidateBoxElement: HTMLDivElement; 779 | pageIndex: number; 780 | pageSize: number; 781 | constructor: ({ utilities, options }: CandidateBoxParams) => any 782 | destroy(): void; 783 | show({ candidateValue, targetElement, onSelect, }: CandidateBoxShowParams): void; 784 | renderPage({ candidateListPages, targetElement, pageIndex, nbPages, onItemSelected, }: CandidateBoxRenderParams): void; 785 | } 786 | -------------------------------------------------------------------------------- /build/polyfills.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hodgef/react-simple-keyboard/753756f72d49ab38aecbd69fd180dfff265fb61d/build/polyfills.d.ts -------------------------------------------------------------------------------- /build/services/Utilities.d.ts: -------------------------------------------------------------------------------- 1 | import { KeyboardReactInterface } from "../interfaces"; 2 | export declare const parseProps: (props: KeyboardReactInterface["options"]) => { 3 | theme: string; 4 | layout?: import("../interfaces").KeyboardLayoutObject | undefined; 5 | layoutName?: string | undefined; 6 | display?: { 7 | [button: string]: string; 8 | } | undefined; 9 | mergeDisplay?: boolean | undefined; 10 | buttonTheme?: import("../interfaces").KeyboardButtonTheme[] | undefined; 11 | buttonAttributes?: import("../interfaces").KeyboardButtonAttributes[] | undefined; 12 | debug?: boolean | undefined; 13 | newLineOnEnter?: boolean | undefined; 14 | tabCharOnTab?: boolean | undefined; 15 | inputName?: string | undefined; 16 | maxLength?: any; 17 | syncInstanceInputs?: boolean | undefined; 18 | physicalKeyboardHighlight?: boolean | undefined; 19 | physicalKeyboardHighlightPress?: boolean | undefined; 20 | physicalKeyboardHighlightPressUseClick?: boolean | undefined; 21 | physicalKeyboardHighlightPressUsePointerEvents?: boolean | undefined; 22 | physicalKeyboardHighlightTextColor?: string | undefined; 23 | physicalKeyboardHighlightBgColor?: string | undefined; 24 | physicalKeyboardHighlightPreventDefault?: boolean | undefined; 25 | preventMouseDownDefault?: boolean | undefined; 26 | preventMouseUpDefault?: boolean | undefined; 27 | stopMouseDownPropagation?: boolean | undefined; 28 | stopMouseUpPropagation?: boolean | undefined; 29 | useButtonTag?: boolean | undefined; 30 | disableCaretPositioning?: boolean | undefined; 31 | inputPattern?: any; 32 | useTouchEvents?: boolean | undefined; 33 | autoUseTouchEvents?: boolean | undefined; 34 | useMouseEvents?: boolean | undefined; 35 | disableButtonHold?: boolean | undefined; 36 | rtl?: boolean | undefined; 37 | enableLayoutCandidates?: boolean | undefined; 38 | layoutCandidates?: { 39 | [key: string]: string; 40 | } | undefined; 41 | excludeFromLayout?: { 42 | [key: string]: string[]; 43 | } | undefined; 44 | layoutCandidatesPageSize?: number | undefined; 45 | layoutCandidatesCaseSensitiveMatch?: boolean | undefined; 46 | disableCandidateNormalization?: boolean | undefined; 47 | enableLayoutCandidatesKeyPress?: boolean | undefined; 48 | updateCaretOnSelectionChange?: boolean | undefined; 49 | clickOnMouseDown?: boolean | undefined; 50 | onRender?: ((instance: import("../interfaces").SimpleKeyboard) => void) | undefined; 51 | onInit?: ((instance: import("../interfaces").SimpleKeyboard) => void) | undefined; 52 | onChange?: ((input: string, e?: MouseEvent | undefined) => any) | undefined; 53 | onChangeAll?: ((inputObj: import("../interfaces").KeyboardInput, e?: MouseEvent | undefined) => any) | undefined; 54 | onKeyPress?: ((button: string, e?: MouseEvent | undefined) => any) | undefined; 55 | onKeyReleased?: ((button: string, e?: MouseEvent | undefined) => any) | undefined; 56 | beforeInputUpdate?: ((instance: import("../interfaces").SimpleKeyboard) => void) | undefined; 57 | keyboardRef?: ((r: any) => void) | undefined; 58 | }; 59 | export declare const changedProps: (prevProps: KeyboardReactInterface["options"], props: KeyboardReactInterface["options"]) => string[]; 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-simple-keyboard", 3 | "version": "3.8.80", 4 | "description": "React.js Virtual Keyboard", 5 | "main": "build/index.js", 6 | "scripts": { 7 | "start": "webpack serve --config webpack.config.demo.js", 8 | "build": "npm run generate-types && webpack && npm run build-modern && npm run build-modern-esm && tsc", 9 | "build-modern": "webpack --config webpack.config.modern.js", 10 | "build-modern-esm": "webpack --config webpack.config.modern_esm.js", 11 | "test": "jest --silent", 12 | "coverage": "npm run test -- --coverage", 13 | "prepare": "npm run build", 14 | "generate-types": "node scripts/generateKeyboardTypes.js" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/hodgef/react-simple-keyboard" 19 | }, 20 | "author": "Francisco Hodge (https://github.com/hodgef)", 21 | "bugs": { 22 | "url": "https://github.com/hodgef/react-simple-keyboard/issues" 23 | }, 24 | "homepage": "https://virtual-keyboard.js.org/", 25 | "keywords": [ 26 | "react", 27 | "reactjs", 28 | "digital", 29 | "keyboard", 30 | "onscreen", 31 | "virtual", 32 | "component", 33 | "screen-keyboard", 34 | "component", 35 | "virtual-keyboard", 36 | "touchscreen", 37 | "touch-screen", 38 | "kiosk", 39 | "osk", 40 | "js" 41 | ], 42 | "license": "MIT", 43 | "devDependencies": { 44 | "@babel/cli": "^7.27.2", 45 | "@babel/core": "^7.27.4", 46 | "@babel/plugin-proposal-class-properties": "^7.16.7", 47 | "@babel/plugin-transform-typescript": "^7.27.0", 48 | "@babel/preset-env": "^7.27.2", 49 | "@babel/preset-react": "^7.26.3", 50 | "@babel/preset-typescript": "^7.27.1", 51 | "@types/enzyme": "^3.10.12", 52 | "@types/jest": "^29.5.14", 53 | "@types/react": "^18.0.9", 54 | "@types/react-dom": "^18.0.3", 55 | "@typescript-eslint/eslint-plugin": "^4.33.0", 56 | "@typescript-eslint/parser": "^4.32.0", 57 | "@wojtekmaj/enzyme-adapter-react-17": "^0.8.0", 58 | "autoprefixer": "^10.4.21", 59 | "babel-eslint": "^10.1.0", 60 | "babel-loader": "^10.0.0", 61 | "babel-preset-minify": "^0.5.2", 62 | "copy-webpack-plugin": "^13.0.0", 63 | "core-js": "^3.42.0", 64 | "css-loader": "^7.1.2", 65 | "css-minimizer-webpack-plugin": "^7.0.2", 66 | "dts-bundle": "^0.7.3", 67 | "enzyme": "^3.11.0", 68 | "eslint": "^7.32.0", 69 | "file-loader": "^6.2.0", 70 | "html-webpack-plugin": "^5.6.3", 71 | "jest": "^29.7.0", 72 | "jest-environment-jsdom": "^29.7.0", 73 | "mini-css-extract-plugin": "^2.9.2", 74 | "postcss": "^8.5.4", 75 | "postcss-loader": "^8.1.1", 76 | "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 77 | "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 78 | "simple-keyboard": "3.8.59", 79 | "style-loader": "^4.0.0", 80 | "terser-webpack-plugin": "^5.3.14", 81 | "typescript": "^4.9.5", 82 | "url-loader": "^4.1.1", 83 | "webpack": "^5.99.9", 84 | "webpack-cli": "^6.0.1", 85 | "webpack-dev-server": "4.13.3" 86 | }, 87 | "peerDependencies": { 88 | "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", 89 | "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" 90 | }, 91 | "jest": { 92 | "testEnvironment": "jsdom", 93 | "roots": [ 94 | "/src" 95 | ], 96 | "collectCoverageFrom": [ 97 | "src/**/*.{js,jsx,ts,tsx}", 98 | "!src/**/*.d.ts", 99 | "!src/lib/index.js", 100 | "!src/lib/polyfills.js", 101 | "!src/demo/**", 102 | "!src/utils/**", 103 | "!src/**/*.d.ts", 104 | "!**/tests/**" 105 | ], 106 | "testMatch": [ 107 | "/src/**/__tests__/**/*.{js,jsx,ts,tsx}", 108 | "/src/**/*.{spec,test}.{js,jsx,ts,tsx}" 109 | ], 110 | "transformIgnorePatterns": [ 111 | "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$", 112 | "^.+\\.module\\.(css|sass|scss)$" 113 | ], 114 | "modulePaths": [], 115 | "moduleNameMapper": { 116 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/scripts/testMock.js", 117 | "\\.(css|less)$": "/scripts/testMock.js" 118 | }, 119 | "moduleFileExtensions": [ 120 | "web.js", 121 | "js", 122 | "web.ts", 123 | "ts", 124 | "web.tsx", 125 | "tsx", 126 | "json", 127 | "web.jsx", 128 | "jsx", 129 | "node" 130 | ] 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /scripts/generateKeyboardTypes.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var dts = require('dts-bundle'); 3 | 4 | dts.bundle({ 5 | name: 'simple-keyboard', 6 | main: 'node_modules/simple-keyboard/build/index.d.ts', 7 | out: '../../../src/lib/interfaces.d.ts', 8 | outputAsModuleFolder: true 9 | }); 10 | 11 | let keyboardInterface = fs.readFileSync('src/lib/interfaces.d.ts', 'utf8'); 12 | keyboardInterface = keyboardInterface.replace(/export default (.*);/g, ""); 13 | keyboardInterface = keyboardInterface.replace(/export {(.*)};/g, ""); 14 | keyboardInterface = keyboardInterface.replace(/import (.*);/g, ""); 15 | keyboardInterface = keyboardInterface.replace(/class (.*) {/g, "export interface $1 {"); 16 | keyboardInterface = keyboardInterface.replace(/static (.*);/g, ""); 17 | keyboardInterface = keyboardInterface.replace(/constructor\((.*)\);/g, "constructor: ($1) => any"); 18 | keyboardInterface = keyboardInterface.replace(/\n\s*\n/g, '\n'); 19 | keyboardInterface = ` 20 | export interface KeyboardReactInterface extends SimpleKeyboard { 21 | options: SimpleKeyboard["options"] & { 22 | // eslint-disable-next-line no-unused-vars 23 | keyboardRef?: (r: any) => void; 24 | }; 25 | } 26 | ` + keyboardInterface; 27 | fs.writeFileSync('src/lib/interfaces.d.ts', keyboardInterface); -------------------------------------------------------------------------------- /scripts/getPackageJson.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | /** 5 | * A module to get package informations from package.json 6 | * @module getPackageJson 7 | * @param {...string} keys from package.json if no arguments passed it returns package.json content as object 8 | * @returns {object} with given keys or content of package.json as object 9 | */ 10 | 11 | /** 12 | * Returns package info 13 | */ 14 | const getPackageJson = function(...args) { 15 | const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'))); 16 | if (!args.length) { 17 | return packageJSON; 18 | } 19 | return args.reduce((out, key) => { 20 | out[key] = packageJSON[key]; 21 | return out; 22 | }, {}); 23 | }; 24 | 25 | module.exports = getPackageJson; -------------------------------------------------------------------------------- /scripts/loaderMock.js: -------------------------------------------------------------------------------- 1 | module.exports = () => ""; -------------------------------------------------------------------------------- /scripts/testMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /src/demo/App.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import SimpleKeyboard from "simple-keyboard"; 3 | import Keyboard from "../lib"; 4 | import "./css/App.css"; 5 | 6 | class App extends React.Component { 7 | state = { 8 | input: "", 9 | layoutName: "default", 10 | }; 11 | 12 | keyboard: SimpleKeyboard; 13 | 14 | onChange = (input) => 15 | this.setState({ input }, () => console.log("Input changed", input)); 16 | 17 | onKeyPress = (button) => { 18 | console.log("Button pressed", button); 19 | 20 | /** 21 | * Shift functionality 22 | */ 23 | if (["{capslock}", "{shiftleft}", "{shiftright}"].includes(button)) 24 | this.handleShiftButton(); 25 | }; 26 | 27 | handleShiftButton = () => { 28 | const { 29 | state: { layoutName }, 30 | } = this; 31 | const shiftToggle = layoutName === "default" ? "shift" : "default"; 32 | 33 | this.setState({ layoutName: shiftToggle }); 34 | }; 35 | 36 | onChangeInput = (event) => { 37 | const input = event.target.value; 38 | 39 | this.setState({ input: event.target.value }, () => 40 | this.keyboard.setInput(input) 41 | ); 42 | }; 43 | 44 | render() { 45 | const { 46 | state: { input, layoutName }, 47 | onChangeInput, 48 | onChange, 49 | onKeyPress, 50 | } = this; 51 | 52 | return ( 53 |
54 |
55 |