From 8fd321e4d9ff78a917970ac3b41dd453ca9d8ebe Mon Sep 17 00:00:00 2001 From: emeryro Date: Wed, 25 Jan 2023 15:51:19 +0100 Subject: [PATCH 1/5] close on click outside and escape --- .../vanilla/components/popover/popover.js | 77 +++++++++++++++++-- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/src/implementations/vanilla/components/popover/popover.js b/src/implementations/vanilla/components/popover/popover.js index badb1f53765..dff6e1a6520 100644 --- a/src/implementations/vanilla/components/popover/popover.js +++ b/src/implementations/vanilla/components/popover/popover.js @@ -5,6 +5,7 @@ import { queryOne } from '@ecl/dom-utils'; * @param {Object} options * @param {String} options.toggleSelector Selector for toggling element * @param {Boolean} options.attachClickListener Whether or not to bind click events on toggle + * @param {Boolean} options.attachKeyListener Whether or not to bind keyboard events */ export class Popover { /** @@ -27,6 +28,7 @@ export class Popover { { toggleSelector = '[data-ecl-popover-toggle]', attachClickListener = true, + attachKeyListener = true, } = {} ) { // Check element @@ -41,13 +43,18 @@ export class Popover { // Options this.toggleSelector = toggleSelector; this.attachClickListener = attachClickListener; + this.attachKeyListener = attachKeyListener; // Private variables this.toggle = null; this.target = null; // Bind `this` for use in callbacks + this.openPopover = this.openPopover.bind(this); + this.closePopover = this.closePopover.bind(this); this.handleClickOnToggle = this.handleClickOnToggle.bind(this); + this.handleKeyboardGlobal = this.handleKeyboardGlobal.bind(this); + this.handleClickGlobal = this.handleClickGlobal.bind(this); } /** @@ -56,6 +63,14 @@ export class Popover { init() { this.toggle = queryOne(this.toggleSelector, this.element); + // Bind global events + if (this.attachKeyListener) { + document.addEventListener('keyup', this.handleKeyboardGlobal); + } + if (this.attachClickListener) { + document.addEventListener('click', this.handleClickGlobal); + } + // Get target element this.target = document.querySelector( `#${this.toggle.getAttribute('aria-controls')}` @@ -84,6 +99,14 @@ export class Popover { if (this.attachClickListener && this.toggle) { this.toggle.removeEventListener('click', this.handleClickOnToggle); } + + if (this.attachKeyListener) { + document.removeEventListener('keyup', this.handleKeyboardGlobal); + } + if (this.attachClickListener) { + document.removeEventListener('click', this.handleClickGlobal); + } + if (this.element) { this.element.removeAttribute('data-ecl-auto-initialized'); } @@ -101,12 +124,11 @@ export class Popover { const isExpanded = this.toggle.getAttribute('aria-expanded') === 'true'; // Toggle the popover - this.toggle.setAttribute('aria-expanded', isExpanded ? 'false' : 'true'); if (isExpanded) { - this.target.hidden = true; - } else { - this.target.hidden = false; + this.closePopover(); + return; } + this.openPopover(); // Check available space this.element.classList.remove('ecl-popover--top'); @@ -130,8 +152,53 @@ export class Popover { if (popoverRect.right > screenWidth) { this.element.classList.add('ecl-popover--push-right'); } + } - return this; + /** + * Open the popover. + */ + openPopover() { + this.toggle.setAttribute('aria-expanded', 'true'); + this.target.hidden = false; + } + + /** + * Close the popover. + */ + closePopover() { + this.toggle.setAttribute('aria-expanded', 'false'); + this.target.hidden = true; + } + + /** + * Handles global keyboard events, triggered outside of the popover. + * + * @param {Event} e + */ + handleKeyboardGlobal(e) { + if (!this.target) return; + + // Detect press on Escape + if (e.key === 'Escape' || e.key === 'Esc') { + this.closePopover(); + } + } + + /** + * Handles global click events, triggered outside of the popover. + * + * @param {Event} e + */ + handleClickGlobal(e) { + if (!this.target) return; + + // Check if the popover is open + if (this.toggle.getAttribute('aria-expanded') === 'true') { + // Check if the click occured on the popover + if (!this.target.contains(e.target) && !this.toggle.contains(e.target)) { + this.closePopover(); + } + } } } From 98cc7010191d22c2ac1941dfddd4dffb3d512154 Mon Sep 17 00:00:00 2001 From: emeryro Date: Thu, 26 Jan 2023 08:49:05 +0100 Subject: [PATCH 2/5] arrow position --- .../vanilla/components/popover/_popover.scss | 5 +++-- .../vanilla/components/popover/popover.js | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/implementations/vanilla/components/popover/_popover.scss b/src/implementations/vanilla/components/popover/_popover.scss index 3fb65751e25..007941f2e89 100644 --- a/src/implementations/vanilla/components/popover/_popover.scss +++ b/src/implementations/vanilla/components/popover/_popover.scss @@ -107,7 +107,7 @@ $_item-height: map.get(theme.$line-height-prolonged, 'm') + transform: none; &::before { - left: 25%; + left: var(--ecl-popover-position); } } @@ -117,6 +117,7 @@ $_item-height: map.get(theme.$line-height-prolonged, 'm') + transform: none; &::before { - left: 75%; + left: auto; + right: var(--ecl-popover-position); } } diff --git a/src/implementations/vanilla/components/popover/popover.js b/src/implementations/vanilla/components/popover/popover.js index dff6e1a6520..118d4a0962b 100644 --- a/src/implementations/vanilla/components/popover/popover.js +++ b/src/implementations/vanilla/components/popover/popover.js @@ -147,10 +147,22 @@ export class Popover { if (popoverRect.left < 0) { this.element.classList.add('ecl-popover--push-left'); + + // Adapt arrow position + this.target.style.setProperty( + '--ecl-popover-position', + `${toggleRect.width / 2}px` + ); } if (popoverRect.right > screenWidth) { this.element.classList.add('ecl-popover--push-right'); + + // Adapt arrow position + this.target.style.setProperty( + '--ecl-popover-position', + `calc(${toggleRect.width / 2}px - 0.5rem)` + ); } } From 41350b7ef7d5d77617bcb7d32de370d776f9daed Mon Sep 17 00:00:00 2001 From: emeryro Date: Thu, 26 Jan 2023 09:00:04 +0100 Subject: [PATCH 3/5] cleanup js --- .../vanilla/components/popover/popover.js | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/implementations/vanilla/components/popover/popover.js b/src/implementations/vanilla/components/popover/popover.js index 118d4a0962b..d262877f06a 100644 --- a/src/implementations/vanilla/components/popover/popover.js +++ b/src/implementations/vanilla/components/popover/popover.js @@ -52,6 +52,7 @@ export class Popover { // Bind `this` for use in callbacks this.openPopover = this.openPopover.bind(this); this.closePopover = this.closePopover.bind(this); + this.positionPopover = this.positionPopover.bind(this); this.handleClickOnToggle = this.handleClickOnToggle.bind(this); this.handleKeyboardGlobal = this.handleKeyboardGlobal.bind(this); this.handleClickGlobal = this.handleClickGlobal.bind(this); @@ -128,8 +129,31 @@ export class Popover { this.closePopover(); return; } + this.openPopover(); + this.positionPopover(); + } + + /** + * Open the popover. + */ + openPopover() { + this.toggle.setAttribute('aria-expanded', 'true'); + this.target.hidden = false; + } + + /** + * Close the popover. + */ + closePopover() { + this.toggle.setAttribute('aria-expanded', 'false'); + this.target.hidden = true; + } + /** + * Manage popover position. + */ + positionPopover() { // Check available space this.element.classList.remove('ecl-popover--top'); this.element.classList.remove('ecl-popover--push-left'); @@ -166,22 +190,6 @@ export class Popover { } } - /** - * Open the popover. - */ - openPopover() { - this.toggle.setAttribute('aria-expanded', 'true'); - this.target.hidden = false; - } - - /** - * Close the popover. - */ - closePopover() { - this.toggle.setAttribute('aria-expanded', 'false'); - this.target.hidden = true; - } - /** * Handles global keyboard events, triggered outside of the popover. * From d7c6c0abfdc6d46e887929293cd97f064a3692dd Mon Sep 17 00:00:00 2001 From: emeryro Date: Wed, 1 Feb 2023 10:24:46 +0100 Subject: [PATCH 4/5] update size --- .size-limit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.size-limit.json b/.size-limit.json index 4694209e4fb..5c0cbb2418c 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -17,7 +17,7 @@ { "path": "dist/packages/eu/scripts/ecl-eu.js", "webpack": false, - "limit": "40 KB" + "limit": "41 KB" }, { "path": "dist/packages/eu/styles/ecl-eu.css", From fa932c544a5d48d61a5999727cedd36ce8655348 Mon Sep 17 00:00:00 2001 From: emeryro Date: Wed, 1 Feb 2023 10:32:07 +0100 Subject: [PATCH 5/5] update size --- .size-limit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.size-limit.json b/.size-limit.json index 9723ba38024..eeffea9ae9e 100644 --- a/.size-limit.json +++ b/.size-limit.json @@ -2,7 +2,7 @@ { "path": "dist/packages/ec/scripts/ecl-ec.js", "webpack": false, - "limit": "40 KB" + "limit": "41 KB" }, { "path": "dist/packages/ec/styles/ecl-ec.css",