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

@openeditor/ui

v0.0.33

Published

Optional styled UI components for OpenEditor.

Readme

@openeditor/ui

Optional styled UI components for OpenEditor.

Public Surface

  • OpenEditor for a composed editor surface
  • OpenEditorSlashMenu for the default slash menu UI
  • OpenEditorSelectionBubble for inline formatting UI
  • OpenEditorTableMenu for selection-aware row, column, header, cell, and table actions
  • OpenEditorButton, OpenEditorToggle, OpenEditorToggleGroup, and OpenEditorInput as Base UI-backed app primitives
  • OpenEditorContent and useOpenEditorController re-exported from @openeditor/react

The UI package owns the default CSS and interactive primitives. User-facing controls are built on Base UI so focus management, keyboard behavior, dismiss behavior, and overlay positioning share one foundation.

Editor interaction contract

OpenEditor keeps keyboard ownership in the editable surface unless the user explicitly enters another control:

  • Selecting text shows the formatting toolbar without moving focus. Delete, Backspace, typing, arrow keys, and formatting/history shortcuts therefore keep their normal editing meaning. The toolbar follows its document selection in the editor's actual scroll container and hides once that selection is clipped. Pointer presses on toolbar actions preserve the document selection. Alt+F10 moves focus into the toolbar, its arrow keys move between controls, and Escape returns focus to the document.
  • Typing / opens one flat, filtered command list. Focus stays in the document; ArrowUp/ArrowDown, Home/End, and PageUp/PageDown change the active command, Enter runs it, and Escape dismisses the current slash session. Its anchor is resolved live from the document position while scrolling and is hidden when clipped. A dismissed session does not reopen merely because more query characters are typed.
  • The block handle menu is an explicit focus-owning menu. Enter or Space opens it, menu arrow keys navigate it, Enter runs an action, and Escape or an outside press closes it. Closing, dragging, and running an action all pass through the same unlock transition, so hover targeting cannot remain frozen.
  • Selecting a table cell shows a toolbar anchored to the table. Row and column menus preserve the cell selection while insert/delete commands run, and header, merge/split, and whole-table actions use the same transactional table controller as custom host UI.

Formatting and history shortcuts come from Tiptap's registered mark and history extensions. OpenEditor keeps focus in the editor so those extension-owned bindings receive Cmd on macOS and Ctrl elsewhere without a competing global shortcut layer.

Theming

Use the typed theme contract instead of targeting OpenEditor implementation classes or defining global custom properties. The provider scopes tokens to editor content and automatically forwards them to portaled menus and dialogs. surfaceRaised is required and controls the background of menus, popovers, and dialogs.

import {
  OpenEditor,
  OpenEditorThemeProvider,
  type OpenEditorTheme,
} from "@openeditor/ui";

const theme = {
  surface: "var(--background)",
  surfaceRaised: "var(--popover)",
  surfaceMuted: "var(--muted)",
  blockSurface: "var(--card)",
  text: "var(--foreground)",
  structuralLine: "var(--border)",
  accentStrong: "var(--primary)",
  bodyFontSize: "1rem",
  bodyLineHeight: "1.65",
  headingFont: "var(--font-display)",
  headingWeight: "650",
  heading1Size: "2.25rem",
  heading2Size: "1.75rem",
  radiusLarge: "1rem",
} satisfies OpenEditorTheme;

export function Editor() {
  return <OpenEditor theme={theme} />;
}

export function HeadlessComposition() {
  return (
    <OpenEditorThemeProvider theme={theme}>
      {/* OpenEditorContent, OpenEditorSelectionBubble, OpenEditorTableMenu, OpenEditorSlashMenu */}
    </OpenEditorThemeProvider>
  );
}

createOpenEditorThemeStyle is available for non-React integrations that need the same canonical token-to-CSS mapping.

Semantic typography tokens cover body size and line height, heading font and line height, heading weight, and independent sizes for heading levels one through six. These tokens apply equally to editable content, the React viewer, and safe HTML mounted under .oe-viewer; print- or product-specific page geometry remains the host's responsibility.

Quick Start

import "@openeditor/ui/styles.css";
import { OpenEditor } from "@openeditor/ui";

export function Example() {
  return <OpenEditor />;
}