summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/scroll-view.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-09 07:36:39 -0500
committerGitHub <[email protected]>2026-03-09 07:36:39 -0500
commitc71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e (patch)
treea30482cedb38dc24cad70e24ad717817065620d6 /packages/ui/src/components/scroll-view.tsx
parentf27ef595f65aa719be3f8d08665d683e95083ed3 (diff)
downloadopencode-c71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e.tar.gz
opencode-c71d1bde5e8dcc8be49c15697ad2e5d0f2607e5e.zip
revert(app): "STUPID SEXY TIMELINE (#16420)" (#16745)
Diffstat (limited to 'packages/ui/src/components/scroll-view.tsx')
-rw-r--r--packages/ui/src/components/scroll-view.tsx70
1 files changed, 14 insertions, 56 deletions
diff --git a/packages/ui/src/components/scroll-view.tsx b/packages/ui/src/components/scroll-view.tsx
index a8d3cf0f8..52ed39a46 100644
--- a/packages/ui/src/components/scroll-view.tsx
+++ b/packages/ui/src/components/scroll-view.tsx
@@ -1,18 +1,17 @@
-import { createSignal, onCleanup, onMount, splitProps, type ComponentProps, Show } from "solid-js"
-import { animate, type AnimationPlaybackControls } from "motion"
+import { createSignal, onCleanup, onMount, splitProps, type ComponentProps, Show, mergeProps } from "solid-js"
import { useI18n } from "../context/i18n"
-import { FAST_SPRING } from "./motion"
export interface ScrollViewProps extends ComponentProps<"div"> {
viewportRef?: (el: HTMLDivElement) => void
- reverse?: boolean
+ orientation?: "vertical" | "horizontal" // currently only vertical is fully implemented for thumb
}
export function ScrollView(props: ScrollViewProps) {
const i18n = useI18n()
+ const merged = mergeProps({ orientation: "vertical" }, props)
const [local, events, rest] = splitProps(
- props,
- ["class", "children", "viewportRef", "style", "reverse"],
+ merged,
+ ["class", "children", "viewportRef", "orientation", "style"],
[
"onScroll",
"onWheel",
@@ -26,9 +25,9 @@ export function ScrollView(props: ScrollViewProps) {
],
)
+ let rootRef!: HTMLDivElement
let viewportRef!: HTMLDivElement
let thumbRef!: HTMLDivElement
- let anim: AnimationPlaybackControls | undefined
const [isHovered, setIsHovered] = createSignal(false)
const [isDragging, setIsDragging] = createSignal(false)
@@ -37,8 +36,6 @@ export function ScrollView(props: ScrollViewProps) {
const [thumbTop, setThumbTop] = createSignal(0)
const [showThumb, setShowThumb] = createSignal(false)
- const reverse = () => local.reverse === true
-
const updateThumb = () => {
if (!viewportRef) return
const { scrollTop, scrollHeight, clientHeight } = viewportRef
@@ -60,13 +57,9 @@ export function ScrollView(props: ScrollViewProps) {
const maxScrollTop = scrollHeight - clientHeight
const maxThumbTop = trackHeight - height
- const top = (() => {
- if (maxScrollTop <= 0) return 0
- if (!reverse()) return (scrollTop / maxScrollTop) * maxThumbTop
- return ((maxScrollTop + scrollTop) / maxScrollTop) * maxThumbTop
- })()
+ const top = maxScrollTop > 0 ? (scrollTop / maxScrollTop) * maxThumbTop : 0
- // Ensure thumb stays within bounds
+ // Ensure thumb stays within bounds (shouldn't be necessary due to math above, but good for safety)
const boundedTop = trackPadding + Math.max(0, Math.min(top, maxThumbTop))
setThumbHeight(height)
@@ -89,7 +82,6 @@ export function ScrollView(props: ScrollViewProps) {
}
onCleanup(() => {
- stop()
observer.disconnect()
})
@@ -131,31 +123,6 @@ export function ScrollView(props: ScrollViewProps) {
thumbRef.addEventListener("pointerup", onPointerUp)
}
- const stop = () => {
- if (!anim) return
- anim.stop()
- anim = undefined
- }
-
- const limit = (top: number) => {
- const max = viewportRef.scrollHeight - viewportRef.clientHeight
- if (reverse()) return Math.max(-max, Math.min(0, top))
- return Math.max(0, Math.min(max, top))
- }
-
- const glide = (top: number) => {
- stop()
- anim = animate(viewportRef.scrollTop, limit(top), {
- ...FAST_SPRING,
- onUpdate: (v) => {
- viewportRef.scrollTop = v
- },
- onComplete: () => {
- anim = undefined
- },
- })
- }
-
// Keybinds implementation
// We ensure the viewport has a tabindex so it can receive focus
// We can also explicitly catch PageUp/Down if we want smooth scroll or specific behavior,
@@ -180,11 +147,11 @@ export function ScrollView(props: ScrollViewProps) {
break
case "Home":
e.preventDefault()
- glide(reverse() ? -(viewportRef.scrollHeight - viewportRef.clientHeight) : 0)
+ viewportRef.scrollTo({ top: 0, behavior: "smooth" })
break
case "End":
e.preventDefault()
- glide(reverse() ? 0 : viewportRef.scrollHeight - viewportRef.clientHeight)
+ viewportRef.scrollTo({ top: viewportRef.scrollHeight, behavior: "smooth" })
break
case "ArrowUp":
e.preventDefault()
@@ -199,6 +166,7 @@ export function ScrollView(props: ScrollViewProps) {
return (
<div
+ ref={rootRef}
class={`scroll-view ${local.class || ""}`}
style={local.style}
onPointerEnter={() => setIsHovered(true)}
@@ -209,26 +177,16 @@ export function ScrollView(props: ScrollViewProps) {
<div
ref={viewportRef}
class="scroll-view__viewport"
- data-reverse={reverse() ? "true" : undefined}
onScroll={(e) => {
updateThumb()
if (typeof events.onScroll === "function") events.onScroll(e as any)
}}
- onWheel={(e) => {
- if (e.deltaY) stop()
- if (typeof events.onWheel === "function") events.onWheel(e as any)
- }}
- onTouchStart={(e) => {
- stop()
- if (typeof events.onTouchStart === "function") events.onTouchStart(e as any)
- }}
+ onWheel={events.onWheel as any}
+ onTouchStart={events.onTouchStart as any}
onTouchMove={events.onTouchMove as any}
onTouchEnd={events.onTouchEnd as any}
onTouchCancel={events.onTouchCancel as any}
- onPointerDown={(e) => {
- stop()
- if (typeof events.onPointerDown === "function") events.onPointerDown(e as any)
- }}
+ onPointerDown={events.onPointerDown as any}
onClick={events.onClick as any}
tabIndex={0}
role="region"