diff --git a/projects/core/.visual/pagination.dark.png b/projects/core/.visual/pagination.dark.png index f54888624..1358893f9 100644 --- a/projects/core/.visual/pagination.dark.png +++ b/projects/core/.visual/pagination.dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:500b5fa3d143be6562a85c659f62be10f2c7e358298e24a0bdd0c734146bca49 -size 15887 +oid sha256:250a084f548e8deb75819f8be3c4c82b8969c41c1949d3ab643a20f2569813b0 +size 15903 diff --git a/projects/core/.visual/pagination.png b/projects/core/.visual/pagination.png index b64a46321..06768f636 100644 --- a/projects/core/.visual/pagination.png +++ b/projects/core/.visual/pagination.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:464605212d1742a1d7dd5342700fea23b0aea2e05dc087b9084939448f279e41 -size 15202 +oid sha256:087ae06f0a3d0ff4f794542a6c070028b7101944b27c9e99728853952717005e +size 15337 diff --git a/projects/core/.visual/select.dark.png b/projects/core/.visual/select.dark.png index 78b4b54fb..b8a19c51c 100644 --- a/projects/core/.visual/select.dark.png +++ b/projects/core/.visual/select.dark.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ce3542c60c801e2764ef1622ceb2f0046996619a4c6c80a53db39bc10c516e1 -size 56856 +oid sha256:f416092d0c6cc6b78e0f45a5a41744fe25b00f895b6c1aae9903810bb09a7bbd +size 54914 diff --git a/projects/core/.visual/select.png b/projects/core/.visual/select.png index a05b5b09f..254bc5002 100644 --- a/projects/core/.visual/select.png +++ b/projects/core/.visual/select.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ab4e007828a2503aa039cd17403388c70b6bcc98042b9e9058bc0f2eae7f880 -size 50625 +oid sha256:60bb957f7720434f776cc5089733a2818d657c69cf46d12572e8f51e841ecdd6 +size 51555 diff --git a/projects/core/src/drawer/drawer.css b/projects/core/src/drawer/drawer.css index 9d54e9021..a70f08e56 100644 --- a/projects/core/src/drawer/drawer.css +++ b/projects/core/src/drawer/drawer.css @@ -107,17 +107,17 @@ nve-icon-button { } :host([position='left']) { - inset: auto auto auto 0; + inset: auto auto auto 0 !important; } :host([position='right']) { - inset: auto 0 auto auto; + inset: auto 0 auto auto !important; } :host([position='top']) { - inset: 0 auto auto; + inset: 0 auto auto !important; } :host([position='bottom']) { - inset: auto auto 0; + inset: auto auto 0 !important; } diff --git a/projects/core/src/drawer/drawer.test.ts b/projects/core/src/drawer/drawer.test.ts index 59118e610..571548838 100644 --- a/projects/core/src/drawer/drawer.test.ts +++ b/projects/core/src/drawer/drawer.test.ts @@ -137,6 +137,19 @@ describe(Drawer.metadata.tag, () => { expect(element.getAttribute('position')).toBe('right'); }); + it.each(['right', 'bottom'] as const)('should position at the viewport %s edge', async position => { + element.position = position; + await elementIsStable(element); + + const open = untilEvent(element, 'open'); + element.showPopover(); + await open; + + const edge = position === 'right' ? 'right' : 'bottom'; + const viewportEdge = position === 'right' ? window.innerWidth : window.innerHeight; + expect(element.getBoundingClientRect()[edge]).toBe(viewportEdge); + }); + it('should reflect modal attribute to DOM', async () => { expect(element.hasAttribute('modal')).toBe(false); element.modal = true; diff --git a/projects/core/src/select/select.css b/projects/core/src/select/select.css index e5000fdff..cc2aa282e 100644 --- a/projects/core/src/select/select.css +++ b/projects/core/src/select/select.css @@ -10,16 +10,21 @@ --border-radius: var(--nve-ref-border-radius-sm); --border: var(--nve-ref-border-width-md) solid transparent; --border-bottom: var(--border); + --gap: var(--nve-ref-space-xxs); --cursor: pointer; --font-weight: normal; --text-align: start; --scroll-height: 50vh; - --_input-background: var(--background); - --_icon-color: var(--color); --width: 100%; --control-width: var(--width); --max-width: 100%; --min-width: fit-content; + --_input-background: var(--background); + --_icon-color: var(--color); + --_gap: var(--gap); + --size: 1; + --_row-height: calc(var(--height) * var(--size) + var(--gap) * (var(--size) - 1)); + --_height: calc(var(--_row-height) + var(--nve-ref-border-width-md) * 2); contain: initial; width: var(--width); max-width: var(--max-width); @@ -35,7 +40,11 @@ } [input] { - height: var(--height); + scroll-behavior: smooth; + scrollbar-color: color-mix(in oklab, var(--nve-sys-scrollbar-thumb-color) 100%, currentColor 20%) + var(--nve-sys-scrollbar-track-color); + scrollbar-width: var(--nve-sys-scrollbar-width); + height: var(--_height); background: var(--background); border: var(--border); border-bottom: var(--border-bottom); @@ -64,7 +73,7 @@ cursor: var(--cursor) !important; font-weight: var(--font-weight) !important; text-align: var(--text-align) !important; - height: var(--height) !important; + height: var(--_height) !important; width: 100% !important; border: 0 !important; background: none !important; @@ -94,7 +103,7 @@ :host(:state(multiple)) .tags { width: fit-content; display: flex; - gap: var(--nve-ref-space-xxs); + gap: var(--gap); } :host(:state(multiple)) .tags-label { @@ -130,10 +139,6 @@ opacity: 0 !important; } -:host(:state(size)) { - --height: calc(var(--nve-ref-size-800) * var(--size)); -} - :host(:state(size)) [input] { overflow: auto; display: block; @@ -184,6 +189,7 @@ nve-dropdown { nve-menu { --max-height: var(--scroll-height); + --gap: var(--_gap); } nve-menu-item { diff --git a/projects/core/src/select/select.test.ts b/projects/core/src/select/select.test.ts index aa9d8556c..ecd7951e2 100644 --- a/projects/core/src/select/select.test.ts +++ b/projects/core/src/select/select.test.ts @@ -700,7 +700,39 @@ describe(`${Select.metadata.tag}: size`, () => { }); it('should set --size property', () => { - expect(getComputedStyle(element).getPropertyValue('--size')).toBe('3.75'); // size (3) + 0.75 buffer + expect(getComputedStyle(element).getPropertyValue('--size')).toBe('3'); + }); + + it('should show all rows without overflow', async () => { + const select = fixture.querySelector('select') as HTMLSelectElement; + for (let optionNumber = 6; optionNumber <= 10; optionNumber++) { + const option = document.createElement('option'); + option.value = `${optionNumber}`; + option.textContent = `Option ${optionNumber}`; + select.append(option); + } + select.size = 10; + await elementIsStable(element); + + const input = element.shadowRoot.querySelector('[input]') as HTMLElement; + const items = element.shadowRoot.querySelectorAll(MenuItem.metadata.tag) as NodeListOf; + const inputBottom = + input.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(input).borderBottomWidth); + const lastItemBottom = items[items.length - 1].getBoundingClientRect().bottom; + + expect(input.scrollTop).toBe(0); + expect(lastItemBottom).toBeCloseTo(inputBottom, 5); + }); + + it('should not leave blank space after the visible rows', () => { + const input = element.shadowRoot.querySelector('[input]'); + const items = element.shadowRoot.querySelectorAll(MenuItem.metadata.tag); + const inputBottom = + input.getBoundingClientRect().bottom - Number.parseFloat(getComputedStyle(input).borderBottomWidth); + const lastVisibleItemBottom = items[2].getBoundingClientRect().bottom; + + expect(input.scrollTop).toBe(0); + expect(lastVisibleItemBottom).toBeCloseTo(inputBottom, 5); }); it('should not render tags when using multiple with size', async () => { diff --git a/projects/core/src/select/select.ts b/projects/core/src/select/select.ts index 0a366ff40..527b9f390 100644 --- a/projects/core/src/select/select.ts +++ b/projects/core/src/select/select.ts @@ -233,7 +233,7 @@ export class Select extends Control { super.updated(props); if (this.#select?.size && this.#select?.size !== 0) { this._internals.states.add('size'); - this.style.setProperty('--size', `${this.#select?.size + 0.75}`); + this.style.setProperty('--size', `${this.#select.size}`); } else { this._internals.states.delete('size'); this.style.removeProperty('--size');