diff --git a/jest.setup.js b/jest.setup.js index 8d6ee667..7e460bab 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1,5 +1,8 @@ import { jest } from '@jest/globals'; +// Mock Popper.js as there is no need to have it +jest.mock('@popperjs/core'); + document.createRange = () => { const range = new Range(); diff --git a/package.json b/package.json index a0e6a37e..c1548f63 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@codemirror/stream-parser": "^0.19.3", "@formatjs/intl-locale": "^2.4.40", "@formatjs/intl-relativetimeformat": "^9.3.2", + "@popperjs/core": "^2.11.7", "clipboard-copy": "^4.0.0", "codemirror-asciidoc": "^2.0.0", "date-fns": "^2.26.0", diff --git a/src/atoms/gv-select/gv-select.js b/src/atoms/gv-select/gv-select.js index a3d4ba09..51ce1e4a 100644 --- a/src/atoms/gv-select/gv-select.js +++ b/src/atoms/gv-select/gv-select.js @@ -25,6 +25,7 @@ import '../gv-icon'; import { dispatchCustomEvent } from '../../lib/events'; import { InputElement } from '../../mixins/input-element'; import { withResizeObserver } from '../../mixins/with-resize-observer'; +import { createPopper } from '@popperjs/core'; /** * A select component, is more like a list box... @@ -149,11 +150,10 @@ export class GvSelect extends withResizeObserver(InputElement(LitElement)) { .select__list { color: var(--c); list-style: none; - position: absolute; + position: fixed; background-color: var(--bgc-list); list-style: none; padding: 0; - transition: all 0.3s ease 0s; margin: 0; width: 100%; cursor: pointer; @@ -366,6 +366,30 @@ export class GvSelect extends withResizeObserver(InputElement(LitElement)) { } } + /** + * When the component has been updated for the first time we can create the + * popper instance that will be used to position the list of options. + */ + firstUpdated() { + const input = this.shadowRoot.querySelector(`#${this._id}`); + const list = this.shadowRoot.querySelector(`#${this._id}-list`); + + if (input && list) { + this.popperInstance = createPopper(input, list, { + placement: 'bottom-start', + strategy: 'fixed', + }); + } + } + + updated() { + if (this.popperInstance) { + // Let's ask the popper instance to update itself to be sure the list of + // options is correctly positioned + this.popperInstance.update(); + } + } + render() { const classes = { box: true, @@ -400,7 +424,12 @@ export class GvSelect extends withResizeObserver(InputElement(LitElement)) { ${this.readonly ? '' - : html`