Skip to content

Commit

Permalink
Allow deselect when renderSelectedChoices enabled - also add renderItems
Browse files Browse the repository at this point in the history
  • Loading branch information
godismyjudge95 committed Oct 11, 2024
1 parent 5fa376b commit 953b0bb
Show file tree
Hide file tree
Showing 23 changed files with 303 additions and 161 deletions.
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._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

0 comments on commit 953b0bb

Please sign in to comment.