Skip to content

Instantly share code, notes, and snippets.

@KristofferEriksson
Last active February 24, 2024 22:22
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save KristofferEriksson/8acb9b3eb241507eb0f6232938bf4ec7 to your computer and use it in GitHub Desktop.
Save KristofferEriksson/8acb9b3eb241507eb0f6232938bf4ec7 to your computer and use it in GitHub Desktop.
A React Typescript hook that tracks user text selections & their screen positions
import { useEffect, useState } from "react";
type UseTextSelectionReturn = {
text: string;
rects: DOMRect[];
ranges: Range[];
selection: Selection | null;
};
const getRangesFromSelection = (selection: Selection): Range[] => {
const rangeCount = selection.rangeCount;
return Array.from({ length: rangeCount }, (_, i) => selection.getRangeAt(i));
};
const isSelectionInsideRef = (
selection: Selection,
ref: React.RefObject<HTMLElement>,
) => {
if (!ref.current || selection.rangeCount === 0) return true;
const range = selection.getRangeAt(0);
return ref.current.contains(range.commonAncestorContainer);
};
export function useTextSelection(
elementRef?: React.RefObject<HTMLElement>,
): UseTextSelectionReturn {
const [selection, setSelection] = useState<Selection | null>(null);
const [text, setText] = useState("");
const [ranges, setRanges] = useState<Range[]>([]);
const [rects, setRects] = useState<DOMRect[]>([]);
useEffect(() => {
const onSelectionChange = () => {
const newSelection = window.getSelection();
if (
newSelection &&
(!elementRef || isSelectionInsideRef(newSelection, elementRef))
) {
setSelection(newSelection);
setText(newSelection.toString());
const newRanges = getRangesFromSelection(newSelection);
setRanges(newRanges);
setRects(newRanges.map((range) => range.getBoundingClientRect()));
} else {
setText("");
setRanges([]);
setRects([]);
setSelection(null);
}
};
document.addEventListener("selectionchange", onSelectionChange);
return () => {
document.removeEventListener("selectionchange", onSelectionChange);
};
}, [elementRef]);
return {
text,
rects,
ranges,
selection,
};
}
@i-am-henri
Copy link

Hey, am I allowed to use your hooks in some of my projects? I'm coding a note-taking app, such hooks could be very helpful.

@KristofferEriksson
Copy link
Author

Hey, am I allowed to use your hooks in some of my projects? I'm coding a note-taking app, such hooks could be very helpful.

Feel free to use it! If you're using it in an open-source project I'd be very happy to get a backlink or mention

@i-am-henri
Copy link

Would you also like a mention in a private project?

@KristofferEriksson
Copy link
Author

Would you also like a mention in a private project?

I'd always by happy for one - but feel free to use the hooks I've published the way you want. If you'd like to show what you've built, please show me at http://twitter.com/buildWithKris

@i-am-henri
Copy link

Thank you, if the product is ready, i'll show you.

@nitishmahawar
Copy link

Can you please provide the example code?

@robSturcke
Copy link

nitishmahawar

Here's a rough example:


export const TestComponent = () => {
  const { isListening, transcript, start, stop } = useSpeechToText({
    lang: 'en-US',
    continuous: true,
    interimResults: true,
    maxAlternatives: 1,
  });

  return (
    <>
      <button onClick={isListening ? stop : start}>
        {isListening ? 'Stop' : 'Start'}
      </button>

      <textarea value={transcript} readOnly />
    </>
  );
};

@KristofferEriksson
Copy link
Author

nitishmahawar

Here's a rough example:


export const TestComponent = () => {
  const { isListening, transcript, start, stop } = useSpeechToText({
    lang: 'en-US',
    continuous: true,
    interimResults: true,
    maxAlternatives: 1,
  });

  return (
    <>
      <button onClick={isListening ? stop : start}>
        {isListening ? 'Stop' : 'Start'}
      </button>

      <textarea value={transcript} readOnly />
    </>
  );
};

Thanks for taking the time putting this together @robSturcke!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment