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

@undoable-edits/vue

v1.1.1

Published

Support undoable value changes through schema based vue 3 editors

Readme

Undoable Editor (Vue 3)

This library provides Vue 3 components for editting values and undoing said edits.

Quickstart

Installation

You can install this library through npm like so:

$ npm install --save @undoable-edits/vue

Basic Usage

The main component for this library is the UndoableValueEditor. You need only supply a model to use this, like so:

<UndoableValueEditor v-model="valueRef"/>

That will provide you a pair of disabled buttons and a type dropdown with all JSON schema type values, starting at "null". Picking one of those options will add the attach the appropriate sub-editor and enable the undo button. Clicking said button will roll you back to null and enable the redo button.

Note that this editor does support the disable attribute, applying that to it's undo/redo buttons and subeditors automatically.

Schemas

You can change the dropdown options by providing a schema property to that component. By default this should be a JSON schema object, though it accepts any boolean or object value. See the corresponding section below for using other schema types.

Schema Parsing

By default the editor uses the JSONSchemaOptionsParser from the schema-select library to convert subschemas into dropdown items. This means the following rules are in effect:

  • If set to true, the default list of all value types is used.
  • If enum is present, each of those values will be wrapped in a const schema for the subschemas.
  • If oneOf or anyOf, the subschema list is drawn from that property.
  • For all other schemas, the schema itself will wrapped in an array.

Should you want to use a different library instead, you can do so through the component's schemaParser property. The provided schema parser should be a SchemaOptionsParser as per the schema-select interface.

Localization

Should you want translation applied to the editor's text, you do so by providing a getTranslatedText function, like so:

import { provide } from 'vue'
import { KeyedTextTranslator, PLACEHOLDER_TEXT } from 'undoable-value-editor-vue'

const translator = new KeyedTextTranslator(PLACEHOLDER_TEXT)
provide('getTranslatedText', (key: string | string[]) => translator.translate(key))

Note that this function is meant to be compatible with i18n translate functions, making it easy to plug such libraries in here.

The above KeyedTextTranslator is just a basic translation mapper we've provided with this library. PLACEHOLDER_TEXT covers the few instances of text messages used by the editor. At present that's just error messages for entering an invalid or in use property name.

Note that that the above injection only applies to the editor's own text, not any labels generated by the schema parser. To localize those, you'll need to specify a schema parser with localization support. Take care when doing so as you'll need localization for all possible labels on any schemas the editor may recieve. At minimum, you'll likely want translations for all data type names. If you're expecting specialized schemas with their own names you'll want translations ready for those as well.

Custom Icons

You can replace any of the icons used in the editor by providing a mapping of named icons, like so:

provide('namedIcons', {
  add: `<u>+</u>`,
  delete: `<u>-</u>`,
  rename: "Rename",
  revert: "Revert",
  copy: "Copy",
  cut: "Cut",
  paste: "Paste",
  alert: `<u>!</u>`,
  undo: "Undo",
  redo: "Redo"
})

Note that those mapping can be to strings or component references. If strings are provided, the icon will be treated as html text via "v-html".

Internally, this is handled by IconPlaceholder components that reference that mapping using their type property, using their slotted content if no component is found.

IconButton components act as button wrapper for said placeholders, with the added effect of attaching their type property as a class name. For example, <IconButton type="add"/> would attach the "add-button" class to the resulting button. These are added to make css styling easier.

Custom Editors

Should you want to use one of you own components as a subeditor, you can do so by providing an editorFactory property. Said factory is simply an object with the following callback:

process: (source: any, context?: boolean | Record<string, any>) => any

That callback will be passed the current value as the source and the selected subschema as the context. The results of said callback will then be used as the target subeditor component.

Note that the subeditor will be passed the model, schema parser, editor factory, transfer handler, and disabled status of the value editor, as well as the selected subschema.

We've provided the following factories with this library.

Type Mapped Value Factory

The TypeMappedValueFactory accepts a mapping of type names to components. You can provide those mappings on creation, like so:

const defaultEditorResolver = new TypeMappedValueFactory({
  array: ArrayEditor,
  bigint: NumberEditor,
  boolean: BooleanEditor,
  integer: NumberEditor,
  number: NumberEditor,
  object: ObjectEditor,
  string: StringEditor
})

The factory will them choose the subeditor based on the type of the target value. If it doesn't have an entry for that type, if will try to match against the type property of the provided schema instead.

Lookup Via Schema Property

LookupViaSchemaProperty checks the target schema property, then uses said property as a key to a component map. For example, let's say you created one like this:

const editorFactory = new LookupViaSchemaProperty('format', { flag: BooleanEditor })

That would check the schema's "format" property, returning a BooleanEditor when the format is "flag".

Transfer Handlers

The transfer handler is simply an object that supports sending out an undoable action for dragging and dropping values within the editor. A new instance will be created by default if none is provided, so you should always have access to one within subeditors via the transferHandler property.

To use that simply call startTransfer when you start a drag, like so:

if (props.transferHandler != null) {
  props.transferHandler.startTransfer({
    source: someObject,
    key: propertyName
  })
}

Then just have the drop target call completeTransfer, like this:

if (props.transferHandler) {
  const action = props.transferHandler.completeTransfer({
    source: someObject,
    key: propertyName
  })
  if (action != null) {
    emit('undoableChange', action)
  }
}

If transferring from or into an array, use index instead of key for the above calls.

Note that you can use standard drag and drop API calls. The transfer handler is simply there to wrap these transfers in an undoable action so they can be reverted easily.

Undoable Changes

You may have noticed the above example emits an undoableChange event. The editor uses these to notify the undo and redo buttons that there's a change they can apply or revert. Should your custom editor involve modifying an object or array you'll probably want to send out those events so the main value editor can catch them and add them to the undo/redo track. Changes to primitives should already be caught as part of model update handling, but objects get special handling as they may have properties initialized without triggering an undoable action.

Alternate Schemas

The value editor does allow other types of schema besides JSON schema. However, you will need to provide a few things to support that should you want to use a different type.

First, you'll need to pass in a custom schema parser. Said parser should be a SchemaOptionsParser as per the schema-select library.

Second, the default sub-editors are based on expected JSON schema properties for the target type. As such, you'll likely need to provide an editor factory with subeditors that play nicely with your new schema type.