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

@quillmark/editor

v0.1.0

Published

Lexical-based rich-text editor for QuillMark documents — Svelte components, headless core, and a self-contained custom element.

Readme

@quillmark/editor

Lexical-based rich-text editor for QuillMark documents. Ships as a single npm package with three entry points:

  • @quillmark/editor — Svelte 5 components (<VisualEditor>, <QuillmarkPreview>, useEditor)
  • @quillmark/editor/element — self-contained <quillmark-editor> and <quillmark-preview> custom elements
  • @quillmark/editor/core — headless TypeScript (no DOM, no framework). For server / agent code.

This package replaces the ProseMirror-based editor in tonguetoquill-web with a smaller, more declarative Lexical core. See references/PROGRAM.md for the full design rationale.

Installation

npm install @quillmark/editor @quillmark/wasm

@quillmark/wasm is a peer dependency, minimum version 0.68.0 — the preview pipeline relies on Quill.open(doc).paint(ctx, page, { layoutScale, densityScale }) → PaintResult from that release, where the painter owns canvas.width/canvas.height and the consumer owns canvas.style.*. @quillmark/editor does not bundle, fetch, or own the WASM lifecycle — the host injects it via the QuillmarkHost interface (a small superset of tonguetoquill-web's quillmarkService).

Architecture in one sentence

createEditorState({ quillmark }) is the canonical primitive: a reactive handle around @quillmark/wasm's Document. Both <VisualEditor> and <QuillmarkPreview> subscribe to the same handle — no markdown round-trip between them, no double-parse. Markdown stays as the persistence format at the edges (save/load, custom-element markdown attribute), not the inter-component contract.

Svelte usage

<script lang="ts">
  import { VisualEditor, QuillmarkPreview, createEditorState } from '@quillmark/editor';
  import '@quillmark/editor/styles.css';
  import { quillmarkService } from '$lib/services/quillmark';

  const state = createEditorState({ quillmark: quillmarkService });
  await state.load(initialMarkdown);
</script>

<div class="editor-grid">
  <VisualEditor {state} theme="auto" features={{ tables: true, cards: true }} />
  <QuillmarkPreview {state} />
</div>

The preview is Canvas-based: the package paints each page directly into a <canvas> via quill.open(doc).paint(...). There is no render injection prop — hosts wanting a different strategy should compose their own UI atop EditorState.

Optional paint={...} prop tunes scale, page subset, and gap:

<QuillmarkPreview
  {state}
  paint={{ scale: 2, gapPx: 24, pages: [0, 1] }}
/>

The package ships no layout primitive. The host wires whatever split-pane / tabs / modal layout it needs.

Custom-element usage

<script type="module" src="/dist/element/index.js"></script>
<link rel="stylesheet" href="/dist/styles.css" />

<quillmark-editor></quillmark-editor>
<quillmark-preview></quillmark-preview>

<script type="module">
  import { quillmarkService } from './my-quillmark-host.js';
  import { createEditorState } from '/dist/element/index.js';

  await quillmarkService.initialize();
  const state = createEditorState({ quillmark: quillmarkService });
  await state.load(initialMarkdown);

  const editorEl = document.querySelector('quillmark-editor');
  const previewEl = document.querySelector('quillmark-preview');
  editorEl.state = state;
  previewEl.state = state;
  // No `render` prop — preview paints via `quill.open(doc).paint(...)`.

  editorEl.addEventListener('quillmark-change', (e) => save(e.detail.markdown));
</script>

<quillmark-editor> also accepts a markdown attribute as a fallback when state is not assigned — useful for editor-only HTML hosts that don't need the preview side.

Headless / server usage

import { createEditorState } from '@quillmark/editor/core';
import { quillmarkService } from './my-quillmark-host';

const state = createEditorState({ quillmark: quillmarkService });
await state.load(markdown);
state.setMainBody('Hello, world.');
state.addCard(0, 'note_card', { priority: 5 });
const updated = state.toMarkdown();

Plain pub-sub reactivity:

const off = state.subscribe((version) => {
  console.log('document changed', version);
});

The core entry has no Svelte runtime dependency. It runs in Node, in CI, and in agent contexts.

QuillmarkHost contract

The host injects an object satisfying:

interface QuillmarkHost {
  isReady(): boolean;
  readonly Document: typeof import('@quillmark/wasm').Document;
  getQuill(ref: string): Quill;
  ensureQuillResolved(ref: string): Promise<void>;
}

tonguetoquill-web's quillmarkService already satisfies this shape. Other hosts can wrap @quillmark/wasm directly.

V1 scope & known gaps

V1 covers the architectural backbone end-to-end:

  • ✅ Three working entry points with conditional exports.
  • ✅ Canonical EditorState primitive (load → mutate → serialize).
  • ✅ Lexical body editor with markdown round-trip; QuillMark __text__-as-underline transformer.
  • ✅ Schema-driven metadata form (text / number / boolean / enum / date / array-of-string).
  • ✅ Card list with add / move / delete / reorder.
  • <VisualEditor> and <QuillmarkPreview> Svelte 5 components.
  • ✅ Canvas-based preview via @quillmark/wasm ≥ 0.68's Quill.open(doc).paint(...) with split layoutScale / densityScale knobs — no render injection.
  • <quillmark-editor> and <quillmark-preview> custom elements with state property + markdown attribute fallback.
  • ✅ Schema walker / validator / date-path collector callable headlessly.
  • ✅ Core unit tests (no Svelte runtime).

Deliberately deferred (see references/PROGRAM.md):

  • ❌ Full table parity (Obsidian-style edge controls, row drag) — @lexical/table defaults wired up; insert / delete row / col, merge / unmerge work via Lexical's built-in commands but we don't ship the hover affordances yet (PROGRAM.md O4).
  • ❌ Full list-commands.ts 700-line edge-case audit (PROGRAM.md O5) — Lexical defaults only.
  • ❌ React adapter (PROGRAM.md §6.1, deferred indefinitely; React hosts use the custom element).
  • ❌ Real-time collaboration / CRDTs (PROGRAM.md §2 non-goal).
  • ❌ MS Teams / MCP Apps embedded mode (PROGRAM.md §4.3, V1 is standalone-only).
  • ❌ Editor mode switch (markdown source view) and resizable split panel — both are host chrome (PROGRAM.md §2 non-goals).

Canvas preview trade-offs

Preview is Canvas-only. The package paints directly via quill.open(doc).paint(ctx, page, { layoutScale, densityScale }) → PaintResult — faster and cheaper than the prior SVG path on multi-page documents, but with two intentional consequences hosts should know about:

  • No text selection in the preview. Canvas is a bitmap. If users need select-to-copy on the rendered page, they should look at the source markdown side instead.
  • No screen-reader coverage of preview content. Assistive tech sees nothing inside the canvas. The editor side is fully accessible; the preview is decorative.

Browser zoom (Ctrl-+/-) and pinch-zoom are handled automatically: <QuillmarkPreview> subscribes to matchMedia('(resolution)') and visualViewport.resize and triggers a debounced repaint when DPR or pinch scale changes. Hosts can still override paint.densityScale for in-app zoom controls; layoutScale independently controls the CSS display-box size so layout and rasterization density don't have to move together. Non-Svelte hosts driving paintPagesIntoElement directly can call the same watchZoom(callback) helper from @quillmark/editor/core.

If these are blockers for your application, do not use <QuillmarkPreview> — compose your own preview UI atop EditorState directly.

Markdown round-trip caveat

QuillMark uses __text__ for underline (Word convention), not bold — the spike's UNDERLINE_UNDERSCORE transformer is wired in by default. Documents that previously stored bold via underscores will be re-serialized as bold via asterisks; this is a visible source-text diff but not a semantic one. See PROGRAM.md §7.

WASM prerequisite

Per PROGRAM.md §7: a 3rd-party SaaS or vanilla HTML page wanting to drop in <quillmark-editor> must npm install @quillmark/wasm, write a host service satisfying QuillmarkHost, and wire it before the element works. That's three setup steps, not one. The alternative — bundling WASM — violates the §2 non-goal "Quill / WASM fetching strategy". A future @quillmark/editor/standalone sub-export with a bundled WASM bootstrap could close the gap; not in V1.

Versioning

Independent SemVer. Pin @quillmark/wasm minimum version in your host package; bump deliberately. (PROGRAM.md O8.)

Development

npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest
npm run build       # builds core, svelte, and element bundles into dist/
npm run size        # gzip + raw-size guard on dist/element/index.js

License

MIT