From 89c295385e13fd685c30dba13b3724b753b2dd9a Mon Sep 17 00:00:00 2001 From: Hunter Johnston <64506580+huntabyte@users.noreply.github.com> Date: Sun, 21 Jul 2024 20:13:47 -0400 Subject: [PATCH] next: Scroll Area (#618) --- NOTICE.txt | 16 +- package.json | 4 +- packages/bits-ui/package.json | 2 +- .../bits-ui/src/lib/bits/date-picker/ctx.ts | 0 .../components/scroll-area-content.svelte | 34 - .../components/scroll-area-corner-impl.svelte | 34 + .../components/scroll-area-corner.svelte | 37 +- .../scroll-area-scrollbar-auto.svelte | 18 + .../scroll-area-scrollbar-hover.svelte | 30 + .../scroll-area-scrollbar-scroll.svelte | 19 + .../scroll-area-scrollbar-shared.svelte | 19 + .../scroll-area-scrollbar-visible.svelte | 16 + .../components/scroll-area-scrollbar-x.svelte | 41 +- .../components/scroll-area-scrollbar-y.svelte | 40 +- .../components/scroll-area-scrollbar.svelte | 48 +- .../components/scroll-area-thumb-impl.svelte | 46 + .../components/scroll-area-thumb-x.svelte | 34 - .../components/scroll-area-thumb-y.svelte | 34 - .../components/scroll-area-thumb.svelte | 30 +- .../components/scroll-area-viewport.svelte | 62 +- .../scroll-area/components/scroll-area.svelte | 74 +- .../bits-ui/src/lib/bits/scroll-area/ctx.ts | 49 - .../bits-ui/src/lib/bits/scroll-area/index.ts | 4 +- .../bits/scroll-area/scroll-area.svelte.ts | 1084 +++++++++++++++++ .../bits-ui/src/lib/bits/scroll-area/types.ts | 79 +- .../lib/bits/select/components/select.svelte | 2 + .../src/lib/bits/select/select.svelte.ts | 5 + packages/bits-ui/src/lib/bits/select/types.ts | 5 + .../focus-scope/focus-scope-stack.svelte.ts | 13 +- .../bits-ui/src/lib/internal/cssToStyleObj.ts | 4 + packages/bits-ui/src/lib/internal/style.ts | 3 +- packages/bits-ui/src/lib/internal/types.ts | 2 +- .../src/lib/internal/useRefById.svelte.ts | 7 + .../lib/internal/useResizeObserver.svelte.ts | 19 + .../tests/link-preview/LinkPreview.spec.ts | 2 +- .../src/tests/scroll-area/ScrollArea.spec.ts | 53 + .../tests/scroll-area/ScrollAreaTest.svelte | 62 + pnpm-lock.yaml | 321 ++--- sites/docs/package.json | 2 +- .../components/demos/alert-dialog-demo.svelte | 2 +- .../components/demos/scroll-area-demo.svelte | 76 +- 41 files changed, 1896 insertions(+), 536 deletions(-) delete mode 100644 packages/bits-ui/src/lib/bits/date-picker/ctx.ts delete mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-content.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-hover.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-scroll.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-shared.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-visible.svelte create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte delete mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-x.svelte delete mode 100644 packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-y.svelte delete mode 100644 packages/bits-ui/src/lib/bits/scroll-area/ctx.ts create mode 100644 packages/bits-ui/src/lib/bits/scroll-area/scroll-area.svelte.ts create mode 100644 packages/bits-ui/src/lib/internal/useResizeObserver.svelte.ts create mode 100644 packages/bits-ui/src/tests/scroll-area/ScrollArea.spec.ts create mode 100644 packages/bits-ui/src/tests/scroll-area/ScrollAreaTest.svelte diff --git a/NOTICE.txt b/NOTICE.txt index 693fff61a..a2e4325c8 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -6,12 +6,12 @@ The following is a list of sources from which code was used/modified in this cod This codebase contains a modified portion of code from Adobe which can be obtained at: * SOURCE: * https://www.npmjs.com/package/@react-aria/utils - * LICENSE: + * LICENSE (Apache 2.0): * https://unpkg.com/@react-aria/utils@3.24.1/LICENSE * SOURCE: * https://www.npmjs.com/package/react-stately - * LICENSE: + * LICENSE (Apache 2.0): * https://unpkg.com/react-stately@3.31.1/LICENSE ------------------------------------------------------------------------------- @@ -19,7 +19,17 @@ This codebase contains a modified portion of code from Adobe which can be obtain This codebase contains a modified portion of code from Melt UI which can be obtained at: * SOURCE: * https://www.npmjs.com/package/@melt-ui/svelte - * LICENSE: + * LICENSE (MIT): * https://unpkg.com/@melt-ui/svelte@0.76.2/LICENSE +------------------------------------------------------------------------------- + +This codebase contains a modified portion of code from Radix UI which can be obtained at: + * SOURCE: + * https://www.npmjs.com/package/@radix-ui/react-scroll-area + * https://www.npmjs.com/package/@radix-ui/react-select + * https://www.npmjs.com/package/@radix-ui/react-navigation-menu + * LICENSE (MIT): + * https://github.com/radix-ui/primitives/blob/main/LICENSE + ------------------------------------------------------------------------------- \ No newline at end of file diff --git a/package.json b/package.json index 9f9473eb3..2e7dc35eb 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "prettier": "^3.2.5", "prettier-plugin-svelte": "^3.2.2", "prettier-plugin-tailwindcss": "0.5.13", - "svelte": "5.0.0-next.183", - "svelte-eslint-parser": "^0.34.1", + "svelte": "5.0.0-next.192", + "svelte-eslint-parser": "^0.41.0", "wrangler": "^3.44.0" }, "type": "module", diff --git a/packages/bits-ui/package.json b/packages/bits-ui/package.json index e79c9c01d..a7db5c4a2 100644 --- a/packages/bits-ui/package.json +++ b/packages/bits-ui/package.json @@ -45,7 +45,7 @@ "jsdom": "^24.1.0", "publint": "^0.2.8", "resize-observer-polyfill": "^1.5.1", - "svelte": "5.0.0-next.183", + "svelte": "5.0.0-next.192", "svelte-check": "^3.8.4", "tslib": "^2.6.3", "typescript": "^5.5.3", diff --git a/packages/bits-ui/src/lib/bits/date-picker/ctx.ts b/packages/bits-ui/src/lib/bits/date-picker/ctx.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-content.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-content.svelte deleted file mode 100644 index e52fe9cd4..000000000 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-content.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - -{#if asChild} - -{:else} -
- -
-{/if} 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 new file mode 100644 index 000000000..58f7c88af --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner-impl.svelte @@ -0,0 +1,34 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} +
+ {@render children?.()} +
+{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner.svelte index f1f963903..4c140d8c6 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-corner.svelte @@ -1,34 +1,19 @@ -{#if asChild} - -{:else} -
- -
+{#if hasCorner} + {/if} 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 new file mode 100644 index 000000000..5deb539a6 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-auto.svelte @@ -0,0 +1,18 @@ + + + + {#snippet presence()} + + {/snippet} + diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-hover.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-hover.svelte new file mode 100644 index 000000000..2eac4b321 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-hover.svelte @@ -0,0 +1,30 @@ + + + + {#snippet presence()} + + {/snippet} + diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-scroll.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-scroll.svelte new file mode 100644 index 000000000..6f9446374 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-scroll.svelte @@ -0,0 +1,19 @@ + + + + {#snippet presence()} + + {/snippet} + diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-shared.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-shared.svelte new file mode 100644 index 000000000..2daca8735 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-shared.svelte @@ -0,0 +1,19 @@ + + +{#if child} + {@render child?.({ props: mergedProps })} +{:else} +
+ {@render children?.()} +
+{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-visible.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-visible.svelte new file mode 100644 index 000000000..c7ed29643 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar-visible.svelte @@ -0,0 +1,16 @@ + + +{#if scrollbarVisibleState.scrollbar.orientation.value === "horizontal"} + +{:else} + +{/if} 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 9de173ca6..48326a84d 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 @@ -1,34 +1,19 @@ -{#if asChild} - -{:else} -
- -
-{/if} + 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 0187f169c..d3ae04865 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 @@ -1,34 +1,20 @@ -{#if asChild} - -{:else} -
- -
-{/if} + diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar.svelte index 9bb94eb24..a580517ab 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-scrollbar.svelte @@ -1,26 +1,38 @@ -{#if $orientationStore === "vertical"} - - - -{:else} - - - +{#if type === "hover"} + +{:else if type === "scroll"} + +{:else if type === "auto"} + +{:else if type === "always"} + {/if} 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 new file mode 100644 index 000000000..5e54c59f3 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-impl.svelte @@ -0,0 +1,46 @@ + + +{#if child} + {@render child({ props: mergedProps })} +{:else} +
+ {@render children?.()} +
+{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-x.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-x.svelte deleted file mode 100644 index 82697c5ed..000000000 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-x.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - -{#if asChild} - -{:else} -
- -
-{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-y.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-y.svelte deleted file mode 100644 index 341e3a786..000000000 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb-y.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - -{#if asChild} - -{:else} -
- -
-{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb.svelte b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb.svelte index 3f9ff0855..60da39621 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb.svelte +++ b/packages/bits-ui/src/lib/bits/scroll-area/components/scroll-area-thumb.svelte @@ -1,20 +1,22 @@ -{#if $orientation === "vertical"} - - - -{:else} - - - -{/if} + + {#snippet presence()} + + {/snippet} + 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 7c933fb36..c2a9f6970 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 @@ -1,34 +1,38 @@ -{#if asChild} - -{:else} -
- +
+
+ {@render children?.()}
-{/if} +
+ + 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 ae8093dc1..030712af0 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 @@ -1,51 +1,39 @@ -{#if asChild} - +{#if child} + {@render child({ props: mergedProps })} {:else} -
- +
+ {@render children?.()}
{/if} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/ctx.ts b/packages/bits-ui/src/lib/bits/scroll-area/ctx.ts deleted file mode 100644 index 14e9030f4..000000000 --- a/packages/bits-ui/src/lib/bits/scroll-area/ctx.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { type CreateScrollAreaProps, createScrollArea } from "@melt-ui/svelte"; -import { getContext, setContext } from "svelte"; -import type { Writable } from "svelte/store"; -import { createBitAttrs, getOptionUpdater, removeUndefined } from "$lib/internal/index.js"; - -function getScrollAreaData() { - const NAME = "scroll-area" as const; - const SCROLLBAR_NAME = "scrollbar" as const; - const PARTS = [ - "scrollbar-x", - "scrollbar-y", - "thumb-x", - "thumb-y", - "viewport", - "content", - "root", - "corner", - ] as const; - - return { NAME, PARTS, SCROLLBAR_NAME }; -} - -type GetReturn = Omit, "updateOption">; - -export function setCtx(props: CreateScrollAreaProps) { - const { NAME, PARTS } = getScrollAreaData(); - const getAttrs = createBitAttrs(NAME, PARTS); - const scrollArea = { ...createScrollArea(removeUndefined(props)), getAttrs }; - setContext(NAME, scrollArea); - return { - ...scrollArea, - updateOption: getOptionUpdater(scrollArea.options), - }; -} - -export function getCtx() { - const { NAME } = getScrollAreaData(); - return getContext(NAME); -} - -export function setScrollbarOrientation(orientation: Writable<"horizontal" | "vertical">) { - const { SCROLLBAR_NAME } = getScrollAreaData(); - return setContext(SCROLLBAR_NAME, orientation); -} - -export function getScrollbarOrientation() { - const { SCROLLBAR_NAME } = getScrollAreaData(); - return getContext>(SCROLLBAR_NAME); -} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/index.ts b/packages/bits-ui/src/lib/bits/scroll-area/index.ts index 87f702b39..19a5ac1ef 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/index.ts +++ b/packages/bits-ui/src/lib/bits/scroll-area/index.ts @@ -1,14 +1,12 @@ export { default as Root } from "./components/scroll-area.svelte"; export { default as Viewport } from "./components/scroll-area-viewport.svelte"; -export { default as Content } from "./components/scroll-area-content.svelte"; export { default as Scrollbar } from "./components/scroll-area-scrollbar.svelte"; export { default as Thumb } from "./components/scroll-area-thumb.svelte"; export { default as Corner } from "./components/scroll-area-corner.svelte"; export type { - ScrollAreaProps as Props, + ScrollAreaRootProps as RootProps, ScrollAreaViewportProps as ViewportProps, - ScrollAreaContentProps as ContentProps, ScrollAreaScrollbarProps as ScrollbarProps, ScrollAreaThumbProps as ThumbProps, ScrollAreaCornerProps as CornerProps, diff --git a/packages/bits-ui/src/lib/bits/scroll-area/scroll-area.svelte.ts b/packages/bits-ui/src/lib/bits/scroll-area/scroll-area.svelte.ts new file mode 100644 index 000000000..f33b6eeb1 --- /dev/null +++ b/packages/bits-ui/src/lib/bits/scroll-area/scroll-area.svelte.ts @@ -0,0 +1,1084 @@ +/** + * This logic is adapted from Radix UI's ScrollArea component. + * https://github.com/radix-ui/primitives/blob/main/packages/react/scroll-area/src/ScrollArea.tsx + * Credit to Jenna Smith (@jjenzz) for the original implementation. + * Incredible thought must have went into solving all the intricacies of this component. + */ + +import type { ReadableBoxedValues } from "$lib/internal/box.svelte.js"; +import { executeCallbacks } from "$lib/internal/callbacks.js"; +import { addEventListener } from "$lib/internal/events.js"; +import type { WithRefProps } from "$lib/internal/types.js"; +import { useRefById } from "$lib/internal/useRefById.svelte.js"; +import { mergeProps, useId, type Direction, type Orientation } from "$lib/shared/index.js"; +import { useDebounce } from "runed"; +import type { ScrollAreaType } from "./types.js"; +import { useStateMachine } from "$lib/internal/useStateMachine.svelte.js"; +import { clamp } from "$lib/internal/clamp.js"; +import { useResizeObserver } from "$lib/internal/useResizeObserver.svelte.js"; +import { untrack } from "svelte"; +import { createContext } from "$lib/internal/createContext.js"; +import { box } from "svelte-toolbelt"; +import { afterTick } from "$lib/internal/afterTick.js"; + +const SCROLL_AREA_ROOT_ATTR = "data-scroll-area-root"; +const SCROLL_AREA_VIEWPORT_ATTR = "data-scroll-area-viewport"; +const SCROLL_AREA_CORNER_ATTR = "data-scroll-area-corner"; +const SCROLL_AREA_THUMB_ATTR = "data-scroll-area-thumb"; +const SCROLL_AREA_SCROLLBAR_ATTR = "data-scroll-area-scrollbar"; + +type Sizes = { + content: number; + viewport: number; + scrollbar: { + size: number; + paddingStart: number; + paddingEnd: number; + }; +}; + +type ScrollAreaRootStateProps = WithRefProps< + ReadableBoxedValues<{ + dir: Direction; + type: ScrollAreaType; + scrollHideDelay: number; + }> +>; + +class ScrollAreaRootState { + #id: ScrollAreaRootStateProps["id"]; + #ref: ScrollAreaRootStateProps["ref"]; + dir: ScrollAreaRootStateProps["dir"]; + type: ScrollAreaRootStateProps["type"]; + scrollHideDelay: ScrollAreaRootStateProps["scrollHideDelay"]; + scrollAreaNode = $state(null); + viewportNode = $state(null); + contentNode = $state(null); + scrollbarXNode = $state(null); + scrollbarYNode = $state(null); + cornerWidth = $state(0); + cornerHeight = $state(0); + scrollbarXEnabled = $state(false); + scrollbarYEnabled = $state(false); + + constructor(props: ScrollAreaRootStateProps) { + this.#id = props.id; + this.#ref = props.ref; + this.dir = props.dir; + this.type = props.type; + this.scrollHideDelay = props.scrollHideDelay; + + useRefById({ + id: this.#id, + ref: this.#ref, + onRefChange: (node) => { + this.scrollAreaNode = node; + }, + }); + } + + props = $derived.by( + () => + ({ + id: this.#id.value, + dir: this.dir.value, + style: { + position: "relative", + "--bits-scroll-area-corner-height": `${this.cornerHeight}px`, + "--bits-scroll-area-corner-width": `${this.cornerWidth}px`, + }, + [SCROLL_AREA_ROOT_ATTR]: "", + }) as const + ); + + createViewport(props: ScrollAreaViewportStateProps) { + return new ScrollAreaViewportState(props, this); + } + + createScrollbar(props: ScrollAreaScrollbarStateProps) { + return new ScrollAreaScrollbarState(props, this); + } + + createCorner(props: ScrollAreaCornerImplStateProps) { + return new ScrollAreaCornerImplState(props, this); + } +} + +type ScrollAreaViewportStateProps = WithRefProps; + +class ScrollAreaViewportState { + #id: ScrollAreaViewportStateProps["id"]; + #ref: ScrollAreaViewportStateProps["ref"]; + #contentId = box(useId()); + #contentRef = box(null); + root: ScrollAreaRootState; + + constructor(props: ScrollAreaViewportStateProps, root: ScrollAreaRootState) { + this.#id = props.id; + this.#ref = props.ref; + this.root = root; + + useRefById({ + id: this.#id, + ref: this.#ref, + onRefChange: (node) => { + this.root.viewportNode = node; + }, + }); + + useRefById({ + id: this.#contentId, + ref: this.#contentRef, + onRefChange: (node) => { + this.root.contentNode = node; + }, + }); + } + + props = $derived.by( + () => + ({ + id: this.#id.value, + style: { + overflowX: this.root.scrollbarXEnabled ? "scroll" : "hidden", + overflowY: this.root.scrollbarYEnabled ? "scroll" : "hidden", + }, + [SCROLL_AREA_VIEWPORT_ATTR]: "", + }) as const + ); + + contentProps = $derived.by( + () => + ({ + id: this.#contentId.value, + style: { + minWidth: "100%", + display: "table", + }, + }) as const + ); +} + +type ScrollAreaScrollbarStateProps = WithRefProps< + ReadableBoxedValues<{ + orientation: Orientation; + }> +>; + +class ScrollAreaScrollbarState { + ref: ScrollAreaScrollbarStateProps["ref"]; + id: ScrollAreaScrollbarStateProps["id"]; + root: ScrollAreaRootState; + orientation: ScrollAreaScrollbarStateProps["orientation"]; + isHorizontal = $derived.by(() => this.orientation.value === "horizontal"); + hasThumb = $state(false); + + constructor(props: ScrollAreaScrollbarStateProps, root: ScrollAreaRootState) { + this.root = root; + this.orientation = props.orientation; + this.ref = props.ref; + this.id = props.id; + + $effect(() => { + this.isHorizontal + ? (this.root.scrollbarXEnabled = true) + : (this.root.scrollbarYEnabled = true); + + return () => { + this.isHorizontal + ? (this.root.scrollbarXEnabled = false) + : (this.root.scrollbarYEnabled = false); + }; + }); + } + + createScrollbarHover() { + return new ScrollAreaScrollbarHoverState(this); + } + + createScrollbarScroll() { + return new ScrollAreaScrollbarScrollState(this); + } + + createScrollbarAuto() { + return new ScrollAreaScrollbarAutoState(this); + } + + createScrollbarVisible() { + return new ScrollAreaScrollbarVisibleState(this); + } +} + +class ScrollAreaScrollbarHoverState { + root: ScrollAreaRootState; + isVisible = $state(false); + scrollbar: ScrollAreaScrollbarState; + + constructor(scrollbar: ScrollAreaScrollbarState) { + this.root = scrollbar.root; + this.scrollbar = scrollbar; + + $effect(() => { + const scrollAreaNode = this.root.scrollAreaNode; + const hideDelay = this.root.scrollHideDelay.value; + let hideTimer = 0; + if (scrollAreaNode) { + const handlePointerEnter = () => { + window.clearTimeout(hideTimer); + untrack(() => (this.isVisible = true)); + }; + + const handlePointerLeave = () => { + if (hideTimer) window.clearTimeout(hideTimer); + hideTimer = window.setTimeout(() => { + untrack(() => { + this.scrollbar.hasThumb = false; + this.isVisible = false; + }); + }, hideDelay); + }; + + const unsubListeners = executeCallbacks( + addEventListener(scrollAreaNode, "pointerenter", handlePointerEnter), + addEventListener(scrollAreaNode, "pointerleave", handlePointerLeave) + ); + + return () => { + window.clearTimeout(hideTimer); + unsubListeners(); + }; + } + }); + } + + props = $derived.by( + () => + ({ + "data-state": this.isVisible ? "visible" : "hidden", + }) as const + ); +} + +class ScrollAreaScrollbarScrollState { + orientation: ScrollAreaScrollbarState["orientation"]; + root: ScrollAreaRootState; + scrollbar: ScrollAreaScrollbarState; + machine = useStateMachine("hidden", { + hidden: { + SCROLL: "scrolling", + }, + scrolling: { + SCROLL_END: "idle", + POINTER_ENTER: "interacting", + }, + interacting: { + SCROLL: "interacting", + POINTER_LEAVE: "idle", + }, + idle: { + HIDE: "hidden", + SCROLL: "scrolling", + POINTER_ENTER: "interacting", + }, + }); + isHidden = $derived.by(() => this.machine.state.value === "hidden"); + + constructor(scrollbar: ScrollAreaScrollbarState) { + this.scrollbar = scrollbar; + this.root = scrollbar.root; + this.orientation = this.scrollbar.orientation; + + const debounceScrollend = useDebounce(() => this.machine.dispatch("SCROLL_END"), 100); + + $effect(() => { + const _state = this.machine.state.value; + const scrollHideDelay = this.root.scrollHideDelay.value; + if (_state === "idle") { + const hideTimer = window.setTimeout( + () => this.machine.dispatch("HIDE"), + scrollHideDelay + ); + return () => window.clearTimeout(hideTimer); + } + }); + + $effect(() => { + const viewportNode = this.root.viewportNode; + if (!viewportNode) return; + const scrollDirection = this.scrollbar.isHorizontal ? "scrollLeft" : "scrollTop"; + + let prevScrollPos = viewportNode[scrollDirection]; + const handleScroll = () => { + const scrollPos = viewportNode[scrollDirection]; + const hasScrollInDirectionChanged = prevScrollPos !== scrollPos; + if (hasScrollInDirectionChanged) { + this.machine.dispatch("SCROLL"); + debounceScrollend(); + } + prevScrollPos = scrollPos; + }; + + const unsubListener = addEventListener(viewportNode, "scroll", handleScroll); + return unsubListener; + }); + } + + #onpointerenter = () => { + this.machine.dispatch("POINTER_ENTER"); + }; + + #onpointerleave = () => { + this.machine.dispatch("POINTER_LEAVE"); + }; + + props = $derived.by( + () => + ({ + "data-state": this.machine.state.value === "hidden" ? "hidden" : "visible", + onpointerenter: this.#onpointerenter, + onpointerleave: this.#onpointerleave, + }) as const + ); +} + +class ScrollAreaScrollbarAutoState { + scrollbar: ScrollAreaScrollbarState; + root: ScrollAreaRootState; + isVisible = $state(false); + + constructor(scrollbar: ScrollAreaScrollbarState) { + this.scrollbar = scrollbar; + this.root = scrollbar.root; + + const handleResize = useDebounce(() => { + const viewportNode = this.root.viewportNode; + if (!viewportNode) return; + const isOverflowX = viewportNode.offsetWidth < viewportNode.scrollWidth; + const isOverflowY = viewportNode.offsetHeight < viewportNode.scrollHeight; + this.isVisible = this.scrollbar.isHorizontal ? isOverflowX : isOverflowY; + }, 10); + + useResizeObserver(() => this.root.viewportNode, handleResize); + useResizeObserver(() => this.root.contentNode, handleResize); + } + + props = $derived.by( + () => + ({ + "data-state": this.isVisible ? "visible" : "hidden", + }) as const + ); +} + +class ScrollAreaScrollbarVisibleState { + scrollbar: ScrollAreaScrollbarState; + root: ScrollAreaRootState; + thumbNode = $state(null); + pointerOffset = $state(0); + sizes = $state.frozen({ + content: 0, + viewport: 0, + scrollbar: { size: 0, paddingStart: 0, paddingEnd: 0 }, + }); + thumbRatio = $derived.by(() => getThumbRatio(this.sizes.viewport, this.sizes.content)); + hasThumb = $derived.by(() => Boolean(this.thumbRatio > 0 && this.thumbRatio < 1)); + + constructor(scrollbar: ScrollAreaScrollbarState) { + this.scrollbar = scrollbar; + this.root = scrollbar.root; + + $effect(() => { + this.scrollbar.hasThumb = this.hasThumb; + }); + } + + setSizes = (sizes: Sizes) => { + this.sizes = sizes; + }; + + getScrollPosition = (pointerPos: number, dir?: Direction) => { + return getScrollPositionFromPointer({ + pointerPos, + pointerOffset: this.pointerOffset, + sizes: this.sizes, + dir, + }); + }; + + onThumbPointerUp = () => { + this.pointerOffset = 0; + }; + + onThumbPointerDown = (pointerPos: number) => { + this.pointerOffset = pointerPos; + }; + + xOnThumbPositionChange = () => { + if (!(this.root.viewportNode && this.thumbNode)) return; + const scrollPos = this.root.viewportNode.scrollLeft; + const offset = getThumbOffsetFromScroll({ + scrollPos, + sizes: this.sizes, + dir: this.root.dir.value, + }); + this.thumbNode.style.transform = `translate3d(${offset}px, 0, 0)`; + }; + + xOnWheelScroll = (scrollPos: number) => { + if (!this.root.viewportNode) return; + this.root.viewportNode.scrollLeft = scrollPos; + }; + + xOnDragScroll = (pointerPos: number) => { + if (!this.root.viewportNode) return; + this.root.viewportNode.scrollLeft = this.getScrollPosition(pointerPos, this.root.dir.value); + }; + + yOnThumbPositionChange = () => { + if (!(this.root.viewportNode && this.thumbNode)) return; + const scrollPos = this.root.viewportNode.scrollTop; + const offset = getThumbOffsetFromScroll({ scrollPos, sizes: this.sizes }); + this.thumbNode.style.transform = `translate3d(0, ${offset}px, 0)`; + }; + + yOnWheelScroll = (scrollPos: number) => { + if (!this.root.viewportNode) return; + this.root.viewportNode.scrollTop = scrollPos; + }; + + yOnDragScroll = (pointerPos: number) => { + if (!this.root.viewportNode) return; + this.root.viewportNode.scrollTop = this.getScrollPosition(pointerPos); + }; + + createScrollbarX(props: ScrollbarAxisStateProps) { + return new ScrollAreaScrollbarXState(props, this); + } + + createScrollbarY(props: ScrollbarAxisStateProps) { + return new ScrollAreaScrollbarYState(props, this); + } +} + +type ScrollbarAxisStateProps = ReadableBoxedValues<{ mounted: boolean }>; + +type ScrollbarAxisState = { + onThumbPointerDown: (pointerPos: { x: number; y: number }) => void; + onDragScroll: (pointerPos: { x: number; y: number }) => void; + onWheelScroll: (e: WheelEvent, maxScrollPos: number) => void; + onResize: () => void; + onThumbPositionChange: () => void; + onThumbPointerUp: () => void; + createShared: () => ScrollAreaScrollbarSharedState; + props: { + id: string; + "data-orientation": "horizontal" | "vertical"; + style: Record; + }; +}; + +class ScrollAreaScrollbarXState implements ScrollbarAxisState { + #id: WithRefProps["id"]; + #mounted: ScrollbarAxisStateProps["mounted"]; + ref: WithRefProps["ref"]; + scrollbarVis: ScrollAreaScrollbarVisibleState; + root: ScrollAreaRootState; + computedStyle = $state(); + + constructor(props: ScrollbarAxisStateProps, scrollbarVis: ScrollAreaScrollbarVisibleState) { + this.#mounted = props.mounted; + this.scrollbarVis = scrollbarVis; + this.#id = this.scrollbarVis.scrollbar.id; + this.ref = this.scrollbarVis.scrollbar.ref; + this.root = scrollbarVis.root; + + useRefById({ + id: this.#id, + ref: this.ref, + onRefChange: (node) => { + this.root.scrollbarXNode = node; + }, + condition: () => this.#mounted.value, + }); + + $effect(() => { + if (!this.ref.value) return; + if (this.#mounted.value) { + afterTick(() => { + this.computedStyle = getComputedStyle(this.ref.value!); + }); + } + }); + } + + onThumbPointerDown = (pointerPos: { x: number; y: number }) => { + this.scrollbarVis.onThumbPointerDown(pointerPos.x); + }; + + onDragScroll = (pointerPos: { x: number; y: number }) => { + this.scrollbarVis.xOnDragScroll(pointerPos.x); + }; + + onThumbPointerUp = () => { + this.scrollbarVis.onThumbPointerUp(); + }; + + onThumbPositionChange = () => { + this.scrollbarVis.xOnThumbPositionChange(); + }; + + onWheelScroll = (e: WheelEvent, maxScrollPos: number) => { + if (!this.root.viewportNode) return; + const scrollPos = this.root.viewportNode.scrollLeft + e.deltaX; + this.scrollbarVis.xOnWheelScroll(scrollPos); + // prevent window scroll when wheeling scrollbar + if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) { + e.preventDefault(); + } + }; + + onResize = () => { + if (!(this.ref.value && this.root.viewportNode && this.computedStyle)) return; + this.scrollbarVis.setSizes({ + content: this.root.viewportNode.scrollWidth, + viewport: this.root.viewportNode.offsetWidth, + scrollbar: { + size: this.ref.value.clientWidth, + paddingStart: toInt(this.computedStyle.paddingLeft), + paddingEnd: toInt(this.computedStyle.paddingRight), + }, + }); + }; + + thumbSize = $derived.by(() => { + const ts = getThumbSize(this.scrollbarVis.sizes); + return ts; + }); + + props = $derived.by( + () => + ({ + id: this.#id.value, + "data-orientation": "horizontal", + style: { + bottom: 0, + left: + this.root.dir.value === "rtl" ? "var(--bits-scroll-area-corner-width)" : 0, + right: + this.root.dir.value === "ltr" ? "var(--bits-scroll-area-corner-width)" : 0, + "--bits-scroll-area-thumb-width": `${this.thumbSize}px`, + }, + }) as const + ); + + createShared() { + return new ScrollAreaScrollbarSharedState(this); + } +} + +class ScrollAreaScrollbarYState implements ScrollbarAxisState { + #id: WithRefProps["id"]; + #mounted: ScrollbarAxisStateProps["mounted"]; + ref: WithRefProps["ref"]; + scrollbarVis: ScrollAreaScrollbarVisibleState; + root: ScrollAreaRootState; + computedStyle = $state(); + + constructor(props: ScrollbarAxisStateProps, scrollbarVis: ScrollAreaScrollbarVisibleState) { + this.#mounted = props.mounted; + this.scrollbarVis = scrollbarVis; + this.#id = this.scrollbarVis.scrollbar.id; + this.ref = this.scrollbarVis.scrollbar.ref; + this.root = scrollbarVis.root; + + useRefById({ + id: this.scrollbarVis.scrollbar.id, + ref: this.scrollbarVis.scrollbar.ref, + onRefChange: (node) => { + this.root.scrollbarYNode = node; + }, + condition: () => this.#mounted.value, + }); + + $effect(() => { + if (!this.ref.value) return; + if (this.#mounted.value) { + afterTick(() => { + this.computedStyle = getComputedStyle(this.ref.value!); + }); + } + }); + } + + onThumbPointerDown = (pointerPos: { x: number; y: number }) => { + this.scrollbarVis.onThumbPointerDown(pointerPos.y); + }; + + onDragScroll = (pointerPos: { x: number; y: number }) => { + this.scrollbarVis.yOnDragScroll(pointerPos.y); + }; + + onThumbPointerUp = () => { + this.scrollbarVis.onThumbPointerUp(); + }; + + onThumbPositionChange = () => { + this.scrollbarVis.yOnThumbPositionChange(); + }; + + onWheelScroll = (e: WheelEvent, maxScrollPos: number) => { + if (!this.root.viewportNode) return; + const scrollPos = this.root.viewportNode.scrollTop + e.deltaY; + this.scrollbarVis.yOnWheelScroll(scrollPos); + // prevent window scroll when wheeling scrollbar + if (isScrollingWithinScrollbarBounds(scrollPos, maxScrollPos)) { + e.preventDefault(); + } + }; + + onResize = () => { + if (!(this.ref.value && this.root.viewportNode && this.computedStyle)) return; + this.scrollbarVis.setSizes({ + content: this.root.viewportNode.scrollHeight, + viewport: this.root.viewportNode.offsetHeight, + scrollbar: { + size: this.ref.value.clientHeight, + paddingStart: toInt(this.computedStyle.paddingTop), + paddingEnd: toInt(this.computedStyle.paddingBottom), + }, + }); + }; + + thumbSize = $derived.by(() => { + return getThumbSize(this.scrollbarVis.sizes); + }); + + props = $derived.by( + () => + ({ + id: this.#id.value, + "data-orientation": "vertical", + style: { + top: 0, + right: this.root.dir.value === "ltr" ? 0 : undefined, + left: this.root.dir.value === "rtl" ? 0 : undefined, + bottom: "var(--bits-scroll-area-corner-height)", + "--bits-scroll-area-thumb-height": `${this.thumbSize}px`, + }, + }) as const + ); + + createShared() { + return new ScrollAreaScrollbarSharedState(this); + } +} + +type ScrollbarAxis = ScrollAreaScrollbarXState | ScrollAreaScrollbarYState; + +class ScrollAreaScrollbarSharedState { + scrollbarState: ScrollbarAxis; + root: ScrollAreaRootState; + scrollbarVis: ScrollAreaScrollbarVisibleState; + rect = $state.frozen(null); + prevWebkitUserSelect = $state(""); + handleResize: () => void; + handleThumbPositionChange: () => void; + handleWheelScroll: (e: WheelEvent, maxScrollPos: number) => void; + handleThumbPointerDown: (pointerPos: { x: number; y: number }) => void; + handleThumbPointerUp: () => void; + maxScrollPos = $derived.by( + () => this.scrollbarVis.sizes.content - this.scrollbarVis.sizes.viewport + ); + + constructor(scrollbarState: ScrollbarAxis) { + this.scrollbarState = scrollbarState; + this.root = scrollbarState.root; + this.scrollbarVis = scrollbarState.scrollbarVis; + this.handleResize = useDebounce(() => this.scrollbarState.onResize(), 10); + this.handleThumbPositionChange = this.scrollbarState.onThumbPositionChange; + this.handleWheelScroll = this.scrollbarState.onWheelScroll; + this.handleThumbPointerDown = this.scrollbarState.onThumbPointerDown; + this.handleThumbPointerUp = this.scrollbarState.onThumbPointerUp; + + $effect(() => { + const maxScrollPos = this.maxScrollPos; + const scrollbarNode = this.scrollbarState.ref.value; + // we want to react to the viewport node changing so we leave this here + this.root.viewportNode; + const handleWheel = (e: WheelEvent) => { + const node = e.target as HTMLElement; + const isScrollbarWheel = scrollbarNode?.contains(node); + if (isScrollbarWheel) this.handleWheelScroll(e, maxScrollPos); + }; + + const unsubListener = addEventListener(document, "wheel", handleWheel, { + passive: false, + }); + + return unsubListener; + }); + + $effect(() => { + // react to changes to this: + this.scrollbarVis.sizes; + untrack(() => this.handleThumbPositionChange()); + }); + + useResizeObserver(() => this.scrollbarState.ref.value, this.handleResize); + useResizeObserver(() => this.root.contentNode, this.handleResize); + } + + handleDragScroll = (e: PointerEvent) => { + if (!this.rect) return; + const x = e.clientX - this.rect.left; + const y = e.clientY - this.rect.top; + this.scrollbarState.onDragScroll({ x, y }); + }; + + #onpointerdown = (e: PointerEvent) => { + if (e.button !== 0) return; + const target = e.target as HTMLElement; + target.setPointerCapture(e.pointerId); + this.rect = this.scrollbarState.ref.value?.getBoundingClientRect() ?? null; + // pointer capture doesn't prevent text selection in Safari + // so we remove text selection manually when scrolling + this.prevWebkitUserSelect = document.body.style.webkitUserSelect; + document.body.style.webkitUserSelect = "none"; + if (this.root.viewportNode) this.root.viewportNode.style.scrollBehavior = "auto"; + this.handleDragScroll(e); + }; + + #onpointermove = (e: PointerEvent) => { + this.handleDragScroll(e); + }; + + #onpointerup = (e: PointerEvent) => { + const target = e.target as HTMLElement; + if (target.hasPointerCapture(e.pointerId)) { + target.releasePointerCapture(e.pointerId); + } + document.body.style.webkitUserSelect = this.prevWebkitUserSelect; + if (this.root.viewportNode) this.root.viewportNode.style.scrollBehavior = ""; + this.rect = null; + }; + + props = $derived.by(() => + mergeProps({ + ...this.scrollbarState.props, + style: { + position: "absolute", + ...this.scrollbarState.props.style, + }, + [SCROLL_AREA_SCROLLBAR_ATTR]: "", + onpointerdown: this.#onpointerdown, + onpointermove: this.#onpointermove, + onpointerup: this.#onpointerup, + }) + ); + + createThumb(props: ScrollAreaThumbImplStateProps) { + return new ScrollAreaThumbImplState(props, this); + } +} + +type ScrollAreaThumbImplStateProps = WithRefProps & + ReadableBoxedValues<{ + mounted: boolean; + }>; +class ScrollAreaThumbImplState { + #id: ScrollAreaThumbImplStateProps["id"]; + #ref: ScrollAreaThumbImplStateProps["ref"]; + #root: ScrollAreaRootState; + #scrollbarState: ScrollAreaScrollbarSharedState; + #removeUnlinkedScrollListener = $state<() => void>(); + #debounceScrollEnd = useDebounce(() => { + if (this.#removeUnlinkedScrollListener) { + this.#removeUnlinkedScrollListener(); + this.#removeUnlinkedScrollListener = undefined; + } + }, 100); + #mounted: ScrollAreaThumbImplStateProps["mounted"]; + + constructor( + props: ScrollAreaThumbImplStateProps, + scrollbarState: ScrollAreaScrollbarSharedState + ) { + this.#root = scrollbarState.root; + this.#scrollbarState = scrollbarState; + this.#mounted = props.mounted; + this.#id = props.id; + this.#ref = props.ref; + + useRefById({ + id: this.#id, + ref: this.#ref, + onRefChange: (node) => { + this.#scrollbarState.scrollbarVis.thumbNode = node; + }, + condition: () => this.#mounted.value, + }); + + $effect(() => { + const viewportNode = this.#root.viewportNode; + if (!viewportNode) return; + const handleScroll = () => { + this.#debounceScrollEnd(); + if (!this.#removeUnlinkedScrollListener) { + const listener = addUnlinkedScrollListener( + viewportNode, + this.#scrollbarState.handleThumbPositionChange + ); + this.#removeUnlinkedScrollListener = listener; + this.#scrollbarState.handleThumbPositionChange(); + } + }; + this.#scrollbarState.handleThumbPositionChange(); + const unsubListener = addEventListener(viewportNode, "scroll", handleScroll); + return unsubListener; + }); + } + + #onpointerdowncapture = (e: PointerEvent) => { + const thumb = e.target as HTMLElement; + if (!thumb) return; + const thumbRect = thumb.getBoundingClientRect(); + const x = e.clientX - thumbRect.left; + const y = e.clientY - thumbRect.top; + this.#scrollbarState.handleThumbPointerDown({ x, y }); + }; + + #onpointerup = (e: PointerEvent) => { + this.#scrollbarState.handleThumbPointerUp(); + }; + + props = $derived.by( + () => + ({ + id: this.#id.value, + "data-state": this.#scrollbarState.scrollbarVis.hasThumb ? "visible" : "hidden", + style: { + width: "var(--bits-scroll-area-thumb-width)", + height: "var(--bits-scroll-area-thumb-height)", + }, + onpointerdowncapture: this.#onpointerdowncapture, + onpointerup: this.#onpointerup, + [SCROLL_AREA_THUMB_ATTR]: "", + }) as const + ); +} + +type ScrollAreaCornerImplStateProps = WithRefProps; + +class ScrollAreaCornerImplState { + #id: ScrollAreaCornerImplStateProps["id"]; + #ref: ScrollAreaCornerImplStateProps["ref"]; + #root: ScrollAreaRootState; + #width = $state(0); + #height = $state(0); + hasSize = $derived(Boolean(this.#width && this.#height)); + + constructor(props: ScrollAreaCornerImplStateProps, root: ScrollAreaRootState) { + this.#root = root; + this.#id = props.id; + this.#ref = props.ref; + + useResizeObserver( + () => this.#root.scrollbarXNode, + () => { + const height = this.#root.scrollbarXNode?.offsetHeight || 0; + this.#root.cornerHeight = height; + this.#height = height; + } + ); + + useResizeObserver( + () => this.#root.scrollbarYNode, + () => { + const width = this.#root.scrollbarYNode?.offsetWidth || 0; + this.#root.cornerWidth = width; + this.#width = width; + } + ); + + useRefById({ + id: this.#id, + ref: this.#ref, + }); + } + + props = $derived.by(() => ({ + id: this.#id.value, + style: { + width: this.#width, + height: this.#height, + position: "absolute", + right: this.#root.dir.value === "ltr" ? 0 : undefined, + left: this.#root.dir.value === "rtl" ? 0 : undefined, + bottom: 0, + }, + [SCROLL_AREA_CORNER_ATTR]: "", + })); +} + +export const [setScrollAreaRootContext, getScrollAreaRootContext] = + createContext("ScrollArea.Root"); + +export const [setScrollAreaScrollbarContext, getScrollAreaScrollbarContext] = + createContext("ScrollArea.Scrollbar"); + +export const [setScrollAreaScrollbarVisibleContext, getScrollAreaScrollbarVisibleContext] = + createContext("ScrollArea.ScrollbarVisible"); + +export const [setScrollAreaScrollbarAxisContext, getScrollAreaScrollbarAxisContext] = + createContext("ScrollArea.ScrollbarAxis"); + +export const [setScrollAreaScrollbarSharedContext, getScrollAreaScrollbarSharedContext] = + createContext("ScrollArea.ScrollbarShared"); + +export function useScrollAreaRoot(props: ScrollAreaRootStateProps) { + return setScrollAreaRootContext(new ScrollAreaRootState(props)); +} + +export function useScrollAreaViewport(props: ScrollAreaViewportStateProps) { + return getScrollAreaRootContext().createViewport(props); +} + +export function useScrollAreaScrollbar(props: ScrollAreaScrollbarStateProps) { + return setScrollAreaScrollbarContext(getScrollAreaRootContext().createScrollbar(props)); +} + +export function useScrollAreaScrollbarVisible() { + return setScrollAreaScrollbarVisibleContext( + getScrollAreaScrollbarContext().createScrollbarVisible() + ); +} + +export function useScrollAreaScrollbarAuto() { + return getScrollAreaScrollbarContext().createScrollbarAuto(); +} + +export function useScrollAreaScrollbarScroll() { + return getScrollAreaScrollbarContext().createScrollbarScroll(); +} + +export function useScrollAreaScrollbarHover() { + return getScrollAreaScrollbarContext().createScrollbarHover(); +} + +export function useScrollAreaScrollbarX(props: ScrollbarAxisStateProps) { + return setScrollAreaScrollbarAxisContext( + getScrollAreaScrollbarVisibleContext().createScrollbarX(props) + ); +} + +export function useScrollAreaScrollbarY(props: ScrollbarAxisStateProps) { + return setScrollAreaScrollbarAxisContext( + getScrollAreaScrollbarVisibleContext().createScrollbarY(props) + ); +} + +export function useScrollAreaScrollbarShared() { + return setScrollAreaScrollbarSharedContext(getScrollAreaScrollbarAxisContext().createShared()); +} + +export function useScrollAreaThumb(props: ScrollAreaThumbImplStateProps) { + return getScrollAreaScrollbarSharedContext().createThumb(props); +} + +export function useScrollAreaCorner(props: ScrollAreaCornerImplStateProps) { + return getScrollAreaRootContext().createCorner(props); +} + +function toInt(value?: string) { + return value ? parseInt(value, 10) : 0; +} + +function getThumbRatio(viewportSize: number, contentSize: number) { + const ratio = viewportSize / contentSize; + return Number.isNaN(ratio) ? 0 : ratio; +} + +function getThumbSize(sizes: Sizes) { + const ratio = getThumbRatio(sizes.viewport, sizes.content); + const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd; + const thumbSize = (sizes.scrollbar.size - scrollbarPadding) * ratio; + return Math.max(thumbSize, 18); +} + +type GetScrollPositionFromPointerProps = { + pointerPos: number; + pointerOffset: number; + sizes: Sizes; + dir?: Direction; +}; + +function getScrollPositionFromPointer({ + pointerPos, + pointerOffset, + sizes, + dir = "ltr", +}: GetScrollPositionFromPointerProps) { + const thumbSizePx = getThumbSize(sizes); + const thumbCenter = thumbSizePx / 2; + const offset = pointerOffset || thumbCenter; + const thumbOffsetFromEnd = thumbSizePx - offset; + const minPointerPos = sizes.scrollbar.paddingStart + offset; + const maxPointerPos = sizes.scrollbar.size - sizes.scrollbar.paddingEnd - thumbOffsetFromEnd; + const maxScrollPos = sizes.content - sizes.viewport; + const scrollRange = dir === "ltr" ? [0, maxScrollPos] : [maxScrollPos * -1, 0]; + const interpolate = linearScale( + [minPointerPos, maxPointerPos], + scrollRange as [number, number] + ); + return interpolate(pointerPos); +} + +type GetThumbOffsetFromScrollProps = { + scrollPos: number; + sizes: Sizes; + dir?: Direction; +}; + +function getThumbOffsetFromScroll({ + scrollPos, + sizes, + dir = "ltr", +}: GetThumbOffsetFromScrollProps) { + const thumbSizePx = getThumbSize(sizes); + const scrollbarPadding = sizes.scrollbar.paddingStart + sizes.scrollbar.paddingEnd; + const scrollbar = sizes.scrollbar.size - scrollbarPadding; + const maxScrollPos = sizes.content - sizes.viewport; + const maxThumbPos = scrollbar - thumbSizePx; + const scrollClampRange = dir === "ltr" ? [0, maxScrollPos] : [maxScrollPos * -1, 0]; + const scrollWithoutMomentum = clamp(scrollPos, scrollClampRange[0]!, scrollClampRange[1]!); + const interpolate = linearScale([0, maxScrollPos], [0, maxThumbPos]); + return interpolate(scrollWithoutMomentum); +} + +// https://github.com/tmcw-up-for-adoption/simple-linear-scale/blob/master/index.js +function linearScale(input: readonly [number, number], output: readonly [number, number]) { + return (value: number) => { + if (input[0] === input[1] || output[0] === output[1]) return output[0]; + const ratio = (output[1] - output[0]) / (input[1] - input[0]); + return output[0] + ratio * (value - input[0]); + }; +} + +function isScrollingWithinScrollbarBounds(scrollPos: number, maxScrollPos: number) { + return scrollPos > 0 && scrollPos < maxScrollPos; +} + +function addUnlinkedScrollListener(node: HTMLElement, handler: () => void) { + let prevPosition = { left: node.scrollLeft, top: node.scrollTop }; + let rAF = 0; + (function loop() { + const position = { left: node.scrollLeft, top: node.scrollTop }; + const isHorizontalScroll = prevPosition.left !== position.left; + const isVerticalScroll = prevPosition.top !== position.top; + if (isHorizontalScroll || isVerticalScroll) handler(); + prevPosition = position; + rAF = window.requestAnimationFrame(loop); + })(); + + return () => window.cancelAnimationFrame(rAF); +} diff --git a/packages/bits-ui/src/lib/bits/scroll-area/types.ts b/packages/bits-ui/src/lib/bits/scroll-area/types.ts index c50800a83..051fd08c8 100644 --- a/packages/bits-ui/src/lib/bits/scroll-area/types.ts +++ b/packages/bits-ui/src/lib/bits/scroll-area/types.ts @@ -1,26 +1,67 @@ -import type { CreateScrollAreaProps as MeltScrollAreaProps } from "@melt-ui/svelte"; -import type { DOMElement, Expand, HTMLDivAttributes } from "$lib/internal/types.js"; +import type { PrimitiveDivAttributes, WithChildren } from "$lib/internal/types.js"; +import type { Direction, Orientation, WithChild, Without } from "$lib/shared/index.js"; -export type ScrollAreaPropsWithoutHTML = Expand> & - DOMElement; +export type ScrollAreaType = "hover" | "scroll" | "auto" | "always"; -type BaseDivProps = DOMElement; +export type ScrollAreaRootPropsWithoutHTML = WithChild<{ + /** + * The type of scroll area to render. + * + * @defaultValue "hover" + */ + type?: ScrollAreaType; -export type ScrollAreaScrollbarPropsWithoutHTML = BaseDivProps & { - orientation: "horizontal" | "vertical"; -}; + /** + * The reading direction of the application. + */ + dir?: Direction; + + /** + * The amount of time in milliseconds to delay before hiding the scrollbars + * after leaving the scroll area or stopping scrolling. + * + * @defaultValue 600 + */ + scrollHideDelay?: number; +}>; + +export type ScrollAreaRootProps = ScrollAreaRootPropsWithoutHTML & + Without; + +export type ScrollAreaViewportPropsWithoutHTML = Omit; + +export type ScrollAreaViewportProps = ScrollAreaViewportPropsWithoutHTML & + Without; -export type ScrollAreaThumbPropsWithoutHTML = BaseDivProps; +export type ScrollAreaScrollbarPropsWithoutHTML = WithChild<{ + orientation: Orientation; -export type ScrollAreaViewportPropsWithoutHTML = BaseDivProps; -export type ScrollAreaContentPropsWithoutHTML = BaseDivProps; -export type ScrollAreaCornerPropsWithoutHTML = BaseDivProps; + /** + * Whether to forcefully mount the component. Useful when working with + * external animation/transition libraries. + */ + forceMount?: boolean; +}>; -// +export type ScrollAreaScrollbarProps = ScrollAreaScrollbarPropsWithoutHTML & + Without; -export type ScrollAreaProps = ScrollAreaPropsWithoutHTML & HTMLDivAttributes; -export type ScrollAreaViewportProps = ScrollAreaViewportPropsWithoutHTML & HTMLDivAttributes; -export type ScrollAreaContentProps = ScrollAreaContentPropsWithoutHTML & HTMLDivAttributes; -export type ScrollAreaScrollbarProps = ScrollAreaScrollbarPropsWithoutHTML & HTMLDivAttributes; -export type ScrollAreaThumbProps = ScrollAreaThumbPropsWithoutHTML & HTMLDivAttributes; -export type ScrollAreaCornerProps = ScrollAreaCornerPropsWithoutHTML & HTMLDivAttributes; +export type ScrollAreaThumbPropsWithoutHTML = WithChild<{ + /** + * Whether to forcefully mount the component. Useful when working with + * external animation/transition libraries. + */ + forceMount?: boolean; +}>; + +export type ScrollAreaThumbProps = ScrollAreaThumbPropsWithoutHTML & + Without; + +export type ScrollAreaCornerPropsWithoutHTML = WithChild; + +export type ScrollAreaCornerProps = ScrollAreaCornerPropsWithoutHTML & + Without; + +export type _ScrollbarStubProps = Omit & { + id: string; +}; diff --git a/packages/bits-ui/src/lib/bits/select/components/select.svelte b/packages/bits-ui/src/lib/bits/select/components/select.svelte index a4b20e2da..98824b518 100644 --- a/packages/bits-ui/src/lib/bits/select/components/select.svelte +++ b/packages/bits-ui/src/lib/bits/select/components/select.svelte @@ -16,6 +16,7 @@ disabled = false, autocomplete = undefined, dir = "ltr", + form, }: RootProps = $props(); const rootState = useSelectRoot({ @@ -55,6 +56,7 @@ {name} {autocomplete} {disabled} + {form} onchange={(e) => (value = e.currentTarget.value)} > {#if value === ""} diff --git a/packages/bits-ui/src/lib/bits/select/select.svelte.ts b/packages/bits-ui/src/lib/bits/select/select.svelte.ts index bf3ff7154..943c0e3e6 100644 --- a/packages/bits-ui/src/lib/bits/select/select.svelte.ts +++ b/packages/bits-ui/src/lib/bits/select/select.svelte.ts @@ -1,3 +1,8 @@ +/** + * This logic is adapted from Radix UI's Select component. + * https://github.com/radix-ui/primitives/blob/main/packages/react/select/src/Select.tsx + * Credit to the Radix UI team for the original implementation. + */ import { type ReadableBox, type WritableBox, box } from "svelte-toolbelt"; import { SvelteMap } from "svelte/reactivity"; import { untrack } from "svelte"; diff --git a/packages/bits-ui/src/lib/bits/select/types.ts b/packages/bits-ui/src/lib/bits/select/types.ts index 6b8b48ab5..7ab4c8dad 100644 --- a/packages/bits-ui/src/lib/bits/select/types.ts +++ b/packages/bits-ui/src/lib/bits/select/types.ts @@ -48,6 +48,11 @@ export type SelectRootPropsWithoutHTML = WithChildren<{ */ autocomplete?: string; + /** + * The native HTML select `form` attribute. + */ + form?: string; + /** * Whether the select is disabled. */ diff --git a/packages/bits-ui/src/lib/bits/utilities/focus-scope/focus-scope-stack.svelte.ts b/packages/bits-ui/src/lib/bits/utilities/focus-scope/focus-scope-stack.svelte.ts index c23164017..0c9f3c7dc 100644 --- a/packages/bits-ui/src/lib/bits/utilities/focus-scope/focus-scope-stack.svelte.ts +++ b/packages/bits-ui/src/lib/bits/utilities/focus-scope/focus-scope-stack.svelte.ts @@ -1,6 +1,8 @@ +import { useId } from "$lib/internal/useId.svelte.js"; import { box } from "svelte-toolbelt"; export type FocusScopeAPI = { + id: string; paused: boolean; pause: () => void; resume: () => void; @@ -20,11 +22,11 @@ export function createFocusScopeStack() { } // remove in case it already exists because it'll be added to the top - stack.value = removeFromArray($state.snapshot(stack.value), focusScope); + stack.value = removeFromFocusScopeArray(stack.value, focusScope); stack.value.unshift(focusScope); }, remove(focusScope: FocusScopeAPI) { - stack.value = removeFromArray($state.snapshot(stack.value), focusScope); + stack.value = removeFromFocusScopeArray(stack.value, focusScope); stack.value[0]?.resume(); }, }; @@ -34,6 +36,7 @@ export function createFocusScopeAPI(): FocusScopeAPI { let paused = $state(false); return { + id: useId(), get paused() { return paused; }, @@ -46,10 +49,8 @@ export function createFocusScopeAPI(): FocusScopeAPI { }; } -export function removeFromArray(arr: T[], item: T) { - const updatedArr = [...arr]; - const index = updatedArr.indexOf(item); - if (index !== -1) updatedArr.splice(index, 1); +function removeFromFocusScopeArray(arr: FocusScopeAPI[], item: FocusScopeAPI) { + const updatedArr = [...arr].filter((i) => i.id !== item.id); return updatedArr; } diff --git a/packages/bits-ui/src/lib/internal/cssToStyleObj.ts b/packages/bits-ui/src/lib/internal/cssToStyleObj.ts index d35c2a274..98dc95ec8 100644 --- a/packages/bits-ui/src/lib/internal/cssToStyleObj.ts +++ b/packages/bits-ui/src/lib/internal/cssToStyleObj.ts @@ -16,6 +16,10 @@ export function cssToStyleObj(css: string | null | undefined): StyleProperties { styleObj[pascalCase(name)] = value; return; } + if (name.startsWith("--")) { + styleObj[name] = value; + return; + } styleObj[camelCase(name)] = value; } diff --git a/packages/bits-ui/src/lib/internal/style.ts b/packages/bits-ui/src/lib/internal/style.ts index 197511d5f..45b4cebca 100644 --- a/packages/bits-ui/src/lib/internal/style.ts +++ b/packages/bits-ui/src/lib/internal/style.ts @@ -2,7 +2,8 @@ import styleToCSS from "style-object-to-css-string"; import type { StyleProperties } from "$lib/shared/index.js"; export function styleToString(style: StyleProperties = {}): string { - return styleToCSS(style).replace("\n", " "); + const stringified = styleToCSS(style).replace("\n", " "); + return stringified; } export const srOnlyStyles: StyleProperties = { diff --git a/packages/bits-ui/src/lib/internal/types.ts b/packages/bits-ui/src/lib/internal/types.ts index a85fc4cd2..18c43a01a 100644 --- a/packages/bits-ui/src/lib/internal/types.ts +++ b/packages/bits-ui/src/lib/internal/types.ts @@ -174,7 +174,7 @@ export type WithChild< ref?: Ref | null; }; -export type WithChildren = Props & { +export type WithChildren = Props & { children?: Snippet; }; diff --git a/packages/bits-ui/src/lib/internal/useRefById.svelte.ts b/packages/bits-ui/src/lib/internal/useRefById.svelte.ts index 1e92ab26d..d4dd2f04d 100644 --- a/packages/bits-ui/src/lib/internal/useRefById.svelte.ts +++ b/packages/bits-ui/src/lib/internal/useRefById.svelte.ts @@ -49,4 +49,11 @@ export function useRefById({ onRefChange(ref.value); }); }); + + $effect(() => { + return () => { + ref.value = null; + onRefChange(null); + }; + }); } diff --git a/packages/bits-ui/src/lib/internal/useResizeObserver.svelte.ts b/packages/bits-ui/src/lib/internal/useResizeObserver.svelte.ts new file mode 100644 index 000000000..133620afc --- /dev/null +++ b/packages/bits-ui/src/lib/internal/useResizeObserver.svelte.ts @@ -0,0 +1,19 @@ +import type { Getter } from "svelte-toolbelt"; + +export function useResizeObserver(node: Getter, onResize: () => void) { + $effect(() => { + let rAF = 0; + const _node = node(); + if (!_node) return; + const resizeObserver = new ResizeObserver(() => { + cancelAnimationFrame(rAF); + rAF = window.requestAnimationFrame(onResize); + }); + + resizeObserver.observe(_node); + return () => { + window.cancelAnimationFrame(rAF); + resizeObserver.unobserve(_node); + }; + }); +} diff --git a/packages/bits-ui/src/tests/link-preview/LinkPreview.spec.ts b/packages/bits-ui/src/tests/link-preview/LinkPreview.spec.ts index cd941e449..49109ea35 100644 --- a/packages/bits-ui/src/tests/link-preview/LinkPreview.spec.ts +++ b/packages/bits-ui/src/tests/link-preview/LinkPreview.spec.ts @@ -1,4 +1,4 @@ -import { fireEvent, render, waitFor } from "@testing-library/svelte"; +import { render, waitFor } from "@testing-library/svelte"; import { axe } from "jest-axe"; import { describe, it, vi } from "vitest"; import { getTestKbd, setupUserEvents } from "../utils.js"; diff --git a/packages/bits-ui/src/tests/scroll-area/ScrollArea.spec.ts b/packages/bits-ui/src/tests/scroll-area/ScrollArea.spec.ts new file mode 100644 index 000000000..e80ed8d58 --- /dev/null +++ b/packages/bits-ui/src/tests/scroll-area/ScrollArea.spec.ts @@ -0,0 +1,53 @@ +import { render } from "@testing-library/svelte/svelte5"; +import { describe, it } from "vitest"; +import { setupUserEvents } from "../utils.js"; +import ScrollAreaTest from "./ScrollAreaTest.svelte"; +import type { ScrollAreaTestProps } from "./ScrollAreaTest.svelte"; + +function setup(props?: ScrollAreaTestProps) { + const user = setupUserEvents(); + const returned = render(ScrollAreaTest, props); + const root = returned.getByTestId("root"); + const viewport = returned.getByTestId("viewport"); + + function getScrollbarX() { + return returned.queryByTestId("scrollbar-x"); + } + + function getScrollbarY() { + return returned.queryByTestId("scrollbar-y"); + } + + function getThumbX() { + return returned.queryByTestId("thumb-x"); + } + + function getThumbY() { + return returned.queryByTestId("thumb-y"); + } + + function getCorner() { + return returned.queryByTestId("corner"); + } + + return { + ...returned, + root, + viewport, + user, + getScrollbarX, + getScrollbarY, + getThumbX, + getThumbY, + getCorner, + }; +} + +// need to determine how to test the scrollbars in vitest/testing-lib +describe.todo("scroll area", () => { + it("renders the root and viewport elements", async () => { + const { root, viewport } = setup(); + expect(root).toBeInTheDocument(); + expect(viewport).toBeInTheDocument(); + }); +}); diff --git a/packages/bits-ui/src/tests/scroll-area/ScrollAreaTest.svelte b/packages/bits-ui/src/tests/scroll-area/ScrollAreaTest.svelte new file mode 100644 index 000000000..7235e9533 --- /dev/null +++ b/packages/bits-ui/src/tests/scroll-area/ScrollAreaTest.svelte @@ -0,0 +1,62 @@ + + + + +
+ + + + + +
+ + + + {#each Array(numParagraphs) as _} +

+ Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, + repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti + eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem ipsum dolor + sit, amet consectetur adipisicing elit. Blanditiis officiis error minima eos fugit + voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae + corrupti autem? Dolorem, sit voluptatum. +

+ {/each} +
+ + + + + + + +
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9983b394e..c3373e4e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 2.27.7 '@huntabyte/eslint-config': specifier: ^0.3.2 - version: 0.3.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0)(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3) + version: 0.3.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192))(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vitest@2.0.2) '@huntabyte/eslint-plugin': specifier: ^0.1.0 version: 0.1.0(eslint@9.7.0) @@ -25,25 +25,25 @@ importers: version: 9.7.0 eslint-plugin-svelte: specifier: ^2.37.0 - version: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.183) + version: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192) prettier: specifier: ^3.2.5 version: 3.3.3 prettier-plugin-svelte: specifier: ^3.2.2 - version: 3.2.5(prettier@3.3.3)(svelte@5.0.0-next.183) + version: 3.2.5(prettier@3.3.3)(svelte@5.0.0-next.192) prettier-plugin-tailwindcss: specifier: 0.5.13 - version: 0.5.13(prettier-plugin-svelte@3.2.5)(prettier@3.3.3) + version: 0.5.13(prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@5.0.0-next.192))(prettier@3.3.3) svelte: - specifier: 5.0.0-next.183 - version: 5.0.0-next.183 + specifier: 5.0.0-next.192 + version: 5.0.0-next.192 svelte-eslint-parser: - specifier: ^0.34.1 - version: 0.34.1(svelte@5.0.0-next.183) + specifier: ^0.41.0 + version: 0.41.0(svelte@5.0.0-next.192) wrangler: specifier: ^3.44.0 - version: 3.64.0 + version: 3.64.0(@cloudflare/workers-types@4.20240712.0) packages/bits-ui: dependencies: @@ -58,7 +58,7 @@ importers: version: 3.5.4 '@melt-ui/svelte': specifier: 0.76.2 - version: 0.76.2(svelte@5.0.0-next.183) + version: 0.76.2(svelte@5.0.0-next.192) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -70,7 +70,7 @@ importers: version: 5.0.7 runed: specifier: ^0.15.0 - version: 0.15.0(svelte@5.0.0-next.183) + version: 0.15.0(svelte@5.0.0-next.192) scule: specifier: ^1.3.0 version: 1.3.0 @@ -82,29 +82,29 @@ importers: version: 1.0.6 svelte-toolbelt: specifier: ^0.0.2 - version: 0.0.2(svelte@5.0.0-next.183) + version: 0.0.2(svelte@5.0.0-next.192) devDependencies: '@melt-ui/pp': specifier: ^0.3.0 - version: 0.3.2(@melt-ui/svelte@0.76.2)(svelte@5.0.0-next.183) + version: 0.3.2(@melt-ui/svelte@0.76.2(svelte@5.0.0-next.192))(svelte@5.0.0-next.192) '@sveltejs/kit': specifier: ^2.5.18 - version: 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3) + version: 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) '@sveltejs/package': specifier: ^2.3.2 - version: 2.3.2(svelte@5.0.0-next.183)(typescript@5.5.3) + version: 2.3.2(svelte@5.0.0-next.192)(typescript@5.5.3) '@sveltejs/vite-plugin-svelte': specifier: ^3.1.1 - version: 3.1.1(svelte@5.0.0-next.183)(vite@5.3.3) + version: 3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) '@testing-library/dom': specifier: ^10.3.1 version: 10.3.1 '@testing-library/jest-dom': specifier: ^6.4.6 - version: 6.4.6(vitest@2.0.2) + version: 6.4.6(@types/jest@29.5.12)(vitest@2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0)) '@testing-library/svelte': specifier: ^5.2.0 - version: 5.2.0(svelte@5.0.0-next.183)(vite@5.3.3)(vitest@2.0.2) + version: 5.2.0(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10))(vitest@2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0)) '@testing-library/user-event': specifier: ^14.5.2 version: 14.5.2(@testing-library/dom@10.3.1) @@ -139,11 +139,11 @@ importers: specifier: ^1.5.1 version: 1.5.1 svelte: - specifier: 5.0.0-next.183 - version: 5.0.0-next.183 + specifier: 5.0.0-next.192 + version: 5.0.0-next.192 svelte-check: specifier: ^3.8.4 - version: 3.8.4(postcss-load-config@5.1.0)(postcss@8.4.39)(svelte@5.0.0-next.183) + version: 3.8.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39))(postcss@8.4.39)(svelte@5.0.0-next.192) tslib: specifier: ^2.6.3 version: 2.6.3 @@ -164,26 +164,26 @@ importers: version: 3.5.4 '@melt-ui/svelte': specifier: 0.76.2 - version: 0.76.2(svelte@5.0.0-next.183) + version: 0.76.2(svelte@5.0.0-next.192) bits-ui: specifier: workspace:* version: link:../../packages/bits-ui devDependencies: '@melt-ui/pp': specifier: ^0.3.0 - version: 0.3.2(@melt-ui/svelte@0.76.2)(svelte@5.0.0-next.183) + version: 0.3.2(@melt-ui/svelte@0.76.2(svelte@5.0.0-next.192))(svelte@5.0.0-next.192) '@prettier/sync': specifier: 0.3.0 version: 0.3.0(prettier@3.3.3) '@sveltejs/adapter-cloudflare': specifier: ^4.2.0 - version: 4.6.1(@sveltejs/kit@2.5.18)(wrangler@3.64.0) + version: 4.6.1(@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(wrangler@3.64.0(@cloudflare/workers-types@4.20240712.0)) '@sveltejs/kit': specifier: ^2.5.0 - version: 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3) + version: 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) '@sveltejs/vite-plugin-svelte': specifier: ^3.1.0 - version: 3.1.1(svelte@5.0.0-next.183)(vite@5.3.3) + version: 3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) '@tailwindcss/typography': specifier: ^0.5.10 version: 0.5.13(tailwindcss@3.4.4) @@ -216,19 +216,19 @@ importers: version: 3.1.0 mdsx: specifier: ^0.0.6 - version: 0.0.6(svelte@5.0.0-next.183) + version: 0.0.6(svelte@5.0.0-next.192) mode-watcher: specifier: ^0.2.0 - version: 0.2.2(svelte@5.0.0-next.183) + version: 0.2.2(svelte@5.0.0-next.192) phosphor-svelte: specifier: ^1.4.2 - version: 1.4.2(svelte@5.0.0-next.183) + version: 1.4.2(svelte@5.0.0-next.192) postcss: specifier: ^8.4.33 version: 8.4.39 postcss-load-config: specifier: ^5.0.2 - version: 5.1.0(postcss@8.4.39) + version: 5.1.0(jiti@1.21.6)(postcss@8.4.39) rehype-pretty-code: specifier: ^0.13.0 version: 0.13.2(shiki@1.10.3) @@ -242,14 +242,14 @@ importers: specifier: ^1.1.1 version: 1.10.3 svelte: - specifier: 5.0.0-next.183 - version: 5.0.0-next.183 + specifier: 5.0.0-next.192 + version: 5.0.0-next.192 svelte-check: specifier: ^3.6.9 - version: 3.8.4(postcss-load-config@5.1.0)(postcss@8.4.39)(svelte@5.0.0-next.183) + version: 3.8.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39))(postcss@8.4.39)(svelte@5.0.0-next.192) svelte-sonner: specifier: ^0.3.24 - version: 0.3.26(svelte@5.0.0-next.183) + version: 0.3.26(svelte@5.0.0-next.192) tailwind-merge: specifier: ^2.2.1 version: 2.4.0 @@ -506,10 +506,6 @@ packages: peerDependencies: '@effect-ts/otel-node': '*' peerDependenciesMeta: - '@effect-ts/core': - optional: true - '@effect-ts/otel': - optional: true '@effect-ts/otel-node': optional: true @@ -4468,20 +4464,20 @@ packages: peerDependencies: svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 - svelte-eslint-parser@0.34.1: - resolution: {integrity: sha512-9+uLA1pqI9AZioKVGJzYYmlOZWxfoCXSbAM9iaNm7H01XlYlzRTtJfZgl9o3StQGN41PfGJIbkKkfk3e/pHFfA==} + svelte-eslint-parser@0.40.0: + resolution: {integrity: sha512-M+v1HhC5T1WKYVxWexUCS4o6oIBS88XKzOZuhl2ew+eGxol7eC21e+VE8TC4rXJ3iT3iXT0qlZsZcpKjVo5/zQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.94 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.181 peerDependenciesMeta: svelte: optional: true - svelte-eslint-parser@0.40.0: - resolution: {integrity: sha512-M+v1HhC5T1WKYVxWexUCS4o6oIBS88XKzOZuhl2ew+eGxol7eC21e+VE8TC4rXJ3iT3iXT0qlZsZcpKjVo5/zQ==} + svelte-eslint-parser@0.41.0: + resolution: {integrity: sha512-L6f4hOL+AbgfBIB52Z310pg1d2QjRqm7wy3kI1W6hhdhX5bvu7+f0R6w4ykp5HoDdzq+vGhIJmsisaiJDGmVfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.181 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.191 peerDependenciesMeta: svelte: optional: true @@ -4545,8 +4541,8 @@ packages: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 - svelte@5.0.0-next.183: - resolution: {integrity: sha512-1onDKWp5+a5ehYVWJ0scHVO0IbOTH9zIqYb/odXp/aG0qF9XdR76DL2tLrgRM5xzUdcvXSmakxa+tQDJojTBVw==} + svelte@5.0.0-next.192: + resolution: {integrity: sha512-UgjiqTCsEWyQ157x5YNbmx859vBVFfznKaxuiMCPqHS3HRZ1iqTsSyO3LI/4BHjqPrtxwrOn1Z63VwoJkYBBDA==} engines: {node: '>=18'} symbol-tree@3.2.4: @@ -5075,12 +5071,12 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@antfu/eslint-config@2.22.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0)(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3)': + '@antfu/eslint-config@2.22.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192))(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vitest@2.0.2)': dependencies: '@antfu/install-pkg': 0.3.3 '@clack/prompts': 0.7.0 '@stylistic/eslint-plugin': 2.6.0-beta.0(eslint@9.7.0)(typescript@5.5.3) - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) eslint: 9.7.0 eslint-config-flat-gitignore: 0.1.7 @@ -5095,13 +5091,12 @@ snapshots: eslint-plugin-markdown: 5.1.0(eslint@9.7.0) eslint-plugin-n: 17.9.0(eslint@9.7.0) eslint-plugin-no-only-tests: 3.1.0 - eslint-plugin-perfectionist: 2.11.0(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3)(vue-eslint-parser@9.4.3) + eslint-plugin-perfectionist: 2.11.0(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vue-eslint-parser@9.4.3(eslint@9.7.0)) eslint-plugin-regexp: 2.6.0(eslint@9.7.0) - eslint-plugin-svelte: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.183) eslint-plugin-toml: 0.11.1(eslint@9.7.0) eslint-plugin-unicorn: 54.0.0(eslint@9.7.0) - eslint-plugin-unused-imports: 4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40)(eslint@9.7.0) - eslint-plugin-vitest: 0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3) + eslint-plugin-unused-imports: 4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0) + eslint-plugin-vitest: 0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)(vitest@2.0.2) eslint-plugin-vue: 9.27.0(eslint@9.7.0) eslint-plugin-yml: 1.14.0(eslint@9.7.0) eslint-processor-vue-blocks: 0.1.2(@vue/compiler-sfc@3.4.31)(eslint@9.7.0) @@ -5110,11 +5105,13 @@ snapshots: local-pkg: 0.5.0 parse-gitignore: 2.0.0 picocolors: 1.0.1 - svelte-eslint-parser: 0.34.1(svelte@5.0.0-next.183) toml-eslint-parser: 0.10.0 vue-eslint-parser: 9.4.3(eslint@9.7.0) yaml-eslint-parser: 1.2.3 yargs: 17.7.2 + optionalDependencies: + eslint-plugin-svelte: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192) + svelte-eslint-parser: 0.41.0(svelte@5.0.0-next.192) transitivePeerDependencies: - '@vue/compiler-sfc' - supports-color @@ -5379,7 +5376,6 @@ snapshots: '@contentlayer/utils': 0.3.4 camel-case: 4.1.2 comment-json: 4.2.4 - esbuild: 0.23.0 gray-matter: 4.0.3 mdx-bundler: 9.2.1(esbuild@0.23.0) rehype-stringify: 9.0.4 @@ -5389,6 +5385,8 @@ snapshots: source-map-support: 0.5.21 type-fest: 3.13.1 unified: 10.1.2 + optionalDependencies: + esbuild: 0.23.0 transitivePeerDependencies: - '@effect-ts/otel-node' - supports-color @@ -5426,9 +5424,9 @@ snapshots: '@contentlayer/utils@0.3.4': dependencies: '@effect-ts/core': 0.60.5 - '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1) - '@effect-ts/otel-exporter-trace-otlp-grpc': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/exporter-trace-otlp-grpc@0.39.1)(@opentelemetry/sdk-trace-base@1.25.1) - '@effect-ts/otel-sdk-trace-node': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1)(@opentelemetry/sdk-trace-node@1.25.1) + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)) + '@effect-ts/otel-exporter-trace-otlp-grpc': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/exporter-trace-otlp-grpc@0.39.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)) + '@effect-ts/otel-sdk-trace-node': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@1.25.1(@opentelemetry/api@1.9.0)) '@js-temporal/polyfill': 0.4.4 '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) @@ -5453,25 +5451,25 @@ snapshots: dependencies: '@effect-ts/system': 0.57.5 - '@effect-ts/otel-exporter-trace-otlp-grpc@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/exporter-trace-otlp-grpc@0.39.1)(@opentelemetry/sdk-trace-base@1.25.1)': + '@effect-ts/otel-exporter-trace-otlp-grpc@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/exporter-trace-otlp-grpc@0.39.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))': dependencies: '@effect-ts/core': 0.60.5 - '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1) + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)) '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-grpc': 0.39.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - '@effect-ts/otel-sdk-trace-node@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1)(@opentelemetry/sdk-trace-node@1.25.1)': + '@effect-ts/otel-sdk-trace-node@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@1.25.1(@opentelemetry/api@1.9.0))': dependencies: '@effect-ts/core': 0.60.5 - '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1) + '@effect-ts/otel': 0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)) '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 1.25.1(@opentelemetry/api@1.9.0) - '@effect-ts/otel@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1)(@opentelemetry/sdk-trace-base@1.25.1)': + '@effect-ts/otel@0.15.1(@effect-ts/core@0.60.5)(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0))': dependencies: '@effect-ts/core': 0.60.5 '@opentelemetry/api': 1.9.0 @@ -5786,21 +5784,21 @@ snapshots: '@humanwhocodes/retry@0.3.0': {} - '@huntabyte/eslint-config@0.3.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0)(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3)': + '@huntabyte/eslint-config@0.3.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192))(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vitest@2.0.2)': dependencies: - '@antfu/eslint-config': 2.22.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0)(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3) + '@antfu/eslint-config': 2.22.2(@vue/compiler-sfc@3.4.31)(eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192))(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vitest@2.0.2) '@antfu/install-pkg': 0.3.3 '@clack/prompts': 0.7.0 '@huntabyte/eslint-plugin': 0.1.0(eslint@9.7.0) - '@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0)(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/eslint-plugin': 7.16.0(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/parser': 7.16.0(eslint@9.7.0)(typescript@5.5.3) chalk: 5.3.0 eslint: 9.7.0 eslint-flat-config-utils: 0.2.5 - eslint-plugin-svelte: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.183) + eslint-plugin-svelte: 2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192) local-pkg: 0.5.0 parse-gitignore: 2.0.0 - svelte-eslint-parser: 0.34.1(svelte@5.0.0-next.183) + svelte-eslint-parser: 0.41.0(svelte@5.0.0-next.192) yargs: 17.7.2 transitivePeerDependencies: - '@eslint-react/eslint-plugin' @@ -5937,14 +5935,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@melt-ui/pp@0.3.2(@melt-ui/svelte@0.76.2)(svelte@5.0.0-next.183)': + '@melt-ui/pp@0.3.2(@melt-ui/svelte@0.76.2(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)': dependencies: - '@melt-ui/svelte': 0.76.2(svelte@5.0.0-next.183) + '@melt-ui/svelte': 0.76.2(svelte@5.0.0-next.192) estree-walker: 3.0.3 magic-string: 0.30.10 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 - '@melt-ui/svelte@0.76.2(svelte@5.0.0-next.183)': + '@melt-ui/svelte@0.76.2(svelte@5.0.0-next.192)': dependencies: '@floating-ui/core': 1.6.4 '@floating-ui/dom': 1.6.7 @@ -5952,7 +5950,7 @@ snapshots: dequal: 2.0.3 focus-trap: 7.5.4 nanoid: 5.0.7 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -6220,17 +6218,17 @@ snapshots: - supports-color - typescript - '@sveltejs/adapter-cloudflare@4.6.1(@sveltejs/kit@2.5.18)(wrangler@3.64.0)': + '@sveltejs/adapter-cloudflare@4.6.1(@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(wrangler@3.64.0(@cloudflare/workers-types@4.20240712.0))': dependencies: '@cloudflare/workers-types': 4.20240712.0 - '@sveltejs/kit': 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3) + '@sveltejs/kit': 2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) esbuild: 0.21.5 worktop: 0.8.0-next.18 - wrangler: 3.64.0 + wrangler: 3.64.0(@cloudflare/workers-types@4.20240712.0) - '@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3)': + '@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10))': dependencies: - '@sveltejs/vite-plugin-svelte': 3.1.1(svelte@5.0.0-next.183)(vite@5.3.3) + '@sveltejs/vite-plugin-svelte': 3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 5.0.0 @@ -6242,41 +6240,41 @@ snapshots: sade: 1.8.1 set-cookie-parser: 2.6.0 sirv: 2.0.4 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 tiny-glob: 0.2.9 vite: 5.3.3(@types/node@20.14.10) - '@sveltejs/package@2.3.2(svelte@5.0.0-next.183)(typescript@5.5.3)': + '@sveltejs/package@2.3.2(svelte@5.0.0-next.192)(typescript@5.5.3)': dependencies: chokidar: 3.6.0 kleur: 4.1.5 sade: 1.8.1 semver: 7.6.2 - svelte: 5.0.0-next.183 - svelte2tsx: 0.7.13(svelte@5.0.0-next.183)(typescript@5.5.3) + svelte: 5.0.0-next.192 + svelte2tsx: 0.7.13(svelte@5.0.0-next.192)(typescript@5.5.3) transitivePeerDependencies: - typescript - '@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3)': + '@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10))': dependencies: - '@sveltejs/vite-plugin-svelte': 3.1.1(svelte@5.0.0-next.183)(vite@5.3.3) + '@sveltejs/vite-plugin-svelte': 3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) debug: 4.3.5 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 vite: 5.3.3(@types/node@20.14.10) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.183)(vite@5.3.3)': + '@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.1)(svelte@5.0.0-next.183)(vite@5.3.3) + '@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)))(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10)) debug: 4.3.5 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.10 - svelte: 5.0.0-next.183 - svelte-hmr: 0.16.0(svelte@5.0.0-next.183) + svelte: 5.0.0-next.192 + svelte-hmr: 0.16.0(svelte@5.0.0-next.192) vite: 5.3.3(@types/node@20.14.10) - vitefu: 0.2.5(vite@5.3.3) + vitefu: 0.2.5(vite@5.3.3(@types/node@20.14.10)) transitivePeerDependencies: - supports-color @@ -6310,7 +6308,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.6(vitest@2.0.2)': + '@testing-library/jest-dom@6.4.6(@types/jest@29.5.12)(vitest@2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0))': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.8 @@ -6320,12 +6318,15 @@ snapshots: dom-accessibility-api: 0.6.3 lodash: 4.17.21 redent: 3.0.0 + optionalDependencies: + '@types/jest': 29.5.12 vitest: 2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0) - '@testing-library/svelte@5.2.0(svelte@5.0.0-next.183)(vite@5.3.3)(vitest@2.0.2)': + '@testing-library/svelte@5.2.0(svelte@5.0.0-next.192)(vite@5.3.3(@types/node@20.14.10))(vitest@2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0))': dependencies: '@testing-library/dom': 10.3.1 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 + optionalDependencies: vite: 5.3.3(@types/node@20.14.10) vitest: 2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0) @@ -6436,7 +6437,7 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0)(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)': dependencies: '@eslint-community/regexpp': 4.11.0 '@typescript-eslint/parser': 7.16.0(eslint@9.7.0)(typescript@5.5.3) @@ -6449,14 +6450,15 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3)': + '@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)': dependencies: '@eslint-community/regexpp': 4.11.0 - '@typescript-eslint/parser': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/parser': 7.16.0(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/scope-manager': 8.0.0-alpha.40 '@typescript-eslint/type-utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) @@ -6466,6 +6468,7 @@ snapshots: ignore: 5.3.1 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6478,6 +6481,7 @@ snapshots: '@typescript-eslint/visitor-keys': 7.16.0 debug: 4.3.5 eslint: 9.7.0 + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6490,6 +6494,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.0.0-alpha.40 debug: 4.3.5 eslint: 9.7.0 + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6516,6 +6521,7 @@ snapshots: debug: 4.3.5 eslint: 9.7.0 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6526,6 +6532,7 @@ snapshots: '@typescript-eslint/utils': 8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3) debug: 4.3.5 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - eslint @@ -6547,6 +6554,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.2 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6561,6 +6569,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.2 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -6575,6 +6584,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.2 ts-api-utils: 1.3.0(typescript@5.5.3) + optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color @@ -7353,14 +7363,15 @@ snapshots: eslint-plugin-no-only-tests@3.1.0: {} - eslint-plugin-perfectionist@2.11.0(eslint@9.7.0)(svelte-eslint-parser@0.34.1)(svelte@5.0.0-next.183)(typescript@5.5.3)(vue-eslint-parser@9.4.3): + eslint-plugin-perfectionist@2.11.0(eslint@9.7.0)(svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192))(svelte@5.0.0-next.192)(typescript@5.5.3)(vue-eslint-parser@9.4.3(eslint@9.7.0)): dependencies: '@typescript-eslint/utils': 7.16.0(eslint@9.7.0)(typescript@5.5.3) eslint: 9.7.0 minimatch: 9.0.5 natural-compare-lite: 1.4.0 - svelte: 5.0.0-next.183 - svelte-eslint-parser: 0.34.1(svelte@5.0.0-next.183) + optionalDependencies: + svelte: 5.0.0-next.192 + svelte-eslint-parser: 0.41.0(svelte@5.0.0-next.192) vue-eslint-parser: 9.4.3(eslint@9.7.0) transitivePeerDependencies: - supports-color @@ -7377,7 +7388,7 @@ snapshots: regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.183): + eslint-plugin-svelte@2.42.0(eslint@9.7.0)(svelte@5.0.0-next.192): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@jridgewell/sourcemap-codec': 1.5.0 @@ -7390,8 +7401,9 @@ snapshots: postcss-safe-parser: 6.0.0(postcss@8.4.39) postcss-selector-parser: 6.1.1 semver: 7.6.2 - svelte: 5.0.0-next.183 - svelte-eslint-parser: 0.40.0(svelte@5.0.0-next.183) + svelte-eslint-parser: 0.40.0(svelte@5.0.0-next.192) + optionalDependencies: + svelte: 5.0.0-next.192 transitivePeerDependencies: - ts-node @@ -7427,17 +7439,20 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-unused-imports@4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40)(eslint@9.7.0): + eslint-plugin-unused-imports@4.0.0(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0): dependencies: - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3) eslint: 9.7.0 eslint-rule-composer: 0.3.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) - eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3): + eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)(vitest@2.0.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@8.0.0-alpha.40)(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/utils': 7.16.0(eslint@9.7.0)(typescript@5.5.3) eslint: 9.7.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.0.0-alpha.40(@typescript-eslint/parser@7.16.0(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) + vitest: 2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0) transitivePeerDependencies: - supports-color - typescript @@ -8598,7 +8613,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - mdsx@0.0.6(svelte@5.0.0-next.183): + mdsx@0.0.6(svelte@5.0.0-next.192): dependencies: esrap: 1.2.2 hast-util-to-html: 9.0.1 @@ -8607,7 +8622,7 @@ snapshots: rehype-stringify: 10.0.0 remark-parse: 11.0.0 remark-rehype: 11.1.0 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 unified: 11.0.5 unist-util-visit: 5.0.0 vfile: 6.0.1 @@ -9113,9 +9128,9 @@ snapshots: pkg-types: 1.1.3 ufo: 1.5.3 - mode-watcher@0.2.2(svelte@5.0.0-next.183): + mode-watcher@0.2.2(svelte@5.0.0-next.192): dependencies: - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 mri@1.2.0: {} @@ -9341,9 +9356,9 @@ snapshots: estree-walker: 3.0.3 is-reference: 3.0.2 - phosphor-svelte@1.4.2(svelte@5.0.0-next.183): + phosphor-svelte@1.4.2(svelte@5.0.0-next.192): dependencies: - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 picocolors@1.0.1: {} @@ -9384,20 +9399,24 @@ snapshots: postcss-load-config@3.1.4(postcss@8.4.39): dependencies: lilconfig: 2.1.0 - postcss: 8.4.39 yaml: 1.10.2 + optionalDependencies: + postcss: 8.4.39 postcss-load-config@4.0.2(postcss@8.4.39): dependencies: lilconfig: 3.1.2 - postcss: 8.4.39 yaml: 2.4.5 + optionalDependencies: + postcss: 8.4.39 - postcss-load-config@5.1.0(postcss@8.4.39): + postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39): dependencies: lilconfig: 3.1.2 - postcss: 8.4.39 yaml: 2.4.5 + optionalDependencies: + jiti: 1.21.6 + postcss: 8.4.39 postcss-nested@6.0.1(postcss@8.4.39): dependencies: @@ -9439,15 +9458,16 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@5.0.0-next.183): + prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@5.0.0-next.192): dependencies: prettier: 3.3.3 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 - prettier-plugin-tailwindcss@0.5.13(prettier-plugin-svelte@3.2.5)(prettier@3.3.3): + prettier-plugin-tailwindcss@0.5.13(prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@5.0.0-next.192))(prettier@3.3.3): dependencies: prettier: 3.3.3 - prettier-plugin-svelte: 3.2.5(prettier@3.3.3)(svelte@5.0.0-next.183) + optionalDependencies: + prettier-plugin-svelte: 3.2.5(prettier@3.3.3)(svelte@5.0.0-next.192) prettier@2.8.8: {} @@ -9734,10 +9754,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 - runed@0.15.0(svelte@5.0.0-next.183): + runed@0.15.0(svelte@5.0.0-next.192): dependencies: esm-env: 1.0.0 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 rxjs@7.8.1: dependencies: @@ -9961,14 +9981,14 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@3.8.4(postcss-load-config@5.1.0)(postcss@8.4.39)(svelte@5.0.0-next.183): + svelte-check@3.8.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39))(postcss@8.4.39)(svelte@5.0.0-next.192): dependencies: '@jridgewell/trace-mapping': 0.3.25 chokidar: 3.6.0 picocolors: 1.0.1 sade: 1.8.1 - svelte: 5.0.0-next.183 - svelte-preprocess: 5.1.4(postcss-load-config@5.1.0)(postcss@8.4.39)(svelte@5.0.0-next.183)(typescript@5.5.3) + svelte: 5.0.0-next.192 + svelte-preprocess: 5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39))(postcss@8.4.39)(svelte@5.0.0-next.192)(typescript@5.5.3) typescript: 5.5.3 transitivePeerDependencies: - '@babel/core' @@ -9981,56 +10001,59 @@ snapshots: - stylus - sugarss - svelte-eslint-parser@0.34.1(svelte@5.0.0-next.183): + svelte-eslint-parser@0.40.0(svelte@5.0.0-next.192): dependencies: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 postcss: 8.4.39 postcss-scss: 4.0.9(postcss@8.4.39) - svelte: 5.0.0-next.183 + optionalDependencies: + svelte: 5.0.0-next.192 - svelte-eslint-parser@0.40.0(svelte@5.0.0-next.183): + svelte-eslint-parser@0.41.0(svelte@5.0.0-next.192): dependencies: eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 postcss: 8.4.39 postcss-scss: 4.0.9(postcss@8.4.39) - svelte: 5.0.0-next.183 + optionalDependencies: + svelte: 5.0.0-next.192 - svelte-hmr@0.16.0(svelte@5.0.0-next.183): + svelte-hmr@0.16.0(svelte@5.0.0-next.192): dependencies: - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 - svelte-preprocess@5.1.4(postcss-load-config@5.1.0)(postcss@8.4.39)(svelte@5.0.0-next.183)(typescript@5.5.3): + svelte-preprocess@5.1.4(postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.39))(postcss@8.4.39)(svelte@5.0.0-next.192)(typescript@5.5.3): dependencies: '@types/pug': 2.0.10 detect-indent: 6.1.0 magic-string: 0.30.10 - postcss: 8.4.39 - postcss-load-config: 5.1.0(postcss@8.4.39) sorcery: 0.11.1 strip-indent: 3.0.0 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 + optionalDependencies: + postcss: 8.4.39 + postcss-load-config: 5.1.0(jiti@1.21.6)(postcss@8.4.39) typescript: 5.5.3 - svelte-sonner@0.3.26(svelte@5.0.0-next.183): + svelte-sonner@0.3.26(svelte@5.0.0-next.192): dependencies: - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 - svelte-toolbelt@0.0.2(svelte@5.0.0-next.183): + svelte-toolbelt@0.0.2(svelte@5.0.0-next.192): dependencies: - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 - svelte2tsx@0.7.13(svelte@5.0.0-next.183)(typescript@5.5.3): + svelte2tsx@0.7.13(svelte@5.0.0-next.192)(typescript@5.5.3): dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 - svelte: 5.0.0-next.183 + svelte: 5.0.0-next.192 typescript: 5.5.3 - svelte@5.0.0-next.183: + svelte@5.0.0-next.192: dependencies: '@ampproject/remapping': 2.3.0 '@jridgewell/sourcemap-codec': 1.5.0 @@ -10382,32 +10405,29 @@ snapshots: vite@5.3.3(@types/node@20.14.10): dependencies: - '@types/node': 20.14.10 esbuild: 0.21.5 postcss: 8.4.39 rollup: 4.18.1 optionalDependencies: + '@types/node': 20.14.10 fsevents: 2.3.3 - vitefu@0.2.5(vite@5.3.3): - dependencies: + vitefu@0.2.5(vite@5.3.3(@types/node@20.14.10)): + optionalDependencies: vite: 5.3.3(@types/node@20.14.10) vitest@2.0.2(@types/node@20.14.10)(@vitest/ui@1.6.0)(jsdom@24.1.0): dependencies: '@ampproject/remapping': 2.3.0 - '@types/node': 20.14.10 '@vitest/expect': 2.0.2 '@vitest/pretty-format': 2.0.2 '@vitest/runner': 2.0.2 '@vitest/snapshot': 2.0.2 '@vitest/spy': 2.0.2 - '@vitest/ui': 1.6.0(vitest@2.0.2) '@vitest/utils': 2.0.2 chai: 5.1.1 debug: 4.3.5 execa: 8.0.1 - jsdom: 24.1.0 magic-string: 0.30.10 pathe: 1.1.2 std-env: 3.7.0 @@ -10417,6 +10437,10 @@ snapshots: vite: 5.3.3(@types/node@20.14.10) vite-node: 2.0.2(@types/node@20.14.10) why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.14.10 + '@vitest/ui': 1.6.0(vitest@2.0.2) + jsdom: 24.1.0 transitivePeerDependencies: - less - lightningcss @@ -10500,7 +10524,7 @@ snapshots: mrmime: 2.0.0 regexparam: 3.0.0 - wrangler@3.64.0: + wrangler@3.64.0(@cloudflare/workers-types@4.20240712.0): dependencies: '@cloudflare/kv-asset-handler': 0.3.4 '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) @@ -10519,6 +10543,7 @@ snapshots: unenv: unenv-nightly@1.10.0-1717606461.a117952 xxhash-wasm: 1.0.2 optionalDependencies: + '@cloudflare/workers-types': 4.20240712.0 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil diff --git a/sites/docs/package.json b/sites/docs/package.json index f5ba3a7e5..bbec56ca1 100644 --- a/sites/docs/package.json +++ b/sites/docs/package.json @@ -39,7 +39,7 @@ "rehype-slug": "^6.0.0", "remark-gfm": "^4.0.0", "shiki": "^1.1.1", - "svelte": "5.0.0-next.183", + "svelte": "5.0.0-next.192", "svelte-check": "^3.6.9", "svelte-sonner": "^0.3.24", "tailwind-merge": "^2.2.1", diff --git a/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte b/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte index 2f6884904..f3a9a723a 100644 --- a/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte +++ b/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte @@ -12,7 +12,7 @@ import { ScrollArea } from "bits-ui"; + import { cn } from "$lib/utils/styles.js"; + + let type = $state<"auto" | "hover" | "scroll" | "always">("auto"); + let height = $state(200); + let width = $state(250); + let wrapText = $state(false); + let numParagraphs = $state(3); -
- +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + - -

+ Scroll Area +

+ {#each Array(numParagraphs) as _} +

- Scroll Area - -

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dignissimos impedit rem, repellat deserunt ducimus quasi nisi voluptatem cumque aliquid esse ea deleniti eveniet incidunt! Deserunt minus laborum accusamus iusto dolorum. Lorem @@ -21,14 +63,22 @@ minima eos fugit voluptate excepturi eveniet dolore et, ratione impedit consequuntur dolorem hic quae corrupti autem? Dolorem, sit voluptatum.

-
+ {/each}
+ + +