Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow deselect when renderSelectedChoices enabled #1221

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 47 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,14 @@ From a [CDN](https://www.jsdelivr.com/package/npm/choices.js):

```html
<!-- Include base CSS (optional) -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/base.min.css"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/base.min.css" />
<!-- Or versioned -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/base.min.css"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/base.min.css" />

<!-- Include Choices CSS -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css" />
<!-- Or versioned -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/choices.min.css"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/choices.min.css" />

<!-- Include Choices JavaScript (latest) -->
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
Expand All @@ -111,13 +99,15 @@ Or include Choices directly:
The use of `import` of css/scss is supported from webpack.

In .scss:

```scss
@import "choices.js/src/styles/choices";
@import 'choices.js/src/styles/choices';
```

In .js/.ts:

```javascript
import "choices.js/public/assets/styles/choices.css";
import 'choices.js/public/assets/styles/choices.css';
```

## Setup
Expand Down Expand Up @@ -246,11 +236,11 @@ import "choices.js/public/assets/styles/choices.css";

Choices works with the following input types, referenced in the documentation as noted.

| HTML Element | Documentation "Input Type" |
| -------------------------------------------------------------------------------------------------------| -------------------------- |
| [`<input type="text">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) | `text` |
| [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select) | `select-one` |
| [`<select multiple>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#attr-multiple) | `select-multiple` |
| HTML Element | Documentation "Input Type" |
| ----------------------------------------------------------------------------------------------------- | -------------------------- |
| [`<input type="text">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input) | `text` |
| [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select) | `select-one` |
| [`<select multiple>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#attr-multiple) | `select-multiple` |

## Configuration Options

Expand Down Expand Up @@ -356,13 +346,22 @@ Pass an array of objects:

**Usage:** The amount of items a user can input/select ("-1" indicates no limit).

### renderItems

**Type:** `Boolean` **Default:** `true`

**Input types affected:** `text`, `select-multiple`

**Usage:** Whether to render items.

### closeDropdownOnSelect

**Type:** `Boolean` | 'auto' **Default:** `auto`

**Input types affected:** select-one, select-multiple

**Usage:** Control how the dropdown closes after making a selection for select-one or select-multiple.

- 'auto' defaults based on backing-element type:
- select-one: true
- select-multiple: false
Expand All @@ -376,6 +375,7 @@ Pass an array of objects:
**Usage:** Make select-multiple with a max item count of 1 work similar to select-one does. Selecting an item will auto-close the dropdown and swap any existing item for the just selected choice. If applied to a select-one, it functions as above and not the standard select-one.

### addChoices

**Type**: `Boolean` **Default:** `false`

**Input types affected:** `select-multiple`, `select-one`
Expand Down Expand Up @@ -502,7 +502,7 @@ Pass an array of objects:

**Input types affected:** `select-one`, `select-multiple`

**Usage:** The maximum amount of search results to show ("-1" indicates no limit).
**Usage:** The maximum amount of search results to show ("-1" indicates no limit).

### shadowRoot

Expand Down Expand Up @@ -838,34 +838,32 @@ or more complex:

```js
const example = new Choices(element, {
callbackOnCreateTemplates: function(strToEl, escapeForTemplate, getClassNames) {
callbackOnCreateTemplates: function (strToEl, escapeForTemplate, getClassNames) {
return {
item: ({ classNames }, data) => {
return template(`
<div class="${getClassNames(classNames.item).join(' ')} ${
getClassNames(data.highlighted
? classNames.highlightedState
: classNames.itemSelectable).join(' ')
} ${
data.placeholder ? classNames.placeholder : ''
}" data-item data-id="${data.id}" data-value="${escapeForTemplate(data.value)}" ${
data.active ? 'aria-selected="true"' : ''
} ${data.disabled ? 'aria-disabled="true"' : ''}>
<div class="${getClassNames(classNames.item).join(' ')} ${getClassNames(
data.highlighted ? classNames.highlightedState : classNames.itemSelectable,
).join(' ')} ${
data.placeholder ? classNames.placeholder : ''
}" data-item data-id="${data.id}" data-value="${escapeForTemplate(data.value)}" ${
data.active ? 'aria-selected="true"' : ''
} ${data.disabled ? 'aria-disabled="true"' : ''}>
<span>&bigstar;</span> ${escapeForTemplate(data.label)}
</div>
`);
},
choice: ({ classNames }, data) => {
return template(`
<div class="${getClassNames(classNames.item).join(' ')} ${getClassNames(classNames.itemChoice).join(' ')} ${
getClassNames(data.disabled ? classNames.itemDisabled : classNames.itemSelectable).join(' ')
}" data-select-text="${this.config.itemSelectText}" data-choice ${
data.disabled
? 'data-choice-disabled aria-disabled="true"'
: 'data-choice-selectable'
} data-id="${data.id}" data-value="${escapeForTemplate(data.value)}" ${
data.groupId > 0 ? 'role="treeitem"' : 'role="option"'
}>
<div class="${getClassNames(classNames.item).join(' ')} ${getClassNames(classNames.itemChoice).join(' ')} ${getClassNames(
data.disabled ? classNames.itemDisabled : classNames.itemSelectable,
).join(
' ',
)}" data-select-text="${this.config.itemSelectText}" data-deselect-text="${this.config.itemDeselectText}" data-choice ${
data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'
} data-id="${data.id}" data-value="${escapeForTemplate(data.value)}" ${
data.groupId > 0 ? 'role="treeitem"' : 'role="option"'
}>
<span>&bigstar;</span> ${escapeForTemplate(data.label)}
</div>
`);
Expand All @@ -887,7 +885,7 @@ const example = new Choices(element);

element.addEventListener(
'addItem',
function(event) {
function (event) {
// do something creative here...
console.log(event.detail.id);
console.log(event.detail.value);
Expand All @@ -903,7 +901,7 @@ const example = new Choices(document.getElementById('example'));

example.passedElement.element.addEventListener(
'addItem',
function(event) {
function (event) {
// do something creative here...
console.log(event.detail.id);
console.log(event.detail.value);
Expand Down Expand Up @@ -1303,7 +1301,7 @@ https://www.jetbrains.com/help/phpstorm/playwright.html
### NPM tasks

| Task | Usage |
|---------------------------|--------------------------------------------------------------|
| ------------------------- | ------------------------------------------------------------ |
| `npm run start` | Fire up local server for development |
| `npm run test:unit` | Run sequence of tests once |
| `npm run test:unit:watch` | Fire up test server and re-test on file change |
Expand All @@ -1315,27 +1313,28 @@ https://www.jetbrains.com/help/phpstorm/playwright.html
| `npm run css:watch` | Watch SCSS files for changes. On a change, run build process |
| `npm run css:build` | Compile, minify and prefix SCSS files to CSS |


### Build flags

Choices supports various environment variables as build-flags to enable/disable features.
The pre-built bundles these features set, and tree shaking uses the non-used parts.

#### CHOICES_SEARCH_FUSE

**Values:** `full` / `basic` / `null`
**Default:** `full`

Fuse.js support a `full`/`basic` profile. `full` adds additional logic operations, which aren't used by default with Choices. The `null` option drops Fuse.js as a dependency and instead uses a simple prefix only search feature.

#### CHOICES_CAN_USE_DOM

**Values:** `1` / `0`
**Default:** `1`

Allows loading Choices into a non-browser environment.

### Interested in contributing?

We're always interested in having more active maintainers. Please get in touch if you're interested 👍
We're always interested in having more active maintainers. Please get in touch if you're interested 👍

## License

Expand Down
38 changes: 24 additions & 14 deletions public/assets/scripts/choices.js
Original file line number Diff line number Diff line change
Expand Up @@ -757,11 +757,15 @@
}
return undefined;
};
var mapInputToChoice = function (value, allowGroup) {
var mapInputToChoice = function (value, allowGroup, allowRawString) {
if (allowRawString === void 0) { allowRawString = true; }
if (typeof value === 'string') {
var sanitisedValue = sanitise(value);
var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };
var result_1 = mapInputToChoice({
value: value,
label: value,
label: userValue,
selected: true,
}, false);
return result_1;
}
Expand Down Expand Up @@ -932,6 +936,7 @@
silent: false,
renderChoiceLimit: -1,
maxItemCount: -1,
renderItems: true,
closeDropdownOnSelect: 'auto',
singleModeForMultiSelect: false,
addChoices: false,
Expand Down Expand Up @@ -967,6 +972,7 @@
noResultsText: 'No results found',
noChoicesText: 'No choices to choose from',
itemSelectText: 'Press to select',
itemDeselectText: 'Press to deselect',
uniqueItemText: 'Only unique values can be added',
customAddItemText: 'Only values matching specific conditions can be added',
addItemText: function (value) { return "Press Enter to add <b>\"".concat(value, "\"</b>"); },
Expand Down Expand Up @@ -3170,7 +3176,7 @@
div.appendChild(heading);
return div;
},
choice: function (_a, choice, selectText, groupName) {
choice: function (_a, choice, selectText, deselectText, groupName) {
var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;
// eslint-disable-next-line prefer-destructuring
var label = choice.label;
Expand Down Expand Up @@ -3217,6 +3223,9 @@
if (selectText) {
div.dataset.selectText = selectText;
}
if (deselectText) {
div.dataset.deselectText = deselectText;
}
if (choice.group) {
div.dataset.groupId = "".concat(choice.group.id);
}
Expand Down Expand Up @@ -3969,7 +3978,7 @@
this._renderChoices();
}
}
if (changes.items) {
if (changes.items && this.config.renderItems) {
this._renderItems();
}
};
Expand Down Expand Up @@ -4014,7 +4023,7 @@
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, config.itemDeselectText, groupLabel);
choice.choiceEl = dropdownItem;
fragment.appendChild(dropdownItem);
if (!choice.disabled && (isSearching || !choice.selected)) {
Expand Down Expand Up @@ -4056,7 +4065,7 @@
renderChoices(renderableChoices(activeChoices), false, undefined);
}
}
if (!selectableChoices) {
if (!selectableChoices && !config.renderSelectedChoices) {
if (!this._notice) {
this._notice = {
text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),
Expand Down Expand Up @@ -4280,6 +4289,12 @@
});
this._triggerChange(choice.value);
}
else if (this.config.renderSelectedChoices && this._isSelectMultipleElement) {
this._store.withTxn(function () {
_this._removeItem(choice);
});
this._triggerChange(choice.value);
}
// We want to close the dropdown if we are dealing with a single select box
if (hasActiveDropdown && this.config.closeDropdownOnSelect) {
this.hideDropdown(true);
Expand Down Expand Up @@ -4312,6 +4327,7 @@
};
Choices.prototype._loadChoices = function () {
var _a;
var _this = this;
var config = this.config;
if (this._isTextElement) {
// Assign preset items from passed object first
Expand All @@ -4320,7 +4336,7 @@
if (this.passedElement.value) {
var elementItems = this.passedElement.value
.split(config.delimiter)
.map(function (e) { return mapInputToChoice(e, false); });
.map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });
this._presetChoices = this._presetChoices.concat(elementItems);
}
this._presetChoices.forEach(function (choice) {
Expand Down Expand Up @@ -4672,13 +4688,7 @@
if (!_this._canCreateItem(value)) {
return;
}
var sanitisedValue = sanitise(value);
var userValue = _this.config.allowHtmlUserInput || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };
_this._addChoice(mapInputToChoice({
value: userValue,
label: userValue,
selected: true,
}, false), true, true);
_this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);
addedItem = true;
}
_this.clearInput();
Expand Down
2 changes: 1 addition & 1 deletion public/assets/scripts/choices.min.js

Large diffs are not rendered by default.

Loading
Loading