use-text-selection
shadcn-hooks/use-text-selectionFreeHook
A hook to get the text selection and its bounding rect from an element
Install it
npx shadcn@latest add https://shadcn-hooks.com/r/use-text-selection.jsonSource
1import { useRef, useState } from 'react'2import { useEffectWithTarget } from '@/registry/hooks/use-effect-with-target'3import { getTargetElement } from '@/registry/lib/create-effect-with-target'4import type { BasicTarget } from '@/registry/lib/create-effect-with-target'56interface Rect {7 top: number8 left: number9 bottom: number10 right: number11 height: number12 width: number13}14export interface State extends Rect {15 text: string16}1718const initRect: Rect = {19 top: Number.NaN,20 left: Number.NaN,21 bottom: Number.NaN,22 right: Number.NaN,23 height: Number.NaN,24 width: Number.NaN,25}2627const initState: State = {28 text: '',29 ...initRect,30}3132function getRectFromSelection(selection: Selection | null): Rect {33 if (!selection) {34 return initRect35 }3637 if (selection.rangeCount < 1) {38 return initRect39 }40 const range = selection.getRangeAt(0)41 const { height, width, top, left, right, bottom } =42 range.getBoundingClientRect()43 return {44 height,45 width,46 top,47 left,48 right,49 bottom,50 }51}5253export function useTextSelection(54 target?: BasicTarget<Document | Element>,55): State {56 const [state, setState] = useState(initState)5758 const stateRef = useRef(state)59 const isInRangeRef = useRef(false)60 stateRef.current = state6162 useEffectWithTarget(63 () => {64 const el = getTargetElement(target, document)65 if (!el) {66 return67 }6869 const mouseupHandler = () => {70 let selObj: Selection | null = null71 let text = ''72 let rect = initRect73 if (!window.getSelection) {74 return75 }76 selObj = window.getSelection()77 text = selObj ? selObj.toString() : ''78 if (text && isInRangeRef.current) {79 rect = getRectFromSelection(selObj)80 setState({ ...state, text, ...rect })81 }82 }8384 // clear the previous range on any click85 const mousedownHandler = (e: MouseEvent) => {86 // if the mouse button is right, skip it because the selection will be cleared87 if (e.button === 2) {88 return89 }90 if (!window.getSelection) {91 return92 }93 if (stateRef.current.text) {94 setState({ ...initState })95 }96 isInRangeRef.current = false97 const selObj = window.getSelection()98 if (!selObj) {99 return100 }101 selObj.removeAllRanges()102 isInRangeRef.current = el.contains(e.target as Node)103 }104105// … truncated
What it pulls in
Other registry items
Files it writes
More from shadcn-hooks
All 58 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| use-active-elementuse-active-element | shadcn-hooks | Hooks | Free | no deps | |
| use-batteryuse-battery | shadcn-hooks | Hooks | Free | no deps | |
| use-booleanuse-boolean | shadcn-hooks | Hooks | Free | no deps | |
| use-click-any-whereuse-click-any-where | shadcn-hooks | Hooks | Free | no deps | |
| use-click-awayuse-click-away | shadcn-hooks | Hooks | Free | no deps | |
| use-clipboarduse-clipboard | shadcn-hooks | Hooks | Free | no deps | |
| use-controllable-valueuse-controllable-value | shadcn-hooks | Hooks | Free | 1 dep | |
| use-counteruse-counter | shadcn-hooks | Hooks | Free | no deps |
