Use express for development + folder restructuring

This commit is contained in:
Josh Johnson 2018-05-27 11:57:21 +01:00
parent 9f8dfb19ec
commit 257a038262
63 changed files with 510 additions and 9643 deletions

View File

@ -1,6 +1,6 @@
language: node_js
node_js:
- "6"
- "8"
before_install:
- '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@1.4.28'
- npm install -g npm@latest

View File

@ -36,11 +36,11 @@ Or include Choices directly:
```html
<!-- Include base CSS (optional) -->
<link rel="stylesheet" href="assets/styles/css/base.min.css">
<link rel="stylesheet" href="public/styles/base.min.css">
<!-- Include Choices CSS -->
<link rel="stylesheet" href="assets/styles/css/choices.min.css">
<link rel="stylesheet" href="public/styles/choices.min.css">
<!-- Include Choices JavaScript -->
<script src="/assets/scripts/dist/choices.min.js"></script>
<script src="/public/scripts/choices.min.js"></script>
```
## Setup

View File

@ -3,8 +3,8 @@
"version": "3.0.2",
"description": "A vanilla JS customisable text input/select box plugin",
"main": [
"./assets/scripts/dist/choices.js",
"./assets/styles/css/choices.css"
"./public/assets/scripts/choices.min.js",
"./public/assets/styles/choices.min.css"
],
"authors": [
"Josh Johnson"
@ -16,6 +16,7 @@
"node_modules",
"bower_components",
"test",
"cypress",
"tests"
],
"keywords": [

View File

@ -0,0 +1,12 @@
describe('Choices (text input)', () => {
context('Test', () => {
beforeEach(() => {
cy.visit('http://localhost:3001');
});
it('cy.screenshot() - take a screenshot', () => {
// https://on.cypress.io/screenshot
cy.screenshot('my-image');
});
});
});

View File

@ -1,81 +0,0 @@
//
// **** Kitchen Sink Tests ****
//
// This app was developed to demonstrate
// how to write tests in Cypress utilizing
// all of the available commands
//
// Feel free to modify this spec in your
// own application as a jumping off point
// Please read our "Introduction to Cypress"
// https://on.cypress.io/introduction-to-cypress
describe('Choices', () => {
context('Misc', () => {
beforeEach(() => {
cy.visit('http://localhost:3000');
});
it('.end() - end the command chain', () => {
// cy.end is useful when you want to end a chain of commands
// and force Cypress to re-query from the root element
// https://on.cypress.io/end
cy.get('.misc-table').within(() => {
// ends the current chain and yields null
cy.contains('Cheryl').click().end();
// queries the entire table again
cy.contains('Charles').click();
});
});
it('cy.exec() - execute a system command', () => {
// cy.exec allows you to execute a system command.
// so you can take actions necessary for your test,
// but outside the scope of Cypress.
// https://on.cypress.io/exec
cy.exec('echo Jane Lane')
.its('stdout').should('contain', 'Jane Lane');
// we can use Cypress.platform string to
// select appropriate command
// https://on.cypress/io/platform
cy.log(`Platform ${Cypress.platform} architecture ${Cypress.arch}`);
if (Cypress.platform === 'win32') {
cy.exec('print cypress.json')
.its('stderr').should('be.empty');
} else {
cy.exec('cat cypress.json')
.its('stderr').should('be.empty');
cy.exec('pwd')
.its('code').should('eq', 0);
}
});
it('cy.focused() - get the DOM element that has focus', () => {
// https://on.cypress.io/focused
cy.get('.misc-form').find('#name').click();
cy.focused().should('have.id', 'name');
cy.get('.misc-form').find('#description').click();
cy.focused().should('have.id', 'description');
});
it('cy.screenshot() - take a screenshot', () => {
// https://on.cypress.io/screenshot
cy.screenshot('my-image');
});
it('cy.wrap() - wrap an object', () => {
// https://on.cypress.io/wrap
cy.wrap({ foo: 'bar' })
.should('have.property', 'foo')
.and('include', 'bar');
});
});
});

View File

@ -1,14 +0,0 @@
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const config = require('./webpack.config.dev');
const opn = require('opn');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
historyApiFallback: true,
quiet: true, // lets WebpackDashboard do its thing
}).listen(3001, 'localhost', (err) => {
if (err) console.log(err);
opn('http://localhost:3001');
console.log('Listening at localhost:3001');
});

View File

