undoable-value-editor-vue
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

Undoable Value 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-value-editor-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.

Package Sidebar

Install

npm i undoable-value-editor-vue

Weekly Downloads

0

Version

1.0.0

License

none

Unpacked Size

257 kB

Total Files

45

Last publish

Collaborators

  • david-cary