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

@quario/editor

v0.9.1

Published

Tiny, embeddable banded document designer for quario. A custom element that edits the report document itself.

Readme

@quario/editor

The embeddable banded document designer for quario. <quario-editor> shows a report rendered on your sample data and lets the author rearrange it structurally. Drag items between bands with a gutter grip, reorder table columns on the table, restructure groups from a docked list, and edit the selected node's values, styles, templates and expressions in a properties panel. Every edit recompiles and re-lays out through the real engine and the real page layout, the one the PDF target writes. What the author sees is therefore the report as it will page, not an approximation of it.

There is no infinite canvas and no free positioning, because the schema has no concept of either: bands stack, items stack, tables have columns. Every drag is structural and every drop snaps to a slot the schema actually has. The editor refuses drops that would break at render time, such as moving an item that reads the current row (@) out of the detail band.

Install

npm install @quario/editor quario

ESM-only, Node 22+ tooling, evergreen browsers. Runtime dependencies: lit, @lit/task, tinykeys, and @quario/layout, the paged layout the design surface paints. The engine is not a dependency — your app passes its own configured instance in, so your bundle carries one copy of it.

Quick start

import { quario } from "quario";
import "@quario/editor/register";

const editor = document.createElement("quario-editor");
editor.instance = quario({ license: "quario_..." });
editor.schema = starterSchema; // the document the author begins with
editor.data = sampleData; // what the design surface is laid out on
editor.page = { size: "A4", margin: 54 }; // the same values you pass pdf({ page })
editor.addEventListener("change", ({ detail }) => {
  save(detail.schema); // deep-frozen; assigning it back to `schema` is a no-op
  saveButton.disabled = detail.problems.length > 0;
});
editor.addEventListener("error", () => {
  // Nothing could be rendered, so the button above may be answering for an
  // older document — it is right again on the next `change`.
  saveButton.disabled = true;
});
document.body.append(editor);

Every rectangle on the surface maps back to the schema node it draws, which is how clicking the rendered report selects the node behind it — no target to configure for it.

The element

The editor is uncontrolled: schema seeds it, and the editor owns the document from there. Only assigning a new schema object resets the document, history and selection. Assigning back the exact object the last change delivered does nothing, so a naive persist-and-restore loop cannot wipe the author's undo history. Assigning a new instance, functions, data, page or fonts recompiles and re-lays out while leaving the author's work untouched — a license key arriving mid-session is one property write, not a catastrophe.

| Property | What it is | | ------------- | ------------------------------------------------------------------------------- | | schema | The starter report document. A new object identity loads and resets. | | instance | Your configured quario() instance. The license rides on it. | | functions | Functions callable from the document's expressions. | | data | The sample data the design surface is laid out on. | | page | Page geometry ({ size, margin }), the same values you pass pdf({ page }). | | fonts | The font mapping, the same record you pass pdf({ fonts }). | | colorScheme | "light" (default), "dark", or "auto". Chrome only — the pages stay white. |

Events. change fires once per turn in which the document committed — an edit, an undo, a redo, or several of them in one turn arriving as one event. It carries { schema, problems, warnings }: the document (deep-frozen), its structured problem list, so you can disable Save without running the engine yourself, and the engine's advisory warnings. Those warnings are never fatal, so nothing that gates on problems should gate on them. The two halves always agree, which means a change needs a plan behind it. While a property the editor rejects or an engine throw is standing, the editor holds edits rather than delivering them. The next render that reaches the document then sends the settled result as one event. A render that merely fails still delivers. The editor checked the document and found it clean, and only the drawing of it went wrong. error reports host mistakes and render failures, and is your cue that anything derived from the last change may be stale. A host mistake reports once, not once per render it blocks, and the panel it opens stays dismissed once dismissed. The panel's label is "The report could not be displayed." until a render has ever landed, and "The report could not be updated." after. renderComplete is a Promise<boolean> for the newest render settling: the render that is newest when it settles, so awaiting it while edits keep landing waits for the last one's render.

Where a node is drawn. boxes(path) answers every rectangle the render drew for a node, in document order, as client rectangles. Use it to anchor your own UI to a node — a badge, a comment marker, a tour step. It answers for every page, whether or not that page is on screen. It answers an empty array when the node draws nothing, when the path is not in the document, and before a render lands. Await renderComplete first.

Editing. Hover an item for its gutter grip: drag to move (a caret shows exactly where it will land, and refuses to go anywhere illegal), click for Delete and Duplicate, and the + beside it inserts a text item. Drag table column headers to reorder — a column's total cell travels with it. The right rail holds four things: the document panel, the properties panel, the groups list, and every problem in the document. The document panel edits the report default — the family and size every band inherits — and stands whether or not anything is selected, because that default belongs to the document rather than to any band. It also lists the bands off the page: page.header, page.footer and empty. Nothing on the sheet is ever one of them — a page band is drawn by a paginating target alone, and empty renders only over a dataset with no rows — so selecting one there is the only way to reach its items, which the panel then lists with the verbs that add, remove and reorder them. Dropping into one from a visible band follows the same anchor rule as any other drop. The properties panel carries real controls for styles, an fx toggle to make any style value an expression, and errors underlined at the exact character when the engine knows it. Mod+Z / Shift+Mod+Z undo and redo whole gestures. Inside a text field they undo typing, not the document. Escape cancels a drag in progress, else clears the selection. Typing commits as one gesture once it pauses for half a second, and history keeps the last hundred gestures. While the document is mid-edit and invalid, the preview keeps the last version that compiled.

Reveal. The render is an honest picture: an empty band or a hidden item draws nothing. The bar's Reveal toggle (off by default) shows placeholders for them — a hidden item's placeholder shows what you wrote in it — and during a drag, empty bands appear as drop targets on their own.

Theming. Chrome styles live on --qe-* custom properties under qe-* class names, the editor's counterpart of the viewer's --qv-* set. A token set on the element or an ancestor wins over the pin. The names are a reference seam, not a frozen vocabulary: backdrop, bar, rail and sheet edge (--qe-backdrop, --qe-bar, --qe-rail, --qe-border, --qe-text, --qe-sheet-shadow), controls (--qe-field, --qe-icon, --qe-hover, --qe-focus), and the error panel (--qe-error, --qe-error-text, --qe-error-border), plus --qe-advisory-text for a warning in the Issues list. The pages stay white.

Documentation

The quario documentation is the reference. The report schema is the normative specification of what a report may declare, and @quario/editor is this element's own API.

License

quario is commercial software. Evaluation is free and fully featured, and quario marks its output as unlicensed. You state the key once, on the quario() instance you pass in. The editor adds no license mechanics of its own. See LICENSE.