Browse Source

Convert to typescript (#795)

* Typescript config setup

* Add type annotations to components

* Further type additions

* And more...

* Add types to actions

* Add types to templates

* Further type checks

* Further type additons

* Install fuse latest

* Housekeeping

* Remove old type definitions

* Fix remaning type issues

* Fix some failing tests

* Remove types workflow

* Fix failing unit tests

* Resolve back space event regression

* Convert cypress files to .ts

* Fix eslint issues

* Remove cachebusting urls

* Resolve delete button bug

* Resolve regression bugs

* Fix lint script

* Fix lint workflow

* Pass args instead of object to keyboard handlers

* Flatten misc reducer

* Resolve keyboad action test failures

* Use Pick instead of Partial

* Use interfaces in action tests

* Update firefox image

* Incorporate #791

* Incorporate #788
pull/807/head
Josh Johnson 2 years ago
committed by GitHub
parent
commit
68313da412
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 35
      .eslintrc.json
  2. BIN
      .github/actions-scripts/__snapshots__/firefox-darwin.png
  3. 8
      .github/workflows/lint.yml
  4. 27
      .github/workflows/types.yml
  5. 9
      .mocharc.yml
  6. 5
      .vscode/settings.json
  7. 0
      cypress/integration/select-multiple.spec.ts
  8. 0
      cypress/integration/select-one.spec.ts
  9. 0
      cypress/integration/text.spec.ts
  10. 326
      package-lock.json
  11. 23
      package.json
  12. 7718
      public/assets/scripts/choices.js
  13. 6
      public/assets/scripts/choices.min.js
  14. 12
      public/test/select-multiple/index.html
  15. 12
      public/test/select-one/index.html
  16. 12
      public/test/text/index.html
  17. 58
      src/scripts/actions/choices.js
  18. 20
      src/scripts/actions/choices.test.ts
  19. 73
      src/scripts/actions/choices.ts
  20. 18
      src/scripts/actions/groups.js
  21. 5
      src/scripts/actions/groups.test.ts
  22. 27
      src/scripts/actions/groups.ts
  23. 53
      src/scripts/actions/items.js
  24. 19
      src/scripts/actions/items.test.ts
  25. 70
      src/scripts/actions/items.ts
  26. 28
      src/scripts/actions/misc.js
  27. 16
      src/scripts/actions/misc.test.ts
  28. 30
      src/scripts/actions/misc.ts
  29. 326
      src/scripts/choices.test.ts
  30. 675
      src/scripts/choices.ts
  31. 6
      src/scripts/components/container.test.ts
  32. 95
      src/scripts/components/container.ts
  33. 0
      src/scripts/components/dropdown.test.ts
  34. 43
      src/scripts/components/dropdown.ts
  35. 0
      src/scripts/components/index.ts
  36. 3
      src/scripts/components/input.test.ts
  37. 101
      src/scripts/components/input.ts
  38. 0
      src/scripts/components/list.test.ts
  39. 58
      src/scripts/components/list.ts
  40. 0
      src/scripts/components/wrapped-element.test.ts
  41. 34
      src/scripts/components/wrapped-element.ts
  42. 38
      src/scripts/components/wrapped-input.js
  43. 30
      src/scripts/components/wrapped-input.test.ts
  44. 29
      src/scripts/components/wrapped-input.ts
  45. 8
      src/scripts/components/wrapped-select.test.ts
  46. 53
      src/scripts/components/wrapped-select.ts
  47. 3
      src/scripts/constants.test.ts
  48. 34
      src/scripts/constants.ts
  49. 754
      src/scripts/interfaces.ts
  50. 214
      src/scripts/lib/utils.js
  51. 21
      src/scripts/lib/utils.test.ts
  52. 180
      src/scripts/lib/utils.ts
  53. 110
      src/scripts/reducers/choices.js
  54. 75
      src/scripts/reducers/choices.test.ts
  55. 127
      src/scripts/reducers/choices.ts
  56. 19
      src/scripts/reducers/general.js
  57. 25
      src/scripts/reducers/groups.js
  58. 4
      src/scripts/reducers/groups.test.ts
  59. 36
      src/scripts/reducers/groups.ts
  60. 14
      src/scripts/reducers/index.test.ts
  61. 15
      src/scripts/reducers/index.ts
  62. 58
      src/scripts/reducers/items.js
  63. 7
      src/scripts/reducers/items.test.ts
  64. 73
      src/scripts/reducers/items.ts
  65. 10
      src/scripts/reducers/loading.test.ts
  66. 23
      src/scripts/reducers/loading.ts
  67. 2
      src/scripts/store/store.test.ts
  68. 70
      src/scripts/store/store.ts
  69. 6
      src/scripts/templates.test.ts
  70. 182
      src/scripts/templates.ts
  71. 18
      tsconfig.json
  72. 1041
      types/index.d.ts
  73. 23
      webpack.config.base.js

35
.eslintrc.json

@ -1,16 +1,21 @@
{
"parserOptions": {
"ecmaVersion": 2020
},
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier", "sort-class-members"],
"extends": [
"airbnb-base",
"plugin:prettier/recommended",
"plugin:compat/recommended"
"plugin:compat/recommended",
"plugin:@typescript-eslint/recommended"
],
"plugins": ["prettier", "sort-class-members"],
"env": {
"es6": true,
"browser": true
"browser": true,
"mocha": true,
"cypress/globals": true
},
"parserOptions": {
"project": "./tsconfig.json",
"ecmaVersion": 2020
},
"rules": {
"import/prefer-default-export": "off",
@ -54,18 +59,23 @@
],
"accessorPairPositioning": "getThenSet"
}
]
],
"lines-between-class-members": "off",
"@typescript-eslint/no-namespace": "off"
},
"overrides": [
{
"files": ["*.test.js"],
"files": ["*.test.ts"],
"env": {
"mocha": true
},
"rules": {
"no-restricted-syntax": "off",
"compat/compat": "off",
"no-new": "off"
"no-new": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off"
}
},
{
@ -92,6 +102,11 @@
"Element.prototype.classList",
"Element.prototype.closest",
"Element.prototype.dataset"
]
],
"import/resolver": {
"node": {
"extensions": [".js", ".ts"]
}
}
}
}

