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

ink-prompt

v0.2.5

Published

A React Ink component for prompts

Readme

ink-prompt

A React Ink component library for creating interactive CLI prompts. Provides MultilineInput for collecting multi-line text in terminal applications.

Installation

npm install ink-prompt

Usage

import React from 'react';
import { render, Box, Text } from 'ink';
import { MultilineInput } from 'ink-prompt';

const App = () => {
  return (
    <Box flexDirection="column">
      <Text>Describe your change (press Enter to submit):</Text>
      <MultilineInput
        onSubmit={(value) => console.log(value)}
      />
    </Box>
  );
};

render(<App />);

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | value | string | | External control of the text value (controlled mode) | | onChange | (value: string) => void | | Called when text content changes | | onSubmit | (value: string, images?: ImageRef[]) => void | | Called when Enter is pressed (without trailing \) | | placeholder | string | | Placeholder text shown when empty and cursor is hidden | | showCursor | boolean | true | Whether to display the cursor | | width | number | terminal width | Width for word wrapping (auto-resizes with terminal) | | isActive | boolean | true | Whether the input accepts keyboard events | | onCursorChange | (offset: number) => void | | Called when cursor position changes | | cursorOverride | number | | Force cursor to a specific offset | | onBoundaryArrow | (direction: 'up' \| 'down' \| 'left' \| 'right') => void | | Called when arrow key reaches a boundary | | undoDebounceMs | number | 200 | Milliseconds of inactivity to commit undo batch (0 = disable) | | pasteThreshold | number | | Max paste length before text is replaced by a placeholder | | formatPastePlaceholder | (displayNumber: number) => string | | Custom placeholder display format (1-based) | | enableImagePaste | boolean | false | Enables image-aware Ctrl+V handling | | images | ImageRef[] | | Controlled image state for pasted images | | onImagesChange | (images: ImageRef[]) => void | | Called when images change | | onPasteError | (reason: PasteErrorReason) => void | | Called when paste fails | | maxImageSizeBytes | number | 10485760 | Maximum image size in bytes (default 10 MiB) | | maxImageCount | number | 10 | Maximum number of pasted images | | acceptedMimeTypes | string[] | | Restricts accepted image MIME types |

Keyboard Controls

MultilineInput supports typical editing controls:

  • Arrow keys for navigation
  • Shift+Enter, Ctrl+J, or typing \ before Enter to add a newline (Shift+Enter requires a terminal that distinguishes it — most emit ESC + CR or the kitty CSI 13;2u sequence)
  • Ctrl+Z / Ctrl+Y for undo/redo
  • Ctrl+A / Ctrl+E for jump to line start/end
  • Home / End keys for line start/end
  • Ctrl+V to paste text or images (when enableImagePaste is enabled)
  • Enter submits the current buffer
  • Delete for forward delete

Paste Placeholders

When pasting large amounts of text, you can use pasteThreshold to automatically replace the pasted content with a compact placeholder for cleaner display.

<MultilineInput
  onSubmit={(value) => console.log(value)}
  pasteThreshold={200}            // Text >200 chars becomes a placeholder
  formatPastePlaceholder={(n) => `[Pasted block #${n}]`}  // Optional formatter
/>

How it works:

  • Pasted text exceeding pasteThreshold is replaced with a placeholder (default: [Paste text #N], customizable via formatPastePlaceholder)
  • The full original text is preserved — onChange / onSubmit return the unmodified content
  • Placeholders are atomic: backspace/delete removes the entire placeholder in one action
  • Arrow keys skip over placeholders (cursor cannot land inside one)
  • Undo/redo correctly tracks placeholder state
  • Counter resets per component instance

Image Paste

Image paste is opt-in through enableImagePaste. When enabled, Ctrl+V reads the system clipboard. Text is inserted as usual; supported images are inserted into the text buffer as placeholders such as [Pasted Image #1] and returned separately through onSubmit or onImagesChange.

import React, {useState} from 'react';
import {render, Box, Text} from 'ink';
import {MultilineInput, type ImageRef, type PasteErrorReason} from 'ink-prompt';

const App = () => {
  const [images, setImages] = useState<ImageRef[]>([]);

  return (
    <Box flexDirection="column">
      <Text>Prompt:</Text>
      <MultilineInput
        enableImagePaste
        maxImageCount={5}
        maxImageSizeBytes={5 * 1024 * 1024}
        acceptedMimeTypes={['image/png', 'image/jpeg', 'image/webp', 'image/gif']}
        images={images}
        onImagesChange={setImages}
        onPasteError={(reason: PasteErrorReason) => {
          console.error(`Paste failed: ${reason}`);
        }}
        onSubmit={(value, submittedImages) => {
          console.log(value);
          console.log(submittedImages);
        }}
        width={80}
      />
    </Box>
  );
};

render(<App />);

Supported image types are detected from image bytes: PNG, JPEG, WebP, and GIF. Clipboard access is platform-specific:

  • macOS: osascript
  • Linux X11: xclip
  • Linux Wayland: wl-paste
  • Windows: PowerShell and System.Windows.Forms.Clipboard

Related props:

  • enableImagePaste?: boolean - enables image-aware Ctrl+V handling.
  • images?: ImageRef[] and onImagesChange?: (images: ImageRef[]) => void - controlled image state for pasted images.
  • onSubmit?: (value: string, images?: ImageRef[]) => void - receives the text buffer and current images.
  • onPasteError?: (reason: PasteErrorReason) => void - receives paste and validation failures.
  • maxImageSizeBytes?: number - defaults to 10 MiB.
  • maxImageCount?: number - defaults to 10.
  • acceptedMimeTypes?: string[] - restricts accepted image MIME types.

Development

# Install dependencies
npm install

# Build the project
npm run build

# Watch for changes
npm run dev

# Type check
npm run type-check

# Run tests
npm test
npm run test:watch
npm run test:ui

License

MIT