Files
kilocode/packages/kilo-vscode/webview-ui/agent-manager/tab-scroll.ts
T
Mariusandgithub-actions[bot] 43204b680e Make Agent Manager session tabs compact (#9970)
* feat(agent-manager): compact session tabs

* fix(agent-manager): avoid tab count class guard

* style(agent-manager): format compact tabs

* chore: update kilo-vscode visual regression baselines

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-07 10:29:50 +00:00

84 lines
2.7 KiB
TypeScript

import { createEffect, createSignal, onCleanup } from "solid-js"
import type { Accessor } from "solid-js"
import type { SessionInfo } from "../src/types/messages"
/**
* Keeps the Agent Manager tab strip usable when tabs overflow.
*
* - Converts vertical wheel movement over the tab strip into horizontal scroll.
* - Tracks whether the left/right fade indicators should be visible.
* - Scrolls the active tab into view after tab selection or tab list changes.
*/
export function useTabScroll(activeTabs: Accessor<SessionInfo[]>, activeId: Accessor<string | undefined>) {
const [ref, setRef] = createSignal<HTMLDivElement | undefined>()
const [showLeft, setShowLeft] = createSignal(false)
const [showRight, setShowRight] = createSignal(false)
let scrollFrame: number | undefined
let activeFrame: number | undefined
const update = () => {
if (scrollFrame !== undefined) return
scrollFrame = requestAnimationFrame(() => {
scrollFrame = undefined
const el = ref()
if (!el) return
setShowLeft(el.scrollLeft > 2)
setShowRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 2)
})
}
const wheel = (e: WheelEvent) => {
const el = ref()
if (!el) return
if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) return
e.preventDefault()
el.scrollLeft += e.deltaY > 0 ? 60 : -60
}
createEffect(() => {
const el = ref()
if (!el) return
el.addEventListener("scroll", update, { passive: true })
el.addEventListener("wheel", wheel, { passive: false })
const ro = new ResizeObserver(update)
ro.observe(el)
const mo = new MutationObserver(update)
mo.observe(el, { childList: true, subtree: true })
onCleanup(() => {
el.removeEventListener("scroll", update)
el.removeEventListener("wheel", wheel)
ro.disconnect()
mo.disconnect()
})
})
createEffect(() => {
const id = activeId()
const el = ref()
activeTabs()
if (!id || !el) return
if (activeFrame !== undefined) cancelAnimationFrame(activeFrame)
activeFrame = requestAnimationFrame(() => {
activeFrame = undefined
const tab = el.querySelector(`[data-tab-id="${id}"]`) as HTMLElement | null
if (!tab) return
const left = tab.offsetLeft
const right = left + tab.offsetWidth
if (left < el.scrollLeft) {
el.scrollTo({ left: left - 8, behavior: "smooth" })
return
}
if (right > el.scrollLeft + el.clientWidth) {
el.scrollTo({ left: right - el.clientWidth + 8, behavior: "smooth" })
}
})
})
onCleanup(() => {
if (scrollFrame !== undefined) cancelAnimationFrame(scrollFrame)
if (activeFrame !== undefined) cancelAnimationFrame(activeFrame)
})
return { setRef, showLeft, showRight }
}