diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b43639c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,64 @@
+## GITATTRIBUTES FOR WEB PROJECTS
+#
+# These settings are for any web project.
+#
+# Details per file setting:
+# text These files should be normalized (i.e. convert CRLF to LF).
+# binary These files are binary and should be left untouched.
+#
+# Note that binary is a macro for -text -diff.
+######################################################################
+
+# Auto detect
+## Handle line endings automatically for files detected as
+## text and leave all files detected as binary untouched.
+## This will handle all files NOT defined below.
+* text eol=lf
+
+# Source code
+*.css text eol=lf
+*.html text diff=html eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.scss text diff=css eol=lf
+*.ts text eol=lf
+
+# Documentation
+*.md text eol=lf
+*.txt text eol=lf
+AUTHORS text eol=lf
+CHANGELOG text eol=lf
+CHANGES text eol=lf
+CONTRIBUTING text eol=lf
+COPYING text eol=lf
+copyright text eol=lf
+*COPYRIGHT* text eol=lf
+INSTALL text eol=lf
+license text eol=lf
+LICENSE text eol=lf
+NEWS text eol=lf
+readme text eol=lf
+*README* text eol=lf
+TODO text eol=lf
+
+# Linters
+.eslintrc text eol=lf
+.stylelintrc text eol=lf
+
+# Configs
+.babelrc text eol=lf
+.browserslistrc text eol=lf
+.editorconfig text eol=lf
+.env text eol=lf
+.gitattributes text eol=lf
+.gitconfig text eol=lf
+package-lock.json text -diff eol=lf
+*.npmignore text eol=lf
+*.yaml text eol=lf
+*.yml text eol=lf
+browserslist text eol=lf
+
+# Graphics
+# SVG treated as an asset (binary) by default.
+*.svg text eol=lf
+*.png binary
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index b8b3e3a..70aaaa9 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,12 +4,6 @@
-## How Has This Been Tested?
-
-
-
-
-
## Screenshots (if appropriate)
## Types of changes
@@ -17,6 +11,7 @@
- [ ] 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)
diff --git a/.github/actions-scripts/__snapshots__/chrome-win32.png b/.github/actions-scripts/__snapshots__/chrome-win32.png
new file mode 100644
index 0000000..b2ed9f1
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/chrome-win32.png differ
diff --git a/.github/actions-scripts/__snapshots__/firefox-darwin.png b/.github/actions-scripts/__snapshots__/firefox-darwin.png
new file mode 100644
index 0000000..ca328d1
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/firefox-darwin.png differ
diff --git a/.github/actions-scripts/__snapshots__/firefox-win32.png b/.github/actions-scripts/__snapshots__/firefox-win32.png
new file mode 100644
index 0000000..8bba2e3
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/firefox-win32.png differ
diff --git a/.github/actions-scripts/__snapshots__/ie-win32.png b/.github/actions-scripts/__snapshots__/ie-win32.png
new file mode 100644
index 0000000..7b74d98
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/ie-win32.png differ
diff --git a/.github/actions-scripts/__snapshots__/puppeteer-darwin.png b/.github/actions-scripts/__snapshots__/puppeteer-darwin.png
new file mode 100644
index 0000000..b9ab3bc
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/puppeteer-darwin.png differ
diff --git a/.github/actions-scripts/__snapshots__/safari-darwin.png b/.github/actions-scripts/__snapshots__/safari-darwin.png
new file mode 100644
index 0000000..722b8d4
Binary files /dev/null and b/.github/actions-scripts/__snapshots__/safari-darwin.png differ
diff --git a/.github/actions-scripts/puppeteer.js b/.github/actions-scripts/puppeteer.js
new file mode 100644
index 0000000..636dc3a
--- /dev/null
+++ b/.github/actions-scripts/puppeteer.js
@@ -0,0 +1,88 @@
+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();
+ let error;
+ let pixelDifference;
+
+ 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.click('label[for="choices-single-custom-templates"]');
+ await page.keyboard.press('ArrowDown');
+ await page.keyboard.press('ArrowDown');
+
+ const snapshotName = `puppeteer-${process.platform}.png`;
+ const artifactsPath = 'screenshot';
+ 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;
+ const diff = new PNG({ width, height });
+ pixelDifference = pixelmatch(
+ screenshot.data,
+ snapshot.data,
+ diff.data,
+ width,
+ height,
+ {
+ threshold: 0.6,
+ },
+ );
+ writeFileSync(path.join(artifactsPath, 'diff.png'), PNG.sync.write(diff));
+ } catch (err) {
+ console.error(err);
+ error = err;
+ } finally {
+ 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);
diff --git a/.github/actions-scripts/selenium.js b/.github/actions-scripts/selenium.js
new file mode 100644
index 0000000..1b69bac
--- /dev/null
+++ b/.github/actions-scripts/selenium.js
@@ -0,0 +1,155 @@
+const path = require('path');
+const { readFileSync, writeFileSync, mkdirSync } = require('fs');
+const { once } = require('events');
+
+const pixelmatch = require('pixelmatch');
+const { PNG } = require('pngjs');
+const {
+ Builder,
+ By,
+ Key,
+ until,
+ Capabilities,
+ logging,
+} = require('selenium-webdriver');
+
+const server = require('../../server');
+
+async function test() {
+ let pixelDifference;
+ let error;
+
+ let capabilities;
+ switch (process.env.BROWSER) {
+ case 'ie':
+ capabilities = Capabilities.ie();
+ capabilities.set('ignoreProtectedModeSettings', true);
+ capabilities.set('ignoreZoomSetting', true);
+ capabilities.set('ie.options', {
+ enableFullPageScreenshot: true,
+ ensureCleanSession: true,
+ });
+ break;
+
+ case 'edge':
+ capabilities = Capabilities.edge();
+ break;
+
+ case 'safari':
+ capabilities = Capabilities.safari();
+ capabilities.set('safari.options', { technologyPreview: false });
+ break;
+
+ case 'firefox': {
+ capabilities = Capabilities.firefox().setLoggingPrefs({ browser: 'ALL' });
+ break;
+ }
+ case 'chrome': {
+ capabilities = Capabilities.chrome().setLoggingPrefs({ browser: 'ALL' });
+ capabilities.set('chromeOptions', {
+ args: ['--headless', '--no-sandbox', '--disable-gpu'],
+ });
+ break;
+ }
+ }
+
+ let driver = await new Builder().withCapabilities(capabilities).build();
+
+ if (!server.listening) await once(server, 'listening');
+
+ try {
+ await driver.get(`http://127.0.0.1:${server.address().port}`);
+
+ // wait for last choice to init
+ await driver.wait(
+ until.elementLocated(By.css('#reset-multiple ~ .choices__list')),
+ 10000,
+ 'waiting for all Choices instances to init',
+ );
+
+ // Resize window
+ await driver
+ .manage()
+ .window()
+ .maximize();
+ await driver
+ .manage()
+ .window()
+ // magic numbers here to make sure all demo page are fit inside
+ .setRect({ x: 0, y: 0, width: 630, height: 4000 });
+
+ // and click on press space on it, so it should open choices
+ await driver
+ .findElement(By.css('#reset-multiple ~ .choices__list button'))
+ .sendKeys(Key.SPACE);
+ await driver.sleep(1000);
+
+ // take screenshot
+ const image = await driver.takeScreenshot();
+ const imageBuffer = Buffer.from(image, 'base64');
+
+ const snapshotName = `${process.env.BROWSER}-${process.platform}.png`;
+ const artifactsPath = 'screenshot';
+ mkdirSync(artifactsPath, { recursive: true });
+
+ writeFileSync(path.join(artifactsPath, snapshotName), imageBuffer);
+
+ // compare with snapshot
+ const screenshot = PNG.sync.read(imageBuffer);
+ const snapshot = PNG.sync.read(
+ readFileSync(path.resolve(__dirname, `./__snapshots__/${snapshotName}`)),
+ );
+ const { width, height } = screenshot;
+ const diff = new PNG({ width, height });
+ pixelDifference = pixelmatch(
+ screenshot.data,
+ snapshot.data,
+ diff.data,
+ width,
+ height,
+ {
+ threshold: 1,
+ },
+ );
+ writeFileSync(path.join(artifactsPath, 'diff.png'), PNG.sync.write(diff));
+
+ // getting console logs
+ // ensure no errors in console (only supported in Chrome currently)
+ if (process.env.BROWSER === 'chrome') {
+ const entries = await driver
+ .manage()
+ .logs()
+ .get(logging.Type.BROWSER);
+ if (
+ Array.isArray(entries) &&
+ entries.some(entry => entry.level.name_ === 'SEVERE')
+ )
+ throw new Error(JSON.stringify(entries));
+ }
+ } catch (err) {
+ console.error(err);
+ error = err;
+ } finally {
+ await Promise.all([
+ driver.quit(),
+ new Promise(resolve => server.close(resolve)),
+ ]);
+ }
+ if (pixelDifference > 200) {
+ console.error(
+ `Snapshot is different from screenshot by ${pixelDifference} pixels`,
+ );
+ process.exit(1);
+ }
+ if (error) process.exit(1);
+}
+
+process.on('unhandledRejection', err => {
+ console.error(err);
+ process.exit(1);
+});
+process.once('uncaughtException', err => {
+ console.error(err);
+ process.exit(1);
+});
+setImmediate(test);
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
index 5b74d19..0d888cb 100644
--- a/.github/release-drafter.yml
+++ b/.github/release-drafter.yml
@@ -1,6 +1,9 @@
name-template: 'Draft (next release)'
tag-template: 'v$NEXT_PATCH_VERSION'
sort-direction: descending
+exclude-labels:
+ - 'skip-changelog'
+ - 'release'
categories:
- title: '🚨 Breaking changes'
labels:
diff --git a/.github/workflows/browsers.yml b/.github/workflows/browsers.yml
new file mode 100644
index 0000000..dc58f31
--- /dev/null
+++ b/.github/workflows/browsers.yml
@@ -0,0 +1,133 @@
+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: [ie, firefox, safari]
+ exclude:
+ # On Windows, run tests with only IE and Edge
+ - os: windows-latest
+ browser: safari
+ # On macOS, run tests with only on safari
+ - os: macOS-latest
+ browser: ie
+ - 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@v1
+ with:
+ fetch-depth: 1
+ - uses: actions/setup-node@v1
+ with:
+ node-version: '12.x'
+
+ - name: Cache node modules
+ uses: actions/cache@v1
+ 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 cask install firefox
+ brew install geckodriver
+ if: matrix.browser == 'firefox' && matrix.os == 'macOS-latest'
+
+ - run: echo "::add-path::$env:GeckoWebDriver"
+ if: matrix.browser == 'firefox' && matrix.os == 'windows-latest'
+
+ - run: echo "::add-path::$env:IEWebDriver"
+ if: matrix.browser == 'ie' && matrix.os == 'windows-latest'
+
+ - run: echo "::add-path::$env:ChromeWebDriver"
+ 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@master
+ if: failure()
+ with:
+ name: screenshot-${{ matrix.browser }}-${{ matrix.os }}
+ path: screenshot
+
+ puppeteer:
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v1
+ with:
+ fetch-depth: 1
+ - name: Cache node modules
+ uses: actions/cache@v1
+ 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@master
+ if: failure()
+ with:
+ name: screenshot-puppeteer-darwin
+ path: screenshot
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 0791084..3b89840 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -15,8 +15,8 @@ jobs:
- uses: actions/setup-node@v1
with:
node-version: 10
- # run all tests
- - run: |
+ - name: Build and run all tests
+ run: |
npm ci
npm run build
npx bundlesize
@@ -32,6 +32,15 @@ jobs:
BUNDLESIZE_GITHUB_TOKEN: ${{secrets.BUNDLESIZE_GITHUB_TOKEN}}
FORCE_COLOR: 2
HUSKY_SKIP_INSTALL: true
+ - 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)
diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml
index 0d45e76..bc6b1e5 100644
--- a/.github/workflows/deployment.yml
+++ b/.github/workflows/deployment.yml
@@ -14,7 +14,6 @@ jobs:
- uses: actions/setup-node@v1
with:
node-version: 10
- # run all tests
- run: |
npm ci
npm run build
@@ -45,7 +44,6 @@ jobs:
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
publish-npm:
- needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
@@ -64,7 +62,6 @@ jobs:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
deploy-gh-pages:
- needs: publish-npm
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 16132f3..0d7d28d 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -10,11 +10,15 @@ on:
- 'webpack.config.*'
- 'public/test/**'
- 'cypress/**'
- - '.github/workflows/cypress.yml'
+ - '.github/workflows/e2e-tests.yml'
jobs:
test-e2e:
runs-on: ubuntu-latest
+ env:
+ CI: true
+ TERM: xterm-256color
+
steps:
- uses: actions/checkout@v1
with:
@@ -22,18 +26,42 @@ jobs:
- uses: actions/setup-node@v1
with:
- node-version: 10
+ node-version: 12.x
+
+ - name: Cache node modules
+ uses: actions/cache@v1
+ 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@v1
+ 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 CI
- run: npx run-p --race start cypress:ci
+ - name: run Cypress (with or without recording)
+ # if we have ran out of free Cypress recordings, run Cypress with recording switched off
+ run: npx run-p --race start cypress:ci || npx run-p --race start cypress:run
env:
- CI: true
- TERM: xterm-256color
NODE_ENV: production # prevent watching
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
DEBUG: commit-info,cypress:server:record
diff --git a/.github/workflows/release-management.yml b/.github/workflows/release-drafter.yml
similarity index 89%
rename from .github/workflows/release-management.yml
rename to .github/workflows/release-drafter.yml
index f264373..e20d2ac 100644
--- a/.github/workflows/release-management.yml
+++ b/.github/workflows/release-drafter.yml
@@ -1,4 +1,4 @@
-name: Release management
+name: Release drafter
on:
push:
diff --git a/.prettierrc.json b/.prettierrc.json
index 7a32250..ab9f978 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1,6 +1,7 @@
{
"singleQuote": true,
"trailingComma": "all",
+ "endOfLine": "lf",
"overrides": [
{
"files": ["*.svg"],
@@ -8,6 +9,12 @@
"parser": "html",
"htmlWhitespaceSensitivity": "ignore"
}
+ },
+ {
+ "files": ["public/*.html"],
+ "options": {
+ "trailingComma": "es5"
+ }
}
]
}
diff --git a/README.md b/README.md
index 3bce930..f573282 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Choices.js [![Actions Status](https://github.com/jshjohnson/Choices/workflows/Unit%20Tests/badge.svg)](https://github.com/jshjohnson/Choices/actions) [![npm](https://img.shields.io/npm/v/choices.js.svg)](https://www.npmjs.com/package/choices.js) [![codebeat badge](https://codebeat.co/badges/55120150-5866-42d8-8010-6aaaff5d3fa1)](https://codebeat.co/projects/github-com-jshjohnson-choices-master)
+# Choices.js [![Actions Status](https://github.com/jshjohnson/Choices/workflows/Build%20and%20test/badge.svg)](https://github.com/jshjohnson/Choices/actions) [![Actions Status](https://github.com/jshjohnson/Choices/workflows/Bundle%20size%20checks/badge.svg)](https://github.com/jshjohnson/Choices/actions) [![npm](https://img.shields.io/npm/v/choices.js.svg)](https://www.npmjs.com/package/choices.js)
A vanilla, lightweight (~19kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.
@@ -105,7 +105,7 @@ Or include Choices directly:
resetScrollPosition: true,
shouldSort: true,
shouldSortItems: false,
- sortFn: () => {...},
+ sorter: () => {...},
placeholder: true,
placeholderValue: null,
searchPlaceholderValue: null,
@@ -122,8 +122,8 @@ Or include Choices directly:
maxItemText: (maxItemCount) => {
return `Only ${maxItemCount} values can be added`;
},
- itemComparer: (choice, item) => {
- return choice === item;
+ valueComparer: (value1, value2) => {
+ return value1 === value2;
},
classNames: {
containerOuter: 'choices',
@@ -147,6 +147,7 @@ Or include Choices directly:
openState: 'is-open',
disabledState: 'is-disabled',
highlightedState: 'is-highlighted',
+ selectedState: 'is-selected',
flippedState: 'is-flipped',
loadingState: 'is-loading',
noResults: 'has-no-results',
@@ -408,7 +409,7 @@ new Choices(element, {
**Usage:** Whether items should be sorted. If false, items will appear in the order they were selected.
-### sortFn
+### sorter
**Type:** `Function` **Default:** sortByAlpha
@@ -421,7 +422,7 @@ new Choices(element, {
```js
// Sorting via length of label from largest to smallest
const example = new Choices(element, {
- sortFn: function(a, b) {
+ sorter: function(a, b) {
return b.label.length - a.label.length;
},
};
@@ -431,11 +432,11 @@ const example = new Choices(element, {
**Type:** `Boolean` **Default:** `true`
-**Input types affected:** `text`, `select-multiple`
+**Input types affected:** `text`
**Usage:** Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value.
-**Note:** For single select boxes, the recommended way of adding a placeholder is as follows:
+**Note:** For select boxes, the recommended way of adding a placeholder is as follows:
```html
Cities
-