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

@cubster/editor

v0.2.0

Published

A keyboard-driven, markdown-aware text editor component for React, built for Cubster

Readme

@cubster/editor

A keyboard-driven, markdown-aware text editor component for React.

Install

npm install @cubster/editor

Usage

import { useState } from 'react';
import { Editor } from '@cubster/editor';

function App() {
  const [text, setText] = useState('');

  return (
    <Editor
      value={text}
      onChange={setText}
      placeholder="Start writing..."
      className="w-full h-64 p-4 bg-gray-900 text-gray-100 font-mono text-sm resize-none focus:outline-none"
    />
  );
}

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | value | string | required | Current text value | | onChange | (value: string) => void | required | Called when text changes | | tabSize | number | 2 | Spaces per indent level | | placeholder | string | 'Start writing...' | Placeholder text | | className | string | '' | CSS class names | | wrapperClassName | string | '' | CSS class name(s) applied to the wrapper <div> | | onContextChange | (label: string \| null) => void | — | Called whenever the markdown context at the cursor changes (e.g. 'Heading 1', 'Blockquote', or null). Fires once on mount and is deduped — it isn't called again while the label stays the same. |

All standard <textarea> HTML attributes are also accepted.

Keyboard Shortcuts

The editor wraps its <textarea> in a <div data-cubster-editor>. Formatting shortcuts introduced in v0.2.0 are keyed off the physical key (e.code), not the character it produces — Option/Shift+digit combos yield symbols and punctuation on Mac keyboards (via e.key), so binding on e.code keeps them working regardless of layout.

| Shortcut | Action | |----------|--------| | Cmd/Ctrl + B | Toggle bold (**text**) | | Cmd/Ctrl + I | Toggle italic (_text_) | | Cmd/Ctrl + Shift + X | Toggle strikethrough (~~text~~) | | Cmd/Ctrl + Alt + E | Toggle inline code (`text`) | | Cmd/Ctrl + Alt + Shift + E | Wrap selection in a fenced code block | | Cmd/Ctrl + Alt + 16 | Toggle heading level 1–6 | | Cmd/Ctrl + Alt + 0 | Clear heading/blockquote/list formatting back to a plain paragraph | | Cmd/Ctrl + Alt + Q | Toggle blockquote (> text) | | Cmd/Ctrl + Shift + 7 | Toggle an ordered (numbered) list | | Cmd/Ctrl + Shift + 8 | Toggle an unordered (bulleted) list | | Cmd/Ctrl + Shift + 9 | Toggle a task list (- [ ] text) | | Cmd/Ctrl + K (no selection) | Insert []() with cursor inside [] | | Cmd/Ctrl + K (with selection) | Wrap selection as [text]() with cursor inside () | | Tab | Indent | | Shift + Tab | Unindent | | Enter on list/task-list item | Continue list | | Enter on empty list/task-list item | End list | | Cmd/Ctrl + Z | Undo (native) | | Cmd/Ctrl + Shift + Z | Redo (native) |

Heading/blockquote/list toggles share one rule: they turn OFF only if every non-blank selected line already has the exact marker, otherwise they turn ON and replace any conflicting block marker (headings, blockquotes, and lists are mutually exclusive at the start of a line). Ordered lists renumber from 1. when turned on; task lists always insert an unchecked - [ ] (upgrading a plain - bullet in place, never marking it checked). Blank lines within a selection are left untouched.

The fenced-code-block shortcut escalates the fence length so a selection containing its own backtick runs (e.g. a ``` line) is wrapped safely — the fence is always longer than the longest backtick run in the content, so the inner run can't close the block early. Info-string and indented-fence edge cases are not specially handled.

Shortcuts data

The complete shortcut set (including the legacy bold/italic/link/undo/redo/indent bindings above) is available as data, for building your own help menu or command palette:

import { shortcuts } from '@cubster/editor';

shortcuts.forEach((s) => {
  console.log(s.id, s.label, s.keys.mac, s.keys.other);
});

Paste URL to Link

When text is selected and you paste a valid URL (e.g. https://, ftp://, mailto:), the editor automatically formats it as a Markdown link: [selected text](url). If the pasted content is not a URL, normal paste behavior applies.

Styling

The editor is headless by default. An optional stylesheet gives the wrapped <textarea> a reasonable, brand-neutral default appearance:

import '@cubster/editor/styles.css';

It defines --cub-editor-* custom properties scoped under [data-cubster-editor] — override any of them on your own selector to re-theme without touching the stylesheet:

| Variable | Controls | |----------|----------| | --cub-editor-font-family | Font stack | | --cub-editor-font-size | Font size | | --cub-editor-line-height | Line height | | --cub-editor-color | Text color | | --cub-editor-background | Background color | | --cub-editor-caret-color | Caret color | | --cub-editor-placeholder-color | Placeholder text color | | --cub-editor-selection-background | Selected-text background | | --cub-editor-selection-color | Selected-text color | | --cub-editor-border-color | Border color | | --cub-editor-border-width | Border width | | --cub-editor-border-radius | Border radius | | --cub-editor-padding | Textarea padding | | --cub-editor-focus-ring-color | Focus outline color |

License

MIT