BIN
.github/actions-scripts/__snapshots__/firefox-darwin.png

Before

Width: 630  |  Height: 704  |  Size: 44 KiB

After

Width: 630  |  Height: 693  |  Size: 44 KiB

8
.github/workflows/lint.yml

@ -27,10 +27,10 @@ jobs:
- name: run eslint
run: |
CHANGED_JS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.js$' | xargs ls -d 2>/dev/null | paste -sd " " -)
if [[ -z $(sed -e 's/[[:space:]]*$//' <<<${CHANGED_JS}) ]]; then CHANGED_JS="src/scripts"; fi
echo $CHANGED_JS
node node_modules/eslint/bin/eslint.js $CHANGED_JS
CHANGED_TS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.ts$' | xargs ls -d 2>/dev/null | paste -sd " " -)
if [[ -z $(sed -e 's/[[:space:]]*$//' <<<${CHANGED_TS}) ]]; then CHANGED_TS="src/scripts"; fi
echo $CHANGED_TS
node node_modules/eslint/bin/eslint.js $CHANGED_TS
- name: Lint JS bundle
run: |

27
.github/workflows/types.yml

@ -1,27 +0,0 @@
name: TypeScript Check
on:
pull_request:
paths:
- 'types/index.d.ts'
jobs:
tsc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- uses: actions/setup-node@v1
with:
node-version: 12
- name: Install TypeScript
run: npm install -g typescript
- name: Install required dependencies
run: npm i --only=production --no-optional --no-audit --ignore-scripts
- name: Check typings file
run: tsc types/index.d.ts

9
.mocharc.yml

