Compare commits

..

No commits in common. "master" and "v6.0.3" have entirely different histories.

307 changed files with 25622 additions and 40388 deletions

View file

@ -1,17 +1,11 @@
{
"presets": [["@babel/preset-env", { "loose": true }]],
"env": {
"test": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": true
}
}
]
]
}
}
"presets": [
"@babel/preset-env"
],
"plugins": [
"@babel/plugin-transform-modules-commonjs",
["@babel/plugin-transform-spread", {
"loose": true
}]
]
}

View file

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

View file

@ -1,4 +0,0 @@
coverage:
parsers:
javascript:
enable_partials: yes

View file

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

54
.eslintrc Normal file
View file

@ -0,0 +1,54 @@
{
"parser": "babel-eslint",
"extends": [
"airbnb",
"prettier"
],
"plugins": [
"prettier",
"cypress"
],
"env": {
"es6": true,
"browser": true,
"node": true,
"mocha": true,
"cypress/globals": true
},
"globals": {
"describe": true,
"it": true,
"before": true,
"after": true,
"beforeEach": true,
"afterEach": 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"
}
]
}
}

View file

@ -1,123 +0,0 @@
{
"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
View file

@ -1,64 +0,0 @@
## 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

View file

@ -1,38 +0,0 @@
---
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

@ -1,20 +0,0 @@
---
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 @@
## Description
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## Screenshots (if appropriate)
## 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):
## 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.
- [ ] I have updated the documentation accordingly.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

View file

@ -1,14 +0,0 @@
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);

View file

@ -1,92 +0,0 @@
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);

View file

@ -1,155 +0,0 @@
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);

View file

@ -1,29 +0,0 @@
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

20
.github/stale.yml vendored Normal file
View file

@ -0,0 +1,20 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 100
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 10
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- feature request
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
Thanks for contributing to this issue. As it has been 60 days since the last
activity, this issue is being automatically closed. This is often because the
request was already solved in some way and it just wasn't updated or it's no
longer applicable. If that's not the case, please do feel free to either
reopen this issue or open a new one. We'll gladly take a look again!
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View file

@ -1,131 +0,0 @@
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,60 +0,0 @@
name: Build and test
on:
push:
branches:
- master
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
- name: Build and run all tests
run: |
npm ci
npm run build
npx bundlesize
npm run test:unit:coverage
npm run test:e2e
env:
CI: true
CI_REPO_NAME: ${{ github.event.repository.name }}
CI_REPO_OWNER: ${{ github.event.organization.login }}
CI_COMMIT_SHA: ${{ github.sha }}
GIT_COMMIT: ${{ github.sha }}
CI_BRANCH: ${{ github.head_ref }}
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)
-f ./coverage/lcov.info
-B ${{ github.head_ref }}
-C ${{ github.sha }}
-Z || echo 'Codecov upload failed'
env:
CI: true
GITLAB_CI: true # pretend we are GitLab CI, while Codecov adding support for Github Actions
CODECOV_ENV: github-action
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}

View file

@ -1,42 +0,0 @@
name: Bundle size checks
on:
pull_request:
paths:
- 'src/scripts/**'
- 'src/styles/**'
- 'package-lock.json'
- '.browserslistrc'
jobs:
measure:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
- name: Install dependencies and build
run: |
npm ci
npm run build
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
# we don't need to build here, as even minized assets expected to be commited
- run: npx bundlesize
env:
CI: true
BUNDLESIZE_GITHUB_TOKEN: ${{secrets.BUNDLESIZE_GITHUB_TOKEN}}
CI_REPO_NAME: ${{ github.event.repository.name }}
CI_REPO_OWNER: ${{ github.event.organization.login }}
CI_COMMIT_SHA: ${{ github.event.after }}
GIT_COMMIT: ${{ github.event.after }}
CI_BRANCH: ${{ github.head_ref }}
FORCE_COLOR: 2

View file

@ -1,32 +0,0 @@
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

View file

@ -1,24 +0,0 @@
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}}

View file

@ -1,71 +0,0 @@
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,41 +0,0 @@
name: Code linting
on:
pull_request:
paths:
- 'src/scripts/**'
- 'src/styles/**'
- package-lock.json
- '.browserslistrc'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
- name: Install dependencies
run: npm ci
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- name: run eslint
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

