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

@opfs-vfs/file-preview

v0.1.1

Published

Shared React file previews and virtualized text editor.

Readme

Shared file previews

Shared React package used by the website and real devtools. It accepts file contents and has no VFS, worker-client, website, or devtools dependency. The website reuses the basic previews and editor while retaining its specialized Office/HTML views.

import { FilePreview, TextEditor, type PreviewExtension } from '@opfs-vfs/file-preview';
import '@opfs-vfs/file-preview/styles.css';

<FilePreview file={{ path: '/note.md', content: '# Hello' }} />;
<FilePreview file={{ path: '/photo.png', content: '', bytes: imageBytes }} />;

// Render inside React Suspense. The host owns drafts, permissions, and saving.
<TextEditor path="/note.md" value={draft} readOnly={!canWrite} onChange={setDraft} />;

Text previews use a read-only, wrapped reading view without line numbers or an active-line highlight. Syntax highlighting and virtual scrolling remain available.

The text editor uses CodeMirror 6 with virtual scrolling, line numbers, undo/redo, find/replace, and lazy syntax highlighting for recognized languages. .conf/.cfg use properties highlighting and .env variants use shell highlighting. Unknown languages remain plain text. Supported text types include common source, markup, shell, and configuration files, including .conf, .env, .env.local, TOML, INI, JSON, Python, Rust, Go, C/C++, Java, and TypeScript. Common filenames such as Dockerfile, Makefile, README, and .gitignore are also editable. HTML source is displayed as text. SVG is rendered as an image, never inserted into the DOM as markup. The built-in PDF preview renders one bounded canvas page at a time with Previous/Next navigation. PDF.js and its rendering worker load only when a PDF is selected. Raster images use the browser decoder. Unknown formats get a bounded hex preview.

FilePreview enforces a 16 MiB input limit before selecting any renderer. canEdit applies the same bound and explicit text extension/filename allowlists. Byte-backed inputs are read-only. The host must strictly decode UTF-8 before opting into text editing. The editor renders a window of lines, but retains the entire bounded document in memory. The editor also serializes drafts per edit; virtual scrolling is not streaming or an unlimited-file guarantee.

const previews: PreviewExtension[] = [
  {
    id: 'palette',
    matches: (path) => path.endsWith('.palette'),
    load: () => import('./PalettePreview'), // default React component taking { file }
  },
];
<FilePreview file={file} extensions={previews} />;

Caller extensions run before built-ins, first match wins. Only the chosen renderer loads. A renderer gets file data, not a volume or mutation callback. Renderers and match functions run inside a preview error boundary. They are trusted application code, not sandboxed third-party plugins. They must clean up object URLs, effects and workers, and avoid executing file contents. Keep the extension array stable. See the devtools CustomPreview story for a working example.

Reuse sources inspected at frachter-app/opfs-vfs commit 4d88149:

  • apps/bash-console/src/features/previews/lib/detect.ts: filename extension handling, adapted here.
  • plugins/binary-raw.tsx: hex formatting, reused with a 4 KiB cap.
  • plugins/text-code.tsx: CodeMirror mount/disposal pattern. Its large-file fallback was deliberately replaced with CodeMirror virtual scrolling.
  • registry.ts, plugins/image.tsx, plugins/pdf.tsx: lazy renderer selection, object-URL lifecycle and page-based PDF behavior inform this extraction.
  • The website's FilePreview.tsx supplies the existing bounded canvas rendering approach.

The bash-console DOCX, spreadsheet and Excalidraw plugins depend on its UI shell and editor-host capabilities. They are candidates for subsequent extensions, not current exports. The full console workbench, Monaco and terminal integration are not dependencies of this package.

The build emits ES modules, declarations and a separate stylesheet. PDF, Markdown and editor implementations are lazy chunks.