@ -1,7 +1,8 @@
require:
- '@babel/register'
- 'ts-node/register'
- './config/jsdom.js'
exit: true
spec: src/**/*.test.js
spec: src/**/**/*.test.ts
extension:
- ts
- js

5
.vscode/settings.json

@ -59,5 +59,8 @@
"fileMatch": [".prettierrc.json"],
"url": "http://json.schemastore.org/prettierrc"
}
]
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}

0
cypress/integration/select-multiple.spec.js → cypress/integration/select-multiple.spec.ts

0
cypress/integration/select-one.spec.js → cypress/integration/select-one.spec.ts

0
cypress/integration/text.spec.js → cypress/integration/text.spec.ts

326
package-lock.json

@ -950,6 +950,18 @@
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"@types/chai": {
"version": "4.2.7",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.7.tgz",
"integrity": "sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==",
"dev": true
},
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
"integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
"dev": true
},
"@types/events": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
@ -967,12 +979,24 @@
"@types/node": "*"
}
},
"@types/json-schema": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz",
"integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==",
"dev": true
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"dev": true
},
"@types/mocha": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
"integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
"dev": true
},
"@types/node": {
"version": "12.11.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.2.tgz",
@ -985,12 +1009,109 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
"@types/sinon": {
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.5.1.tgz",
"integrity": "sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ==",
"dev": true
},
"@types/sinon-chai": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.3.tgz",
"integrity": "sha512-TOUFS6vqS0PVL1I8NGVSNcFaNJtFoyZPXZ5zur+qlhDfOmQECZZM4H4kKgca6O8L+QceX/ymODZASfUfn+y4yQ==",
"dev": true,
"requires": {
"@types/chai": "*",
"@types/sinon": "*"
}
},
"@types/sizzle": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.11.0.tgz",
"integrity": "sha512-G2HHA1vpMN0EEbUuWubiCCfd0R3a30BB+UdvnFkxwZIxYEGOrWEXDv8tBFO9f44CWc47Xv9lLM3VSn4ORLI2bA==",
"dev": true,
"requires": {
"@typescript-eslint/experimental-utils": "2.11.0",
"eslint-utils": "^1.4.3",
"functional-red-black-tree": "^1.0.1",
"regexpp": "^3.0.0",
"tsutils": "^3.17.1"
},
"dependencies": {
"regexpp": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
"integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
"dev": true
}
}
},
"@typescript-eslint/experimental-utils": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.11.0.tgz",
"integrity": "sha512-YxcA/y0ZJaCc/fB/MClhcDxHI0nOBB7v2/WxBju2cOTanX7jO9ttQq6Fy4yW9UaY5bPd9xL3cun3lDVqk67sPQ==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/typescript-estree": "2.11.0",
"eslint-scope": "^5.0.0"
}
},
"@typescript-eslint/parser": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.11.0.tgz",
"integrity": "sha512-DyGXeqhb3moMioEFZIHIp7oXBBh7dEfPTzGrlyP0Mi9ScCra4SWEGs3kPd18mG7Sy9Wy8z88zmrw5tSGL6r/6A==",
"dev": true,
"requires": {
"@types/eslint-visitor-keys": "^1.0.0",
"@typescript-eslint/experimental-utils": "2.11.0",
"@typescript-eslint/typescript-estree": "2.11.0",
"eslint-visitor-keys": "^1.1.0"
}
},
"@typescript-eslint/typescript-estree": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.11.0.tgz",
"integrity": "sha512-HGY4+d4MagO6cKMcKfIKaTMxcAv7dEVnji2Zi+vi5VV8uWAM631KjAB5GxFcexMYrwKT0EekRiiGK1/Sd7VFGA==",
"dev": true,
"requires": {
"debug": "^4.1.1",
"eslint-visitor-keys": "^1.1.0",
"glob": "^7.1.6",
"is-glob": "^4.0.1",
"lodash.unescape": "4.0.1",
"semver": "^6.3.0",
"tsutils": "^3.17.1"
},
"dependencies": {
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"@webassemblyjs/ast": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
@ -1413,6 +1534,12 @@
"readable-stream": "^2.0.6"
}
},
"arg": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.2.tgz",
"integrity": "sha512-+ytCkGcBtHZ3V2r2Z06AncYO8jz46UEamcspGoU8lHcEbpn6J77QK0vdWvChsclg/tM5XIJC5tnjmPp7Eq6Obg==",
"dev": true
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@ -3681,9 +3808,9 @@
}
},
"eslint": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.6.0.tgz",
"integrity": "sha512-PpEBq7b6qY/qrOmpYQ/jTMDYfuQMELR4g4WI1M/NaSDDD/bdcMb+dj4Hgks7p41kW2caXsPsEZAEAyAgjVVC0g==",
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
"integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
@ -3701,7 +3828,7 @@
"file-entry-cache": "^5.0.1",
"functional-red-black-tree": "^1.0.1",
"glob-parent": "^5.0.0",
"globals": "^11.7.0",
"globals": "^12.1.0",
"ignore": "^4.0.6",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
@ -3714,7 +3841,7 @@
"minimatch": "^3.0.4",
"mkdirp": "^0.5.1",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"optionator": "^0.8.3",
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"semver": "^6.1.2",
@ -3731,16 +3858,39 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"globals": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
"integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
}
},
"import-fresh": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
"integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
"integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
"dev": true,
"requires": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
}
},
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"dev": true,
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
}
},
"resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@ -3767,6 +3917,12 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
"integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
"dev": true
},
"type-fest": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
},
@ -3955,9 +4111,9 @@
}
},
"eslint-plugin-cypress": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.7.0.tgz",
"integrity": "sha512-52Lq5ePCD/8jc536e1RqtLfj33BAy1s7BlYgCjbG39J5kqUitcTlRY5i3NRoeAyPHueDwETsq0eASF44ugLosQ==",
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.8.1.tgz",
"integrity": "sha512-jDpcP+MmjmqQO/x3bwIXgp4cl7Q66RYS5/IsuOQP4Qo2sEqE3DI8tTxBQ1EhnV5qEDd2Z2TYHR+5vYI6oCN4uw==",
"dev": true,
"requires": {
"globals": "^11.12.0"
@ -5870,9 +6026,9 @@
"dev": true
},
"fuse.js": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.5.tgz",
"integrity": "sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ=="
"version": "3.4.6",
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.4.6.tgz",
"integrity": "sha512-H6aJY4UpLFwxj1+5nAvufom5b2BT2v45P1MkPvdGIK8fWjQx/7o6tTT1+ALV0yawQvbmvCF0ufl2et8eJ7v7Cg=="
},
"gauge": {
"version": "2.7.4",
@ -6653,9 +6809,9 @@
"dev": true
},
"inquirer": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz",
"integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz",
"integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==",
"dev": true,
"requires": {
"ansi-escapes": "^4.2.1",
@ -6667,25 +6823,25 @@
"lodash": "^4.17.15",
"mute-stream": "0.0.8",
"run-async": "^2.2.0",
"rxjs": "^6.4.0",
"rxjs": "^6.5.3",
"string-width": "^4.1.0",
"strip-ansi": "^5.1.0",
"through": "^2.3.6"
},
"dependencies": {
"ansi-escapes": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz",
"integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz",
"integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==",
"dev": true,
"requires": {
"type-fest": "^0.5.2"
"type-fest": "^0.8.1"
}
},
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true
},
"cli-cursor": {
@ -6747,14 +6903,25 @@
}
},
"string-width": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz",
"integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^5.2.0"
"strip-ansi": "^6.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.0"
}
}
}
},
"strip-ansi": {
@ -6764,12 +6931,20 @@
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
}
}
},
"type-fest": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz",
"integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==",
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
}
}
@ -8064,6 +8239,12 @@
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
"dev": true
},
"lodash.unescape": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
"integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=",
"dev": true
},
"log-symbols": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
@ -8133,6 +8314,12 @@
"semver": "^5.6.0"
}
},
"make-error": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
"dev": true
},
"mamacro": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
@ -10794,9 +10981,9 @@
"dev": true
},
"prettier": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
"integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true
},
"prettier-linter-helpers": {
@ -13195,12 +13382,63 @@
"glob": "^7.1.2"
}
},
"ts-loader": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.2.1.tgz",
"integrity": "sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
"enhanced-resolve": "^4.0.0",
"loader-utils": "^1.0.2",
"micromatch": "^4.0.0",
"semver": "^6.0.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"ts-node": {
"version": "8.5.4",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.5.4.tgz",
"integrity": "sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==",
"dev": true,
"requires": {
"arg": "^4.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"source-map-support": "^0.5.6",
"yn": "^3.0.0"
},
"dependencies": {
"diff": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
"dev": true
}
}
},
"tslib": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
"dev": true
},
"tsutils": {
"version": "3.17.1",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz",
"integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
"dev": true,
"requires": {
"tslib": "^1.8.1"
}
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
@ -13259,6 +13497,12 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typescript": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz",
"integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==",
"dev": true
},
"uglify-js": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.3.tgz",
@ -14667,6 +14911,12 @@
}
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
@ -14891,6 +15141,12 @@
}
}
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
}
}
}

23
package.json

@ -7,14 +7,14 @@
"scripts": {
"start": "run-p js:watch css:watch",
"build": "run-p js:build css:build",
"lint": "eslint src/scripts",
"lint": "eslint src/scripts/**/*.ts",
"bundlesize": "bundlesize",
"cypress:run": "cypress run",
"cypress:open": "cypress open",
"cypress:ci": "cypress run --record --group $GITHUB_REF --ci-build-id $GITHUB_SHA",
"test": "run-s test:unit test:e2e",
"test:unit": "NODE_ENV=test mocha",
"test:unit:watch": "NODE_ENV=test mocha --watch --inspect=5556",
"test:unit": "TS_NODE_TRANSPILE_ONLY=true NODE_ENV=test mocha",
"test:unit:watch": "npm run test:unit -- --watch --inspect=5556",
"test:unit:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text --reporter=text-summary mocha",
"test:e2e": "run-p --race start cypress:run",
"js:watch": "cross-env NODE_ENV=development node server.js",
@ -56,6 +56,12 @@
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/register": "^7.6.2",
"@types/chai": "^4.2.7",
"@types/mocha": "^5.2.7",
"@types/sinon": "^7.5.1",
"@types/sinon-chai": "^3.2.3",
"@typescript-eslint/eslint-plugin": "^2.11.0",
"@typescript-eslint/parser": "^2.11.0",
"autoprefixer": "^9.6.5",
"babel-loader": "^8.0.6",
"bundlesize": "^0.18.0",
@ -63,12 +69,12 @@
"cross-env": "^6.0.3",
"csso-cli": "^3.0.0",
"cypress": "3.6.0",
"eslint": "^6.6.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-config-prettier": "^6.5.0",
"eslint-loader": "^3.0.2",
"eslint-plugin-compat": "3.3.0",
"eslint-plugin-cypress": "^2.7.0",
"eslint-plugin-cypress": "^2.8.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-sort-class-members": "^1.6.0",
@ -82,9 +88,12 @@
"npm-run-all": "^4.1.5",
"nyc": "^14.1.1",
"postcss-cli": "^6.1.3",
"prettier": "^1.18.2",
"prettier": "^1.19.1",
"sinon": "^7.5.0",
"sinon-chai": "^3.3.0",
"ts-loader": "^6.2.1",
"ts-node": "^8.5.4",
"typescript": "^3.7.3",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9",
"webpack-dev-middleware": "^3.7.2",
@ -92,7 +101,7 @@
},
"dependencies": {
"deepmerge": "^4.2.0",
"fuse.js": "^3.4.5",
"fuse.js": "^3.4.6",
"redux": "^4.0.4"
},
"npmName": "choices.js",

