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

@manifest-editor/editor-api

v2.1.0

Published

Everything that happens in the Manifest Editor is an editing operation on an instance of the Vault on one or more resources. There are also "creation" steps.

Downloads

1,001

Readme

Editor API

Everything that happens in the Manifest Editor is an editing operation on an instance of the Vault on one or more resources. There are also "creation" steps.

This directory will try to bring structure to this whole process. There will be 2 types of helpers:

  • Editors
  • Factories

Editors

List of existing "editors"

  • Manifest descriptive
  • Manifest metadata
  • Manifest linking
  • Manifest technical
  • Canvas descriptive
  • Canvas metadata
  • Canvas media
  • Canvas technical
  • Edit media item
  • Canvas thumbnail list/grid
const editors = {
  label: 'Media editor',
  resourceType: 'Canvas',
  tabs: true,
  editors: [
    {
      label: 'Media editior',
      hideFromTabs: true,
      supports: (ctx) => true, // Supports all.
      renderEditor: renderMediaEditor,
    }
  ],
  
}

The boilerplate editor code will handle the direct saving of the resource and provide the apis for mutating. For example, the boilerplate will handle SpecificResource issues and if there is a target that is available to edit. Also handle saving back to the parent.

Editors will be automatically selected from this list. Anywhere in the application you will be able to run: edit(resource) and it will open the right panel with the correct editor.

Factories

List of existing (proto) factories.

  • Add new media
  • Add new canvas

The properties of a factory:

  • A configuration describing how to create a resource
  • Contains a pointer to the target type + property
  • Has a list of options for each property (reusable)
const newCanvas = {
  label: 'Add new canvas',
  property: 'items',
  targetType: 'Manifest',
  editors: [], // Otherwise defaults will be used.
  creators: [
    {
      label: 'Blank canvas',
      outputType: 'Canvas',
      form: {
        width: { type: 'number-field', defaultValue: 1000 },
        height: { type: 'number-field', defaultValue: 1000 },
      },
      renderForm: renderBlankCanvas,
      creator: createBlankCanvas,
    }
  ]
};

renderForm - Takes in form, presents to the user and calls creator.

From anywhere in the app you will be able to run: create('Canvas', 'Manifest', 'items') - the user will then be presented with the UI to make a choice. Alternatively createModal(...) will open outside the right panel.

The reusable part built here will do the following:

  • Take the output of createBlankCanvas
    • Add dependencies (new nested resources) to Vault
    • Add the original resource to Vault
    • Link the resource to the specified property
const vault = new Vault();

const builder = new IIIFBuilder(vault);

const editor = new IIIFEditor(vault);

const {
  // Editors
  technical,
  descriptive,
  metadata,
  linking,
  structural,

  // Reference
  position,
  selector,

  // Extra helpers
  isMultiple,
  required,
  recommended,
  documentation,
  validate,
  observe,
} = editor.createEditor(referenceOrResource, context);

Editing + observing properties

const { descriptive, structural, observe } = editor.createEditor(referenceOrResource, context);

const { label, summary } = descriptive;

label.get(); // Returns value.
label.set(newValue); // Sets new value.
label.subscribe(() => {}); // Subscribe to changes to the label
label.focusId(); // Unique identifier for focus states
label.isValid(); // If it passes validation rules
label.errors; // list of errors
label.warnings; // list of warnings

observe.subscribe(() => {}); // Subscribe to all changes
observe.begin(); // Begin a snapshot.

label.get(); // Indicates that label should be observed.
summary.get(); // Indicates that the summary should be observed.

const { items } = structural;

items.get(); // all
items.get(index); // at index
items.length; // size of items
items.editor(items.get(0)); // Return new editor instance
items.generateReference(items.get(0)); // Full configuration (parent/index) for item.

Position changes

const { position } = editor.createEditor(ref, { parent, index: 1 });

if (position) {
  position.moveUp(); // optionally by number
  position.moveDown(); // optionally by number
  position.moveToStart();
  position.moveToEnd();
  position.moveBeforeIndex(idx);
}

Selector changes

const { selector } = editor.createEditor(ref, { parent, index });

selector.hasValid(); // Already has
selector.get();
selector.getRaw();
selector.set(newValue);
selector.subscribe(() => {});

Extra

const { documentation, required, recommended, validate } = editor.createEditor(ref);

// @note - documentation now split out into it's own static thing.
documentation.getLink("label");
documentation.getSummary("label");

recommended.includes("label"); // Array of recommended properties
required.includes("id"); // Array of required properties

const [isValid, warnings] = validate.label(proposedNewValue); // Validation for proposed new value

Validation rules

const editor = new IIIFEditor(vault, {
  validators: [
    {
      types: ["Canvas"],
      properties: ["duration", "height", "width"],
      message: "All canvases must have a duration or height and width",
      error: true,
      warning: false,
      valid: (canvas) => canvas.duration || (canvas.width && canvas.height),
    },
  ],
});

Code

Supported / required

const supportedDescriptive = {
  Manifest: ["label", "summary"],
  Canvas: ["label", "summary"],
};

const requiredDescriptive = {
  Manifest: ["label"],
};

Documentation links:

const rootDocumentation = "https://iiif.io/api/presentation/3.0/";
const documentationProperties = {
  label: "#label",
};

Documentation summary:

const documentationSummary = {
  label: `A human readable label, name or title. The label property is intended to be displayed as a short, textual surrogate for the resource if a human needs to make a distinction between it and similar resources, for example between objects, pages, or options for a choice of images to display. The label property can be fully internationalized, and each language can have multiple values.`,
};