import type { Range } from '../rga/Range'; import type { ITimestampStruct } from '../../../json-crdt-patch/clock'; import type { SliceStacking, SliceTypeCon } from './constants'; import type { NodeBuilder, nodes } from '../../../json-crdt-patch'; import type { SchemaToJsonNode } from '../../../json-crdt/schema/types'; import type { JsonNodeView } from '../../../json-crdt/nodes'; /** * Represents a developer-defined type of a slice, allows developers to assign * rich-text formatting or block types to slices. * * For example: * * ```ts * 'bold' * '' * 'p' * '

' * ['paragraph'] * ['

'] * ``` * * Slice types can specify block nesting: * * ```ts * ['blockquote', 'paragraph'] * ['

', '

'] * ['ul', 'li', 'code'] * ``` * * Slice types can use integers for performance: * * ```ts * 1 * [2] * [3, 4] * ``` * * Block split with discriminant, to differentiate between two adjacent blocks: * * ```ts * [['

', 0], '

'] * [['

', 1], '

'] * ``` * * Each block nesting level can have a custom data object: * * ```ts * [['

', 0, {author: 'Alice'}], '

'] * [ * ['list', 0, {type: 'ordered'}], * '

  • ', * ['

    ', 0, {indent: 2}] * ] * ``` */ export type SliceType = TypeTag | SliceTypeSteps; export type SliceTypeSteps = SliceTypeStep[]; export type SliceTypeStep = TypeTag | SliceTypeCompositeStep; export type SliceTypeCompositeStep = [tag: TypeTag, discriminant: number, data?: Record]; /** * Tag is number or a string, the last type element if type is a list. Tag * specifies the kind of the leaf block element. For example, if the full type * is `['ul', 'li', 'p']`, then the tag is `

    `. */ export type TypeTag = SliceTypeCon | number | string; /** * The JSON CRDT schema of the stored slices in the document. The slices are * stored compactly in "vec" nodes, with the first *header* element storing * multiple values in a single integer. */ export type SliceSchema = nodes.vec<[ /** * The header stores the stacking behavior {@link SliceStacking} of the * slice as well as anchor {@link Anchor} points of the x1 and x2 points. */ header: nodes.con, /** * ID of the start {@link Point} of the slice. */ x1: nodes.con, /** * ID of the end {@link Point} of the slice, if 0 then it is equal to x1. */ x2: nodes.con, /** * App specific type of the slice. For slices with "Marker" stacking * behavior, this is a path of block nesting. For other slices, it * specifies inline formatting, such as bold, italic, etc.; the value has * to be a primitive number or a string. * * Inline formatting is encoded as a single "con" node: * * ```ts * s.con('bold') * ``` * * The most basic one-level block split can be encoded as a single * "con" node: * * ```ts * s.con('p') * ``` * * Nested blocks are encoded as an "arr" node of "con" nodes or "vec" tuples. * The "con" nodes are when only the tag is specified, while the "vec" tuples * are used when the tag is accompanied by a discriminant and/or custom data * (attributes of the block). * * ```ts * s.vec([ * s.con('blockquote'), * s.con('p') * ]) * * s.vec([ * // * s.con('ul'), * * // * s.vec([ * s.con('li'), * s.con(1), // discriminant * ]), * * // * s.vec([ * s.con('p'), * s.con(0), // discriminant * s.obj({ // data * indent: 2, * }), * ]), * ]) * ``` */ type: nodes.con | nodes.arr | nodes.vec<[tag: nodes.con, discriminant: nodes.con, data: nodes.obj<{}>]>>, /** * Reference to additional metadata about the slice, usually an object. * Normally used for inline formatting, block formatting attaches data to * specific block tags in the steps of the `type` field. This field is * optional. */ data: nodes.obj<{}> ]>; /** * JSON CRDT node representation of the stored slices. */ export type SliceNode = SchemaToJsonNode; /** * The view of a stored slice. */ export type SliceView = JsonNodeView; /** * Parameters for updating a slice. */ export interface SliceUpdateParams { /** * When set, updates the stacking behavior of the slice. */ stacking?: SliceStacking; /** * When set, updates the type of the slice. */ type?: SliceType | NodeBuilder; /** * When set, overwrites the custom data of the slice. To edit the data more * granularly, use the `dataNode()` method of the slice instead, to get * access to the data node. */ data?: unknown; /** * When set, updates the range and endpoint anchors of the slice. */ range?: Range; }