diff --git a/cypress/e2e/ui/__snapshots__/scenario.cy.js.snap b/cypress/e2e/ui/__snapshots__/scenario.cy.js.snap index 951917f1..a902aed7 100644 --- a/cypress/e2e/ui/__snapshots__/scenario.cy.js.snap +++ b/cypress/e2e/ui/__snapshots__/scenario.cy.js.snap @@ -497,7 +497,7 @@ exports[`use various parts of svg-edit > check tool_text_align_to_page #0`] = ` stroke="#000000" stroke-width="0" text-anchor="middle" - x="145" + x="623.33" xml:space="preserve" y="145" > diff --git a/cypress/e2e/ui/__snapshots__/scenario5.cy.js.snap b/cypress/e2e/ui/__snapshots__/scenario5.cy.js.snap index eec8bfd2..b1080505 100644 --- a/cypress/e2e/ui/__snapshots__/scenario5.cy.js.snap +++ b/cypress/e2e/ui/__snapshots__/scenario5.cy.js.snap @@ -457,8 +457,8 @@ exports[`use all parts of svg-edit > check tool_line_align_to_page #0`] = ` opacity="0.25" stroke="#bf5f00" stroke-width="5" - x1="220" - x2="470" + x1="387.5" + x2="637.5" y1="220" y2="470" > diff --git a/cypress/e2e/ui/__snapshots__/scenario6.cy.js.snap b/cypress/e2e/ui/__snapshots__/scenario6.cy.js.snap index 92ed5005..e76904c2 100644 --- a/cypress/e2e/ui/__snapshots__/scenario6.cy.js.snap +++ b/cypress/e2e/ui/__snapshots__/scenario6.cy.js.snap @@ -377,7 +377,7 @@ exports[`use all parts of svg-edit > check tool_polygon_align_to_page #0`] = ` fill="#FF0000" id="svg_1" orient="x" - points="378.87455119562924,250 341.6481518837726,301.23774297708 281.41457251841285,281.6666666666667 281.4145725184128,218.33333333333334 341.6481518837726,198.76225702291998 378.87455119562924,250 " + points="637.5,250 600.2736206054688,301.23773193359375 540.0400390625,281.6666564941406 540.0400390625,218.3333282470703 600.2736206054688,198.7622528076172 637.5,250 " shape="regularPoly" sides="5" stroke="#000000" @@ -405,7 +405,7 @@ exports[`use all parts of svg-edit > check tool_polygon_change_stroke_width #0`] fill="#FF0000" id="svg_1" orient="x" - points="378.87455119562924,250 341.6481518837726,301.23774297708 281.41457251841285,281.6666666666667 281.4145725184128,218.33333333333334 341.6481518837726,198.76225702291998 378.87455119562924,250 " + points="637.5,250 600.2736206054688,301.23773193359375 540.0400390625,281.6666564941406 540.0400390625,218.3333282470703 600.2736206054688,198.7622528076172 637.5,250 " shape="regularPoly" sides="5" stroke="#000000" @@ -433,7 +433,7 @@ exports[`use all parts of svg-edit > check tool_polygon_change_stoke_fill_color fill="#bf0000" id="svg_1" orient="x" - points="378.87455119562924,250 341.6481518837726,301.23774297708 281.41457251841285,281.6666666666667 281.4145725184128,218.33333333333334 341.6481518837726,198.76225702291998 378.87455119562924,250 " + points="637.5,250 600.2736206054688,301.23773193359375 540.0400390625,281.6666564941406 540.0400390625,218.3333282470703 600.2736206054688,198.7622528076172 637.5,250 " shape="regularPoly" sides="5" stroke="#0000bf" @@ -461,7 +461,7 @@ exports[`use all parts of svg-edit > check tool_polygon_change_sides #0`] = ` fill="#bf0000" id="svg_1" orient="x" - points="406.36004929315476,249.999995640346 374.69338262648813,304.8482712133604 311.3600492931548,304.8482712133604 279.69338262648813,249.999995640346 311.36004929315476,195.15172006733155 374.69338262648813,195.15172006733155 406.36004929315476,249.99999564034596 " + points="664.9855026971727,249.999995640346 633.318836030506,304.8482712133604 569.9855026971727,304.8482712133604 538.318836030506,249.999995640346 569.9855026971726,195.15172006733155 633.318836030506,195.15172006733155 664.9855026971727,249.99999564034596 " shape="regularPoly" sides="6" stroke="#0000bf" diff --git a/cypress/e2e/ui/__snapshots__/scenario7.cy.js.snap b/cypress/e2e/ui/__snapshots__/scenario7.cy.js.snap index 43ad9460..68f17a88 100644 --- a/cypress/e2e/ui/__snapshots__/scenario7.cy.js.snap +++ b/cypress/e2e/ui/__snapshots__/scenario7.cy.js.snap @@ -419,7 +419,7 @@ exports[`use all parts of svg-edit > check tool_star_align_to_page #0`] = ` id="svg_1" orient="point" point="5" - points="300,83.33333333333333 313.0618944953883,132.02184456944562 363.40376775301024,129.39886704167017 321.13458925100343,156.86704431944327 339.18568348616486,203.93446629166317 300,172.22222222222223 260.81431651383514,203.93446629166317 278.86541074899657,156.86704431944327 236.59623224698976,129.39886704167017 286.9381055046117,132.02184456944562 300,83.33333333333333 313.0618944953883,132.02184456944562 " + points="574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 637.5,129.39886474609375 595.2308044433594,156.86705017089844 613.2818908691406,203.93446350097656 574.0962219238281,172.22222900390625 534.9105529785156,203.93446350097656 552.9616394042969,156.86705017089844 510.6924591064453,129.39886474609375 561.0343322753906,132.0218505859375 574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 " r="66.67" r2="22.22" radialshift="0" @@ -450,7 +450,7 @@ exports[`use all parts of svg-edit > check tool_star_change_stroke_width #0`] = id="svg_1" orient="point" point="5" - points="300,83.33333333333333 313.0618944953883,132.02184456944562 363.40376775301024,129.39886704167017 321.13458925100343,156.86704431944327 339.18568348616486,203.93446629166317 300,172.22222222222223 260.81431651383514,203.93446629166317 278.86541074899657,156.86704431944327 236.59623224698976,129.39886704167017 286.9381055046117,132.02184456944562 300,83.33333333333333 313.0618944953883,132.02184456944562 " + points="574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 637.5,129.39886474609375 595.2308044433594,156.86705017089844 613.2818908691406,203.93446350097656 574.0962219238281,172.22222900390625 534.9105529785156,203.93446350097656 552.9616394042969,156.86705017089844 510.6924591064453,129.39886474609375 561.0343322753906,132.0218505859375 574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 " r="66.67" r2="22.22" radialshift="0" @@ -481,7 +481,7 @@ exports[`use all parts of svg-edit > check tool_star_change_stoke_fill_color #0` id="svg_1" orient="point" point="5" - points="300,83.33333333333333 313.0618944953883,132.02184456944562 363.40376775301024,129.39886704167017 321.13458925100343,156.86704431944327 339.18568348616486,203.93446629166317 300,172.22222222222223 260.81431651383514,203.93446629166317 278.86541074899657,156.86704431944327 236.59623224698976,129.39886704167017 286.9381055046117,132.02184456944562 300,83.33333333333333 313.0618944953883,132.02184456944562 " + points="574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 637.5,129.39886474609375 595.2308044433594,156.86705017089844 613.2818908691406,203.93446350097656 574.0962219238281,172.22222900390625 534.9105529785156,203.93446350097656 552.9616394042969,156.86705017089844 510.6924591064453,129.39886474609375 561.0343322753906,132.0218505859375 574.0962219238281,83.33333587646484 587.1581115722656,132.0218505859375 " r="66.67" r2="22.22" radialshift="0" @@ -512,7 +512,7 @@ exports[`use all parts of svg-edit > check tool_star_change_sides #0`] = ` id="svg_1" orient="point" point="6" - points="301.8821476527623,70.14305132911319 312.99325876387337,117.56470902279233 359.61717457172483,103.47638466244652 324.1043698749845,136.80971799577986 359.6171745717249,170.14305132911318 312.9932587638734,156.0547269687674 301.8821476527623,203.47638466244655 290.7710365416512,156.0547269687674 244.1471207337997,170.14305132911323 279.65992543054006,136.80971799577986 244.1471207337997,103.47638466244652 290.7710365416512,117.56470902279233 301.8821476527623,70.14305132911319 312.9932587638734,117.56470902279233 " + points="575.9783673967634,70.14305132911319 587.0894785078744,117.56470902279233 633.713394315726,103.47638466244652 598.2005896189855,136.80971799577986 633.713394315726,170.14305132911318 587.0894785078744,156.0547269687674 575.9783673967634,203.47638466244655 564.8672562856523,156.0547269687674 518.2433404778008,170.14305132911323 553.7561451745412,136.80971799577986 518.2433404778008,103.47638466244652 564.8672562856523,117.56470902279233 575.9783673967634,70.14305132911319 587.0894785078744,117.56470902279233 " r="66.67" r2="22.22" radialshift="0" diff --git a/cypress/e2e/ui/scenario.cy.js b/cypress/e2e/ui/scenario.cy.js index 1e69b765..92450468 100644 --- a/cypress/e2e/ui/scenario.cy.js +++ b/cypress/e2e/ui/scenario.cy.js @@ -125,8 +125,8 @@ describe('use various parts of svg-edit', function () { }) it('check tool_text_align_to_page', function () { cy.get('#svg_2').click({ force: true }) - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') - cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('elix-option').eq(0) + cy.get('#tool_position').shadow().find('#select-container').eq(0).click({ force: true }) + cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('[aria-label="option"]').eq(0) .click({ force: true }) testSnapshot() }) diff --git a/cypress/e2e/ui/scenario5.cy.js b/cypress/e2e/ui/scenario5.cy.js index 3ec70183..f68ccb8f 100644 --- a/cypress/e2e/ui/scenario5.cy.js +++ b/cypress/e2e/ui/scenario5.cy.js @@ -141,8 +141,8 @@ describe('use all parts of svg-edit', function () { }) it('check tool_line_align_to_page', function () { cy.get('#svg_3').click({ force: true }) - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') - cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('elix-option').eq(0) + cy.get('#tool_position').shadow().find('#select-container').eq(0).click({ force: true }) + cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('[aria-label="option"]').eq(0) .click({ force: true }) testSnapshot() }) diff --git a/cypress/e2e/ui/scenario6.cy.js b/cypress/e2e/ui/scenario6.cy.js index 53e4c1d9..acba6044 100644 --- a/cypress/e2e/ui/scenario6.cy.js +++ b/cypress/e2e/ui/scenario6.cy.js @@ -94,8 +94,8 @@ describe('use all parts of svg-edit', function () { }) it('check tool_polygon_align_to_page', function () { cy.get('#svg_1').click({ force: true }) - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') - cy.get('#tool_position').find('se-list-item').eq(0).shadow().find('elix-option').eq(0) + cy.get('#tool_position').shadow().find('#select-container').eq(0).click({ force: true }) + cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('[aria-label="option"]').eq(0) .click({ force: true }) testSnapshot() }) diff --git a/cypress/e2e/ui/scenario7.cy.js b/cypress/e2e/ui/scenario7.cy.js index e5f273eb..8485c97f 100644 --- a/cypress/e2e/ui/scenario7.cy.js +++ b/cypress/e2e/ui/scenario7.cy.js @@ -94,8 +94,8 @@ describe('use all parts of svg-edit', function () { }) it('check tool_star_align_to_page', function () { cy.get('#svg_1').click({ force: true }) - cy.get('#tool_position').shadow().find('elix-dropdown-list').eq(0).invoke('attr', 'opened', 'opened') - cy.get('#tool_position').find('se-list-item').eq(0).shadow().find('elix-option').eq(0) + cy.get('#tool_position').shadow().find('#select-container').eq(0).click({ force: true }) + cy.get('#tool_position').find('se-list-item').eq(2).shadow().find('[aria-label="option"]').eq(0) .click({ force: true }) testSnapshot() }) diff --git a/src/editor/components/seList.js b/src/editor/components/seList.js index f3932e9d..e3620219 100644 --- a/src/editor/components/seList.js +++ b/src/editor/components/seList.js @@ -1,34 +1,46 @@ /* globals svgEditor */ -import 'elix/define/DropdownList.js' import { t } from '../locale.js' const template = document.createElement('template') template.innerHTML = ` - - - +
+
+
+ +
+
` /** @@ -43,11 +55,47 @@ export class SeList extends HTMLElement { // create the shadowDom and insert the template this._shadowRoot = this.attachShadow({ mode: 'open' }) this._shadowRoot.append(template.content.cloneNode(true)) - this.$dropdown = this._shadowRoot.querySelector('elix-dropdown-list') + this.$dropdown = this._shadowRoot.querySelector('#select-container') this.$label = this._shadowRoot.querySelector('label') - this.$selection = this.$dropdown.shadowRoot.querySelector('#value') + this.$selection = this.$dropdown.querySelector('#selected-value') this.items = this.querySelectorAll('se-list-item') this.imgPath = svgEditor.configObj.curConfig.imgPath + this.$optionsContainer = this._shadowRoot.querySelector('#options-container') + this.$optionsContainer.classList.add('closed') + this.$selection.addEventListener('click', this.toggleList) + this.updateSelectedValue(this.items[0].getAttribute('value')) + this.isDropdownOpen = false + } + + toggleList = (e) => { + if (!this.isDropdownOpen) { + this.openDropdown() + this.setDropdownListPosition() + } else { + this.closeDropdown() + } + } + + updateSelectedValue = (newValue) => { + Array.from(this.items).forEach((element) => { + if (element.getAttribute('value') === newValue) { + element.setAttribute('selected', true) + if (element.hasAttribute('src')) { + // empty current selection children + while (this.$selection.firstChild) { this.$selection.removeChild(this.$selection.firstChild) } + // replace selection child with image of new value + const img = document.createElement('img') + img.src = this.imgPath + '/' + element.getAttribute('src') + img.style.height = element.getAttribute('img-height') + img.setAttribute('title', t(element.getAttribute('title'))) + this.$selection.append(img) + } else { + this.$selection.textContent = t(element.getAttribute('option')) + } + } else { + element.setAttribute('selected', false) + } + }) } /** @@ -66,7 +114,6 @@ export class SeList extends HTMLElement { * @returns {void} */ attributeChangedCallback (name, oldValue, newValue) { - const currentObj = this if (oldValue === newValue) return switch (name) { case 'title': @@ -82,22 +129,7 @@ export class SeList extends HTMLElement { this.$dropdown.style.width = newValue break case 'value': - Array.from(this.items).forEach(function (element) { - if (element.getAttribute('value') === newValue) { - if (element.hasAttribute('src')) { - // empty current selection children - while (currentObj.$selection.firstChild) { currentObj.$selection.removeChild(currentObj.$selection.firstChild) } - // replace selection child with image of new value - const img = document.createElement('img') - img.src = currentObj.imgPath + '/' + element.getAttribute('src') - img.style.height = element.getAttribute('img-height') - img.setAttribute('title', t(element.getAttribute('title'))) - currentObj.$selection.append(img) - } else { - currentObj.$selection.textContent = t(element.getAttribute('option')) - } - } - }) + this.updateSelectedValue(newValue) break default: console.error(`unknown attribute: ${name}`) @@ -169,6 +201,30 @@ export class SeList extends HTMLElement { this.setAttribute('height', value) } + openDropdown = () => { + this.isDropdownOpen = true + this.$optionsContainer.classList.remove('closed') + } + + closeDropdown = () => { + this.isDropdownOpen = false + this.$optionsContainer.classList.add('closed') + } + + setDropdownListPosition = () => { + const windowHeight = window.innerHeight + const selectedContainerPosition = this.$selection.getBoundingClientRect() + const optionsContainerPosition = this.$optionsContainer.getBoundingClientRect() + // list is bottom of frame - needs to open from above + if (selectedContainerPosition.bottom + optionsContainerPosition.height > windowHeight) { + this.$optionsContainer.style.top = selectedContainerPosition.top - optionsContainerPosition.height + 'px' + this.$optionsContainer.style.left = selectedContainerPosition.left + 'px' + } else { + this.$optionsContainer.style.top = selectedContainerPosition.bottom + 'px' + this.$optionsContainer.style.left = selectedContainerPosition.left + 'px' + } + } + /** * @function connectedCallback * @returns {void} @@ -176,20 +232,28 @@ export class SeList extends HTMLElement { connectedCallback () { const currentObj = this this.$dropdown.addEventListener('selectedindexchange', (e) => { - if (e?.detail?.selectedIndex !== undefined) { - const value = this.$dropdown.selectedItem.getAttribute('value') + if (e?.detail?.selectedItem !== undefined) { + const value = e.detail.selectedItem const closeEvent = new CustomEvent('change', { detail: { value } }) currentObj.dispatchEvent(closeEvent) currentObj.value = value currentObj.setAttribute('value', value) } }) - this.$dropdown.addEventListener('close', (_e) => { - /** with Chrome, selectedindexchange does not fire consistently - * unless you forec change in this close event - */ - this.$dropdown.selectedIndex = this.$dropdown.currentIndex + + this.$dropdown.addEventListener('focusout', (e) => { + this.closeDropdown() }) + + window.addEventListener('mousedown', e => { + // When we click on the canvas and if the dropdown is open, then just close the dropdown and stop the event + if (this.isDropdownOpen) { + if (!e.target.closest('se-list')) { + e.stopPropagation() + this.closeDropdown() + } + } + }, { capture: true }) } } diff --git a/src/editor/components/seListItem.js b/src/editor/components/seListItem.js index 63216b50..4a9b2556 100644 --- a/src/editor/components/seListItem.js +++ b/src/editor/components/seListItem.js @@ -1,22 +1,26 @@ /* globals svgEditor */ -import 'elix/define/Option.js' import { t } from '../locale.js' const template = document.createElement('template') template.innerHTML = ` - +
icon - +
` /** * @class SeMenu @@ -30,12 +34,19 @@ export class SeListItem extends HTMLElement { // create the shadowDom and insert the template this._shadowRoot = this.attachShadow({ mode: 'open' }) this._shadowRoot.append(template.content.cloneNode(true)) - this.$menuitem = this._shadowRoot.querySelector('elix-option') - this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark') - this.$svg.setAttribute('style', 'display: none;') + this.$menuitem = this._shadowRoot.querySelector('[aria-label=option]') + // this.$svg = this.$menuitem.shadowRoot.querySelector('#checkmark') + // this.$svg.setAttribute('style', 'display: none;') this.$img = this._shadowRoot.querySelector('img') this.$img.setAttribute('style', 'display: none;') this.imgPath = svgEditor.configObj.curConfig.imgPath + this.$menuitem.addEventListener('mousedown', e => { + this.$menuitem.dispatchEvent(new CustomEvent('selectedindexchange', { + bubbles: true, + composed: true, + detail: { selectedItem: this.getAttribute('value') } + })) + }) } /** @@ -43,7 +54,7 @@ export class SeListItem extends HTMLElement { * @returns {any} observed */ static get observedAttributes () { - return ['option', 'src', 'title', 'img-height'] + return ['option', 'src', 'title', 'img-height', 'selected'] } /** @@ -70,6 +81,13 @@ export class SeListItem extends HTMLElement { case 'img-height': this.$img.setAttribute('height', newValue) break + case 'selected': + if (newValue === 'true') { + this.$menuitem.classList.add('selected') + } else { + this.$menuitem.classList.remove('selected') + } + break default: console.error(`unknown attribute: ${name}`) break