import { ChangeSet, Node, Pos, Plot, Mark, Schema } from 'wordgard/doc'; type wgNode = Node; /** The base class for editor selections. Actual selections will be a subclass of this—usually {@link GardSelection.Text} or {@link GardSelection.Node}. */ declare abstract class GardSelection { /** The anchor of the selection—the side that doesn't move when you extend it. */ readonly anchor: number; /** The head of the selection, which is moved when it is extended (for example by moving the cursor while holding Shift). */ readonly head: number; /** The goal column (stored vertical offset) associated with a selection. This is used to preserve the vertical position when moving across lines of different length. */ readonly goalColumn?: number | undefined; protected constructor( /** The anchor of the selection—the side that doesn't move when you extend it. */ anchor: number, /** The head of the selection, which is moved when it is extended (for example by moving the cursor while holding Shift). */ head: number, /** The goal column (stored vertical offset) associated with a selection. This is used to preserve the vertical position when moving across lines of different length. */ goalColumn?: number | undefined); /** The lower boundary of the selected range. */ get from(): number; /** The upper boundary of the range. */ get to(): number; /** True when `anchor` and `head` are at the same position. */ get empty(): boolean; /** Returns true when this is an empty text selection. */ get isCursor(): boolean; /** The set of ranges covered by this selection, sorted. By default, this is just the selection's main `from` to `to`, but custom selection implementations can override it. */ get ranges(): readonly { from: number; to: number; }[]; /** The range that should be used when replacing this selection with other content (for example when typing or pasting over it) or deleting it. The default implementation returns `this.from` to `this.to`. */ get replacementRange(): { from: number; to: number; }; /** This can be overridden to control the DOM selection created for a selection. The default is to just return the selection's own head and anchor. */ get domSelection(): { head: number; headSide: -1 | 1; anchor: number; anchorSide: -1 | 1; }; /** The side that the selection head is associated with. -1 means it is after the element before its position, 1 means it is before the element after its position. This influences where the cursor is drawn (for example when on a line wrapping boundary or in bidirectional text) and where further motion takes it. It is valid for it to point in a direction where the is no element (say, -1 when at the start of its parent node). By default, this points in the direction of the anchor or forward if that is equal to the head, but selection types like {@link GardSelection.Text} can override it. */ get headSide(): -1 | 1; /** The {@link GardSelection.headSide side} associated with the selection anchor. Also by default points towards the head, or if that is the same position, forward. */ get anchorSide(): -1 | 1; /** Compare this selection to another selection. */ abstract eq(other: GardSelection): boolean; /** Returns true if this selection has the same head and anchor as the given selection. */ eqPos(other: GardSelection): boolean; /** Map a selection through a change. Used to adjust the selection position for changes. */ abstract map(change: ChangeSet, cx: GardSelection.Context, assoc?: -1 | 1): GardSelection; /** Convert this selection to an object that can be serialized to JSON. Each selection type may define its own JSON representation format. */ toJSON(state: GardState): unknown; /** Deserialize a selection. The configuration is used to associate custom selection types with their implementation. */ static fromJSON(cx: GardSelection.Context, json: unknown): GardSelection; /** Create a cursor text selection at the given position. */ static cursor(pos: number, side?: -1 | 1, goalColumn?: number): GardSelection.Text; /** Find a normal cursor near the given position. */ static near(cx: GardSelection.Context, pos: number, side?: -1 | 1, goalColumn?: number): GardSelection.Text; /** Create a text selection. */ static range(anchor: number, head?: number, headSide?: -1 | 1, goalColumn?: number): GardSelection.Text; /** Create a node selection. */ static node(pos: number, node: wgNode, goalColumn?: number): GardSelection.Node; /** Find the next normal cursor position after or before this selection's head. Normal cursor positions are: - Any inline position. - Positions between two cursor barriers, if not already an inline position. Cursor barriers are the sides of the document, any block leaves, or plots that are {@link Plot.Spec.isolating isolating}, {@link Plot.Spec.preserveWhitespace whitespace-preserving}, or explicitly defined as a {@link Plot.Spec.cursorBarrier cursor barrier}. */ nextNormalCursor(cx: GardSelection.Context, forward?: boolean): GardSelection.Text | null; /** Move across one word starting from this selection's head. */ skipWord(cx: GardSelection.Context, forward?: boolean): GardSelection.Text | null; /** Find a normal selection at the start of the document or the given textblock. */ static atStart(cx: GardSelection.Context, block?: Pos.Plot): GardSelection.Text; /** Find a normal selection at the end of the document or the given textblock. */ static atEnd(cx: GardSelection.Context, block?: Pos.Plot): GardSelection.Text; } declare namespace GardSelection { /** Create an extension that registers a custom selection type using the given class. Such a selection is only valid in a state that has the extension active. The JSON representation of a selection will be tagged with the `tag` string, and created and read via the functions passed here. */ function define(tag: string, cls: { new (...args: any[]): T; }, toJSON: (sel: T) => JSON, fromJSON: (doc: Plot.Doc, json: JSON) => T): any; /** Text selections hold a single arbitrary range in the document. They represent a cursor when their anchor and head are the same position. */ class Text extends GardSelection { private _headSide; /** A set of active marks that should be applied to content inserted at this selection (replacing the contextual marks). Used mostly for making the effect of toggling inline styles stick until something is inserted. Marks that aren't valid for the inserted content will be ignored. */ readonly marks: Mark.Set | undefined; private constructor(); get headSide(): 1 | -1; get anchorSide(): 1 | -1; /** Create a text selection. */ static create(spec: GardSelection.Text.Spec): Text; map(change: ChangeSet, cx: GardSelection.Context, assoc?: -1 | 1): GardSelection; eq(other: GardSelection): boolean; } namespace Text { /** Description of a text selection. */ type Spec = { /** The anchor point of the selection. This is the side that doesn't move when extending the selection (for example by moving the cursor while holding shift). */ anchor: number; /** The moving side of the selection. This will default to `anchor` when not given. */ head?: number; /** The side of the head position that the selection is associated with, if any. `-1` points at the element before the position, `1` at the element after. This is only meaningful for empty/cursor selections. It will influence where the cursor is drawn. */ headSide?: -1 | 1; /** Associates a horizontal position with this selection for use during vertical cursor motion. */ goalColumn?: number; /** Marks associated with a cursor selection, which will determine the marks of inline content inserted at that selection. This is used for things like toggling emphasis on a cursor selection. */ marks?: Mark.Set; }; /** The representation of a text selection when serialized to JSON. */ type JSON = { anchor: number; head?: number; side?: -1 | 1; marks?: Record; }; } /** Node selections select a single node. They are created, for example, when clicking on or moving into a {@link Node.Spec.selectable selectable} leaf node. Use {@link GardSelection.node} to create one. */ class Node extends GardSelection { /** The selected node. */ readonly node: wgNode; private constructor(); map(change: ChangeSet, cx: GardSelection.Context, assoc?: -1 | 1): Text | Node; eq(other: GardSelection): boolean; } namespace Node { /** The representation of a node selection when serialized to JSON. */ type JSON = { pos: number; }; } /** A selection object where the selection positions have been {@link Plot.Doc.resolve resolved}. For convenience, an editor state's {@link GardState.sel `sel` property} provides an instance of this, derived from the state's regular selection. */ class Resolved { /** The original selection. */ readonly selection: GardSelection; /** The selection anchor. */ anchor: Pos; /** The head of the selection. */ head: Pos; private _ranges; private constructor(); /** The lower bound of the selection. */ get from(): Pos; /** The upper bound of the selection. */ get to(): Pos; /** The selection ranges. */ get ranges(): readonly { from: Pos; to: Pos; }[]; private resolveRanges; /** The resolved replacement range. */ get replacementRange(): { from: Pos; to: Pos; }; /** The active marks for this selection. If this is a cursor selection with explicitly stored {@link GardSelection.Text.Spec.marks marks}, those are returned. Otherwise, this computes the marks that should be applied to content inserted in the selection's position, based on spanning marks on the surrounding nodes. */ get activeMarks(): Mark.Set; } /** Many selection related functions need access to a configuration (to determine text direction and visual motion behavior) and a document. Note that {@link GardState} is a subtype of this. */ type Context = { doc: Plot.Doc; config: GardState.Configuration; }; } /** Changes to the editor state are grouped into transactions. Typically, a user action creates a single transaction, which may contain any number of document changes, may change the selection, or have other {@link Transaction.Effect effects}. Create a transaction by calling {@link GardState.update}, or immediately dispatch one by calling {@link editor.Wordgard.dispatch `Wordgard.dispatch`}. */ declare class Transaction { /** The state from which this transaction starts. */ readonly startState: GardState; /** The document changes made by this transaction. */ readonly changes: ChangeSet; /** The selection set by this transaction, or undefined if it doesn't explicitly set a selection. */ readonly selection: GardSelection | undefined; /** The effects contained in this transaction. */ readonly effects: readonly Transaction.Effect[]; /** Whether the selection should be scrolled into view after this transaction is dispatched. */ readonly scrollIntoView: boolean; private constructor(); /** The new selection produced by the transaction. If {@link Transaction.selection `this.selection`} is undefined, this will {@link GardSelection.map map} the start state's current selection through the changes made by the transaction. */ newSelection: GardSelection; /** The new document produced by the transaction. Contrary to {@link Transaction.state `.state`}`.doc`, accessing this won't force the entire new state to be computed right away, so it is recommended that {@link Transaction.extender transaction extenders} use this property when they need to look at the new document. */ newDoc: Plot.Doc; /** The new state created by the transaction. Lazily computed so that the state is resolved the first time this property is accessed. */ get state(): GardState; /** Get the value of the given transaction {@link Transaction.Annotation annotation} type, if any. */ annotation(type: Transaction.Annotation.Type): T | undefined; /** Indicates whether the transaction changed the document. */ get docChanged(): boolean; /** Indicates whether this transaction reconfigures the state (through a {@link GardState.Compartment configuration compartment}, {@link GardState.reconfigure reconfiguration}, or {@link GardState.appendConfig appended configuration}). */ get reconfigured(): boolean; /** Returns true if the transaction has a {@link Transaction.userEvent user event} annotation that is equal to or more specific than `event`. For example, if the transaction has `"select.pointer"` as user event, `"select"` and `"select.pointer"` will match it. */ isUserEvent(event: string): boolean; } declare namespace Transaction { /** Describes a {@link Transaction transaction} when calling {@link GardState.update `GardState.update`} or {@link Wordgard.dispatch `Wordgard.dispatch`}. */ interface Spec { /** The changes to the document made by this transaction. */ changes?: ChangeSet.Spec; /** When set, this transaction explicitly updates the selection. Offsets in this selection should refer to the document as it is _after_ the transaction. If a selection can only be computed after the new document is available, you can pass a function here. */ selection?: GardSelection | GardSelection.Text.Spec | ((cx: GardSelection.Context, changes: ChangeSet) => GardSelection | null); /** Attach {@link Transaction.Effect effects} to this transaction. Again, when they contain positions and this same spec makes changes, those positions should refer to positions in the updated document. */ effects?: Transaction.Effect | readonly Transaction.Effect[]; /** Set {@link Transaction.Annotation annotations} for this transaction. */ annotations?: Transaction.Annotation | readonly Transaction.Annotation[]; /** Shorthand for `annotations: `{@link Transaction.userEvent `Transaction.userEvent`}`.of(...)`. */ userEvent?: string; /** When set to `true`, the transaction is marked as needing to scroll the current selection into view. */ scrollIntoView?: boolean; /** Only meaningful for specs that are combined with another transaction spec (via {@link Transaction.merge or by being returned from an {@link Transaction.extender extender}. Normally, when specs are combined, the positions in `changes` are taken to refer to the document positions in the initial document. When a spec has `sequental` set to true, its positions will be taken to refer to the document created by the changes in the spec before it. */ sequential?: boolean; } /** Merge two transaction specs into a single one, combining the effect of both. */ function merge(state: GardState, a: Transaction.Spec, b: Transaction.Spec): Transaction.Spec; /** Facet used to register a hook that gets a chance to add to transactions before they are applied. If such a function returns a transaction spec, it will be combined with the original transaction (in the same way as the arguments to {@link GardState.update}). When possible, it is recommended to avoid accessing {@link Transaction.state} in an extender, since it will force creation of a state that will then be discarded again, if the transaction is actually extended. This functionality should be used with care. Indiscriminately modifying transaction is likely to break something or degrade the user experience. Extenders that may add document changes should generally not do anything for {@link Transaction.remote remote} transactions, because doing so risks causing endlessly cascading changes or other confusion. It is possible to define extenders that are safe when activated on multiple peer (for example, duplicate deletions of the same content tend to converge), but it requires a lot of care. */ let extender: GardState.Facet<(tr: Transaction) => Transaction.Spec | null>; /** A transaction appender can create more transactions in response to a transaction. {@link Transaction.append}, which is called by the {@link Wordgard editor} when dispatching a transaction, will call appenders on sets of transactions, allowing them to add another transaction. When another appender adds a transaction, extenders that already ran will be called again, but only with the transactions that were added after they ran. */ let appender: GardState.Facet<(trs: readonly Transaction[], state: GardState) => Transaction.Spec | null>; /** Apply {@link Transaction.appender transaction appenders}, return an array of the original transaction plus any that were appended. */ function append(tr: Transaction): readonly Transaction[]; /** Annotations are tagged values that are used to add metadata to transactions in an extensible way. They should be used to model things that effect the entire transaction (such as its {@link Transaction.time time stamp} or information about its {@link Transaction.userEvent origin}). For effects that happen _alongside_ the other changes made by the transaction, {@link Transaction.Effect effects} are more appropriate. */ class Annotation { /** The annotation type. */ readonly type: Transaction.Annotation.Type; /** The value of this annotation. */ readonly value: T; /** Define a new type of annotation. */ static define(): Annotation.Type; private _isAnnotation; } namespace Annotation { /** Marker that identifies a type of {@link Transaction.Annotation annotation}. */ class Type { /** Create an instance of this annotation. */ of(value: T): Transaction.Annotation; } } const foo: number; /** Annotation used to store transaction timestamps. Automatically added to every transaction, holding `Date.now()`. */ const time: Annotation.Type; /** Annotation used to associate a transaction with a user interface event. Holds a string identifying the event, using a dot-separated format to support attaching more specific information. The events used by the core libraries are: - `"input"` when content is entered - `"input.type"` for typed input - `"input.type.compose"` for composition - `"input.paste"` for pasted input - `"input.drop"` when adding content with drag-and-drop - `"delete"` when the user deletes content - `"delete.selection"` when deleting the selection - `"delete.forward"` when deleting forward from the selection - `"delete.backward"` when deleting backward from the selection - `"delete.cut"` when cutting to the clipboard - `"move"` when content is moved - `"move.drop"` when content is moved within the editor through drag-and-drop - `"select"` when explicitly changing the selection - `"select.pointer"` when selecting with a mouse or other pointing device - `"select.all"` when selecting the entire document - `"undo"` and `"redo"` for history actions - `"insert"` for actions that insert nodes - `"mark"` for actions that manipulate marks - `"mark.add"` when a command adds a mark - `"mark.remove"` when a command removes one - `"split"`, `"wrap"`, `"settype"`, `"wrap"`, `"unwrap"` for block manipulation actions Use {@link Transaction.isUserEvent `isUserEvent`} to check whether the annotation matches a given event. */ const userEvent: Annotation.Type; /** Annotation indicating whether a transaction should be added to the undo history or not. */ const addToHistory: Annotation.Type; /** Annotation indicating (when present and true) that a transaction represents a change made by some other actor, not the user. This is used, for example, to tag other people's changes in collaborative editing. */ const remote: Annotation.Type; /** A flag set on transactions created by a {@link Transaction.appender transaction appender}. */ const appended: Annotation.Type; /** Transaction effects can be used to represent additional effects associated with a {@link Transaction.effects transaction}. They are often useful to model changes to custom {@link GardState.Field state fields}, when those changes aren't implicit in document or selection changes. */ class Effect { /** The value of this effect. */ readonly value: Value; /** Map this effect through a position mapping. Will return `undefined` when the changes deleted the effect. */ map(mapping: ChangeSet): Transaction.Effect | undefined; /** Tells you whether this effect object is of a given {@link Transaction.Effect.Type type}. */ is(type: Transaction.Effect.Type): this is Transaction.Effect; /** Define a new effect type. The type parameter indicates the type of values that his effect holds. It should be a type that doesn't include `undefined`, since that is used in {@link Transaction.Effect.map mapping} to indicate that an effect is removed. */ static define(spec?: Transaction.Effect.Spec): Transaction.Effect.Type; } namespace Effect { /** Map an array of effects through a change set. */ function mapEffects(effects: readonly Transaction.Effect[], mapping: ChangeSet): readonly Effect[]; /** A type of state effect. Defined with {@link Transaction.Effect.define}. */ class Type { /** @internal */ readonly map: (value: any, mapping: ChangeSet) => any | undefined; /** Create an {@link Transaction.Effect effect} instance of this type. */ of(value: Value): Transaction.Effect; } /** Options passed when defining an effect. */ interface Spec { /** Provides a way to map an effect like this through a position mapping. When not given, the effects will simply not be mapped. When the function returns `undefined`, that means the mapping deletes the effect. */ map?: (value: Value, mapping: ChangeSet) => Value | undefined; } } } /** Represents a contiguous range of text that has a single direction (as in left-to-right or right-to-left). */ declare class BidiSpan { /** The start of the span (relative to the start of the line). */ readonly from: number; /** The end of the span. */ readonly to: number; /** The ["bidi level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm) of the span. 0 means left-to-right, 1 means right-to-left, 2 means left-to-right embedded inside right-to-left, and so on, with even numbers being left-to-right, odd numbers right-to-left.. */ readonly level: number; /** The direction of this span. */ get ltr(): boolean; /** Query whether the given character has a strong direction. Returns null when not, true when left-to-right, and false when right-to-left. */ static strongDir(ch: number): boolean | null; } /** A textblock map contains the text in a textblock as a string, and can help convert between string offsets and document positions. Note that this is not the way to convert a piece of document to a string. Use {@link doc.Plot.textContent} for that. */ declare class TextblockMap { /** The start position of the textblock content. */ readonly start: number; /** The textblock's document node. */ readonly node: Plot; /** Whether the base direction of this block is left-to-right. */ readonly ltr: boolean; /** The text in the block. Non-text leaf nodes and nodes with block content will be replaced by a single `0xfffc` character in this string. */ readonly text: string; private _order; private config; private sections; private constructor(); /** The text order of the text in this block. Will generally be a single span, but if the block mixes left-to-right and right-to-left text, this describes the individual sections, ordered from the block's start to its end. */ get order(): readonly BidiSpan[]; /** Get the map for the given textblock. Will use a cache to reuse results for unchanged blocks. */ static get(cx: GardSelection.Context, start: number, node: Plot): TextblockMap; private static create; /** Get the string index for a document position. Positions outside of the textblock will be clipped to its start or end. */ toIndex(pos: number): number; /** Get the document position for a given string index. */ fromIndex(index: number): number; /** Get the position at the start or end of the textblock. Note that in bidirectional text this may not be the actual start or end position of the node. */ visualSide(start: boolean): { pos: number; side: -1 | 1; }; } type DocSource = Plot.Doc | HTMLElement | DocumentFragment | string | Node.JSON | ((schema: Schema) => Plot.Doc); /** The editor state tracks things like the current document, the selection, the configuration of the editor, and any extra state defined by extensions. The state is a persistent (immutable) data structure. To update a state, you {@link GardState.update create} a {@link Transaction transaction}, which produces a _new_ state instance, without modifying the original object. */ declare class GardState { /** The configuration for this state. */ readonly config: GardState.Configuration; private _doc; private _selection; private resolvedSel; private trackAccess; /** Create a new state. You'll usually only need this when initializing an editor or loading a new document—updated states are created by applying transactions. The schema of the state can be provided either via the {@link GardState.schemaElement configuration} or by passing in an initialized document (which will have its own schema). If the configuration contains a document plot type, the schema from the configuration will be used, even if a document was provided. */ static create(spec: GardState.Spec): GardState; private constructor(); /** The current document. */ get doc(): Plot.Doc; /** The document's schema. */ get schema(): Schema; /** The current selection. */ get selection(): GardSelection; /** A resolved form of the state's selection. Instead of raw positions, this object holds {@link Pos document position} objects for `head`, `anchor`, `from`, and `to`. */ get sel(): GardSelection.Resolved; /** Retrieve the value of a {@link GardState.Field state field}. Throws an error when the state doesn't have that field, unless you pass `false` as second parameter. */ field(field: GardState.Field): T; field(field: GardState.Field, require: false): T | undefined; /** Get the value of a state {@link GardState.Facet facet}. */ facet(facet: GardState.Facet.Reader): Output; /** Create a {@link Transaction transaction} that updates this state. */ update(spec: Transaction.Spec): Transaction; /** Compute the textblock map for the given plot (which should be a textblock). */ textblockMap(node: Pos.Plot): TextblockMap; /** Convert this state to a JSON-serializable object. When custom fields should be serialized, you can pass them in as an object mapping property names (in the resulting object, which should not use `doc` or `selection`) to fields. */ toJSON(fields?: { [prop: string]: GardState.Field; }): any; /** Deserialize a state from its JSON representation. When custom fields should be deserialized, pass the same object you passed to {@link GardState.toJSON `toJSON`} when serializing as third argument. */ static fromJSON(json: any, extensions: GardState.Extension, fields?: { [prop: string]: GardState.Field; }): GardState; /** Returns true when the editor is {@link GardState.readOnly} to be read-only. */ get readOnly(): boolean; /** Get the global text direction (true when left-to-right, false when right-to-left) for the document. Note that the direction of individual blocks can be overridden with {@link GardState.textblockLTR}. */ get textLTR(): boolean; /** Return the text direction in a given textblock (by tag). */ textblockLTR(plot: Plot): boolean; /** Tells you whether a node type is an atom (a leaf or a plot with an atomic shape). */ isAtom(type: Node.Type): boolean; /** Return the extent of the word around the given position, as a text selection. */ wordAt(pos: number, bias?: -1 | 1): GardSelection.Text; /** This effect can be used to reconfigure the root extensions of the editor. Doing this will discard any extensions {@link GardState.appendConfig appended}, but does not reset the content of {@link GardState.Compartment.reconfigure reconfigured} compartments. */ static reconfigure: Transaction.Effect.Type; /** Append extensions to the top-level configuration of the editor. */ static appendConfig: Transaction.Effect.Type; } declare namespace GardState { /** Options passed when {@link GardState.create creating} an editor state. */ interface Spec { /** The initial document. When passing in a {@link Plot.Doc document node} here, it is not necessary to include a schema in your configuration (though it is allowed, and the document content will be moved into that schema if it differs from the one on the given document). All other forms require a schema from the configuration. A string or DOM structure will be parsed as HTML. Passing a string only works in the browser, where the library can use the browser's HTML parser. In other environments, you'll need to do the parsing yourself (for example with [jsdom](https://jsdom.org/)). A JSON node deserialized, and a function called to produce the document. */ doc?: DocSource; /** The starting selection. Defaults to a cursor at the start of the document. */ selection?: GardSelection | GardSelection.Text.Spec | ((cx: GardSelection.Context) => GardSelection); /** The configuration for this state, either as a resolved {@link GardState.Configuration} or as a set of extensions. */ config?: GardState.Extension | GardState.Configuration; } /** Fields can store additional information in an editor state, and keep it in sync with the rest of the state. The type parameter indicates the type of value stored in the field. */ class Field { private createF; private updateF; private compareF; private constructor(); /** Define a state field. */ static define(config: GardState.Field.Spec): GardState.Field; private create; /** State field instances can be used as {@link GardState.Extension `Extension`} values to enable the field in a given state. */ get extension(): GardState.Extension; /** Returns an extension that enables this field and overrides the way it is initialized. Can be useful when you need to provide a non-default starting value for the field. */ init(create: (state: GardState) => Value): GardState.Extension; } namespace Field { /** The options passed when defining a state field. */ type Spec = { /** Creates the initial value for the field when a state is created. */ create: (state: GardState) => Value; /** Compute a new value from the field's previous value and a {@link Transaction transaction}. Should not mutate the old value (since that will change the existing state), but create a fresh one or return the old value unchanged. */ update: (value: Value, transaction: Transaction) => Value; /** Compare two values of the field, returning `true` when they are the same. This is used to avoid recomputing facets that depend on the field when its value did not change. Defaults to using `===`. */ compare?: (a: Value, b: Value) => boolean; /** Provide extensions based on this field. The given function will be called once with the initialized field. It is typically used with a facet's {@link GardState.Facet.from} method to create facet inputs from this field, but can also return other extensions that should be enabled when the field is present in a configuration. */ provide?: (field: GardState.Field) => GardState.Extension; /** A function used to serialize this field's content to JSON. Only necessary when this field is included in the argument to {@link GardState.toJSON}. */ toJSON?: (value: Value, state: GardState) => any; /** A function that deserializes the JSON representation of this field's content. */ fromJSON?: (json: any, state: GardState) => Value; }; } /** A facet is a labeled value that is associated with an editor state. It takes inputs from any number of extensions, and combines those into a single output value. Examples of uses of facets are the {@link GardState.readOnly read-only configuration}, {@link editor.Wordgard.editorAttributes editor attributes}, and {@link editor.Wordgard.updateListener update listeners}. Note that `Facet` instances can be used anywhere where {@link GardState.Facet.Reader} is expected. Facets have an input type (the type of values provided for it), and an output type (the type you get when you read the facet) that defaults to an array of input values, but can be anything if a {@link GardState.Facet.Spec.combine} option is provided. */ class Facet implements GardState.Facet.Reader { /** True when this is a static facet. */ readonly isStatic: boolean; /** The output of the facet when it has no inputs. */ readonly default: Output; private constructor(); /** A facet reader for this facet, which can be used to {@link GardState.facet read} it but not to define values for it. */ get reader(): GardState.Facet.Reader; /** Defines a facet with the given input an output types. */ static define(config?: GardState.Facet.Spec): Facet; /** Returns an extension that provides the given value to this facet. */ of(value: Input): GardState.Extension; /** Create an extension that computes a value for the facet from a state. The given function should only depend on the state, not any external non-constant inputs. Its return value will be kept on state update, unless any of the fields or facets (including document and selection) that it read are changed by the update, in which case it is called again. In cases where your value depends only on a single field, you can use the {@link GardState.Facet.from `from`} method instead. */ compute(get: (state: GardState) => Input): GardState.Extension; /** Create an extension that computes zero or more values for this facet from a state. */ computeN(get: (state: GardState) => readonly Input[]): GardState.Extension; /** Shorthand method for registering a facet source with a state field as input. If the field's type corresponds to this facet's input type, the getter function can be omitted. If given, it will be used to produce the input from the field value. */ from(field: GardState.Field): GardState.Extension; from(field: GardState.Field, get: (value: T) => Input): GardState.Extension; tag: Output; } namespace Facet { /** Options passed when {@link GardState.Facet.define defining} a facet. */ type Spec = { /** How to combine the input values into a single output value. When not given, the array of input values becomes the output. This function will immediately be called on creating the facet, with an empty array, to compute the facet's default value when no inputs are present. */ combine?: (value: readonly Input[]) => Output; /** How to compare output values to determine whether the value of the facet changed. When a new value for the facet is computed that that compares as equal to the old value, the old value is kept. So in most circumstances, facet values can be cheaply compared by identity to check for changes. Defaults to comparing by `===` or, if no `combine` function was given, comparing each element of the array with `===`. */ compare?: (a: Output, b: Output) => boolean; /** How to compare input values to avoid recomputing the output value when no inputs changed. Defaults to comparing with `===`. */ compareInput?: (a: Input, b: Input) => boolean; /** Forbids dynamic inputs to this facet. Allows the facet to be {@link GardState.Configuration.staticFacet read} from a configuration. */ static?: boolean; /** If given, these extensions (or the result of calling the given function with the facet) will be added to any state where this facet is provided. (Note that, while a facet's {@link GardState.Facet.default default} value can be read from a state even if the facet wasn't present in the state at all, the extensions won't be added in that situation.) */ enables?: GardState.Extension | ((self: GardState.Facet) => GardState.Extension); }; /** A facet reader can be used to fetch the value of a facet, through {@link GardState.facet} or as a dependency in {@link GardState.Facet.compute `Facet.compute`}, but not to define new values for the facet. */ type Reader = { /** @hidden */ tag: Output; }; /** Utility function for combining multiple configuration objects. `defaults` should hold default values for all optional fields in `Config`. The function will, by default, raise an error when a field gets two values that aren't `===`-equal, but you can provide combine functions per field to do something else. */ function combineConfig(configs: readonly Partial[], defaults: Partial, // Should hold only the optional properties of Config, but I haven't managed to express that combine?: { [P in keyof Config]?: (first: Config[P], second: Config[P]) => Config[P]; }): Config; } /** A state configuration stores a set of extensions, structured so that state updates can be performed efficiently. */ class Configuration { /** The set of extensions that this configuration is based on. */ readonly base: GardState.Extension; private constructor(); /** Read the value of a static facet. */ staticFacet(facet: GardState.Facet): Output; /** Create a configuration from the given set of extensions. */ static create(extensions: GardState.Extension): Configuration; /** Get the schema defined by this configuration. Will be null if the schema does not contain a document plot type. */ get schema(): Schema | null; } /** Extension values can be {@link GardState.Spec.config provided} when creating a state to attach various kinds of configuration and behavior information. They can either be built-in extension-providing objects, such as {@link GardState.Field state fields} or {@link GardState.Facet.of facet providers}, or objects with an extension in its `extension` property. Extensions can be nested in arrays arbitrarily deep—they will be flattened when resolved into a configuration. */ type Extension = { extension: GardState.Extension; } | readonly GardState.Extension[]; /** By default extensions are registered in the order they are found in the flattened form of the configuration's extension tree. Individual extension values can be assigned a precedence to override this. Extensions that do not have a precedence set get the precedence of the nearest parent with a precedence, or {@link GardState.prec.default `default`} if there is no such parent. The final ordering of extensions is determined by first sorting by precedence and then by order within each precedence. */ const prec: { /** The highest precedence level, for extensions that should end up near the start of the precedence ordering. */ highest: (ext: GardState.Extension) => GardState.Extension; /** A higher-than-default precedence, for extensions that should come before those with default precedence. */ high: (ext: GardState.Extension) => GardState.Extension; /** The default precedence, which is also used for extensions without an explicit precedence. */ default: (ext: GardState.Extension) => GardState.Extension; /** A lower-than-default precedence. */ low: (ext: GardState.Extension) => GardState.Extension; /** The lowest precedence level. Meant for things that should end up near the end of the extension order. */ lowest: (ext: GardState.Extension) => GardState.Extension; }; /** Extension compartments can be used to make a configuration dynamic. By {@link GardState.Compartment.of wrapping} part of your configuration in a compartment, you can later {@link GardState.Compartment.reconfigure replace} that part through a transaction. */ class Compartment { private constructor(); /** Define a new compartment. */ static define(): Compartment; /** Create an instance of this compartment to add to your {@link GardState.Spec.config state configuration}. */ of(ext: GardState.Extension): GardState.Extension; /** Create an {@link Transaction.Spec.effects effect} that reconfigures this compartment. */ reconfigure(content: GardState.Extension): Transaction.Effect; /** Get the current content of the compartment in the state, or `undefined` if it isn't present. */ get(state: GardState): GardState.Extension | undefined; } /** Facet used to register {@link Schema schema} elements. *If* a configuration contains a {@link Plot.defineDoc document} type, the editor's document schema will be derived from the content of this facet. (Otherwise, the state will try to use the schema provided via the {@link GardState.Spec.doc} option, or raise an error is none is provided.) */ const schemaElement: Facet; /** This facet controls the value of the {@link GardState.readOnly `readOnly` getter}, which is consulted by commands and extensions that implement editing functionality to determine whether they should apply. It defaults to false, but when its highest-precedence value is `true`, the state is considered read-only, and such functions won't change the document. Not to be confused with {@link editor.Wordgard.editable}, which controls whether the editor's DOM is set to be editable (and thus focusable). */ const readOnly: Facet; /** Facet that indicates the document's default text direction. Note that this will not affect the editor CSS, and when the state's value disagrees with the direction set in the editor, the editor component will automatically inject an instance of this with a high precedence to align the state to the DOM. Still, if you know the direction in advance, it can be useful to set this, so that the direction is already accurate during initialization. Defaults to true. */ const textLTR: Facet; /** Configure the text direction per textblock. All values given for this will be consulted in order of precedence, until one returns a non-null value. If none set a direction, the editor's {@link GardState.textLTR base direction} is used. Schema elements like {@link schema.direction} register an instance of this to make the editor aware of the meaning of the {@link types.Direction} mark. */ const textblockLTR: Facet<(plot: Plot) => boolean | null, readonly ((plot: Plot) => boolean | null)[]>; /** Configure whether to use visual or logical cursor motion in bidirectional text. The default is visual, where pressing left/right arrow keys moves the cursor in the direction that corresponds to the arrow on key. When disabled, the motion uses the string index order instead. */ const visualCursorMotion: Facet; /** @hidden FIXME expose this? */ const isAtom: Facet<[Plot.Type, boolean], Map, boolean>>; } /** The class representing a correction. Counts as an editor extension. Corrections install themselves as {@link Transaction.extender transaction extenders} that check modified nodes and, if necessary, apply fixes to enforce constraints. In normal operation, this means that they guarantee the constraints implemented in the transaction are enforced. They do not activate for {@link Transaction.remote remote} transactions, because acting on those can cause collaborative editing setups to malfunction (for example, causing all peers to repeatedly try to correct the same issue, causing an endless loop of updates or other chaos). The collab module has special provisions for integrating corrections in the step transformation in a safe way, but that requires you to explicitly tell it to use them, both on the {@link collab.Config.corrections client} and the {@link collab.transformUpdate server}. */ declare class Correction { /** To take effect, corrections must be included in an editor configuration. */ extension: GardState.Extension; private constructor(); /** This method can be used to run a correction agains all matching nodes in an existing document. If the correction makes any changes, the method returns a transaction with those changes. */ scan(state: GardState): Transaction | null; /** Create a correction that runs whenever the child list of a node that matches the given query changes, or such a node is inserted into the document. */ static onChildList(query: Node.Query, correct: (node: Pos.Plot) => ChangeSet.Spec | null): Correction; /** Create a correction that runs whenever any content inside a node that matches the given query changes, or such a node is inserted into the document. */ static onContent(query: Node.Query, correct: (node: Pos.Plot) => ChangeSet.Spec | null): Correction; /** Define a correction that runs whenever the set of marks on a matching tag changes. */ static onMarks(query: Node.Query, correct: (node: Pos.Node) => ChangeSet.Spec | null): Correction; /** Check the ranges touched by the given change set against the given list of corrections. Return a change set if any changes need to be made. (This isn't how you normally use corrections, but can be useful in a situation where you aren't working with an editor state transaction.) */ static check(changes: ChangeSet, doc: Plot.Doc, corrections: readonly Correction[]): ChangeSet | null; } export { BidiSpan, Correction, GardSelection, GardState, TextblockMap, Transaction };