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

@taylordb/typst

v0.3.0

Published

Typst for TaylorDB apps: a browser-side Typst compiler (typst.ts / WASM) and a React editor with a live page preview, a collapsible CodeMirror source drawer, and file-backed saving.

Readme

@taylordb/typst

Typst for TaylorDB apps: a browser-side compiler and a React editor with a live page preview and a TinaCMS-style source drawer. The whole edit → compile → preview loop runs client-side, on typst.ts (the Typst compiler and renderer compiled to WebAssembly).

import { TypstEditor } from '@taylordb/typst'
import '@taylordb/typst/styles.css'

<TypstEditor
  defaultSource={"= Hello\nWorld"}
  inputs={{ name: 'TaylorDB' }} // exposed as sys.inputs in the document
  editorSide="right"            // drawer side: 'left' | 'right' (default 'right')
  drawerWidth={380}             // px (default 380)
  defaultOpen                   // drawer starts open (default false)
  onSave={saveToServer}         // adds the Save button and ⌘S
  pdfFilename="report.pdf"
/>

Four entry points, split so each side only carries what it needs:

| Import | Contains | Pulls in | | --- | --- | --- | | @taylordb/typst | compiler + React editor | typst.ts, React | | @taylordb/typst/compiler | compiler only | typst.ts | | @taylordb/typst/node | .typ file store | node:fs | | @taylordb/typst/styles.css | editor stylesheet | — |

The root and /compiler share one internal chunk, so importing both costs nothing extra.