View file

@ -1,23 +0,0 @@
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

View file

@ -1,14 +0,0 @@
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,42 +0,0 @@
name: Unit tests
on:
pull_request:
paths:
- 'src/scripts/**'
- package-lock.json
- '.browserslistrc'
jobs:
test-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: actions/setup-node@v2
with:
node-version: 18
- name: Install dependencies
run: npm install --no-optional --no-audit --ignore-scripts
env:
CYPRESS_INSTALL_BINARY: 0
HUSKY_SKIP_INSTALL: true
- run: npm run test:unit:coverage
env:
FORCE_COLOR: 2
- name: Upload coverage to Codecov
run: bash <(curl -s https://codecov.io/bash)
-f ./coverage/lcov.info
-B ${{ github.head_ref }}
-C ${{ github.sha }}
-Z || echo 'Codecov upload failed'
env:
CI: true
GITLAB_CI: true # pretend we are GitLab CI, while Codecov adding support for Github Actions
CODECOV_ENV: github-action
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}

View file

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

View file

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

2
.npmrc
View file

@ -1,2 +0,0 @@
message=":bookmark: Version %s"
git-tag-version=true

1
.nvmrc
View file

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

View file

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

View file

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

19
.travis.yml Normal file
View file

@ -0,0 +1,19 @@
language: node_js
node_js:
- 10
cache:
directories:
- ~/.npm
- ~/.cache
install:
- npm ci
jobs:
include:
- stage: Judging bundle size
script: npm run bundlesize
- stage: Linting code
script: npm run lint
- stage: Running tests
script: npm run test

View file

@ -1,17 +0,0 @@
{
// 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
View file

@ -1,70 +0,0 @@
{
"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:*"
}
}
]
}

73
.vscode/settings.json vendored
View file

@ -1,72 +1,3 @@
{
"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"
]
}
"eslint.enable": true
}

87
.vscode/tasks.json vendored
View file

@ -1,87 +0,0 @@
{
// 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

@ -1,12 +1,11 @@
# Contributions
# Contributions
In lieu of a formal styleguide, take care to maintain the existing coding style ensuring there are no linting errors. Add unit tests for any new or changed functionality. Lint and test your code using the npm scripts below:
### NPM tasks
| Task | Usage |
| -------------------- | ------------------------------------------------------------ |
| `npm run start` | Fire up local server for development |
| `npm run test:unit` | Run sequence of unit tests once |
| `npm run test:e2e` | Run sequence of integration tests once |
| `npm run test` | Run sequence of 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 |

642
README.md

File diff suppressed because it is too large Load diff

54
bump-cache.js Normal file
View file

@ -0,0 +1,54 @@
const fs = require('fs');
const path = require('path');
const config = {
files: ['public/index.html'],
};
/**
* Convert node arguments into an object
* @return {Object} Arguments
*/
const argvToObject = () => {
const args = {};
let arg = null;
process.argv.forEach((val, index) => {
if (/^--/.test(val)) {
arg = {
index,
name: val.replace(/^--/, ''),
};
return;
}
if (arg && arg.index + 1 === index) {
args[arg.name] = val;
}
});
return args;
};
/**
* Loop through files updating the current version
* @param {Object} config
*/
const updateVersion = ({ files }) => {
const args = argvToObject();
const version = args.current;
console.log(`Updating version to ${version}`);
files.forEach(file => {
const filePath = path.join(__dirname, file);
const regex = new RegExp(/\?version=(.*?)\"/, 'g');
let contents = fs.readFileSync(filePath, 'utf-8');
contents = contents.replace(regex, `?version=${version}"`);
fs.writeFileSync(filePath, contents);
});
console.log(`Updated version to ${version}`);
};
updateVersion(config);

View file

@ -1,13 +1,6 @@
/* eslint-disable no-param-reassign */
const { JSDOM } = require('jsdom');
const jsdom = new JSDOM(
'<!doctype html><html><head><meta charset="utf-8"></head><body></body></html>',
{
pretendToBeVisual: true,
},
);
const jsdom = new JSDOM('<!doctype html><html><body></body></html>');
const { window } = jsdom;
function copyProps(src, target) {
@ -27,6 +20,26 @@ 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 = {
@ -35,16 +48,12 @@ 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'], '');

View file

@ -1,15 +0,0 @@
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}',
},
})

