From 4c0b6546e985189d58250ff6cec9687bf0d074b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Padyku=C5=82a?= Date: Tue, 14 Feb 2023 11:33:47 +0100 Subject: [PATCH 01/13] zoo-modal improvements: - add `zoo-modal-z-index` CSS variable to control z-index in case of conflict with other components - ptional `button-closeable` attribute to prevent closing of modal when clicking on box overlay area - fix duplicated click event listener on added on every modal opening --- CHANGELOG.md | 10 +++++-- package.json | 2 +- src/zoo-modules/misc/modal/modal.css | 2 +- src/zoo-modules/misc/modal/modal.js | 33 ++++++++++++++++------- src/zoo-modules/misc/modal/modal.spec.mjs | 19 +++++++++++++ 5 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2f5d1f7..fd1518b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,18 @@ # CHANGELOG +## 10.3.4 + +`zoo-modal`: + - added CSS variable `zoo-modal-z-index` to change predefined z-index in case of conflict with some other 3rd party components + - added optional `button-closeable` attribute to prevent closing of modal when clicking on box overlay area + ## 10.3.3 -`zoo-grid` - added property `grid-stickyheader-position-top` to change top position of sticky header +`zoo-grid` - added CSS variable `grid-stickyheader-position-top` to change top position of sticky header ## 10.3.2 -`zoo-modal` - added property `zoo-modal-opacity` to change background transparency +`zoo-modal` - added CSS variable `zoo-modal-opacity` to change background transparency ## 10.3.1 diff --git a/package.json b/package.json index 0b2d61c5..ab8d54cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zooplus/zoo-web-components", - "version": "10.3.3", + "version": "10.3.4", "main": "dist/zoo-web-components.js", "sideEffects": false, "files": [ diff --git a/src/zoo-modules/misc/modal/modal.css b/src/zoo-modules/misc/modal/modal.css index b0391ac0..d53c94ee 100644 --- a/src/zoo-modules/misc/modal/modal.css +++ b/src/zoo-modules/misc/modal/modal.css @@ -10,7 +10,7 @@ background: rgba(0, 0, 0, var(--zoo-modal-opacity, 0.8)); opacity: 0; transition: opacity 0.3s; - z-index: 9999; + z-index: var(--zoo-modal-z-index, 9999); left: 0; top: 0; display: flex; diff --git a/src/zoo-modules/misc/modal/modal.js b/src/zoo-modules/misc/modal/modal.js index 5ca62c09..655796a1 100644 --- a/src/zoo-modules/misc/modal/modal.js +++ b/src/zoo-modules/misc/modal/modal.js @@ -10,10 +10,13 @@ export class Modal extends HTMLElement { super(); registerComponents(CrossIcon); this.shadowRoot.querySelector('.close').addEventListener('click', () => this.closeModal()); + const box = this.shadowRoot.querySelector('.box'); - box.addEventListener('click', e => { - if (e.target == box) this.closeModal(); - }); + this.closeModalOnClickHandler = (clickEvent) => { + if (clickEvent.target == box) this.closeModal(); + }; + box.addEventListener('click', this.closeModalOnClickHandler); + // https://github.com/HugoGiraudel/a11y-dialog/blob/main/a11y-dialog.js this.focusableSelectors = [ 'a[href]:not([tabindex^="-"]):not([inert])', @@ -28,6 +31,11 @@ export class Modal extends HTMLElement { '[contenteditable]:not([tabindex^="-"]):not([inert])', '[tabindex]:not([tabindex^="-"]):not([inert])', ]; + + this.keyUpEventHandler = (event) => { + if (event.key === 'Escape') this.closeModal(); + if (event.key === 'Tab') this.maintainFocus(event.shiftKey); + }; } connectedCallback() { @@ -35,21 +43,28 @@ export class Modal extends HTMLElement { } static get observedAttributes() { - return ['closelabel']; + return ['closelabel', 'button-closeable']; } attributeChangedCallback(attrName, oldVal, newVal) { - this.shadowRoot.querySelector('zoo-cross-icon').setAttribute('title', newVal); + if (attrName === 'button-closeable') { + if (this.hasAttribute('button-closeable')) { + const box = this.shadowRoot.querySelector('.box'); + box.removeEventListener('click', this.closeModalOnClickHandler); + } else { + this.shadowRoot.querySelector('.box').addEventListener('click', this.closeModalOnClickHandler); + } + + } else if (attrName === 'closelabel') { + this.shadowRoot.querySelector('zoo-cross-icon').setAttribute('title', newVal); + } } openModal() { this.style.display = 'block'; this.toggleModalClass(); this.shadowRoot.querySelector('button').focus(); - document.addEventListener('keyup', e => { - if (e.key === 'Escape') this.closeModal(); - if (e.key === 'Tab') this.maintainFocus(e.shiftKey); - }); + document.addEventListener('keyup', this.keyUpEventHandler); } maintainFocus(shiftKey) { diff --git a/src/zoo-modules/misc/modal/modal.spec.mjs b/src/zoo-modules/misc/modal/modal.spec.mjs index 3d43d2cd..6cf28f2e 100644 --- a/src/zoo-modules/misc/modal/modal.spec.mjs +++ b/src/zoo-modules/misc/modal/modal.spec.mjs @@ -56,6 +56,25 @@ describe('Zoo modal', function () { expect(modalDisplay).toEqual('none'); }); + it('should not close opened modal when button-closeable attribute is set and outer box is clicked', async () => { + const modalDisplay = await page.evaluate(async () => { + document.body.innerHTML = ` + + header-text +
content
+
+ `; + let modal = document.querySelector('zoo-modal'); + modal.style.display = 'block'; + + const box = modal.shadowRoot.querySelector('.box'); + box.dispatchEvent(new Event('click')); + jasmine.clock().tick(400); + return modal.style.display; + }); + expect(modalDisplay).toEqual('block'); + }); + it('should close opened modal when escape is clicked', async () => { const modalDisplay = await page.evaluate(async () => { document.body.innerHTML = ` From 46789ece0e10344c42ac506a9c019b53919afc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Padyku=C5=82a?= Date: Tue, 14 Feb 2023 15:43:55 +0100 Subject: [PATCH 02/13] Fixes after dependency upgrade --- CHANGELOG.md | 8 ++++++++ src/zoo-modules/grid/grid/grid.css | 2 +- src/zoo-modules/misc/spinner/spinner.css | 2 +- src/zoo-modules/misc/toast/toast.css | 2 +- src/zoo-modules/misc/tooltip/tooltip.css | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1518b9..c44f72e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ - added CSS variable `zoo-modal-z-index` to change predefined z-index in case of conflict with some other 3rd party components - added optional `button-closeable` attribute to prevent closing of modal when clicking on box overlay area +`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 + ## 10.3.3 `zoo-grid` - added CSS variable `grid-stickyheader-position-top` to change top position of sticky header diff --git a/src/zoo-modules/grid/grid/grid.css b/src/zoo-modules/grid/grid/grid.css index a896a1a3..854405e0 100644 --- a/src/zoo-modules/grid/grid/grid.css +++ b/src/zoo-modules/grid/grid/grid.css @@ -10,7 +10,7 @@ left: 0; top: 0; right: 0; - z-index: 9998; + z-index: var(--zoo-grid-z-index, 9998); justify-content: center; height: 100%; background: rgba(0, 0, 0, 0.15); diff --git a/src/zoo-modules/misc/spinner/spinner.css b/src/zoo-modules/misc/spinner/spinner.css index 9a712212..d0c014a5 100644 --- a/src/zoo-modules/misc/spinner/spinner.css +++ b/src/zoo-modules/misc/spinner/spinner.css @@ -12,7 +12,7 @@ svg { width: 120px; transform-origin: center center; animation: rotate 2s linear infinite; - z-index: 10002; + z-index: var(--zoo-spinner-z-index, 10002); } svg circle { diff --git a/src/zoo-modules/misc/toast/toast.css b/src/zoo-modules/misc/toast/toast.css index c101785a..e2011a78 100644 --- a/src/zoo-modules/misc/toast/toast.css +++ b/src/zoo-modules/misc/toast/toast.css @@ -3,7 +3,7 @@ top: 20px; right: 20px; position: fixed; - z-index: 10001; + z-index: var(--zoo-toast-z-index, 10001); contain: layout; --color-ultralight: var(--info-ultralight); diff --git a/src/zoo-modules/misc/tooltip/tooltip.css b/src/zoo-modules/misc/tooltip/tooltip.css index 4d26c559..4f217388 100644 --- a/src/zoo-modules/misc/tooltip/tooltip.css +++ b/src/zoo-modules/misc/tooltip/tooltip.css @@ -2,7 +2,7 @@ display: grid; position: absolute; width: max-content; - z-index: 9997; + z-index: var(--zoo-tooltip-z-index, 9997); pointer-events: none; color: black; From 36412ace694735ab658ffafc905f9d23e60ae9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Padyku=C5=82a?= Date: Thu, 28 Sep 2023 17:29:55 +0200 Subject: [PATCH 03/13] zoo-input-tag enhancements --- CHANGELOG.md | 22 +- docs/index.html | 30 ++ docs/main.js | 24 +- package-lock.json | 88 +++--- package.json | 2 +- src/zoo-modules/form/checkbox/checkbox.css | 2 +- .../form/input-tag/input-tag-option.css | 4 - src/zoo-modules/form/input-tag/input-tag.css | 18 +- src/zoo-modules/form/input-tag/input-tag.js | 87 ++++-- .../form/input-tag/input-tag.spec.mjs | 275 +++++++++++++++++- src/zoo-modules/form/input/input.css | 2 +- .../quantity-control/quantity-control.css | 2 +- src/zoo-modules/form/select/select.css | 2 +- .../form/toggle-switch/toggle-switch.css | 2 +- .../grid/grid-header/grid-header.css | 2 +- src/zoo-modules/grid/grid/grid.css | 2 +- .../icon/arrow-icon/arrow-icon.css | 4 +- .../icon/attention-icon/attention-icon.css | 4 +- .../icon/cross-icon/cross-icon.css | 4 +- src/zoo-modules/icon/paw-icon/paw-icon.css | 4 +- src/zoo-modules/misc/button/button.css | 6 +- src/zoo-modules/misc/tag/tag.css | 2 +- 22 files changed, 480 insertions(+), 108 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7b58bf..6b7a83d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,23 @@ # 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`: + - `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-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 7ee1a6c0..5b2d54c4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -130,6 +130,36 @@

Input/Textarea

no results + + + + 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 + +

Select

diff --git a/docs/main.js b/docs/main.js index 61e10e04..abc955dd 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 abfc6e2b..601af67a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@zooplus/zoo-web-components", - "version": "10.3.3", + "version": "10.3.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@zooplus/zoo-web-components", - "version": "10.3.3", + "version": "10.3.5", "license": "MIT", "devDependencies": { "axe-core": "^4.3.3", @@ -99,9 +99,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -149,9 +149,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2890,9 +2890,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3234,9 +3234,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -4308,9 +4308,9 @@ } }, "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -4602,9 +4602,9 @@ "dev": true }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5471,9 +5471,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5665,9 +5665,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -5704,9 +5704,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -7735,9 +7735,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -8008,9 +8008,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -8825,9 +8825,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "type-fest": { @@ -9046,9 +9046,9 @@ "dev": true }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9730,9 +9730,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://bin.private.zooplus.net/artifactory/api/npm/npm-virtual/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wrap-ansi": { diff --git a/package.json b/package.json index ab8d54cf..58acb265 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 43adfc9c..17e617e1 100644 --- a/src/zoo-modules/form/checkbox/checkbox.css +++ b/src/zoo-modules/form/checkbox/checkbox.css @@ -85,7 +85,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 c63e5958..3da54a9d 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 02b3d38f..852dfc7b 100644 --- a/src/zoo-modules/form/input-tag/input-tag.css +++ b/src/zoo-modules/form/input-tag/input-tag.css @@ -57,15 +57,16 @@ zoo-label { position: absolute; flex-wrap: wrap; background: white; - padding: 5px; + padding: 5px 15px; border: 1px solid #555; border-radius: 0 0 3px 3px; - gap: 5px; left: -1px; top: 90%; 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, @@ -98,5 +99,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 bcd579dd..f123aaa9 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,39 +45,73 @@ 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); }); } - handleTagSelect(e) { + toggleOptionSelect(e) { 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 { + this.handleTagSelect(target); + } + } + + handleTagSelect(tagOptionSlot) { + const optionElement = tagOptionSlot.querySelector('zoo-tag, [tag-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); + } + if (hideOptionsAfterSelect) { + this.removeAttribute('show-tags'); } - this.removeAttribute('show-tags'); this.input.focus(); } + 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.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'); const defaultValues = this.hasAttribute('data-initial-value') @@ -87,7 +122,7 @@ export class InputTag extends FormElement { if (tagOptions && defaultValues) { [...tagOptions].forEach((tagOption) => { if (defaultValues.includes([...tagOption.children][0].getAttribute('data-value'))) { - this.handleTagSelect({ + this.toggleOptionSelect({ target: tagOption }); } @@ -95,11 +130,15 @@ export class InputTag extends FormElement { } } - 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'); + } 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 774980e9..c623c2aa 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 = ` @@ -52,11 +52,20 @@ 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); - }); - expect(optionsStatus).toEqual(['Dog']); - expect(optionsStatus).not.toContain(['Cat']); + 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 not render input error', async () => { @@ -132,6 +141,262 @@ 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 = ` + + + + 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 = ` + + + + 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 = ` + + + + 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 tag-option-content attribute', async () => { + const ret = await page.evaluate(async () => { + document.body.innerHTML = ` + + + + 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'); + }); + + it('should show and not hide tags on input when attribute set', async () => { + const ret = await page.evaluate(async () => { + document.body.innerHTML = ` + + + + 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 = ` diff --git a/src/zoo-modules/form/input/input.css b/src/zoo-modules/form/input/input.css index 55dcb1de..cf33b435 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 e9e8effe..98ffe956 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 f7444a09..da7d5c5c 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 77d087d3..a510c232 100644 --- a/src/zoo-modules/form/toggle-switch/toggle-switch.css +++ b/src/zoo-modules/form/toggle-switch/toggle-switch.css @@ -41,7 +41,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 c14e918c..acbd23cf 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 854405e0..696c02a6 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 1ab21d37..027ac6bf 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 2f5d16eb..c8d8ec86 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 315f1f9f..c990ec4f 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/icon/paw-icon/paw-icon.css b/src/zoo-modules/icon/paw-icon/paw-icon.css index 724526e1..96dea373 100644 --- a/src/zoo-modules/icon/paw-icon/paw-icon.css +++ b/src/zoo-modules/icon/paw-icon/paw-icon.css @@ -1,7 +1,7 @@ svg { display: flex; - width: var(--width, 44px); - height: var(--height, 44px); + width: var(--icon-width, 44px); + height: var(--icon-height, 44px); fill: var(--icon-color, white); } diff --git a/src/zoo-modules/misc/button/button.css b/src/zoo-modules/misc/button/button.css index 7052eac6..dc3e1419 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 62f56b70..87aab956 100644 --- a/src/zoo-modules/misc/tag/tag.css +++ b/src/zoo-modules/misc/tag/tag.css @@ -7,6 +7,7 @@ color: var(--color); border-color: var(--color); 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; From 7de0c4eaeba0250e1249a45c7da01c9383bcd165 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Mon, 2 Oct 2023 12:29:01 +0200 Subject: [PATCH 04/13] input-tag-padding CSS variables --- CHANGELOG.md | 3 ++- src/zoo-modules/form/input-tag/input-tag.css | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7a83d0..48b901dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ Semi-Breaking Changes: - `zoo-input-tag`: - `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 + - `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 - `--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 diff --git a/src/zoo-modules/form/input-tag/input-tag.css b/src/zoo-modules/form/input-tag/input-tag.css index 852dfc7b..0b4b9c75 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,7 +61,7 @@ zoo-label { position: absolute; flex-wrap: wrap; background: white; - padding: 5px 15px; + 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; left: -1px; From 0cebd64617d979e7159691937cb386da91c203f3 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Fri, 20 Oct 2023 10:07:18 +0200 Subject: [PATCH 05/13] - fix attribute for custom values to be `data-` prefixed - add clearSelection method for clearing input tag - CSS fixes --- docs/index.html | 17 +++++-- src/zoo-modules/form/input-tag/input-tag.css | 4 +- src/zoo-modules/form/input-tag/input-tag.js | 20 +++++++- .../form/input-tag/input-tag.spec.mjs | 51 +++++++++++++++++-- src/zoo-modules/misc/tag/tag.css | 2 +- 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/docs/index.html b/docs/index.html index 5b2d54c4..0568727b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -102,6 +102,7 @@

Input/Textarea

+ @@ -127,6 +128,12 @@

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
@@ -143,19 +150,19 @@

Input/Textarea

- 🐕 Dog + 🐕 Dog - 🐈 Cat + 🐈 Cat - 🐦‍⬛ Bird + 🐦‍⬛ Bird - 🐟 Aquatic + 🐟 Aquatic - 🦎 Reptile + 🦎 Reptile no results diff --git a/src/zoo-modules/form/input-tag/input-tag.css b/src/zoo-modules/form/input-tag/input-tag.css index 0b4b9c75..e7a1bc8c 100644 --- a/src/zoo-modules/form/input-tag/input-tag.css +++ b/src/zoo-modules/form/input-tag/input-tag.css @@ -65,7 +65,7 @@ zoo-label { border: 1px solid #555; border-radius: 0 0 3px 3px; left: -1px; - top: 90%; + top: calc(90%); border-top: 0; width: calc(100% + 2px); box-sizing: border-box; @@ -78,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 { diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index f123aaa9..8358c98b 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -61,11 +61,12 @@ export class InputTag extends FormElement { } handleTagSelect(tagOptionSlot) { - const optionElement = tagOptionSlot.querySelector('zoo-tag, [tag-option-content]'); + 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', ''); @@ -142,6 +143,23 @@ export class InputTag extends FormElement { this.input.focus(); } + 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(); + } + getElAsParentBySlotName(startEl, slotName) { if (startEl.getAttribute('slot') === slotName) return startEl; let el = startEl.parentElement; 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 c623c2aa..9ac165ed 100644 --- a/src/zoo-modules/form/input-tag/input-tag.spec.mjs +++ b/src/zoo-modules/form/input-tag/input-tag.spec.mjs @@ -183,7 +183,6 @@ describe('Zoo input tag', function () { }); expect(ret.optionsStatus.length).toEqual(0); expect(ret.selectedTags.length).toEqual(0); - }); it('should toggle tag selection when clicking on option list', async () => { @@ -299,7 +298,7 @@ describe('Zoo input tag', function () { expect(ret.selectedTagContent).toEqual('Dog content'); }); - it('should render clicked option as tag when using custom markup with tag-option-content attribute', async () => { + 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 = ` @@ -310,7 +309,7 @@ describe('Zoo input tag', function () { -
Dog content
+
Dog content
The domestic dog (Canis familiaris or Canis lupus familiaris)[4] is a domesticated descendant of the wolf.
@@ -442,4 +441,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 = ` + + + + 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/misc/tag/tag.css b/src/zoo-modules/misc/tag/tag.css index 87aab956..ccd7fa2c 100644 --- a/src/zoo-modules/misc/tag/tag.css +++ b/src/zoo-modules/misc/tag/tag.css @@ -6,7 +6,7 @@ width: max-content; color: var(--color); border-color: var(--color); - max-width: 100px; + max-width: var(--zoo-tag-max-width, 100px); border-radius: 3px; } From fb719afe8a5d7405aee1e8ebc6ecd9ecf8852082 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Fri, 20 Oct 2023 10:10:04 +0200 Subject: [PATCH 06/13] - readme update --- CHANGELOG.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b901dc..b21f64eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,14 @@ ## 10.4.0 Semi-Breaking Changes: - - `zoo-input-tag`: - - `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 - - `--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-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 + - `--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: From 227faacb4c0ad552a0d8960ff60ff62745ba6fc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 09:50:34 +0200 Subject: [PATCH 07/13] build(deps-dev): bump @babel/traverse from 7.23.0 to 7.23.2 (#53) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.23.0 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ba57ef7..483fa397 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", From f6b752825f6915212833bfee0aa4f60556b3ef95 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Wed, 25 Oct 2023 07:28:55 +0200 Subject: [PATCH 08/13] - fix if click captures tag-option and not it's content --- src/zoo-modules/form/input-tag/input-tag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index 8358c98b..31f244d7 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -55,7 +55,7 @@ export class InputTag extends FormElement { 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 { + } else if(target) { this.handleTagSelect(target); } } From cee342803dc7833b894b57a1ec0ab47c1c75dd92 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Wed, 25 Oct 2023 14:00:55 +0200 Subject: [PATCH 09/13] - fix toggling off already selected option when it was in initial values list --- src/zoo-modules/form/input-tag/input-tag.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index 31f244d7..75db35ba 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -119,13 +119,12 @@ export class InputTag extends FormElement { ? 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.toggleOptionSelect({ - 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); } }); } From 445477cf37b6c597aeb1e0b5146f2b7ab5af8361 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Wed, 25 Oct 2023 16:33:51 +0200 Subject: [PATCH 10/13] - selection will be updated when `data-initial-value` attribute changes --- CHANGELOG.md | 1 + src/zoo-modules/form/input-tag/input-tag.js | 16 ++++- .../form/input-tag/input-tag.spec.mjs | 59 +++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b21f64eb..cc3e2175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Semi-Breaking Changes: - `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 diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index 75db35ba..43674d40 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -49,6 +49,18 @@ export class InputTag extends FormElement { }); } + static get observedAttributes() { + return [...super.observedAttributes, 'data-initial-value']; + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'invalid') { + super.attributeChangedCallback(); + } else if (name === 'data-initial-value' && oldValue != null) { + this.handleInitialValues(); + } + } + toggleOptionSelect(e) { const target = this.getElAsParentBySlotName(e.target, 'tag-option'); if (target && target.hasAttribute('selected')) { @@ -114,7 +126,9 @@ export class InputTag extends FormElement { } 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(',') 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 9ac165ed..5b66941f 100644 --- a/src/zoo-modules/form/input-tag/input-tag.spec.mjs +++ b/src/zoo-modules/form/input-tag/input-tag.spec.mjs @@ -68,6 +68,65 @@ describe('Zoo input tag', function () { 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 = ` + + + + 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)); + + 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 () => { const errorDisplay = await page.evaluate(async () => { document.body.innerHTML = ` From c2071188148c488661bde571e0b25a9164562536 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Wed, 25 Oct 2023 16:39:57 +0200 Subject: [PATCH 11/13] - lint fix --- src/zoo-modules/form/input-tag/input-tag.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index 43674d40..d8620807 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -53,7 +53,7 @@ export class InputTag extends FormElement { return [...super.observedAttributes, 'data-initial-value']; } - attributeChangedCallback(name, oldValue, newValue) { + attributeChangedCallback(name, oldValue) { if (name === 'invalid') { super.attributeChangedCallback(); } else if (name === 'data-initial-value' && oldValue != null) { @@ -127,7 +127,7 @@ export class InputTag extends FormElement { handleInitialValues() { let tagOptions = []; - [].push.apply(tagOptions, this.children) + [].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') From 181a0f36a92e956b95e9ea2236d9c6839848bc0e Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Wed, 25 Oct 2023 18:52:11 +0200 Subject: [PATCH 12/13] - focus settings --- src/zoo-modules/form/input-tag/input-tag.css | 2 +- src/zoo-modules/form/input-tag/input-tag.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zoo-modules/form/input-tag/input-tag.css b/src/zoo-modules/form/input-tag/input-tag.css index e7a1bc8c..ec1388dd 100644 --- a/src/zoo-modules/form/input-tag/input-tag.css +++ b/src/zoo-modules/form/input-tag/input-tag.css @@ -65,7 +65,7 @@ zoo-label { border: 1px solid #555; border-radius: 0 0 3px 3px; left: -1px; - top: calc(90%); + top: calc(90% + 2px); border-top: 0; width: calc(100% + 2px); box-sizing: border-box; diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index d8620807..b6b66209 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -45,7 +45,7 @@ export class InputTag extends FormElement { this.select && this.registerElementForValidation(this.select); }); this.shadowRoot.querySelector('slot[name="tag-option"]').addEventListener('click', e => { - this.toggleOptionSelect(e); + this.toggleOptionSelect(e, true); }); } @@ -61,7 +61,7 @@ export class InputTag extends FormElement { } } - toggleOptionSelect(e) { + toggleOptionSelect(e, withFocusOnInput = false) { const target = this.getElAsParentBySlotName(e.target, 'tag-option'); if (target && target.hasAttribute('selected')) { const dataElem = target.querySelector('[data-value]'); @@ -70,6 +70,9 @@ export class InputTag extends FormElement { } else if(target) { this.handleTagSelect(target); } + if (withFocusOnInput) { + this.input.focus(); + } } handleTagSelect(tagOptionSlot) { @@ -94,7 +97,6 @@ export class InputTag extends FormElement { if (hideOptionsAfterSelect) { this.removeAttribute('show-tags'); } - this.input.focus(); } createSelectedTagElement(selectedOptionElement, matchedOptionIndex) { @@ -153,7 +155,6 @@ export class InputTag extends FormElement { selectedOptionElement.parentElement.removeAttribute('selected'); selectedOptionElement.parentElement.setAttribute('aria-selected', 'false'); } - this.input.focus(); } clearSelection() { From 46e3722b38bed2670d9c0da641f8546e72028232 Mon Sep 17 00:00:00 2001 From: Mariusz Padykula Date: Fri, 27 Oct 2023 12:37:18 +0200 Subject: [PATCH 13/13] - add role and label for tag buttons --- src/zoo-modules/form/input-tag/input-tag.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zoo-modules/form/input-tag/input-tag.js b/src/zoo-modules/form/input-tag/input-tag.js index b6b66209..f8f48afe 100644 --- a/src/zoo-modules/form/input-tag/input-tag.js +++ b/src/zoo-modules/form/input-tag/input-tag.js @@ -116,6 +116,8 @@ export class InputTag extends FormElement { 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') {