* Housekeeping

* Resolve placeholder bug + hide from choice list

* Restructure test folder

* Update cypress test to assert one placeholder

* Fix breaking e2e test

* Remove ability to pass placeholder via config for select boxes

* Add further e2e tests covering placeholders

* Add unit tests for _generatePlaceholderValue

* Display placeholder choice for select one

* Add further e2e test to assert on placeholder ordering

* Add labels to exclude from draft releases

* Add failure case to e2e test workflow

* Resolve broken e2e test

* Update puppeteer snapshot baseline
This commit is contained in:
Josh Johnson 2019-11-02 13:49:33 +00:00 committed by GitHub
parent 939a73b762
commit a0fe05f926
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 398 additions and 70 deletions

BIN
.github/actions-scripts/__snapshots__/puppeteer-darwin.png vendored Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 264 KiB

View file

@ -1,6 +1,9 @@
name-template: 'Draft (next release)' name-template: 'Draft (next release)'
tag-template: 'v$NEXT_PATCH_VERSION' tag-template: 'v$NEXT_PATCH_VERSION'
sort-direction: descending sort-direction: descending
exclude-labels:
- 'skip-changelog'
- 'release'
categories: categories:
- title: '🚨 Breaking changes' - title: '🚨 Breaking changes'
labels: labels:

View file

@ -29,7 +29,7 @@ jobs:
env: env:
HUSKY_SKIP_INSTALL: true HUSKY_SKIP_INSTALL: true
- name: run Cypress CI - name: run Cypress (with recording)
run: npx run-p --race start cypress:ci run: npx run-p --race start cypress:ci
env: env:
CI: true CI: true
@ -41,3 +41,18 @@ jobs:
COMMIT_INFO_BRANCH: ${{ github.head_ref }} COMMIT_INFO_BRANCH: ${{ github.head_ref }}
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }} COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }}
COMMIT_INFO_SHA: ${{ github.event.after }} COMMIT_INFO_SHA: ${{ github.event.after }}
# if we have ran out of free Cypress recordings, run Cypress with recording switched off
- name: run Cypress (without recording)
if: failure()
run: npx run-p --race start cypress:run
env:
CI: true
TERM: xterm-256color
NODE_ENV: production # prevent watching
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
DEBUG: commit-info,cypress:server:record
# https://docs.cypress.io/guides/guides/continuous-integration.html#Environment-variables
COMMIT_INFO_BRANCH: ${{ github.head_ref }}
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }}
COMMIT_INFO_SHA: ${{ github.event.after }}

View file

