this._highlightPosition?t[this._highlightPosition]:t[t.length-1])||(i=t[0]),M(i,n),i.setAttribute("aria-selected","true"),this.passedElement.triggerEvent("highlightChoice",{el:i}),this.dropdown.isActive&&(this.input.setActiveDescendant(i.id),this.containerOuter.setActiveDescendant(i.id))}},e.prototype._addItem=function(e,t,i){if(void 0===t&&(t=!0),void 0===i&&(i=!1),!e.id)throw new TypeError("item.id must be set before _addItem is called for a choice/item");if((this.config.singleModeForMultiSelect||this._isSelectOneElement)&&this.removeActiveItems(e.id),this._store.dispatch(b(e)),t){var n=x(e);this.passedElement.triggerEvent("addItem",n),i&&this.passedElement.triggerEvent("choice",n)}},e.prototype._removeItem=function(e){if(e.id){this._store.dispatch(E(e));var t=this._notice;t&&t.type===ee&&this._clearNotice(),this.passedElement.triggerEvent(m,x(e))}},e.prototype._addChoice=function(e,t,i){if(void 0===t&&(t=!0),void 0===i&&(i=!1),e.id)throw new TypeError("Can not re-add a choice which has already been added");var n=this.config;if(n.duplicateItemsAllowed||!this._store.choices.find((function(t){return n.valueComparer(t.value,e.value)}))){this._lastAddedChoiceId++,e.id=this._lastAddedChoiceId,e.elementId="".concat(this._baseId,"-").concat(this._idNames.itemChoice,"-").concat(e.id);var s=n.prependValue,o=n.appendValue;s&&(e.value=s+e.value),o&&(e.value+=o.toString()),(s||o)&&e.element&&(e.element.value=e.value),this._clearNotice(),this._store.dispatch(y(e)),e.selected&&this._addItem(e,t,i)}},e.prototype._addGroup=function(e,t){var i=this;if(void 0===t&&(t=!0),e.id)throw new TypeError("Can not re-add a group which has already been added");this._store.dispatch(function(e){return{type:l,group:e}}(e)),e.choices&&(this._lastAddedGroupId++,e.id=this._lastAddedGroupId,e.choices.forEach((function(n){n.group=e,e.disabled&&(n.disabled=!0),i._addChoice(n,t)})))},e.prototype._createTemplates=function(){var e=this,t=this.config.callbackOnCreateTemplates,i={};"function"==typeof t&&(i=t.call(this,I,D,F));var n={};Object.keys(this._templates).forEach((function(t){n[t]=t in i?i[t].bind(e):e._templates[t].bind(e)})),this._templates=n},e.prototype._createElements=function(){var e=this._templates,t=this.config,i=this._isSelectOneElement,n=t.position,s=t.classNames,o=this._elementType;this.containerOuter=new B({element:e.containerOuter(t,this._direction,this._isSelectElement,i,t.searchEnabled,o,t.labelId),classNames:s,type:o,position:n}),this.containerInner=new B({element:e.containerInner(t),classNames:s,type:o,position:n}),this.input=new H({element:e.input(t,this._placeholderValue),classNames:s,type:o,preventPaste:!t.paste}),this.choiceList=new R({element:e.choiceList(t,i)}),this.itemList=new R({element:e.itemList(t,i)}),this.dropdown=new V({element:e.dropdown(t),classNames:s,type:o})},e.prototype._createStructure=function(){var e=this,t=e.containerInner,i=e.containerOuter,n=e.passedElement,s=this.dropdown.element;n.conceal(),t.wrap(n.element),i.wrap(t.element),this._isSelectOneElement?this.input.placeholder=this.config.searchPlaceholderValue||"":(this._placeholderValue&&(this.input.placeholder=this._placeholderValue),this.input.setWidth()),i.element.appendChild(t.element),i.element.appendChild(s),t.element.appendChild(this.itemList.element),s.appendChild(this.choiceList.element),this._isSelectOneElement?this.config.searchEnabled&&s.insertBefore(this.input.element,s.firstChild):t.element.appendChild(this.input.element),this._highlightPosition=0,this._isSearching=!1},e.prototype._initStore=function(){var e=this;this._store.subscribe(this._render).withTxn((function(){e._addPredefinedChoices(e._presetChoices,e._isSelectOneElement&&!e._hasNonChoicePlaceholder,!1)})),(!this._store.choices.length||this._isSelectOneElement&&this._hasNonChoicePlaceholder)&&this._render()},e.prototype._addPredefinedChoices=function(e,t,i){var n=this;void 0===t&&(t=!1),void 0===i&&(i=!0),t&&-1===e.findIndex((function(e){return e.selected}))&&e.some((function(e){return!e.disabled&&!("choices"in e)&&(e.selected=!0,!0)})),e.forEach((function(e){"choices"in e?n._isSelectElement&&n._addGroup(e,i):n._addChoice(e,i)}))},e.prototype._findAndSelectChoiceByValue=function(e,t){var i=this;void 0===t&&(t=!1);var n=this._store.choices.find((function(t){return i.config.valueComparer(t.value,e)}));return!(!n||n.disabled||n.selected||(this._addItem(n,!0,t),0))},e.prototype._generatePlaceholderValue=function(){var e=this.config;if(!e.placeholder)return null;if(this._hasNonChoicePlaceholder)return e.placeholderValue;if(this._isSelectElement){var t=this.passedElement.placeholderOption;return t?t.text:null}return null},e.prototype._warnChoicesInitFailed=function(e){if(!this.config.silent){if(!this.initialised)throw new TypeError("".concat(e," called on a non-initialised instance of Choices"));if(!this.initialisedOK)throw new TypeError("".concat(e," called for an element which has multiple instances of Choices initialised on it"))}},e.version="11.1.0",e}()}));
diff --git a/public/assets/scripts/choices.search-prefix.mjs b/public/assets/scripts/choices.search-prefix.mjs
index 1866bbaf2..e5d6b1d83 100644
--- a/public/assets/scripts/choices.search-prefix.mjs
+++ b/public/assets/scripts/choices.search-prefix.mjs
@@ -420,6 +420,12 @@ var Container = /** @class */ (function () {
Container.prototype.removeFocusState = function () {
removeClassesFromElement(this.element, this.classNames.focusState);
};
+ Container.prototype.addInvalidState = function () {
+ addClassesToElement(this.element, this.classNames.invalidState);
+ };
+ Container.prototype.removeInvalidState = function () {
+ removeClassesFromElement(this.element, this.classNames.invalidState);
+ };
Container.prototype.enable = function () {
removeClassesFromElement(this.element, this.classNames.disabledState);
this.element.removeAttribute('aria-disabled');
@@ -931,6 +937,7 @@ var DEFAULT_CLASSNAMES = {
selectedState: ['is-selected'],
flippedState: ['is-flipped'],
loadingState: ['is-loading'],
+ invalidState: ['is-invalid'],
notice: ['choices__notice'],
addChoice: ['choices__item--selectable', 'add-choice'],
noResults: ['has-no-results'],
@@ -1821,6 +1828,8 @@ var Choices = /** @class */ (function () {
this._onEscapeKey = this._onEscapeKey.bind(this);
this._onDirectionKey = this._onDirectionKey.bind(this);
this._onDeleteKey = this._onDeleteKey.bind(this);
+ this._onChange = this._onChange.bind(this);
+ this._onInvalid = this._onInvalid.bind(this);
// If element has already been initialised with Choices, fail silently
if (this.passedElement.isActive) {
if (!config.silent) {
@@ -2854,6 +2863,7 @@ var Choices = /** @class */ (function () {
var documentElement = this._docRoot;
var outerElement = this.containerOuter.element;
var inputElement = this.input.element;
+ var passedElement = this.passedElement.element;
// capture events - can cancel event processing or propagation
documentElement.addEventListener('touchend', this._onTouchEnd, true);
outerElement.addEventListener('keydown', this._onKeyDown, true);
@@ -2891,12 +2901,21 @@ var Choices = /** @class */ (function () {
passive: true,
});
}
+ if (passedElement.hasAttribute('required')) {
+ passedElement.addEventListener('change', this._onChange, {
+ passive: true,
+ });
+ passedElement.addEventListener('invalid', this._onInvalid, {
+ passive: true,
+ });
+ }
this.input.addEventListeners();
};
Choices.prototype._removeEventListeners = function () {
var documentElement = this._docRoot;
var outerElement = this.containerOuter.element;
var inputElement = this.input.element;
+ var passedElement = this.passedElement.element;
documentElement.removeEventListener('touchend', this._onTouchEnd, true);
outerElement.removeEventListener('keydown', this._onKeyDown, true);
outerElement.removeEventListener('mousedown', this._onMouseDown, true);
@@ -2914,6 +2933,10 @@ var Choices = /** @class */ (function () {
if (inputElement.form) {
inputElement.form.removeEventListener('reset', this._onFormReset);
}
+ if (passedElement.hasAttribute('required')) {
+ passedElement.removeEventListener('change', this._onChange);
+ passedElement.removeEventListener('invalid', this._onInvalid);
+ }
this.input.removeEventListeners();
};
Choices.prototype._onKeyDown = function (event) {
@@ -3296,6 +3319,15 @@ var Choices = /** @class */ (function () {
}
});
};
+ Choices.prototype._onChange = function (event) {
+ if (!event.target.checkValidity()) {
+ return;
+ }
+ this.containerOuter.removeInvalidState();
+ };
+ Choices.prototype._onInvalid = function () {
+ this.containerOuter.addInvalidState();
+ };
Choices.prototype._highlightChoice = function (el) {
if (el === void 0) { el = null; }
var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));
diff --git a/public/assets/styles/choices.css b/public/assets/styles/choices.css
index 0cc203cba..3491bcf9c 100644
--- a/public/assets/styles/choices.css
+++ b/public/assets/styles/choices.css
@@ -27,7 +27,10 @@
cursor: not-allowed;
}
.choices [hidden] {
- display: none !important;
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0;
}
.choices[data-type*=select-one] {
@@ -137,6 +140,9 @@
.is-open .choices__inner {
border-radius: 2.5px 2.5px 0 0;
}
+.is-invalid .choices__inner {
+ border-color: #d33141;
+}
.is-flipped.is-open .choices__inner {
border-radius: 0 0 2.5px 2.5px;
}
diff --git a/public/assets/styles/choices.css.map b/public/assets/styles/choices.css.map
index 9d06c9657..07df2406e 100644
--- a/public/assets/styles/choices.css.map
+++ b/public/assets/styles/choices.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["../../../src/styles/choices.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AA+CA;EACE;EACA;EACA,eAxCkB;EAyClB,WA5CqB;;AA8CrB;EACE;;AAGF;EACE;;AAGF;EACE;;AAIA;AAAA;EAEE,kBAtDsB;EAuDtB;EACA;;AAEF;EACE;;AAIJ;EACE;;;AAIJ;EACE;;AACA;EACE,gBAjDwB;;AAmD1B;EACE;EACA,OA9DY;EA+DZ,SA3D4B;EA4D5B,eA/DkB;EAgElB,kBA7EwB;EA8ExB;;AAEF;EACE,kBAxEyB;EAyEzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE,SAnEyB;;AAsE3B;EACE;;AAGJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA,cA3FiB;EA4FjB;EACA,OA1FkB;EA2FlB;EACA,YA9FuB;EA+FvB;;AAGF;EACE;EACA,YAnG4B;;AAuG5B;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAOJ;AAAA;EACE;;AAEF;AAAA;EACE;EACA;EACA;EACA;EACA;EACA,kBA/IiB;EAgJjB,iBAlJuB;EAmJvB,OAnJuB;EAoJvB,aAhIyB;EAiIzB,eAhI2B;EAiI3B,SAhIqB;;AAkIrB;AAAA;AAAA;EAEE,SAnIyB;;;AAwI/B;EACE;EACA;EACA,OA5Jc;EA6Jd,kBA3KiB;EA4KjB,SAtJsB;EAuJtB,QA9JoB;EA+JpB,eAhLsB;EAiLtB,WApLqB;EAqLrB,YAnKqB;EAoKrB;;AAEA;EAEE;;AAGF;EACE;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;;AAOF;EACE;EACA,SA1L4B;EA2L5B,OAhMc;;AAkMd;EACE;EACA;;AAEF;EACE,OAvMY;;;AA2MhB;EACE;;AACA;EACE;EACA;EACA,eA/NyB;EAgOzB,SA9M4B;EA+M5B,WApOmB;EAqOnB;EACA,cAlN2B;EAmN3B,eAnN2B;EAoN3B,kBA/NoB;EAgOpB;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA,aAhOyB;;AAmO3B;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA,SArPgB;EAsPhB;EACA,OArPc;EAsPd,kBAlQ0B;EAmQ1B,QAtPoB;EAuPpB;EACA;EACA,2BA1QsB;EA2QtB,4BA3QsB;EA4QtB;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA,SAnR4B;EAoR5B,WA3SmB;;AA6SnB;EACE;;AAKA;EADF;IAEI;;EAEA;IACE;IACA,WAvTa;IAwTb;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;;EAEA;IACE;IACA;;;AAMR;EACE;;AAEA;EACE;;;AAUR;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA,WA1WqB;EA2WrB;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA,kBA7XiB;EA8XjB,WAnYqB;EAoYrB,eA3W4B;EA4W5B;EACA;EACA,WApXc;EAqXd,SA9WsB;;AAgXtB;EACE;;AAGF;EAIE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE,SA9X4B;;;AAiY9B","file":"choices.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["../../../src/styles/choices.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAgDA;EACE;EACA;EACA,eAzCkB;EA0ClB,WA7CqB;;AA+CrB;EACE;;AAGF;EACE;;AAGF;EACE;;AAIA;AAAA;EAEE,kBAvDsB;EAwDtB;EACA;;AAEF;EACE;;AAIJ;EACE;EACA;EACA;EACA;;;AAIJ;EACE;;AACA;EACE,gBApDwB;;AAsD1B;EACE;EACA,OAjEY;EAkEZ,SA9D4B;EA+D5B,eAlEkB;EAmElB,kBAjFwB;EAkFxB;;AAEF;EACE,kBA3EyB;EA4EzB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAEE,SAtEyB;;AAyE3B;EACE;;AAGJ;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA,cA9FiB;EA+FjB;EACA,OA7FkB;EA8FlB;EACA,YAjGuB;EAkGvB;;AAGF;EACE;EACA,YAtG4B;;AA0G5B;EACE;EACA;;AAEF;EACE;EACA;EACA;EACA;;;AAOJ;AAAA;EACE;;AAEF;AAAA;EACE;EACA;EACA;EACA;EACA;EACA,kBAlJiB;EAmJjB,iBArJuB;EAsJvB,OAtJuB;EAuJvB,aAnIyB;EAoIzB,eAnI2B;EAoI3B,SAnIqB;;AAqIrB;AAAA;AAAA;EAEE,SAtIyB;;;AA2I/B;EACE;EACA;EACA,OA/Jc;EAgKd,kBA/KiB;EAgLjB,SAzJsB;EA0JtB,QAjKoB;EAkKpB,eApLsB;EAqLtB,WAxLqB;EAyLrB,YAtKqB;EAuKrB;;AAEA;EAEE;;AAGF;EACE;;AAGF;EACE,cA1LoB;;AA6LtB;EACE;;;AAIJ;EACE;EACA;EACA;;AAOF;EACE;EACA,SAjM4B;EAkM5B,OAvMc;;AAyMd;EACE;EACA;;AAEF;EACE,OA9MY;;;AAkNhB;EACE;;AACA;EACE;EACA;EACA,eAvOyB;EAwOzB,SArN4B;EAsN5B,WA5OmB;EA6OnB;EACA,cAzN2B;EA0N3B,eA1N2B;EA2N3B,kBAvOoB;EAwOpB;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;EACA,aAvOyB;;AA0O3B;EACE;EACA;;AAGF;EACE;EACA;;;AAKN;EACE;EACA,SA5PgB;EA6PhB;EACA,OA5Pc;EA6Pd,kBA1Q0B;EA2Q1B,QA7PoB;EA8PpB;EACA;EACA,2BAlRsB;EAmRtB,4BAnRsB;EAoRtB;EACA;;AAEA;EACE;;AAGF;EACE;;AAGF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA,SA1R4B;EA2R5B,WAnTmB;;AAqTnB;EACE;;AAKA;EADF;IAEI;;EAEA;IACE;IACA,WA/Ta;IAgUb;IACA;IACA;IACA;IACA;;EAGF;IACE;IACA;IACA;;EAEA;IACE;IACA;;;AAMR;EACE;;AAEA;EACE;;;AAUR;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA,WAlXqB;EAmXrB;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA,kBArYiB;EAsYjB,WA3YqB;EA4YrB,eAlX4B;EAmX5B;EACA;EACA,WA3Xc;EA4Xd,SArXsB;;AAuXtB;EACE;;AAGF;EAIE;;AAGF;EAEE;EACA;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE,SArY4B;;;AAwY9B","file":"choices.css"}
\ No newline at end of file
diff --git a/public/assets/styles/choices.min.css b/public/assets/styles/choices.min.css
index aeea0361c..edf3a97cb 100644
--- a/public/assets/styles/choices.min.css
+++ b/public/assets/styles/choices.min.css
@@ -1 +1 @@
-.choices{position:relative;overflow:hidden;margin-bottom:24px;font-size:16px}.choices:focus{outline:0}.choices:last-child{margin-bottom:0}.choices.is-open{overflow:visible}.choices.is-disabled .choices__inner,.choices.is-disabled .choices__input{background-color:#eaeaea;cursor:not-allowed;-webkit-user-select:none;user-select:none}.choices.is-disabled .choices__item{cursor:not-allowed}.choices [hidden]{display:none!important}.choices[data-type*=select-one]{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 #ddd;background-color:#fff;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:.25}.choices[data-type*=select-one] .choices__button:focus,.choices[data-type*=select-one] .choices__button:hover{opacity:1}.choices[data-type*=select-one] .choices__button:focus{box-shadow:0 0 0 2px #005f75}.choices[data-type*=select-one] .choices__item[data-placeholder] .choices__button{display:none}.choices[data-type*=select-one]::after{content:"";height:0;width:0;border-style:solid;border-color:#333 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 #333;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;margin:0-4px 0 8px;padding-left:16px;border-left:1px solid #003642;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);background-size:8px;width:8px;line-height:1;border-radius:0;opacity:.75}.choices[data-type*=select-multiple] .choices__button:focus,.choices[data-type*=select-multiple] .choices__button:hover,.choices[data-type*=text] .choices__button:focus,.choices[data-type*=text] .choices__button:hover{opacity:1}.choices__inner{display:inline-block;vertical-align:top;width:100%;background-color:#f9f9f9;padding:7.5px 7.5px 3.75px;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:#005f75;border:1px solid #004a5c;color:#fff;word-break:break-all;box-sizing:border-box}.choices__list--multiple .choices__item[data-deletable]{padding-right:5px}[dir=rtl] .choices__list--multiple .choices__item{margin-right:0;margin-left:3.75px}.choices__list--multiple .choices__item.is-highlighted{background-color:#004a5c;border:1px solid #003642}.is-disabled .choices__list--multiple .choices__item{background-color:#aaa;border:1px solid #919191}.choices__list--dropdown,.choices__list[aria-expanded]{display:none;z-index:1;position:absolute;width:100%;background-color:#fff;border:1px solid #ddd;top:100%;margin-top:-1px;border-bottom-left-radius:2.5px;border-bottom-right-radius:2.5px;overflow:hidden;word-break:break-all}.is-active.choices__list--dropdown,.is-active.choices__list[aria-expanded]{display:block}.is-open .choices__list--dropdown,.is-open .choices__list[aria-expanded]{border-color:#b7b7b7}.is-flipped .choices__list--dropdown,.is-flipped .choices__list[aria-expanded]{top:auto;bottom:100%;margin-top:0;margin-bottom:-1px;border-radius:.25rem .25rem 0 0}.choices__list--dropdown .choices__list,.choices__list[aria-expanded] .choices__list{position:relative;max-height:300px;overflow:auto;-webkit-overflow-scrolling:touch;will-change:scroll-position}.choices__list--dropdown .choices__item,.choices__list[aria-expanded] .choices__item{position:relative;padding:10px;font-size:14px}[dir=rtl] .choices__list--dropdown .choices__item,[dir=rtl] .choices__list[aria-expanded] .choices__item{text-align:right}@media (min-width:640px){.choices__list--dropdown .choices__item--selectable[data-select-text],.choices__list[aria-expanded] .choices__item--selectable[data-select-text]{padding-right:100px}.choices__list--dropdown .choices__item--selectable[data-select-text]::after,.choices__list[aria-expanded] .choices__item--selectable[data-select-text]::after{content:attr(data-select-text);font-size:12px;opacity:0;position:absolute;right:10px;top:50%;transform:translateY(-50%)}[dir=rtl] .choices__list--dropdown .choices__item--selectable[data-select-text],[dir=rtl] .choices__list[aria-expanded] .choices__item--selectable[data-select-text]{text-align:right;padding-left:100px;padding-right:10px}[dir=rtl] .choices__list--dropdown .choices__item--selectable[data-select-text]::after,[dir=rtl] .choices__list[aria-expanded] .choices__item--selectable[data-select-text]::after{right:auto;left:10px}}.choices__list--dropdown .choices__item--selectable.is-highlighted,.choices__list[aria-expanded] .choices__item--selectable.is-highlighted{background-color:#f2f2f2}.choices__list--dropdown .choices__item--selectable.is-highlighted::after,.choices__list[aria-expanded] .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;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;appearance:none;border:0;background-color:transparent;background-repeat:no-repeat;background-position:center;cursor:pointer}.choices__button:focus,.choices__input:focus{outline:0}.choices__input{display:inline-block;vertical-align:baseline;background-color:#f9f9f9;font-size:14px;margin-bottom:5px;border:0;border-radius:0;max-width:100%;padding:4px 0 4px 2px}.choices__input::-webkit-search-cancel-button,.choices__input::-webkit-search-decoration,.choices__input::-webkit-search-results-button,.choices__input::-webkit-search-results-decoration{display:none}.choices__input::-ms-clear,.choices__input::-ms-reveal{display:none;width:0;height:0}[dir=rtl] .choices__input{padding-right:2px;padding-left:0}.choices__placeholder{opacity:.5}
\ No newline at end of file
+.choices{position:relative;overflow:hidden;margin-bottom:24px;font-size:16px}.choices:focus{outline:0}.choices:last-child{margin-bottom:0}.choices.is-open{overflow:visible}.choices.is-disabled .choices__inner,.choices.is-disabled .choices__input{background-color:#eaeaea;cursor:not-allowed;-webkit-user-select:none;user-select:none}.choices.is-disabled .choices__item{cursor:not-allowed}.choices [hidden]{position:absolute;inset:0;pointer-events:none;opacity:0}.choices[data-type*=select-one]{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 #ddd;background-color:#fff;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:.25}.choices[data-type*=select-one] .choices__button:focus,.choices[data-type*=select-one] .choices__button:hover{opacity:1}.choices[data-type*=select-one] .choices__button:focus{box-shadow:0 0 0 2px #005f75}.choices[data-type*=select-one] .choices__item[data-placeholder] .choices__button{display:none}.choices[data-type*=select-one]::after{content:"";height:0;width:0;border-style:solid;border-color:#333 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 #333;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;margin:0-4px 0 8px;padding-left:16px;border-left:1px solid #003642;background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==);background-size:8px;width:8px;line-height:1;border-radius:0;opacity:.75}.choices[data-type*=select-multiple] .choices__button:focus,.choices[data-type*=select-multiple] .choices__button:hover,.choices[data-type*=text] .choices__button:focus,.choices[data-type*=text] .choices__button:hover{opacity:1}.choices__inner{display:inline-block;vertical-align:top;width:100%;background-color:#f9f9f9;padding:7.5px 7.5px 3.75px;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-invalid .choices__inner{border-color:#d33141}.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:#005f75;border:1px solid #004a5c;color:#fff;word-break:break-all;box-sizing:border-box}.choices__list--multiple .choices__item[data-deletable]{padding-right:5px}[dir=rtl] .choices__list--multiple .choices__item{margin-right:0;margin-left:3.75px}.choices__list--multiple .choices__item.is-highlighted{background-color:#004a5c;border:1px solid #003642}.is-disabled .choices__list--multiple .choices__item{background-color:#aaa;border:1px solid #919191}.choices__list--dropdown,.choices__list[aria-expanded]{display:none;z-index:1;position:absolute;width:100%;background-color:#fff;border:1px solid #ddd;top:100%;margin-top:-1px;border-bottom-left-radius:2.5px;border-bottom-right-radius:2.5px;overflow:hidden;word-break:break-all}.is-active.choices__list--dropdown,.is-active.choices__list[aria-expanded]{display:block}.is-open .choices__list--dropdown,.is-open .choices__list[aria-expanded]{border-color:#b7b7b7}.is-flipped .choices__list--dropdown,.is-flipped .choices__list[aria-expanded]{top:auto;bottom:100%;margin-top:0;margin-bottom:-1px;border-radius:.25rem .25rem 0 0}.choices__list--dropdown .choices__list,.choices__list[aria-expanded] .choices__list{position:relative;max-height:300px;overflow:auto;-webkit-overflow-scrolling:touch;will-change:scroll-position}.choices__list--dropdown .choices__item,.choices__list[aria-expanded] .choices__item{position:relative;padding:10px;font-size:14px}[dir=rtl] .choices__list--dropdown .choices__item,[dir=rtl] .choices__list[aria-expanded] .choices__item{text-align:right}@media (min-width:640px){.choices__list--dropdown .choices__item--selectable[data-select-text],.choices__list[aria-expanded] .choices__item--selectable[data-select-text]{padding-right:100px}.choices__list--dropdown .choices__item--selectable[data-select-text]::after,.choices__list[aria-expanded] .choices__item--selectable[data-select-text]::after{content:attr(data-select-text);font-size:12px;opacity:0;position:absolute;right:10px;top:50%;transform:translateY(-50%)}[dir=rtl] .choices__list--dropdown .choices__item--selectable[data-select-text],[dir=rtl] .choices__list[aria-expanded] .choices__item--selectable[data-select-text]{text-align:right;padding-left:100px;padding-right:10px}[dir=rtl] .choices__list--dropdown .choices__item--selectable[data-select-text]::after,[dir=rtl] .choices__list[aria-expanded] .choices__item--selectable[data-select-text]::after{right:auto;left:10px}}.choices__list--dropdown .choices__item--selectable.is-highlighted,.choices__list[aria-expanded] .choices__item--selectable.is-highlighted{background-color:#f2f2f2}.choices__list--dropdown .choices__item--selectable.is-highlighted::after,.choices__list[aria-expanded] .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;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;appearance:none;border:0;background-color:transparent;background-repeat:no-repeat;background-position:center;cursor:pointer}.choices__button:focus,.choices__input:focus{outline:0}.choices__input{display:inline-block;vertical-align:baseline;background-color:#f9f9f9;font-size:14px;margin-bottom:5px;border:0;border-radius:0;max-width:100%;padding:4px 0 4px 2px}.choices__input::-webkit-search-cancel-button,.choices__input::-webkit-search-decoration,.choices__input::-webkit-search-results-button,.choices__input::-webkit-search-results-decoration{display:none}.choices__input::-ms-clear,.choices__input::-ms-reveal{display:none;width:0;height:0}[dir=rtl] .choices__input{padding-right:2px;padding-left:0}.choices__placeholder{opacity:.5}
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 92b5efa72..212c2c97f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -548,6 +548,37 @@ Form interaction
+
+
+ Form validation
+ Try submitting the form first.
+
+ Then try setting the values as they are required!
+
+
diff --git a/src/scripts/choices.ts b/src/scripts/choices.ts
index 1814666e9..310228a0f 100644
--- a/src/scripts/choices.ts
+++ b/src/scripts/choices.ts
@@ -304,6 +304,8 @@ class Choices {
this._onEscapeKey = this._onEscapeKey.bind(this);
this._onDirectionKey = this._onDirectionKey.bind(this);
this._onDeleteKey = this._onDeleteKey.bind(this);
+ this._onChange = this._onChange.bind(this);
+ this._onInvalid = this._onInvalid.bind(this);
// If element has already been initialised with Choices, fail silently
if (this.passedElement.isActive) {
@@ -1500,6 +1502,7 @@ class Choices {
const documentElement = this._docRoot;
const outerElement = this.containerOuter.element;
const inputElement = this.input.element;
+ const passedElement = this.passedElement.element;
// capture events - can cancel event processing or propagation
documentElement.addEventListener('touchend', this._onTouchEnd, true);
@@ -1544,6 +1547,16 @@ class Choices {
});
}
+ if (passedElement.hasAttribute('required')) {
+ passedElement.addEventListener('change', this._onChange, {
+ passive: true,
+ });
+
+ passedElement.addEventListener('invalid', this._onInvalid, {
+ passive: true,
+ });
+ }
+
this.input.addEventListeners();
}
@@ -1551,6 +1564,7 @@ class Choices {
const documentElement = this._docRoot;
const outerElement = this.containerOuter.element;
const inputElement = this.input.element;
+ const passedElement = this.passedElement.element;
documentElement.removeEventListener('touchend', this._onTouchEnd, true);
outerElement.removeEventListener('keydown', this._onKeyDown, true);
@@ -1574,6 +1588,11 @@ class Choices {
inputElement.form.removeEventListener('reset', this._onFormReset);
}
+ if (passedElement.hasAttribute('required')) {
+ passedElement.removeEventListener('change', this._onChange);
+ passedElement.removeEventListener('invalid', this._onInvalid);
+ }
+
this.input.removeEventListeners();
}
@@ -2008,6 +2027,18 @@ class Choices {
});
}
+ _onChange(event: Event & { target: HTMLInputElement | HTMLSelectElement }): void {
+ if (!event.target.checkValidity()) {
+ return;
+ }
+
+ this.containerOuter.removeInvalidState();
+ }
+
+ _onInvalid(): void {
+ this.containerOuter.addInvalidState();
+ }
+
_highlightChoice(el: HTMLElement | null = null): void {
const choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));
diff --git a/src/scripts/components/container.ts b/src/scripts/components/container.ts
index e8ca42460..80c7bcf8c 100644
--- a/src/scripts/components/container.ts
+++ b/src/scripts/components/container.ts
@@ -100,6 +100,14 @@ export default class Container {
removeClassesFromElement(this.element, this.classNames.focusState);
}
+ addInvalidState(): void {
+ addClassesToElement(this.element, this.classNames.invalidState);
+ }
+
+ removeInvalidState(): void {
+ removeClassesFromElement(this.element, this.classNames.invalidState);
+ }
+
enable(): void {
removeClassesFromElement(this.element, this.classNames.disabledState);
this.element.removeAttribute('aria-disabled');
diff --git a/src/scripts/defaults.ts b/src/scripts/defaults.ts
index e243abe45..84200dee6 100644
--- a/src/scripts/defaults.ts
+++ b/src/scripts/defaults.ts
@@ -29,6 +29,7 @@ export const DEFAULT_CLASSNAMES: ClassNames = {
selectedState: ['is-selected'],
flippedState: ['is-flipped'],
loadingState: ['is-loading'],
+ invalidState: ['is-invalid'],
notice: ['choices__notice'],
addChoice: ['choices__item--selectable', 'add-choice'],
noResults: ['has-no-results'],
diff --git a/src/scripts/interfaces/class-names.ts b/src/scripts/interfaces/class-names.ts
index bf1e7e041..3fda36cc0 100644
--- a/src/scripts/interfaces/class-names.ts
+++ b/src/scripts/interfaces/class-names.ts
@@ -50,6 +50,8 @@ export interface ClassNames {
flippedState: string | Array;
/** @default ['is-loading'] */
loadingState: string | Array;
+ /** @default ['is-invalid'] */
+ invalidState: string | Array;
/** @default ['choices__notice'] */
notice: string | Array;
/** @default ['choices__item--selectable', 'add-choice'] */
diff --git a/src/styles/choices.css b/src/styles/choices.css
index e1a476b12..b72947d58 100644
--- a/src/styles/choices.css
+++ b/src/styles/choices.css
@@ -17,6 +17,7 @@
--choices-keyline-color: #ddd;
--choices-primary-color: #005F75;
--choices-disabled-color: #eaeaea;
+ --choices-invalid-color: #d33141;
--choices-highlight-color: var(--choices-primary-color);
--choices-button-dimension: 8px;
--choices-button-offset: 8px;
@@ -70,7 +71,10 @@
cursor: not-allowed;
}
.choices [hidden] {
- display: none !important;
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0;
}
.choices[data-type*="select-one"] {
@@ -181,6 +185,9 @@
.is-open .choices__inner {
border-radius: var(--choices-border-radius) var(--choices-border-radius) 0 0;
}
+.is-invalid .choices__inner {
+ border-color: var(--choices-invalid-color);
+}
.is-flipped.is-open .choices__inner {
border-radius: 0 0 var(--choices-border-radius) var(--choices-border-radius);
}
diff --git a/src/styles/choices.scss b/src/styles/choices.scss
index 53755eec7..e2f13859a 100644
--- a/src/styles/choices.scss
+++ b/src/styles/choices.scss
@@ -18,6 +18,7 @@ $choices-text-color: #333 !default;
$choices-keyline-color: #ddd !default;
$choices-primary-color: #005F75 !default;
$choices-disabled-color: #eaeaea !default;
+$choices-invalid-color: #d33141 !default;
$choices-highlight-color: $choices-primary-color !default;
$choices-button-dimension: 8px !default;
$choices-button-offset: 8px !default;
@@ -76,7 +77,10 @@ $choices-placeholder-opacity: 0.5 !default;
}
[hidden] {
- display: none !important;
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ opacity: 0;
}
}
@@ -199,6 +203,10 @@ $choices-placeholder-opacity: 0.5 !default;
border-radius: $choices-border-radius $choices-border-radius 0 0;
}
+ .is-invalid & {
+ border-color: $choices-invalid-color;
+ }
+
.is-flipped.is-open & {
border-radius: 0 0 $choices-border-radius $choices-border-radius;
}
diff --git a/test-e2e/__screenshots__/chromium-darwin.png b/test-e2e/__screenshots__/chromium-darwin.png
index 0a9898930..cc5206a2e 100644
Binary files a/test-e2e/__screenshots__/chromium-darwin.png and b/test-e2e/__screenshots__/chromium-darwin.png differ
diff --git a/test-e2e/__screenshots__/chromium-linux.png b/test-e2e/__screenshots__/chromium-linux.png
index 357f6848d..5cbde9224 100644
Binary files a/test-e2e/__screenshots__/chromium-linux.png and b/test-e2e/__screenshots__/chromium-linux.png differ
diff --git a/test-e2e/__screenshots__/chromium-win32.png b/test-e2e/__screenshots__/chromium-win32.png
index af44f5313..2c8166394 100644
Binary files a/test-e2e/__screenshots__/chromium-win32.png and b/test-e2e/__screenshots__/chromium-win32.png differ
diff --git a/test-e2e/__screenshots__/firefox-linux.png b/test-e2e/__screenshots__/firefox-linux.png
index 5462ba7b6..31042de56 100644
Binary files a/test-e2e/__screenshots__/firefox-linux.png and b/test-e2e/__screenshots__/firefox-linux.png differ
diff --git a/test-e2e/__screenshots__/webkit-darwin.png b/test-e2e/__screenshots__/webkit-darwin.png
index e2aaf71b1..1ba16333b 100644
Binary files a/test-e2e/__screenshots__/webkit-darwin.png and b/test-e2e/__screenshots__/webkit-darwin.png differ
diff --git a/test-e2e/__screenshots__/webkit-linux.png b/test-e2e/__screenshots__/webkit-linux.png
index b987c69c7..805014e9c 100644
Binary files a/test-e2e/__screenshots__/webkit-linux.png and b/test-e2e/__screenshots__/webkit-linux.png differ
diff --git a/test-e2e/test-suit.ts b/test-e2e/test-suit.ts
index 7a948163e..c45560ea9 100644
--- a/test-e2e/test-suit.ts
+++ b/test-e2e/test-suit.ts
@@ -179,6 +179,10 @@ export class TestSuit {
throw new Error('Not implemented');
}
+ getWrapper(): Locator {
+ return this.wrapper;
+ }
+
async expectedValue(text: string): Promise {
if (text !== '') {
await expect(this.items.filter({ hasText: text })).not.toHaveCount(0);
diff --git a/test-e2e/tests/demo-page.spec.ts b/test-e2e/tests/demo-page.spec.ts
index 212f22568..b8a567bcb 100644
--- a/test-e2e/tests/demo-page.spec.ts
+++ b/test-e2e/tests/demo-page.spec.ts
@@ -1,6 +1,7 @@
import { expect } from '@playwright/test';
import { test } from '../bundle-test';
import { SelectTestSuit } from '../select-test-suit';
+import { DEFAULT_CLASSNAMES } from '../../src';
// import { mkdirSync } from 'fs';
// import path from 'path';
@@ -53,5 +54,22 @@ describe(`Choices`, () => {
await suite.expectedItemCount(1);
await expect(suite.items.first()).toHaveText('Option 2');
});
+
+ test('show invalid on required form submit', async ({ page, bundle }) => {
+ const testId = 'invalid-select';
+ const suite = new SelectTestSuit(page, bundle, testUrl, testId);
+ await suite.startWithClick();
+
+ await page
+ .getByTestId('invalid-form')
+ .getByRole('button', { name: /submit/i })
+ .click();
+
+ await suite.advanceClock();
+
+ await expect(suite.getWrapper()).toHaveClass(
+ `${DEFAULT_CLASSNAMES.containerOuter} ${DEFAULT_CLASSNAMES.invalidState}`,
+ );
+ });
});
});