import type { JSX, ValidComponent } from "@solidjs/web"; import { dynamic } from "@solidjs/web"; import { createEffect, createSignal, omit } from "solid-js"; import { composeRefs, userRef } from "../../internals/compose-refs"; import { mergeRootProps } from "../../internals/merge-root-props"; import { resolveClassStyle } from "../../internals/resolve-class-style"; import type { BaseUIComponentProps } from "../../internals/types"; import { type ScrollAreaRootState, useScrollAreaRootContext, } from "../root/scroll-area-root-context.ts"; import { scrollAreaDataAttrs } from "../utils/state-attrs.ts"; import { useScrollAreaViewportContext } from "../viewport/scroll-area-viewport-context.ts"; export interface ScrollAreaContentState extends ScrollAreaRootState {} export interface ScrollAreaContentProps extends BaseUIComponentProps<"div", ScrollAreaContentState> { /** Tag/component to render. Defaults to `"div"`. */ as?: ValidComponent; } /** * Container for the scrollable content. Renders a `
` element (or `as` * override). Runs a `ResizeObserver` on its own wrapper so size changes within * the content re-trigger the viewport's thumb recompute. * * ยง1 wave 3: replaces `renderElement` with `dynamic(() => props.as ?? "div")`. */ export function ScrollAreaContent(props: ScrollAreaContentProps): JSX.Element { const root = useScrollAreaRootContext(); const viewport = useScrollAreaViewportContext(); const [contentWrapper, setContentWrapper] = createSignal(null, { ownedWrite: true }); createEffect( () => contentWrapper(), (el) => { if (typeof ResizeObserver === "undefined" || !el) return; let hasInitialized = false; const ro = new ResizeObserver(() => { // Skip the initial delivery to avoid double-counting the mount // pass which the viewport already performed. if (!hasInitialized) { hasInitialized = true; return; } viewport.computeThumbPosition(); }); ro.observe(el); return () => { ro.disconnect(); }; }, ); const userStyling = resolveClassStyle(props, () => root.viewportState()); const userProps = omit(props, "class", "style", "attrs", "as"); const localRef = (el: HTMLDivElement | null): void => { setContentWrapper(el); }; const internalSlot = { role: "presentation" as const, style: { "min-width": "fit-content" } as JSX.CSSProperties, }; const styledUserProps = mergeRootProps(userStyling, userProps); let merged: Record = mergeRootProps( internalSlot, scrollAreaDataAttrs(root.viewportState), ); merged = mergeRootProps(merged, styledUserProps); const Tag = dynamic(() => props.as ?? "div"); return ; }