function useTextSelection()

in packages/hooks/src/useTextSelection/index.ts [52:109]


function useTextSelection(target?: BasicTarget<Document | Element>): State {
  const [state, setState] = useState(initState);

  const stateRef = useRef(state);
  const isInRangeRef = useRef(false);
  stateRef.current = state;

  useEffectWithTarget(
    () => {
      const el = getTargetElement(target, document);
      if (!el) {
        return;
      }

      const mouseupHandler = () => {
        let selObj: Selection | null = null;
        let text = '';
        let rect = initRect;
        if (!window.getSelection) return;
        selObj = window.getSelection();
        text = selObj ? selObj.toString() : '';
        if (text && isInRangeRef.current) {
          rect = getRectFromSelection(selObj);
          setState({ ...state, text, ...rect });
        }
      };

      // 任意点击都需要清空之前的 range
      const mousedownHandler = (e) => {
        // 如果是鼠标右键需要跳过 这样选中的数据就不会被清空
        if (e.button === 2) return;

        if (!window.getSelection) return;
        if (stateRef.current.text) {
          setState({ ...initState });
        }
        isInRangeRef.current = false;
        const selObj = window.getSelection();
        if (!selObj) return;
        selObj.removeAllRanges();
        isInRangeRef.current = el.contains(e.target);
      };

      el.addEventListener('mouseup', mouseupHandler);

      document.addEventListener('mousedown', mousedownHandler);

      return () => {
        el.removeEventListener('mouseup', mouseupHandler);
        document.removeEventListener('mousedown', mousedownHandler);
      };
    },
    [],
    target,
  );

  return state;
}