diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6b7b58b..cc3e217 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,11 +1,26 @@
# CHANGELOG
-## 10.3.5
+## 10.4.0
-`zoo-tooltip` - added CSS variable `zoo-tooltip-z-index` to change predefined z-index in case of conflict with some other 3rd party components
-`zoo-toast` - added CSS variable `zoo-toast-z-index` to change predefined z-index in case of conflict with some other 3rd party components
-`zoo-grid` - added CSS variable `zoo-grid-z-index` to change predefined z-index in case of conflict with some other 3rd party components
-`zoo-spinner` - added CSS variable `zoo-spinner-z-index` to change predefined z-index in case of conflict with some other 3rd party components
+Semi-Breaking Changes:
+ - `zoo-input-tag`:
+ - added `clearSelection()` method to programmatically clear current component selection
+ - `zoo-tag-options` can contain not only `zoo-tag` elements, but custom markup
+ - `zoo-tag-options` are now stacked vertically
+ - `zoo-tag-options` - changed left,right padding to `15px` and removed `5px` gap, `--input-tag-padding-top-bottom`
+ and `--input-tag-padding-left-right` to control component padding
+ - selection will be updated when `data-initial-value` attribute changes
+ - `--input-tag-options-max-height` CSS variable to control max height of options list overlay
+ - `--input-tag-options-overflow` CSS variable to control options list scrolls
+ - `zoo-tag` with `type="tag"` uses same border radius as other components
+
+ CSS changes:
+ - `--item-hovered` - new CSS variable to control color of hovered areas in components
+ - `--input-disabled` - new CSS variable to control color of disabled form components
+ - `zoo-tooltip` - new CSS variable `zoo-tooltip-z-index` to change predefined z-index in case of conflict with some other 3rd party components
+ - `zoo-toast` - new CSS variable `zoo-toast-z-index` to change predefined z-index in case of conflict with some other 3rd party components
+ - `zoo-grid` - new CSS variable `zoo-grid-z-index` to change predefined z-index in case of conflict with some other 3rd party components
+ - `zoo-spinner` - new CSS variable `zoo-spinner-z-index` to change predefined z-index in case of conflict with some other 3rd party components
## 10.3.4
diff --git a/docs/index.html b/docs/index.html
index 7ee1a6c..0568727 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -102,6 +102,7 @@
Input/Textarea
+
@@ -127,6 +128,42 @@ Input/Textarea
Birds are a group of warm-blooded vertebrates constituting the class Aves /ˈeɪviːz/, characterised by feathers, toothless beaked jaws, the laying of hard-shelled eggs, a high metabolic rate, a four-chambered heart, and a strong yet lightweight skeleton.
+
+
+ Reptile
+
+ Reptiles, in common parlance, are a group of tetrapods with an ectothermic ('cold-blooded') metabolism and amniotic development.
+
+ no results
+
+
+
+ Tag input & custom option list
+
+ Start typing to see available tags. Tag filtering should be done on client side by listening on 'input' event on slotted input.
+ At least one tag should be selected!
+
+
+
+
+
+
+
+
+ 🐕 Dog
+
+
+ 🐈 Cat
+
+
+ 🐦⬛ Bird
+
+
+ 🐟 Aquatic
+
+
+ 🦎 Reptile
+
no results
diff --git a/docs/main.js b/docs/main.js
index 61e10e0..abc955d 100644
--- a/docs/main.js
+++ b/docs/main.js
@@ -241,7 +241,7 @@ handleExpandAction('#row-1-actions .expander', '#row-1-content');
handleExpandAction('#row-2-actions .expander', '#row-2-content');
handleExpandAction('#row-3-actions .expander', '#row-3-content');
-const tagInfos = ['dog', 'cat', 'bird', 'aquatic'];
+const tagInfos = ['dog', 'cat', 'bird', 'aquatic', 'reptile'];
const inputTag = document.querySelector('zoo-input-tag');
document.getElementById('input-tag').addEventListener('input', e => {
inputTag.querySelectorAll('zoo-input-tag-option').forEach(o => o.style.display = 'none');
@@ -250,7 +250,6 @@ document.getElementById('input-tag').addEventListener('input', e => {
const val = e.target.value;
if (!val) return;
const matchedTags = tagInfos.filter(i => i.toLowerCase().indexOf(val.toLowerCase()) > -1);
- const docFrag = document.createDocumentFragment();
if (matchedTags && matchedTags.length > 0) {
matchedTags.forEach(m => {
document.getElementById(`${m}-tag`).style.display = 'flex';
@@ -258,4 +257,23 @@ document.getElementById('input-tag').addEventListener('input', e => {
} else {
noResultsSpan.style.display = 'flex';
}
-});
\ No newline at end of file
+});
+
+const customTagInput = document.getElementById('input-tag-custom-input');
+document.getElementById('input-tag-custom').addEventListener('input', e => {
+ customTagInput.querySelectorAll('zoo-input-tag-option').forEach(o => o.style.display = 'none');
+ const noResultsSpan = document.getElementById('input-tag-custom').querySelector('*[slot="no-results"]');
+ if (noResultsSpan) noResultsSpan.style.display = 'none';
+ const val = e.target.value;
+ if (!val) return;
+ const matchedTags = tagInfos.filter(i => i.toLowerCase().indexOf(val.toLowerCase()) > -1);
+ if (matchedTags && matchedTags.length > 0) {
+ matchedTags.forEach(m => {
+ document.getElementById(`${m}-tagc`).style.display = 'flex';
+ });
+ } else {
+ noResultsSpan.style.display = 'flex';
+ }
+ const unMatchedTags = tagInfos.filter(i => i.toLowerCase().indexOf(val.toLowerCase()) === -1);
+ unMatchedTags.forEach( m => document.getElementById(`${m}-tagc`).style.display = 'none')
+});
diff --git a/package-lock.json b/package-lock.json
index 980b398..483fa39 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@zooplus/zoo-web-components",
- "version": "10.3.4",
+ "version": "10.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@zooplus/zoo-web-components",
- "version": "10.3.4",
+ "version": "10.4.0",
"license": "MIT",
"devDependencies": {
"axe-core": "^4.3.3",
@@ -481,9 +481,9 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz",
- "integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.22.13",
diff --git a/package.json b/package.json
index 50330ef..ab71b66 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@zooplus/zoo-web-components",
- "version": "10.3.4",
+ "version": "10.4.0",
"main": "dist/zoo-web-components.js",
"sideEffects": false,
"files": [
diff --git a/src/zoo-modules/form/checkbox/checkbox.css b/src/zoo-modules/form/checkbox/checkbox.css
index 20cb587..9f0eb13 100644
--- a/src/zoo-modules/form/checkbox/checkbox.css
+++ b/src/zoo-modules/form/checkbox/checkbox.css
@@ -84,7 +84,7 @@ svg path {
}
:host([disabled]) svg {
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
}
.checkbox {
diff --git a/src/zoo-modules/form/input-tag/input-tag-option.css b/src/zoo-modules/form/input-tag/input-tag-option.css
index c63e595..3da54a9 100644
--- a/src/zoo-modules/form/input-tag/input-tag-option.css
+++ b/src/zoo-modules/form/input-tag/input-tag-option.css
@@ -7,7 +7,3 @@
font-size: 12px;
gap: 3px;
}
-
-:host(:hover) {
- background: var(--primary-ultralight);
-}
diff --git a/src/zoo-modules/form/input-tag/input-tag.css b/src/zoo-modules/form/input-tag/input-tag.css
index 02b3d38..ec1388d 100644
--- a/src/zoo-modules/form/input-tag/input-tag.css
+++ b/src/zoo-modules/form/input-tag/input-tag.css
@@ -4,6 +4,10 @@
width: 100%;
height: max-content;
box-sizing: border-box;
+
+ --input-tag-padding-top-bottom-default: 13px;
+ --input-tag-padding-left-right-default: 15px;
+ --input-tag-padding-reduced: calc(var(--input-tag-padding-top-bottom, var(--input-tag-padding-top-bottom-default)) - 1px) calc(var(--input-tag-padding-left-right, var(--input-tag-padding-left-right-default)) - 1px);
}
#input-wrapper {
@@ -14,7 +18,7 @@
gap: 5px;
font-size: 14px;
line-height: 20px;
- padding: 13px 15px;
+ padding: var(--input-tag-padding-top-bottom, var(--input-tag-padding-top-bottom-default)) var(--input-tag-padding-left-right, var(--input-tag-padding-left-right-default));
border: 1px solid #767676;
border-radius: 5px;
color: #555;
@@ -26,7 +30,7 @@
:host(:focus-within) #input-wrapper {
border: 2px solid #555;
- padding: 12px 14px;
+ padding: var(--input-tag-padding-reduced);
}
:host([show-tags]) #input-wrapper {
@@ -35,7 +39,7 @@
:host([invalid]) #input-wrapper {
border: 2px solid var(--warning-mid);
- padding: 12px 14px;
+ padding: var(--input-tag-padding-reduced);
}
::slotted(input) {
@@ -57,15 +61,16 @@ zoo-label {
position: absolute;
flex-wrap: wrap;
background: white;
- padding: 5px;
+ padding: 5px var(--input-tag-padding-left-right, var(--input-tag-padding-left-right-default));
border: 1px solid #555;
border-radius: 0 0 3px 3px;
- gap: 5px;
left: -1px;
- top: 90%;
+ top: calc(90% + 2px);
border-top: 0;
width: calc(100% + 2px);
box-sizing: border-box;
+ max-height: var(--input-tag-options-max-height, fit-content);
+ overflow: var(--input-tag-options-overflow, auto);
}
:host(:focus-within) #tag-options,
@@ -73,6 +78,8 @@ zoo-label {
border-width: 2px;
width: calc(100% + 4px);
left: -2px;
+ padding-left: calc(var(--input-tag-padding-left-right, var(--input-tag-padding-left-right-default)) - 1px);
+ padding-right: calc(var(--input-tag-padding-left-right, var(--input-tag-padding-left-right-default)) - 1px);
}
:host([invalid]) #tag-options {
@@ -98,5 +105,16 @@ zoo-cross-icon {
}
::slotted(zoo-input-tag-option) {
- flex: 1 0 30%;
+ box-sizing: border-box;
+ width: 100%;
}
+
+::slotted(zoo-input-tag-option:hover),
+::slotted(zoo-input-tag-option[selected]:hover) {
+ background: var(--item-hovered, #E6E6E6);
+}
+
+::slotted(zoo-input-tag-option[selected]) {
+ background: var(--primary-ultralight);
+}
+
diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js
index bcd579d..f8f48af 100644
--- a/src/zoo-modules/form/input-tag/input-tag.js
+++ b/src/zoo-modules/form/input-tag/input-tag.js
@@ -34,9 +34,10 @@ export class InputTag extends FormElement {
}));
this.addEventListener('keydown', e => {
- if (e.key === ' ' && e.target.tagName === 'ZOO-TAG') {
+ if ((e.key === ' ' || e.key === 'Enter')
+ && (e.target.tagName === 'ZOO-TAG' || e.target.tagName === 'ZOO-INPUT-TAG-OPTION')) {
e.preventDefault();
- this.handleTagSelect(e);
+ this.toggleOptionSelect(e);
}
});
this.shadowRoot.querySelector('slot[name="select"]').addEventListener('slotchange', e => {
@@ -44,62 +45,134 @@ export class InputTag extends FormElement {
this.select && this.registerElementForValidation(this.select);
});
this.shadowRoot.querySelector('slot[name="tag-option"]').addEventListener('click', e => {
- this.handleTagSelect(e);
+ this.toggleOptionSelect(e, true);
});
}
- handleTagSelect(e) {
+ static get observedAttributes() {
+ return [...super.observedAttributes, 'data-initial-value'];
+ }
+
+ attributeChangedCallback(name, oldValue) {
+ if (name === 'invalid') {
+ super.attributeChangedCallback();
+ } else if (name === 'data-initial-value' && oldValue != null) {
+ this.handleInitialValues();
+ }
+ }
+
+ toggleOptionSelect(e, withFocusOnInput = false) {
const target = this.getElAsParentBySlotName(e.target, 'tag-option');
- const tag = target.querySelector('zoo-tag');
- const selectedValue = tag.getAttribute('data-value');
+ if (target && target.hasAttribute('selected')) {
+ const dataElem = target.querySelector('[data-value]');
+ const tagInInput = this.shadowRoot.querySelector(`zoo-tag[data-value="${dataElem.getAttribute('data-value')}"] zoo-cross-icon`);
+ tagInInput.dispatchEvent(new Event('click'));
+ } else if(target) {
+ this.handleTagSelect(target);
+ }
+ if (withFocusOnInput) {
+ this.input.focus();
+ }
+ }
+
+ handleTagSelect(tagOptionSlot) {
+ const optionElement = tagOptionSlot.querySelector('zoo-tag, [data-option-content]');
+ const selectedValue = optionElement.getAttribute('data-value');
const options = [...this.select.querySelectorAll('option')];
const matchedOptionIndex = options.findIndex(o => o.value === selectedValue);
+ const hideOptionsAfterSelect = !this.hasAttribute('show-tags-after-select');
+
if (matchedOptionIndex > -1 && !this.select.options[matchedOptionIndex].selected) {
this.select.options[matchedOptionIndex].selected = true;
this.select.options[matchedOptionIndex].setAttribute('selected', '');
this.select.dispatchEvent(new Event('input'));
- this.input.value = '';
- const clonedTag = tag.cloneNode(true);
- const crossIcon = document.createElement('zoo-cross-icon');
- crossIcon.setAttribute('tabindex', 0);
- crossIcon.setAttribute('slot', 'post');
- crossIcon.addEventListener('click', () => this.deselectOption(clonedTag, matchedOptionIndex));
- crossIcon.addEventListener('keydown', e => {
- if (e.key === ' ') {
- e.preventDefault();
- this.deselectOption(clonedTag, matchedOptionIndex);
- }
- });
- clonedTag.appendChild(crossIcon);
- this.inputSlot.before(clonedTag);
+ if (hideOptionsAfterSelect) {
+ this.input.value = '';
+ }
+ optionElement.parentElement.setAttribute('selected', '');
+ optionElement.parentElement.setAttribute('aria-selected', 'true');
+ let tagElementFromSelection = this.createSelectedTagElement(optionElement, matchedOptionIndex);
+ this.inputSlot.before(tagElementFromSelection);
}
- this.removeAttribute('show-tags');
- this.input.focus();
+ if (hideOptionsAfterSelect) {
+ this.removeAttribute('show-tags');
+ }
+ }
+
+ createSelectedTagElement(selectedOptionElement, matchedOptionIndex) {
+ let tagElementForInput;
+ const dataValue = selectedOptionElement.getAttribute('data-value');
+ if(selectedOptionElement.tagName === 'ZOO-TAG') {
+ tagElementForInput = selectedOptionElement.cloneNode(true);
+ } else {
+ tagElementForInput = document.createElement('ZOO-TAG');
+ tagElementForInput.setAttribute('slot', 'tag');
+ tagElementForInput.setAttribute('type', 'tag');
+ tagElementForInput.setAttribute('data-value', dataValue);
+ tagElementForInput.setAttribute('tabindex', '0');
+ tagElementForInput.insertAdjacentHTML('beforeend', `${dataValue} `);
+ }
+
+ const crossIcon = document.createElement('zoo-cross-icon');
+ crossIcon.setAttribute('tabindex', '0');
+ crossIcon.setAttribute('slot', 'post');
+ crossIcon.setAttribute('role', 'button');
+ crossIcon.setAttribute('aria-label', 'Deselect ' + dataValue);
+ crossIcon.addEventListener('click', () => this.deselectOption(tagElementForInput, matchedOptionIndex, selectedOptionElement));
+ crossIcon.addEventListener('keydown', e => {
+ if (e.key === ' ' || e.key === 'Enter') {
+ e.preventDefault();
+ this.deselectOption(tagElementForInput, matchedOptionIndex, selectedOptionElement);
+ }
+ });
+ tagElementForInput.appendChild(crossIcon);
+ return tagElementForInput;
}
handleInitialValues() {
- const tagOptions = [...this.children].filter(el => el.tagName === 'ZOO-INPUT-TAG-OPTION');
+ let tagOptions = [];
+ [].push.apply(tagOptions, this.children);
+ tagOptions = tagOptions.filter(el => el.tagName === 'ZOO-INPUT-TAG-OPTION');
const defaultValues = this.hasAttribute('data-initial-value')
? this.getAttribute('data-initial-value')
.split(',')
.map(value => value.trim())
+ .filter(value => !!value)
: null;
- if (tagOptions && defaultValues) {
- [...tagOptions].forEach((tagOption) => {
- if (defaultValues.includes([...tagOption.children][0].getAttribute('data-value'))) {
- this.handleTagSelect({
- target: tagOption
- });
+ if (tagOptions && defaultValues && defaultValues.length) {
+ tagOptions.forEach((tagOption) => {
+ if (!tagOption.hasAttribute('selected') && defaultValues.includes([...tagOption.children][0].getAttribute('data-value'))) {
+ this.handleTagSelect(tagOption);
}
});
}
}
- deselectOption(clonedTag, matchedOptionIndex) {
- clonedTag.remove();
+ deselectOption(tagElementForInput, matchedOptionIndex, selectedOptionElement) {
+ tagElementForInput.remove();
this.select.options[matchedOptionIndex].selected = false;
this.select.options[matchedOptionIndex].removeAttribute('selected');
this.select.dispatchEvent(new Event('input'));
+ if (selectedOptionElement) {
+ selectedOptionElement.parentElement.removeAttribute('selected');
+ selectedOptionElement.parentElement.setAttribute('aria-selected', 'false');
+ }
+ }
+
+ clearSelection() {
+ this.shadowRoot.querySelectorAll('#input-wrapper > zoo-tag').forEach(el => el.remove());
+ this.select.querySelectorAll(':checked').forEach(option => {
+ option.selected = false;
+ option.removeAttribute('selected');
+ });
+ this.shadowRoot.querySelectorAll('slot[name="tag-option"]').forEach(slot =>
+ slot.assignedElements().forEach(tagOption => {
+ tagOption.removeAttribute('selected');
+ tagOption.setAttribute('aria-selected', 'false');
+ }));
+ this.input.value = '';
+ this.select.dispatchEvent(new Event('input'));
+ this.input.dispatchEvent(new Event('input'));
this.input.focus();
}
diff --git a/src/zoo-modules/form/input-tag/input-tag.spec.mjs b/src/zoo-modules/form/input-tag/input-tag.spec.mjs
index 774980e..5b66941 100644
--- a/src/zoo-modules/form/input-tag/input-tag.spec.mjs
+++ b/src/zoo-modules/form/input-tag/input-tag.spec.mjs
@@ -26,7 +26,7 @@ describe('Zoo input tag', function () {
});
it('should render component with initial values', async () => {
- const optionsStatus = await page.evaluate(async () => {
+ const ret = await page.evaluate(async () => {
document.body.innerHTML = `
Tag input
@@ -52,11 +52,79 @@ describe('Zoo input tag', function () {
`;
const options = [...document.querySelectorAll('option')];
await new Promise(r => setTimeout(r, 10));
- return options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+
+ const input = document.querySelector('zoo-input-tag');
+ let selectedTags = []
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags.push(el.textContent.trim()));
+ const optionsStatus = options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+ return {
+ optionsStatus,
+ selectedTags
+ }
});
+ expect(ret.optionsStatus).toEqual(['Dog']);
+ expect(ret.optionsStatus).not.toContain('Cat');
+ expect(ret.selectedTags).toContain('Dog');
+ expect(ret.selectedTags).not.toContain('Cat');
+ });
+
+ it('should update initial selection when the attribute changes', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+
+ Dog
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+
+ Cat
+
+ The cat (Felis catus) is a domestic species of small carnivorous mammal.
+
+
+ `;
+ let options = [...document.querySelectorAll('option')];
+ await new Promise(r => setTimeout(r, 10));
+
+ const input = document.querySelector('zoo-input-tag');
+ let selectedTags = []
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags.push(el.textContent.trim()));
+ const optionsStatus = options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+
+ input.setAttribute("data-initial-value", "Dog,Cat");
+ await new Promise(r => setTimeout(r, 10));
- expect(optionsStatus).toEqual(['Dog']);
- expect(optionsStatus).not.toContain(['Cat']);
+ let selectedTagsAfter = [];
+ options = [...document.querySelectorAll('option')];
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTagsAfter.push(el.textContent.trim()));
+ const optionsStatusAfter = options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+
+ return {
+ optionsStatus,
+ selectedTags,
+ selectedTagsAfter,
+ optionsStatusAfter
+ }
+ });
+ expect(ret.optionsStatus).toEqual(['Dog']);
+ expect(ret.optionsStatus).not.toContain('Cat');
+ expect(ret.selectedTags).toContain('Dog');
+ expect(ret.selectedTags).not.toContain('Cat');
+
+ expect(ret.optionsStatusAfter).toContain('Dog');
+ expect(ret.optionsStatusAfter).toContain('Cat');
+ expect(ret.selectedTagsAfter).toContain('Dog');
+ expect(ret.selectedTagsAfter).toContain('Cat');
});
it('should not render input error', async () => {
@@ -132,6 +200,261 @@ describe('Zoo input tag', function () {
expect(ret.tagOptionsDisplayWithoutInputValue).toEqual('none');
});
+ it('should remove selected tag after clicking cross icon', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+
+ Dog
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+
+ Cat
+
+ The cat (Felis catus) is a domestic species of small carnivorous mammal.
+
+
+ `;
+ const input = document.querySelector('zoo-input-tag');
+ const options = [...document.querySelectorAll('option')];
+ await new Promise(r => setTimeout(r, 10));
+
+ input.shadowRoot.querySelector('#input-wrapper zoo-tag zoo-cross-icon').click()
+ await new Promise(r => setTimeout(r, 10));
+
+ let selectedTags = []
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags.push(el.textContent.trim()));
+ const optionsStatus = options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+ return {
+ optionsStatus,
+ selectedTags
+ }
+ });
+ expect(ret.optionsStatus.length).toEqual(0);
+ expect(ret.selectedTags.length).toEqual(0);
+ });
+
+ it('should toggle tag selection when clicking on option list', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+
+ Dog
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+
+ Bird
+
+ Birds are a group of warm-blooded vertebrates constituting the class Aves /ˈeɪviːz/.
+
+
+ `;
+ await new Promise(r => setTimeout(r, 10));
+ let input = document.querySelector('zoo-input-tag');
+ const slottedInput = input.shadowRoot.querySelector('slot[name="input"]').assignedElements()[0];
+ slottedInput.value = 123;
+ slottedInput.dispatchEvent(new Event('input'));
+ await new Promise(r => setTimeout(r, 10));
+
+ const tagOption1 = input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements()[0]
+ tagOption1.click();
+ await new Promise(r => setTimeout(r, 10));
+
+ let selectedTags1stClick = [];
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags1stClick.push(el.textContent.trim()));
+ let selectedOptions1stClick = [];
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements().forEach(el=> {
+ if(el.hasAttribute('selected')) {
+ selectedOptions1stClick.push(el.querySelector('span').textContent.trim())
+ }
+ });
+
+ tagOption1.click();
+ await new Promise(r => setTimeout(r, 10));
+
+ let selectedTags2stClick = [];
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags2stClick.push(el.textContent.trim()));
+ let selectedOptions2stClick = [];
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements().forEach(el=> {
+ if(el.hasAttribute('selected')) {
+ selectedOptions2stClick.push(el.querySelector('span').textContent.trim())
+ }
+ });
+ return {
+ selectedTags1stClick,
+ selectedOptions1stClick,
+ selectedTags2stClick,
+ selectedOptions2stClick
+ }
+ });
+ expect(ret.selectedOptions1stClick).toEqual(['Dog']);
+ expect(ret.selectedTags1stClick).toEqual(['Dog']);
+ expect(ret.selectedOptions2stClick.length).toEqual(0);
+ expect(ret.selectedTags2stClick.length).toEqual(0);
+ });
+
+ it('should render clicked option as tag with tag content as text', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+ Dog content
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+ `;
+ await new Promise(r => setTimeout(r, 10));
+ let input = document.querySelector('zoo-input-tag');
+ const slottedInput = input.shadowRoot.querySelector('slot[name="input"]').assignedElements()[0];
+ slottedInput.value = 123;
+ slottedInput.dispatchEvent(new Event('input'));
+ await new Promise(r => setTimeout(r, 10));
+ const tagOptions = input.shadowRoot.getElementById('tag-options');
+ const tagOptionsDisplayWithInputValue = window.getComputedStyle(tagOptions).display;
+ const showTagsAttrPresentWithInputValue = input.hasAttribute('show-tags');
+
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements()[0].click();
+ await new Promise(r => setTimeout(r, 10));
+
+ const selectedTag = input.shadowRoot.querySelector('#input-wrapper zoo-tag');
+ const selectedTagContent = selectedTag.textContent.trim()
+ return {
+ showTagsAttrPresentWithInputValue,
+ tagOptionsDisplayWithInputValue,
+ selectedTagContent
+ };
+ });
+ expect(ret.showTagsAttrPresentWithInputValue).toBeTrue();
+ expect(ret.tagOptionsDisplayWithInputValue).toEqual('flex');
+ expect(ret.selectedTagContent).toEqual('Dog content');
+ });
+
+ it('should render clicked option as tag when using custom markup with data-option-content attribute', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+ Dog
+
+
+ Dog content
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+ `;
+ await new Promise(r => setTimeout(r, 10));
+ let input = document.querySelector('zoo-input-tag');
+ const slottedInput = input.shadowRoot.querySelector('slot[name="input"]').assignedElements()[0];
+ slottedInput.value = 123;
+ slottedInput.dispatchEvent(new Event('input'));
+ await new Promise(r => setTimeout(r, 10));
+
+ const tagOptions = input.shadowRoot.getElementById('tag-options');
+ const tagOptionsDisplayWithInputValue = window.getComputedStyle(tagOptions).display;
+ const showTagsAttrPresentWithInputValue = input.hasAttribute('show-tags');
+
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements()[0].click();
+ await new Promise(r => setTimeout(r, 10));
+
+ const selectedTag = input.shadowRoot.querySelector('#input-wrapper zoo-tag');
+ const selectedTagContent = selectedTag.textContent.trim()
+ return {
+ showTagsAttrPresentWithInputValue,
+ tagOptionsDisplayWithInputValue,
+ selectedTagContent
+ };
+ });
+ expect(ret.showTagsAttrPresentWithInputValue).toBeTrue();
+ expect(ret.tagOptionsDisplayWithInputValue).toEqual('flex');
+ expect(ret.selectedTagContent).toEqual('Dog');
+ });
+
+ it('should show and not hide tags on input when attribute set', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+
+ Dog
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+
+ Bird
+
+ Birds are a group of warm-blooded vertebrates constituting the class Aves /ˈeɪviːz/.
+
+
+ `;
+ await new Promise(r => setTimeout(r, 10));
+ let input = document.querySelector('zoo-input-tag');
+ const slottedInput = input.shadowRoot.querySelector('slot[name="input"]').assignedElements()[0];
+ slottedInput.value = 123;
+ slottedInput.dispatchEvent(new Event('input'));
+ await new Promise(r => setTimeout(r, 10));
+ const tagOptions = input.shadowRoot.getElementById('tag-options');
+ const tagOptionsDisplayWithInputValue = window.getComputedStyle(tagOptions).display;
+ const showTagsAttrPresentWithInputValue = input.hasAttribute('show-tags');
+
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements()[0].click();
+
+ await new Promise(r => setTimeout(r, 10));
+
+ const showTagsAttrPresentWithoutInputValue = input.hasAttribute('show-tags');
+ const tagOptionsDisplayWithoutInputValue = window.getComputedStyle(tagOptions).display;
+
+ return {
+ showTagsAttrPresentWithInputValue,
+ tagOptionsDisplayWithInputValue,
+ showTagsAttrPresentWithoutInputValue,
+ tagOptionsDisplayWithoutInputValue
+ };
+ });
+ expect(ret.showTagsAttrPresentWithInputValue).toBeTrue();
+ expect(ret.tagOptionsDisplayWithInputValue).toEqual('flex');
+ expect(ret.showTagsAttrPresentWithoutInputValue).toBeTrue();
+ expect(ret.tagOptionsDisplayWithoutInputValue).toEqual('flex');
+ });
+
it('should set and then remove invalid attribute from host while setting the value in the slotted select', async () => {
const result = await page.evaluate(async () => {
document.body.innerHTML = `
@@ -177,4 +500,50 @@ describe('Zoo input tag', function () {
expect(result.invalidAfterCrossClick).toBeTrue();
expect(result.selectValueAfterCrossClick).toEqual('');
});
+
+ it('should clear selection by invoking function', async () => {
+ const ret = await page.evaluate(async () => {
+ document.body.innerHTML = `
+
+ Tag input
+
+ At least one tag should be selected!
+
+
+
+
+
+
+ Dog
+
+ The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
+
+
+
+ Cat
+
+ The cat (Felis catus) is a domestic species of small carnivorous mammal.
+
+
+ `;
+ const input = document.querySelector('zoo-input-tag');
+ input.shadowRoot.querySelector('slot[name="tag-option"]').assignedElements()[1].click();
+ await new Promise(r => setTimeout(r, 10));
+
+ input.clearSelection();
+
+ const options = [...document.querySelectorAll('option')];
+ await new Promise(r => setTimeout(r, 10));
+
+ let selectedTags = []
+ input.shadowRoot.querySelectorAll('#input-wrapper zoo-tag').forEach(el=> selectedTags.push(el.textContent.trim()));
+ const optionsStatus = options.filter((option) => option.hasAttribute('selected')).map(option => option.value);
+ return {
+ optionsStatus,
+ selectedTags
+ }
+ });
+ expect(ret.optionsStatus.length).toEqual(0);
+ expect(ret.selectedTags.length).toEqual(0);
+ });
});
\ No newline at end of file
diff --git a/src/zoo-modules/form/input/input.css b/src/zoo-modules/form/input/input.css
index 55dcb1d..cf33b43 100644
--- a/src/zoo-modules/form/input/input.css
+++ b/src/zoo-modules/form/input/input.css
@@ -42,7 +42,7 @@
::slotted(input:disabled),
::slotted(textarea:disabled) {
border: 1px solid #E6E6E6;
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
color: #767676;
cursor: not-allowed;
}
diff --git a/src/zoo-modules/form/quantity-control/quantity-control.css b/src/zoo-modules/form/quantity-control/quantity-control.css
index 0d8ca5c..60b02e1 100644
--- a/src/zoo-modules/form/quantity-control/quantity-control.css
+++ b/src/zoo-modules/form/quantity-control/quantity-control.css
@@ -30,7 +30,7 @@ div {
}
::slotted(button:disabled) {
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
cursor: not-allowed;
}
diff --git a/src/zoo-modules/form/select/select.css b/src/zoo-modules/form/select/select.css
index fb03971..c556fcd 100644
--- a/src/zoo-modules/form/select/select.css
+++ b/src/zoo-modules/form/select/select.css
@@ -38,7 +38,7 @@ zoo-arrow-icon {
::slotted(select:disabled) {
border: 1px solid #E6E6E6;
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
color: #666;
}
diff --git a/src/zoo-modules/form/toggle-switch/toggle-switch.css b/src/zoo-modules/form/toggle-switch/toggle-switch.css
index 03ca650..20bc12a 100644
--- a/src/zoo-modules/form/toggle-switch/toggle-switch.css
+++ b/src/zoo-modules/form/toggle-switch/toggle-switch.css
@@ -40,7 +40,7 @@ div {
}
::slotted(input:disabled) {
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
cursor: not-allowed;
}
diff --git a/src/zoo-modules/grid/grid-header/grid-header.css b/src/zoo-modules/grid/grid-header/grid-header.css
index c14e918..acbd23c 100644
--- a/src/zoo-modules/grid/grid-header/grid-header.css
+++ b/src/zoo-modules/grid/grid-header/grid-header.css
@@ -15,7 +15,7 @@ button {
border: 0;
cursor: pointer;
border-radius: 5px;
- background: #F2F3F4;
+ background: var(--input-disabled, #F2F3F4);
--icon-color: black;
}
diff --git a/src/zoo-modules/grid/grid/grid.css b/src/zoo-modules/grid/grid/grid.css
index 75e4e2e..42727a1 100644
--- a/src/zoo-modules/grid/grid/grid.css
+++ b/src/zoo-modules/grid/grid/grid.css
@@ -77,7 +77,7 @@
::slotted(*[slot="row"]:hover),
::slotted(*[slot="row"]:focus) {
- background: #E6E6E6;
+ background: var(--item-hovered, #E6E6E6);
}
::slotted(*[slot="norecords"]) {
diff --git a/src/zoo-modules/icon/arrow-icon/arrow-icon.css b/src/zoo-modules/icon/arrow-icon/arrow-icon.css
index 1ab21d3..027ac6b 100644
--- a/src/zoo-modules/icon/arrow-icon/arrow-icon.css
+++ b/src/zoo-modules/icon/arrow-icon/arrow-icon.css
@@ -1,6 +1,6 @@
svg {
display: flex;
- width: var(--width, 24px);
- height: var(--height, 24px);
+ width: var(--icon-width, 24px);
+ height: var(--icon-height, 24px);
fill: var(--icon-color, var(--primary-mid));
}
diff --git a/src/zoo-modules/icon/attention-icon/attention-icon.css b/src/zoo-modules/icon/attention-icon/attention-icon.css
index 2f5d16e..c8d8ec8 100644
--- a/src/zoo-modules/icon/attention-icon/attention-icon.css
+++ b/src/zoo-modules/icon/attention-icon/attention-icon.css
@@ -1,7 +1,7 @@
svg {
display: flex;
padding-right: 5px;
- width: var(--width, 18px);
- height: var(--height, 18px);
+ width: var(--icon-width, 18px);
+ height: var(--icon-height, 18px);
fill: var(--icon-color, var(--info-mid));
}
diff --git a/src/zoo-modules/icon/cross-icon/cross-icon.css b/src/zoo-modules/icon/cross-icon/cross-icon.css
index 315f1f9..c990ec4 100644
--- a/src/zoo-modules/icon/cross-icon/cross-icon.css
+++ b/src/zoo-modules/icon/cross-icon/cross-icon.css
@@ -1,6 +1,6 @@
svg {
display: flex;
- width: var(--width, 24px);
- height: var(--height, 24px);
+ width: var(--icon-width, 18px);
+ height: var(--icon-height, 18px);
fill: var(--icon-color, black);
}
diff --git a/src/zoo-modules/misc/button/button.css b/src/zoo-modules/misc/button/button.css
index 7052eac..dc3e141 100644
--- a/src/zoo-modules/misc/button/button.css
+++ b/src/zoo-modules/misc/button/button.css
@@ -69,9 +69,9 @@
::slotted(button:disabled) {
cursor: not-allowed;
- --background: #F2F3F4;
- --color-mid: #F2F3F4;
- --color-dark: #F2F3F4;
+ --background: var(--input-disabled, #F2F3F4);
+ --color-mid: var(--input-disabled, #F2F3F4);
+ --color-dark: var(--input-disabled, #F2F3F4);
--text-normal: #767676;
--text-active: #767676;
--border: 1px solid #E6E6E6;
diff --git a/src/zoo-modules/misc/tag/tag.css b/src/zoo-modules/misc/tag/tag.css
index 62f56b7..ccd7fa2 100644
--- a/src/zoo-modules/misc/tag/tag.css
+++ b/src/zoo-modules/misc/tag/tag.css
@@ -6,7 +6,8 @@
width: max-content;
color: var(--color);
border-color: var(--color);
- max-width: 100px;
+ max-width: var(--zoo-tag-max-width, 100px);
+ border-radius: 3px;
}
:host(:hover) {
@@ -32,7 +33,6 @@
::slotted(*[slot="content"]) {
font-size: 12px;
- line-height: 16px;
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;