replicated PR 525 from main repo

This commit is contained in:
Joe Workman 2023-04-28 13:12:48 -07:00
parent 5dbea2825a
commit 04977bae97
No known key found for this signature in database
GPG key ID: 52D9F1902936CAFE
8 changed files with 116 additions and 13 deletions

View file

@ -122,6 +122,7 @@ Or include Choices directly:
choices: [],
renderChoiceLimit: -1,
maxItemCount: -1,
addChoices: false,
addItems: true,
addItemFilter: null,
removeItems: true,
@ -304,6 +305,15 @@ Pass an array of objects:
**Usage:** The amount of items a user can input/select ("-1" indicates no limit).
### addChoices
**Type**: `Boolean` **Default:** `false`
**Input types affected:** `select-multiple`, `select-one`
**Usage:** Whether a user can add choices
**Note:** `addItems` must also be `true`
### addItems
**Type:** `Boolean` **Default:** `true`

View file

@ -1006,6 +1006,24 @@ describe('Choices - select multiple', () => {
});
});
});
describe('adding user-created choices', () => {
it('allows the user to add choices', () => {
const newChoice = 'New Choice';
cy.get('[data-test-hook=add-choices]')
.find('.choices__input--cloned')
.type(newChoice)
.type('{enter}');
cy.get('[data-test-hook=add-choices]')
.find('.choices__list--multiple')
.last()
.should($el => {
expect($el).to.contain(newChoice);
});
});
});
});
});
});

View file

@ -1145,5 +1145,26 @@ describe('Choices - select one', () => {
.should('have.length', 3);
});
});
describe('adding user-created choices', () => {
beforeEach(() => {
cy.get('[data-test-hook=add-choices]').find('.choices').click();
});
it('allows the user to add choices', () => {
const newChoice = 'New Choice';
cy.get('[data-test-hook=add-choices]')
.find('.choices__input--cloned')
.type(newChoice)
.type('{enter}');
cy.get('[data-test-hook=add-choices]')
.find('.choices__list--single .choices__item')
.should(($el) => {
expect($el).to.contain(newChoice);
});
});
});
});
});

View file

@ -397,6 +397,15 @@
multiple
></select>
</div>
<div data-test-hook="add-choices">
<label for="choices-add-choices">Add choices</label>
<select class="form-control" name="choices-add-choices" id="choices-add-choices" multiple>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
</div>
</div>
<script>
@ -622,6 +631,8 @@
},
],
});
new Choices('#choices-add-choices', { addChoices: true });
});
</script>
</body>

View file

@ -417,6 +417,16 @@
<button class="destroy">Destroy</button>
<button class="init">Init</button>
</div>
<div data-test-hook="add-choices">
<label for="choices-add-choices">Add choices</label>
<select class="form-control" name="choices-add-choices" id="choices-add-choices">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
</div>
</div>
<script>
@ -676,6 +686,8 @@
document.querySelector('button.init').addEventListener('click', () => {
newDestroyInitChoices.init();
});
new Choices('#choices-add-choices', { addChoices: true });
});
</script>
</body>

View file

@ -825,12 +825,12 @@ class Choices implements Choices {
);
}
// If we have choices to show
const { activeItems } = this._store; // If we have choices to show
if (
choiceListFragment.childNodes &&
choiceListFragment.childNodes.length > 0
) {
const { activeItems } = this._store;
const canAddItem = this._canAddItem(activeItems, this.input.value);
// ...and we can select them
@ -844,18 +844,21 @@ class Choices implements Choices {
}
} else {
// Otherwise show a notice
let dropdownItem;
let notice;
const canAddChoice = this._canAddChoice(activeItems, this.input.value);
if (this._isSearching) {
notice =
let dropdownItem;
if (canAddChoice.response) {
dropdownItem = this._getTemplate('notice', canAddChoice.notice);
} else if (this._isSearching) {
const notice =
typeof this.config.noResultsText === 'function'
? this.config.noResultsText()
: this.config.noResultsText;
dropdownItem = this._getTemplate('notice', notice, 'no-results');
} else {
notice =
const notice =
typeof this.config.noChoicesText === 'function'
? this.config.noChoicesText()
: this.config.noChoicesText;
@ -1260,6 +1263,14 @@ class Choices implements Choices {
}
}
_canAddChoice(activeItems: Item[], value: string): Notice {
const canAddItem = this._canAddItem(activeItems, value);
canAddItem.response = this.config.addChoices && canAddItem.response;
return canAddItem;
}
_canAddItem(activeItems: Item[], value: string): Notice {
let canAddItem = true;
let notice =
@ -1555,16 +1566,22 @@ class Choices implements Choices {
const { ENTER_KEY: enterKey } = KEY_CODES;
const targetWasButton =
target && (target as HTMLElement).hasAttribute('data-button');
let addedItem = false;
if (this._isTextElement && target && (target as HTMLInputElement).value) {
if (target && (target as HTMLInputElement).value) {
const { value } = this.input;
const canAddItem = this._canAddItem(activeItems, value);
const canAddChoice = this._canAddChoice(activeItems, value);
if (canAddItem.response) {
if (
(this._isTextElement && canAddItem.response) ||
(!this._isTextElement && canAddChoice.response)
) {
this.hideDropdown(true);
this._addItem({ value });
this._triggerChange(value);
this.clearInput();
addedItem = true;
}
}
@ -1579,11 +1596,15 @@ class Choices implements Choices {
);
if (highlightedChoice) {
// add enter keyCode value
if (activeItems[0]) {
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
if (addedItem) {
this.unhighlightAll();
} else {
if (activeItems[0]) {
// add enter keyCode value
activeItems[0].keyCode = enterKey; // eslint-disable-line no-param-reassign
}
this._handleChoiceAction(activeItems, highlightedChoice);
}
this._handleChoiceAction(activeItems, highlightedChoice);
}
event.preventDefault();

View file

@ -37,6 +37,7 @@ export const DEFAULT_CONFIG: Options = {
silent: false,
renderChoiceLimit: -1,
maxItemCount: -1,
addChoices: false,
addItems: true,
addItemFilter: null,
removeItems: true,

View file

@ -102,6 +102,15 @@ export interface Options {
*/
maxItemCount: number;
/**
* Whether a user can add choices dynamically.
*
* **Input types affected:** select-one, select-multiple
*
* @default false
*/
addChoices: boolean;
/**
* Whether a user can add items.
*