This commit is contained in:
Xon 2026-01-05 02:56:50 +00:00
commit b0911cdfd3
29 changed files with 1378 additions and 796 deletions

View file

@ -1,4 +1,4 @@
/*! choices.js v11.1.0 | © 2025 Josh Johnson | https://github.com/jshjohnson/Choices#readme */
/*! choices.js v11.2.0 | © 2026 Josh Johnson | https://github.com/jshjohnson/Choices#readme */
/******************************************************************************
Copyright (c) Microsoft Corporation.
@ -202,9 +202,6 @@ var strToEl = (function () {
return firstChild;
};
})();
var resolveNoticeFunction = function (fn, value) {
return typeof fn === 'function' ? fn(sanitise(value), value) : fn;
};
var resolveStringFunction = function (fn) {
return typeof fn === 'function' ? fn() : fn;
};
@ -236,6 +233,26 @@ var unwrapStringForEscaped = function (s) {
}
return '';
};
var getChoiceForOutput = function (choice, keyCode) {
return {
id: choice.id,
highlighted: choice.highlighted,
labelClass: choice.labelClass,
labelDescription: unwrapStringForRaw(choice.labelDescription),
customProperties: choice.customProperties,
disabled: choice.disabled,
active: choice.active,
label: choice.label,
placeholder: choice.placeholder,
value: choice.value,
groupValue: choice.group ? choice.group.label : undefined,
element: choice.element,
keyCode: keyCode,
};
};
var resolveNoticeFunction = function (fn, value, item) {
return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;
};
var escapeForTemplate = function (allowHTML, s) {
return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);
};
@ -403,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');
@ -868,7 +891,9 @@ var WrappedSelect = /** @class */ (function (_super) {
highlighted: false,
placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),
labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,
labelDescription: typeof option.dataset.labelDescription !== 'undefined' ? option.dataset.labelDescription : undefined,
labelDescription: typeof option.dataset.labelDescription !== 'undefined'
? { trusted: option.dataset.labelDescription }
: undefined,
customProperties: parseCustomProperties(option.dataset.customProperties),
};
};
@ -914,6 +939,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'],
@ -941,6 +967,7 @@ var DEFAULT_CONFIG = {
paste: true,
searchEnabled: true,
searchChoices: true,
searchDisabledChoices: false,
searchFloor: 1,
searchResultLimit: 4,
searchFields: ['label', 'value'],
@ -956,6 +983,7 @@ var DEFAULT_CONFIG = {
prependValue: null,
appendValue: null,
renderSelectedChoices: 'auto',
searchRenderSelectedChoices: true,
loadingText: 'Loading...',
noResultsText: 'No results found',
noChoicesText: 'No choices to choose from',
@ -964,7 +992,9 @@ var DEFAULT_CONFIG = {
customAddItemText: 'Only values matching specific conditions can be added',
addItemText: function (value) { return "Press Enter to add <b>\"".concat(value, "\"</b>"); },
removeItemIconText: function () { return "Remove item"; },
removeItemLabelText: function (value) { return "Remove item: ".concat(value); },
removeItemLabelText: function (value, _valueRaw, i) {
return "Remove item: ".concat(i ? sanitise(i.label) : value);
},
maxItemText: function (maxItemCount) { return "Only ".concat(maxItemCount, " values can be added"); },
valueComparer: function (value1, value2) { return value1 === value2; },
fuseOptions: {
@ -1265,7 +1295,8 @@ var Store = /** @class */ (function () {
* Get choices that can be searched (excluding placeholders or disabled choices)
*/
get: function () {
return this.choices.filter(function (choice) { return !choice.disabled && !choice.placeholder; });
var context = this._context;
return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });
},
enumerable: false,
configurable: true
@ -1379,11 +1410,12 @@ var SearchByKMP = /** @class */ (function () {
var field = this._fields[k];
if (field in obj && kmpSearch(needle, obj[field].toLowerCase()) !== -1) {
results.push({
item: obj[field],
item: obj,
score: count,
rank: count + 1,
});
count++;
break;
}
}
}
@ -1419,7 +1451,7 @@ var assignCustomProperties = function (el, choice, withCustomProperties) {
dataset.labelClass = getClassNames(labelClass).join(' ');
}
if (labelDescription) {
dataset.labelDescription = labelDescription;
dataset.labelDescription = unwrapStringForRaw(labelDescription);
}
if (withCustomProperties && customProperties) {
if (typeof customProperties === 'string') {
@ -1526,8 +1558,9 @@ var templates = {
var removeButton = document.createElement('button');
removeButton.type = 'button';
addClassesToElement(removeButton, button);
setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value));
var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value);
var eventChoice = getChoiceForOutput(choice);
setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));
var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);
if (REMOVE_ITEM_LABEL) {
removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);
}
@ -1632,6 +1665,7 @@ var templates = {
else {
addClassesToElement(div, itemSelectable);
div.dataset.choiceSelectable = '';
div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');
}
return div;
},
@ -1801,7 +1835,7 @@ var Choices = /** @class */ (function () {
this.initialised = false;
this._store = new Store(config);
this._currentValue = '';
config.searchEnabled = (!isText && config.searchEnabled) || isSelectMultiple;
config.searchEnabled = !isText && config.searchEnabled;
this._canSearch = config.searchEnabled;
this._isScrollingOnIe = false;
this._highlightPosition = 0;
@ -1841,6 +1875,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) {
@ -1947,7 +1983,7 @@ var Choices = /** @class */ (function () {
}
this._store.dispatch(highlightItem(choice, true));
if (runEvent) {
this.passedElement.triggerEvent(EventType.highlightItem, this._getChoiceForOutput(choice));
this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));
}
return this;
};
@ -1962,7 +1998,7 @@ var Choices = /** @class */ (function () {
}
this._store.dispatch(highlightItem(choice, false));
if (runEvent) {
this.passedElement.triggerEvent(EventType.unhighlightItem, this._getChoiceForOutput(choice));
this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));
}
return this;
};
@ -1972,7 +2008,7 @@ var Choices = /** @class */ (function () {
_this._store.items.forEach(function (item) {
if (!item.highlighted) {
_this._store.dispatch(highlightItem(item, true));
_this.passedElement.triggerEvent(EventType.highlightItem, _this._getChoiceForOutput(item));
_this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));
}
});
});
@ -1984,7 +2020,7 @@ var Choices = /** @class */ (function () {
_this._store.items.forEach(function (item) {
if (item.highlighted) {
_this._store.dispatch(highlightItem(item, false));
_this.passedElement.triggerEvent(EventType.highlightItem, _this._getChoiceForOutput(item));
_this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));
}
});
});
@ -2039,6 +2075,11 @@ var Choices = /** @class */ (function () {
_this.input.focus();
}
_this.passedElement.triggerEvent(EventType.showDropdown);
var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));
if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {
// We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.
activeElement.scrollIntoView();
}
});
return this;
};
@ -2047,6 +2088,7 @@ var Choices = /** @class */ (function () {
if (!this.dropdown.isActive) {
return this;
}
this._removeHighlightedChoices();
requestAnimationFrame(function () {
_this.dropdown.hide();
_this.containerOuter.close();
@ -2059,9 +2101,8 @@ var Choices = /** @class */ (function () {
return this;
};
Choices.prototype.getValue = function (valueOnly) {
var _this = this;
var values = this._store.items.map(function (item) {
return (valueOnly ? item.value : _this._getChoiceForOutput(item));
return (valueOnly ? item.value : getChoiceForOutput(item));
});
return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;
};
@ -2319,7 +2360,7 @@ var Choices = /** @class */ (function () {
// @todo integrate with Store
this._searcher.reset();
if (choice.selected) {
this.passedElement.triggerEvent(EventType.removeItem, this._getChoiceForOutput(choice));
this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));
}
return this;
};
@ -2402,13 +2443,7 @@ var Choices = /** @class */ (function () {
}
var _a = this, config = _a.config, isSearching = _a._isSearching;
var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;
var renderLimit = 0;
if (isSearching && config.searchResultLimit > 0) {
renderLimit = config.searchResultLimit;
}
else if (config.renderChoiceLimit > 0) {
renderLimit = config.renderChoiceLimit;
}
var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;
if (this._isSelectElement) {
var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });
if (backingOptions.length) {
@ -2418,11 +2453,16 @@ var Choices = /** @class */ (function () {
var fragment = document.createDocumentFragment();
var renderableChoices = function (choices) {
return choices.filter(function (choice) {
return !choice.placeholder && (isSearching ? !!choice.rank : config.renderSelectedChoices || !choice.selected);
return !choice.placeholder &&
(isSearching
? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank
: config.renderSelectedChoices || !choice.selected);
});
};
var showLabel = config.appendGroupInSearch && isSearching;
var selectableChoices = false;
var renderChoices = function (choices, withinGroup, groupLabel) {
var highlightedEl = null;
var renderChoices = function (choices, withinGroup) {
if (isSearching) {
// sortByRank is used to ensure stable sorting, as scores are non-unique
// this additionally ensures fuseOptions.sortFn is not ignored
@ -2432,16 +2472,20 @@ var Choices = /** @class */ (function () {
choices.sort(config.sorter);
}
var choiceLimit = choices.length;
choiceLimit = !withinGroup && renderLimit && choiceLimit > renderLimit ? renderLimit : choiceLimit;
choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;
choiceLimit--;
choices.every(function (choice, index) {
// choiceEl being empty signals the contents has probably significantly changed
var dropdownItem = choice.choiceEl || _this._templates.choice(config, choice, config.itemSelectText, groupLabel);
var dropdownItem = choice.choiceEl ||
_this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);
choice.choiceEl = dropdownItem;
fragment.appendChild(dropdownItem);
if (isSearching || !choice.selected) {
selectableChoices = true;
}
else if (!highlightedEl) {
highlightedEl = dropdownItem;
}
return index < choiceLimit;
});
};
@ -2451,7 +2495,7 @@ var Choices = /** @class */ (function () {
}
if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {
// If we have a placeholder choice along with groups
renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false, undefined);
renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);
}
// If we have grouped options
if (activeGroups.length && !isSearching) {
@ -2460,7 +2504,7 @@ var Choices = /** @class */ (function () {
}
// render Choices without group first, regardless of sort, otherwise they won't be distinguishable
// from the last group
renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false, undefined);
renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);
activeGroups.forEach(function (group) {
var groupChoices = renderableChoices(group.choices);
if (groupChoices.length) {
@ -2470,12 +2514,12 @@ var Choices = /** @class */ (function () {
dropdownGroup.remove();
fragment.appendChild(dropdownGroup);
}
renderChoices(groupChoices, true, config.appendGroupInSearch && isSearching ? group.label : undefined);
renderChoices(groupChoices, true);
}
});
}
else {
renderChoices(renderableChoices(activeChoices), false, undefined);
renderChoices(renderableChoices(activeChoices), false);
}
}
if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {
@ -2489,9 +2533,7 @@ var Choices = /** @class */ (function () {
}
this._renderNotice(fragment);
this.choiceList.element.replaceChildren(fragment);
if (selectableChoices) {
this._highlightChoice();
}
this._highlightChoice(highlightedEl);
};
Choices.prototype._renderItems = function () {
var _this = this;
@ -2601,23 +2643,12 @@ var Choices = /** @class */ (function () {
}
}
};
/**
* @deprecated Use utils.getChoiceForOutput
*/
// eslint-disable-next-line class-methods-use-this
Choices.prototype._getChoiceForOutput = function (choice, keyCode) {
return {
id: choice.id,
highlighted: choice.highlighted,
labelClass: choice.labelClass,
labelDescription: choice.labelDescription,
customProperties: choice.customProperties,
disabled: choice.disabled,
active: choice.active,
label: choice.label,
placeholder: choice.placeholder,
value: choice.value,
groupValue: choice.group ? choice.group.label : undefined,
element: choice.element,
keyCode: keyCode,
};
return getChoiceForOutput(choice, keyCode);
};
Choices.prototype._triggerChange = function (value) {
if (value === undefined || value === null) {
@ -2633,7 +2664,7 @@ var Choices = /** @class */ (function () {
if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {
return;
}
var id = element && parseDataSetId(element.parentElement);
var id = element && parseDataSetId(element.closest('[data-id]'));
var itemToRemove = id && items.find(function (item) { return item.id === id; });
if (!itemToRemove) {
return;
@ -2822,7 +2853,7 @@ var Choices = /** @class */ (function () {
var notice = '';
if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {
canAddItem = false;
notice = resolveNoticeFunction(config.customAddItemText, value);
notice = resolveNoticeFunction(config.customAddItemText, value, undefined);
}
if (canAddItem) {
var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });
@ -2834,12 +2865,12 @@ var Choices = /** @class */ (function () {
}
if (!config.duplicateItemsAllowed) {
canAddItem = false;
notice = resolveNoticeFunction(config.uniqueItemText, value);
notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);
}
}
}
if (canAddItem) {
notice = resolveNoticeFunction(config.addItemText, value);
notice = resolveNoticeFunction(config.addItemText, value, undefined);
}
if (notice) {
this._displayNotice(notice, NoticeTypes.addChoice);
@ -2890,6 +2921,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);
@ -2927,12 +2959,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);
@ -2950,6 +2991,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) {
@ -3199,7 +3244,7 @@ var Choices = /** @class */ (function () {
*/
Choices.prototype._onMouseDown = function (event) {
var target = event.target;
if (!(target instanceof HTMLElement)) {
if (!(target instanceof Element)) {
return;
}
// If we have our mouse down on the scrollbar and are on IE11...
@ -3308,7 +3353,7 @@ var Choices = /** @class */ (function () {
// Remove the focus state when the past outerContainer was the target
containerOuter.removeFocusState();
// Also close the dropdown if search is disabled
if (!this._canSearch) {
if (!this.config.searchEnabled) {
this.hideDropdown(true);
}
}
@ -3332,6 +3377,27 @@ var Choices = /** @class */ (function () {
}
});
};
Choices.prototype._onChange = function (event) {
if (!event.target.checkValidity()) {
return;
}
this.containerOuter.removeInvalidState();
};
Choices.prototype._onInvalid = function () {
this.containerOuter.addInvalidState();
};
/**
* Removes any highlighted choice options
*/
Choices.prototype._removeHighlightedChoices = function () {
var highlightedState = this.config.classNames.highlightedState;
var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));
// Remove any highlighted choices
highlightedChoices.forEach(function (choice) {
removeClassesFromElement(choice, highlightedState);
choice.setAttribute('aria-selected', 'false');
});
};
Choices.prototype._highlightChoice = function (el) {
if (el === void 0) { el = null; }
var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));
@ -3340,12 +3406,7 @@ var Choices = /** @class */ (function () {
}
var passedEl = el;
var highlightedState = this.config.classNames.highlightedState;
var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));
// Remove any highlighted choices
highlightedChoices.forEach(function (choice) {
removeClassesFromElement(choice, highlightedState);
choice.setAttribute('aria-selected', 'false');
});
this._removeHighlightedChoices();
if (passedEl) {
this._highlightPosition = choices.indexOf(passedEl);
}
@ -3386,9 +3447,10 @@ var Choices = /** @class */ (function () {
}
this._store.dispatch(addItem(item));
if (withEvents) {
this.passedElement.triggerEvent(EventType.addItem, this._getChoiceForOutput(item));
var eventChoice = getChoiceForOutput(item);
this.passedElement.triggerEvent(EventType.addItem, eventChoice);
if (userTriggered) {
this.passedElement.triggerEvent(EventType.choice, this._getChoiceForOutput(item));
this.passedElement.triggerEvent(EventType.choice, eventChoice);
}
}
};
@ -3401,7 +3463,7 @@ var Choices = /** @class */ (function () {
if (notice && notice.type === NoticeTypes.noChoices) {
this._clearNotice();
}
this.passedElement.triggerEvent(EventType.removeItem, this._getChoiceForOutput(item));
this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));
};
Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {
if (withEvents === void 0) { withEvents = true; }
@ -3516,24 +3578,24 @@ var Choices = /** @class */ (function () {
containerInner.wrap(passedElement.element);
// Wrapper inner container with outer container
containerOuter.wrap(containerInner.element);
if (this._isSelectOneElement) {
this.input.placeholder = this.config.searchPlaceholderValue || '';
}
else {
if (this._placeholderValue) {
this.input.placeholder = this._placeholderValue;
}
this.input.setWidth();
}
containerOuter.element.appendChild(containerInner.element);
containerOuter.element.appendChild(dropdownElement);
containerInner.element.appendChild(this.itemList.element);
dropdownElement.appendChild(this.choiceList.element);
if (!this._isSelectOneElement) {
containerInner.element.appendChild(this.input.element);
if (this._isSelectOneElement) {
this.input.placeholder = this.config.searchPlaceholderValue || '';
if (this.config.searchEnabled) {
dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);
}
}
else if (this.config.searchEnabled) {
dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);
else {
if (!this._isSelectMultipleElement || this.config.searchEnabled) {
containerInner.element.appendChild(this.input.element);
}
if (this._placeholderValue) {
this.input.placeholder = this._placeholderValue;
}
this.input.setWidth();
}
this._highlightPosition = 0;
this._isSearching = false;
@ -3616,7 +3678,7 @@ var Choices = /** @class */ (function () {
throw new TypeError("".concat(caller, " called for an element which has multiple instances of Choices initialised on it"));
}
};
Choices.version = '11.1.0';
Choices.version = '11.2.0';
return Choices;
}());