@ -1,27 +1,27 @@
{
"name": "choices.js",
"version": "3.0.2",
"version": "4.0.0",
"description": "A vanilla JS customisable text input/select box plugin",
"main": "./src/scripts/dist/choices.min.js",
"main": "./public/assets/scripts/choices.min.js",
"types": "./types/index.d.ts",
"scripts": {
"start": "node devServer.js",
"start": "npm run clear && NODE_ENV=development node server.js",
"build": "npm run clear && npm run js:build && npm run css:build",
"lint": "eslint assets/**/*.js",
"coverage": "nyc npm run test",
"test": "mocha --require ./config/test.js --compilers js:babel-core/register \"./src/**/**/**/**/*.test.js\"",
"test:watch": "npm run test -- --watch --inspect=5556",
"test:cypress": "node server.js && cypress open",
"coverage": "nyc npm run test",
"test:cypress": "npm run build && concurrently \"NODE_ENV=production node server.js\" \"cypress open\"",
"css:watch": "nodemon -e scss -x \"npm run css:build\"",
"css:build": "npm run css:sass -s && npm run css:prefix -s && npm run css:min -s",
"css:sass": "node-sass --output-style expanded --include-path scss src/styles/scss/base.scss public/assets/styles/base.css && node-sass --output-style expanded --include-path scss src/styles/scss/choices.scss public/assets/styles/choices.css",
"css:sass": "node-sass --output-style expanded --include-path scss src/styles/scss/*.scss public/assets/styles/base.css && node-sass --output-style expanded --include-path scss src/styles/scss/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",
"js:build": "concurrently --prefix-colors yellow,green \"webpack --env.minimize --config webpack.config.prod.js\" \"webpack --config webpack.config.prod.js\"",
"build": "rm -rf public/assets/scripts && npm run js:build && npm run css:build",
"clear": "rm -rf public/assets/scripts",
"version": "node version.js --current $npm_package_version --new $npm_config_newVersion",
"postversion": "npm run js:build",
"prepush": "npm run lint && npm run test",
"dev": "dev"
"prepush": "npm run lint && npm run test"
},
"repository": {
"type": "git",
@ -65,8 +65,8 @@
"postcss-cli": "^2.5.1",
"sinon": "^2.4.0",
"webpack": "^3.8.1",
"webpack-dashboard": "^0.1.8",
"webpack-dev-server": "^1.14.1",
"webpack-dev-middleware": "^2.0.0",
"webpack-hot-middleware": "^2.22.2",
"whatwg-fetch": "^1.0.0",
"wrapper-webpack-plugin": "^0.1.7"
},
@ -83,9 +83,9 @@
{
"basePath": "src",
"files": [
"scripts/dist/*",
"styles/css/*",
"icons/*"
"public/scripts/*",
"public/styles/*",
"src/icons/*"
]
}
],

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,365 +1,157 @@
/*===============================
= Choices =
===============================*/
.choices {
/*=============================================
= Generic styling =
=============================================*/
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
*, *:before, *:after {
box-sizing: border-box;
}
html, body {
position: relative;
margin-bottom: 24px;
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: #FFFFFF;
background-color: #333;
overflow-x: hidden;
}
.choices:focus {
outline: none;
}
.choices:last-child {
margin-bottom: 0;
}
.choices.is-disabled .choices__inner, .choices.is-disabled .choices__input {
background-color: #EAEAEA;
cursor: not-allowed;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.choices.is-disabled .choices__item {
cursor: not-allowed;
}
.choices[data-type*="select-one"] {
label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
.choices[data-type*="select-one"] .choices__inner {
padding-bottom: 7.5px;
}
.choices[data-type*="select-one"] .choices__input {
display: block;
width: 100%;
padding: 10px;
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==);
padding: 0;
background-size: 8px;
position: absolute;
top: 50%;
right: 0;
margin-top: -10px;
margin-right: 25px;
height: 20px;
width: 20px;
border-radius: 10em;
opacity: .5;
}
.choices[data-type*="select-one"] .choices__button:hover, .choices[data-type*="select-one"] .choices__button:focus {
opacity: 1;
}
.choices[data-type*="select-one"] .choices__button:focus {
box-shadow: 0px 0px 0px 2px #00BCD4;
}
.choices[data-type*="select-one"]:after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: #333333 transparent transparent transparent;
border-width: 5px;
position: absolute;
right: 11.5px;
top: 50%;
margin-top: -2.5px;
pointer-events: none;
}
.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 {
left: 11.5px;
right: auto;
}
.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 {
cursor: text;
}
.choices[data-type*="select-multiple"] .choices__button, .choices[data-type*="text"] .choices__button {
position: relative;
display: inline-block;
p {
margin-top: 0;
margin-right: -4px;
margin-bottom: 0;
margin-left: 8px;
padding-left: 16px;
border-left: 1px solid #008fa1;
background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);
background-size: 8px;
width: 8px;
line-height: 1;
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 {
opacity: 1;
hr {
display: block;
margin: 30px 0;
border: 0;
border-bottom: 1px solid #eaeaea;
height: 1px;
}
.choices__inner {
display: inline-block;
vertical-align: top;
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 12px;
font-weight: 400;
line-height: 1.2;
}
a, a:visited, a:focus {
color: #FFFFFF;
text-decoration: none;
font-weight: 600;
}
.form-control {
display: block;
width: 100%;
background-color: #f9f9f9;
padding: 7.5px 7.5px 3.75px;
border: 1px solid #DDDDDD;
padding: 12px;
border: 1px solid #ddd;
border-radius: 2.5px;
font-size: 14px;
min-height: 44px;
overflow: hidden;
}
.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;
}
.choices__list {
margin: 0;
padding-left: 0;
list-style: none;
}
.choices__list--single {
display: inline-block;
padding: 4px 16px 4px 4px;
width: 100%;
}
[dir="rtl"] .choices__list--single {
padding-right: 4px;
padding-left: 16px;
}
.choices__list--single .choices__item {
width: 100%;
}
.choices__list--multiple {
display: inline;
}
.choices__list--multiple .choices__item {
display: inline-block;
vertical-align: middle;
border-radius: 20px;
padding: 4px 10px;
font-size: 12px;
font-weight: 500;
margin-right: 3.75px;
margin-bottom: 3.75px;
background-color: #00BCD4;
border: 1px solid #00a5bb;
color: #FFFFFF;
word-break: break-all;
}
.choices__list--multiple .choices__item[data-deletable] {
padding-right: 5px;
}
[dir="rtl"] .choices__list--multiple .choices__item {
margin-right: 0;
margin-left: 3.75px;
}
.choices__list--multiple .choices__item.is-highlighted {
background-color: #00a5bb;
border: 1px solid #008fa1;
}
.is-disabled .choices__list--multiple .choices__item {
background-color: #aaaaaa;
border: 1px solid #919191;
}
.choices__list--dropdown {
display: none;
z-index: 1;
position: absolute;
width: 100%;
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;
}
.choices__list--dropdown.is-active {
display: block;
}
.is-open .choices__list--dropdown {
border-color: #b7b7b7;
}
.is-flipped .choices__list--dropdown {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: -1px;
border-radius: .25rem .25rem 0 0;
}
.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 {
position: relative;
padding: 10px;
font-size: 14px;
}
[dir="rtl"] .choices__list--dropdown .choices__item {
text-align: right;
}
@media (min-width: 640px) {
.choices__list--dropdown .choices__item--selectable {
padding-right: 100px;
}
.choices__list--dropdown .choices__item--selectable:after {
content: attr(data-select-text);
font-size: 12px;
opacity: 0;
position: absolute;
right: 10px;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
[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 {
right: auto;
left: 10px;
}
}
.choices__list--dropdown .choices__item--selectable.is-highlighted {
background-color: #f2f2f2;
}
.choices__list--dropdown .choices__item--selectable.is-highlighted:after {
opacity: .5;
}
.choices__item {
cursor: default;
}
.choices__item--selectable {
cursor: pointer;
}
.choices__item--disabled {
cursor: not-allowed;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
opacity: .5;
}
.choices__heading {
font-weight: 600;
font-size: 12px;
padding: 10px;
border-bottom: 1px solid #f7f7f7;
color: gray;
}
.choices__button {
text-indent: -9999px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
margin-bottom: 24px;
}
.choices__button:focus {
outline: none;
h1, .h1 {
font-size: 32px;
}
.choices__input {
display: inline-block;
vertical-align: baseline;
background-color: #f9f9f9;
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;
margin-bottom: 5px;
border: 0;
border-radius: 0;
}
.container {
display: block;
margin: auto;
max-width: 40em;
padding: 48px;
}
@media (max-width: 620px) {
.container {
padding: 0;
}
}
.section {
background-color: #FFFFFF;
padding: 24px;
color: #333;
}
.section a, .section a:visited, .section a:focus {
color: #00bcd4;
}
.logo {
display: block;
margin-bottom: 12px;
}
.logo__img {
width: 100%;
height: auto;
display: inline-block;
max-width: 100%;
padding: 4px 0 4px 2px;
vertical-align: top;
padding: 6px 0;
}
.choices__input:focus {
outline: 0;
}
[dir="rtl"] .choices__input {
padding-right: 2px;
padding-left: 0;
}
.choices__placeholder {
opacity: .5;
}
.choices__input.is-hidden,
.choices[data-type*="select-one"] .choices__input.is-hidden,
.choices[data-type*="select-multiple"] .choices__input.is-hidden {
.visible-ie {
display: none;
}
/*===== End of Choices ======*/
.zero-bottom {
margin-bottom: 0;
}
.zero-top {
margin-top: 0;
}
.text-center {
text-align: center;
}
.is-hidden {
display: none;
}
/*===== End of Section comment block ======*/

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/* eslint-disable no-console */
/* eslint-disable no-console,global-require,import/no-extraneous-dependencies */
const express = require('express');
const path = require('path');
@ -6,9 +6,32 @@ const app = express();
const port = 3001;
app.use(express.static(path.join(__dirname, 'public')));
if (process.env.NODE_ENV === 'development') {
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./webpack.config.dev');
console.log('Compiling bundle... 👷🏽');
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
stats: {
colors: true,
},
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
}));
}
app.listen(port, (err) => {
if (err) {
console.log(err);
}
console.log(`Listening at ${port}`);
console.log(`Listening at ${port} 👂`);
});

View File

@ -26,6 +26,7 @@ import {
/**
* Choices
* @author Josh Johnson<josh@joshuajohnson.co.uk>
*/
class Choices {
constructor(element = '[data-choice]', userConfig = {}) {
@ -45,17 +46,6 @@ class Choices {
this.config.renderSelectedChoices = 'auto';
}
// Create data store
this._store = new Store(this.render);
// State tracking
this.initialised = false;
this._currentState = {};
this._prevState = {};
this._currentValue = '';
this._isScrollingOnIe = false;
this._wasTap = true;
// Retrieve triggering element (i.e. element with 'data-choice' trigger)
const passedElement = isType('String', element) ? document.querySelector(element) : element;
@ -85,26 +75,29 @@ class Choices {
console.warn('shouldSortElements: Type of passed element is \'select-one\', falling back to false.');
}
this._store = new Store(this.render);
this.initialised = false;
this._currentState = {};
this._prevState = {};
this._currentValue = '';
this._isScrollingOnIe = false;
this._highlightPosition = 0;
this._wasTap = true;
this._placeholderValue = this._generatePlaceholderValue();
this._baseId = generateId(this.passedElement.element, 'choices-');
this._idNames = {
itemChoice: 'item-choice',
};
// Assign preset choices from passed object
this._presetChoices = this.config.choices;
// Assign preset items from passed object first
this._presetItems = this.config.items;
// Then add any values passed from attribute
if (this.passedElement.value) {
this._presetItems = this._presetItems.concat(
this.passedElement.value.split(this.config.delimiter),
);
}
this._baseId = generateId(this.passedElement.element, 'choices-');
this._idNames = {
itemChoice: 'item-choice',
};
this.render = this.render.bind(this);
this._onFocus = this._onFocus.bind(this);
this._onBlur = this._onBlur.bind(this);
@ -129,11 +122,6 @@ class Choices {
= Public functions =
======================================== */
/**
* Initialise Choices
* @return
* @public
*/
init() {
if (this.initialised) {
return;
@ -161,17 +149,11 @@ class Choices {
}
}
/**
* Destroy Choices and nullify values
* @return
* @public
*/
destroy() {
if (!this.initialised) {
return;
}
// Remove all event listeners
this._removeEventListeners();
this.passedElement.reveal();
this.containerOuter.unwrap(this.passedElement.element);
@ -180,20 +162,12 @@ class Choices {
this.passedElement.options = this._presetChoices;
}
// Clear data store
this.clearStore();
// Nullify instance-specific data
this.config.templates = null;
// Uninitialise
this.initialised = false;
}
/**
* Enable interaction with Choices
* @return {Object} Class instance
*/
enable() {
if (!this.initialised) {
return this;
@ -210,11 +184,6 @@ class Choices {
return this;
}
/**
* Disable interaction with Choices
* @return {Object} Class instance
* @public
*/
disable() {
if (!this.initialised) {
return this;
@ -231,11 +200,6 @@ class Choices {
return this;
}
/**
* Render DOM with values
* @return
* @private
*/
render() {
this._currentState = this._store.state;
@ -262,13 +226,6 @@ class Choices {
this._prevState = this._currentState;
}
/**
* Select item (a selected item can be deleted)
* @param {Element} item Element to select
* @param {Boolean} [runEvent=true] Whether to trigger 'highlightItem' event
* @return {Object} Class instance
* @public
*/
highlightItem(item, runEvent = true) {
if (!item) {
return this;
@ -291,12 +248,6 @@ class Choices {
return this;
}
/**
* Deselect item
* @param {Element} item Element to de-select
* @return {Object} Class instance
* @public
*/
unhighlightItem(item) {
if (!item) {
return this;
@ -316,33 +267,16 @@ class Choices {
return this;
}
/**
* Highlight items within store
* @return {Object} Class instance
* @public
*/
highlightAll() {
this._store.items.forEach(item => this.highlightItem(item));
return this;
}
/**
* Deselect items within store
* @return {Object} Class instance
* @public
*/
unhighlightAll() {
this._store.items.forEach(item => this.unhighlightItem(item));
return this;
}
/**
* Remove an item from the store by its value
* @param {String} value Value to search for
* @return {Object} Class instance
* @todo Merge with removeActiveItems
* @public
*/
removeActiveItemsByValue(value) {
this._store.activeItems
.filter(item => item.value === value)
@ -351,13 +285,6 @@ class Choices {
return this;
}
/**
* Remove all items from store array
* @note Removed items are soft deleted
* @param {Number} excludedId Optionally exclude item by ID
* @return {Object} Class instance
* @public
*/
removeActiveItems(excludedId) {
this._store.activeItems
.filter(({ id }) => id !== excludedId)
@ -366,12 +293,6 @@ class Choices {
return this;
}
/**
* Remove all selected items from store
* @note Removed items are soft deleted
* @return {Object} Class instance
* @public
*/
removeHighlightedItems(runEvent = false) {
this._store.highlightedActiveItems
.forEach((item) => {
@ -386,11 +307,6 @@ class Choices {
return this;
}
/**
* Show dropdown to user by adding active state class
* @return {Object} Class instance
* @public
*/
showDropdown(focusInput) {
if (this.dropdown.isActive) {
return this;
@ -410,11 +326,6 @@ class Choices {
return this;
}
/**
* Hide dropdown from user
* @return {Object} Class instance
* @public
*/
hideDropdown(blurInput) {
if (!this.dropdown.isActive) {
return this;
@ -435,11 +346,6 @@ class Choices {
return this;
}
/**
* Determine whether to hide or show dropdown based on its current state
* @return {Object} Class instance
* @public
*/
toggleDropdown() {
if (this.dropdown.isActive) {
this.hideDropdown();
@ -450,13 +356,6 @@ class Choices {
return this;
}
/**
* Get value(s) of input (i.e. inputted items (text) or selected choices (select))
* @param {Boolean} valueOnly Get only values of selected items, otherwise return selected items
* @return {Array/String} selected value (select-one) or
* array of selected items (inputs & select-multiple)
* @public
*/
getValue(valueOnly = false) {
const values = this._store.activeItems
.reduce((selectedItems, item) => {
@ -468,13 +367,6 @@ class Choices {
return this._isSelectOneElement ? values[0] : values;
}
/**
* Set value of input. If the input is a select box, a choice will
* be created and selected otherwise an item will created directly.
* @param {Array} args Array of value objects or value strings
* @return {Object} Class instance
* @public
*/
setValue(args) {
if (!this.initialised) {
return this;
@ -487,12 +379,6 @@ class Choices {
return this;
}
/**
* Select value of select box via the value of an existing choice
* @param {Array/String} value An array of strings of a single string
* @return {Object} Class instance
* @public
*/
setChoiceByValue(value) {
if (!this.initialised || this._isTextElement) {
return this;
@ -507,15 +393,6 @@ class Choices {
return this;
}
/**
* Direct populate choices
* @param {Array} choices - Choices to insert
* @param {String} value - Name of 'value' property
* @param {String} label - Name of 'label' property
* @param {Boolean} replaceChoices Whether existing choices should be removed
* @return {Object} Class instance
* @public
*/
setChoices(choices = [], value = '', label = '', replaceChoices = false) {
if (
!this._isSelectElement ||
@ -557,22 +434,11 @@ class Choices {
return this;
}
/**
* Clear items,choices and groups
* @note Hard delete
* @return {Object} Class instance
* @public
*/
clearStore() {
this._store.dispatch(clearAll());
return this;
}
/**
* Set value of input to blank
* @return {Object} Class instance
* @public
*/
clearInput() {
const shouldSetInputWidth = !this._isSelectOneElement;
this.input.clear(shouldSetInputWidth);
@ -585,12 +451,6 @@ class Choices {
return this;
}
/**
* Populate options via ajax callback
* @param {Function} fn Function that actually makes an AJAX request
* @return {Object} Class instance
* @public
*/
ajax(fn) {
if (!this.initialised || !this._isSelectElement || !fn) {
return this;
@ -608,14 +468,6 @@ class Choices {
= Private functions =
============================================= */
/**
* Render group choices into a DOM fragment and append to choice list
* @param {Array} groups Groups to add to list
* @param {Array} choices Choices to add to groups
* @param {DocumentFragment} fragment Fragment to add groups and options to (optional)
* @return {DocumentFragment} Populated options fragment
* @private
*/
_createGroupsFragment(groups, choices, fragment) {
const groupFragment = fragment || document.createDocumentFragment();
const getGroupChoices = group => choices.filter((choice) => {
@ -643,13 +495,6 @@ class Choices {
return groupFragment;
}
/**
* Render choices into a DOM fragment and append to choice list
* @param {Array} choices Choices to add to list
* @param {DocumentFragment} fragment Fragment to add choices to (optional)
* @return {DocumentFragment} Populated choices fragment
* @private
*/
_createChoicesFragment(choices, fragment, withinGroup = false) {
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
const choicesFragment = fragment || document.createDocumentFragment();
@ -707,13 +552,6 @@ class Choices {
return choicesFragment;
}
/**
* Render items into a DOM fragment and append to items list
* @param {Array} items Items to add to list
* @param {DocumentFragment} [fragment] Fragment to add items to (optional)
* @return
* @private
*/
_createItemsFragment(items, fragment = null) {
// Create fragment to add elements to
const { shouldSortItems, sortFn, removeItemButton } = this.config;
@ -745,12 +583,6 @@ class Choices {
return itemListFragment;
}
/**
* Call change callback
* @param {String} value - last added/deleted/selected value
* @return
* @private
*/
_triggerChange(value) {
if (value === undefined || value === null) {
return;
@ -761,9 +593,6 @@ class Choices {
});
}
/**
* Select placeholder choice
*/
_selectPlaceholderChoice() {
const placeholderChoice = this._store.placeholderChoice;
@ -780,14 +609,6 @@ class Choices {
}
}
/**
* Process enter/click of an item button
* @param {Array} activeItems The currently active items
* @param {Element} element Button being interacted with
* @return
* @private
*/
_handleButtonAction(activeItems, element) {
if (
!activeItems ||
@ -810,14 +631,6 @@ class Choices {
}
}
/**
* Process click of an item
* @param {Array} activeItems The currently active items
* @param {Element} element Item being interacted with
* @param {Boolean} hasShiftKey Whether the user has the shift key active
* @return
* @private
*/
_handleItemAction(activeItems, element, hasShiftKey = false) {
if (
!activeItems ||
@ -846,12 +659,6 @@ class Choices {
this.input.focus();
}
/**
* Process click of a choice
* @param {Array} activeItems The currently active items
* @param {Element} element Choice being interacted with
* @return
*/
_handleChoiceAction(activeItems, element) {
if (!activeItems || !element) {
return;
@ -896,12 +703,6 @@ class Choices {
}
}
/**
* Process back space event
* @param {Array} activeItems items
* @return
* @private
*/
_handleBackspace(activeItems) {
if (!this.config.removeItems || !activeItems) {
return;
@ -926,12 +727,6 @@ class Choices {
}
}
/**
* Apply or remove a loading state to the component.
* @param {Boolean} isLoading default value set to 'true'.
* @return
* @private
*/
_handleLoadingState(isLoading = true) {
let placeholderItem = this.itemList.getChild(`.${this.config.classNames.placeholder}`);
if (isLoading) {
@ -957,14 +752,6 @@ class Choices {
}
}
/**
* Validates whether an item can be added by a user
* @param {Array} activeItems The currently active items
* @param {String} value Value of item to add
* @return {Object} Response: Whether user can add item
* Notice: Notice show in dropdown
*/
_canAddItem(activeItems, value) {
let canAddItem = true;
let notice = isType('Function', this.config.addItemText) ?
@ -1016,11 +803,6 @@ class Choices {
};
}
/**
* Retrieve the callback used to populate component's choices in an async way.
* @returns {Function} The callback as a function.
* @private
*/
_ajaxCallback() {
return (results, value, label) => {
if (!results || !value) {
@ -1065,12 +847,6 @@ class Choices {
};
}
/**
* Filter choices based on search value
* @param {String} value Value to filter by
* @return
* @private
*/
_searchChoices(value) {
const newValue = isType('String', value) ? value.trim() : value;
const currentValue = isType('String', this._currentValue) ?
@ -1099,12 +875,6 @@ class Choices {
return results.length;
}
/**
* Determine the action when a user is searching
* @param {String} value Value entered by user
* @return
* @private
*/
_handleSearch(value) {
if (!value || !this.input.isFocussed) {
return;
@ -1129,11 +899,6 @@ class Choices {
}
}
/**
* Trigger event listeners
* @return
* @private
*/
_addEventListeners() {
document.addEventListener('keyup', this._onKeyUp);
document.addEventListener('keydown', this._onKeyDown);
@ -1154,11 +919,6 @@ class Choices {
this.input.addEventListeners();
}
/**
* Remove event listeners
* @return
* @private
*/
_removeEventListeners() {
document.removeEventListener('keyup', this._onKeyUp);
document.removeEventListener('keydown', this._onKeyDown);
@ -1178,22 +938,18 @@ class Choices {
this.input.removeEventListeners();
}
/**
* Key down event
* @param {Object} e Event
* @return
*/
_onKeyDown(e) {
if (e.target !== this.input.element && !this.containerOuter.element.contains(e.target)) {
_onKeyDown(event) {
const { target, keyCode, ctrlKey, metaKey } = event;
if (target !== this.input.element && !this.containerOuter.element.contains(target)) {
return;
}
const target = e.target;
const activeItems = this._store.activeItems;
const hasFocusedInput = this.input.isFocussed;
const hasActiveDropdown = this.dropdown.isActive;
const hasItems = this.itemList.hasChildren;
const keyString = String.fromCharCode(e.keyCode);
const keyString = String.fromCharCode(keyCode);
const backKey = KEY_CODES.BACK_KEY;
const deleteKey = KEY_CODES.DELETE_KEY;
const enterKey = KEY_CODES.ENTER_KEY;
@ -1203,7 +959,7 @@ class Choices {
const downKey = KEY_CODES.DOWN_KEY;
const pageUpKey = KEY_CODES.PAGE_UP_KEY;
const pageDownKey = KEY_CODES.PAGE_DOWN_KEY;
const ctrlDownKey = (e.ctrlKey || e.metaKey);
const ctrlDownKey = (ctrlKey || metaKey);
// If a user is typing and the dropdown is not active
if (!this._isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString)) {
@ -1244,11 +1000,11 @@ class Choices {
if (target.hasAttribute('data-button')) {
this._handleButtonAction(activeItems, target);
e.preventDefault();
event.preventDefault();
}
if (hasActiveDropdown) {
e.preventDefault();
event.preventDefault();
const highlighted = this.dropdown.getChild(`.${this.config.classNames.highlightedState}`);
// If we have a highlighted choice
@ -1262,7 +1018,7 @@ class Choices {
} else if (this._isSelectOneElement) {
// Open single select dropdown if it's not active
this.showDropdown(true);
e.preventDefault();
event.preventDefault();
}
};
@ -1281,8 +1037,8 @@ class Choices {
this.config.searchEnabled = false;
const directionInt = e.keyCode === downKey || e.keyCode === pageDownKey ? 1 : -1;
const skipKey = e.metaKey || e.keyCode === pageDownKey || e.keyCode === pageUpKey;
const directionInt = keyCode === downKey || keyCode === pageDownKey ? 1 : -1;
const skipKey = metaKey || keyCode === pageDownKey || keyCode === pageUpKey;
const selectableChoiceIdentifier = '[data-choice-selectable]';
let nextEl;
@ -1316,15 +1072,15 @@ class Choices {
// Prevent default to maintain cursor position whilst
// traversing dropdown options
e.preventDefault();
event.preventDefault();
}
};
const onDeleteKey = () => {
// If backspace or delete key is pressed and the input has no value
if (hasFocusedInput && !e.target.value && !this._isSelectOneElement) {
if (hasFocusedInput && !target.value && !this._isSelectOneElement) {
this._handleBackspace(activeItems);
e.preventDefault();
event.preventDefault();
}
};
@ -1342,19 +1098,13 @@ class Choices {
};
// If keycode has a function, run it
if (keyDownActions[e.keyCode]) {
keyDownActions[e.keyCode]();
if (keyDownActions[keyCode]) {
keyDownActions[keyCode]();
}
}
/**
* Key up event
* @param {Object} e Event
* @return
* @private
*/
_onKeyUp(e) {
if (e.target !== this.input.element) {
_onKeyUp({ target, keyCode }) {
if (target !== this.input.element) {
return;
}
@ -1384,7 +1134,7 @@ class Choices {
const deleteKey = KEY_CODES.DELETE_KEY;
// If user has removed value...
if ((e.keyCode === backKey || e.keyCode === deleteKey) && !e.target.value) {
if ((keyCode === backKey || keyCode === deleteKey) && !target.value) {
// ...and it is a multiple select input, activate choices (if searching)
if (!this._isTextElement && this._isSearching) {
this._isSearching = false;
@ -1398,25 +1148,14 @@ class Choices {
this.config.searchEnabled = this.config.searchEnabled;
}
/**
* Touch move event
* @return
* @private
*/
_onTouchMove() {
if (this._wasTap === true) {
this._wasTap = false;
}
}
/**
* Touch end event
* @param {Object} e Event
* @return
* @private
*/
_onTouchEnd(e) {
const target = (e.target || e.touches[0].target);
_onTouchEnd(event) {
const target = (event.target || event.touches[0].target);
// If a user tapped within our container...
if (this._wasTap === true && this.containerOuter.element.contains(target)) {
@ -1434,21 +1173,14 @@ class Choices {
}
}
// Prevents focus event firing
e.stopPropagation();
event.stopPropagation();
}
this._wasTap = true;
}
/**
* Mouse down event
* @param {Object} e Event
* @return
* @private
*/
_onMouseDown(e) {
const target = e.target;
_onMouseDown(event) {
const { target, shiftKey } = event;
// If we have our mouse down on the scrollbar and are on IE11...
if (target === this.choiceList && isIE11()) {
this._isScrollingOnIe = true;
@ -1456,7 +1188,7 @@ class Choices {
if (this.containerOuter.element.contains(target) && target !== this.input.element) {
const activeItems = this._store.activeItems;
const hasShiftKey = e.shiftKey;
const hasShiftKey = shiftKey;
const buttonTarget = findAncestorByAttrName(target, 'data-button');
const itemTarget = findAncestorByAttrName(target, 'data-item');
@ -1470,40 +1202,25 @@ class Choices {
this._handleChoiceAction(activeItems, choiceTarget);
}
e.preventDefault();
event.preventDefault();
}
}
/**
* Mouse over (hover) event
* @param {Object} e Event
* @return
* @private
*/
_onMouseOver(e) {
// If the dropdown is either the target or one of its children is the target
_onMouseOver({ target }) {
const targetWithinDropdown = (
e.target === this.dropdown || this.dropdown.element.contains(e.target)
target === this.dropdown || this.dropdown.element.contains(target)
);
const shouldHighlightChoice = targetWithinDropdown && e.target.hasAttribute('data-choice');
const shouldHighlightChoice = targetWithinDropdown && target.hasAttribute('data-choice');
if (shouldHighlightChoice) {
this._highlightChoice(e.target);
this._highlightChoice(target);
}
}
/**
* Click event
* @param {Object} e Event
* @return
* @private
*/
_onClick(e) {
const target = e.target;
_onClick({ target }) {
const hasActiveDropdown = this.dropdown.isActive;
const activeItems = this._store.activeItems;
// If target is something that concerns us
if (this.containerOuter.element.contains(target)) {
if (!hasActiveDropdown) {
if (this._isTextElement) {
@ -1527,27 +1244,16 @@ class Choices {
} else {
const hasHighlightedItems = activeItems.some(item => item.highlighted);
// De-select any highlighted items
if (hasHighlightedItems) {
this.unhighlightAll();
}
// Remove focus state
this.containerOuter.removeFocusState();
// Close all other dropdowns
this.hideDropdown();
}
}
/**
* Focus event
* @param {Object} e Event
* @return
* @private
*/
_onFocus(e) {
const target = e.target;
_onFocus({ target }) {
if (!this.containerOuter.element.contains(target)) {
return;
}
@ -1578,14 +1284,7 @@ class Choices {
focusActions[this.passedElement.element.type]();
}
/**
* Blur event
* @param {Object} e Event
* @return
* @private
*/
_onBlur(e) {
const target = e.target;
_onBlur({ target }) {
// If target is something that concerns us
if (this.containerOuter.element.contains(target) && !this._isScrollingOnIe) {
const activeItems = this._store.activeItems;
@ -1632,13 +1331,6 @@ class Choices {
}
}
/**
* Scroll to an option element
* @param {HTMLElement} choice Option to scroll to
* @param {Number} direction Whether option is above or below
* @return
* @private
*/
_scrollToChoice(choice, direction) {
if (!choice) {
return;
@ -1692,12 +1384,6 @@ class Choices {
});
}
/**
* Highlight choice
* @param {HTMLElement} [el] Element to highlight
* @return
* @private
*/
_highlightChoice(el = null) {
// Highlight first element in dropdown
const choices = Array.from(this.dropdown.element.querySelectorAll('[data-choice-selectable]'));
@ -1747,16 +1433,6 @@ class Choices {
}
}
/**
* Add item to store with correct value
* @param {String} value Value to add to store
* @param {String} [label] Label to add to store
* @param {Number} [choiceId=-1] ID of the associated choice that was selected
* @param {Number} [groupId=-1] ID of group choice is within. Negative number indicates no group
* @param {Object} [customProperties] Object containing user defined properties
* @return {Object} Class instance
* @public
*/
_addItem(
value,
label = null,
@ -1826,12 +1502,6 @@ class Choices {
return this;
}
/**
* Remove item from store
* @param {Object} item Item to remove
* @return {Object} Class instance
* @public
*/
_removeItem(item) {
if (!item || !isType('Object', item)) {
return this;
@ -1860,17 +1530,6 @@ class Choices {
return this;
}
/**
* Add choice to dropdown
* @param {String} value Value of choice
* @param {String} [label] Label of choice
* @param {Boolean} [isSelected=false] Whether choice is selected
* @param {Boolean} [isDisabled=false] Whether choice is disabled
* @param {Number} [groupId=-1] ID of group choice is within. Negative number indicates no group
* @param {Object} [customProperties] Object containing user defined properties
* @return
* @private
*/
_addChoice(
value,
label = null,
@ -1918,24 +1577,10 @@ class Choices {
}
}
/**
* Clear all choices added to the store.
* @return
* @private
*/
_clearChoices() {
this._store.dispatch(clearChoices());
}
/**
* Add group to dropdown
* @param {Object} group Group to add
* @param {Number} id Group ID
* @param {String} [valueKey] name of the value property on the object
* @param {String} [labelKey] name of the label property on the object
* @return
* @private
*/
_addGroup(group, id, valueKey = 'value', labelKey = 'label') {
const groupChoices = isType('Object', group) ?
group.choices :
@ -1979,13 +1624,6 @@ class Choices {
}
}
/**
* Get template from name
* @param {String} template Name of template to get
* @param {...} args Data to pass to template
* @return {HTMLElement} Template
* @private
*/
_getTemplate(template, ...args) {
if (!template) {
return null;
@ -1997,11 +1635,6 @@ class Choices {
return templates[template].call(this, globalClasses, ...args);
}
/**
* Create HTML element based on type and arguments
* @return
* @private
*/
_createTemplates() {
const { callbackOnCreateTemplates } = this.config;
let userTemplates = {};
@ -2013,9 +1646,6 @@ class Choices {
this.config.templates = extend(TEMPLATES, userTemplates);
}
/**
* Create DOM elements using templates
*/
_createElements() {
const direction = this.passedElement.element.getAttribute('dir') || 'ltr';
const containerOuter = this._getTemplate('containerOuter',
@ -2066,11 +1696,6 @@ class Choices {
});
}
/**
* Create DOM structure around passed select element
* @return
* @private
*/
_createStructure() {
// Hide original element
this.passedElement.conceal();
@ -2308,13 +1933,13 @@ class Choices {
}
_generatePlaceholderValue() {
if (!this._isSelectOneElement) {
return this.config.placeholder ?
(this.config.placeholderValue || this.passedElement.element.getAttribute('placeholder')) :
false;
if (this._isSelectOneElement) {
return false;
}
return false;
return this.config.placeholder ?
(this.config.placeholderValue || this.passedElement.element.getAttribute('placeholder')) :
false;
}
_renderChoices() {

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -1 +0,0 @@
{"version":3,"file":"choices.min.js","sources":[],"mappings":";;;","sourceRoot":""}

View File

@ -1,301 +1,156 @@
/*===============================
= Choices =
===============================*/
/*=============================================
= Generic styling =
=============================================*/
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
$choices-selector: 'choices' !default;
$choices-font-size-lg: 16px !default;
$choices-font-size-md: 14px !default;
$choices-font-size-sm: 12px !default;
$choices-guttering: 24px !default;
$choices-border-radius: 2.5px !default;
$choices-border-radius-item: 20px !default;
$choices-bg-color: #f9f9f9 !default;
$choices-bg-color-disabled: #EAEAEA !default;
$choices-bg-color-dropdown: #FFFFFF !default;
$choices-text-color: #333333 !default;
$choices-keyline-color: #DDDDDD !default;
$choices-primary-color: #00BCD4 !default;
$choices-disabled-color: #eaeaea !default;
$choices-highlight-color: $choices-primary-color !default;
$choices-button-dimension: 8px !default;
$choices-button-offset: 8px !default;
$choices-icon-cross: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==) !default;
$choices-icon-cross-inverse: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==) !default;
*, *:before, *:after {
box-sizing: border-box;
}
.#{$choices-selector} {
html, body {
position: relative;
margin-bottom: $choices-guttering;
font-size: $choices-font-size-lg;
&:focus { outline: none; }
&:last-child { margin-bottom: 0; }
&.is-disabled {
.#{$choices-selector}__inner, .#{$choices-selector}__input {
background-color: $choices-bg-color-disabled;
cursor: not-allowed;
user-select: none;
}
.#{$choices-selector}__item { cursor: not-allowed; }
}
}
.#{$choices-selector}[data-type*="select-one"] {
cursor: pointer;
.#{$choices-selector}__inner { padding-bottom: 7.5px; }
.#{$choices-selector}__input {
display: block;
width: 100%;
padding: 10px;
border-bottom: 1px solid $choices-keyline-color;
background-color: #FFFFFF;
margin: 0;
}
.#{$choices-selector}__button {
background-image: $choices-icon-cross-inverse;
padding: 0;
background-size: 8px;
position: absolute;
top: 50%;
right: 0;
margin-top: -10px;
margin-right: 25px;
height: 20px;
width: 20px;
border-radius: 10em;
opacity: .5;
&:hover, &:focus { opacity: 1; }
&:focus { box-shadow: 0px 0px 0px 2px $choices-highlight-color; }
}
&:after {
content: "";
height: 0;
width: 0;
border-style: solid;
border-color: $choices-text-color transparent transparent transparent;
border-width: 5px;
position: absolute;
right: 11.5px;
top: 50%;
margin-top: -2.5px;
pointer-events: none;
}
&.is-open:after {
border-color: transparent transparent $choices-text-color transparent;
margin-top: -7.5px;
}
&[dir="rtl"] {
&:after {
left: 11.5px;
right: auto;
}
.#{$choices-selector}__button {
right: auto;
left: 0;
margin-left: 25px;
margin-right: 0;
}
}
}
.#{$choices-selector}[data-type*="select-multiple"], .#{$choices-selector}[data-type*="text"] {
.#{$choices-selector}__inner { cursor: text; }
.#{$choices-selector}__button {
position: relative;
display: inline-block;
margin-top: 0;
margin-right: -$choices-button-offset/2;
margin-bottom: 0;
margin-left: $choices-button-offset;
padding-left: $choices-button-offset*2;
border-left: 1px solid darken($choices-primary-color, 10%);
background-image: $choices-icon-cross;
background-size: $choices-button-dimension;
width: $choices-button-dimension;
line-height: 1;
opacity: .75;
border-radius: 0;
&:hover, &:focus { opacity: 1; }
}
}
.#{$choices-selector}__inner {
display: inline-block;
vertical-align: top;
width: 100%;
background-color: $choices-bg-color;
padding: 7.5px 7.5px 3.75px;
border: 1px solid $choices-keyline-color;
border-radius: $choices-border-radius;
font-size: $choices-font-size-md;
min-height: 44px;
overflow: hidden;
.is-focused &, .is-open & { border-color: darken($choices-keyline-color, 15%); }
.is-open & { border-radius: $choices-border-radius $choices-border-radius 0 0; }
.is-flipped.is-open & { border-radius: 0 0 $choices-border-radius $choices-border-radius; }
}
.#{$choices-selector}__list {
margin: 0;
padding-left: 0;
list-style: none;
}
.#{$choices-selector}__list--single {
display: inline-block;
padding: 4px 16px 4px 4px;
width: 100%;
[dir="rtl"] & {
padding-right: 4px;
padding-left: 16px;
}
.#{$choices-selector}__item { width: 100%; }
height: 100%;
}
.#{$choices-selector}__list--multiple {
display: inline;
.#{$choices-selector}__item {
display: inline-block;
vertical-align: middle;
border-radius: $choices-border-radius-item;
padding: 4px 10px;
font-size: $choices-font-size-sm;
font-weight: 500;
margin-right: 3.75px;
margin-bottom: 3.75px;
background-color: $choices-primary-color;
border: 1px solid darken($choices-primary-color, 5%);
color: #FFFFFF;
word-break: break-all;
&[data-deletable] { padding-right: 5px; }
[dir="rtl"] & {
margin-right: 0;
margin-left: 3.75px;
}
&.is-highlighted {
background-color: darken($choices-primary-color, 5%);
border: 1px solid darken($choices-primary-color, 10%);
}
.is-disabled & {
background-color: darken($choices-disabled-color, 25%);
border: 1px solid darken($choices-disabled-color, 35%);
}
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-size: 16px;
line-height: 1.4;
color: #FFFFFF;
background-color: #333;
overflow-x: hidden;
}
.#{$choices-selector}__list--dropdown {
display: none;
z-index: 1;
position: absolute;
width: 100%;
background-color: $choices-bg-color-dropdown;
border: 1px solid $choices-keyline-color;
top: 100%;
margin-top: -1px;
border-bottom-left-radius: $choices-border-radius;
border-bottom-right-radius: $choices-border-radius;
overflow: hidden;
word-break: break-all;
&.is-active { display: block; }
.is-open & { border-color: darken($choices-keyline-color, 15%); }
.is-flipped & {
top: auto;
bottom: 100%;
margin-top: 0;
margin-bottom: -1px;
border-radius: .25rem .25rem 0 0;
}
.#{$choices-selector}__list {
position: relative;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
will-change: scroll-position;
}
.#{$choices-selector}__item {
position: relative;
padding: 10px;
font-size: $choices-font-size-md;
[dir="rtl"] & { text-align: right; }
}
.#{$choices-selector}__item--selectable {
@media (min-width: 640px) {
padding-right: 100px;
&:after {
content: attr(data-select-text);
font-size: $choices-font-size-sm;
opacity: 0;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
[dir="rtl"] & {
text-align: right;
padding-left: 100px;
padding-right: 10px;
&:after {
right: auto;
left: 10px;
}
}
}
&.is-highlighted {
background-color: mix(#000000, #FFFFFF, 5%);
&:after { opacity: .5; }
}
}
label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
.#{$choices-selector}__item { cursor: default; }
.#{$choices-selector}__item--selectable { cursor: pointer; }
.#{$choices-selector}__item--disabled {
cursor: not-allowed;
user-select: none;
opacity: .5;
p {
margin-top: 0;
}
.#{$choices-selector}__heading {
hr {
display: block;
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:visited, a:focus {
color: #FFFFFF;
text-decoration: none;
font-weight: 600;
font-size: $choices-font-size-sm;
padding: 10px;
border-bottom: 1px solid lighten($choices-keyline-color, 10%);
color: lighten(#333, 30%);
}
.#{$choices-selector}__button {
text-indent: -9999px;
.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;
border: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
&:focus { outline: none; }
margin-bottom: 24px;
}
.#{$choices-selector}__input {
display: inline-block;
vertical-align: baseline;
background-color: $choices-bg-color;
font-size: $choices-font-size-md;
margin-bottom: 5px;
border: 0;
border-radius: 0;
max-width: 100%;
padding: 4px 0 4px 2px;
&:focus { outline: 0; }
[dir="rtl"] & {
padding-right: 2px;
padding-left: 0;
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;
}
.container {
display: block;
margin: auto;
max-width: 40em;
padding: 48px;
}
@media (max-width: 620px) {
.container {
padding: 0;
}
}
.#{$choices-selector}__placeholder { opacity: .5; }
.section {
background-color: #FFFFFF;
padding: 24px;
color: #333;
}
.#{$choices-selector}__input.is-hidden,
.#{$choices-selector}[data-type*="select-one"] .#{$choices-selector}__input.is-hidden,
.#{$choices-selector}[data-type*="select-multiple"] .#{$choices-selector}__input.is-hidden {
.section a, .section a:visited, .section a:focus {
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;
}
/*===== End of Choices ======*/
.zero-bottom {
margin-bottom: 0;
}
.zero-top {
margin-top: 0;
}
.text-center {
text-align: center;
}
.is-hidden {
display: none;
}
/*===== End of Section comment block ======*/

View File

@ -1,25 +1,21 @@
const path = require('path');
const webpack = require('webpack');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const dashboard = new Dashboard();
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'./src/scripts/src/choices',
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'./src/scripts/choices',
],
output: {
path: path.join(__dirname, 'dist'),
path: path.resolve('public'),
filename: 'choices.min.js',
publicPath: '/src/scripts/dist/',
publicPath: 'http://localhost:3001/assets/scripts/',
library: 'Choices',
libraryTarget: 'umd',
},
plugins: [
new DashboardPlugin(dashboard.setData),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env': {
@ -32,7 +28,7 @@ module.exports = {
{
enforce: 'pre',
test: /\.js?$/,
include: path.join(__dirname, 'src/scripts/src'),
include: path.join(__dirname, 'src/scripts'),
exclude: /(node_modules|bower_components)/,
loader: 'eslint-loader',
query: {
@ -41,7 +37,7 @@ module.exports = {
},
{
test: /\.js?$/,
include: path.join(__dirname, 'src/scripts/src'),
include: path.join(__dirname, 'src/scripts'),
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
},

View File

@ -11,7 +11,7 @@ module.exports = (env) => {
const config = {
devtool: minimize ? false : 'cheap-module-source-map',
entry: [
'./src/scripts/src/choices',
'./src/scripts/choices',
],
output: {
path: path.join(__dirname, '/public/assets/scripts'),
@ -43,7 +43,7 @@ module.exports = (env) => {
{
enforce: 'pre',
test: /\.js?$/,
include: path.join(__dirname, 'src/scripts/src'),
include: path.join(__dirname, 'src/scripts'),
exclude: /(node_modules|bower_components)/,
loader: 'eslint-loader',
query: {
@ -52,7 +52,7 @@ module.exports = (env) => {
},
{
test: /\.js?$/,
include: path.join(__dirname, 'src/scripts/src'),
include: path.join(__dirname, 'src/scripts'),
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
},