@ -1,4 +1,4 @@
name: Release management name: Release drafter
on: on:
push: push:
@ -9,6 +9,6 @@ jobs:
update-draft-release: update-draft-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: toolmantim/release-drafter@v5.2.0 - uses: toolmantim/release-drafter@v5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -431,11 +431,11 @@ const example = new Choices(element, {
**Type:** `Boolean` **Default:** `true` **Type:** `Boolean` **Default:** `true`
**Input types affected:** `text`, `select-multiple` **Input types affected:** `text`
**Usage:** Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value. **Usage:** Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value.
**Note:** For single select boxes, the recommended way of adding a placeholder is as follows: **Note:** For select boxes, the recommended way of adding a placeholder is as follows:
```html ```html
<select> <select>

View file

@ -1,6 +1,6 @@
describe('Choices - select multiple', () => { describe('Choices - select multiple', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/select-multiple.html'); cy.visit('/select-multiple');
}); });
describe('scenarios', () => { describe('scenarios', () => {
@ -486,20 +486,42 @@ describe('Choices - select multiple', () => {
}); });
}); });
describe('placeholder', () => { describe('placeholder via empty option value', () => {
/*
{
placeholder: true,
placeholderValue: 'I am a placeholder',
}
*/
describe('when no value has been inputted', () => { describe('when no value has been inputted', () => {
it('displays a placeholder', () => { it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder]') cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned') .find('.choices__input--cloned')
.should('have.attr', 'placeholder', 'I am a placeholder'); .should('have.attr', 'placeholder', 'I am a placeholder');
}); });
}); });
describe('when a value has been inputted', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.type('test')
.should('not.have.value', 'I am a placeholder');
});
});
});
describe('placeholder via option attribute', () => {
describe('when no value has been inputted', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.should('have.attr', 'placeholder', 'I am a placeholder');
});
});
describe('when a value has been inputted', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.type('test')
.should('not.have.value', 'I am a placeholder');
});
});
}); });
describe('remote data', () => { describe('remote data', () => {

View file

@ -1,6 +1,6 @@
describe('Choices - select one', () => { describe('Choices - select one', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/select-one.html'); cy.visit('/select-one');
}); });
describe('scenarios', () => { describe('scenarios', () => {
@ -448,6 +448,102 @@ describe('Choices - select one', () => {
}); });
}); });
describe('placeholder via empty option value', () => {
describe('when no choice has been selected', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--single')
.children()
.first()
.should('have.class', 'choices__placeholder')
.and($placeholder => {
expect($placeholder).to.contain('I am a placeholder');
});
});
});
describe('when a choice has been selected', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.click();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.should('not.have.value', 'I am a placeholder');
});
});
describe('when choice list is open', () => {
it('displays the placeholder choice first', () => {
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-value]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should('have.class', 'choices__placeholder')
.should('have.text', 'I am a placeholder');
});
});
});
describe('placeholder via option attribute', () => {
describe('when no choice has been selected', () => {
it('displays a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--single')
.children()
.first()
.should('have.class', 'choices__placeholder')
.and($placeholder => {
expect($placeholder).to.contain('I am a placeholder');
});
});
});
describe('when a choice has been selected', () => {
it('does not display a placeholder', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.click();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.should('not.have.value', 'I am a placeholder');
});
});
describe('when choice list is open', () => {
it('displays the placeholder choice first', () => {
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__input--cloned')
.focus();
cy.get('[data-test-hook=placeholder-via-option-attr]')
.find('.choices__list--dropdown .choices__list')
.children()
.first()
.should('have.class', 'choices__placeholder')
.should('have.text', 'I am a placeholder');
});
});
});
describe('remote data', () => { describe('remote data', () => {
beforeEach(() => { beforeEach(() => {
cy.reload(true); cy.reload(true);
@ -458,6 +554,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remote-data]') cy.get('[data-test-hook=remote-data]')
.find('.choices__list--single') .find('.choices__list--single')
.children() .children()
.should('have.length', 1)
.first() .first()
.should('have.class', 'choices__placeholder') .should('have.class', 'choices__placeholder')
.and($placeholder => { .and($placeholder => {
@ -483,10 +580,14 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=remote-data]') cy.get('[data-test-hook=remote-data]')
.find('.choices__list--dropdown .choices__list') .find('.choices__list--dropdown .choices__list')
.children() .children()
.should('have.length', 50) .should('have.length', 51) // 50 choices + 1 placeholder choice
.each(($choice, index) => { .each(($choice, index) => {
expect($choice.text().trim()).to.equal(`Label ${index + 1}`); if (index === 0) {
expect($choice.data('value')).to.equal(`Value ${index + 1}`); expect($choice.text().trim()).to.equal('I am a placeholder');
} else {
expect($choice.text().trim()).to.equal(`Label ${index}`);
expect($choice.data('value')).to.equal(`Value ${index}`);
}
}); });
}); });
}); });

View file

@ -1,6 +1,6 @@
describe('Choices - text element', () => { describe('Choices - text element', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/text.html'); cy.visit('/text');
}); });
describe('scenarios', () => { describe('scenarios', () => {

View file

@ -218,7 +218,7 @@
} }
.choices__list--dropdown { .choices__list--dropdown {
display: none; visibility: hidden;
z-index: 1; z-index: 1;
position: absolute; position: absolute;
width: 100%; width: 100%;
@ -230,10 +230,11 @@
border-bottom-right-radius: 2.5px; border-bottom-right-radius: 2.5px;
overflow: hidden; overflow: hidden;
word-break: break-all; word-break: break-all;
will-change: visibility;
} }
.choices__list--dropdown.is-active { .choices__list--dropdown.is-active {
display: block; visibility: visible;
} }
.is-open .choices__list--dropdown { .is-open .choices__list--dropdown {

File diff suppressed because one or more lines are too long

View file

@ -15,43 +15,46 @@
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="../assets/images/apple-touch-icon.png" href="../../assets/images/apple-touch-icon.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-32x32.png" href="../../assets/images/favicon-32x32.png"
sizes="32x32" sizes="32x32"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-16x16.png" href="../../assets/images/favicon-16x16.png"
sizes="16x16" sizes="16x16"
/> />
<link rel="manifest" href="../assets/images/manifest.json" /> <link rel="manifest" href="../../assets/images/manifest.json" />
<link <link
rel="mask-icon" rel="mask-icon"
href="../assets/images/safari-pinned-tab.svg" href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4" color="#00bcd4"
/> />
<link rel="shortcut icon" href="../assets/images/favicon.ico" /> <link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta <meta
name="msapplication-config" name="msapplication-config"
content="../assets/images/browserconfig.xml" content="../../assets/images/browserconfig.xml"
/> />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<!-- Ignore these --> <!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3" /> <link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<!-- End ignore these --> <!-- End ignore these -->
<!-- Choices includes --> <!-- Choices includes -->
<link <link
rel="stylesheet" rel="stylesheet"
href="../assets/styles/choices.min.css?version=6.0.3" href="../../assets/styles/choices.min.css?version=6.0.3"
/> />
<script src="../assets/scripts/choices.min.js?version=6.0.3"></script> <script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<!-- End Choices includes --> <!-- End Choices includes -->
</head> </head>
@ -194,14 +197,34 @@
</select> </select>
</div> </div>
<div data-test-hook="placeholder"> <div data-test-hook="placeholder-via-option-value">
<label for="choices-placeholder">Placeholder</label> <label for="choices-placeholder-via-option-value"
>Placeholder via empty option value</label
>
<select <select
class="form-control" class="form-control"
name="choices-placeholder" name="choices-placeholder-via-option-value"
id="choices-placeholder" id="choices-placeholder-via-option-value"
multiple multiple
> >
<option value="">I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-attr">
<label for="choices-placeholder-via-option-attr"
>Placeholder via option attribute</label
>
<select
class="form-control"
name="choices-placeholder-via-option-attr"
id="choices-placeholder-via-option-attr"
multiple
>
<option placeholder>I am a placeholder</option>
<option value="Choice 1">Choice 1</option> <option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option> <option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option> <option value="Choice 3">Choice 3</option>
@ -215,7 +238,9 @@
name="choices-remote-data" name="choices-remote-data"
id="choices-remote-data" id="choices-remote-data"
multiple multiple
></select> >
<option value="">I am a placeholder</option>
</select>
</div> </div>
<div data-test-hook="scrolling-dropdown"> <div data-test-hook="scrolling-dropdown">
@ -373,10 +398,9 @@
searchFloor: 5, searchFloor: 5,
}); });
new Choices('#choices-placeholder', { new Choices('#choices-placeholder-via-option-value');
placeholder: true,
placeholderValue: 'I am a placeholder', new Choices('#choices-placeholder-via-option-attr');
});
new Choices('#choices-remote-data', { new Choices('#choices-remote-data', {
shouldSort: false, shouldSort: false,

View file

@ -15,43 +15,46 @@
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="../assets/images/apple-touch-icon.png" href="../../assets/images/apple-touch-icon.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-32x32.png" href="../../assets/images/favicon-32x32.png"
sizes="32x32" sizes="32x32"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-16x16.png" href="../../assets/images/favicon-16x16.png"
sizes="16x16" sizes="16x16"
/> />
<link rel="manifest" href="../assets/images/manifest.json" /> <link rel="manifest" href="../../assets/images/manifest.json" />
<link <link
rel="mask-icon" rel="mask-icon"
href="../assets/images/safari-pinned-tab.svg" href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4" color="#00bcd4"
/> />
<link rel="shortcut icon" href="../assets/images/favicon.ico" /> <link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta <meta
name="msapplication-config" name="msapplication-config"
content="../assets/images/browserconfig.xml" content="../../assets/images/browserconfig.xml"
/> />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<!-- Ignore these --> <!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3" /> <link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<!-- End ignore these --> <!-- End ignore these -->
<!-- Choices includes --> <!-- Choices includes -->
<link <link
rel="stylesheet" rel="stylesheet"
href="../assets/styles/choices.min.css?version=6.0.3" href="../../assets/styles/choices.min.css?version=6.0.3"
/> />
<script src="../assets/scripts/choices.min.js?version=6.0.3"></script> <script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<!-- End Choices includes --> <!-- End Choices includes -->
</head> </head>
@ -178,13 +181,47 @@
</select> </select>
</div> </div>
<div data-test-hook="placeholder-via-option-value">
<label for="choices-placeholder-via-option-value"
>Placeholder via empty option value</label
>
<select
class="form-control"
name="choices-placeholder-via-option-value"
id="choices-placeholder-via-option-value"
>
<option value="">I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="placeholder-via-option-attr">
<label for="choices-placeholder-via-option-attr"
>Placeholder via option attribute</label
>
<select
class="form-control"
name="choices-placeholder-via-option-attr"
id="choices-placeholder-via-option-attr"
>
<option placeholder>I am a placeholder</option>
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div data-test-hook="remote-data"> <div data-test-hook="remote-data">
<label for="choices-remote-data">Remote data</label> <label for="choices-remote-data">Remote data</label>
<select <select
class="form-control" class="form-control"
name="choices-remote-data" name="choices-remote-data"
id="choices-remote-data" id="choices-remote-data"
></select> >
<option value="">I am a placeholder</option>
</select>
</div> </div>
<div data-test-hook="scrolling-dropdown"> <div data-test-hook="scrolling-dropdown">
@ -359,6 +396,10 @@
searchFloor: 5, searchFloor: 5,
}); });
new Choices('#choices-placeholder-via-option-value');
new Choices('#choices-placeholder-via-option-attr');
new Choices('#choices-remote-data', { new Choices('#choices-remote-data', {
shouldSort: false, shouldSort: false,
}).setChoices(async () => { }).setChoices(async () => {

View file

@ -15,43 +15,46 @@
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="../assets/images/apple-touch-icon.png" href="../../assets/images/apple-touch-icon.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-32x32.png" href="../../assets/images/favicon-32x32.png"
sizes="32x32" sizes="32x32"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
href="../assets/images/favicon-16x16.png" href="../../assets/images/favicon-16x16.png"
sizes="16x16" sizes="16x16"
/> />
<link rel="manifest" href="../assets/images/manifest.json" /> <link rel="manifest" href="../../assets/images/manifest.json" />
<link <link
rel="mask-icon" rel="mask-icon"
href="../assets/images/safari-pinned-tab.svg" href="../../assets/images/safari-pinned-tab.svg"
color="#00bcd4" color="#00bcd4"
/> />
<link rel="shortcut icon" href="../assets/images/favicon.ico" /> <link rel="shortcut icon" href="../../assets/images/favicon.ico" />
<meta <meta
name="msapplication-config" name="msapplication-config"
content="../assets/images/browserconfig.xml" content="../../assets/images/browserconfig.xml"
/> />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<!-- Ignore these --> <!-- Ignore these -->
<link rel="stylesheet" href="../assets/styles/base.min.css?version=6.0.3" /> <link
rel="stylesheet"
href="../../assets/styles/base.min.css?version=6.0.3"
/>
<!-- End ignore these --> <!-- End ignore these -->
<!-- Choices includes --> <!-- Choices includes -->
<link <link
rel="stylesheet" rel="stylesheet"
href="../assets/styles/choices.min.css?version=6.0.3" href="../../assets/styles/choices.min.css?version=6.0.3"
/> />
<script src="../assets/scripts/choices.min.js?version=6.0.3"></script> <script src="../../assets/scripts/choices.min.js?version=6.0.3"></script>
<!-- End Choices includes --> <!-- End Choices includes -->
</head> </head>

View file

@ -149,6 +149,7 @@ class Choices {
* @type {HTMLElement['dir']} * @type {HTMLElement['dir']}
*/ */
this._direction = this.passedElement.element.dir; this._direction = this.passedElement.element.dir;
if (!this._direction) { if (!this._direction) {
const { direction: elementDirection } = window.getComputedStyle( const { direction: elementDirection } = window.getComputedStyle(
this.passedElement.element, this.passedElement.element,
@ -160,6 +161,7 @@ class Choices {
this._direction = elementDirection; this._direction = elementDirection;
} }
} }
this._idNames = { this._idNames = {
itemChoice: 'item-choice', itemChoice: 'item-choice',
}; };
@ -849,7 +851,9 @@ class Choices {
let choiceLimit = rendererableChoices.length; let choiceLimit = rendererableChoices.length;
// Prepend placeholeder // Prepend placeholeder
const sortedChoices = [...placeholderChoices, ...normalChoices]; const sortedChoices = this._isSelectOneElement
? [...placeholderChoices, ...normalChoices]
: normalChoices;
if (this._isSearching) { if (this._isSearching) {
choiceLimit = searchResultLimit; choiceLimit = searchResultLimit;
@ -2075,7 +2079,7 @@ class Choices {
label: o.innerHTML, label: o.innerHTML,
selected: o.selected, selected: o.selected,
disabled: o.disabled || o.parentNode.disabled, disabled: o.disabled || o.parentNode.disabled,
placeholder: o.hasAttribute('placeholder'), placeholder: o.value === '' || o.hasAttribute('placeholder'),
customProperties: o.getAttribute('data-custom-properties'), customProperties: o.getAttribute('data-custom-properties'),
}); });
}); });
@ -2224,14 +2228,28 @@ class Choices {
} }
_generatePlaceholderValue() { _generatePlaceholderValue() {
if (this._isSelectOneElement) { if (this._isSelectElement) {
return false; const { placeholderOption } = this.passedElement;
return placeholderOption ? placeholderOption.text : false;
} }
return this.config.placeholder const { placeholder, placeholderValue } = this.config;
? this.config.placeholderValue || const {
this.passedElement.element.getAttribute('placeholder') element: { dataset },
: false; } = this.passedElement;
if (placeholder) {
if (placeholderValue) {
return placeholderValue;
}
if (dataset.placeholder) {
return dataset.placeholder;
}
}
return false;
} }
/* ===== End of Private functions ====== */ /* ===== End of Private functions ====== */

View file

@ -1873,5 +1873,96 @@ describe('choices', () => {
}); });
}); });
}); });
describe('_generatePlaceholderValue', () => {
describe('select element', () => {
describe('when a placeholder option is defined', () => {
it('returns the text value of the placeholder option', () => {
const placeholderValue = 'I am a placeholder';
instance._isSelectElement = true;
instance.passedElement.placeholderOption = {
text: placeholderValue,
};
const value = instance._generatePlaceholderValue();
expect(value).to.equal(placeholderValue);
});
});
describe('when a placeholder option is not defined', () => {
it('returns false', () => {
instance._isSelectElement = true;
instance.passedElement.placeholderOption = undefined;
const value = instance._generatePlaceholderValue();
expect(value).to.equal(false);
});
});
});
describe('text input', () => {
describe('when the placeholder config option is set to true', () => {
describe('when the placeholderValue config option is defined', () => {
it('returns placeholderValue', () => {
const placeholderValue = 'I am a placeholder';
instance._isSelectElement = false;
instance.config.placeholder = true;
instance.config.placeholderValue = placeholderValue;
const value = instance._generatePlaceholderValue();
expect(value).to.equal(placeholderValue);
});
});
describe('when the placeholderValue config option is not defined', () => {
describe('when the placeholder attribute is defined on the passed element', () => {
it('returns the value of the placeholder attribute', () => {
const placeholderValue = 'I am a placeholder';
instance._isSelectElement = false;
instance.config.placeholder = true;
instance.config.placeholderValue = undefined;
instance.passedElement.element = {
dataset: {
placeholder: placeholderValue,
},
};
const value = instance._generatePlaceholderValue();
expect(value).to.equal(placeholderValue);
});
});
describe('when the placeholder attribute is not defined on the passed element', () => {
it('returns false', () => {
instance._isSelectElement = false;
instance.config.placeholder = true;
instance.config.placeholderValue = undefined;
instance.passedElement.element = {
dataset: {
placeholder: undefined,
},
};
const value = instance._generatePlaceholderValue();
expect(value).to.equal(false);
});
});
});
});
describe('when the placeholder config option is set to false', () => {
it('returns false', () => {
instance._isSelectElement = false;
instance.config.placeholder = false;
const value = instance._generatePlaceholderValue();
expect(value).to.equal(false);
});
});
});
});
}); });
}); });

