Skip to content

Commit

Permalink
fix: ScrollbarX issues (melt-ui#1046)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored and lolcabanon committed Apr 20, 2024
1 parent c2263cd commit ef39b8e
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-dots-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@melt-ui/svelte': patch
---

Scroll Area: fixed bug with `type: 'hover'` scrollbars always showing on hover even if content not overflowing
5 changes: 5 additions & 0 deletions .changeset/six-vans-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@melt-ui/svelte': patch
---

Scroll Area: fixed bug with `scrollbarX` styles
19 changes: 17 additions & 2 deletions src/docs/previews/scroll-area/main/tailwind/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@
import { flavors } from './flavors.js';
const {
elements: { root, content, viewport, corner, scrollbarY, thumbY },
elements: {
root,
content,
viewport,
corner,
scrollbarY,
thumbY,
thumbX,
scrollbarX,
},
} = createScrollArea({
type: 'hover',
dir: 'ltr',
Expand All @@ -12,7 +21,7 @@

<div
use:melt={$root}
class="relative h-72 w-56 overflow-hidden rounded-md border bg-white text-magnum-900 shadow-lg"
class="relative h-72 w-52 overflow-hidden rounded-md border bg-white text-magnum-900 shadow-lg"
>
<div use:melt={$viewport} class="h-full w-full rounded-[inherit]">
<div use:melt={$content}>
Expand All @@ -36,5 +45,11 @@
class="relative flex-1 rounded-full bg-magnum-600"
/>
</div>
<div
use:melt={$scrollbarX}
class="flex h-2.5 w-full touch-none select-none border-t border-t-transparent bg-magnum-800/10 p-px"
>
<div use:melt={$thumbX} class="relative rounded-full bg-magnum-600" />
</div>
<div use:melt={$corner} />
</div>
13 changes: 9 additions & 4 deletions src/lib/builders/scroll-area/scrollbars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,12 @@ export function createHoverScrollbarAction(state: ScrollAreaState) {
function handlePointerEnter() {
window.clearTimeout(timeout);
if (scrollbarState.isVisible.get()) return;
scrollbarState.isVisible.set(true);
const $viewportEl = rootState.viewportEl.get();
if (!$viewportEl) return;
const isOverflowX = $viewportEl.offsetWidth < $viewportEl.scrollWidth;
const isOverflowY = $viewportEl.offsetHeight < $viewportEl.scrollHeight;

scrollbarState.isVisible.set(scrollbarState.isHorizontal.get() ? isOverflowX : isOverflowY);
}

function handlePointerLeave() {
Expand Down Expand Up @@ -347,9 +352,9 @@ export function createScrollbarX(state: ScrollAreaState, createAction: CreateScr
position: 'absolute',
bottom: 0,
left: $dir === 'rtl' ? 'var(--melt-scroll-area-corner-width)' : 0,
right: $dir === 'ltr' ? 'var(--melt-scroll-area-corner-width' : 0,
'--melt-scroll-area-thumb-width': $sizes ? `${getThumbSize($sizes)}px` : undefined,
display: !$isVisible ? 'none' : undefined,
right: $dir === 'ltr' ? 'var(--melt-scroll-area-corner-width)' : 0,
'--melt-scroll-area-thumb-width': `${getThumbSize($sizes)}px`,
visibility: !$isVisible ? 'hidden' : undefined,
}),
'data-state': $isVisible ? 'visible' : 'hidden',
};
Expand Down
96 changes: 96 additions & 0 deletions src/tests/scroll-area/ScrollArea.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { render, waitFor, fireEvent } from '@testing-library/svelte';
import { describe, it } from 'vitest';
import { userEvent } from '@testing-library/user-event';
import ScrollAreaTest from './ScrollAreaTest.svelte';
import type { CreateScrollAreaProps } from '$lib/index.js';

function setup(
props?: CreateScrollAreaProps & {
height?: string;
width?: string;
}
) {
const user = userEvent.setup();
const returned = render(ScrollAreaTest, { props });
const root = returned.getByTestId('root');
const scrollbarX = returned.getByTestId('scrollbar-x');
const scrollbarY = returned.getByTestId('scrollbar-y');
const content = returned.getByTestId('content');
const thumbX = returned.getByTestId('thumb-x');
const thumbY = returned.getByTestId('thumb-y');

return {
user,
elements: {
scrollbarX,
scrollbarY,
content,
thumbX,
thumbY,
root,
},
...returned,
};
}

describe('Scroll Area', () => {
it('Displays the scrollbars when `type` is "always"', async () => {
const { elements } = setup({
type: 'always',
});

expect(elements.scrollbarX).toBeVisible();
expect(elements.scrollbarY).toBeVisible();
});

it('Displays the x scrollbar when `type` is "auto" and content overflows', async () => {
const { elements } = setup({
type: 'always',
width: '10px',
});

expect(elements.scrollbarX).toBeVisible();
});

it('Displays the y scrollbar when `type` is "auto" and content overflows', async () => {
const { elements } = setup({
type: 'always',
height: '10px',
});

expect(elements.scrollbarY).toBeVisible();
});

it("Doesn't display the scrollbars when `type` is 'auto' and content doesn't overflow", async () => {
const { elements } = setup({
type: 'auto',
width: '5000px',
height: '5000px',
});

await waitFor(() => expect(elements.scrollbarX).not.toBeVisible());
await waitFor(() => expect(elements.scrollbarY).not.toBeVisible());
});

// I hate vitest/testing library sometimes.
it.skip('Displays the scrollbars on hover', async () => {
const { elements } = setup({
type: 'hover',
width: '10px',
height: '10px',
});

await waitFor(() => expect(elements.scrollbarX).not.toBeVisible());
await waitFor(() => expect(elements.scrollbarY).not.toBeVisible());

await fireEvent.pointerEnter(elements.root);

await waitFor(() => expect(elements.scrollbarX).toBeVisible());
await waitFor(() => expect(elements.scrollbarY).toBeVisible());

await fireEvent.pointerLeave(elements.root);

await waitFor(() => expect(elements.scrollbarX).not.toBeVisible());
await waitFor(() => expect(elements.scrollbarY).not.toBeVisible());
});
});
99 changes: 99 additions & 0 deletions src/tests/scroll-area/ScrollAreaTest.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script lang="ts">
import { createScrollArea, melt, type CreateScrollAreaProps } from '$lib/index.js';
import { removeUndefined } from '../utils.js';
const flavors = [
'Vanilla',
'Chocolate',
'Strawberry',
'Mint Chocolate Chip',
'Cookies and Cream',
'Rocky Road',
'Pistachio',
'Neapolitan',
'Butter Pecan',
'Salted Caramel',
'Coffee',
'Mango',
'Raspberry Ripple',
'Lemon Sorbet',
'Green Tea',
'Coconut',
'Black Cherry',
'Banana',
'Almond Fudge',
'Cinnamon',
'Blueberry Cheesecake',
'Tiramisu',
'Red Velvet',
'Matcha',
'Peanut Butter Cup',
'Cookie Dough',
'Rum Raisin',
'Birthday Cake',
'Lychee',
'Honey Lavender',
];
type $$Props = CreateScrollAreaProps & {
height?: string;
width?: string;
};
export let height = '288px';
export let width = '490px';
export let type: $$Props['type'] = 'hover';
const {
elements: { root, content, viewport, corner, scrollbarY, thumbY, scrollbarX, thumbX },
} = createScrollArea(
removeUndefined({
type,
...$$restProps,
})
);
</script>

<div
use:melt={$root}
class="relative overflow-hidden rounded-md border bg-white text-magnum-900 shadow-lg"
data-testid="root"
style:width
style:height
>
<div use:melt={$viewport} class="h-full w-full rounded-[inherit]" data-testid="viewport">
<div use:melt={$content} data-testid="content">
<div class="w-[300px] p-4" data-testid="inner-content">
<h4 class="mb-4 font-semibold leading-none">Endless Flavors</h4>
<div data-testid="hover">Hover me please</div>
{#each flavors as flavor (flavor)}
<div class="text-sm">
{flavor}
</div>
<div role="separator" class="my-2 h-px w-full bg-magnum-600" />
{/each}
</div>
</div>
</div>
<div
use:melt={$scrollbarY}
data-testid="scrollbar-y"
class="flex h-full w-2.5 border-l border-l-transparent bg-magnum-800/10 p-px"
>
<div
use:melt={$thumbY}
data-testid="thumb-y"
class="relative flex-1 rounded-full bg-magnum-600"
/>
</div>

<div
use:melt={$scrollbarX}
data-testid="scrollbar-x"
class="flex h-full w-2.5 border-l border-l-transparent bg-magnum-800/10 p-px"
>
<div use:melt={$thumbX} data-testid="thumb-x" class="relative rounded-full bg-magnum-600" />
</div>
<div use:melt={$corner} />
</div>

0 comments on commit ef39b8e

Please sign in to comment.