7718
public/assets/scripts/choices.js
File diff suppressed because it is too large
View File

6
public/assets/scripts/choices.min.js
File diff suppressed because it is too large
View File

12
public/test/select-multiple/index.html

@ -43,18 +43,12 @@
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link
rel="stylesheet"
href="../../assets/styles/choices.min.css?version=6.0.3"
/>
<script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>

12
public/test/select-one/index.html

@ -43,18 +43,12 @@
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link
rel="stylesheet"
href="../../assets/styles/choices.min.css?version=6.0.3"
/>
<script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>

12
public/test/text/index.html

@ -43,18 +43,12 @@
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link
rel="stylesheet"
href="../../assets/styles/choices.min.css?version=6.0.3"
/>
<script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>

58
src/scripts/actions/choices.js

@ -1,58 +0,0 @@
/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Choice} Choice
*/
import { ACTION_TYPES } from '../constants';
/**
* @argument {Choice} choice
* @returns {Action & Choice}
*/
export const addChoice = ({
value,
label,
id,
groupId,
disabled,
elementId,
customProperties,
placeholder,
keyCode,
}) => ({
type: ACTION_TYPES.ADD_CHOICE,
value,
label,
id,
groupId,
disabled,
elementId,
customProperties,
placeholder,
keyCode,
});
/**
* @argument {Choice[]} results
* @returns {Action & { results: Choice[] }}
*/
export const filterChoices = results => ({
type: ACTION_TYPES.FILTER_CHOICES,
results,
});
/**
* @argument {boolean} active
* @returns {Action & { active: boolean }}
*/
export const activateChoices = (active = true) => ({
type: ACTION_TYPES.ACTIVATE_CHOICES,
active,
});
/**
* @returns {Action}
*/
export const clearChoices = () => ({
type: ACTION_TYPES.CLEAR_CHOICES,
});

