Use Line Breakdown

PreviousNext

A hook component.

Docs
fancyhook

Preview

Loading preview…
hooks/use-line-breakdown.ts
import { RefObject, useEffect, useState } from "react"

interface UseLineBreakdownResult {
  lineCount: number
  lines: string[][]
}

export function useLineBreakdown(
  elementRef: RefObject<HTMLElement | null>,
  text: string
): UseLineBreakdownResult {
  const [breakdown, setBreakdown] = useState<UseLineBreakdownResult>({
    lineCount: 0,
    lines: [[]],
  })

  useEffect(() => {
    const element = elementRef.current
    if (!element) return

    const calculateLines = () => {
      // Get basic measurements
      const style = window.getComputedStyle(element)
      const lineHeight = parseInt(style.lineHeight)
      const elementHeight = element.offsetHeight

      const linesCount = Math.ceil(elementHeight / lineHeight)

      console.log(elementHeight / lineHeight)

      // Create temporary elements to measure text
      const tempSpan = element.appendChild(document.createElement("span"))
      tempSpan.style.visibility = "hidden"
      tempSpan.style.position = "absolute"
      tempSpan.style.whiteSpace = "nowrap"
      element.appendChild(tempSpan)

      // Split text into words
      const words = text.split(" ")
      const lineGroups: string[][] = [[]]
      let currentLine = 0
      let previousTop = 0

      // Group words into lines
      words.forEach((word, index) => {
        tempSpan.textContent = word
        const rect = tempSpan.getBoundingClientRect()

        if (rect.top > previousTop && index > 0) {
          currentLine++
          lineGroups[currentLine] = []
          previousTop = rect.top
        }

        lineGroups[currentLine].push(word)
      })

      element.removeChild(tempSpan)

      setBreakdown({
        lineCount: lineGroups.length,
        lines: lineGroups,
      })
    }

    calculateLines()

    const resizeObserver = new ResizeObserver(calculateLines)
    resizeObserver.observe(element)

    return () => {
      resizeObserver.disconnect()
    }
  }, [elementRef, text])

  return breakdown
}

Installation

npx shadcn@latest add @fancy/use-line-breakdown

Usage

import { UseLineBreakdown } from "@/hooks/use-line-breakdown"
const value = UseLineBreakdown()