View file

@ -39,16 +39,19 @@ export const TEMPLATES = /** @type {Templates} */ ({
return div; return div;
}, },
containerInner({ containerInner }) { containerInner({ containerInner }) {
return Object.assign(document.createElement('div'), { return Object.assign(document.createElement('div'), {
className: containerInner, className: containerInner,
}); });
}, },
itemList({ list, listSingle, listItems }, isSelectOneElement) { itemList({ list, listSingle, listItems }, isSelectOneElement) {
return Object.assign(document.createElement('div'), { return Object.assign(document.createElement('div'), {
className: `${list} ${isSelectOneElement ? listSingle : listItems}`, className: `${list} ${isSelectOneElement ? listSingle : listItems}`,
}); });
}, },
placeholder({ placeholder }, value) { placeholder({ placeholder }, value) {
return Object.assign(document.createElement('div'), { return Object.assign(document.createElement('div'), {
className: placeholder, className: placeholder,
@ -93,6 +96,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
if (isPlaceholder) { if (isPlaceholder) {
div.classList.add(placeholder); div.classList.add(placeholder);
} }
div.classList.add(highlighted ? highlightedState : itemSelectable); div.classList.add(highlighted ? highlightedState : itemSelectable);
if (removeItemButton) { if (removeItemButton) {
@ -117,6 +121,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
return div; return div;
}, },
choiceList({ list }, isSelectOneElement) { choiceList({ list }, isSelectOneElement) {
const div = Object.assign(document.createElement('div'), { const div = Object.assign(document.createElement('div'), {
className: list, className: list,
@ -196,6 +201,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
return div; return div;
}, },
input({ input, inputCloned }, placeholderValue) { input({ input, inputCloned }, placeholderValue) {
const inp = Object.assign(document.createElement('input'), { const inp = Object.assign(document.createElement('input'), {
type: 'text', type: 'text',
@ -211,6 +217,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
return inp; return inp;
}, },
dropdown({ list, listDropdown }) { dropdown({ list, listDropdown }) {
const div = document.createElement('div'); const div = document.createElement('div');
@ -219,6 +226,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
return div; return div;
}, },
notice({ item, itemChoice, noResults, noChoices }, innerHTML, type = '') { notice({ item, itemChoice, noResults, noChoices }, innerHTML, type = '') {
const classes = [item, itemChoice]; const classes = [item, itemChoice];
@ -233,6 +241,7 @@ export const TEMPLATES = /** @type {Templates} */ ({
className: classes.join(' '), className: classes.join(' '),
}); });
}, },
option({ label, value, customProperties, active, disabled }) { option({ label, value, customProperties, active, disabled }) {
const opt = new Option(label, value, false, active); const opt = new Option(label, value, false, active);