diff --git a/.changeset/bitter-animals-jump.md b/.changeset/bitter-animals-jump.md new file mode 100644 index 000000000..b47bc4438 --- /dev/null +++ b/.changeset/bitter-animals-jump.md @@ -0,0 +1,5 @@ +--- +"bits-ui": minor +--- + +feat(ScrollArea): allow overriding styles set by internal component logic if desired diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte index 7bec72e13..8017bfdb9 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte @@ -8,6 +8,7 @@ id, children, child, + style, ...restProps }: Omit & { id: string; @@ -21,7 +22,7 @@ ), }); - const mergedProps = $derived(mergeProps(restProps, cornerState.props)); + const mergedProps = $derived(mergeProps(restProps, cornerState.props, { style })); {#if child} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte index 72e8b2611..19377b0d2 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte @@ -5,10 +5,10 @@ import ScrollAreaScrollbarVisible from "./scroll-area-scrollbar-visible.svelte"; import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte"; - let { forceMount = false, ...restProps }: _ScrollbarStubProps = $props(); + let { forceMount = false, style, ...restProps }: _ScrollbarStubProps = $props(); const scrollbarAutoState = ScrollAreaScrollbarAutoState.create(); - const mergedProps = $derived(mergeProps(restProps, scrollbarAutoState.props)); + const mergedProps = $derived(mergeProps(restProps, scrollbarAutoState.props, { style })); {#if child} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-x.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-x.svelte index f8f18b8fa..550a3d6b7 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-x.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-x.svelte @@ -5,7 +5,7 @@ import type { _ScrollbarStubProps } from "../types.js"; import ScrollAreaScrollbarShared from "./scroll-area-scrollbar-shared.svelte"; - let { ...restProps }: _ScrollbarStubProps = $props(); + let { style, ...restProps }: _ScrollbarStubProps = $props(); const isMounted = new IsMounted(); @@ -13,7 +13,7 @@ mounted: boxWith(() => isMounted.current), }); // oxlint-disable-next-line no-explicit-any - const mergedProps = $derived(mergeProps(restProps, scrollbarXState.props)) as any; + const mergedProps = $derived(mergeProps(restProps, scrollbarXState.props, { style })) as any; diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-y.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-y.svelte index 953f520c9..c372b2d27 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-y.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-y.svelte @@ -5,7 +5,7 @@ import type { _ScrollbarStubProps } from "../types.js"; import ScrollAreaScrollbarShared from "./scroll-area-scrollbar-shared.svelte"; - let { ...restProps }: _ScrollbarStubProps = $props(); + let { style, ...restProps }: _ScrollbarStubProps = $props(); const isMounted = new IsMounted(); @@ -14,7 +14,7 @@ }); // oxlint-disable-next-line no-explicit-any - const mergedProps = $derived(mergeProps(restProps, scrollbarYState.props)) as any; + const mergedProps = $derived(mergeProps(restProps, scrollbarYState.props, { style })) as any; diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte index 801046008..41c415e3b 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte @@ -10,6 +10,7 @@ child, children, present, + style, ...restProps }: Omit & { id: string; @@ -28,11 +29,16 @@ }); const mergedProps = $derived( - mergeProps(restProps, thumbState.props, { - style: { - hidden: !present, - }, - }) + mergeProps( + restProps, + thumbState.props, + { style }, + { + style: { + hidden: !present, + }, + } + ) ); diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-viewport.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-viewport.svelte index 43b4e02a4..c8706a6ea 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-viewport.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-viewport.svelte @@ -10,6 +10,7 @@ ref = $bindable(null), id = createId(uid), children, + style, ...restProps }: ScrollAreaViewportProps = $props(); @@ -21,7 +22,7 @@ ), }); - const mergedProps = $derived(mergeProps(restProps, viewportState.props)); + const mergedProps = $derived(mergeProps(restProps, viewportState.props, { style })); const mergedContentProps = $derived(mergeProps({}, viewportState.contentProps)); diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area.svelte index 536ac4fa7..6188769e7 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area.svelte @@ -14,6 +14,7 @@ scrollHideDelay = 600, children, child, + style, ...restProps }: ScrollAreaRootProps = $props(); @@ -28,7 +29,7 @@ ), }); - const mergedProps = $derived(mergeProps(restProps, rootState.props)); + const mergedProps = $derived(mergeProps(restProps, rootState.props, { style })); {#if child} diff --git a/tests/src/tests/scroll-area/scroll-area-style-override-test.svelte b/tests/src/tests/scroll-area/scroll-area-style-override-test.svelte new file mode 100644 index 000000000..ea8dd7358 --- /dev/null +++ b/tests/src/tests/scroll-area/scroll-area-style-override-test.svelte @@ -0,0 +1,30 @@ + + + + + + + {#each Array(20) as _, i (i)} +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Dignissimos impedit rem, + repellat deserunt ducimus quasi nisi voluptatem. +

+ {/each} +
+ + + +
diff --git a/tests/src/tests/scroll-area/scroll-area.browser.test.ts b/tests/src/tests/scroll-area/scroll-area.browser.test.ts index 18d27eab8..71ce5db40 100644 --- a/tests/src/tests/scroll-area/scroll-area.browser.test.ts +++ b/tests/src/tests/scroll-area/scroll-area.browser.test.ts @@ -2,6 +2,9 @@ import { expect, it, vi, describe } from "vitest"; import { render } from "vitest-browser-svelte"; import { getTestKbd } from "../utils.js"; import ScrollAreaTest, { type ScrollAreaTestProps } from "./scroll-area-test.svelte"; +import ScrollAreaStyleOverrideTest, { + type ScrollAreaStyleOverrideTestProps, +} from "./scroll-area-style-override-test.svelte"; import { expectExists, expectNotExists } from "../browser-utils"; import { page, userEvent } from "@vitest/browser/context"; @@ -310,4 +313,14 @@ describe("ScrollArea", () => { await vi.waitFor(() => expect(t.viewport.element().scrollLeft).not.toBe(initialScrollLeft)); }); + + it("should allow overriding predefined scrollbar styles via style prop", async () => { + render(ScrollAreaStyleOverrideTest, { scrollbarYStyle: "top: 20px;" }); + + const scrollbarY = page.getByTestId("scrollbar-y"); + await expectExists(scrollbarY); + + const element = scrollbarY.element() as HTMLElement; + expect(element.style.top).toBe("20px"); + }); });