@thomasfosterau/effect-richtext 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +48 -0
- package/README.md +118 -2
- package/dist/_virtual/_rolldown/runtime.js +12 -0
- package/dist/commands/commands.d.ts +323 -0
- package/dist/commands/commands.js +722 -0
- package/dist/commands/internal.js +43 -0
- package/dist/commands/keymaps.d.ts +46 -0
- package/dist/commands/keymaps.js +64 -0
- package/dist/commands.d.ts +3 -0
- package/dist/commands.js +3 -0
- package/dist/compat/commands.d.ts +250 -0
- package/dist/compat/commands.js +275 -0
- package/dist/compat/internal/core.d.ts +20 -0
- package/dist/compat/internal/core.js +148 -0
- package/dist/compat/internal/props.js +82 -0
- package/dist/compat/keymap.d.ts +21 -0
- package/dist/compat/keymap.js +38 -0
- package/dist/compat/model.d.ts +893 -0
- package/dist/compat/model.js +1212 -0
- package/dist/compat/orderedmap.d.ts +74 -0
- package/dist/compat/orderedmap.js +124 -0
- package/dist/compat/schema-basic.d.ts +38 -0
- package/dist/compat/schema-basic.js +238 -0
- package/dist/compat/schema-list.d.ts +81 -0
- package/dist/compat/schema-list.js +156 -0
- package/dist/compat/state.d.ts +415 -0
- package/dist/compat/state.js +689 -0
- package/dist/compat/test-builder.d.ts +98 -0
- package/dist/compat/test-builder.js +197 -0
- package/dist/compat/transform.d.ts +458 -0
- package/dist/compat/transform.js +803 -0
- package/dist/compat/view.d.ts +411 -0
- package/dist/compat/view.js +409 -0
- package/dist/dropcursor.d.ts +46 -0
- package/dist/dropcursor.js +176 -0
- package/dist/extensions/defaults.d.ts +716 -0
- package/dist/extensions/defaults.js +209 -0
- package/dist/extensions/editor.d.ts +246 -0
- package/dist/extensions/editor.js +271 -0
- package/dist/extensions/extension.d.ts +375 -0
- package/dist/extensions/extension.js +233 -0
- package/dist/extensions.d.ts +4 -0
- package/dist/extensions.js +4 -0
- package/dist/gapcursor.d.ts +66 -0
- package/dist/gapcursor.js +273 -0
- package/dist/history.d.ts +178 -0
- package/dist/history.js +412 -0
- package/dist/html.d.ts +158 -0
- package/dist/html.js +164 -0
- package/dist/inputrules.d.ts +271 -0
- package/dist/inputrules.js +321 -0
- package/dist/internal/attempt.js +15 -0
- package/dist/internal/json.js +29 -0
- package/dist/keymap/keymap.d.ts +130 -0
- package/dist/keymap/keymap.js +159 -0
- package/dist/keymap.d.ts +2 -0
- package/dist/keymap.js +1 -0
- package/dist/markdown/errors.d.ts +23 -0
- package/dist/markdown/errors.js +26 -0
- package/dist/markdown/from_markdown.d.ts +185 -0
- package/dist/markdown/from_markdown.js +266 -0
- package/dist/markdown/schema.d.ts +522 -0
- package/dist/markdown/schema.js +292 -0
- package/dist/markdown/to_markdown.d.ts +251 -0
- package/dist/markdown/to_markdown.js +413 -0
- package/dist/markdown.d.ts +5 -0
- package/dist/markdown.js +5 -0
- package/dist/model/attrsCodec.js +48 -0
- package/dist/model/comparedeep.js +17 -0
- package/dist/model/content.d.ts +232 -0
- package/dist/model/content.js +630 -0
- package/dist/model/diff.js +66 -0
- package/dist/model/dom.d.ts +3 -0
- package/dist/model/errors.d.ts +90 -0
- package/dist/model/errors.js +76 -0
- package/dist/model/fragment.d.ts +131 -0
- package/dist/model/fragment.js +262 -0
- package/dist/model/from_dom.d.ts +299 -0
- package/dist/model/from_dom.js +618 -0
- package/dist/model/json.d.ts +37 -0
- package/dist/model/json.js +126 -0
- package/dist/model/mark.d.ts +73 -0
- package/dist/model/mark.js +121 -0
- package/dist/model/node.d.ts +267 -0
- package/dist/model/node.js +434 -0
- package/dist/model/replace.d.ts +78 -0
- package/dist/model/replace.js +207 -0
- package/dist/model/resolvedpos.d.ts +196 -0
- package/dist/model/resolvedpos.js +305 -0
- package/dist/model/schema.d.ts +740 -0
- package/dist/model/schema.js +451 -0
- package/dist/model/to_dom.d.ts +169 -0
- package/dist/model/to_dom.js +238 -0
- package/dist/model.d.ts +12 -0
- package/dist/model.js +12 -0
- package/dist/placeholder.d.ts +53 -0
- package/dist/placeholder.js +79 -0
- package/dist/reactive/observer.d.ts +54 -0
- package/dist/reactive/observer.js +61 -0
- package/dist/reactive/selectors.d.ts +22 -0
- package/dist/reactive/selectors.js +61 -0
- package/dist/reactive/stateref.d.ts +72 -0
- package/dist/reactive/stateref.js +71 -0
- package/dist/reactive/streams.d.ts +83 -0
- package/dist/reactive/streams.js +85 -0
- package/dist/reactive.d.ts +16 -0
- package/dist/reactive.js +26 -0
- package/dist/schema-basic.d.ts +448 -0
- package/dist/schema-basic.js +269 -0
- package/dist/schema-list/commands.d.ts +66 -0
- package/dist/schema-list/commands.js +203 -0
- package/dist/schema-list.d.ts +92 -0
- package/dist/schema-list.js +100 -0
- package/dist/state/errors.d.ts +39 -0
- package/dist/state/errors.js +32 -0
- package/dist/state/plugin.d.ts +232 -0
- package/dist/state/plugin.js +82 -0
- package/dist/state/selection.d.ts +297 -0
- package/dist/state/selection.js +486 -0
- package/dist/state/state.d.ts +212 -0
- package/dist/state/state.js +489 -0
- package/dist/state/transaction.d.ts +145 -0
- package/dist/state/transaction.js +195 -0
- package/dist/state.d.ts +6 -0
- package/dist/state.js +6 -0
- package/dist/test-builder.d.ts +3582 -0
- package/dist/test-builder.js +239 -0
- package/dist/transform/attr_step.d.ts +60 -0
- package/dist/transform/attr_step.js +105 -0
- package/dist/transform/errors.d.ts +50 -0
- package/dist/transform/errors.js +35 -0
- package/dist/transform/map.d.ts +182 -0
- package/dist/transform/map.js +280 -0
- package/dist/transform/mark.js +98 -0
- package/dist/transform/mark_set_step.js +69 -0
- package/dist/transform/mark_step.d.ts +113 -0
- package/dist/transform/mark_step.js +225 -0
- package/dist/transform/replace.d.ts +18 -0
- package/dist/transform/replace.js +381 -0
- package/dist/transform/replace_step.d.ts +109 -0
- package/dist/transform/replace_step.js +175 -0
- package/dist/transform/step.d.ts +157 -0
- package/dist/transform/step.js +168 -0
- package/dist/transform/structure.d.ts +89 -0
- package/dist/transform/structure.js +350 -0
- package/dist/transform/transform.d.ts +248 -0
- package/dist/transform/transform.js +373 -0
- package/dist/transform.d.ts +10 -0
- package/dist/transform.js +10 -0
- package/dist/view/browser.js +39 -0
- package/dist/view/capturekeys.js +282 -0
- package/dist/view/clipboard.d.ts +8 -0
- package/dist/view/clipboard.js +245 -0
- package/dist/view/decoration.d.ts +339 -0
- package/dist/view/decoration.js +566 -0
- package/dist/view/dom.d.ts +18 -0
- package/dist/view/dom.js +140 -0
- package/dist/view/domchange.js +295 -0
- package/dist/view/domcoords.d.ts +22 -0
- package/dist/view/domcoords.js +448 -0
- package/dist/view/domobserver.d.ts +47 -0
- package/dist/view/domobserver.js +328 -0
- package/dist/view/errors.d.ts +18 -0
- package/dist/view/errors.js +21 -0
- package/dist/view/input.d.ts +58 -0
- package/dist/view/input.js +704 -0
- package/dist/view/selection.js +198 -0
- package/dist/view/view.d.ts +699 -0
- package/dist/view/view.js +623 -0
- package/dist/view/viewdesc.d.ts +236 -0
- package/dist/view/viewdesc.js +1205 -0
- package/dist/view-css.d.ts +43 -0
- package/dist/view-css.js +124 -0
- package/dist/view.d.ts +6 -0
- package/dist/view.js +4 -0
- package/package.json +206 -3
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { AnySchema } from "./model/schema.js";
|
|
2
|
+
import "./model.js";
|
|
3
|
+
import { Mapping, StepMap } from "./transform/map.js";
|
|
4
|
+
import { Step } from "./transform/step.js";
|
|
5
|
+
import { Transform } from "./transform/transform.js";
|
|
6
|
+
import "./state.js";
|
|
7
|
+
import { Dispatch, Transaction } from "./state/transaction.js";
|
|
8
|
+
import { SelectionBookmark } from "./state/selection.js";
|
|
9
|
+
import { EditorState } from "./state/state.js";
|
|
10
|
+
import { EditorViewLike, Plugin } from "./state/plugin.js";
|
|
11
|
+
import "./transform.js";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import RopeSequence from "rope-sequence";
|
|
14
|
+
interface PopResult {
|
|
15
|
+
readonly remaining: Branch;
|
|
16
|
+
readonly transform: Transaction<any>;
|
|
17
|
+
readonly selection: SelectionBookmark<any>;
|
|
18
|
+
}
|
|
19
|
+
/** @internal */
|
|
20
|
+
export declare class Branch {
|
|
21
|
+
readonly items: RopeSequence<Item>;
|
|
22
|
+
readonly eventCount: number;
|
|
23
|
+
constructor(items: RopeSequence<Item>, eventCount: number);
|
|
24
|
+
popEvent(state: EditorState<any, any, any>, preserveItems: boolean): PopResult | null;
|
|
25
|
+
addTransform(transform: Transform<any>, selection: SelectionBookmark<any> | undefined, histOptions: HistoryConfig, preserveItems: boolean): Branch;
|
|
26
|
+
remapping(from: number, to: number): Mapping;
|
|
27
|
+
addMaps(array: ReadonlyArray<StepMap>): Branch;
|
|
28
|
+
rebased(rebasedTransform: Transform<any>, rebasedCount: number): Branch;
|
|
29
|
+
emptyItemCount(): number;
|
|
30
|
+
compress(upto?: number): Branch;
|
|
31
|
+
static empty: Branch;
|
|
32
|
+
}
|
|
33
|
+
/** @internal */
|
|
34
|
+
export declare class Item {
|
|
35
|
+
readonly map: StepMap;
|
|
36
|
+
readonly step?: Step<any> | undefined;
|
|
37
|
+
readonly selection?: SelectionBookmark<any> | undefined;
|
|
38
|
+
readonly mirrorOffset?: number | undefined;
|
|
39
|
+
constructor(map: StepMap, step?: Step<any> | undefined, selection?: SelectionBookmark<any> | undefined, mirrorOffset?: number | undefined);
|
|
40
|
+
merge(other: Item): Item | undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The value of the state field that tracks undo/redo history for that
|
|
44
|
+
* state. Will be stored in the plugin state when the history plugin is
|
|
45
|
+
* active. Its contents are opaque.
|
|
46
|
+
*
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
* @category models
|
|
49
|
+
*/
|
|
50
|
+
export declare class HistoryState {
|
|
51
|
+
/** @internal */
|
|
52
|
+
readonly done: Branch;
|
|
53
|
+
/** @internal */
|
|
54
|
+
readonly undone: Branch;
|
|
55
|
+
/** @internal */
|
|
56
|
+
readonly prevRanges: ReadonlyArray<number> | null;
|
|
57
|
+
/** @internal */
|
|
58
|
+
readonly prevTime: number;
|
|
59
|
+
/** @internal */
|
|
60
|
+
readonly prevComposition: number;
|
|
61
|
+
/** @internal */
|
|
62
|
+
constructor(
|
|
63
|
+
/** @internal */
|
|
64
|
+
done: Branch,
|
|
65
|
+
/** @internal */
|
|
66
|
+
undone: Branch,
|
|
67
|
+
/** @internal */
|
|
68
|
+
prevRanges: ReadonlyArray<number> | null,
|
|
69
|
+
/** @internal */
|
|
70
|
+
prevTime: number,
|
|
71
|
+
/** @internal */
|
|
72
|
+
prevComposition: number);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Set a flag on the given transaction that will prevent further steps
|
|
76
|
+
* from being appended to an existing history event (so that they
|
|
77
|
+
* require a separate undo command to undo).
|
|
78
|
+
*
|
|
79
|
+
* @since 0.1.0
|
|
80
|
+
* @category transactions
|
|
81
|
+
*/
|
|
82
|
+
export declare const closeHistory: <Sc extends AnySchema>(tr: Transaction<Sc>) => Transaction<Sc>;
|
|
83
|
+
interface HistoryConfig {
|
|
84
|
+
readonly depth: number;
|
|
85
|
+
readonly newGroupDelay: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Options for the history plugin.
|
|
89
|
+
*
|
|
90
|
+
* @since 0.1.0
|
|
91
|
+
* @category models
|
|
92
|
+
*/
|
|
93
|
+
export interface HistoryOptions {
|
|
94
|
+
/**
|
|
95
|
+
* The amount of history events that are collected before the oldest
|
|
96
|
+
* events are discarded. Defaults to 100.
|
|
97
|
+
*/
|
|
98
|
+
readonly depth?: number | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* The delay between changes after which a new group should be
|
|
101
|
+
* started. Defaults to 500 (milliseconds). Note that when changes
|
|
102
|
+
* aren't adjacent, a new group is always started.
|
|
103
|
+
*/
|
|
104
|
+
readonly newGroupDelay?: number | undefined;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A command provided by this module. It works with any schema and
|
|
108
|
+
* needs no services.
|
|
109
|
+
*
|
|
110
|
+
* @since 0.1.0
|
|
111
|
+
* @category models
|
|
112
|
+
*/
|
|
113
|
+
export type HistoryCommand = <Sc extends AnySchema>(state: EditorState<Sc, any, any>, dispatch?: Dispatch<Sc>, view?: EditorViewLike) => Effect.Effect<boolean>;
|
|
114
|
+
/**
|
|
115
|
+
* Returns a plugin that enables the undo history for an editor. The
|
|
116
|
+
* plugin will track undo and redo stacks, which can be used with the
|
|
117
|
+
* `undo` and `redo` commands.
|
|
118
|
+
*
|
|
119
|
+
* You can set an `"addToHistory"` metadata property of `false` on a
|
|
120
|
+
* transaction to prevent it from being rolled back by undo.
|
|
121
|
+
*
|
|
122
|
+
* @since 0.1.0
|
|
123
|
+
* @category constructors
|
|
124
|
+
*/
|
|
125
|
+
export declare const history: (config?: HistoryOptions) => Plugin<HistoryState>;
|
|
126
|
+
/**
|
|
127
|
+
* A command that undoes the last change, if any.
|
|
128
|
+
*
|
|
129
|
+
* @since 0.1.0
|
|
130
|
+
* @category commands
|
|
131
|
+
*/
|
|
132
|
+
export declare const undo: HistoryCommand;
|
|
133
|
+
/**
|
|
134
|
+
* A command that redoes the last undone change, if any.
|
|
135
|
+
*
|
|
136
|
+
* @since 0.1.0
|
|
137
|
+
* @category commands
|
|
138
|
+
*/
|
|
139
|
+
export declare const redo: HistoryCommand;
|
|
140
|
+
/**
|
|
141
|
+
* A command that undoes the last change. Doesn't scroll the selection
|
|
142
|
+
* into view.
|
|
143
|
+
*
|
|
144
|
+
* @since 0.1.0
|
|
145
|
+
* @category commands
|
|
146
|
+
*/
|
|
147
|
+
export declare const undoNoScroll: HistoryCommand;
|
|
148
|
+
/**
|
|
149
|
+
* A command that redoes the last undone change. Doesn't scroll the
|
|
150
|
+
* selection into view.
|
|
151
|
+
*
|
|
152
|
+
* @since 0.1.0
|
|
153
|
+
* @category commands
|
|
154
|
+
*/
|
|
155
|
+
export declare const redoNoScroll: HistoryCommand;
|
|
156
|
+
/**
|
|
157
|
+
* The amount of undoable events available in a given state.
|
|
158
|
+
*
|
|
159
|
+
* @since 0.1.0
|
|
160
|
+
* @category getters
|
|
161
|
+
*/
|
|
162
|
+
export declare const undoDepth: (state: EditorState<any, any, any>) => number;
|
|
163
|
+
/**
|
|
164
|
+
* The amount of redoable events available in a given editor state.
|
|
165
|
+
*
|
|
166
|
+
* @since 0.1.0
|
|
167
|
+
* @category getters
|
|
168
|
+
*/
|
|
169
|
+
export declare const redoDepth: (state: EditorState<any, any, any>) => number;
|
|
170
|
+
/**
|
|
171
|
+
* Returns true if the given transaction was generated by the history
|
|
172
|
+
* plugin.
|
|
173
|
+
*
|
|
174
|
+
* @since 0.1.0
|
|
175
|
+
* @category guards
|
|
176
|
+
*/
|
|
177
|
+
export declare const isHistoryTransaction: (tr: Transaction<any>) => boolean;
|
|
178
|
+
export {};
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { Plugin, PluginKey } from "./state/plugin.js";
|
|
2
|
+
import { Mapping } from "./transform/map.js";
|
|
3
|
+
import * as Arr from "effect/Array";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
import RopeSequence from "rope-sequence";
|
|
7
|
+
// src/history.ts
|
|
8
|
+
/**
|
|
9
|
+
* An undo/redo history for the editor, ported from
|
|
10
|
+
* `prosemirror-history`.
|
|
11
|
+
*
|
|
12
|
+
* ```ts skip-type-checking
|
|
13
|
+
* const state = EditorState.createUnsafe({ schema, plugins: [history()] })
|
|
14
|
+
* // ...
|
|
15
|
+
* yield* undo(state, dispatch)
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @since 0.1.0
|
|
19
|
+
*/
|
|
20
|
+
const max_empty_items = 500;
|
|
21
|
+
const DEPTH_OVERFLOW = 20;
|
|
22
|
+
/** @internal */
|
|
23
|
+
var Branch = class Branch {
|
|
24
|
+
constructor(items, eventCount) {
|
|
25
|
+
this.items = items;
|
|
26
|
+
this.eventCount = eventCount;
|
|
27
|
+
}
|
|
28
|
+
popEvent(state, preserveItems) {
|
|
29
|
+
if (this.eventCount === 0) return null;
|
|
30
|
+
let end = this.items.length;
|
|
31
|
+
for (;; end--) if (this.items.get(end - 1).selection) {
|
|
32
|
+
--end;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
let remap, mapFrom;
|
|
36
|
+
if (preserveItems) {
|
|
37
|
+
remap = this.remapping(end, this.items.length);
|
|
38
|
+
mapFrom = remap.maps.length;
|
|
39
|
+
}
|
|
40
|
+
const transform = state.tr;
|
|
41
|
+
let selection, remaining;
|
|
42
|
+
const addAfter = [], addBefore = [];
|
|
43
|
+
this.items.forEach((item, i) => {
|
|
44
|
+
if (!item.step) {
|
|
45
|
+
if (!remap) {
|
|
46
|
+
remap = this.remapping(end, i + 1);
|
|
47
|
+
mapFrom = remap.maps.length;
|
|
48
|
+
}
|
|
49
|
+
mapFrom--;
|
|
50
|
+
addBefore.push(item);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (remap) {
|
|
54
|
+
addBefore.push(new Item(item.map));
|
|
55
|
+
const step = Option.getOrNull(item.step.map(remap.slice(mapFrom)));
|
|
56
|
+
let map;
|
|
57
|
+
if (step && transform.maybeStep(step).docOrNull) {
|
|
58
|
+
map = transform.mapping.maps[transform.mapping.maps.length - 1];
|
|
59
|
+
addAfter.push(new Item(map, void 0, void 0, addAfter.length + addBefore.length));
|
|
60
|
+
}
|
|
61
|
+
mapFrom--;
|
|
62
|
+
if (map) remap.appendMap(map, mapFrom);
|
|
63
|
+
} else transform.maybeStep(item.step);
|
|
64
|
+
if (item.selection) {
|
|
65
|
+
selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
|
|
66
|
+
remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}, this.items.length, 0);
|
|
70
|
+
return {
|
|
71
|
+
remaining,
|
|
72
|
+
transform,
|
|
73
|
+
selection
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
addTransform(transform, selection, histOptions, preserveItems) {
|
|
77
|
+
const newItems = [];
|
|
78
|
+
let eventCount = this.eventCount;
|
|
79
|
+
let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
|
|
80
|
+
for (let i = 0; i < transform.steps.length; i++) {
|
|
81
|
+
const step = transform.steps[i].invert(transform.docs[i]);
|
|
82
|
+
let item = new Item(transform.mapping.maps[i], step, selection);
|
|
83
|
+
const merged = lastItem && lastItem.merge(item);
|
|
84
|
+
if (merged) {
|
|
85
|
+
item = merged;
|
|
86
|
+
if (i) newItems.pop();
|
|
87
|
+
else oldItems = oldItems.slice(0, oldItems.length - 1);
|
|
88
|
+
}
|
|
89
|
+
newItems.push(item);
|
|
90
|
+
if (selection) {
|
|
91
|
+
eventCount++;
|
|
92
|
+
selection = void 0;
|
|
93
|
+
}
|
|
94
|
+
if (!preserveItems) lastItem = item;
|
|
95
|
+
}
|
|
96
|
+
const overflow = eventCount - histOptions.depth;
|
|
97
|
+
if (overflow > DEPTH_OVERFLOW) {
|
|
98
|
+
oldItems = cutOffEvents(oldItems, overflow);
|
|
99
|
+
eventCount -= overflow;
|
|
100
|
+
}
|
|
101
|
+
return new Branch(oldItems.append(newItems), eventCount);
|
|
102
|
+
}
|
|
103
|
+
remapping(from, to) {
|
|
104
|
+
const maps = new Mapping();
|
|
105
|
+
this.items.forEach((item, i) => {
|
|
106
|
+
const mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from ? maps.maps.length - item.mirrorOffset : void 0;
|
|
107
|
+
maps.appendMap(item.map, mirrorPos);
|
|
108
|
+
}, from, to);
|
|
109
|
+
return maps;
|
|
110
|
+
}
|
|
111
|
+
addMaps(array) {
|
|
112
|
+
if (this.eventCount === 0) return this;
|
|
113
|
+
return new Branch(this.items.append(array.map((map) => new Item(map))), this.eventCount);
|
|
114
|
+
}
|
|
115
|
+
rebased(rebasedTransform, rebasedCount) {
|
|
116
|
+
if (!this.eventCount) return this;
|
|
117
|
+
const count = Math.min(this.items.length, rebasedCount);
|
|
118
|
+
const rebasedItems = [], start = this.items.length - count;
|
|
119
|
+
const mapping = rebasedTransform.mapping;
|
|
120
|
+
let newUntil = rebasedTransform.steps.length;
|
|
121
|
+
let eventCount = this.eventCount;
|
|
122
|
+
this.items.forEach((item) => {
|
|
123
|
+
if (item.selection) eventCount--;
|
|
124
|
+
}, start);
|
|
125
|
+
let iRebased = count;
|
|
126
|
+
this.items.forEach((item) => {
|
|
127
|
+
const pos = mapping.getMirrorOrUndefined(--iRebased);
|
|
128
|
+
if (pos == null) return;
|
|
129
|
+
newUntil = Math.min(newUntil, pos);
|
|
130
|
+
const map = mapping.maps[pos];
|
|
131
|
+
if (item.step) {
|
|
132
|
+
const step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
|
|
133
|
+
const selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
|
|
134
|
+
if (selection) eventCount++;
|
|
135
|
+
rebasedItems.push(new Item(map, step, selection));
|
|
136
|
+
} else rebasedItems.push(new Item(map));
|
|
137
|
+
}, start);
|
|
138
|
+
const newMaps = [];
|
|
139
|
+
for (let i = count; i < newUntil; i++) newMaps.push(new Item(mapping.maps[i]));
|
|
140
|
+
const items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
|
|
141
|
+
let branch = new Branch(items, eventCount);
|
|
142
|
+
if (branch.emptyItemCount() > max_empty_items) branch = branch.compress(this.items.length - rebasedItems.length);
|
|
143
|
+
return branch;
|
|
144
|
+
}
|
|
145
|
+
emptyItemCount() {
|
|
146
|
+
let count = 0;
|
|
147
|
+
this.items.forEach((item) => {
|
|
148
|
+
if (!item.step) count++;
|
|
149
|
+
});
|
|
150
|
+
return count;
|
|
151
|
+
}
|
|
152
|
+
compress(upto = this.items.length) {
|
|
153
|
+
const remap = this.remapping(0, upto);
|
|
154
|
+
let mapFrom = remap.maps.length;
|
|
155
|
+
const items = [];
|
|
156
|
+
let events = 0;
|
|
157
|
+
this.items.forEach((item, i) => {
|
|
158
|
+
if (i >= upto) {
|
|
159
|
+
items.push(item);
|
|
160
|
+
if (item.selection) events++;
|
|
161
|
+
} else if (item.step) {
|
|
162
|
+
const step = Option.getOrNull(item.step.map(remap.slice(mapFrom))), map = step && step.getMap();
|
|
163
|
+
mapFrom--;
|
|
164
|
+
if (map) remap.appendMap(map, mapFrom);
|
|
165
|
+
if (step) {
|
|
166
|
+
const selection = item.selection && item.selection.map(remap.slice(mapFrom));
|
|
167
|
+
if (selection) events++;
|
|
168
|
+
const newItem = new Item(map.invert(), step, selection), last = items.length - 1;
|
|
169
|
+
const merged = items.length ? items[last].merge(newItem) : void 0;
|
|
170
|
+
if (merged) items[last] = merged;
|
|
171
|
+
else items.push(newItem);
|
|
172
|
+
}
|
|
173
|
+
} else if (item.map) mapFrom--;
|
|
174
|
+
}, this.items.length, 0);
|
|
175
|
+
return new Branch(RopeSequence.from(items.reverse()), events);
|
|
176
|
+
}
|
|
177
|
+
static {
|
|
178
|
+
this.empty = new Branch(RopeSequence.empty, 0);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
function cutOffEvents(items, n) {
|
|
182
|
+
let cutPoint;
|
|
183
|
+
items.forEach((item, i) => {
|
|
184
|
+
if (item.selection && n-- === 0) {
|
|
185
|
+
cutPoint = i;
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
return items.slice(cutPoint);
|
|
190
|
+
}
|
|
191
|
+
/** @internal */
|
|
192
|
+
var Item = class Item {
|
|
193
|
+
constructor(map, step, selection, mirrorOffset) {
|
|
194
|
+
this.map = map;
|
|
195
|
+
this.step = step;
|
|
196
|
+
this.selection = selection;
|
|
197
|
+
this.mirrorOffset = mirrorOffset;
|
|
198
|
+
}
|
|
199
|
+
merge(other) {
|
|
200
|
+
if (this.step && other.step && !other.selection) {
|
|
201
|
+
const step = Option.getOrNull(other.step.merge(this.step));
|
|
202
|
+
if (step) return new Item(step.getMap().invert(), step, this.selection);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* The value of the state field that tracks undo/redo history for that
|
|
208
|
+
* state. Will be stored in the plugin state when the history plugin is
|
|
209
|
+
* active. Its contents are opaque.
|
|
210
|
+
*
|
|
211
|
+
* @since 0.1.0
|
|
212
|
+
* @category models
|
|
213
|
+
*/
|
|
214
|
+
var HistoryState = class {
|
|
215
|
+
/** @internal */
|
|
216
|
+
constructor(done, undone, prevRanges, prevTime, prevComposition) {
|
|
217
|
+
this.done = done;
|
|
218
|
+
this.undone = undone;
|
|
219
|
+
this.prevRanges = prevRanges;
|
|
220
|
+
this.prevTime = prevTime;
|
|
221
|
+
this.prevComposition = prevComposition;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const meta = (tr, key) => Option.getOrUndefined(tr.getMeta(key));
|
|
225
|
+
function applyTransaction(history, state, tr, options) {
|
|
226
|
+
const historyTr = meta(tr, historyKey);
|
|
227
|
+
if (historyTr) return historyTr.historyState;
|
|
228
|
+
if (meta(tr, closeHistoryKey)) history = new HistoryState(history.done, history.undone, null, 0, -1);
|
|
229
|
+
const appended = meta(tr, "appendedTransaction");
|
|
230
|
+
let rebased;
|
|
231
|
+
if (Arr.isReadonlyArrayEmpty(tr.steps)) return history;
|
|
232
|
+
else if (appended && meta(appended, historyKey)) {
|
|
233
|
+
if (meta(appended, historyKey).redo) return new HistoryState(history.done.addTransform(tr, void 0, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
|
|
234
|
+
else return new HistoryState(history.done, history.undone.addTransform(tr, void 0, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
|
|
235
|
+
} else if (meta(tr, "addToHistory") !== false && !(appended && meta(appended, "addToHistory") === false)) {
|
|
236
|
+
const composition = meta(tr, "composition");
|
|
237
|
+
const newGroup = history.prevTime === 0 || !appended && history.prevComposition !== composition && (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges));
|
|
238
|
+
const prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
|
|
239
|
+
return new HistoryState(history.done.addTransform(tr, newGroup ? state.selection.getBookmark() : void 0, options, mustPreserveItems(state)), Branch.empty, prevRanges, tr.time, composition == null ? history.prevComposition : composition);
|
|
240
|
+
} else if (rebased = meta(tr, "rebased")) return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
|
|
241
|
+
else return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
|
|
242
|
+
}
|
|
243
|
+
function isAdjacentTo(transform, prevRanges) {
|
|
244
|
+
if (!prevRanges) return false;
|
|
245
|
+
if (!transform.docChanged) return true;
|
|
246
|
+
let adjacent = false;
|
|
247
|
+
transform.mapping.maps[0].forEach((start, end) => {
|
|
248
|
+
for (let i = 0; i < prevRanges.length; i += 2) if (start <= prevRanges[i + 1] && end >= prevRanges[i]) adjacent = true;
|
|
249
|
+
});
|
|
250
|
+
return adjacent;
|
|
251
|
+
}
|
|
252
|
+
function rangesFor(maps) {
|
|
253
|
+
const result = [];
|
|
254
|
+
for (let i = maps.length - 1; i >= 0; i--) {
|
|
255
|
+
maps[i].forEach((_from, _to, from, to) => result.push(from, to));
|
|
256
|
+
if (Arr.isArrayNonEmpty(result)) break;
|
|
257
|
+
}
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
function mapRanges(ranges, mapping) {
|
|
261
|
+
if (!ranges) return null;
|
|
262
|
+
const result = [];
|
|
263
|
+
for (let i = 0; i < ranges.length; i += 2) {
|
|
264
|
+
const from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
|
|
265
|
+
if (from <= to) result.push(from, to);
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
function histTransaction(history, state, redo) {
|
|
270
|
+
const preserveItems = mustPreserveItems(state);
|
|
271
|
+
const plugin = Option.getOrUndefined(historyKey.get(state));
|
|
272
|
+
if (!plugin) return null;
|
|
273
|
+
const histOptions = plugin.spec.config;
|
|
274
|
+
const pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
|
|
275
|
+
if (!pop) return null;
|
|
276
|
+
const selection = pop.selection.resolve(pop.transform.doc);
|
|
277
|
+
const added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
|
|
278
|
+
const newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
|
|
279
|
+
return pop.transform.setSelectionUnsafe(selection).setMeta(historyKey, {
|
|
280
|
+
redo,
|
|
281
|
+
historyState: newHist
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
let cachedPreserveItems = false;
|
|
285
|
+
let cachedPreserveItemsPlugins = null;
|
|
286
|
+
function mustPreserveItems(state) {
|
|
287
|
+
const plugins = state.plugins;
|
|
288
|
+
if (cachedPreserveItemsPlugins !== plugins) {
|
|
289
|
+
cachedPreserveItems = false;
|
|
290
|
+
cachedPreserveItemsPlugins = plugins;
|
|
291
|
+
for (let i = 0; i < plugins.length; i++) if (plugins[i].spec.historyPreserveItems) {
|
|
292
|
+
cachedPreserveItems = true;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return cachedPreserveItems;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Set a flag on the given transaction that will prevent further steps
|
|
300
|
+
* from being appended to an existing history event (so that they
|
|
301
|
+
* require a separate undo command to undo).
|
|
302
|
+
*
|
|
303
|
+
* @since 0.1.0
|
|
304
|
+
* @category transactions
|
|
305
|
+
*/
|
|
306
|
+
const closeHistory = (tr) => tr.setMeta(closeHistoryKey, true);
|
|
307
|
+
const historyKey = new PluginKey("history");
|
|
308
|
+
const closeHistoryKey = new PluginKey("closeHistory");
|
|
309
|
+
/**
|
|
310
|
+
* Returns a plugin that enables the undo history for an editor. The
|
|
311
|
+
* plugin will track undo and redo stacks, which can be used with the
|
|
312
|
+
* `undo` and `redo` commands.
|
|
313
|
+
*
|
|
314
|
+
* You can set an `"addToHistory"` metadata property of `false` on a
|
|
315
|
+
* transaction to prevent it from being rolled back by undo.
|
|
316
|
+
*
|
|
317
|
+
* @since 0.1.0
|
|
318
|
+
* @category constructors
|
|
319
|
+
*/
|
|
320
|
+
const history = (config = {}) => {
|
|
321
|
+
const options = {
|
|
322
|
+
depth: config.depth || 100,
|
|
323
|
+
newGroupDelay: config.newGroupDelay || 500
|
|
324
|
+
};
|
|
325
|
+
return new Plugin({
|
|
326
|
+
key: historyKey,
|
|
327
|
+
state: {
|
|
328
|
+
init() {
|
|
329
|
+
return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
|
|
330
|
+
},
|
|
331
|
+
apply(tr, hist, state) {
|
|
332
|
+
return applyTransaction(hist, state, tr, options);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
config: options,
|
|
336
|
+
props: { handleDOMEvents: { beforeinput(view, e) {
|
|
337
|
+
const inputType = e.inputType;
|
|
338
|
+
const command = inputType === "historyUndo" ? undo : inputType === "historyRedo" ? redo : null;
|
|
339
|
+
if (!command || !view.editable) return false;
|
|
340
|
+
e.preventDefault();
|
|
341
|
+
return command(view.state, view.dispatch);
|
|
342
|
+
} } }
|
|
343
|
+
});
|
|
344
|
+
};
|
|
345
|
+
const buildCommand = (redo, scroll) => (state, dispatch) => Effect.suspend(() => {
|
|
346
|
+
const hist = Option.getOrUndefined(historyKey.getState(state));
|
|
347
|
+
if (!hist || (redo ? hist.undone : hist.done).eventCount === 0) return Effect.succeed(false);
|
|
348
|
+
if (dispatch) {
|
|
349
|
+
const tr = histTransaction(hist, state, redo);
|
|
350
|
+
if (tr) return Effect.as(dispatch(scroll ? tr.scrollIntoView() : tr), true);
|
|
351
|
+
}
|
|
352
|
+
return Effect.succeed(true);
|
|
353
|
+
});
|
|
354
|
+
/**
|
|
355
|
+
* A command that undoes the last change, if any.
|
|
356
|
+
*
|
|
357
|
+
* @since 0.1.0
|
|
358
|
+
* @category commands
|
|
359
|
+
*/
|
|
360
|
+
const undo = buildCommand(false, true);
|
|
361
|
+
/**
|
|
362
|
+
* A command that redoes the last undone change, if any.
|
|
363
|
+
*
|
|
364
|
+
* @since 0.1.0
|
|
365
|
+
* @category commands
|
|
366
|
+
*/
|
|
367
|
+
const redo = buildCommand(true, true);
|
|
368
|
+
/**
|
|
369
|
+
* A command that undoes the last change. Doesn't scroll the selection
|
|
370
|
+
* into view.
|
|
371
|
+
*
|
|
372
|
+
* @since 0.1.0
|
|
373
|
+
* @category commands
|
|
374
|
+
*/
|
|
375
|
+
const undoNoScroll = buildCommand(false, false);
|
|
376
|
+
/**
|
|
377
|
+
* A command that redoes the last undone change. Doesn't scroll the
|
|
378
|
+
* selection into view.
|
|
379
|
+
*
|
|
380
|
+
* @since 0.1.0
|
|
381
|
+
* @category commands
|
|
382
|
+
*/
|
|
383
|
+
const redoNoScroll = buildCommand(true, false);
|
|
384
|
+
/**
|
|
385
|
+
* The amount of undoable events available in a given state.
|
|
386
|
+
*
|
|
387
|
+
* @since 0.1.0
|
|
388
|
+
* @category getters
|
|
389
|
+
*/
|
|
390
|
+
const undoDepth = (state) => {
|
|
391
|
+
const hist = Option.getOrUndefined(historyKey.getState(state));
|
|
392
|
+
return hist ? hist.done.eventCount : 0;
|
|
393
|
+
};
|
|
394
|
+
/**
|
|
395
|
+
* The amount of redoable events available in a given editor state.
|
|
396
|
+
*
|
|
397
|
+
* @since 0.1.0
|
|
398
|
+
* @category getters
|
|
399
|
+
*/
|
|
400
|
+
const redoDepth = (state) => {
|
|
401
|
+
const hist = Option.getOrUndefined(historyKey.getState(state));
|
|
402
|
+
return hist ? hist.undone.eventCount : 0;
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* Returns true if the given transaction was generated by the history
|
|
406
|
+
* plugin.
|
|
407
|
+
*
|
|
408
|
+
* @since 0.1.0
|
|
409
|
+
* @category guards
|
|
410
|
+
*/
|
|
411
|
+
const isHistoryTransaction = (tr) => Option.isSome(tr.getMeta(historyKey));
|
|
412
|
+
export { Branch, HistoryState, Item, closeHistory, history, isHistoryTransaction, redo, redoDepth, redoNoScroll, undo, undoDepth, undoNoScroll };
|