51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
"use client"
|
|
|
|
import { useLayoutEffect, useRef, useState } from "react"
|
|
|
|
const OVERFLOW_BUTTON_WIDTH = 36
|
|
|
|
export function useToolbarOverflow(itemCount: number) {
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
const measureRef = useRef<HTMLDivElement>(null)
|
|
const [visibleCount, setVisibleCount] = useState(itemCount)
|
|
|
|
useLayoutEffect(() => {
|
|
const container = containerRef.current
|
|
const measure = measureRef.current
|
|
if (!container || !measure) return
|
|
|
|
const recalculate = () => {
|
|
const children = Array.from(measure.children) as HTMLElement[]
|
|
if (children.length === 0) return
|
|
|
|
const totalWidth = children.reduce((sum, child) => sum + child.offsetWidth, 0)
|
|
if (totalWidth <= container.clientWidth) {
|
|
setVisibleCount(children.length)
|
|
return
|
|
}
|
|
|
|
const available = container.clientWidth - OVERFLOW_BUTTON_WIDTH
|
|
let used = 0
|
|
let fit = 0
|
|
|
|
for (const child of children) {
|
|
const width = child.offsetWidth
|
|
if (used + width > available) break
|
|
used += width
|
|
fit += 1
|
|
}
|
|
|
|
setVisibleCount(Math.max(1, fit))
|
|
}
|
|
|
|
recalculate()
|
|
const ro = new ResizeObserver(recalculate)
|
|
ro.observe(container)
|
|
return () => ro.disconnect()
|
|
}, [itemCount])
|
|
|
|
const hasOverflow = visibleCount < itemCount
|
|
|
|
return { containerRef, measureRef, visibleCount, hasOverflow }
|
|
}
|