20
src/scripts/actions/choices.test.js → src/scripts/actions/choices.test.ts

@ -6,15 +6,15 @@ describe('actions/choices', () => {
it('returns ADD_CHOICE action', () => {
const value = 'test';
const label = 'test';
const id = 'test';
const groupId = 'test';
const id = 1;
const groupId = 1;
const disabled = false;
const elementId = 'test';
const customProperties = 'test';
const placeholder = 'test';
const elementId = 1;
const customProperties = { test: true };
const placeholder = true;
const keyCode = 10;
const expectedAction = {
const expectedAction: actions.AddChoiceAction = {
type: 'ADD_CHOICE',
value,
label,
@ -46,7 +46,7 @@ describe('actions/choices', () => {
describe('filterChoices action', () => {
it('returns FILTER_CHOICES action', () => {
const results = Array(10);
const expectedAction = {
const expectedAction: actions.FilterChoicesAction = {
type: 'FILTER_CHOICES',
results,
};
@ -58,7 +58,7 @@ describe('actions/choices', () => {
describe('activateChoices action', () => {
describe('not passing active parameter', () => {
it('returns ACTIVATE_CHOICES action', () => {
const expectedAction = {
const expectedAction: actions.ActivateChoicesAction = {
type: 'ACTIVATE_CHOICES',
active: true,
};
@ -70,7 +70,7 @@ describe('actions/choices', () => {
describe('passing active parameter', () => {
it('returns ACTIVATE_CHOICES action', () => {
const active = true;
const expectedAction = {
const expectedAction: actions.ActivateChoicesAction = {
type: 'ACTIVATE_CHOICES',
active,
};
@ -82,7 +82,7 @@ describe('actions/choices', () => {
describe('clearChoices action', () => {
it('returns CLEAR_CHOICES action', () => {
const expectedAction = {
const expectedAction: actions.ClearChoicesAction = {
type: 'CLEAR_CHOICES',
};

73
src/scripts/actions/choices.ts

@ -0,0 +1,73 @@
import { ACTION_TYPES } from '../constants';
import { Choice } from '../interfaces';
export interface AddChoiceAction {
type: typeof ACTION_TYPES.ADD_CHOICE;
id: number;
value: string;
label: string;
groupId: number;
disabled: boolean;
elementId: number;
customProperties: object;
placeholder: boolean;
keyCode: number;
}
export interface Result<T> {
item: T;
score: number;
}
export interface FilterChoicesAction {
type: typeof ACTION_TYPES.FILTER_CHOICES;
results: Result<Choice>[];
}
export interface ActivateChoicesAction {
type: typeof ACTION_TYPES.ACTIVATE_CHOICES;
active: boolean;
}
export interface ClearChoicesAction {
type: typeof ACTION_TYPES.CLEAR_CHOICES;
}
export const addChoice = ({
value,
label,
id,
groupId,
disabled,
elementId,
customProperties,
placeholder,
keyCode,
}): AddChoiceAction => ({
type: ACTION_TYPES.ADD_CHOICE,
value,
label,
id,
groupId,
disabled,
elementId,
customProperties,
placeholder,
keyCode,
});
export const filterChoices = (
results: Result<Choice>[],
): FilterChoicesAction => ({
type: ACTION_TYPES.FILTER_CHOICES,
results,
});
export const activateChoices = (active = true): ActivateChoicesAction => ({
type: ACTION_TYPES.ACTIVATE_CHOICES,
active,
});
export const clearChoices = (): ClearChoicesAction => ({
type: ACTION_TYPES.CLEAR_CHOICES,
});

18
src/scripts/actions/groups.js

@ -1,18 +0,0 @@
import { ACTION_TYPES } from '../constants';
/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Group} Group
*/
/**
* @param {Group} group
* @returns {Action & Group}
*/
export const addGroup = ({ value, id, active, disabled }) => ({
type: ACTION_TYPES.ADD_GROUP,
value,
id,
active,
disabled,
});

5
src/scripts/actions/groups.test.js → src/scripts/actions/groups.test.ts

@ -5,10 +5,11 @@ describe('actions/groups', () => {
describe('addGroup action', () => {
it('returns ADD_GROUP action', () => {
const value = 'test';
const id = 'test';
const id = 1;
const active = true;
const disabled = false;
const expectedAction = {
const expectedAction: actions.AddGroupAction = {
type: 'ADD_GROUP',
value,
id,

27
src/scripts/actions/groups.ts

@ -0,0 +1,27 @@
import { ACTION_TYPES } from '../constants';
export interface AddGroupAction {
type: typeof ACTION_TYPES.ADD_GROUP;
id: number;
value: string;
active: boolean;
disabled: boolean;
}
export const addGroup = ({
value,
id,
active,
disabled,
}: {
id: number;
value: string;
active: boolean;
disabled: boolean;
}): AddGroupAction => ({
type: ACTION_TYPES.ADD_GROUP,
value,
id,
active,
disabled,
});

53
src/scripts/actions/items.js

@ -1,53 +0,0 @@
import { ACTION_TYPES } from '../constants';
/**
* @typedef {import('redux').Action} Action
* @typedef {import('../../../types/index').Choices.Item} Item
*/
/**
* @param {Item} item
* @returns {Action & Item}
*/
export const addItem = ({
value,
label,
id,
choiceId,
groupId,
customProperties,
placeholder,
keyCode,
}) => ({
type: ACTION_TYPES.ADD_ITEM,
value,
label,
id,
choiceId,
groupId,
customProperties,
placeholder,
keyCode,
});
/**
* @param {number} id
* @param {number} choiceId
* @returns {Action & { id: number, choiceId: number }}
*/
export const removeItem = (id, choiceId) => ({
type: ACTION_TYPES.REMOVE_ITEM,
id,
choiceId,
});
/**
* @param {number} id
* @param {boolean} highlighted
* @returns {Action & { id: number, highlighted: boolean }}
*/
export const highlightItem = (id, highlighted) => ({
type: ACTION_TYPES.HIGHLIGHT_ITEM,
id,
highlighted,
});

19
src/scripts/actions/items.test.js → src/scripts/actions/items.test.ts

@ -6,14 +6,14 @@ describe('actions/items', () => {
it('returns ADD_ITEM action', () => {
const value = 'test';
const label = 'test';
const id = '1234';
const choiceId = '1234';
const groupId = 'test';
const id = 1;
const choiceId = 1;
const groupId = 1;
const customProperties = { test: true };
const placeholder = true;
const keyCode = 10;
const expectedAction = {
const expectedAction: actions.AddItemAction = {
type: 'ADD_ITEM',
value,
label,
@ -42,9 +42,10 @@ describe('actions/items', () => {
describe('removeItem action', () => {
it('returns REMOVE_ITEM action', () => {
const id = '1234';
const choiceId = '1';
const expectedAction = {
const id = 1;
const choiceId = 1;
const expectedAction: actions.RemoveItemAction = {
type: 'REMOVE_ITEM',
id,
choiceId,
@ -56,10 +57,10 @@ describe('actions/items', () => {
describe('highlightItem action', () => {
it('returns HIGHLIGHT_ITEM action', () => {
const id = '1234';
const id = 1;
const highlighted = true;
const expectedAction = {
const expectedAction: actions.HighlightItemAction = {
type: 'HIGHLIGHT_ITEM',
id,
highlighted,

70
src/scripts/actions/items.ts

@ -0,0 +1,70 @@
import { ACTION_TYPES } from '../constants';
export interface AddItemAction {
type: typeof ACTION_TYPES.ADD_ITEM;
id: number;
value: string;
label: string;
choiceId: number;
groupId: number;
customProperties: object;
placeholder: boolean;
keyCode: number;
}
export interface RemoveItemAction {
type: typeof ACTION_TYPES.REMOVE_ITEM;
id: number;
choiceId: number;
}
export interface HighlightItemAction {
type: typeof ACTION_TYPES.HIGHLIGHT_ITEM;
id: number;
highlighted: boolean;
}
export const addItem = ({
value,
label,
id,
choiceId,
groupId,
customProperties,
placeholder,
keyCode,
}: {
id: number;
value: string;
label: string;
choiceId: number;
groupId: number;
customProperties: object;
placeholder: boolean;
keyCode: number;
}): AddItemAction => ({
type: ACTION_TYPES.ADD_ITEM,
value,
label,
id,
choiceId,
groupId,
customProperties,
placeholder,
keyCode,
});
export const removeItem = (id: number, choiceId: number): RemoveItemAction => ({
type: ACTION_TYPES.REMOVE_ITEM,
id,
choiceId,
});
export const highlightItem = (
id: number,
highlighted: boolean,
): HighlightItemAction => ({
type: ACTION_TYPES.HIGHLIGHT_ITEM,
id,
highlighted,
});

28
src/scripts/actions/misc.js

@ -1,28 +0,0 @@
/**
* @typedef {import('redux').Action} Action
*/
/**
* @returns {Action}
*/
export const clearAll = () => ({
type: 'CLEAR_ALL',
});
/**
* @param {any} state
* @returns {Action & { state: object }}
*/
export const resetTo = state => ({
type: 'RESET_TO',
state,
});
/**
* @param {boolean} isLoading
* @returns {Action & { isLoading: boolean }}
*/
export const setIsLoading = isLoading => ({
type: 'SET_IS_LOADING',
isLoading,
});

16
src/scripts/actions/misc.test.js → src/scripts/actions/misc.test.ts

@ -1,10 +1,11 @@
import { expect } from 'chai';
import * as actions from './misc';
import { State } from '../interfaces';
describe('actions/misc', () => {
describe('clearAll action', () => {
it('returns CLEAR_ALL action', () => {
const expectedAction = {
const expectedAction: actions.ClearAllAction = {
type: 'CLEAR_ALL',
};
@ -14,8 +15,13 @@ describe('actions/misc', () => {
describe('resetTo action', () => {
it('returns RESET_TO action', () => {
const state = { test: true };
const expectedAction = {
const state: State = {
choices: [],
items: [],
groups: [],
loading: false,
};
const expectedAction: actions.ResetToAction = {
type: 'RESET_TO',
state,
};
@ -27,7 +33,7 @@ describe('actions/misc', () => {
describe('setIsLoading action', () => {
describe('setting loading state to true', () => {
it('returns expected action', () => {
const expectedAction = {
const expectedAction: actions.SetIsLoadingAction = {
type: 'SET_IS_LOADING',
isLoading: true,
};
@ -38,7 +44,7 @@ describe('actions/misc', () => {
describe('setting loading state to false', () => {
it('returns expected action', () => {
const expectedAction = {
const expectedAction: actions.SetIsLoadingAction = {
type: 'SET_IS_LOADING',
isLoading: false,
};

30
src/scripts/actions/misc.ts

@ -0,0 +1,30 @@
import { State } from '../interfaces';
import { ACTION_TYPES } from '../constants';
export interface ClearAllAction {
type: typeof ACTION_TYPES.CLEAR_ALL;
}
export interface ResetToAction {
type: typeof ACTION_TYPES.RESET_TO;
state: State;
}
export interface SetIsLoadingAction {
type: typeof ACTION_TYPES.SET_IS_LOADING;
isLoading: boolean;
}
export const clearAll = (): ClearAllAction => ({
type: ACTION_TYPES.CLEAR_ALL,
});
export const resetTo = (state: State): ResetToAction => ({
type: ACTION_TYPES.RESET_TO,
state,
});
export const setIsLoading = (isLoading: boolean): SetIsLoadingAction => ({
type: ACTION_TYPES.SET_IS_LOADING,
isLoading,
});

326
src/scripts/choices.test.js → src/scripts/choices.test.ts

@ -3,9 +3,12 @@ import { spy, stub } from 'sinon';
import sinonChai from 'sinon-chai';
import Choices from './choices';
import { EVENTS, ACTION_TYPES, DEFAULT_CONFIG, KEY_CODES } from './constants';
import { WrappedSelect, WrappedInput } from './components/index';
import { removeItem } from './actions/items';
import { Item, Choice, Group } from './interfaces';
import templates from './templates';
chai.use(sinonChai);
@ -28,12 +31,6 @@ describe('choices', () => {
instance = null;
});
const returnsInstance = () => {
it('returns this', () => {
expect(output).to.eql(instance);
});
};
describe('constructor', () => {
describe('config', () => {
describe('not passing config options', () => {
@ -88,7 +85,7 @@ describe('choices', () => {
`;
instance = new Choices('[data-choice]', {
renderSelectedChoices: 'test',
renderSelectedChoices: 'test' as any,
});
expect(instance.config.renderSelectedChoices).to.equal('auto');
@ -211,7 +208,7 @@ describe('choices', () => {
<input data-choice type="text" id="input-1" />
`;
instance = new Choices(document.querySelector('[data-choice]'));
instance = new Choices('[data-choice]');
expect(instance.passedElement).to.be.an.instanceOf(WrappedInput);
});
@ -223,7 +220,7 @@ describe('choices', () => {
<select data-choice id="select-1"></select>
`;
instance = new Choices(document.querySelector('[data-choice]'));
instance = new Choices('[data-choice]');
expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect);
});
@ -386,8 +383,8 @@ describe('choices', () => {
expect(clearStoreSpy.called).to.equal(true);
});
it('nullifys templates config', () => {
expect(instance._templates).to.equal(null);
it('restes templates config', () => {
expect(instance._templates).to.deep.equal(templates);
});
it('resets initialise flag', () => {
@ -423,7 +420,9 @@ describe('choices', () => {
output = instance.enable();
});
returnsInstance(output);
it('returns this', () => {
expect(output).to.eql(instance);
});
it('returns early', () => {
expect(passedElementEnableSpy.called).to.equal(false);