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

grapper-editor

v1.1.0-beta.4.1

Published

Grapper Source Code Editor

Readme

GrapperCode editor web component

<g-editor>

A standalone code editor component that edits a <grapper-view> in real time and keeps its attributes/internal markup synchronized.

Features

  • Inline editor with copy/save/reload/rearrange controls
  • Works against:
    • A <grapper-view> component (keeps attributes and content synchronized)
    • Inline code provided in the light DOM (comment node or <textarea>)
    • An <iframe>’s document.body
  • Read-only, show, and edit modes
  • Optional line highlighting
  • Theme switching (light/dark)
  • Diagnostics event stream for Grapper View validation

Installation

You can install the component via npm:

npm install --save grapper-editor

Then import it in your app from CDN:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/editor.js"></script>

The component registers as <g-editor>.

Working with the Grapper view (<grapper-view>)

When the href points at a <grapper-view>, the editor switches to composer mode:

<grapper-view id="composer"></grapper-view>

<g-editor title="Composer" href="#composer" mode="edit"></g-editor>

In composer mode:

  • The edited markup is applied to the composer’s inner content.
  • All attributes on the composer are kept in sync (added/removed/updated) to match the edited source.
  • Diagnostics will be computed against the live <grapper-view> and surfaced via the diagnostic event and the built-in panel (if your provider UI shows it).

Inline content

You can provide the initial code as a comment node or a <textarea> in the light DOM:


<g-editor title="My template" mode="edit">
  <!--
  <svg width="300" height="80">
    <text x="10" y="40">Hello Graphane!</text>
  </svg>
  -->
</g-editor>

Or:

<g-editor title="My template" mode="edit">
  <textarea>
    <svg width="300" height="80">
      <text x="10" y="40">Hello Graphane!</text>
    </svg>
  </textarea>
</g-editor>

Editing an existing element with href

Point the editor at any element in the same document (or an <iframe>):

<div id="preview"></div>

<g-editor title="Section editor" href="#preview" mode="edit"></g-editor>
  • If href targets an <iframe>, the editor waits for it to load and uses its contentDocument.body.
  • When you edit, the target element’s innerHTML is updated in real time.

Attributes

| Attribute | Type | Default | Description | |-------------------|-----------|-----------|--------------------------------------------------------------------------------------------------------------------| | title | string | "" | UI title displayed in the editor header. | | href | string | "" | CSS selector for the element to edit. Supports elements and <iframe>. When empty, uses inline light-DOM content. | | keep-format | boolean | false | Preserve original formatting when re-loading code into the model. | | options | object | {} | Editor/model options (pass JSON string in HTML; a plain object when set programmatically). | | theme | string | "light" | Editor theme. Set to "dark" for dark mode. Also responds to a global themeChanged event (see Theming). | | mode | string | "show" | One of: "readonly", "show", "edit". Controls editability and which header actions are visible. | | lines-highlight | string | "" | Line ranges to highlight (e.g. "1-3;8;12-14"). See Line highlighting. |

All attributes are reactive and can be changed at runtime.

Line highlighting

Use lines-highlight with a semicolon-separated list of single lines or inclusive ranges:

  • Single lines: 5
  • Ranges: 10-15
  • Combined: 1-3;5;12-14

The string is parsed into numeric lines and applied by the editor provider.

UI & header actions

Depending on mode, the header shows:

  • Edit / Show toggles
  • Reload — discard unsaved edits and restore the original code
  • Rearrange — re-parse and re-format the current code using the model’s loader
  • Copy — copy current code to clipboard
  • Save — trigger a download of the current code (uses the provided saveFile helper)

In readonly mode, all editing controls are hidden and the editor is non-editable.

Events

diagnostic

Emitted whenever diagnostics are computed (typically after edits), especially useful with <grapper-view>.

const editor = document.querySelector('g-editor');
editor.addEventListener('diagnostic', (evt) => {
  // evt.detail is the diagnostic payload produced by your diagnostic pipeline
  console.log('Diagnostic:', evt.detail);
});

Perfect — with that BASE.md content I can now integrate the public events from grapper-core into the README for <g-editor>.

Here’s the updated README section with the public events clearly documented.

Lifecycle Events

These are automatically emitted during the component's lifecycle:

| Event | When it fires | | ------------- | --------------------------------------------------------------------------- | | ready | When the component has been instantiated and its constructor has run. | | render | After the component has built its initial UI structure in the shadow DOM. | | refresh | After the component has updated its content without a full re-render. | | update | Each time the component’s content is updated (may fire multiple times). |

Programmatic API

Access the component instance and call methods/properties directly:

const editor = document.querySelector('g-editor');

// Read or replace the entire code buffer
console.log(editor.code);
editor.code = '<svg><text>Hello</text></svg>';

// Update without changing "original" snapshot
editor.update('<div>New content</div>');

// Is the buffer different from the original snapshot?
if (editor.isChanged) {
  // Revert to original snapshot
  await editor.discardChanges();
}

// Re-parse/normalize current code via the model
await editor.rearrange();

// Utilities
await editor.toClipboard();
await editor.toDisk();     // triggers a file save
editor.resetChange();      // sets "original" = current buffer

Properties

  • code: string — get/set current buffer
  • isChanged: boolean — whether code differs from the original snapshot captured on load or after resetChange()

Methods (async when noted)

  • update(v: string): Promise<void>
  • discardChanges(): Promise<void>
  • rearrange(): Promise<void>
  • toClipboard(): Promise<void>
  • toDisk(): Promise<void>
  • resetChange(): void

Theming

Set theme="light" or theme="dark" directly, or broadcast a global theme change:

document.documentElement.dispatchEvent(
  new CustomEvent('themeChanged', {detail : {theme : 'dark'}})
);

The editor listens for themeChanged on document.documentElement and updates itself.

Examples

1) Grapper View

<grapper-view id="chart">
  <tempplate>
    <svg viewBox="0 0 200 100" width="200px" height="100px">
      <g stroke-width="12" stroke-linecap="round">
        <g g-for="(record, index) of data">
          <line  x1="22"
                 :x2="record.value"
                 :y1="index * 20 + 30"
                 :y2="index * 20 + 30"
                 :stroke="record.color"
          ></line>
        </g>
      </g>
    </svg>
  </tempplate>
  <script type="data">
    [
      {"color": "#D80000", "value": 130},
      {"color": "#00D800", "value": 170},
      {"color": "#0000D8", "value": 100}
    ]
  </script>
</grapper-view>

<g-editor title="Basic example" href="#chart"></g-editor>

2) Read-only viewer

<g-editor title="Spec preview" mode="readonly" lines-highlight="1-5;12">
  <!--
  <article>
    <h1>Spec</h1>
    <p>…</p>
  </article>
  -->
</g-editor>

3) Editing inside an iframe

<iframe id="sandbox" src="/playground.html"></iframe>

<g-editor title="Iframe body editor" href="#sandbox" mode="edit"></g-editor>

Tips & gotchas

  • keep-format helps preserve the original formatting when re-loading code into the model. If you prefer normalized output, leave it false.
  • If your href selector doesn’t match anything, the editor logs an error and renders nothing.
  • For <grapper-view>, both attributes and inner content are source-of-truth from the editor; manual changes to the live element may be overwritten by subsequent edits.