Editor

  • TypstEditor — preview filling the surface plus the source drawer: header with compile status, outline / problems panels, an overflow menu, and a close button; when closed, a TinaCMS-style vertical "Edit" tab (same --taylor-cms-* theme variables, hover slide-out, and periodic nudge as @taylordb/cms) reopens it. The drawer overlays the preview, so it starts closed and never opens by itself. The open/closed choice persists in localStorage (taylordb.typst.drawerOpen, same protocol as Tina's tina.embedSidebarOpen); defaultOpen applies only before the user has toggled it. ?drawer=collapse on the page URL forces the drawer closed for that load (for screenshots), and ?drawer=expand seeds it open while the user has not toggled it — the same param @taylordb/cms honours. The CodeMirror editor (+ Typst grammar, ~130 KB gzip) is code-split and lazy-loaded — prefetched during idle time so opening feels instant, with a loading state in the drawer if it's still arriving. Typst syntax highlighting comes from codemirror-lang-typst's wasm-free Lezer parser. Controlled (source + onChange) or uncontrolled (defaultSource).
  • Saving — pass onSave(source) and the drawer grows a Save button bound to ⌘S/Ctrl+S. It tracks unsaved changes (Save → Saving… → Saved) and shows Retry if the promise rejects. Pair it with /node to persist the document as a .typ file.
  • Save events — each successful save dispatches a taylor-cms:save CustomEvent on window with detail: { collection, relativePath, savedAt } — the same signal @taylordb/cms sends after a Tina save, which the TaylorDB preview platform commits on. Identify the document with saveEvent={{ detail: { collection, relativePath } }}, add postToParent for a host that frames the app instead of injecting into it, or pass saveEvent={false} to stay silent. announceSave() is exported if you need to fire it yourself.
  • External changes — pass externalSource when the app watches the file and re-reads it. With no unsaved edits the editor adopts the new text silently; with unsaved edits it shows a Keep mine / Load changes notice rather than clobbering them.
  • Unsaved-changes guard — while dirty, ⌘R/Ctrl+R is intercepted and the editor shows its own Keep editing / Discard & reload / Save & reload dialog (confirmReload={false} opts out). A reload from the browser's toolbar or a tab close cannot be intercepted by any page, so those fall back to the browser's native beforeunload prompt, whose wording and styling are fixed by the browser.
  • Editor panels and commands — the drawer header toggles an Outline (headings read off the Typst syntax tree, so = inside raw blocks or code is ignored; selecting one moves the cursor) and a Problems panel (compiler diagnostics with their hints, plus a count badge). The ⋯ menu carries undo/redo, find & replace, select all, toggle line comment, fold / unfold all, and PDF export. The editor itself has autocompletion for Typst built-ins, symbols, local bindings and labels, heading/block folding, and CodeMirror's search panel on ⌘F.
  • TypstPreview — the rendered page cards + diagnostics overlay, with an optional floating toolbar (showToolbar) — one pill, its sections split by hairline dividers: jump-to-cursor (when getJumpTarget is provided), zoom out / percent / zoom in (clicking the percent resets to fit-width), a Chrome-PDF-style page field — an editable current-page box next to / 7, tracking the page on screen, with ↑/↓ to step — for multi-page documents, and download + print. onDownload adds the download button and drives its busy state (downloading forces it); print is on by default (showPrint={false} to drop it) and prints the already-rendered vector pages without recompiling, titled by printTitle. Set showDiagnostics={false} when the host reports errors elsewhere. The compiler's own stylesheet — which contains global rules such as svg { fill: none } — is scoped to the page cards so it can't leak into the surrounding app.
  • useTypstCompiler — debounced compile hook returning { svg, diagnostics, compiling }; keeps the last good page during errors.

Compiler

  • compileToSvg({ source, inputs }) — compile Typst source to an SVG string
  • compileToPdf({ source, inputs }) — compile to a PDF Uint8Array
  • compileToVector({ source, inputs }) — typst.ts's compact vector artifact
  • downloadPdf(pdf, filename) — trigger a browser download
  • initTypst(options) — optional; configure where the wasm modules load from

inputs is exposed to the document as sys.inputs — the hook for injecting TaylorDB record data into templates.

files mounts a virtual filesystem for the document, which is how images and data reach a compiler that has no disk and no network:

compileToSvg({
  source: '#image("logo.png")\n#json("data.json").title',
  files: {
    'logo.png': logoBytes,          // Uint8Array → binary file
    'data.json': '{"title": "Hi"}', // string → source file
  },
})

The document compiles at /main.typ, so relative references resolve against the root: #image("logo.png") needs the key logo.png. Entries persist on the shared compiler between calls, and only changed ones are re-sent — a keystroke-rate recompile does not re-upload every image.

Compile failures reject with TypstCompileError, carrying the compiler's diagnostics as { severity, message, hints? } entries. typst.ts surfaces them as one Rust-Debug-formatted string, so they are parsed back into individual diagnostics here; the compiler reports opaque span ids rather than line numbers, so no source range comes with them.

Import these from @taylordb/typst/compiler when you don't want the editor. That entry has no React dependency at all — useful in a web worker, a render-only page, or any build where React shouldn't be a peer requirement:

import { compileToPdf, initTypst } from '@taylordb/typst/compiler'

The root entry re-exports the same functions, so @taylordb/typst alone is fine when you're already rendering the editor.

Document files (@taylordb/typst/node)

A Node-only entry point for keeping documents as .typ files on disk — the server half of an editor whose Save button writes back to the repo. Import it from server code only; it pulls in node:fs.

import { createTypstFileStore } from '@taylordb/typst/node'

const documents = createTypstFileStore({ dir: 'content/documents' })

await documents.readOrCreate('main.typ', '= Hello\n') // source, creating it if absent
await documents.write('main.typ', source)             // write-then-rename, so a crash can't truncate
await documents.list()                                // ['main.typ', …]
await documents.listAssets()                          // ['logo.png', …]
await documents.readBytes('logo.png')                 // Uint8Array | null

// Push external edits (an agent, a script) back to the browser.
const stop = documents.watch((name) => notifyClients(name))

Names are restricted to letters, digits, dots, dashes and underscores, so a document name can never escape the store's directory.

Wasm loading

By default the two wasm modules (compiler ~27 MB, renderer ~1 MB) load lazily from the jsDelivr CDN, pinned to the bundled typst.ts version. To self-host them in a Vite app:

import compilerWasm from '@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm?url'
import rendererWasm from '@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm?url'
import { initTypst } from '@taylordb/typst'

initTypst({ compilerWasm, rendererWasm })

Call initTypst before the first compile; the first compile call initializes with the CDN defaults otherwise. Font assets are fetched remotely by typst.ts on first compile, so the browser needs network access unless you preload fonts.

Playground

See apps/typst/playground for a running example (pnpm --filter @taylordb/typst-playground dev, port 3002). It edits content/main.typ on disk: a small Vite middleware in its vite.config.ts serves GET/POST /api/document through @taylordb/typst/node, so Save exercises the same load/save path a real app uses.