Compare commits

...

196 commits

Author SHA1 Message Date
Matt Triff 5dbea2825a
Prep for 10.2.0 (#1077) 2022-11-29 13:44:43 -05:00
Morez 312971acea
[BUGFIX] Fix support for non-Latin characters (#1072)
* solve 1068

* resolve problems

* resolve npm problem

* Merge master and rebuild, fix lint error

* Create fresh package-lock.json

Co-authored-by: محمدرضا ضربی زاده <mohammad.zarbizadeh@samim.net>
Co-authored-by: Matt Triff <matt.triff@gmail.com>
2022-11-29 13:01:01 -05:00
Matt Triff a7ed4d880e
Merge pull request #1001 from brosua/feature/custom-properties
[BUGFIX] Correct evaluation of HTML custom properties and JSON support
2022-11-29 11:18:59 -05:00
Matt Triff ba27dbb533 Convert npx to npm exec 2022-11-29 10:46:06 -05:00
Matt Triff 9c6de739c7 Update build 2022-11-28 17:25:48 -05:00
Matt Triff 2730d7aad4
Merge pull request #1051 from Sysix/update-readme
Documentation: Add option "uniqueItemText" and "customAddItemText" to README
2022-11-28 17:15:03 -05:00
Matt Triff 5d17dd8531 Fix CI workflows 2022-11-28 17:11:41 -05:00
Matt Triff d1f39c6cda Update screenshot 2022-11-28 15:51:16 -05:00
Matt Triff bbdacdfe3b Update all CI workflows to use latest LTS (v18) 2022-11-28 14:18:14 -05:00
Matt Triff 92eabcbd4a Update all CI workflows to use latest LTS (v18) 2022-11-28 12:08:05 -05:00
Matt Triff 2a8107f379 Update package-lock.json 2022-11-28 11:45:39 -05:00
Matt Triff ea45c47d43 Merge branch 'master' into feature/custom-properties 2022-11-28 11:43:15 -05:00
Matt Triff d130beb4e9 Update dependencies, add e2e tests for HTML custom properties 2022-11-28 11:36:04 -05:00
Matt Triff 6056cce4e9
Merge pull request #1073 from Choices-js/dependabot/npm_and_yarn/minimatch-3.1.2
Bump minimatch from 3.0.4 to 3.1.2
2022-11-17 16:15:02 -05:00
dependabot[bot] ce590e3785
Bump minimatch from 3.0.4 to 3.1.2
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-17 16:54:11 +00:00
Matt Triff 30e6dbadda
Merge pull request #1048 from Choices-js/dependabot/npm_and_yarn/terser-5.14.2
Bump terser from 5.10.0 to 5.14.2
2022-11-17 11:29:49 -05:00
Matt Triff 4da6239a67
Merge pull request #1069 from Choices-js/dependabot/npm_and_yarn/loader-utils-1.4.2
Bump loader-utils from 1.4.0 to 1.4.2
2022-11-17 11:29:09 -05:00
dependabot[bot] 9ac71c4717
Bump loader-utils from 1.4.0 to 1.4.2
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-13 12:19:25 +00:00
Alexander Schlegel 835ea12ac9 add option "uniqueItemText" and "customAddItemText" into README.md 2022-08-27 16:50:32 +02:00
dependabot[bot] 1b67baec25
Bump terser from 5.10.0 to 5.14.2
Bumps [terser](https://github.com/terser/terser) from 5.10.0 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-20 01:34:00 +00:00
Matt Triff 624dd797a4
Merge pull request #1030 from Choices-js/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-07-09 11:05:50 -04:00
Matt Triff cbbdbda95b
Merge pull request #1034 from Moonlight-Angel/patch-1
Allow to overwrite the `$choices-z-index` variable
2022-07-09 10:38:20 -04:00
Genesis d796e90955
Allow to overwrite the $choices-z-index variable
#794 introduced a new SCSS variable for configuring the z-index, but it didn't set the `!default` flag, making it impossible to overwrite in external files.
2022-05-04 11:41:57 +02:00
Matt Triff 06d16cd857
Merge pull request #1026 from comxd/master
Fix typo on aria-labelledby attribute
2022-04-11 20:26:47 -04:00
dependabot[bot] d26b753f6b
Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 18:22:59 +00:00
David DIVERRES 72da548a64 Fix typo on aria-labelledby attribute 2022-04-01 14:13:08 +02:00
Josua Vogel 490e341db5 Build public code 2022-03-14 15:57:05 +01:00
Josua Vogel 76780ccc34 Adding unit test and lint 2022-03-14 15:52:48 +01:00
Josua Vogel beb07ebc2c Merge branch 'master' into feature/custom-properties 2022-03-14 15:11:52 +01:00
Matt Triff 20d3f5cd55
Merge pull request #1021 from Choices-js/fix-param
Fix type for parameter on setChoiceByValue
2022-03-13 17:30:36 -04:00
Matt Triff f63201d929 Fix type for parameter on setChoiceByValue 2022-03-13 17:22:37 -04:00
Matt Triff 08d4f1fee7
Merge pull request #1011 from Choices-js/prep-10-1-0
Prep for 10.1.0
2022-02-13 21:49:32 -05:00
Matt Triff 09eeca0db0 Prep for 10.1.0 2022-02-13 21:39:17 -05:00
Matt Triff e2aab31bc0
Merge pull request #1010 from Choices-js/fix-hidden-first-char
Fix first character not appearing in webkit browsers
2022-02-13 21:12:40 -05:00
Matt Triff c01144ab23 Merge branch 'master' into fix-hidden-first-char 2022-02-13 21:07:18 -05:00
Matt Triff 86694c138e
Merge pull request #1009 from Choices-js/sponsor
Add sponsor
2022-02-13 21:05:30 -05:00
Matt Triff 7c360b44b3 Update snapshots 2022-02-13 20:58:20 -05:00
Matt Triff 2099c3dc2e Add sponsor 2022-02-13 20:46:02 -05:00
Matt Triff d25c065210 Fix first character not appearing in webkit browsers 2022-01-27 18:04:49 -05:00
Josua Vogel eb22895f00
Add option labelId to improve a11y (#971)
* Add option labelId to improve a11y

* Console.log entfernt

* Add test case for aria-labeledby

Co-authored-by: Josua Vogel <josua.vogel@t-systems.com>
2022-01-18 17:07:07 -05:00
Josua Vogel ac8d27facf [BUGFIX] Correct evaluation of custom properties 2022-01-17 13:46:19 +01:00
Matt Triff 06d4435c82
Merge pull request #1000 from mysliwietzflorian/mysliwietzflorian-patch-1
README Fix: Use select-single everywhere, fix missing comma in default options
2022-01-15 22:04:42 -05:00
Mysliwietz Florian bb76a572c0
minor update docs/readme
- use  `select-one` consistently (instead of `select-single` with two occurrences)
- add missing comma (,) in setup example with default options
2022-01-15 21:59:42 +01:00
Matt Triff 6df44b1044
Merge pull request #999 from Choices-js/bump-deps
Bump dev dependencies
2022-01-13 20:41:56 -05:00
Matt Triff 29097d5457 Bump dev dependencies 2022-01-13 20:31:33 -05:00
Matt Triff c21b998eaa Lint on style PRs 2022-01-13 20:16:49 -05:00
Matt Triff 96e4ac53d9 Merge branch 'master' of github.com:Choices-js/Choices 2022-01-11 20:24:30 -05:00
Matt Triff 770342b7e8 Split GitHub pages action, allow manual dispatch 2022-01-11 20:24:15 -05:00
Matt Triff eef836a037
Merge pull request #996 from supermueller/resolve-887
Fix multiple select in Internet Explorer 11
2022-01-11 20:07:58 -05:00
Matt Triff 8ab8157607 Bump CSS max size 2022-01-11 20:01:38 -05:00
Karsten Müller 75caa0b1f3 Resolve #887
Fix compatibility with Internet Explorer 11
2022-01-10 10:56:10 +01:00
Matt Triff 3d42067bbd Version 10.0.0 2022-01-02 23:38:07 -05:00
Matt Triff ce3d1111d8
Merge pull request #991 from Choices-js/fuse6
Upgrade to Fuse v6
2022-01-02 13:27:09 -05:00
Matt Triff 7758226d64
Merge pull request #992 from Choices-js/searchfloor0
Trigger search when clearing the input field with search floor of 0
2021-12-31 22:06:22 -05:00
Matt Triff 25a7ed0318 Add test with searchFloor of 0 2021-12-31 21:51:00 -05:00
Daiana Cambruzzi Ávila 23f0b7cb9d Fix Issue 630: allow triggering of 'search' event when clearing the input field 2021-12-31 18:23:13 -05:00
Matt Triff 303d12504c Upgrade to Fuse v6 2021-12-31 18:11:45 -05:00
Matt Triff 3b4d7543e5 Set line endings for type definition files 2021-12-31 18:10:15 -05:00
Matt Triff 781c729e13
Merge pull request #990 from Choices-js/fix-search-sanitisation
Remove character sanitisation when searching
2021-12-30 22:12:53 -05:00
Matt Triff 9605f367f9 Search using non-sanitised input value 2021-12-30 22:05:03 -05:00
Matt Triff 1b4d3553ef
Merge pull request #989 from Choices-js/update-actions
Update GitHub Actions
2021-12-30 20:45:24 -05:00
Matt Triff f12c62c4b8
Add methods to Table of Contents 2021-12-30 20:37:27 -05:00
Matt Triff c7976b7acd Add pause after resize to fix inconsistent dropdown/dropup direction behaviour 2021-12-30 20:25:33 -05:00
Matt Triff 4df199e0b9
Add checklist items for tests 2021-12-30 20:21:45 -05:00
Matt Triff 0903934848 Update GitHub Actions 2021-12-30 20:16:52 -05:00
Matt Triff 64b5df6874
Merge pull request #987 from victiondev/fix/typings
Fix/typings
2021-12-27 11:38:02 -05:00
Mason Rogers 824eca6f81 fix: Fix non-string-valeus 2021-12-27 15:58:25 +00:00
Mason Rogers 9c9aded8b2 chore: Build 2021-12-27 14:50:45 +00:00
Mason Rogers 7e200664c4 feat: Export interfaces 2021-12-27 14:46:22 +00:00
Matt Triff 04571e36d3
Merge pull request #986 from victiondev/fix/typings
fix: Add typings to published files
2021-12-27 09:01:45 -05:00
Mason Rogers 11208fe62d fix: Add typings to published files 2021-12-27 13:27:26 +00:00
Matt Triff b9acfa773d Add table of contents 2021-12-26 17:47:34 -05:00
Matt Triff 6e4903e852
Merge pull request #985 from Choices-js/fix-typings
Fix typings
2021-12-26 16:59:28 -05:00
Matt Triff a8862e78be Add typings and declaration maps 2021-12-26 16:38:09 -05:00
Matt Triff bf94386cc5 Update configuration to output types 2021-12-26 16:37:23 -05:00
Matt Triff 0b6973b322
Merge pull request #984 from victiondev/feat/allowHTML
feat: Introduce allowHTML option to allow people to disable injecting HTML into choices.
2021-12-26 09:47:07 -05:00
Matt Triff 66c6864267 Update allowHTML wording, set remote examples to allowHTML false 2021-12-26 09:36:12 -05:00
viction 391c3e39cb fix: README examples & change template type 2021-12-26 02:47:49 +00:00
viction 3d402d4560 fix: Circular dep caused by requiring options 2021-12-25 21:38:19 +00:00
viction 545a442f5c fix: Custom template displaying/unit tests 2021-12-25 20:29:54 +00:00
viction c989be1491 test: select-multiple coverage 2021-12-25 20:29:31 +00:00
viction 3633c4ac0f test: select-one coverage 2021-12-25 20:29:15 +00:00
viction 859f6262eb test: Coverage for allowHTML 2021-12-24 17:33:32 +00:00
viction 6b16e93977 fix: template testing & type errors 2021-12-24 17:32:50 +00:00
viction 7f727480e8 feat: allowHTML 2021-12-23 16:59:48 +00:00
Bob Maerten 82b94228f9
Enhance inputCloned text input with type and name (#908)
* Enhance inputCloned text input with type and name

Safari will display a contact autocomplete on every text input which `name` attribute contains "*name*" or does not have any `name` attribute.
Adding a fine tuned `name`attribute to the input should prevent that.

Plus, input type="search" seems more suited to the field intent (https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input/search).

* Adapt inputCloned related test
2021-12-22 16:56:04 -05:00
Matt Triff b92823b70c
Merge pull request #983 from Choices-js/patch-1
Fix Sanitization of > Characters
2021-12-21 21:50:44 -05:00
Matt Triff 22f9be0d93 Update tests for &gt; 2021-12-21 18:07:31 -05:00
Raphaël Jorel 2222f767a9 Fix sanitise function
HTML uses `&gt;` to encode `>` characters.
2021-12-21 11:15:44 -05:00
Matt Triff f0ec43fa20 Version 9.1.0 2021-12-19 20:54:48 -05:00
Matt Triff c4f3a81d41
Merge pull request #979 from Choices-js/npm-audit-fix
Switch to dart-sass, fix npm audit issues, add stylelint
2021-12-19 18:25:44 -05:00
Matt Triff fb379408c1 Use Chrome for cypress:ci runs (fixes flakey test in Electron) 2021-12-19 18:21:42 -05:00
Matt Triff c26596e9ec Simplify linting GitHub Action 2021-12-19 18:09:41 -05:00
Matt Triff 9835eb756a Implement stylelint 2021-12-19 17:43:03 -05:00
Matt Triff 70397fd89a Switch to dart-sass, fix npm audit issues 2021-12-19 16:58:00 -05:00
Matt Triff 59ea75ef14
Update README.md
De-emphasize call for maintainers.
2021-12-19 14:07:02 -05:00
Ryan B 8647f36fbe
Documentation of input type terms (#873)
* Documentation of input type terms

Add a table with documentation of HTML5 input tag correspondence to terms used in Choices documentation

* Update README.md

Clean up typos, simplify table and use MDN for reference links

Co-authored-by: Matt Triff <matt.triff@gmail.com>
2021-12-19 10:14:20 -05:00
Hans Kuijpers 046afbb614
Solve deprecated warning using / for division outside of calc() (#976)
* replace / by *

* replace / by *

* add leading zero

* add leading zero
2021-12-19 10:02:21 -05:00
flip111 de5307ce4d
Update README.md (#844)
* Update README.md

* Update README.md

Switch to the Choices-js organization link.

Co-authored-by: Matt Triff <matt.triff@gmail.com>
2021-12-19 09:51:45 -05:00
Matt Triff 05a41c5c7d
Merge pull request #848 from JoshuaCrewe/fix/readme-typo
Fix typo in README.md s/withing/within
2021-12-18 23:22:54 -05:00
Matt Triff 9e656397cd
Merge pull request #977 from Choices-js/fix-selenium-workflow
Update dependencies, refactor to remove dependency cycles, fix GitHub Action workflows
2021-12-18 22:54:10 -05:00
Matt Triff 20579bad35 Use Chrome with Cypress (Electron resulted in flaky dropdown test), save Puppeteer diff image even if pixelmatch throws error, update Chrome snapshot 2021-12-18 22:36:40 -05:00
Matt Triff 977221650a Update snapshots, add Chrome to browser test, remove linting JS, bump dependencies - replace deprecated eslint-loader 2021-12-18 22:07:37 -05:00
Matt Triff e09a342ac8 PostCSS now required as a separate dependency of postcss-cli 2021-12-18 12:08:26 -05:00
Matt Triff e64eface11 Update all workflows to use Node 12+ for node-sass and other module compatibility, switch IE to Edge for browser testing (IE web driver no longer pre-installed on runner) 2021-12-17 16:59:43 -05:00
Matt Triff de6c46cdd0 Disable committing built files in GitHub Actions, conflicts with protected branch 2021-12-17 16:40:06 -05:00
Matt Triff a1ec9d0de6 eslint 8.x requires Node 12.22.0^ 2021-12-17 16:39:16 -05:00
Matt Triff 3d921621b7 Update dependencies, fix linting issues, split interfaces and default objects to resolve dependency cycles 2021-12-17 16:26:52 -05:00
Matt Triff 46deb9abe5 Switch to new brew cask syntax, IE driver no longer available - switch to hardcoded path 2021-12-15 20:59:31 -05:00
Matt Triff 6b6fb17bca Update adding to path to new syntax 2021-12-15 20:37:52 -05:00
Matt Triff b4a6371cc8
Merge pull request #975 from bzf/fix-demo-links
Fix broken demo link in README.md
2021-12-14 17:11:04 -05:00
André Ligné 60adc56bbf Fix broken demo link in README.md
After trying to see the demo for this project I noticed that the link
leads to a 404 page.

I found the updated link in [#957] and this commit updates the README to
link to the proper URL.

[#957]: https://github.com/Choices-js/Choices/issues/957
2021-11-15 14:56:35 +01:00
Josh Johnson ebbea8c3b0
Update README.md 2020-07-28 11:01:32 +01:00
Joshua Crewe 41f81d22ed Fix typo in README.md 2020-04-07 14:22:00 +01:00
Alex Chan cbaf43232c Fix a typo in the README: s/seperates/separates (#807) 2020-01-14 08:50:42 +00:00
Josh Johnson 825efc6fd0
Update release drafter to latest (#800) 2019-12-23 18:33:31 +00:00
Josh Johnson 68313da412
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
2019-12-23 18:22:54 +00:00
dGrammatiko 3ed027229d Adds a variable for the z-index (#794) 2019-12-15 19:26:56 +00:00
Josh Johnson 44b4326a52
Resolve #780 (#785)
* Attempt #1

* Remove console.log

* Update puppeteer screenshot
2019-12-03 12:56:47 +00:00
Josh Johnson b3b7b3f14f Update README 2019-11-28 18:52:45 +00:00
Josh Johnson 3d099d85fc Update README 2019-11-28 18:06:33 +00:00
Josh Johnson 9676cff128
Resolve #622 and #781 (#784)
* Resolve duplicate initialise in demo

* Update README with versioned cdn links

* Update log

* Re-add env var
2019-11-27 11:46:40 +00:00
Josh Johnson 47aba515fb
Add fetch to polyfill bundle on the demo page (#783) 2019-11-26 16:59:16 +00:00
Josh Johnson 62e849d1b4
Resolve 774 (#777)
* Include customProperties in removeItem

* Add tests

* Housekeeping

* Update mac vm label

* Add .nvmrc
2019-11-24 17:32:02 +00:00
Josh Johnson d116f95c54 Update issue templates 2019-11-23 22:41:44 +00:00
GitHub Action 6215ca5e59 Update build files 🏗 2019-11-22 19:13:46 +00:00
Josh Johnson 67266a3aae
Resolve #762 (#767)
* Update value with character value

* Remove .only

* Lowercase character before updating value

* Add cypress tests covering change

* Update logic to affect both select inputs

* Update cypress

* Emphasise remove button focus

* Text change

* Revert "Update cypress"

This reverts commit 81e406de85.

* Remove false positive tests
2019-11-22 19:09:45 +00:00
GitHub Action 85f0b5f9be Update build files 🏗 2019-11-19 18:38:17 +00:00
Josh Johnson 592c326442
Update polyfill list (#765)
* Update polyfill list

* Update eslintrc.json

* Add keydown methods to types

* Resolve type issue
2019-11-19 18:34:08 +00:00
GitHub Action 214b6e80df Update build files 🏗 2019-11-18 09:55:07 +00:00
Josh Johnson 9f2661023d
Next release (#763)
* 🔖 Version 9.0.1

* Remove post version check
2019-11-18 09:51:24 +00:00
GitHub Action d2516e7de3 Update build files 🏗 2019-11-17 12:38:39 +00:00
Kazuki Nishikawa 0e8e42e015 Fix #573 (#574)
* add specs

* fix to restore preset choices after destroy

* avoid to modify `this.config.choices` directly

* Update cypress/integration/select-one.spec.js

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update public/test/select-one.html

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update public/test/select-one.html

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update public/test/select-one.html

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update public/test/select-one.html

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* fix specs

* restoring passed element initial options

 - Save `passedElement.options` values as `this._presetOptions`
 - Restore saved `this._presetOptions` to `passedElement.options` on `destroy`
 - It avoids restoring options in `this.config.choices`

* Update cypress/integration/select-one.spec.js

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update cypress/integration/select-one.spec.js

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* Update public/test/select-one.html

Co-Authored-By: Josh Johnson <josh@joshuajohnson.co.uk>

* move preset options assignment statement
2019-11-17 12:34:34 +00:00
Josh Johnson e7b4afd472
Fix releases (#761)
* Testing

* Re add "needs" flags

* Further testing

* Add skip husky install flag

* Revert "on" flag
2019-11-15 19:34:20 +00:00
GitHub Action 952b3fc146 Update build files 🏗 2019-11-14 23:06:48 +00:00
Josh Johnson 760f39dbf3 Remove "needs" from deployment.yaml 2019-11-14 23:03:03 +00:00
Josh Johnson 573c840de4 Fix deployment.yml 2019-11-14 23:00:06 +00:00
Josh Johnson 44da784f29
🔖 Version 9.0.0 (#758) 2019-11-14 22:51:50 +00:00
agamemnus 6be462c80b Typo. (#759) 2019-11-14 20:34:05 +00:00
Josh Johnson e67b8a3e4c
Commit and push built files to master (#756)
* Commit and push built files to master

* Testing...

* Add  name

* Add fallback

* Revert back to master branch
2019-11-14 09:47:20 +00:00
Josh Johnson 933ea6093f
Remove redundant check (#755)
* Remove redundant check

* Add integration tests covering fix

* Add missing test
2019-11-13 15:40:47 +00:00
Josh Johnson 84b952e115
Resolve bug #637 (#754)
* Add is-selected class when item is selected

* Remove console.log

* Update README
2019-11-13 14:49:23 +00:00
Chris DeLuca f745be449d Always hide remove button if no value is selected (#744)
In some cases, the remove item X button is not hidden when there is no
selection made from the dropdown. This is not as usable, since there's
no item to clear, hence an effective noop.

The condition I saw seeing this issue arise is in single selects with
a placeholder value, a selection has been made, and then cleared: the
button HTML remains.

To fix, add some styles to hide the button if the select doesn't have a
value selected, in this case keying off of it's parents `data-value`
property.

fixes #684
2019-11-12 12:29:34 +00:00
Konstantin Vyatkin 8775bacdd9 improve whole-page performance by scoping events handlers (#740)
* scope onMouseDown event capture

* supercedes #710

* make isIE11 a const

* scope keydown

* scope mouseover

* fix removeEventListener for keyup
2019-11-12 09:47:41 +00:00
Oleg Dmitrochenko fb2310cb56 Indent fixed in "choices__list--dropdown" (#750)
Indent fixed in "choices__list--dropdown". Added "box-sizing: border-box;".
2019-11-12 09:03:04 +00:00
Konstantin Vyatkin 68322d9528 Upgrade Cypress to 3.6 and use cache in Github Actions (#748)
* try to cache cypress cache

* try to fix

* try cache hit

* Upgrade Cypress to 3.6

* remove uneeded prefix
2019-11-08 13:24:57 +00:00
Josh Johnson d04031e02f
Fix id types (#743)
* Set ids to be numbers

* Split out _setLoading into start/stop methods

* Build
2019-11-08 09:19:18 +00:00
Konstantin Vyatkin 7dcc155b8f remove safari test, update snapshots for new macOS, use dependency caching (#745)
* remove safari test

* add node modules caching

* update macos snapshots

* try to fix caching

* try like this

* cache .npm

* adjust cache keys
2019-11-08 07:48:29 +00:00
Josh Johnson b5b593a62f
Resolve bug 473 (#739)
* Fix #473

* Add tests

* Tweak cypress tests

* Build
2019-11-07 08:50:19 +00:00
Konstantin Vyatkin 81c44ba8f2 Enable test on Safari (#737)
* Enable test on Safari

* fix platform name

* update base Safari snapshot
2019-11-04 13:17:45 +00:00
Josh Johnson f30b976424
Resolve bug 533 (#736)
* Add placeholder options to demo page

* Use constant types in components

* Refactor adding predefined groups/items/choices

* Add 'highlighted' flag to Item type

* Fix dispatch param type

* Build

* Add jsdoc comments to utils

* Remove unused file

* Add default values to js doc comments

* Use Redux Action type

* Housekeeping

* Increase utils coverage

* Apply suggestions from code review

* Add _getTemplate unit tests

* Resolve #533

* Add tests
2019-11-03 18:12:47 +00:00
Josh Johnson ab22347d7b
Code refactoring (#735)
* Add placeholder options to demo page

* Use constant types in components

* Refactor adding predefined groups/items/choices

* Add 'highlighted' flag to Item type

* Fix dispatch param type

* Build

* Add jsdoc comments to utils

* Remove unused file

* Add default values to js doc comments

* Use Redux Action type

* Housekeeping

* Increase utils coverage

* Apply suggestions from code review

* Add _getTemplate unit tests
2019-11-03 17:45:16 +00:00
Josh Johnson e6882f3e4b
Add missing type definitions + rename sortFn (#734)
* Add wrapped element getters + fix some types

* Remove comment

* Add missing config options to types

* Add types to constants

* Rename sortFn to sorter

* Update PR template

* Add refactor to PR template

* Add passed element types to constants

* Add js doc comments to actions

* Add "returns" to js doc comments

* Add missing choice prop to type

* Add types to store.js

* Add jsdoc comments to components

* Ignore strict null checks

* Move loading action into misc.js

* Further type def additions

* Rename itemCompare to valueCompare

* Update badges

* Rename scrollToChoice to scrollToChildElement
2019-11-03 13:18:16 +00:00
Josh Johnson 452c8fa666 Fix release drafter 2019-11-02 14:03:27 +00:00
Josh Johnson a0fe05f926
Fix #727 (#731)
* Housekeeping

* Resolve placeholder bug + hide from choice list

* Restructure test folder

* Update cypress test to assert one placeholder

* Fix breaking e2e test

* Remove ability to pass placeholder via config for select boxes

* Add further e2e tests covering placeholders

* Add unit tests for _generatePlaceholderValue

* Display placeholder choice for select one

* Add further e2e test to assert on placeholder ordering

* Add labels to exclude from draft releases

* Add failure case to e2e test workflow

* Resolve broken e2e test

* Update puppeteer snapshot baseline
2019-11-02 13:49:33 +00:00
Konstantin Vyatkin 939a73b762 fix setChoices flow (#730)
* fix setChoices flow

* ignore Promise as it gate checked

* re-run cypress
2019-11-02 12:58:18 +00:00
Konstantin Vyatkin 68f6b8e398 [bug] Override Prettier settings for Demo page (#733)
* add prettier override

* run prettier
2019-11-02 11:19:09 +00:00
Konstantin Vyatkin dddba5b35b [TEST] Automatic screenshots comparing and error checking in IE11, Firefox and Chrome (#715)
* taking screenshots

* let's try

* save artifacts

* better exceptiosn

* try to install geskodriver

* fix edge name

* add check for safari

* check os

* try this

* again

* fix syntax

* try this

* try firefox on windows

* and again

* handle error

* and again

* try older macos

* add firefox screenshot

* switch back env

* switch back env

* add IE screenshot

* try sudo for safari

* try not install nuget

* try more

* more

* try this

* install firefox

* add chrome

* increase threshold

* add firefox-darwin

* push

* fixing

* let's go

* increase threeshold

* again

* try safari tp

* tap cask versions

* fix conditions

* try like this

* last run

* increase threshold

* reenable macos firefox

* last try for safari

* rename screenshots to snapshots

* check console

* console workarounds

* fix safari misspleings

* logging is not supported by everyone

* maximize and set rect

* errors only for Chrome

* remove safari for now

* try to decrease threshold

* cleanup

* increase threeshold

* sleep more and increase threeshold

* add pupeeter

* handle errors

* build

* add prettier end of line

* add gitattributes

* add png to binary

* more attributest

* limit run

* run on chages to snapshots

* hey!

* make artifacts named as snapshots

* just for fun: we don't need express here

* update pupeeter snapshot

* no audit

* don't wait for quit?

* try more IE capabilities

* add wait timeout

* use server.js
2019-11-02 11:18:19 +00:00
Konstantin Vyatkin 5afe8b5a7f speed up getAdjacentEl (#726)
* use element accessors

* don't change params
2019-10-31 17:49:27 +00:00
Josh Johnson 9e11db8181
Add documentation label + headings (#729) 2019-10-31 17:40:02 +00:00
Josh Johnson 00e53f76ee
Update GitHub action workflows (#728)
* Deploy on published release

* Run build and test on merge to master

* Update release drafter template

* Update title of releases

* Testing cypress fix

* Pass group to --group flag
2019-10-31 17:28:12 +00:00
Konstantin Vyatkin 5051bf1b10 Fix lint (#723)
* adjust eslint config

* run prettier

* limit cypress run

* add all cypress files
2019-10-31 12:11:46 +00:00
Konstantin Vyatkin 034191c78a use CSS queries (#718)
* use matchMedia

* use last-of-type

* better type check

* simplify distanceFromTopWindow

* use visibility

* update JSDoc
2019-10-30 17:28:15 +00:00
Josh Johnson c03fcf5d03
Store config in file (#722) 2019-10-30 13:19:34 +00:00
Josh Johnson eb17194ff3
Add release drafter (#720)
* Add release management github action

* Simplify PR template

* Add chore to PR template

* Simplify labels

* Add housekeeping label

* Add refactor label
2019-10-30 13:10:52 +00:00
Josh Johnson 0e44a916e3
Fix constructor (#693)
* breaking test

* Remove ablity to pass multiple elements + tests

* Update readme

* Update README.md

* 🔖 Version 8.0.0

* Remove type definition hack

* Update coverage command

* Add some missing list tests

* Remove .only

* Update demo page to loop over elements

* Update constructor to set initialised flag if already active

* Make templates private

* Throw type error once if element is invalid

* Fix list children bug

* Re-add generic examples to index.html

* Housekeeping

* Use typeof instead of isType where applicable

* Remove isElement

* Add test for isIE11
2019-10-29 21:19:56 +00:00
Josh Johnson 88f63faa0b
Update code styling rules (#713)
* Enforce curly braces around conditionals

* Install sort class members + update rules

* Satisfy linting changes

* Add todo

* Add tests for clearChoices

* Update eslint-plugin-prettier to latest

* Resolve conflicts

* Fix linting errors
2019-10-29 18:26:11 +00:00
Konstantin Vyatkin 172366d6fa [Tooling] Expand browsers target while keeping Polyfills under control (#709)
* expand browsers target

* add eslint-plugin-compat

* sort polyfils

* adjust readme

* add polyfills sync check action

* only build js

* trim

* add Element.prototype.closest

* add closest to demo links

* fix ignore
2019-10-29 18:19:19 +00:00
Konstantin Vyatkin e3cc6eaf1b [MAJOR] Remove .ajax and allow async function for .setChoices (#701)
* WIP: remove ajax

* copy #700

* remove ajax, add fetchChoices

* extend setChoices

* update README
2019-10-29 18:12:32 +00:00
Konstantin Vyatkin 1f5192b4ad remove delegateEvents (#703) 2019-10-29 17:46:10 +00:00
Konstantin Vyatkin 2e004015d5 fix preventPaste (#707)
* what is preventPaste?

* fix preventPaste
2019-10-29 17:35:20 +00:00
Konstantin Vyatkin b080bcda7d rename addItemFilterFn (#699) 2019-10-29 17:29:31 +00:00
Konstantin Vyatkin 2a03d9be12 don't reemplement localeCompare (#695) 2019-10-29 17:09:49 +00:00
Tadeusz Wawszczak 2b8acc5f37 add clearChoices typings (#717) 2019-10-29 17:07:22 +00:00
Konstantin Vyatkin 9504cfcec5 [MAJOR] expose defaults and original Template rendering functions (#708)
* expose original Template rendering functions

* add to types

* add moduleResolution

* use `defaults`
2019-10-29 15:13:00 +00:00
Konstantin Vyatkin 1c751472b2 [Tooling] Transpile tests targeting Node, not browser (#700)
* transplite tests for higher target

* fix test

* add to lint-stagged too
2019-10-29 14:05:37 +00:00
Konstantin Vyatkin b48395ce36 fix dir (#711) 2019-10-29 14:02:24 +00:00
Konstantin Vyatkin a2485392a5 don't reimplement native closest (#696) 2019-10-28 20:26:19 +00:00
Josh Johnson 50fae125ed
Resolve on save vscode conflict (#714) 2019-10-28 20:26:03 +00:00
Josh Johnson 264a0cb486 Build 2019-10-28 19:53:24 +00:00
Konstantin Vyatkin 92d5e49fb6 [Tooling] VSCode Debug configurations and project settings (#705)
* configure tasks

* configure VSCode debugging

* adjust VSCode project settings

* fix bdd

* fix cypress path on macos/linux

* enforce checkJs

* make buildAndWatch default build task

* recommend and configure mocha-sidebar

* tune settings
2019-10-28 19:43:21 +00:00
Konstantin Vyatkin 64407174e3 closes #587 (#704) 2019-10-28 19:33:27 +00:00
Konstantin Vyatkin dbd15d7823 don't calculate pixel width (#694) 2019-10-28 19:27:10 +00:00
Konstantin Vyatkin 99f945bc03 raf is supported natively by JSDOM (#706) 2019-10-27 20:18:59 +00:00
Konstantin Vyatkin 312569a734 make hidden important (#702) 2019-10-27 20:17:30 +00:00
Konstantin Vyatkin 15d54c7d34 Remove classnames and use createElement (#687)
* enable restricted syntax in tests

* add Options to global

* crearte native elements

* remove unused helper

* fix/improve typings

* add JSDoc typings

* remove if/else
2019-10-25 15:43:28 +01:00
Konstantin Vyatkin ef2c70fb7a use default parameters (#698)
* use default parameters

* Fix argument name in README
2019-10-25 13:21:38 +01:00
Konstantin Vyatkin 69582349bb remove redundant CSS (#697)
* remove redundant CSS

* fix error with lack of test for false

* destruct dataset

* fix typo
2019-10-25 13:09:27 +01:00
Konstantin Vyatkin bef6743c3b set window target for minified build (#685)
* set `globalObject` option

* commit builded assets

* set window target for minified build
2019-10-24 18:21:40 +01:00
Konstantin Vyatkin 472e0dff39 [Tooling] use lint-stagged and unleash full Prettier (#692)
* switch to lint-stagged

* separate prettier config into external file

* recommend and configure VSCode extensions
2019-10-24 18:13:06 +01:00
Konstantin Vyatkin 7887c05249 [MAJOR] use attribute hidden (#691)
* use attribute hidden

* commit something to re-run tests
2019-10-24 18:09:44 +01:00
Josh Johnson 9bb0c628b2
Add deploy to gh pages action (#690) 2019-10-24 17:20:57 +01:00
Konstantin Vyatkin a35c8b9009 Fixing typings (again 🤷🏼‍♂️) + test for them (#682)
* add index notation

* add types check
2019-10-24 12:02:34 +01:00
Konstantin Vyatkin 1dbab0f29e upgrade Cypress to 3.5 (#686) 2019-10-24 07:50:00 +01:00
Konstantin Vyatkin e83f40956b fix typings (#681)
* fix typings

* allow array in constructor
2019-10-23 19:11:22 +01:00
Josh Johnson dc7cf42e90
Ignore branches that are not master (#678)
* Ignore branches that are not master

* List branches and ignored branches

* Remove tags check from npm publish instead

* 🔖 Version 7.1.5
2019-10-23 11:01:05 +01:00
302 changed files with 37925 additions and 21701 deletions

View file

@ -1,3 +1,17 @@
{
"presets": [["@babel/preset-env", { "loose": true }]]
"presets": [["@babel/preset-env", { "loose": true }]],
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": true
}
}
]
]
}
}
}

View file

@ -1,2 +1 @@
> 5%
IE 11
> 1%

View file

@ -1,2 +1,3 @@
node_modules/
types/
public/

View file

@ -1,56 +0,0 @@
{
"parserOptions": {
"ecmaVersion": 2020
},
"extends": ["airbnb-base", "prettier"],
"plugins": ["prettier"],
"env": {
"es6": true,
"browser": true
},
"rules": {
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true
}
],
"no-console": [
"warn",
{
"allow": ["warn", "error"]
}
],
"no-plusplus": "off",
"no-unused-expressions": "off",
"no-underscore-dangle": "off",
"consistent-return": "off",
"prettier/prettier": [
"error",
{
"singleQuote": true,
"trailingComma": "all"
}
],
"import/no-useless-path-segments": "warn",
"prefer-destructuring": ["warn", {
"array": false,
"object": true
}]
},
"overrides": [
{
"files": ["*.test.js"],
"env": {
"mocha": true
}
},
{
"files": ["cypress/**/*.spec.js"],
"plugins": ["cypress"],
"env": {
"cypress/globals": true
}
}
]
}

123
.eslintrc.json Normal file
View file

@ -0,0 +1,123 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier", "sort-class-members"],
"extends": [
"airbnb-base",
"airbnb-typescript",
"plugin:prettier/recommended",
"plugin:compat/recommended",
"plugin:@typescript-eslint/recommended"
],
"env": {
"es6": true,
"browser": true,
"mocha": true,
"cypress/globals": true
},
"parserOptions": {
"project": "./tsconfig.json",
"ecmaVersion": 2020
},
"rules": {
"import/prefer-default-export": "off",
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true
}
],
"no-console": [
"warn",
{
"allow": ["warn", "error"]
}
],
"no-plusplus": "off",
"no-unused-expressions": "off",
"no-underscore-dangle": "off",
"consistent-return": "off",
"import/no-useless-path-segments": "warn",
"prefer-destructuring": [
"warn",
{
"array": false,
"object": true
}
],
"curly": ["error", "all"],
"newline-before-return": "error",
"sort-class-members/sort-class-members": [
2,
{
"order": [
"[static-properties]",
"[static-methods]",
"[properties]",
"[conventional-private-properties]",
"constructor",
"[methods]",
"[conventional-private-methods]"
],
"accessorPairPositioning": "getThenSet"
}
],
"lines-between-class-members": "off",
"@typescript-eslint/no-namespace": "off",
"react/jsx-filename-extension": [0]
},
"overrides": [
{
"files": ["*.test.ts"],
"env": {
"mocha": true
},
"rules": {
"no-restricted-syntax": "off",
"compat/compat": "off",
"no-new": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "default",
"format": ["camelCase", "PascalCase", "UPPER_CASE"],
"leadingUnderscore": "allow"
}
]
}
},
{
"files": ["cypress/**"],
"plugins": ["cypress"],
"rules": {
"no-unused-vars": "warn"
},
"env": {
"cypress/globals": true
}
}
],
"settings": {
"polyfills": [
"Array.from",
"Array.prototype.find",
"Array.prototype.includes",
"Symbol",
"Symbol.iterator",
"DOMTokenList",
"Object.assign",
"CustomEvent",
"Element.prototype.classList",
"Element.prototype.closest",
"Element.prototype.dataset"
],
"import/resolver": {
"node": {
"extensions": [".js", ".ts"]
}
}
}
}

64
.gitattributes vendored Normal file
View file

@ -0,0 +1,64 @@
## GITATTRIBUTES FOR WEB PROJECTS
#
# These settings are for any web project.
#
# Details per file setting:
# text These files should be normalized (i.e. convert CRLF to LF).
# binary These files are binary and should be left untouched.
#
# Note that binary is a macro for -text -diff.
######################################################################
# Auto detect
## Handle line endings automatically for files detected as
## text and leave all files detected as binary untouched.
## This will handle all files NOT defined below.
* text eol=lf
# Source code
*.css text eol=lf
*.html text diff=html eol=lf
*.js text eol=lf
*.json text eol=lf
*.scss text diff=css eol=lf
*.ts text eol=lf
# Documentation
*.md text eol=lf
*.txt text eol=lf
AUTHORS text eol=lf
CHANGELOG text eol=lf
CHANGES text eol=lf
CONTRIBUTING text eol=lf
COPYING text eol=lf
copyright text eol=lf
*COPYRIGHT* text eol=lf
INSTALL text eol=lf
license text eol=lf
LICENSE text eol=lf
NEWS text eol=lf
readme text eol=lf
*README* text eol=lf
TODO text eol=lf
# Linters
.eslintrc text eol=lf
.stylelintrc text eol=lf
# Configs
.babelrc text eol=lf
.browserslistrc text eol=lf
.editorconfig text eol=lf
.env text eol=lf
.gitattributes text eol=lf
.gitconfig text eol=lf
package-lock.json text -diff eol=lf
*.npmignore text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
browserslist text eol=lf
# Graphics
# SVG treated as an asset (binary) by default.
*.svg text eol=lf
*.png binary

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -1,28 +1,28 @@
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Describe your changes in detail -->
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, tests ran to see how -->
<!--- your change affects other areas of the code, etc. -->
## Screenshots (if appropriate):
## Screenshots (if appropriate)
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Chore (tooling change or documentation change)
- [ ] Refactor (non-breaking change which maintains existing functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
## Checklist:
## Checklist
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] I have added new tests for the bug I fixed/the new feature I added.
- [ ] I have modified existing tests for the bug I fixed/the new feature I added.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

View file

@ -0,0 +1,14 @@
const { readFileSync } = require('fs');
const path = require('path');
const assert = require('assert');
const readme = readFileSync(path.resolve(__dirname, '../../README.md'), 'utf8');
const polyfillsFromDocs = /^```polyfills\s*\n([^`]+)\n^```/m
.exec(readme)[1]
.split('\n')
.map(v => v.trim())
.sort();
// @ts-ignore
const polyfillsFromSettings = require('../../.eslintrc.json').settings.polyfills.sort();
assert.deepStrictEqual(polyfillsFromDocs, polyfillsFromSettings);

92
.github/actions-scripts/puppeteer.js vendored Normal file
View file

@ -0,0 +1,92 @@
const { readFileSync, writeFileSync, mkdirSync } = require('fs');
const path = require('path');
const { once } = require('events');
const puppeteer = require('puppeteer');
const pixelmatch = require('pixelmatch');
const { PNG } = require('pngjs');
const server = require('../../server');
async function test() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const artifactsPath = 'screenshot';
const snapshotName = `puppeteer-${process.platform}.png`;
let error;
let pixelDifference;
let diff;
if (!server.listening) await once(server, 'listening');
try {
page.on('console', msg => {
if (msg.type() === 'error') throw new Error(msg.text());
});
page.on('pageerror', err => {
throw err;
});
await page.goto(`http://127.0.0.1:${server.address().port}`, {
waitUntil: 'networkidle2',
});
await page.setViewport({ width: 640, height: 1000 });
await page.waitForTimeout(500); // Wait for resize to complete
await page.click('label[for="choices-single-custom-templates"]');
await page.keyboard.press('ArrowDown');
await page.keyboard.press('ArrowDown');
mkdirSync(artifactsPath, { recursive: true });
const imageBuffer = await page.screenshot({
path: path.join(artifactsPath, snapshotName),
fullPage: true,
});
// compare with snapshot
const screenshot = PNG.sync.read(imageBuffer);
const snapshot = PNG.sync.read(
readFileSync(path.resolve(__dirname, `./__snapshots__/${snapshotName}`)),
);
const { width, height } = screenshot;
diff = new PNG({ width, height });
pixelDifference = pixelmatch(
screenshot.data,
snapshot.data,
diff.data,
width,
height,
{
threshold: 0.6,
},
);
} catch (err) {
console.error(err);
error = err;
} finally {
if (diff) {
writeFileSync(path.join(artifactsPath, 'diff-' + snapshotName), PNG.sync.write(diff));
}
await Promise.all([
browser.close(),
new Promise(resolve => server.close(resolve)),
]);
}
if (pixelDifference > 200) {
console.error(
`Snapshot is different from screenshot by ${pixelDifference} pixels`,
);
process.exit(1);
}
if (error) process.exit(1);
}
process.on('unhandledRejection', err => {
console.error(err);
process.exit(1);
});
process.once('uncaughtException', err => {
console.error(err);
process.exit(1);
});
setImmediate(test);

155
.github/actions-scripts/selenium.js vendored Normal file
View file

@ -0,0 +1,155 @@
const path = require('path');
const { readFileSync, writeFileSync, mkdirSync } = require('fs');
const { once } = require('events');
const pixelmatch = require('pixelmatch');
const { PNG } = require('pngjs');
const {
Builder,
By,
Key,
until,
Capabilities,
logging,
} = require('selenium-webdriver');
const server = require('../../server');
async function test() {
let pixelDifference;
let error;
let capabilities;
switch (process.env.BROWSER) {
case 'ie':
capabilities = Capabilities.ie();
capabilities.set('ignoreProtectedModeSettings', true);
capabilities.set('ignoreZoomSetting', true);
capabilities.set('ie.options', {
enableFullPageScreenshot: true,
ensureCleanSession: true,
});
break;
case 'edge':
capabilities = Capabilities.edge();
break;
case 'safari':
capabilities = Capabilities.safari();
capabilities.set('safari.options', { technologyPreview: false });
break;
case 'firefox': {
capabilities = Capabilities.firefox().setLoggingPrefs({ browser: 'ALL' });
break;
}
case 'chrome': {
capabilities = Capabilities.chrome().setLoggingPrefs({ browser: 'ALL' });
capabilities.set('chromeOptions', {
args: ['--headless', '--no-sandbox', '--disable-gpu'],
});
break;
}
}
let driver = await new Builder().withCapabilities(capabilities).build();
if (!server.listening) await once(server, 'listening');
try {
await driver.get(`http://127.0.0.1:${server.address().port}`);
// wait for last choice to init
await driver.wait(
until.elementLocated(By.css('#reset-multiple ~ .choices__list')),
10000,
'waiting for all Choices instances to init',
);
// Resize window
await driver
.manage()
.window()
.maximize();
await driver
.manage()
.window()
// magic numbers here to make sure all demo page are fit inside
.setRect({ x: 0, y: 0, width: 630, height: 4000 });
// and click on press space on it, so it should open choices
await driver
.findElement(By.css('#reset-multiple ~ .choices__list button'))
.sendKeys(Key.SPACE);
await driver.sleep(1000);
// take screenshot
const image = await driver.takeScreenshot();
const imageBuffer = Buffer.from(image, 'base64');
const snapshotName = `${process.env.BROWSER}-${process.platform}.png`;
const artifactsPath = 'screenshot';
mkdirSync(artifactsPath, { recursive: true });
writeFileSync(path.join(artifactsPath, snapshotName), imageBuffer);
// compare with snapshot
const screenshot = PNG.sync.read(imageBuffer);
const snapshot = PNG.sync.read(
readFileSync(path.resolve(__dirname, `./__snapshots__/${snapshotName}`)),
);
const { width, height } = screenshot;
const diff = new PNG({ width, height });
pixelDifference = pixelmatch(
screenshot.data,
snapshot.data,
diff.data,
width,
height,
{
threshold: 1,
},
);
writeFileSync(path.join(artifactsPath, 'diff.png'), PNG.sync.write(diff));
// getting console logs
// ensure no errors in console (only supported in Chrome currently)
if (process.env.BROWSER === 'chrome') {
const entries = await driver
.manage()
.logs()
.get(logging.Type.BROWSER);
if (
Array.isArray(entries) &&
entries.some(entry => entry.level.name_ === 'SEVERE')
)
throw new Error(JSON.stringify(entries));
}
} catch (err) {
console.error(err);
error = err;
} finally {
await Promise.all([
driver.quit(),
new Promise(resolve => server.close(resolve)),
]);
}
if (pixelDifference > 200) {
console.error(
`Snapshot is different from screenshot by ${pixelDifference} pixels`,
);
process.exit(1);
}
if (error) process.exit(1);
}
process.on('unhandledRejection', err => {
console.error(err);
process.exit(1);
});
process.once('uncaughtException', err => {
console.error(err);
process.exit(1);
});
setImmediate(test);

29
.github/release-drafter.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name-template: 'Draft (next release)'
tag-template: 'v$NEXT_PATCH_VERSION'
sort-direction: descending
exclude-labels:
- 'skip-changelog'
- 'release'
categories:
- title: '🚨 Breaking changes'
labels:
- 'breaking change'
- title: '🚀 Features'
labels:
- 'feature'
- 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'bugfix'
- title: '🔧 Maintenance'
labels:
- 'chore'
- 'housekeeping'
- 'refactor'
- 'documentation'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
# Changes
$CHANGES
# Contributors
$CONTRIBUTORS

131
.github/workflows/browsers.yml vendored Normal file
View file

@ -0,0 +1,131 @@
name: Browsers
on:
pull_request:
paths:
- 'src/**'
- 'package-lock.json'
- '.browserslistrc'
- '.babelrc'
- 'webpack.config.*'
- 'public/index.html'
- '.github/actions-scripts/__snapshots__/**'
- '.github/workflows/browsers.yml'
jobs:
selenium:
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest]
browser: [edge, firefox, safari, chrome]
exclude:
- os: windows-latest
browser: safari
- os: macos-latest
browser: edge
- os: macos-latest
browser: chrome
# Safari workaround is not working in Catalina
- browser: safari
runs-on: ${{ matrix.os }}
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18.x
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.OS }}-build-${{ matrix.browser }}
restore-keys: |
${{ runner.OS }}-build-${{ env.cache-name }}-
${{ runner.OS }}-build-
${{ runner.OS }}-
- run: |
npm ci
npm run build
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
# install drivers
- name: Enable Safari Driver
run: |
# Workaround for `sudo safardriver --enable` not working:
# https://github.com/web-platform-tests/wpt/issues/19845
# https://github.com/web-platform-tests/wpt/blob/master/tools/ci/azure/install_safari.yml
mkdir -p ~/Library/WebDriver/
curl https://raw.githubusercontent.com/web-platform-tests/wpt/master/tools/ci/azure/com.apple.Safari.plist -o ~/Library/WebDriver/com.apple.Safari.plist
defaults write com.apple.Safari WebKitJavaScriptCanOpenWindowsAutomatically 1
# sudo safaridriver --enable
if: matrix.browser == 'safari'
- run: |
brew install --cask firefox
brew install geckodriver
if: matrix.browser == 'firefox' && matrix.os == 'macos-latest'
- run: echo "$env:GeckoWebDriver" >> $GITHUB_PATH
if: matrix.browser == 'firefox' && matrix.os == 'windows-latest'
- run: echo "$env:EdgeWebDriver" >> $GITHUB_PATH
if: matrix.browser == 'edge' && matrix.os == 'windows-latest'
- run: echo "$env:ChromeWebDriver" >> $GITHUB_PATH
if: matrix.browser == 'chrome' && matrix.os == 'windows-latest'
- run: npm i --no-optional --no-audit selenium-webdriver pixelmatch pngjs
- run: node .github/actions-scripts/selenium.js
env:
BROWSER: ${{ matrix.browser }}
PORT: 0
NODE_ENV: production # prevent watching
- uses: actions/upload-artifact@v2
if: failure()
with:
name: screenshot-${{ matrix.browser }}-${{ matrix.os }}
path: screenshot
puppeteer:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.OS }}-build-puppeteer
restore-keys: |
${{ runner.OS }}-build-puppeteer
- run: |
npm ci
npm run build
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- run: npm i --no-optional --no-audit puppeteer pixelmatch pngjs
- run: node .github/actions-scripts/puppeteer.js
env:
PORT: 0
NODE_ENV: production # prevent watching
- uses: actions/upload-artifact@v2
if: failure()
with:
name: screenshot-puppeteer-darwin
path: screenshot

View file

@ -1,28 +1,26 @@
name: Publish Package
name: Build and test
on:
push:
branches:
- master
tags:
- v*
jobs:
build:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 10
# run all tests
- run: |
node-version: 18
- name: Build and run all tests
run: |
npm ci
npm run build
npx bundlesize
npm run coverage
npm run test:unit:coverage
npm run test:e2e
env:
CI: true
@ -34,6 +32,20 @@ jobs:
BUNDLESIZE_GITHUB_TOKEN: ${{secrets.BUNDLESIZE_GITHUB_TOKEN}}
FORCE_COLOR: 2
HUSKY_SKIP_INSTALL: true
##
## Disabling for now. There does not appear to be a secure way to do this
## with protected branches. See discussion:
## https://github.community/t/how-to-push-to-protected-branches-in-a-github-action/16101
##
# - name: Commit built files
# run: |
# git config --local user.email "action@github.com"
# git config --local user.name "GitHub Action"
# git commit -m "Update build files 🏗" -a || echo "No changes to commit" && exit 0
# - name: Push changes
# uses: ad-m/github-push-action@master
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload coverage to Codecov
run: bash <(curl -s https://codecov.io/bash)
@ -46,38 +58,3 @@ jobs:
GITLAB_CI: true # pretend we are GitLab CI, while Codecov adding support for Github Actions
CODECOV_ENV: github-action
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- uses: actions/setup-node@v1
with:
node-version: 10
registry-url: https://registry.npmjs.org/
- run: npm ci
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
publish-github:
needs: publish-npm
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- run: echo ${{ github.sha }} > RELEASE.txt
- run: cat RELEASE.txt
- uses: softprops/action-gh-release@v1
with:
files: RELEASE.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,4 +1,4 @@
name: BundleSize
name: Bundle size checks
on:
pull_request:
@ -12,13 +12,13 @@ jobs:
measure:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 10
node-version: 18
- name: Install dependencies and build
run: |

View file

@ -1,32 +0,0 @@
name: Cypress
on: [pull_request]
jobs:
test-e2e:
name: integration tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 1
- uses: actions/setup-node@v1
with:
node-version: 10
- name: Install dependencies
run: npm ci
env:
HUSKY_SKIP_INSTALL: true
- name: run Cypress
run: npx run-p --race start cypress:run
env:
CI: true
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
DEBUG: commit-info,cypress:server:record
# https://docs.cypress.io/guides/guides/continuous-integration.html#Environment-variables
COMMIT_INFO_BRANCH: ${{ github.head_ref }}
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }}
COMMIT_INFO_SHA: ${{ github.event.after }}

32
.github/workflows/deploy-pages.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: Deploy Pages
on:
release:
types: [published]
workflow_dispatch:
jobs:
deploy-gh-pages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- name: Build
run: |
npm ci
npm run build
rm -rf public/test
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PUBLISH_BRANCH: gh-pages
PUBLISH_DIR: ./public

24
.github/workflows/deployment.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Publish to npm
on:
release:
types: [published]
jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
registry-url: https://registry.npmjs.org/
- run: npm ci
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

71
.github/workflows/e2e-tests.yml vendored Normal file
View file

@ -0,0 +1,71 @@
name: End-to-end tests
on:
pull_request:
paths:
- 'src/**'
- 'package-lock.json'
- '.browserslistrc'
- '.babelrc'
- 'webpack.config.*'
- 'public/test/**'
- 'cypress/**'
- '.github/workflows/e2e-tests.yml'
jobs:
test-e2e:
runs-on: ubuntu-latest
env:
CI: true
TERM: xterm-256color
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18.x
- name: Cache node modules
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.OS }}-build-${{ env.cache-name }}-
${{ runner.OS }}-build-
${{ runner.OS }}-
- name: Get Cypress info
id: cypress-info
run: |
echo ::set-output name=version::$(jq -r .devDependencies.cypress ./package.json)
echo ::set-output name=cache::$(npx cypress cache path)
env:
CYPRESS_INSTALL_BINARY: 0
- name: Cache Cypress cache
uses: actions/cache@v2
with:
path: ${{ steps.cypress-info.outputs.cache }}
key: ${{ runner.OS }}-cypress-${{ steps.cypress-info.outputs.version }}
restore-keys: |
${{ runner.OS }}-cypress-${{ steps.cypress-info.outputs.version }}
- name: Install dependencies
run: npm ci
env:
HUSKY_SKIP_INSTALL: true
- name: run Cypress (with or without recording)
# if we have ran out of free Cypress recordings, run Cypress with recording switched off
run: npm exec -- run-p --race start cypress:ci || npm exec -- run-p --race start cypress:run
env:
NODE_ENV: production # prevent watching
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
DEBUG: commit-info,cypress:server:record
# https://docs.cypress.io/guides/guides/continuous-integration.html#Environment-variables
COMMIT_INFO_BRANCH: ${{ github.head_ref }}
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }}
COMMIT_INFO_SHA: ${{ github.event.after }}

View file

@ -1,9 +1,10 @@
name: Lint
name: Code linting
on:
pull_request:
paths:
- 'src/scripts/**'
- 'src/styles/**'
- package-lock.json
- '.browserslistrc'
@ -11,23 +12,30 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 10
node-version: 18
- name: Install dependencies
run: npm install --no-optional --no-audit --ignore-scripts
run: npm ci
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- name: run eslint
run: |
CHANGED_JS=$(git --no-pager diff --name-only ..origin/master | grep '^src\/scripts\/.*\.js$' | 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
run: npm run lint:js
## Can't use same eslint config for TypeScript and JavaScript
## TypeScript rules cause rule definition not found errors
## Can be re-enabled if this is resolved: https://github.com/eslint/eslint/issues/14851
# - name: Lint JS bundle
# run: |
# npm run js:build
# npx eslint --no-ignore ./public/assets/scripts/*.js
- name: run stylelint
run: npm run lint:scss

23
.github/workflows/polyfills-sync.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Polyfills documentation
on:
pull_request:
paths:
- 'README.md'
- '.browserslistrc'
- '.eslintrc.json'
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
- name: Check Polyfills documentation and settings sync
run: node .github/actions-scripts/polyfills-sync.js

14
.github/workflows/release-drafter.yml vendored Normal file
View file

@ -0,0 +1,14 @@
name: Release drafter
on:
push:
branches:
- master
jobs:
update-draft-release:
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -1,4 +1,4 @@
name: Unit Tests
name: Unit tests
on:
pull_request:
@ -11,13 +11,13 @@ jobs:
test-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: 10
node-version: 18
- name: Install dependencies
run: npm install --no-optional --no-audit --ignore-scripts
@ -25,7 +25,7 @@ jobs:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- run: npm run coverage
- run: npm run test:unit:coverage
env:
FORCE_COLOR: 2

6
.huskyrc Normal file
View file

@ -0,0 +1,6 @@
{
"skipCI": true,
"hooks": {
"pre-commit": "lint-staged"
}
}

View file

@ -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

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
v12.13.1

20
.prettierrc.json Normal file
View file

@ -0,0 +1,20 @@
{
"singleQuote": true,
"trailingComma": "all",
"endOfLine": "lf",
"overrides": [
{
"files": ["*.svg"],
"options": {
"parser": "html",
"htmlWhitespaceSensitivity": "ignore"
}
},
{
"files": ["public/*.html"],
"options": {
"trailingComma": "es5"
}
}
]
}

6
.stylelintrc.json Normal file
View file

@ -0,0 +1,6 @@
{
"extends": "stylelint-config-standard-scss",
"rules": {
"declaration-block-no-redundant-longhand-properties": null
}
}

17
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,17 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
// we enforce ESLint rules, so, recommend extension
"dbaeumer.vscode-eslint",
// we use prettier, so, recommend extension
"esbenp.prettier-vscode",
// we are on GitHub, so, recommend extension
"github.vscode-pull-request-github",
// needed for our configured debug configuration with Chrome
"msjsdiag.debugger-for-chrome"
// Mocha recommended - https://mochajs.org/#mocha-sidebar-vs-code,
// but it's buggy
// "maty.vscode-mocha-sidebar"
]
}

70
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,70 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"preLaunchTask": "buildAndWatch",
"url": "http://localhost:3001",
"webRoot": "${workspaceFolder}",
"sourceMapPathOverrides": {
"webpack://Choices/*": "${workspaceFolder}/*"
}
},
{
"type": "node",
"request": "launch",
"name": "Mocha Current File",
"program": "${workspaceFolder}/node_modules/mocha/bin/mocha",
"args": ["-u", "bdd", "--timeout", "999999", "--colors", "${file}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"env": {
"NODE_ENV": "test"
}
},
{
"type": "node",
"request": "launch",
"name": "Mocha All",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"args": ["-u", "bdd", "--timeout", "999999", "--colors"],
"console": "integratedTerminal",
"internalConsoleOptions": "openOnSessionStart",
"env": {
"NODE_ENV": "test"
}
},
{
"type": "node",
"request": "launch",
"name": "Cypress Current File",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/cypress",
"windows": {
"runtimeExecutable": "${workspaceFolder}\\node_modules\\.bin\\cypress.cmd"
},
"runtimeArgs": [
"run",
"--headed",
"--no-exit",
"--browser=electron",
"--port",
"9898",
"--spec"
],
"protocol": "legacy",
"port": 9898,
"program": "${file}",
"console": "integratedTerminal",
"preLaunchTask": "buildAndWatch",
"internalConsoleOptions": "openOnSessionStart",
"timeout": 999999999999999,
"autoAttachChildProcesses": false,
"env": {
"NODE_ENV": "test"
// "DEBUG": "cypress:*"
}
}
]
}

71
.vscode/settings.json vendored
View file

@ -1,3 +1,72 @@
{
"eslint.enable": true
"eslint.enable": true,
// prevent watch task failures on lint errors
"eslint.autoFixOnSave": true,
// switch off default VSCode formatting rules
"javascript.format.enable": false,
// Javascript prettier runs via ESLint
"prettier.disableLanguages": ["javascript"],
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.formatOnSave": false
},
"search.exclude": {
"**/node_modules": true,
"public/assets": true,
"**/coverage": true
},
// Mocha Sidebar settings
"mocha.env": {
"NODE_ENV": "test"
},
"mocha.files.glob": "src/scripts/**/*.test.js",
"mocha.requires": ["@babel/register", "./config/jsdom.js"],
// for Windows collaborators
"files.eol": "\n",
"files.encoding": "utf8",
// associations for some files this project is using
"files.associations": {
".browserslistrc": "gitignore",
".huskyrc": "jsonc",
".npmrc": "ini"
},
// We use NPM as package manager
"npm.packageManager": "npm",
"npm.autoDetect": "on",
"npm.fetchOnlinePackageInfo": true,
"eslint.packageManager": "npm",
"json.schemas": [
// Cypress related settings - https://docs.cypress.io/guides/tooling/intelligent-code-completion.html#Features-1
{
"fileMatch": ["cypress.json"],
"url": "https://on.cypress.io/cypress.schema.json"
},
// Husky config file
{
"fileMatch": [".huskyrc"],
"url": "http://json.schemastore.org/huskyrc"
},
// Prettier config
{
"fileMatch": [".prettierrc.json"],
"url": "http://json.schemastore.org/prettierrc"
}
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"stylelint.validate": [
"css",
"less",
"postcss",
"scss"
]
}

87
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,87 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"label": "buildAndWatch",
"script": "js:watch",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": true,
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "dedicated",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": [
"$eslint-stylish",
{
"owner": "webpack",
"fileLocation": "absolute",
"pattern": [
{
"regexp": "^Module build failed \\(from (\\.+)\\)",
"file": 1,
"line": 2,
"column": 3
},
{
"regexp": "\\s*TS\\d+:\\s*(.*)",
"message": 1
}
],
"severity": "error",
"source": "webpack",
"background": {
"activeOnStart": true,
"beginsPattern": "^Listening at",
"endsPattern": "Compiled successfully\\."
}
}
]
},
{
"type": "npm",
"script": "css:build",
"group": "build",
"problemMatcher": ["$node-sass"]
},
{
"type": "npm",
"script": "lint",
"problemMatcher": ["$eslint-stylish"]
},
{
"type": "npm",
"script": "build",
"group": "build"
},
{
"type": "npm",
"script": "test",
"group": "test"
},
{
"type": "npm",
"script": "test:e2e",
"group": "test"
},
{
"type": "npm",
"script": "test:unit",
"group": "test"
},
{
"type": "npm",
"script": "cypress:open",
"isBackground": true
}
]
}

View file

@ -5,7 +5,8 @@ In lieu of a formal styleguide, take care to maintain the existing coding style
| Task | Usage |
| -------------------- | ------------------------------------------------------------ |
| `npm run start` | Fire up local server for development |
| `npm run test` | Run sequence of tests once |
| `npm run test:unit` | Run sequence of unit tests once |
| `npm run test:e2e` | Run sequence of integration tests once |
| `npm run test:watch` | Fire up test server and re-test on file change |
| `npm run js:build` | Compile Choices to an uglified JavaScript file |
| `npm run css:watch` | Watch SCSS files for changes. On a change, run build process |

500
README.md

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,13 @@
/* eslint-disable no-param-reassign */
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
const jsdom = new JSDOM(
'<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>',
{
pretendToBeVisual: true,
},
);
const { window } = jsdom;
function copyProps(src, target) {
@ -20,26 +27,6 @@ function ignoreExtensions(extensions = [], returnValue = {}) {
});
}
function mockRAF(global) {
let callbacksQueue = [];
global.setInterval(() => {
for (let i = 0; i < callbacksQueue.length; i++) {
if (callbacksQueue[i] !== false) {
callbacksQueue[i].call(null);
}
}
callbacksQueue = [];
}, 1000 / 60);
global.requestAnimationFrame = callback => callbacksQueue.push(callback) - 1;
global.cancelAnimationFrame = id => {
callbacksQueue[id] = false;
};
}
global.window = window;
global.document = window.document;
global.navigator = {
@ -48,12 +35,16 @@ global.navigator = {
global.CustomEvent = window.CustomEvent;
global.Element = window.Element;
global.HTMLElement = window.HTMLElement;
global.Option = window.Option;
global.HTMLOptionElement = window.HTMLOptionElement;
global.HTMLOptGroupElement = window.HTMLOptGroupElement;
global.HTMLSelectElement = window.HTMLSelectElement;
global.HTMLInputElement = window.HTMLInputElement;
global.DocumentFragment = window.DocumentFragment;
global.requestAnimationFrame = window.requestAnimationFrame;
window.matchMedia = () => true;
copyProps(window, global);
mockRAF(global);
ignoreExtensions(['.scss', '.css']);
ignoreExtensions(['.jpg', '.png', '.svg'], '');

15
cypress.config.ts Normal file
View file

@ -0,0 +1,15 @@
import { defineConfig } from 'cypress'
export default defineConfig({
video: false,
projectId: 'n7g5qp',
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
return require('./cypress/plugins/index.js')(on, config)
},
baseUrl: 'http://localhost:3001/test',
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
},
})

View file

@ -1,5 +0,0 @@
{
"baseUrl": "http://localhost:3001/test",
"video": false,
"projectId": "n7g5qp"
}

View file

@ -1,6 +1,10 @@
describe('Choices - select multiple', () => {
beforeEach(() => {
cy.visit('/select-multiple.html');
cy.visit('/select-multiple', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
});
describe('scenarios', () => {
@ -30,6 +34,7 @@ describe('Choices - select multiple', () => {
beforeEach(() => {
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.wait(200) // Otherwise these tests are flaky
.type('{esc}');
});
@ -62,7 +67,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then($choice => {
.then(($choice) => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -72,15 +77,15 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--multiple .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item).to.contain(selectedChoiceText);
});
});
it('updates the value of the original input', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__input.is-hidden')
.should($select => {
.find('.choices__input[hidden]')
.should(($select) => {
expect($select.val()).to.contain(selectedChoiceText);
});
});
@ -89,7 +94,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown .choices__list')
.children()
.each($choice => {
.each(($choice) => {
expect($choice.text().trim()).to.not.equal(selectedChoiceText);
});
});
@ -114,7 +119,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal('No choices to choose from');
});
@ -130,7 +135,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then($choice => {
.then(($choice) => {
removedChoiceText = $choice.text().trim();
})
.click();
@ -150,8 +155,8 @@ describe('Choices - select multiple', () => {
it('updates the value of the original input', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__input.is-hidden')
.should($select => {
.find('.choices__input[hidden]')
.should(($select) => {
const val = $select.val() || [];
expect(val).to.not.contain(removedChoiceText);
});
@ -171,7 +176,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 2');
});
});
@ -187,7 +192,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 3');
});
});
@ -202,7 +207,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal('No results found');
});
@ -370,7 +375,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=selection-limit]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Only ${selectionLimit} values can be added`,
@ -397,7 +402,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then($choice => {
.then(($choice) => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -407,7 +412,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(
`before-${selectedChoiceText}-after`,
);
@ -418,7 +423,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text()).to.not.contain(
`before-${selectedChoiceText}-after`,
);
@ -460,7 +465,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.not.contain(searchTerm);
});
});
@ -478,7 +483,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.contain(searchTerm);
});
});
@ -486,20 +491,42 @@ describe('Choices - select multiple', () => {
});
});
describe('placeholder', () => {
/*
{
placeholder: true,
placeholderValue: 'I am a placeholder',
}
*/
describe('placeholder via empty option value', () => {
describe('when no value has been inputted', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder]')
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.should('have.attr', 'placeholder', 'I am a placeholder');
});
});
describe('when a value has been inputted', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.type('test')
.should('not.have.value', 'I am a placeholder');
});
});
});
describe('placeholder via option attribute', () => {
describe('when no value has been inputted', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.should('have.attr', 'placeholder', 'I am a placeholder');
});
});
describe('when a value has been inputted', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.type('test')
.should('not.have.value', 'I am a placeholder');
});
});
});
describe('remote data', () => {
@ -548,7 +575,7 @@ describe('Choices - select multiple', () => {
beforeEach(() => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .choices__item')
.then($choices => {
.then(($choices) => {
choicesCount = $choices.length;
});
@ -560,19 +587,20 @@ describe('Choices - select multiple', () => {
it('highlights first choice on dropdown open', () => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
it('scrolls to next choice on down arrow', () => {
for (let index = 0; index < choicesCount; index++) {
for (let index = 1; index <= choicesCount; index++) {
cy.wait(100);
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
.invoke('text')
.then((text) => {
expect(text.trim()).to.equal(`Choice ${index}`);
});
cy.get('[data-test-hook=scrolling-dropdown]')
@ -595,8 +623,9 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
expect($choice.text().trim()).to.equal(`Choice ${index}`);
.invoke('text')
.then((text) => {
expect(text.trim()).to.equal(`Choice ${index}`);
});
cy.get('[data-test-hook=scrolling-dropdown]')
@ -614,7 +643,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.then($group => {
.then(($group) => {
groupValue = $group.text().trim();
});
});
@ -635,7 +664,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.should($group => {
.should(($group) => {
expect($group.text().trim()).to.not.equal(groupValue);
});
});
@ -666,7 +695,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.should($group => {
.should(($group) => {
expect($group.text().trim()).to.equal(groupValue);
});
});
@ -706,7 +735,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(city);
});
@ -718,13 +747,75 @@ describe('Choices - select multiple', () => {
});
});
describe('non-string values', () => {
describe('custom properties via HTML', () => {
beforeEach(() => {
cy.get('[data-test-hook=non-string-values]')
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices')
.click();
});
describe('on input', () => {
it('filters choices based on a string custom property', () => {
const data = [
{
searchText: 'fantastic',
label: 'Label Three',
},
];
data.forEach(({ searchText, label }) => {
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type(searchText);
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal(label);
});
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type('{selectall}{del}');
});
});
it('filters choices based on a JSON custom property', () => {
const data = [
{
searchText: 'foo',
label: 'Label Four',
},
];
data.forEach(({ searchText, label }) => {
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type(searchText);
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal(label);
});
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type('{selectall}{del}');
});
});
});
});
describe('non-string values', () => {
beforeEach(() => {
cy.get('[data-test-hook=non-string-values]').find('.choices').click();
});
it('displays expected amount of choices in dropdown', () => {
cy.get('[data-test-hook=non-string-values]')
.find('.choices__list--dropdown .choices__list')
@ -738,7 +829,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then($choice => {
.then(($choice) => {
$selectedChoice = $choice;
})
.click();
@ -746,7 +837,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=non-string-values]')
.find('.choices__list--single .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item.text().trim()).to.equal($selectedChoice.text().trim());
});
});
@ -756,7 +847,7 @@ describe('Choices - select multiple', () => {
describe('selecting choice', () => {
describe('on enter key', () => {
it('selects choice', () => {
cy.get('[data-test-hook=within-form] form').then($form => {
cy.get('[data-test-hook=within-form] form').then(($form) => {
$form.submit(() => {
// this will fail the test if the form submits
throw new Error('Form submitted');
@ -771,7 +862,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=within-form]')
.find('.choices__list--multiple .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item).to.contain('Choice 1');
});
});
@ -786,7 +877,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(
dynamicallySelectedChoiceValue,
);
@ -797,7 +888,7 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__list--dropdown .choices__list')
.children()
.each($choice => {
.each(($choice) => {
expect($choice.text().trim()).to.not.equal(
dynamicallySelectedChoiceValue,
);
@ -806,8 +897,8 @@ describe('Choices - select multiple', () => {
it('updates the value of the original input', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__input.is-hidden')
.should($select => {
.find('.choices__input[hidden]')
.should(($select) => {
const val = $select.val() || [];
expect(val).to.contain(dynamicallySelectedChoiceValue);
});
@ -824,7 +915,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('No results found');
});
});
@ -838,10 +929,83 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('label1');
});
});
});
describe('allow html', () => {
describe('is undefined', () => {
it('logs a deprecation warning', () => {
cy.get('@consoleWarn').should(
'be.calledOnceWithExactly',
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
);
});
it('does not show as text when selected', () => {
cy.get('[data-test-hook=allowhtml-undefined]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
it('does not show html as text in dropdown', () => {
cy.get('[data-test-hook=allowhtml-undefined]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 2');
});
});
});
describe('set to true', () => {
it('does not show as text when selected', () => {
cy.get('[data-test-hook=allowhtml-true]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
it('does not show html as text in dropdown', () => {
cy.get('[data-test-hook=allowhtml-true]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 2');
});
});
});
describe('set to false', () => {
it('shows html as text when selected', () => {
cy.get('[data-test-hook=allowhtml-false]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('<b>Choice 1</b>');
});
});
it('shows html as text', () => {
cy.get('[data-test-hook=allowhtml-false]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('<b>Choice 2</b>');
});
});
});
});
});
});

View file

@ -1,48 +1,63 @@
describe('Choices - select one', () => {
beforeEach(() => {
cy.visit('/select-one.html');
cy.visit('/select-one', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
});
describe('scenarios', () => {
describe('basic', () => {
beforeEach(() => {
// open dropdown
describe('focusing on container', () => {
describe('pressing enter key', () => {
it('toggles the dropdown', () => {
cy.get('[data-test-hook=basic]')
.find('.choices')
.click();
});
.focus()
.type('{enter}');
describe('focusing on text input', () => {
it('displays a dropdown of choices', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 4)
.each(($choice, index) => {
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
});
});
.find('.choices')
.focus()
.type('{enter}');
describe('pressing escape', () => {
beforeEach(() => {
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.type('{esc}');
});
it('closes the dropdown', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('not.be.visible');
});
});
describe('pressing an alpha-numeric key', () => {
it('opens the dropdown and the input value', () => {
const inputValue = 'test';
cy.get('[data-test-hook=basic]')
.find('.choices')
.focus()
.type(inputValue);
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.should('have.value', inputValue);
});
});
});
describe('selecting choices', () => {
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]').find('.choices').click();
});
const selectedChoiceText = 'Choice 1';
it('allows selecting choices from dropdown', () => {
@ -55,7 +70,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--single .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item).to.contain(selectedChoiceText);
});
});
@ -71,13 +86,18 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($item => {
.should(($item) => {
expect($item).to.contain(selectedChoiceText);
});
});
});
describe('searching choices', () => {
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]').find('.choices').click();
});
describe('on input', () => {
describe('searching by label', () => {
it('displays choices filtered by inputted value', () => {
@ -89,7 +109,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 2');
});
});
@ -105,7 +125,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 3');
});
});
@ -120,7 +140,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal('No results found');
});
@ -186,7 +206,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__list--single .choices__item')
.last()
.then($choice => {
.then(($choice) => {
removedChoiceText = $choice.text().trim();
})
.click();
@ -208,8 +228,8 @@ describe('Choices - select one', () => {
it('updates the value of the original input', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__input.is-hidden')
.should($select => {
.find('.choices__input[hidden]')
.should(($select) => {
const val = $select.val() || [];
expect(val).to.not.contain(removedChoiceText);
@ -228,7 +248,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=disabled-choice]')
.find('.choices__list--dropdown .choices__item--disabled')
.then($choice => {
.then(($choice) => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -238,7 +258,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--single .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text()).to.not.contain(selectedChoiceText);
});
});
@ -285,9 +305,7 @@ describe('Choices - select one', () => {
describe('on click', () => {
it('does not open choice dropdown', () => {
cy.get('[data-test-hook=disabled-via-attr]')
.find('.choices')
.click();
cy.get('[data-test-hook=disabled-via-attr]').find('.choices').click();
cy.get('[data-test-hook=disabled-via-attr]')
.find('.choices__list--dropdown')
@ -315,7 +333,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then($choice => {
.then(($choice) => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -325,7 +343,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--single .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(
`before-${selectedChoiceText}-after`,
);
@ -336,7 +354,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--single .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text()).to.not.contain(
`before-${selectedChoiceText}-after`,
);
@ -369,9 +387,7 @@ describe('Choices - select one', () => {
const selectedChoiceText = 'Choice 3';
beforeEach(() => {
cy.get('[data-test-hook=search-disabled]')
.find('.choices')
.click();
cy.get('[data-test-hook=search-disabled]').find('.choices').click();
});
it('does not display a search input', () => {
@ -390,7 +406,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=search-disabled]')
.find('.choices__list--single .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item).to.contain(selectedChoiceText);
});
});
@ -422,7 +438,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.not.contain(searchTerm);
});
});
@ -440,7 +456,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.contain(searchTerm);
});
});
@ -448,6 +464,102 @@ describe('Choices - select one', () => {
});
});
describe('placeholder via empty option value', () => {
describe('when no choice has been selected', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--single')
.children()
.first()
.should('have.class', 'choices__placeholder')
.and(($placeholder) => {
expect($placeholder).to.contain('I am a placeholder');
});
});
});
describe('when a choice has been selected', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.click();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.should('not.have.value', 'I am a placeholder');
});
});
describe('when choice list is open', () => {
it('displays the placeholder choice first', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should('have.class', 'choices__placeholder')
.should('have.text', 'I am a placeholder');
});
});
});
describe('placeholder via option attribute', () => {
describe('when no choice has been selected', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--single')
.children()
.first()
.should('have.class', 'choices__placeholder')
.and(($placeholder) => {
expect($placeholder).to.contain('I am a placeholder');
});
});
});
describe('when a choice has been selected', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.click();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.should('not.have.value', 'I am a placeholder');
});
});
describe('when choice list is open', () => {
it('displays the placeholder choice first', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should('have.class', 'choices__placeholder')
.should('have.text', 'I am a placeholder');
});
});
});
describe('remote data', () => {
beforeEach(() => {
cy.reload(true);
@ -458,9 +570,10 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remote-data]')
.find('.choices__list--single')
.children()
.should('have.length', 1)
.first()
.should('have.class', 'choices__placeholder')
.and($placeholder => {
.and(($placeholder) => {
expect($placeholder).to.contain('Loading...');
});
});
@ -483,10 +596,14 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remote-data]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 50)
.should('have.length', 51) // 50 choices + 1 placeholder choice
.each(($choice, index) => {
expect($choice.text().trim()).to.equal(`Label ${index + 1}`);
expect($choice.data('value')).to.equal(`Value ${index + 1}`);
if (index === 0) {
expect($choice.text().trim()).to.equal('I am a placeholder');
} else {
expect($choice.text().trim()).to.equal(`Label ${index}`);
expect($choice.data('value')).to.equal(`Value ${index}`);
}
});
});
});
@ -499,19 +616,17 @@ describe('Choices - select one', () => {
beforeEach(() => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .choices__item')
.then($choices => {
.then(($choices) => {
choicesCount = $choices.length;
});
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices')
.click();
cy.get('[data-test-hook=scrolling-dropdown]').find('.choices').click();
});
it('highlights first choice on dropdown open', () => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
@ -520,7 +635,7 @@ describe('Choices - select one', () => {
for (let index = 0; index < choicesCount; index++) {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
});
@ -544,7 +659,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(`Choice ${index}`);
});
@ -563,7 +678,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.then($group => {
.then(($group) => {
groupValue = $group.text().trim();
});
});
@ -584,7 +699,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.should($group => {
.should(($group) => {
expect($group.text().trim()).to.not.equal(groupValue);
});
});
@ -615,7 +730,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=groups]')
.find('.choices__list--dropdown .choices__list .choices__group')
.first()
.should($group => {
.should(($group) => {
expect($group.text().trim()).to.equal(groupValue);
});
});
@ -685,9 +800,7 @@ describe('Choices - select one', () => {
describe('custom properties', () => {
beforeEach(() => {
cy.get('[data-test-hook=custom-properties]')
.find('.choices')
.click();
cy.get('[data-test-hook=custom-properties]').find('.choices').click();
});
describe('on input', () => {
@ -716,7 +829,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(city);
});
@ -728,13 +841,75 @@ describe('Choices - select one', () => {
});
});
describe('non-string values', () => {
describe('custom properties via HTML', () => {
beforeEach(() => {
cy.get('[data-test-hook=non-string-values]')
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices')
.click();
});
describe('on input', () => {
it('filters choices based on a string custom property', () => {
const data = [
{
searchText: 'fantastic',
label: 'Label Three',
},
];
data.forEach(({ searchText, label }) => {
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type(searchText);
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal(label);
});
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type('{selectall}{del}');
});
});
it('filters choices based on a JSON custom property', () => {
const data = [
{
searchText: 'foo',
label: 'Label Four',
},
];
data.forEach(({ searchText, label }) => {
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type(searchText);
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal(label);
});
cy.get('[data-test-hook=custom-properties-html]')
.find('.choices__input--cloned')
.type('{selectall}{del}');
});
});
});
});
describe('non-string values', () => {
beforeEach(() => {
cy.get('[data-test-hook=non-string-values]').find('.choices').click();
});
it('displays expected amount of choices in dropdown', () => {
cy.get('[data-test-hook=non-string-values]')
.find('.choices__list--dropdown .choices__list')
@ -748,7 +923,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then($choice => {
.then(($choice) => {
$selectedChoice = $choice;
})
.click();
@ -756,7 +931,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=non-string-values]')
.find('.choices__list--single .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item.text().trim()).to.equal($selectedChoice.text().trim());
});
});
@ -766,7 +941,7 @@ describe('Choices - select one', () => {
describe('selecting choice', () => {
describe('on enter key', () => {
it('does not submit form', () => {
cy.get('[data-test-hook=within-form] form').then($form => {
cy.get('[data-test-hook=within-form] form').then(($form) => {
$form.submit(() => {
// this will fail the test if the form submits
throw new Error('Form submitted');
@ -779,14 +954,12 @@ describe('Choices - select one', () => {
.find('.choices__input--cloned')
.type('{enter}');
cy.get('[data-test-hook=within-form]')
.find('.choices')
.click();
cy.get('[data-test-hook=within-form]').find('.choices').click();
cy.get('[data-test-hook=within-form]')
.find('.choices__list--single .choices__item')
.last()
.should($item => {
.should(($item) => {
expect($item).to.contain('Choice 1');
});
});
@ -801,7 +974,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__list--single .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(
dynamicallySelectedChoiceValue,
);
@ -811,15 +984,15 @@ describe('Choices - select one', () => {
it('does not remove choice from dropdown list', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__list--dropdown .choices__list')
.then($choicesList => {
.then(($choicesList) => {
expect($choicesList).to.contain(dynamicallySelectedChoiceValue);
});
});
it('updates the value of the original input', () => {
cy.get('[data-test-hook=set-choice-by-value]')
.find('.choices__input.is-hidden')
.should($select => {
.find('.choices__input[hidden]')
.should(($select) => {
const val = $select.val() || [];
expect(val).to.contain(dynamicallySelectedChoiceValue);
});
@ -828,9 +1001,7 @@ describe('Choices - select one', () => {
describe('searching by label only', () => {
beforeEach(() => {
cy.get('[data-test-hook=search-by-label]')
.find('.choices')
.click();
cy.get('[data-test-hook=search-by-label]').find('.choices').click();
});
it('gets zero results when searching by value', () => {
@ -842,7 +1013,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('No results found');
});
});
@ -856,10 +1027,123 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('label1');
});
});
});
describe('disabling first choice via options', () => {
beforeEach(() => {
cy.get('[data-test-hook=disabled-first-choice-via-options]')
.find('.choices')
.click();
});
let disabledValue;
it('disables the first choice', () => {
cy.get('[data-test-hook=disabled-first-choice-via-options]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should('have.class', 'choices__item--disabled')
.then(($choice) => {
disabledValue = $choice.val();
});
});
it('selects the first enabled choice', () => {
cy.get('[data-test-hook=disabled-first-choice-via-options]')
.find('.choices__input[hidden]')
.then(($option) => {
expect($option.text().trim()).to.not.equal(disabledValue);
});
cy.get('[data-test-hook=disabled-first-choice-via-options]')
.find('.choices__item.choices__item--selectable')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.not.equal(disabledValue);
});
});
});
describe('allow html', () => {
describe('is undefined', () => {
it('logs a deprecation warning', () => {
cy.get('@consoleWarn').should(
'be.calledOnceWithExactly',
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
);
});
it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-undefined]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
});
describe('set to true', () => {
it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-true]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Choice 1');
});
});
});
describe('set to false', () => {
it('shows html as text', () => {
cy.get('[data-test-hook=allowhtml-false]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('<b>Choice 1</b>');
});
});
});
});
describe('re-initialising a choices instance', () => {
it('preserves the choices list', () => {
cy.get('[data-test-hook=new-destroy-init]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 3);
cy.get('[data-test-hook=new-destroy-init]')
.find('button.destroy')
.click();
cy.get('[data-test-hook=new-destroy-init]').find('button.init').click();
cy.get('[data-test-hook=new-destroy-init]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 3);
});
});
describe('destroying the choices instance', () => {
it('preserves the original select element', () => {
cy.get('[data-test-hook=new-destroy-init]')
.find('button.destroy')
.click();
cy.get('[data-test-hook=new-destroy-init]')
.find('select')
.children()
.should('have.length', 3);
});
});
});
});

View file

@ -1,6 +1,10 @@
describe('Choices - text element', () => {
beforeEach(() => {
cy.visit('/text.html');
cy.visit('/text', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
});
describe('scenarios', () => {
@ -17,7 +21,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--multiple .choices__item')
.last()
.should($el => {
.should(($el) => {
expect($el).to.contain(textInput);
});
});
@ -29,7 +33,7 @@ describe('Choices - text element', () => {
.type('{enter}');
cy.get('[data-test-hook=basic]')
.find('.choices__input.is-hidden')
.find('.choices__input[hidden]')
.should('have.value', textInput);
});
@ -42,7 +46,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Press Enter to add "${textInput}"`,
@ -74,7 +78,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=edit-items]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(`${textInput}-edited`);
});
});
@ -90,7 +94,7 @@ describe('Choices - text element', () => {
it('highlights all items', () => {
cy.get('[data-test-hook=edit-items]')
.find('.choices__list--multiple .choices__item')
.each($choice => {
.each(($choice) => {
expect($choice.hasClass('is-highlighted')).to.equal(true);
});
});
@ -124,7 +128,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__list--multiple')
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(1);
});
@ -137,7 +141,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__list--multiple .choices__item')
.should($items => {
.should(($items) => {
expect($items.length).to.equal(0);
});
});
@ -151,8 +155,8 @@ describe('Choices - text element', () => {
.click();
cy.get('[data-test-hook=remove-button]')
.find('.choices__input.is-hidden')
.then($input => {
.find('.choices__input[hidden]')
.then(($input) => {
expect($input.val()).to.not.contain(textInput);
});
});
@ -175,7 +179,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(1);
});
});
@ -185,7 +189,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=unique-values]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
'Only unique values can be added',
@ -212,7 +216,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should($items => {
.should(($items) => {
expect($items.length).to.equal(inputLimit);
});
});
@ -222,7 +226,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=input-limit]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
`Only ${inputLimit} values can be added`,
@ -245,7 +249,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal(input);
});
});
@ -261,7 +265,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=add-item-filter]')
.find('.choices__list--dropdown')
.should('be.visible')
.should($dropdown => {
.should(($dropdown) => {
const dropdownText = $dropdown.text().trim();
expect(dropdownText).to.equal(
'Only values matching specific conditions can be added',
@ -283,7 +287,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.data('value')).to.equal(`before-${textInput}-after`);
});
});
@ -292,7 +296,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=prepend-append]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text()).to.not.contain(`before-${textInput}-after`);
expect($choice.text()).to.contain(textInput);
});
@ -319,21 +323,21 @@ describe('Choices - text element', () => {
it('pre-populates choices', () => {
cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.should($choices => {
.should(($choices) => {
expect($choices.length).to.equal(2);
});
cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.first()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Josh Johnson');
});
cy.get('[data-test-hook=prepopulated]')
.find('.choices__list--multiple .choices__item')
.last()
.should($choice => {
.should(($choice) => {
expect($choice.text().trim()).to.equal('Joe Bloggs');
});
});
@ -355,11 +359,53 @@ describe('Choices - text element', () => {
});
});
describe('allow html', () => {
describe('is undefined', () => {
it('logs a deprecation warning', () => {
cy.get('@consoleWarn').should(
'be.calledOnceWithExactly',
'Deprecation warning: allowHTML will default to false in a future release. To render HTML in Choices, you will need to set it to true. Setting allowHTML will suppress this message.',
);
});
it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-undefined]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Mason Rogers');
});
});
});
describe('set to true', () => {
it('does not show html as text', () => {
cy.get('[data-test-hook=allowhtml-true]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('Mason Rogers');
});
});
});
describe('set to false', () => {
it('shows html as text', () => {
cy.get('[data-test-hook=allowhtml-false]')
.find('.choices__list--multiple .choices__item')
.first()
.should(($choice) => {
expect($choice.text().trim()).to.equal('<b>Mason Rogers</b>');
});
});
});
});
describe('within form', () => {
describe('inputting item', () => {
describe('on enter key', () => {
it('does not submit form', () => {
cy.get('[data-test-hook=within-form] form').then($form => {
cy.get('[data-test-hook=within-form] form').then(($form) => {
$form.submit(() => {
// this will fail the test if the form submits
throw new Error('Form submitted');
@ -374,7 +420,7 @@ describe('Choices - text element', () => {
cy.get('[data-test-hook=within-form]')
.find('.choices__list--multiple .choices__item')
.last()
.should($el => {
.should(($el) => {
expect($el).to.contain(textInput);
});
});

View file

@ -14,4 +14,4 @@
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}
};

View file

@ -14,7 +14,7 @@
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')

View file

@ -1,9 +1,17 @@
{
"compilerOptions": {
"strict": true,
"baseUrl": "../node_modules",
"checkJs": true,
"target": "es2020",
"lib": ["es5", "dom"],
"types": ["cypress"]
"lib": ["esnext", "dom"],
"types": ["cypress"],
"strict": true,
"moduleResolution": "node",
/* Additional Checks */
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"strictNullChecks": false
}
}

14
lint-staged.config.js Normal file
View file

@ -0,0 +1,14 @@
module.exports = {
'*.js': ['eslint --fix --quiet -f visualstudio', 'git add'],
'*.{ts,scss,yaml,yml,md,html,json,babelrc,eslintrc}': [
'prettier --write',
'git add',
],
'src/icons/*.svg': [
'prettier --write --parser=html --html-whitespace-sensitivity=ignore',
'git add',
],
'.codecov.yml': () =>
'curl -f --silent --data-binary @.codecov.yml https://codecov.io/validate',
'src/scripts/**/*.js': () => 'npm run test:unit',
};

30245
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,32 +1,32 @@
{
"name": "choices.js",
"version": "7.1.4",
"version": "10.2.0",
"description": "A vanilla JS customisable text input/select box plugin",
"main": "./public/assets/scripts/choices.min.js",
"types": "./types/index.d.ts",
"main": "./public/assets/scripts/choices.js",
"types": "./public/types/src/index.d.ts",
"scripts": {
"start": "run-p js:watch css:watch",
"build": "run-p js:build css:build",
"lint": "eslint src/scripts",
"coverage": "nyc --reporter=lcov --reporter=text --reporter=text-summary mocha",
"lint": "run-p lint:js lint:scss",
"lint:js": "eslint src/scripts/**/*.ts",
"lint:scss": "stylelint src/**/*.scss",
"bundlesize": "bundlesize",
"cypress:run": "$(npm bin)/cypress run",
"cypress:open": "$(npm bin)/cypress open",
"cypress:ci": "cypress run --record --group --ci-build-id $GITHUB_SHA",
"cypress:run": "cypress run --browser chrome",
"cypress:open": "cypress open",
"cypress:ci": "cypress run --browser chrome --record --group $GITHUB_REF --ci-build-id $GITHUB_SHA",
"test": "run-s test:unit test:e2e",
"test:unit": "mocha",
"test:unit:watch": "mocha --watch --inspect=5556",
"test:unit": "cross-env 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": "NODE_ENV=development node server.js",
"js:watch": "cross-env NODE_ENV=development node server.js",
"js:build": "webpack --config webpack.config.prod.js",
"css:watch": "nodemon -e scss -x \"npm run css:build\"",
"css:build": "run-s css:sass css:prefix css:min",
"css:sass": "node-sass --output-style expanded --include-path scss src/styles/base.scss public/assets/styles/base.css && node-sass --output-style expanded --include-path scss src/styles/choices.scss public/assets/styles/choices.css",
"css:sass": "sass -I scss src/styles/base.scss public/assets/styles/base.css && sass -I scss src/styles/choices.scss public/assets/styles/choices.css",
"css:prefix": "postcss public/assets/styles/*.css --use autoprefixer --no-map --env prod --dir public/assets/styles",
"css:min": "csso public/assets/styles/base.css --output public/assets/styles/base.min.css && csso public/assets/styles/choices.css --output public/assets/styles/choices.min.css",
"deploy": "git subtree push --prefix public origin gh-pages",
"prepush": "run-s lint test:unit bundlesize",
"postversion": "git push --no-verify --atomic --follow-tags",
"prepublishOnly": "npm run build"
},
"repository": {
@ -38,6 +38,7 @@
"files": [
"public/assets/scripts",
"public/assets/styles",
"public/types",
"src",
"!src/**/*.test.js",
"types"
@ -55,43 +56,61 @@
"js"
],
"devDependencies": {
"@babel/core": "^7.6.4",
"@babel/preset-env": "^7.6.3",
"@babel/register": "^7.6.2",
"autoprefixer": "^9.6.5",
"babel-loader": "^8.0.6",
"bundlesize": "^0.18.0",
"chai": "^4.2.0",
"csso-cli": "^3.0.0",
"cypress": "3.2.0",
"eslint": "^6.5.1",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-config-prettier": "^6.4.0",
"eslint-loader": "^3.0.2",
"eslint-plugin-cypress": "^2.7.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.1",
"express": "^4.16.4",
"husky": "^3.0.9",
"jsdom": "^15.2.0",
"mocha": "^6.2.2",
"node-sass": "^4.12.0",
"nodemon": "^1.18.10",
"@babel/core": "^7.20.5",
"@babel/preset-env": "^7.20.2",
"@babel/register": "^7.18.9",
"@types/chai": "^4.3.4",
"@types/mocha": "^10.0.1",
"@types/sinon": "^10.0.13",
"@types/sinon-chai": "^3.2.9",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.13",
"babel-loader": "^9.1.0",
"bundlesize": "^0.18.1",
"chai": "^4.3.7",
"cross-env": "^7.0.3",
"csso-cli": "^4.0.1",
"cypress": "11.2.0",
"eslint": "^8.28.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-compat": "4.0.2",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-sort-class-members": "^1.15.2",
"eslint-webpack-plugin": "^3.2.0",
"express": "^4.18.2",
"husky": "^8.0.2",
"jsdom": "^20.0.3",
"lint-staged": "^13.0.4",
"mocha": "^10.1.0",
"nodemon": "^2.0.20",
"npm-run-all": "^4.1.5",
"nyc": "^14.1.1",
"postcss-cli": "^6.1.3",
"prettier": "^1.16.4",
"sinon": "^7.5.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9",
"webpack-dev-middleware": "^3.7.2",
"webpack-hot-middleware": "^2.25.0"
"nyc": "^15.1.0",
"postcss": "^8.4.19",
"postcss-cli": "^10.0.0",
"prettier": "^2.8.0",
"sass": "^1.56.1",
"sinon": "^15.0.0",
"sinon-chai": "^3.7.0",
"stylelint": "^14.15.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-config-standard-scss": "^6.1.0",
"ts-loader": "^9.4.1",
"ts-node": "^10.9.1",
"typescript": "^4.9.3",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-dev-middleware": "^6.0.1",
"webpack-hot-middleware": "^2.25.3"
},
"dependencies": {
"classnames": "^2.2.6",
"deepmerge": "^4.2.0",
"fuse.js": "3.4.2",
"redux": "^4.0.4"
"deepmerge": "^4.2.2",
"fuse.js": "^6.6.2",
"redux": "^4.2.0"
},
"npmName": "choices.js",
"npmFileMap": [
@ -99,6 +118,7 @@
"files": [
"public/assets/scripts/*",
"public/assets/styles/*",
"public/types/*",
"src/icons/*"
]
}
@ -114,11 +134,11 @@
"bundlesize": [
{
"path": "public/assets/scripts/choices.min.js",
"maxSize": "20 kB"
"maxSize": "25 kB"
},
{
"path": "public/assets/styles/choices.min.css",
"maxSize": "1.8 kB"
"maxSize": "2.5 kB"
}
]
}

View file

@ -0,0 +1,27 @@
// get polyfill settings from top level config
// @ts-ignore
const { settings } = require('../../../.eslintrc.json');
// Adding non-polyfilable Symbol-related functions as they are most probably
// behind the flag
settings.polyfills.push(
'Symbol.toStringTag',
'Symbol.for',
'Object.getOwnPropertySymbols',
'Object.getOwnPropertyDescriptors',
'Promise', // Promise is gate checked
);
module.exports = /** @type {import('eslint').Linter.Config} */ ({
root: true,
extends: ['plugin:compat/recommended'],
parserOptions: {
// ensure that it's compatible with ES5 browsers, so, no `const`, etc
ecmaVersion: 5,
},
env: {
browser: true,
},
settings,
});

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
/*! choices.js v10.2.0 | © 2022 Josh Johnson | https://github.com/jshjohnson/Choices#readme */

View file

@ -7,8 +7,8 @@
}
*,
*:before,
*:after {
*::before,
*::after {
box-sizing: border-box;
}
@ -24,7 +24,7 @@ body {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 16px;
line-height: 1.4;
color: #FFFFFF;
color: #fff;
background-color: #333;
overflow-x: hidden;
}
@ -39,6 +39,7 @@ label {
p {
margin-top: 0;
margin-bottom: 8px;
}
hr {
@ -64,7 +65,7 @@ h6 {
a,
a:visited,
a:focus {
color: #FFFFFF;
color: #fff;
text-decoration: none;
font-weight: 600;
}
@ -112,10 +113,6 @@ h6,
font-size: 14px;
}
p {
margin-bottom: 8px;
}
label + p {
margin-top: -4px;
}
@ -126,7 +123,6 @@ label + p {
max-width: 40em;
padding: 48px;
}
@media (max-width: 620px) {
.container {
padding: 0;
@ -134,11 +130,10 @@ label + p {
}
.section {
background-color: #FFFFFF;
background-color: #fff;
padding: 24px;
color: #333;
}
.section a,
.section a:visited,
.section a:focus {
@ -150,7 +145,7 @@ label + p {
margin-bottom: 12px;
}
.logo__img {
.logo-img {
width: 100%;
height: auto;
display: inline-block;
@ -179,10 +174,6 @@ label + p {
text-align: center;
}
.is-hidden {
display: none;
}
[data-test-hook] {
margin-bottom: 24px;
}

View file

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../../src/styles/base.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAYA;EACE;EACA;;;AAGF;AAAA;AAAA;EAGE;;;AAGF;AAAA;EAEE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;AAAA;AAAA;AAAA;AAAA;AAAA;EAME;EACA;EACA;EACA;;;AAGF;AAAA;AAAA;EAGE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,eAtFiB;;;AAyFnB;AAAA;EAEE,WA1FoB;;;AA6FtB;AAAA;EAEE,WA9FoB;;;AAiGtB;AAAA;EAEE,WAlGoB;;;AAqGtB;AAAA;EAEE,WAtGoB;;;AAyGtB;AAAA;EAEE,WA1GoB;;;AA6GtB;AAAA;EAEE,WA9GoB;;;AAiHtB;EACE;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EANF;IAOI;;;;AAIJ;EACE;EACA,SAxIiB;EAyIjB;;AAEA;AAAA;AAAA;EAGE;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE,eArKiB;;;AAwKnB;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE,eArLiB;;;AAwLnB","file":"base.css"}

View file

@ -1 +1 @@
*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,:after,:before{box-sizing:border-box}body,html{position:relative;margin:0;width:100%;height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:16px;line-height:1.4;color:#fff;background-color:#333;overflow-x:hidden}hr,label{display:block}label,p{margin-bottom:8px}label{font-size:14px;font-weight:500;cursor:pointer}p{margin-top:0}hr{margin:30px 0;border:0;border-bottom:1px solid #eaeaea;height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:12px;font-weight:400;line-height:1.2}a,a:focus,a:visited{color:#fff;text-decoration:none;font-weight:600}.form-control{display:block;width:100%;background-color:#f9f9f9;padding:12px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;-webkit-appearance:none;appearance:none;margin-bottom:24px}.h1,h1{font-size:32px}.h2,h2{font-size:24px}.h3,h3{font-size:20px}.h4,h4{font-size:18px}.h5,h5{font-size:16px}.h6,h6{font-size:14px}label+p{margin-top:-4px}.container{display:block;margin:auto;max-width:40em;padding:48px}@media (max-width:620px){.container{padding:0}}.section{background-color:#fff;padding:24px;color:#333}.section a,.section a:focus,.section a:visited{color:#00bcd4}.logo{display:block;margin-bottom:12px}.logo__img{width:100%;height:auto;display:inline-block;max-width:100%;vertical-align:top;padding:6px 0}.visible-ie{display:none}.push-bottom{margin-bottom:24px}.zero-bottom{margin-bottom:0}.zero-top{margin-top:0}.text-center{text-align:center}.is-hidden{display:none}[data-test-hook]{margin-bottom:24px}
*{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}*,::after,::before{box-sizing:border-box}body,html{position:relative;margin:0;width:100%;height:100%}body{font-family:"Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;font-size:16px;line-height:1.4;color:#fff;background-color:#333;overflow-x:hidden}hr,label{display:block}label,p{margin-bottom:8px}label{font-size:14px;font-weight:500;cursor:pointer}p{margin-top:0}hr{margin:30px 0;border:0;border-bottom:1px solid #eaeaea;height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:12px;font-weight:400;line-height:1.2}a,a:focus,a:visited{color:#fff;text-decoration:none;font-weight:600}.form-control{display:block;width:100%;background-color:#f9f9f9;padding:12px;border:1px solid #ddd;border-radius:2.5px;font-size:14px;-webkit-appearance:none;appearance:none;margin-bottom:24px}.h1,h1{font-size:32px}.h2,h2{font-size:24px}.h3,h3{font-size:20px}.h4,h4{font-size:18px}.h5,h5{font-size:16px}.h6,h6{font-size:14px}label+p{margin-top:-4px}.container{display:block;margin:auto;max-width:40em;padding:48px}@media (max-width:620px){.container{padding:0}}.section{background-color:#fff;padding:24px;color:#333}.section a,.section a:focus,.section a:visited{color:#00bcd4}.logo{display:block;margin-bottom:12px}.logo-img{width:100%;height:auto;display:inline-block;max-width:100%;vertical-align:top;padding:6px 0}.visible-ie{display:none}.push-bottom{margin-bottom:24px}.zero-bottom{margin-bottom:0}.zero-top{margin-top:0}.text-center{text-align:center}[data-test-hook]{margin-bottom:24px}

View file

@ -3,50 +3,49 @@
=============================== */
.choices {
position: relative;
overflow: hidden;
margin-bottom: 24px;
font-size: 16px;
}
.choices:focus {
outline: none;
}
.choices:last-child {
margin-bottom: 0;
}
.choices.is-open {
overflow: visible;
}
.choices.is-disabled .choices__inner,
.choices.is-disabled .choices__input {
background-color: #EAEAEA;
background-color: #eaeaea;
cursor: not-allowed;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.choices.is-disabled .choices__item {
cursor: not-allowed;
}
.choices [hidden] {
display: none !important;
}
.choices[data-type*="select-one"] {
.choices[data-type*=select-one] {
cursor: pointer;
}
.choices[data-type*="select-one"] .choices__inner {
.choices[data-type*=select-one] .choices__inner {
padding-bottom: 7.5px;
}
.choices[data-type*="select-one"] .choices__input {
.choices[data-type*=select-one] .choices__input {
display: block;
width: 100%;
padding: 10px;
border-bottom: 1px solid #DDDDDD;
background-color: #FFFFFF;
border-bottom: 1px solid #ddd;
background-color: #fff;
margin: 0;
}
.choices[data-type*="select-one"] .choices__button {
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);
.choices[data-type*=select-one] .choices__button {
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==");
padding: 0;
background-size: 8px;
position: absolute;
@ -57,23 +56,23 @@
height: 20px;
width: 20px;
border-radius: 10em;
opacity: .5;
opacity: 0.25;
}
.choices[data-type*="select-one"] .choices__button:hover, .choices[data-type*="select-one"] .choices__button:focus {
.choices[data-type*=select-one] .choices__button:hover, .choices[data-type*=select-one] .choices__button:focus {
opacity: 1;
}
.choices[data-type*="select-one"] .choices__button:focus {
box-shadow: 0px 0px 0px 2px #00BCD4;
.choices[data-type*=select-one] .choices__button:focus {
box-shadow: 0 0 0 2px #00bcd4;
}
.choices[data-type*="select-one"]:after {
.choices[data-type*=select-one] .choices__item[data-value=""] .choices__button {
display: none;
}
.choices[data-type*=select-one]::after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: #333333 transparent transparent transparent;
border-color: #333 transparent transparent transparent;
border-width: 5px;
position: absolute;
right: 11.5px;
@ -81,31 +80,27 @@
margin-top: -2.5px;
pointer-events: none;
}
.choices[data-type*="select-one"].is-open:after {
border-color: transparent transparent #333333 transparent;
.choices[data-type*=select-one].is-open::after {
border-color: transparent transparent #333 transparent;
margin-top: -7.5px;
}
.choices[data-type*="select-one"][dir="rtl"]:after {
.choices[data-type*=select-one][dir=rtl]::after {
left: 11.5px;
right: auto;
}
.choices[data-type*="select-one"][dir="rtl"] .choices__button {
.choices[data-type*=select-one][dir=rtl] .choices__button {
right: auto;
left: 0;
margin-left: 25px;
margin-right: 0;
}
.choices[data-type*="select-multiple"] .choices__inner,
.choices[data-type*="text"] .choices__inner {
.choices[data-type*=select-multiple] .choices__inner,
.choices[data-type*=text] .choices__inner {
cursor: text;
}
.choices[data-type*="select-multiple"] .choices__button,
.choices[data-type*="text"] .choices__button {
.choices[data-type*=select-multiple] .choices__button,
.choices[data-type*=text] .choices__button {
position: relative;
display: inline-block;
margin-top: 0;
@ -114,17 +109,16 @@
margin-left: 8px;
padding-left: 16px;
border-left: 1px solid #008fa1;
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==");
background-size: 8px;
width: 8px;
line-height: 1;
opacity: .75;
opacity: 0.75;
border-radius: 0;
}
.choices[data-type*="select-multiple"] .choices__button:hover, .choices[data-type*="select-multiple"] .choices__button:focus,
.choices[data-type*="text"] .choices__button:hover,
.choices[data-type*="text"] .choices__button:focus {
.choices[data-type*=select-multiple] .choices__button:hover, .choices[data-type*=select-multiple] .choices__button:focus,
.choices[data-type*=text] .choices__button:hover,
.choices[data-type*=text] .choices__button:focus {
opacity: 1;
}
@ -134,22 +128,18 @@
width: 100%;
background-color: #f9f9f9;
padding: 7.5px 7.5px 3.75px;
border: 1px solid #DDDDDD;
border: 1px solid #ddd;
border-radius: 2.5px;
font-size: 14px;
min-height: 44px;
overflow: hidden;
}
.is-focused .choices__inner,
.is-open .choices__inner {
.is-focused .choices__inner, .is-open .choices__inner {
border-color: #b7b7b7;
}
.is-open .choices__inner {
border-radius: 2.5px 2.5px 0 0;
}
.is-flipped.is-open .choices__inner {
border-radius: 0 0 2.5px 2.5px;
}
@ -159,18 +149,15 @@
padding-left: 0;
list-style: none;
}
.choices__list--single {
display: inline-block;
padding: 4px 16px 4px 4px;
width: 100%;
}
[dir="rtl"] .choices__list--single {
[dir=rtl] .choices__list--single {
padding-right: 4px;
padding-left: 16px;
}
.choices__list--single .choices__item {
width: 100%;
}
@ -178,7 +165,6 @@
.choices__list--multiple {
display: inline;
}
.choices__list--multiple .choices__item {
display: inline-block;
vertical-align: middle;
@ -188,85 +174,76 @@
font-weight: 500;
margin-right: 3.75px;
margin-bottom: 3.75px;
background-color: #00BCD4;
background-color: #00bcd4;
border: 1px solid #00a5bb;
color: #FFFFFF;
color: #fff;
word-break: break-all;
box-sizing: border-box;
}
.choices__list--multiple .choices__item[data-deletable] {
padding-right: 5px;
}
[dir="rtl"] .choices__list--multiple .choices__item {
[dir=rtl] .choices__list--multiple .choices__item {
margin-right: 0;
margin-left: 3.75px;
}
.choices__list--multiple .choices__item.is-highlighted {
background-color: #00a5bb;
border: 1px solid #008fa1;
}
.is-disabled .choices__list--multiple .choices__item {
background-color: #aaaaaa;
border: 1px solid #919191;
}
.choices__list--dropdown {
display: none;
.choices__list--dropdown, .choices__list[aria-expanded] {
visibility: hidden;
z-index: 1;
position: absolute;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #DDDDDD;
background-color: #fff;
border: 1px solid #ddd;
top: 100%;
margin-top: -1px;
border-bottom-left-radius: 2.5px;
border-bottom-right-radius: 2.5px;
overflow: hidden;
word-break: break-all;
will-change: visibility;
}
.choices__list--dropdown.is-active {
display: block;
.is-active.choices__list--dropdown, .is-active.choices__list[aria-expanded] {
visibility: visible;
}
.is-open .choices__list--dropdown {
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
border-color: #b7b7b7;
}
.is-flipped .choices__list--dropdown {
.is-flipped .choices__list--dropdown, .is-flipped .choices__list[aria-expanded] {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: -1px;
border-radius: .25rem .25rem 0 0;
border-radius: 0.25rem 0.25rem 0 0;
}
.choices__list--dropdown .choices__list {
.choices__list--dropdown .choices__list, .choices__list[aria-expanded] .choices__list {
position: relative;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
will-change: scroll-position;
}
.choices__list--dropdown .choices__item {
.choices__list--dropdown .choices__item, .choices__list[aria-expanded] .choices__item {
position: relative;
padding: 10px;
font-size: 14px;
}
[dir="rtl"] .choices__list--dropdown .choices__item {
[dir=rtl] .choices__list--dropdown .choices__item, [dir=rtl] .choices__list[aria-expanded] .choices__item {
text-align: right;
}
@media (min-width: 640px) {
.choices__list--dropdown .choices__item--selectable {
.choices__list--dropdown .choices__item--selectable, .choices__list[aria-expanded] .choices__item--selectable {
padding-right: 100px;
}
.choices__list--dropdown .choices__item--selectable:after {
.choices__list--dropdown .choices__item--selectable::after, .choices__list[aria-expanded] .choices__item--selectable::after {
content: attr(data-select-text);
font-size: 12px;
opacity: 0;
@ -275,23 +252,21 @@
top: 50%;
transform: translateY(-50%);
}
[dir="rtl"] .choices__list--dropdown .choices__item--selectable {
[dir=rtl] .choices__list--dropdown .choices__item--selectable, [dir=rtl] .choices__list[aria-expanded] .choices__item--selectable {
text-align: right;
padding-left: 100px;
padding-right: 10px;
}
[dir="rtl"] .choices__list--dropdown .choices__item--selectable:after {
[dir=rtl] .choices__list--dropdown .choices__item--selectable::after, [dir=rtl] .choices__list[aria-expanded] .choices__item--selectable::after {
right: auto;
left: 10px;
}
}
.choices__list--dropdown .choices__item--selectable.is-highlighted {
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
background-color: #f2f2f2;
}
.choices__list--dropdown .choices__item--selectable.is-highlighted:after {
opacity: .5;
.choices__list--dropdown .choices__item--selectable.is-highlighted::after, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after {
opacity: 0.5;
}
.choices__item {
@ -305,9 +280,8 @@
.choices__item--disabled {
cursor: not-allowed;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: .5;
opacity: 0.5;
}
.choices__heading {
@ -328,7 +302,6 @@
background-position: center;
cursor: pointer;
}
.choices__button:focus {
outline: none;
}
@ -344,24 +317,24 @@
max-width: 100%;
padding: 4px 0 4px 2px;
}
.choices__input:focus {
outline: 0;
}
[dir="rtl"] .choices__input {
.choices__input::-webkit-search-decoration, .choices__input::-webkit-search-cancel-button, .choices__input::-webkit-search-results-button, .choices__input::-webkit-search-results-decoration {
display: none;
}
.choices__input::-ms-clear, .choices__input::-ms-reveal {
display: none;
width: 0;
height: 0;
}
[dir=rtl] .choices__input {
padding-right: 2px;
padding-left: 0;
}
.choices__placeholder {
opacity: .5;
}
.choices__input.is-hidden,
.choices[data-type*="select-one"] .choices__input.is-hidden,
.choices[data-type*="select-multiple"] .choices__input.is-hidden {
display: none;
opacity: 0.5;
}
/* ===== End of Choices ====== */

View file

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../../src/styles/choices.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AA2BA;EACE;EACA;EACA,eApBkB;EAqBlB,WAxBqB;;AA0BrB;EACE;;AAGF;EACE;;AAGF;EACE;;AAIA;AAAA;EAEE,kBAlCsB;EAmCtB;EACA;;AAEF;EACE;;AAIJ;EACE;;;AAIJ;EACE;;AACA;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE,kBApDyB;EAqDzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE;;AAGF;EACE;;AAGJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAIA;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAOJ;AAAA;EACE;;AAEF;AAAA;EACE;EACA;EACA;EACA;EACA;EACA,aA5HoB;EA6HpB;EACA;EACA,kBA9HiB;EA+HjB,iBAjIuB;EAkIvB,OAlIuB;EAmIvB;EACA;EACA;;AAEA;AAAA;AAAA;EAEE;;;AAKN;EACE;EACA;EACA;EACA,kBA1JiB;EA2JjB;EACA;EACA,eA/JsB;EAgKtB,WAnKqB;EAoKrB;EACA;;AAEA;EAEE;;AAGF;EACE;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;;AAOF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAEF;EACE;;;AAIJ;EACE;;AACA;EACE;EACA;EACA,eA9MyB;EA+MzB;EACA,WAnNmB;EAoNnB;EACA;EACA;EACA,kBA9MoB;EA+MpB;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA,SApOgB;EAqOhB;EACA;EACA,kBAjP0B;EAkP1B;EACA;EACA;EACA,2BAzPsB;EA0PtB,4BA1PsB;EA2PtB;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA,WA3RmB;;AA6RnB;EACE;;AAIF;EADF;IAEI;;EAEA;IACE;IACA,WAtSe;IAuSf;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;;EAEA;IACE;IACA;;;AAKN;EACE;;AAEA;EACE;;;AAUR;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA,WAxVqB;EAyVrB;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA,kBA3WiB;EA4WjB,WAjXqB;EAkXrB;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EAIE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;;;AAGF","file":"choices.css"}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,340 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>Choices</title>
<meta name=description itemprop=description content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.">
<link rel="apple-touch-icon" sizes="180x180" href="../assets/images/apple-touch-icon.png">
<link rel="icon" type="image/png" href="../assets/images/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="../assets/images/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="../assets/images/manifest.json">
<link rel="mask-icon" href="../assets/images/safari-pinned-tab.svg" color="#00bcd4">
<link rel="shortcut icon" href="../assets/images/favicon.ico">
<meta name="msapplication-config" content="../assets/images/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3">
<!-- 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>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Select multiple inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<button class="disable push-bottom">Disable</button>
<button class="enable push-bottom">Enable</button>
<select class="form-control" name="choices-basic" id="choices-basic" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Find me">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<select class="form-control" name="choices-remove-button" id="choices-remove-button" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="disabled-choice">
<label for="choices-disabled-choice">Disabled choice</label>
<select class="form-control" name="choices-disabled-choice" id="choices-disabled-choice" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4" disabled>Choice 4</option>
</select>
</div>
<div data-test-hook="add-items-disabled">
<label for="choices-add-items-disabled">Add items disabled</label>
<select class="form-control" name="choices-add-items-disabled" id="choices-add-items-disabled" multiple>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<select class="form-control" name="choices-disabled-via-attr" id="choices-disabled-via-attr" multiple disabled>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="selection-limit">
<label for="choices-selection-limit">Input limit</label>
<select class="form-control" name="choices-selection-limit" id="choices-selection-limit" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
</select>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<select class="form-control" name="choices-prepend-append" id="choices-prepend-append" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="render-choice-limit">
<label for="choices-render-choice-limit">Render choice limit</label>
<select class="form-control" name="choices-render-choice-limit" id="choices-render-choice-limit" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-floor">
<label for="choices-search-floor">Search floor</label>
<select class="form-control" name="choices-search-floor" id="choices-search-floor" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder">
<label for="choices-placeholder">Placeholder</label>
<select class="form-control" name="choices-placeholder" id="choices-placeholder" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="remote-data">
<label for="choices-remote-data">Remote data</label>
<select class="form-control" name="choices-remote-data" id="choices-remote-data" multiple></select>
</div>
<div data-test-hook="scrolling-dropdown">
<label for="choices-scrolling-dropdown">Scrolling dropdown</label>
<select class="form-control" name="choices-scrolling-dropdown" id="choices-scrolling-dropdown" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
<option value="Choice 7">Choice 7</option>
<option value="Choice 8">Choice 8</option>
<option value="Choice 9">Choice 9</option>
<option value="Choice 10">Choice 10</option>
<option value="Choice 11">Choice 11</option>
<option value="Choice 12">Choice 12</option>
<option value="Choice 13">Choice 13</option>
<option value="Choice 14">Choice 14</option>
<option value="Choice 15">Choice 15</option>
</select>
</div>
<div data-test-hook="groups">
<label for="choices-groups">Choice groups</label>
<select class="form-control" name="choices-groups" id="choices-groups" multiple>
<optgroup label="UK">
<option value="London">London</option>
<option value="Manchester">Manchester</option>
<option value="Liverpool">Liverpool</option>
</optgroup>
<optgroup label="FR">
<option value="Paris">Paris</option>
<option value="Lyon">Lyon</option>
<option value="Marseille">Marseille</option>
</optgroup>
</select>
</div>
<div data-test-hook="custom-properties">
<label for="choices-custom-properties">Custom properties</label>
<select class="form-control" name="choices-custom-properties" id="choices-custom-properties" multiple></select>
</div>
<div data-test-hook="non-string-values">
<label for="choices-non-string-values">Non-string values</label>
<select class="form-control" name="choices-non-string-values" id="choices-non-string-values"></select>
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<select class="form-control" name="choices-within-form" id="choices-within-form" multiple>
<option value="Choice 1">Choice 1</option>
</select>
</form>
</div>
<div data-test-hook="set-choice-by-value">
<label for="choices-set-choice-by-value">Dynamically set choice by value</label>
<select class="form-control" name="choices-set-choice-by-value" id="choices-set-choice-by-value" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-by-label">
<label for="choices-search-by-label">Search by label</label>
<select class="form-control" name="choices-search-by-label" id="choices-search-by-label" multiple>
<option value="value1">label1</option>
<option value="value2">label2</option>
</select>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const choicesBasic = new Choices('#choices-basic');
document.querySelector('button.disable').addEventListener('click', () => {
choicesBasic.disable();
});
document.querySelector('button.enable').addEventListener('click', () => {
choicesBasic.enable();
});
new Choices('#choices-remove-button', {
removeItemButton: true,
});
new Choices('#choices-disabled-choice');
new Choices('#choices-add-items-disabled', {
addItems: false,
});
new Choices('#choices-disabled-via-attr');
new Choices('#choices-selection-limit', {
maxItemCount: 5,
});
new Choices('#choices-prepend-append', {
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-render-choice-limit', {
renderChoiceLimit: 1,
});
new Choices('#choices-search-floor', {
searchFloor: 5,
});
new Choices('#choices-placeholder', {
placeholder: true,
placeholderValue: 'I am a placeholder',
});
new Choices('#choices-remote-data', {
shouldSort: false,
}).ajax((callback) => {
fetch('/data')
.then((response) => {
response.json().then((data) => {
callback(data, 'value', 'label');
});
})
.catch((error) => {
console.error(error);
});
});
new Choices('#choices-scrolling-dropdown', {
shouldSort: false,
});
new Choices('#choices-groups');
new Choices('#choices-custom-properties', {
searchFields: ['label', 'value', 'customProperties.country'],
choices: [
{
id: 1,
value: 'London',
label: 'London',
customProperties: {
country: 'United Kingdom',
},
},
{
id: 2,
value: 'Berlin',
label: 'Berlin',
customProperties: {
country: 'Germany',
},
},
{
id: 3,
value: 'Lisbon',
label: 'Lisbon',
customProperties: {
country: 'Portugal',
},
},
],
});
new Choices('#choices-non-string-values', {
choices: [
{
id: 1,
label: 'Number',
value: 1,
},
{
id: 2,
label: 'Boolean',
value: true,
},
{
id: 3,
label: 'Object',
value: {
test: true,
},
},
{
id: 4,
label: 'Array',
value: ['test'],
},
],
});
new Choices('#choices-within-form');
new Choices('#choices-set-choice-by-value').setChoiceByValue('Choice 2');
new Choices('#choices-search-by-label', { searchFields: ['label'] });
});
</script>
</body>
</html>

View file

@ -0,0 +1,628 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,user-scalable=no"
/>
<title>Choices</title>
<meta
name="description"
itemprop="description"
content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency."
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../assets/images/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-32x32.png"
sizes="32x32"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-16x16.png"
sizes="16x16"
/>
<link rel="manifest" href="../../assets/images/manifest.json" />
<link
rel="mask-icon"
href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4"
/>
<link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta
name="msapplication-config"
content="../../assets/images/browserconfig.xml"
/>
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Select multiple inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<button class="disable push-bottom">Disable</button>
<button class="enable push-bottom">Enable</button>
<select
class="form-control"
name="choices-basic"
id="choices-basic"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Find me">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<select
class="form-control"
name="choices-remove-button"
id="choices-remove-button"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="disabled-choice">
<label for="choices-disabled-choice">Disabled choice</label>
<select
class="form-control"
name="choices-disabled-choice"
id="choices-disabled-choice"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4" disabled>Choice 4</option>
</select>
</div>
<div data-test-hook="add-items-disabled">
<label for="choices-add-items-disabled">Add items disabled</label>
<select
class="form-control"
name="choices-add-items-disabled"
id="choices-add-items-disabled"
multiple
>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<select
class="form-control"
name="choices-disabled-via-attr"
id="choices-disabled-via-attr"
multiple
disabled
>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="selection-limit">
<label for="choices-selection-limit">Input limit</label>
<select
class="form-control"
name="choices-selection-limit"
id="choices-selection-limit"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
</select>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<select
class="form-control"
name="choices-prepend-append"
id="choices-prepend-append"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="render-choice-limit">
<label for="choices-render-choice-limit">Render choice limit</label>
<select
class="form-control"
name="choices-render-choice-limit"
id="choices-render-choice-limit"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-floor">
<label for="choices-search-floor">Search floor</label>
<select
class="form-control"
name="choices-search-floor"
id="choices-search-floor"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-value">
<label for="choices-placeholder-via-option-value"
>Placeholder via empty option value</label
>
<select
class="form-control"
name="choices-placeholder-via-option-value"
id="choices-placeholder-via-option-value"
multiple
>
<option value="">I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-attr">
<label for="choices-placeholder-via-option-attr"
>Placeholder via option attribute</label
>
<select
class="form-control"
name="choices-placeholder-via-option-attr"
id="choices-placeholder-via-option-attr"
multiple
>
<option placeholder>I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="remote-data">
<label for="choices-remote-data">Remote data</label>
<select
class="form-control"
name="choices-remote-data"
id="choices-remote-data"
multiple
>
<option value="">I am a placeholder</option>
</select>
</div>
<div data-test-hook="scrolling-dropdown">
<label for="choices-scrolling-dropdown">Scrolling dropdown</label>
<select
class="form-control"
name="choices-scrolling-dropdown"
id="choices-scrolling-dropdown"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
<option value="Choice 7">Choice 7</option>
<option value="Choice 8">Choice 8</option>
<option value="Choice 9">Choice 9</option>
<option value="Choice 10">Choice 10</option>
<option value="Choice 11">Choice 11</option>
<option value="Choice 12">Choice 12</option>
<option value="Choice 13">Choice 13</option>
<option value="Choice 14">Choice 14</option>
<option value="Choice 15">Choice 15</option>
</select>
</div>
<div data-test-hook="groups">
<label for="choices-groups">Choice groups</label>
<select
class="form-control"
name="choices-groups"
id="choices-groups"
multiple
>
<optgroup label="UK">
<option value="London">London</option>
<option value="Manchester">Manchester</option>
<option value="Liverpool">Liverpool</option>
</optgroup>
<optgroup label="FR">
<option value="Paris">Paris</option>
<option value="Lyon">Lyon</option>
<option value="Marseille">Marseille</option>
</optgroup>
</select>
</div>
<div data-test-hook="custom-properties">
<label for="choices-custom-properties">Custom properties</label>
<select
class="form-control"
name="choices-custom-properties"
id="choices-custom-properties"
multiple
></select>
</div>
<div data-test-hook="custom-properties-html">
<label for="choices-custom-properties-html">Custom properties</label>
<select
class="form-control"
name="choices-custom-properties-html"
id="choices-custom-properties-html"
>
<option value="Dropdown item 1">Label One</option>
<option value="Dropdown item 2">Label Two</option>
<option
value="Dropdown item 3"
data-custom-properties="This option is fantastic"
>Label Three</option
>
<option
value="Dropdown item 4"
data-custom-properties="{ 'description': 'foo' }"
>Label Four</option
>
</select>
</div>
<div data-test-hook="non-string-values">
<label for="choices-non-string-values">Non-string values</label>
<select
class="form-control"
name="choices-non-string-values"
id="choices-non-string-values"
></select>
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<select
class="form-control"
name="choices-within-form"
id="choices-within-form"
multiple
>
<option value="Choice 1">Choice 1</option>
</select>
</form>
</div>
<div data-test-hook="set-choice-by-value">
<label for="choices-set-choice-by-value"
>Dynamically set choice by value</label
>
<select
class="form-control"
name="choices-set-choice-by-value"
id="choices-set-choice-by-value"
multiple
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-by-label">
<label for="choices-search-by-label">Search by label</label>
<select
class="form-control"
name="choices-search-by-label"
id="choices-search-by-label"
multiple
>
<option value="value1">label1</option>
<option value="value2">label2</option>
</select>
</div>
<div data-test-hook="allowhtml-undefined">
<label for="choices-allowhtml-undefined">HTML allowed by default</label>
<select
class="form-control"
name="choices-allowhtml-undefined"
id="choices-allowhtml-undefined"
multiple
></select>
</div>
<div data-test-hook="allowhtml-true">
<label for="choices-allowhtml-true">HTML allowed</label>
<select
class="form-control"
name="choices-allowhtml-true"
id="choices-allowhtml-true"
multiple
></select>
</div>
<div data-test-hook="allowhtml-false">
<label for="choices-allowhtml-false">HTML disabled</label>
<select
class="form-control"
name="choices-allowhtml-false"
id="choices-allowhtml-false"
multiple
></select>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const choicesBasic = new Choices('#choices-basic', {
allowHTML: true,
});
document
.querySelector('button.disable')
.addEventListener('click', () => {
choicesBasic.disable();
});
document
.querySelector('button.enable')
.addEventListener('click', () => {
choicesBasic.enable();
});
new Choices('#choices-remove-button', {
allowHTML: true,
removeItemButton: true,
});
new Choices('#choices-disabled-choice', {
allowHTML: true,
});
new Choices('#choices-add-items-disabled', {
allowHTML: true,
addItems: false,
});
new Choices('#choices-disabled-via-attr', {
allowHTML: true,
});
new Choices('#choices-selection-limit', {
allowHTML: true,
maxItemCount: 5,
});
new Choices('#choices-prepend-append', {
allowHTML: true,
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-render-choice-limit', {
allowHTML: true,
renderChoiceLimit: 1,
});
new Choices('#choices-search-floor', {
allowHTML: true,
searchFloor: 5,
});
new Choices('#choices-placeholder-via-option-value', {
allowHTML: true,
});
new Choices('#choices-placeholder-via-option-attr', {
allowHTML: true,
});
new Choices('#choices-remote-data', {
allowHTML: true,
shouldSort: false,
}).setChoices(async () => {
const data = await fetch('/data');
return data.json();
});
new Choices('#choices-scrolling-dropdown', {
allowHTML: true,
shouldSort: false,
});
new Choices('#choices-groups', {
allowHTML: true,
});
new Choices('#choices-custom-properties', {
allowHTML: true,
searchFields: ['label', 'value', 'customProperties.country'],
choices: [
{
id: 1,
value: 'London',
label: 'London',
customProperties: {
country: 'United Kingdom',
},
},
{
id: 2,
value: 'Berlin',
label: 'Berlin',
customProperties: {
country: 'Germany',
},
},
{
id: 3,
value: 'Lisbon',
label: 'Lisbon',
customProperties: {
country: 'Portugal',
},
},
],
});
new Choices('#choices-custom-properties-html', {
allowHTML: true,
searchFields: ['label', 'value', 'customProperties'],
});
new Choices('#choices-non-string-values', {
allowHTML: true,
choices: [
{
id: 1,
label: 'Number',
value: 1,
},
{
id: 2,
label: 'Boolean',
value: true,
},
{
id: 3,
label: 'Object',
value: {
test: true,
},
},
{
id: 4,
label: 'Array',
value: ['test'],
},
],
});
new Choices('#choices-within-form', {
allowHTML: true,
});
new Choices('#choices-set-choice-by-value', {
allowHTML: true,
}).setChoiceByValue('Choice 2');
new Choices('#choices-search-by-label', {
allowHTML: true,
searchFields: ['label']
});
new Choices('#choices-allowhtml-undefined', {
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
selected: true
},
{
id: 2,
label: '<b>Choice 2</b>',
value: 'Choice 2',
},
{
id: 3,
label: 'Choice 3',
value: 'Choice 3',
},
],
});
new Choices('#choices-allowhtml-true', {
allowHTML: true,
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
selected: true
},
{
id: 2,
label: '<b>Choice 2</b>',
value: 'Choice 2',
},
{
id: 3,
label: 'Choice 3',
value: 'Choice 3',
},
],
});
new Choices('#choices-allowhtml-false', {
allowHTML: false,
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
selected: true
},
{
id: 2,
label: '<b>Choice 2</b>',
value: 'Choice 2',
},
{
id: 3,
label: 'Choice 3',
value: 'Choice 3',
},
],
});
});
</script>
</body>
</html>

View file

@ -1,352 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>Choices</title>
<meta name=description itemprop=description content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.">
<link rel="apple-touch-icon" sizes="180x180" href="../assets/images/apple-touch-icon.png">
<link rel="icon" type="image/png" href="../assets/images/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="../assets/images/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="../assets/images/manifest.json">
<link rel="mask-icon" href="../assets/images/safari-pinned-tab.svg" color="#00bcd4">
<link rel="shortcut icon" href="../assets/images/favicon.ico">
<meta name="msapplication-config" content="../assets/images/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3">
<!-- 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>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Select one inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<button class="disable push-bottom">Disable</button>
<button class="enable push-bottom">Enable</button>
<select class="form-control" name="choices-basic" id="choices-basic">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Find me">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<select class="form-control" name="choices-remove-button" id="choices-remove-button">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="disabled-choice">
<label for="choices-disabled-choice">Disabled choice</label>
<select class="form-control" name="choices-disabled-choice" id="choices-disabled-choice">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4" disabled>Choice 4</option>
</select>
</div>
<div data-test-hook="add-items-disabled">
<label for="choices-add-items-disabled">Add items disabled</label>
<select class="form-control" name="choices-add-items-disabled" id="choices-add-items-disabled">
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<select class="form-control" name="choices-disabled-via-attr" id="choices-disabled-via-attr" disabled>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<select class="form-control" name="choices-prepend-append" id="choices-prepend-append">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="render-choice-limit">
<label for="choices-render-choice-limit">Render choice limit</label>
<select class="form-control" name="choices-render-choice-limit" id="choices-render-choice-limit">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-disabled">
<label for="choices-search-disabled">Search disabled</label>
<select class="form-control" name="choices-search-disabled" id="choices-search-disabled">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-floor">
<label for="choices-search-floor">Search floor</label>
<select class="form-control" name="choices-search-floor" id="choices-search-floor">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="remote-data">
<label for="choices-remote-data">Remote data</label>
<select class="form-control" name="choices-remote-data" id="choices-remote-data"></select>
</div>
<div data-test-hook="scrolling-dropdown">
<label for="choices-scrolling-dropdown">Scrolling dropdown</label>
<select class="form-control" name="choices-scrolling-dropdown" id="choices-scrolling-dropdown">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
<option value="Choice 7">Choice 7</option>
<option value="Choice 8">Choice 8</option>
<option value="Choice 9">Choice 9</option>
<option value="Choice 10">Choice 10</option>
<option value="Choice 11">Choice 11</option>
<option value="Choice 12">Choice 12</option>
<option value="Choice 13">Choice 13</option>
<option value="Choice 14">Choice 14</option>
<option value="Choice 15">Choice 15</option>
</select>
</div>
<div data-test-hook="groups">
<label for="choices-groups">Choice groups</label>
<select class="form-control" name="choices-groups" id="choices-groups" multiple>
<optgroup label="UK">
<option value="London">London</option>
<option value="Manchester">Manchester</option>
<option value="Liverpool">Liverpool</option>
</optgroup>
<optgroup label="FR">
<option value="Paris">Paris</option>
<option value="Lyon">Lyon</option>
<option value="Marseille">Marseille</option>
</optgroup>
</select>
</div>
<div data-test-hook="parent-child">
<label for="choices-parent">Parent</label>
<select class="form-control" name="choices-parent" id="choices-parent">
<option value="Parent choice 1">Parent choice 1</option>
<option value="Parent choice 2">Parent choice 2</option>
<option value="Parent choice 3">Parent choice 3</option>
</select>
<label for="choices-child">Child</label>
<select class="form-control" name="choices-child" id="choices-child">
<option value="Child choice 1">Child choice 1</option>
<option value="Child choice 2">Child choice 2</option>
<option value="Child choice 3">Child choice 3</option>
</select>
</div>
<div data-test-hook="custom-properties">
<label for="choices-custom-properties">Custom properties</label>
<select class="form-control" name="choices-custom-properties" id="choices-custom-properties"></select>
</div>
<div data-test-hook="non-string-values">
<label for="choices-non-string-values">Non-string values</label>
<select class="form-control" name="choices-non-string-values" id="choices-non-string-values"></select>
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<select class="form-control" name="choices-within-form" id="choices-within-form">
<option value="Choice 1">Choice 1</option>
</select>
</form>
</div>
<div data-test-hook="set-choice-by-value">
<label for="choices-set-choice-by-value">Dynamically set choice by value</label>
<select class="form-control" name="choices-set-choice-by-value" id="choices-set-choice-by-value">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-by-label">
<label for="choices-search-by-label">Search by label</label>
<select class="form-control" name="choices-search-by-label" id="choices-search-by-label">
<option value="value1">label1</option>
<option value="value2">label2</option>
</select>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const choicesBasic = new Choices('#choices-basic');
document.querySelector('button.disable').addEventListener('click', () => {
choicesBasic.disable();
});
document.querySelector('button.enable').addEventListener('click', () => {
choicesBasic.enable();
});
new Choices('#choices-remove-button', {
removeItemButton: true,
});
new Choices('#choices-disabled-choice', {
removeItemButton: true,
});
new Choices('#choices-add-items-disabled', {
addItems: false,
});
new Choices('#choices-disabled-via-attr');
new Choices('#choices-prepend-append', {
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-render-choice-limit', {
renderChoiceLimit: 1
});
new Choices('#choices-search-disabled', {
searchEnabled: false
})
new Choices('#choices-search-floor', {
searchFloor: 5,
});
new Choices('#choices-remote-data', {
shouldSort: false,
}).ajax((callback) => {
fetch('/data')
.then((response) => {
response.json().then((data) => {
callback(data, 'value', 'label');
});
})
.catch((error) => {
console.error(error);
});
});
new Choices('#choices-scrolling-dropdown', {
shouldSort: false,
});
new Choices('#choices-groups');
const parent = new Choices('#choices-parent');
const child = new Choices('#choices-child').disable();
parent.passedElement.element.addEventListener('change', (event) => {
if (event.detail.value === 'Parent choice 2') {
child.enable();
} else {
child.disable();
}
});
new Choices('#choices-custom-properties', {
searchFields: ['label', 'value', 'customProperties.country'],
choices: [
{
id: 1,
value: 'London',
label: 'London',
customProperties: {
country: 'United Kingdom',
},
},
{
id: 2,
value: 'Berlin',
label: 'Berlin',
customProperties: {
country: 'Germany',
},
},
{
id: 3,
value: 'Lisbon',
label: 'Lisbon',
customProperties: {
country: 'Portugal',
},
}
]
});
new Choices('#choices-non-string-values', {
choices: [
{
id: 1,
label: 'Number',
value: 1,
},
{
id: 2,
label: 'Boolean',
value: true,
},
{
id: 3,
label: 'Object',
value: {
test: true,
},
},
{
id: 4,
label: 'Array',
value: ['test'],
},
],
});
new Choices('#choices-within-form');
new Choices('#choices-set-choice-by-value').setChoiceByValue('Choice 2');
new Choices('#choices-search-by-label', { searchFields: ['label'] });
});
</script>
</body>
</html>

View file

@ -0,0 +1,682 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,user-scalable=no"
/>
<title>Choices</title>
<meta
name="description"
itemprop="description"
content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency."
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../assets/images/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-32x32.png"
sizes="32x32"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-16x16.png"
sizes="16x16"
/>
<link rel="manifest" href="../../assets/images/manifest.json" />
<link
rel="mask-icon"
href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4"
/>
<link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta
name="msapplication-config"
content="../../assets/images/browserconfig.xml"
/>
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Select one inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<button class="disable push-bottom">Disable</button>
<button class="enable push-bottom">Enable</button>
<select class="form-control" name="choices-basic" id="choices-basic">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Find me">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<select
class="form-control"
name="choices-remove-button"
id="choices-remove-button"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
</select>
</div>
<div data-test-hook="disabled-choice">
<label for="choices-disabled-choice">Disabled choice</label>
<select
class="form-control"
name="choices-disabled-choice"
id="choices-disabled-choice"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4" disabled>Choice 4</option>
</select>
</div>
<div data-test-hook="disabled-first-choice-via-options">
<label for="choices-disabled-choice-via-options"
>Disabled first choice by options</label
>
<select
class="form-control"
name="choices-disabled-choice-via-options"
id="choices-disabled-choice-via-options"
>
</select>
</div>
<div data-test-hook="add-items-disabled">
<label for="choices-add-items-disabled">Add items disabled</label>
<select
class="form-control"
name="choices-add-items-disabled"
id="choices-add-items-disabled"
>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<select
class="form-control"
name="choices-disabled-via-attr"
id="choices-disabled-via-attr"
disabled
>
<option value="Choice 1" selected>Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<select
class="form-control"
name="choices-prepend-append"
id="choices-prepend-append"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="render-choice-limit">
<label for="choices-render-choice-limit">Render choice limit</label>
<select
class="form-control"
name="choices-render-choice-limit"
id="choices-render-choice-limit"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-disabled">
<label for="choices-search-disabled">Search disabled</label>
<select
class="form-control"
name="choices-search-disabled"
id="choices-search-disabled"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-floor">
<label for="choices-search-floor">Search floor</label>
<select
class="form-control"
name="choices-search-floor"
id="choices-search-floor"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-value">
<label for="choices-placeholder-via-option-value"
>Placeholder via empty option value</label
>
<select
class="form-control"
name="choices-placeholder-via-option-value"
id="choices-placeholder-via-option-value"
>
<option value="">I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-attr">
<label for="choices-placeholder-via-option-attr"
>Placeholder via option attribute</label
>
<select
class="form-control"
name="choices-placeholder-via-option-attr"
id="choices-placeholder-via-option-attr"
>
<option placeholder>I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="remote-data">
<label for="choices-remote-data">Remote data</label>
<select
class="form-control"
name="choices-remote-data"
id="choices-remote-data"
>
<option value="">I am a placeholder</option>
</select>
</div>
<div data-test-hook="scrolling-dropdown">
<label for="choices-scrolling-dropdown">Scrolling dropdown</label>
<select
class="form-control"
name="choices-scrolling-dropdown"
id="choices-scrolling-dropdown"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
<option value="Choice 4">Choice 4</option>
<option value="Choice 5">Choice 5</option>
<option value="Choice 6">Choice 6</option>
<option value="Choice 7">Choice 7</option>
<option value="Choice 8">Choice 8</option>
<option value="Choice 9">Choice 9</option>
<option value="Choice 10">Choice 10</option>
<option value="Choice 11">Choice 11</option>
<option value="Choice 12">Choice 12</option>
<option value="Choice 13">Choice 13</option>
<option value="Choice 14">Choice 14</option>
<option value="Choice 15">Choice 15</option>
</select>
</div>
<div data-test-hook="groups">
<label for="choices-groups">Choice groups</label>
<select
class="form-control"
name="choices-groups"
id="choices-groups"
multiple
>
<optgroup label="UK">
<option value="London">London</option>
<option value="Manchester">Manchester</option>
<option value="Liverpool">Liverpool</option>
</optgroup>
<optgroup label="FR">
<option value="Paris">Paris</option>
<option value="Lyon">Lyon</option>
<option value="Marseille">Marseille</option>
</optgroup>
</select>
</div>
<div data-test-hook="parent-child">
<label for="choices-parent">Parent</label>
<select
class="form-control"
name="choices-parent"
id="choices-parent"
>
<option value="Parent choice 1">Parent choice 1</option>
<option value="Parent choice 2">Parent choice 2</option>
<option value="Parent choice 3">Parent choice 3</option>
</select>
<label for="choices-child">Child</label>
<select class="form-control" name="choices-child" id="choices-child">
<option value="Child choice 1">Child choice 1</option>
<option value="Child choice 2">Child choice 2</option>
<option value="Child choice 3">Child choice 3</option>
</select>
</div>
<div data-test-hook="custom-properties">
<label for="choices-custom-properties">Custom properties</label>
<select
class="form-control"
name="choices-custom-properties"
id="choices-custom-properties"
></select>
</div>
<div data-test-hook="custom-properties-html">
<label for="choices-custom-properties-html">Custom properties</label>
<select
class="form-control"
name="choices-custom-properties-html"
id="choices-custom-properties-html"
>
<option value="Dropdown item 1">Label One</option>
<option value="Dropdown item 2">Label Two</option>
<option
value="Dropdown item 3"
data-custom-properties="This option is fantastic"
>Label Three</option
>
<option
value="Dropdown item 4"
data-custom-properties="{ 'description': 'foo' }"
>Label Four</option
>
</select>
</div>
<div data-test-hook="non-string-values">
<label for="choices-non-string-values">Non-string values</label>
<select
class="form-control"
name="choices-non-string-values"
id="choices-non-string-values"
></select>
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<select
class="form-control"
name="choices-within-form"
id="choices-within-form"
>
<option value="Choice 1">Choice 1</option>
</select>
</form>
</div>
<div data-test-hook="set-choice-by-value">
<label for="choices-set-choice-by-value"
>Dynamically set choice by value</label
>
<select
class="form-control"
name="choices-set-choice-by-value"
id="choices-set-choice-by-value"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="search-by-label">
<label for="choices-search-by-label">Search by label</label>
<select
class="form-control"
name="choices-search-by-label"
id="choices-search-by-label"
>
<option value="value1">label1</option>
<option value="value2">label2</option>
</select>
</div>
<div data-test-hook="allowhtml-undefined">
<label for="choices-allowhtml-undefined">HTML allowed by default</label>
<select
class="form-control"
name="choices-allowhtml-undefined"
id="choices-allowhtml-undefined"
></select>
</div>
<div data-test-hook="allowhtml-true">
<label for="choices-allowhtml-true">HTML allowed</label>
<select
class="form-control"
name="choices-allowhtml-true"
id="choices-allowhtml-true"
></select>
</div>
<div data-test-hook="allowhtml-false">
<label for="choices-allowhtml-false">HTML disabled</label>
<select
class="form-control"
name="choices-allowhtml-false"
id="choices-allowhtml-false"
></select>
</div>
<div data-test-hook="new-destroy-init">
<label for="choices-new-destroy-init">New, Destroy, Init</label>
<select
class="form-control"
name="choices-new-destroy-init"
id="choices-new-destroy-init"
>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
<button class="destroy">Destroy</button>
<button class="init">Init</button>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const choicesBasic = new Choices('#choices-basic', {
allowHTML: true,
});
document
.querySelector('button.disable')
.addEventListener('click', () => {
choicesBasic.disable();
});
document
.querySelector('button.enable')
.addEventListener('click', () => {
choicesBasic.enable();
});
new Choices('#choices-remove-button', {
allowHTML: true,
removeItemButton: true,
});
new Choices('#choices-disabled-choice', {
allowHTML: true,
removeItemButton: true,
});
new Choices('#choices-disabled-choice-via-options', {
allowHTML: true,
removeItemButton: true,
choices: [
{
value: 'Choice 1',
label: 'Choice 1',
disabled: true,
},
{
value: 'Choice 2',
label: 'Choice 2',
},
{
value: 'Choice 3',
label: 'Choice 3',
},
{
value: 'Choice 4',
label: 'Choice 4',
},
],
});
new Choices('#choices-add-items-disabled', {
allowHTML: true,
addItems: false,
});
new Choices('#choices-disabled-via-attr', {
allowHTML: true,
});
new Choices('#choices-prepend-append', {
allowHTML: true,
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-render-choice-limit', {
allowHTML: true,
renderChoiceLimit: 1,
});
new Choices('#choices-search-disabled', {
allowHTML: true,
searchEnabled: false,
});
new Choices('#choices-search-floor', {
allowHTML: true,
searchFloor: 5,
});
new Choices('#choices-placeholder-via-option-value', {
allowHTML: true,
});
new Choices('#choices-placeholder-via-option-attr', {
allowHTML: true,
});
new Choices('#choices-remote-data', {
allowHTML: true,
shouldSort: false,
}).setChoices(async () => {
const res = await fetch('/data');
return res.json();
});
new Choices('#choices-scrolling-dropdown', {
allowHTML: true,
shouldSort: false,
});
new Choices('#choices-groups', {
allowHTML: true,
});
const parent = new Choices('#choices-parent', {
allowHTML: true,
});
const child = new Choices('#choices-child', {
allowHTML: true,
}).disable();
parent.passedElement.element.addEventListener('change', event => {
if (event.detail.value === 'Parent choice 2') {
child.enable();
} else {
child.disable();
}
});
new Choices('#choices-custom-properties', {
allowHTML: true,
searchFields: ['label', 'value', 'customProperties.country'],
choices: [
{
id: 1,
value: 'London',
label: 'London',
customProperties: {
country: 'United Kingdom',
},
},
{
id: 2,
value: 'Berlin',
label: 'Berlin',
customProperties: {
country: 'Germany',
},
},
{
id: 3,
value: 'Lisbon',
label: 'Lisbon',
customProperties: {
country: 'Portugal',
},
},
],
});
new Choices('#choices-custom-properties-html', {
allowHTML: true,
searchFields: ['label', 'value', 'customProperties'],
});
new Choices('#choices-non-string-values', {
allowHTML: true,
choices: [
{
id: 1,
label: 'Number',
value: 1,
},
{
id: 2,
label: 'Boolean',
value: true,
},
{
id: 3,
label: 'Object',
value: {
test: true,
},
},
{
id: 4,
label: 'Array',
value: ['test'],
},
],
});
new Choices('#choices-within-form', {
allowHTML: true,
});
new Choices('#choices-set-choice-by-value', {
allowHTML: true,
}).setChoiceByValue('Choice 2');
new Choices('#choices-search-by-label', {
allowHTML: true,
searchFields: ['label']
});
new Choices('#choices-allowhtml-undefined', {
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
},
{
id: 2,
label: 'Choice 2',
value: 'Choice 2',
},
],
});
new Choices('#choices-allowhtml-true', {
allowHTML: true,
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
},
{
id: 2,
label: 'Choice 2',
value: 'Choice 2',
},
],
});
new Choices('#choices-allowhtml-false', {
allowHTML: false,
choices: [
{
id: 1,
label: '<b>Choice 1</b>',
value: 'Choice 1',
},
{
id: 2,
label: 'Choice 2',
value: 'Choice 2',
},
],
});
const newDestroyInitChoices = new Choices('#choices-new-destroy-init', {
allowHTML: true,
});
document
.querySelector('button.destroy')
.addEventListener('click', () => {
newDestroyInitChoices.destroy();
});
document.querySelector('button.init').addEventListener('click', () => {
newDestroyInitChoices.init();
});
});
</script>
</body>
</html>

View file

@ -1,154 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>Choices</title>
<meta name=description itemprop=description content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.">
<link rel="apple-touch-icon" sizes="180x180" href="../assets/images/apple-touch-icon.png">
<link rel="icon" type="image/png" href="../assets/images/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="../assets/images/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="../assets/images/manifest.json">
<link rel="mask-icon" href="../assets/images/safari-pinned-tab.svg" color="#00bcd4">
<link rel="shortcut icon" href="../assets/images/favicon.ico">
<meta name="msapplication-config" content="../assets/images/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3">
<!-- 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>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Text inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<input class="form-control" id="choices-basic" type="text">
</div>
<div data-test-hook="edit-items">
<label for="choices-edit-items">Edit items</label>
<input class="form-control" id="choices-edit-items" type="text">
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<input class="form-control" id="choices-remove-button" type="text">
</div>
<div data-test-hook="unique-values">
<label for="choices-unique-values">Unique values</label>
<input class="form-control" id="choices-unique-values" type="text">
</div>
<div data-test-hook="input-limit">
<label for="choices-input-limit">Input limit</label>
<input class="form-control" id="choices-input-limit" type="text">
</div>
<div data-test-hook="add-item-filter">
<label for="choices-add-item-filter">Add item filter</label>
<input class="form-control" id="choices-add-item-filter" type="text">
</div>
<div data-test-hook="adding-items-disabled">
<label for="choices-adding-items-disabled">Add items disabled</label>
<input class="form-control" id="choices-adding-items-disabled" type="text">
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<input class="form-control" id="choices-disabled-via-attr" type="text" disabled>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<input class="form-control" id="choices-prepend-append" type="text">
</div>
<div data-test-hook="prepopulated">
<label for="choices-prepopulated">Pre-populated choices</label>
<input class="form-control" id="choices-prepopulated" type="text">
</div>
<div data-test-hook="placeholder">
<label for="choices-placeholder">Placeholder</label>
<input class="form-control" id="choices-placeholder" type="text">
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<input class="form-control" id="choices-within-form" type="text">
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
new Choices('#choices-basic');
new Choices('#choices-edit-items', {
editItems: true,
});
new Choices('#choices-remove-button', {
removeItemButton: true,
});
new Choices('#choices-unique-values', {
duplicateItemsAllowed: false,
});
new Choices('#choices-input-limit', {
maxItemCount: 5,
});
new Choices('#choices-add-item-filter', {
addItems: true,
addItemFilterFn: (value) => {
const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
const expression = new RegExp(regex.source, 'i');
return expression.test(value);
},
});
new Choices('#choices-adding-items-disabled', {
addItems: false,
});
new Choices('#choices-disabled-via-attr');
new Choices('#choices-prepend-append', {
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-prepopulated', {
items: ['Josh Johnson', {
value: 'joe@bloggs.co.uk',
label: 'Joe Bloggs',
customProperties: {
description: 'Joe Blogg is such a generic name',
}
}],
});
new Choices('#choices-placeholder', {
placeholder: true,
placeholderValue: 'I am a placeholder',
});
new Choices('#choices-within-form');
});
</script>
</body>
</html>

247
public/test/text/index.html Normal file
View file

@ -0,0 +1,247 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,user-scalable=no"
/>
<title>Choices</title>
<meta
name="description"
itemprop="description"
content="A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency."
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../assets/images/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-32x32.png"
sizes="32x32"
/>
<link
rel="icon"
type="image/png"
href="../../assets/images/favicon-16x16.png"
sizes="16x16"
/>
<link rel="manifest" href="../../assets/images/manifest.json" />
<link
rel="mask-icon"
href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4"
/>
<link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta
name="msapplication-config"
content="../../assets/images/browserconfig.xml"
/>
<meta name="theme-color" content="#ffffff" />
<!-- Ignore these -->
<link rel="stylesheet" href="../../assets/styles/base.min.css" />
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../../assets/styles/choices.min.css" />
<script src="../../assets/scripts/choices.min.js"></script>
<!-- End Choices includes -->
</head>
<body>
<div class="container">
<div class="section">
<h2>Text inputs</h2>
<div data-test-hook="basic">
<label for="choices-basic">Basic</label>
<input class="form-control" id="choices-basic" type="text" />
</div>
<div data-test-hook="edit-items">
<label for="choices-edit-items">Edit items</label>
<input class="form-control" id="choices-edit-items" type="text" />
</div>
<div data-test-hook="remove-button">
<label for="choices-remove-button">Remove button</label>
<input class="form-control" id="choices-remove-button" type="text" />
</div>
<div data-test-hook="unique-values">
<label for="choices-unique-values">Unique values</label>
<input class="form-control" id="choices-unique-values" type="text" />
</div>
<div data-test-hook="allowhtml-undefined">
<label for="allowhtml-undefined">HTML allowed by default</label>
<input class="form-control" id="allowhtml-undefined" type="text" />
</div>
<div data-test-hook="allowhtml-true">
<label for="allowhtml-true">HTML allowed</label>
<input class="form-control" id="allowhtml-true" type="text" />
</div>
<div data-test-hook="allowhtml-false">
<label for="allowhtml-false">HTML disabled</label>
<input class="form-control" id="allowhtml-false" type="text" />
</div>
<div data-test-hook="input-limit">
<label for="choices-input-limit">Input limit</label>
<input class="form-control" id="choices-input-limit" type="text" />
</div>
<div data-test-hook="add-item-filter">
<label for="choices-add-item-filter">Add item filter</label>
<input
class="form-control"
id="choices-add-item-filter"
type="text"
/>
</div>
<div data-test-hook="adding-items-disabled">
<label for="choices-adding-items-disabled">Add items disabled</label>
<input
class="form-control"
id="choices-adding-items-disabled"
type="text"
/>
</div>
<div data-test-hook="disabled-via-attr">
<label for="choices-disabled-via-attr">Disabled via attribute</label>
<input
class="form-control"
id="choices-disabled-via-attr"
type="text"
disabled
/>
</div>
<div data-test-hook="prepend-append">
<label for="choices-prepend-append">Prepend/append</label>
<input class="form-control" id="choices-prepend-append" type="text" />
</div>
<div data-test-hook="prepopulated">
<label for="choices-prepopulated">Pre-populated choices</label>
<input class="form-control" id="choices-prepopulated" type="text" />
</div>
<div data-test-hook="placeholder">
<label for="choices-placeholder">Placeholder</label>
<input class="form-control" id="choices-placeholder" type="text" />
</div>
<div data-test-hook="within-form">
<form>
<label for="choices-within-form">Within form</label>
<input class="form-control" id="choices-within-form" type="text" />
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
new Choices('#choices-basic', {
allowHTML: true,
});
new Choices('#choices-edit-items', {
allowHTML: true,
editItems: true,
});
new Choices('#choices-remove-button', {
allowHTML: true,
removeItemButton: true,
});
new Choices('#choices-unique-values', {
allowHTML: true,
duplicateItemsAllowed: false,
});
new Choices('#allowhtml-undefined', {
items: [
'<b>Mason Rogers</b>'
],
});
new Choices('#allowhtml-true', {
allowHTML: true,
items: [
'<b>Mason Rogers</b>'
],
});
new Choices('#allowhtml-false', {
allowHTML: false,
items: [
'<b>Mason Rogers</b>'
],
});
new Choices('#choices-input-limit', {
allowHTML: true,
maxItemCount: 5,
});
new Choices('#choices-add-item-filter', {
allowHTML: true,
addItems: true,
addItemFilter: value => {
const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const expression = new RegExp(regex.source, 'i');
return expression.test(value);
},
});
new Choices('#choices-adding-items-disabled', {
allowHTML: true,
addItems: false,
});
new Choices('#choices-disabled-via-attr', {
allowHTML: true,
});
new Choices('#choices-prepend-append', {
allowHTML: true,
prependValue: 'before-',
appendValue: '-after',
});
new Choices('#choices-prepopulated', {
allowHTML: true,
items: [
'Josh Johnson',
{
value: 'joe@bloggs.co.uk',
label: 'Joe Bloggs',
customProperties: {
description: 'Joe Blogg is such a generic name',
},
},
],
});
new Choices('#choices-placeholder', {
allowHTML: true,
placeholder: true,
placeholderValue: 'I am a placeholder',
});
new Choices('#choices-within-form', {
allowHTML: true,
});
});
</script>
</body>
</html>

View file

@ -0,0 +1 @@
//# sourceMappingURL=select-multiple.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"select-multiple.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/e2e/select-multiple.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1 @@
//# sourceMappingURL=select-one.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"select-one.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/e2e/select-one.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1 @@
//# sourceMappingURL=text.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"text.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/e2e/text.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1 @@
//# sourceMappingURL=select-multiple.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"select-multiple.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/integration/select-multiple.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1 @@
//# sourceMappingURL=select-one.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"select-one.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/integration/select-one.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1 @@
//# sourceMappingURL=text.spec.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"text.spec.d.ts","sourceRoot":"","sources":["../../../../cypress/integration/text.spec.ts"],"names":[],"mappings":""}

View file

@ -0,0 +1,3 @@
declare function _exports(on: any, config: any): void;
export = _exports;
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../cypress/plugins/index.js"],"names":[],"mappings":"AAaiB,sDAGhB"}

View file

@ -0,0 +1 @@
//# sourceMappingURL=commands.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../cypress/support/commands.js"],"names":[],"mappings":""}

2
public/types/cypress/support/e2e.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=e2e.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"e2e.d.ts","sourceRoot":"","sources":["../../../../cypress/support/e2e.js"],"names":[],"mappings":""}

View file

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../cypress/support/index.js"],"names":[],"mappings":""}

7
public/types/src/index.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
import Choices from './scripts/choices';
export * from './scripts/interfaces';
export * from './scripts/constants';
export * from './scripts/defaults';
export { default as templates } from './scripts/templates';
export default Choices;
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,mBAAmB,CAAC;AAExC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE3D,eAAe,OAAO,CAAC"}

View file

@ -0,0 +1,44 @@
import { ACTION_TYPES } from '../constants';
import { Choice } from '../interfaces/choice';
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 declare const addChoice: ({ value, label, id, groupId, disabled, elementId, customProperties, placeholder, keyCode, }: {
value: any;
label: any;
id: any;
groupId: any;
disabled: any;
elementId: any;
customProperties: any;
placeholder: any;
keyCode: any;
}) => AddChoiceAction;
export declare const filterChoices: (results: Result<Choice>[]) => FilterChoicesAction;
export declare const activateChoices: (active?: boolean) => ActivateChoicesAction;
export declare const clearChoices: () => ClearChoicesAction;
//# sourceMappingURL=choices.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"choices.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/actions/choices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,OAAO,YAAY,CAAC,UAAU,CAAC;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,YAAY,CAAC,cAAc,CAAC;IACzC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,YAAY,CAAC,gBAAgB,CAAC;IAC3C,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,YAAY,CAAC,aAAa,CAAC;CACzC;AAED,eAAO,MAAM,SAAS;;;;;;;;;;MAUlB,eAWF,CAAC;AAEH,eAAO,MAAM,aAAa,YACf,OAAO,MAAM,CAAC,EAAE,KACxB,mBAGD,CAAC;AAEH,eAAO,MAAM,eAAe,wBAAoB,qBAG9C,CAAC;AAEH,eAAO,MAAM,YAAY,QAAO,kBAE9B,CAAC"}

View file

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=choices.test.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"choices.test.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/actions/choices.test.ts"],"names":[],"mappings":""}

View file

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

View file

@ -0,0 +1 @@
{"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../../../src/scripts/actions/groups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,YAAY,CAAC,SAAS,CAAC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,QAAQ;QAMf,MAAM;WACH,MAAM;YACL,OAAO;cACL,OAAO;MACf,cAMF,CAAC"}

View file

@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=groups.test.d.ts.map

Some files were not shown because too many files have changed in this diff Show more