+
You can select any text on the page.
-
Selected Text: {{ state.text || 'No selected' }}
-
Selected Position: {{ JSON.stringify(position) }}
-
Selected Size: {{ JSON.stringify(size) }}
+
+ Selected Text:
+ {{ text || 'No selected' }}
+
+
+ Selected rects:
+ {{ JSON.stringify(rects) }}
+
diff --git a/packages/core/useTextSelection/index.ts b/packages/core/useTextSelection/index.ts
index 080f031dfe0..2d6f632006e 100644
--- a/packages/core/useTextSelection/index.ts
+++ b/packages/core/useTextSelection/index.ts
@@ -1,70 +1,39 @@
-import type { MaybeRef } from '@vueuse/shared'
-import { ref } from 'vue-demi'
+import { computed, ref } from 'vue-demi'
import { useEventListener } from '../useEventListener'
-import { defaultWindow } from '../_configurable'
-type Rect = Omit
-
-export interface UseTextSelectionState extends Rect {
- text: string
-}
-
-const initialRect: Rect = {
- top: 0,
- left: 0,
- bottom: 0,
- right: 0,
- height: 0,
- width: 0,
-}
-
-const initialState: UseTextSelectionState = {
- text: '',
- ...initialRect,
-}
-
-function getRectFromSelection(selection: Selection | null): Rect {
- if (!selection || selection.rangeCount < 1)
- return initialRect
-
- const range = selection.getRangeAt(0)
- const { height, width, top, left, right, bottom } = range.getBoundingClientRect()
- return {
- height,
- width,
- top,
- left,
- right,
- bottom,
+function getRangesFromSelection(selection: Selection) {
+ const rangeCount = selection.rangeCount ?? 0
+ const ranges = new Array(rangeCount)
+ for (let i = 0; i < rangeCount; i++) {
+ const range = selection.getRangeAt(i)
+ ranges[i] = range
}
+ return ranges
}
-export function useTextSelection(
- element?: MaybeRef,
-) {
- const state = ref(initialState)
-
- if (!defaultWindow?.getSelection) return state
-
- const onMouseup = () => {
- const text = window.getSelection()?.toString()
- if (text) {
- const rect = getRectFromSelection(window.getSelection())
- state.value = {
- ...state.value,
- ...rect,
- text,
- }
- }
+/**
+ * Reactively track user text selection based on [`Window.getSelection`](https://developer.mozilla.org/en-US/docs/Web/API/Window/getSelection).
+ *
+ * @see https://vueuse.org/useTextSelection
+ */
+export function useTextSelection() {
+ const selection = ref(null)
+ const text = computed(() => selection.value?.toString() ?? '')
+ const ranges = computed(() => selection.value ? getRangesFromSelection(selection.value) : [])
+ const rects = computed(() => ranges.value.map(range => range.getBoundingClientRect()))
+
+ function onSelectionChange() {
+ selection.value = null // trigger computed update
+ selection.value = window.getSelection()
}
- const onMousedown = () => {
- state.value.text && (state.value = initialState)
- window.getSelection()?.removeAllRanges()
- }
- useEventListener(element ?? document, 'mouseup', onMouseup)
- useEventListener(document, 'mousedown', onMousedown)
- return state
+ useEventListener(document, 'selectionchange', onSelectionChange)
+ return {
+ text,
+ rects,
+ ranges,
+ selection,
+ }
}
export type UseTextSelectionReturn = ReturnType