4
cypress.json Normal file
View file

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

View file

@ -1,10 +1,6 @@
describe('Choices - select multiple', () => {
beforeEach(() => {
cy.visit('/select-multiple', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
cy.visit('/select-multiple.html');
});
describe('scenarios', () => {
@ -34,7 +30,6 @@ describe('Choices - select multiple', () => {
beforeEach(() => {
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.wait(200) // Otherwise these tests are flaky
.type('{esc}');
});
@ -67,7 +62,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then(($choice) => {
.then($choice => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -77,15 +72,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[hidden]')
.should(($select) => {
.find('.choices__input.is-hidden')
.should($select => {
expect($select.val()).to.contain(selectedChoiceText);
});
});
@ -94,7 +89,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);
});
});
@ -119,7 +114,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');
});
@ -135,7 +130,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then(($choice) => {
.then($choice => {
removedChoiceText = $choice.text().trim();
})
.click();
@ -155,8 +150,8 @@ describe('Choices - select multiple', () => {
it('updates the value of the original input', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__input[hidden]')
.should(($select) => {
.find('.choices__input.is-hidden')
.should($select => {
const val = $select.val() || [];
expect(val).to.not.contain(removedChoiceText);
});
@ -176,7 +171,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');
});
});
@ -192,7 +187,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');
});
});
@ -207,7 +202,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');
});
@ -339,7 +334,7 @@ describe('Choices - select multiple', () => {
});
describe('on click', () => {
it('does not open choice dropdown', () => {
it('does not opens choice dropdown', () => {
cy.get('[data-test-hook=disabled-via-attr]')
.find('.choices')
.click()
@ -351,10 +346,10 @@ describe('Choices - select multiple', () => {
describe('selection limit', () => {
/*
{
maxItemCount: 5,
}
*/
{
maxItemCount: 5,
}
*/
const selectionLimit = 5;
beforeEach(() => {
@ -375,7 +370,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`,
@ -402,7 +397,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then(($choice) => {
.then($choice => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -412,7 +407,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`,
);
@ -423,7 +418,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`,
);
@ -465,7 +460,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);
});
});
@ -483,7 +478,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
.should($choice => {
expect($choice.text().trim()).to.contain(searchTerm);
});
});
@ -491,42 +486,20 @@ describe('Choices - select multiple', () => {
});
});
describe('placeholder via empty option value', () => {
describe('placeholder', () => {
/*
{
placeholder: true,
placeholderValue: 'I am a placeholder',
}
*/
describe('when no value has been inputted', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
cy.get('[data-test-hook=placeholder]')
.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', () => {
@ -542,7 +515,7 @@ describe('Choices - select multiple', () => {
});
describe('on click', () => {
it('does not open choice dropdown', () => {
it('does not opens choice dropdown', () => {
cy.get('[data-test-hook=remote-data]')
.find('.choices')
.click()
@ -575,7 +548,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;
});
@ -587,20 +560,17 @@ 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 = 1; index <= choicesCount; index++) {
cy.wait(100);
for (let index = 0; index < choicesCount; index++) {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.invoke('text')
.then((text) => {
expect(text.trim()).to.equal(`Choice ${index}`);
.should($choice => {
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
});
cy.get('[data-test-hook=scrolling-dropdown]')
@ -623,9 +593,8 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=scrolling-dropdown]')
.find('.choices__list--dropdown .choices__list .is-highlighted')
.invoke('text')
.then((text) => {
expect(text.trim()).to.equal(`Choice ${index}`);
.should($choice => {
expect($choice.text().trim()).to.equal(`Choice ${index}`);
});
cy.get('[data-test-hook=scrolling-dropdown]')
@ -643,7 +612,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();
});
});
@ -664,7 +633,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);
});
});
@ -695,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.equal(groupValue);
});
});
@ -735,7 +704,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
.should($choice => {
expect($choice.text().trim()).to.equal(city);
});
@ -747,73 +716,11 @@ describe('Choices - select multiple', () => {
});
});
describe('custom properties via HTML', () => {
beforeEach(() => {
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();
cy.get('[data-test-hook=non-string-values]')
.find('.choices')
.click();
});
it('displays expected amount of choices in dropdown', () => {
@ -829,7 +736,7 @@ describe('Choices - select multiple', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then(($choice) => {
.then($choice => {
$selectedChoice = $choice;
})
.click();
@ -837,7 +744,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());
});
});
@ -846,8 +753,8 @@ describe('Choices - select multiple', () => {
describe('within form', () => {
describe('selecting choice', () => {
describe('on enter key', () => {
it('selects choice', () => {
cy.get('[data-test-hook=within-form] form').then(($form) => {
it('does not submit 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');
@ -856,13 +763,13 @@ describe('Choices - select multiple', () => {
cy.get('[data-test-hook=within-form]')
.find('.choices__input--cloned')
.click()
.focus()
.type('{enter}');
cy.get('[data-test-hook=within-form]')
.find('.choices__list--multiple .choices__item')
.last()
.should(($item) => {
.should($item => {
expect($item).to.contain('Choice 1');
});
});
@ -877,7 +784,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,
);
@ -888,7 +795,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,
);
@ -897,8 +804,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[hidden]')
.should(($select) => {
.find('.choices__input.is-hidden')
.should($select => {
const val = $select.val() || [];
expect(val).to.contain(dynamicallySelectedChoiceValue);
});
@ -915,7 +822,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');
});
});
@ -929,83 +836,10 @@ 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,63 +1,48 @@
describe('Choices - select one', () => {
beforeEach(() => {
cy.visit('/select-one', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
cy.visit('/select-one.html');
});
describe('scenarios', () => {
describe('basic', () => {
describe('focusing on container', () => {
describe('pressing enter key', () => {
it('toggles the dropdown', () => {
cy.get('[data-test-hook=basic]')
.find('.choices')
.focus()
.type('{enter}');
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]')
.find('.choices')
.click();
});
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
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')
.focus()
.type('{enter}');
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}`);
});
});
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', () => {
@ -70,7 +55,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);
});
});
@ -86,18 +71,13 @@ 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', () => {
@ -109,7 +89,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');
});
});
@ -125,7 +105,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');
});
});
@ -140,7 +120,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');
});
@ -206,7 +186,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();
@ -228,8 +208,8 @@ describe('Choices - select one', () => {
it('updates the value of the original input', () => {
cy.get('[data-test-hook=remove-button]')
.find('.choices__input[hidden]')
.should(($select) => {
.find('.choices__input.is-hidden')
.should($select => {
const val = $select.val() || [];
expect(val).to.not.contain(removedChoiceText);
@ -248,7 +228,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();
@ -258,7 +238,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);
});
});
@ -305,7 +285,9 @@ 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')
@ -333,7 +315,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.last()
.then(($choice) => {
.then($choice => {
selectedChoiceText = $choice.text().trim();
})
.click();
@ -343,7 +325,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`,
);
@ -354,7 +336,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`,
);
@ -387,7 +369,9 @@ 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', () => {
@ -406,7 +390,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);
});
});
@ -438,7 +422,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);
});
});
@ -456,7 +440,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
.should($choice => {
expect($choice.text().trim()).to.contain(searchTerm);
});
});
@ -464,102 +448,6 @@ 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);
@ -570,16 +458,15 @@ 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...');
});
});
describe('on click', () => {
it('does not open choice dropdown', () => {
it('does not opens choice dropdown', () => {
cy.get('[data-test-hook=remote-data]')
.find('.choices')
.click()
@ -596,14 +483,10 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remote-data]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 51) // 50 choices + 1 placeholder choice
.should('have.length', 50)
.each(($choice, index) => {
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}`);
}
expect($choice.text().trim()).to.equal(`Label ${index + 1}`);
expect($choice.data('value')).to.equal(`Value ${index + 1}`);
});
});
});
@ -616,17 +499,19 @@ 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');
});
});
@ -635,7 +520,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}`);
});
@ -659,7 +544,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}`);
});
@ -678,7 +563,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();
});
});
@ -699,7 +584,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);
});
});
@ -730,7 +615,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);
});
});
@ -800,7 +685,9 @@ 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', () => {
@ -829,7 +716,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should(($choice) => {
.should($choice => {
expect($choice.text().trim()).to.equal(city);
});
@ -841,73 +728,11 @@ describe('Choices - select one', () => {
});
});
describe('custom properties via HTML', () => {
beforeEach(() => {
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();
cy.get('[data-test-hook=non-string-values]')
.find('.choices')
.click();
});
it('displays expected amount of choices in dropdown', () => {
@ -923,7 +748,7 @@ describe('Choices - select one', () => {
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.then(($choice) => {
.then($choice => {
$selectedChoice = $choice;
})
.click();
@ -931,7 +756,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());
});
});
@ -941,7 +766,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');
@ -954,12 +779,14 @@ 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');
});
});
@ -974,7 +801,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,
);
@ -984,15 +811,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[hidden]')
.should(($select) => {
.find('.choices__input.is-hidden')
.should($select => {
const val = $select.val() || [];
expect(val).to.contain(dynamicallySelectedChoiceValue);
});
@ -1001,7 +828,9 @@ 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', () => {
@ -1013,7 +842,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');
});
});
@ -1027,123 +856,10 @@ 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,10 +1,6 @@
describe('Choices - text element', () => {
beforeEach(() => {
cy.visit('/text', {
onBeforeLoad(win) {
cy.stub(win.console, 'warn').as('consoleWarn');
},
});
cy.visit('/text.html');
});
describe('scenarios', () => {
@ -21,7 +17,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);
});
});
@ -33,7 +29,7 @@ describe('Choices - text element', () => {
.type('{enter}');
cy.get('[data-test-hook=basic]')
.find('.choices__input[hidden]')
.find('.choices__input.is-hidden')
.should('have.value', textInput);
});
@ -46,7 +42,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}"`,
@ -78,7 +74,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`);
});
});
@ -94,7 +90,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);
});
});
@ -128,7 +124,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);
});
@ -141,7 +137,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);
});
});
@ -155,8 +151,8 @@ describe('Choices - text element', () => {
.click();
cy.get('[data-test-hook=remove-button]')
.find('.choices__input[hidden]')
.then(($input) => {
.find('.choices__input.is-hidden')
.then($input => {
expect($input.val()).to.not.contain(textInput);
});
});
@ -179,7 +175,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should(($items) => {
.should($items => {
expect($items.length).to.equal(1);
});
});
@ -189,7 +185,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',
@ -216,7 +212,7 @@ describe('Choices - text element', () => {
.find('.choices__list--multiple')
.first()
.children()
.should(($items) => {
.should($items => {
expect($items.length).to.equal(inputLimit);
});
});
@ -226,7 +222,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`,
@ -249,7 +245,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);
});
});
@ -265,7 +261,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',
@ -287,7 +283,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`);
});
});
@ -296,7 +292,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);
});
@ -323,21 +319,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');
});
});
@ -359,53 +355,11 @@ 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');
@ -420,7 +374,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,17 +0,0 @@
{
"compilerOptions": {
"checkJs": true,
"target": "es2020",
"lib": ["esnext", "dom"],
"types": ["cypress"],
"strict": true,
"moduleResolution": "node",
/* Additional Checks */
"noImplicitAny": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"strictNullChecks": false
}
}

View file

@ -1,14 +0,0 @@
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',
};

34745
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,33 +1,32 @@
{
"name": "choices.js",
"version": "10.2.0",
"version": "6.0.3",
"description": "A vanilla JS customisable text input/select box plugin",
"main": "./public/assets/scripts/choices.js",
"types": "./public/types/src/index.d.ts",
"main": "./public/assets/scripts/choices.min.js",
"types": "./types/index.d.ts",
"scripts": {
"start": "run-p js:watch css:watch",
"build": "run-p js:build css:build",
"lint": "run-p lint:js lint:scss",
"lint:js": "eslint src/scripts/**/*.ts",
"lint:scss": "stylelint src/**/*.scss",
"build": "npm run js:build && npm run css:build",
"lint": "eslint $(find src -name '*.js')",
"coverage": "nyc npm run test:unit",
"bundlesize": "bundlesize",
"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": "cross-env TS_NODE_TRANSPILE_ONLY=true NODE_ENV=test mocha",
"cypress:run": "$(npm bin)/cypress run",
"cypress:open": "$(npm bin)/cypress open",
"test": "npm run test:unit && npm run test:e2e",
"test:unit": "mocha --require ./config/jsdom.js --require @babel/register $(find src -name '*.test.js') --exit",
"test:unit:watch": "npm run test:unit -- --watch --inspect=5556",
"test:unit:coverage": "NODE_ENV=test nyc --reporter=lcov --reporter=text --reporter=text-summary mocha",
"test:e2e": "run-p --race start cypress:run",
"js:watch": "cross-env NODE_ENV=development node server.js",
"js:watch": "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": "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",
"css:build": "run-p 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:prefix": "postcss --use autoprefixer -b 'last 2 versions' public/assets/styles/*.css -d public/assets/styles",
"css:min": "csso public/assets/styles/base.css public/assets/styles/base.min.css && csso public/assets/styles/choices.css public/assets/styles/choices.min.css",
"bump-cache": "node bump-cache.js --current $npm_package_version",
"deploy": "git subtree push --prefix public origin gh-pages",
"prepublishOnly": "npm run build"
"postversion": "npm run js:build && npm run bump-cache",
"prepush": "run-p lint test:unit && npm run bundlesize"
},
"repository": {
"type": "git",
@ -38,9 +37,7 @@
"files": [
"public/assets/scripts",
"public/assets/styles",
"public/types",
"src",
"!src/**/*.test.js",
"types"
],
"bugs": {
@ -56,61 +53,54 @@
"js"
],
"devDependencies": {
"@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",
"@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.3.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/plugin-transform-spread": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"@babel/register": "^7.0.0",
"autoprefixer": "^6.3.3",
"babel-eslint": "^9.0.0",
"babel-loader": "^8.0.5",
"bundlesize": "^0.17.1",
"chai": "^4.2.0",
"csso": "^1.8.2",
"cypress": "^3.1.5",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^15.1.0",
"eslint-config-prettier": "^2.10.0",
"eslint-loader": "^2.1.2",
"eslint-plugin-cypress": "^2.2.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-prettier": "^2.7.0",
"eslint-plugin-react": "^7.12.4",
"express": "^4.16.4",
"husky": "^0.14.3",
"jsdom": "^11.12.0",
"mocha": "^5.2.0",
"node-sass": "^4.11.0",
"nodemon": "^1.18.10",
"npm-run-all": "^4.1.5",
"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"
"nyc": "^11.9.0",
"opn": "^5.4.0",
"postcss-cli": "^2.5.1",
"prettier": "^1.16.4",
"sinon": "^2.4.0",
"unminified-webpack-plugin": "^2.0.0",
"webpack": "^4.29.3",
"webpack-cli": "^3.2.3",
"webpack-dev-middleware": "^3.5.2",
"webpack-hot-middleware": "^2.24.3",
"whatwg-fetch": "^1.0.0",
"wrapper-webpack-plugin": "^2.1.0"
},
"dependencies": {
"deepmerge": "^4.2.2",
"fuse.js": "^6.6.2",
"redux": "^4.2.0"
"classnames": "^2.2.6",
"custom-event-polyfill": "^0.3.0",
"deepmerge": "^2.2.1",
"fuse.js": "3.4.2",
"redux": "^3.3.1"
},
"npmName": "choices.js",
"npmFileMap": [
@ -118,7 +108,6 @@
"files": [
"public/assets/scripts/*",
"public/assets/styles/*",
"public/types/*",
"src/icons/*"
]
}
@ -138,7 +127,7 @@
},
{
"path": "public/assets/styles/choices.min.css",
"maxSize": "2.5 kB"
"maxSize": "2 kB"
}
]
}

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/images/mstile-150x150.png"/>
<TileColor>#ffffff</TileColor>
</tile>
</msapplication>
</browserconfig>
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/assets/images/mstile-150x150.png"/>
<TileColor>#ffffff</TileColor>
</tile>
</msapplication>
</browserconfig>

View file

@ -1,27 +0,0 @@
// 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

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

View file

@ -1,14 +1,14 @@
/* =============================================
/*=============================================
= Generic styling =
============================================= */
=============================================*/
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
*,
*::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: #fff;
color: #FFFFFF;
background-color: #333;
overflow-x: hidden;
}
@ -39,7 +39,6 @@ label {
p {
margin-top: 0;
margin-bottom: 8px;
}
hr {
@ -65,7 +64,7 @@ h6 {
a,
a:visited,
a:focus {
color: #fff;
color: #FFFFFF;
text-decoration: none;
font-weight: 600;
}
@ -79,7 +78,8 @@ a:focus {
border-radius: 2.5px;
font-size: 14px;
-webkit-appearance: none;
appearance: none;
-moz-appearance: none;
appearance: none;
margin-bottom: 24px;
}
@ -113,6 +113,10 @@ h6,
font-size: 14px;
}
p {
margin-bottom: 8px;
}
label + p {
margin-top: -4px;
}
@ -123,6 +127,7 @@ label + p {
max-width: 40em;
padding: 48px;
}
@media (max-width: 620px) {
.container {
padding: 0;
@ -130,10 +135,11 @@ label + p {
}
.section {
background-color: #fff;
background-color: #FFFFFF;
padding: 24px;
color: #333;
}
.section a,
.section a:visited,
.section a:focus {
@ -145,7 +151,7 @@ label + p {
margin-bottom: 12px;
}
.logo-img {
.logo__img {
width: 100%;
height: auto;
display: inline-block;
@ -174,8 +180,12 @@ label + p {
text-align: center;
}
.is-hidden {
display: none;
}
[data-test-hook] {
margin-bottom: 24px;
}
/* ===== End of Section comment block ====== */
/*===== End of Section comment block ======*/

View file

@ -1 +0,0 @@
{"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}[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;-moz-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}

View file

@ -1,51 +1,50 @@
/* ===============================
/*===============================
= Choices =
=============================== */
===============================*/
.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;
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 #ddd;
background-color: #fff;
border-bottom: 1px solid #DDDDDD;
background-color: #FFFFFF;
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;
@ -56,23 +55,23 @@
height: 20px;
width: 20px;
border-radius: 10em;
opacity: 0.25;
opacity: .5;
}
.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: 0 0 0 2px #00bcd4;
.choices[data-type*="select-one"] .choices__button:focus {
box-shadow: 0px 0px 0px 2px #00BCD4;
}
.choices[data-type*=select-one] .choices__item[data-value=""] .choices__button {
display: none;
}
.choices[data-type*=select-one]::after {
.choices[data-type*="select-one"]:after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: #333 transparent transparent transparent;
border-color: #333333 transparent transparent transparent;
border-width: 5px;
position: absolute;
right: 11.5px;
@ -80,27 +79,31 @@
margin-top: -2.5px;
pointer-events: none;
}
.choices[data-type*=select-one].is-open::after {
border-color: transparent transparent #333 transparent;
.choices[data-type*="select-one"].is-open:after {
border-color: transparent transparent #333333 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;
@ -109,16 +112,17 @@
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: 0.75;
opacity: .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;
}
@ -128,18 +132,22 @@
width: 100%;
background-color: #f9f9f9;
padding: 7.5px 7.5px 3.75px;
border: 1px solid #ddd;
border: 1px solid #DDDDDD;
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;
}
@ -149,15 +157,18 @@
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%;
}
@ -165,6 +176,7 @@
.choices__list--multiple {
display: inline;
}
.choices__list--multiple .choices__item {
display: inline-block;
vertical-align: middle;
@ -174,76 +186,85 @@
font-weight: 500;
margin-right: 3.75px;
margin-bottom: 3.75px;
background-color: #00bcd4;
background-color: #00BCD4;
border: 1px solid #00a5bb;
color: #fff;
color: #FFFFFF;
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, .choices__list[aria-expanded] {
visibility: hidden;
.choices__list--dropdown {
display: none;
z-index: 1;
position: absolute;
width: 100%;
background-color: #fff;
border: 1px solid #ddd;
background-color: #FFFFFF;
border: 1px solid #DDDDDD;
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;
}
.is-active.choices__list--dropdown, .is-active.choices__list[aria-expanded] {
visibility: visible;
.choices__list--dropdown.is-active {
display: block;
}
.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {
.is-open .choices__list--dropdown {
border-color: #b7b7b7;
}
.is-flipped .choices__list--dropdown, .is-flipped .choices__list[aria-expanded] {
.is-flipped .choices__list--dropdown {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: -1px;
border-radius: 0.25rem 0.25rem 0 0;
border-radius: .25rem .25rem 0 0;
}
.choices__list--dropdown .choices__list, .choices__list[aria-expanded] .choices__list {
.choices__list--dropdown .choices__list {
position: relative;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
will-change: scroll-position;
}
.choices__list--dropdown .choices__item, .choices__list[aria-expanded] .choices__item {
.choices__list--dropdown .choices__item {
position: relative;
padding: 10px;
font-size: 14px;
}
[dir=rtl] .choices__list--dropdown .choices__item, [dir=rtl] .choices__list[aria-expanded] .choices__item {
[dir="rtl"] .choices__list--dropdown .choices__item {
text-align: right;
}
@media (min-width: 640px) {
.choices__list--dropdown .choices__item--selectable, .choices__list[aria-expanded] .choices__item--selectable {
.choices__list--dropdown .choices__item--selectable {
padding-right: 100px;
}
.choices__list--dropdown .choices__item--selectable::after, .choices__list[aria-expanded] .choices__item--selectable::after {
.choices__list--dropdown .choices__item--selectable:after {
content: attr(data-select-text);
font-size: 12px;
opacity: 0;
@ -252,21 +273,23 @@
top: 50%;
transform: translateY(-50%);
}
[dir=rtl] .choices__list--dropdown .choices__item--selectable, [dir=rtl] .choices__list[aria-expanded] .choices__item--selectable {
[dir="rtl"] .choices__list--dropdown .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[aria-expanded] .choices__item--selectable::after {
[dir="rtl"] .choices__list--dropdown .choices__item--selectable:after {
right: auto;
left: 10px;
}
}
.choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
.choices__list--dropdown .choices__item--selectable.is-highlighted {
background-color: #f2f2f2;
}
.choices__list--dropdown .choices__item--selectable.is-highlighted::after, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted::after {
opacity: 0.5;
.choices__list--dropdown .choices__item--selectable.is-highlighted:after {
opacity: .5;
}
.choices__item {
@ -279,9 +302,8 @@
.choices__item--disabled {
cursor: not-allowed;
-webkit-user-select: none;
user-select: none;
opacity: 0.5;
user-select: none;
opacity: .5;
}
.choices__heading {
@ -295,13 +317,14 @@
.choices__button {
text-indent: -9999px;
-webkit-appearance: none;
appearance: none;
appearance: none;
border: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.choices__button:focus {
outline: none;
}
@ -317,24 +340,24 @@
max-width: 100%;
padding: 4px 0 4px 2px;
}
.choices__input:focus {
outline: 0;
}
.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 {
[dir="rtl"] .choices__input {
padding-right: 2px;
padding-left: 0;
}
.choices__placeholder {
opacity: 0.5;
opacity: .5;
}
/* ===== End of Choices ====== */
.choices__input.is-hidden,
.choices[data-type*="select-one"] .choices__input.is-hidden,
.choices[data-type*="select-multiple"] .choices__input.is-hidden {
display: none;
}
/*===== End of Choices ======*/

View file

@ -1 +0,0 @@
{"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

@ -0,0 +1,340 @@
<!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=3.0.2">
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../assets/styles/choices.min.css?version=3.0.2">
<script src="../assets/scripts/choices.min.js?version=2.8.8"></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

@ -1,628 +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" />
<!-- 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>

352
public/test/select-one.html Normal file
View file

@ -0,0 +1,352 @@
<!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=3.0.2">
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../assets/styles/choices.min.css?version=3.0.2">
<script src="../assets/scripts/choices.min.js?version=2.8.8"></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

@ -1,682 +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" />
<!-- 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>

154
public/test/text.html Normal file
View file

@ -0,0 +1,154 @@
<!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=3.0.2">
<!-- End ignore these -->
<!-- Choices includes -->
<link rel="stylesheet" href="../assets/styles/choices.min.css?version=3.0.2">
<script src="../assets/scripts/choices.min.js?version=2.8.8"></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>

View file

@ -1,247 +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" />
<!-- 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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +0,0 @@
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

@ -1 +0,0 @@
{"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

@ -1,44 +0,0 @@
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

@ -1 +0,0 @@
{"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"}

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