npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@type-editor/selection-util

v0.0.3

Published

Selection utility functions for the Type Editor.

Downloads

308

Readme

@type-editor/selection-util

This module was part of the ProseMirror view module.

Selection utility functions for the Type Editor.

This module provides utility functions for handling the synchronization and conversion between DOM selections and ProseMirror selections. It handles browser-specific quirks, Shadow DOM support, and various edge cases that arise when working with rich text selections.

Installation

npm install @type-editor/selection-util

API Reference

Selection Conversion

selectionFromDOM(view: PmEditorView, origin?: string | null): PmSelection | null

Converts a DOM selection to a ProseMirror Selection.

This function reads the current browser selection and translates it into a ProseMirror selection that can be used with the editor state. It handles various edge cases including collapsed selections, node selections, and multi-range selections.

import { selectionFromDOM } from '@type-editor/selection-util';

// Convert the current browser selection to a ProseMirror selection
const selection = selectionFromDOM(view);
if (selection) {
    const tr = view.state.tr.setSelection(selection);
    view.dispatch(tr);
}

// Pass origin for bias calculation (e.g., from pointer events)
const pointerSelection = selectionFromDOM(view, 'pointer');

selectionToDOM(view: PmEditorView, force?: boolean): void

Synchronizes the ProseMirror selection to the DOM.

This function updates the browser's selection to match the current ProseMirror selection state. It handles various edge cases including:

  • Node selections
  • Delayed drag selections in Chrome
  • Broken selection behavior in Safari/older Chrome
  • Cursor wrappers for special cases
  • Selection visibility
import { selectionToDOM } from '@type-editor/selection-util';

// Sync the current ProseMirror selection to the DOM
selectionToDOM(view);

// Force sync even if it appears unnecessary
selectionToDOM(view, true);

Selection Creation

selectionBetween(view: PmEditorView, $anchor: ResolvedPos, $head: ResolvedPos, bias?: number): PmSelection

Creates a selection between two resolved positions.

This function first checks if any plugins provide a custom createSelectionBetween method. If not, it falls back to creating a standard text selection. This allows plugins to implement custom selection types (e.g., table cell selections).

import { selectionBetween } from '@type-editor/selection-util';

const doc = view.state.doc;
const $anchor = doc.resolve(10);
const $head = doc.resolve(20);

// Create a selection between two positions
const selection = selectionBetween(view, $anchor, $head);

// With forward bias
const forwardSelection = selectionBetween(view, $anchor, $head, 1);

// With backward bias
const backwardSelection = selectionBetween(view, $anchor, $head, -1);

Selection State Checks

hasFocusAndSelection(view: PmEditorView): boolean

Checks if the editor both has focus and contains a selection.

For editable views, this requires the view to have focus. For all views, this checks if a valid selection exists within the editor.

import { hasFocusAndSelection } from '@type-editor/selection-util';

if (hasFocusAndSelection(view)) {
    // Safe to perform selection-dependent operations
    console.log('Editor has focus and selection');
}

selectionCollapsed(domSel: DOMSelectionRange): boolean

Checks if a DOM selection is collapsed (has no range).

This function works around a Chrome issue where isCollapsed inappropriately returns true in Shadow DOM. It uses position comparison to properly detect collapsed selections.

import { selectionCollapsed } from '@type-editor/selection-util';

const domSelection = view.domSelectionRange();
if (selectionCollapsed(domSelection)) {
    console.log('Selection is a caret (collapsed)');
} else {
    console.log('Selection has a range');
}

anchorInRightPlace(view: PmEditorView): boolean

Checks if the DOM selection's anchor is at the expected position.

This compares the ProseMirror selection's anchor position with the actual DOM selection's anchor position to verify they are equivalent. This is useful for detecting if the DOM selection has drifted from the expected state.

import { anchorInRightPlace } from '@type-editor/selection-util';

if (!anchorInRightPlace(view)) {
    // DOM selection has drifted, may need to resync
    selectionToDOM(view, true);
}

Caret Position

caretFromPoint(doc: Document, x: number, y: number): { node: Node, offset: number } | undefined

Gets the caret position from a point in the document.

This function tries browser-specific methods to determine the DOM position (node and offset) at the given screen coordinates. It handles both Firefox's caretPositionFromPoint and Chrome/Safari's caretRangeFromPoint.

The offset is clipped to the node size to handle edge cases where browsers might return invalid offsets (e.g., text offsets into <input> nodes).

import { caretFromPoint } from '@type-editor/selection-util';

document.addEventListener('click', (event) => {
    const position = caretFromPoint(document, event.clientX, event.clientY);
    if (position) {
        console.log('Clicked at node:', position.node);
        console.log('Offset:', position.offset);
    }
});

Node Selection Sync

syncNodeSelection(view: PmEditorView, sel: PmSelection): void

Synchronizes node selection state between ProseMirror and the DOM.

When a node is selected (as opposed to text selection), this function ensures that the appropriate view descriptor is marked as selected, and any previously selected node is deselected. This allows node views to apply custom styling or behavior when selected.

import { syncNodeSelection } from '@type-editor/selection-util';

// Typically called internally by selectionToDOM, but can be used directly
syncNodeSelection(view, view.state.selection);

Browser Compatibility

This module handles several browser-specific quirks:

  • Chrome: Handles delayed drag selection sync to prevent flickering
  • Chrome Shadow DOM: Works around isCollapsed returning incorrect values in Shadow DOM
  • Safari/older Chrome: Works around issues with selections between non-editable block nodes
  • Firefox: Uses caretPositionFromPoint API for caret position detection
  • All browsers: Falls back to caretRangeFromPoint when Firefox API is unavailable

License

MIT