@thomasfosterau/effect-richtext 0.0.0 → 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.
Files changed (176) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +117 -1
  3. package/dist/_virtual/_rolldown/runtime.js +12 -0
  4. package/dist/commands/commands.d.ts +323 -0
  5. package/dist/commands/commands.js +722 -0
  6. package/dist/commands/internal.js +43 -0
  7. package/dist/commands/keymaps.d.ts +46 -0
  8. package/dist/commands/keymaps.js +64 -0
  9. package/dist/commands.d.ts +3 -0
  10. package/dist/commands.js +3 -0
  11. package/dist/compat/commands.d.ts +250 -0
  12. package/dist/compat/commands.js +275 -0
  13. package/dist/compat/internal/core.d.ts +20 -0
  14. package/dist/compat/internal/core.js +148 -0
  15. package/dist/compat/internal/props.js +82 -0
  16. package/dist/compat/keymap.d.ts +21 -0
  17. package/dist/compat/keymap.js +38 -0
  18. package/dist/compat/model.d.ts +893 -0
  19. package/dist/compat/model.js +1212 -0
  20. package/dist/compat/orderedmap.d.ts +74 -0
  21. package/dist/compat/orderedmap.js +124 -0
  22. package/dist/compat/schema-basic.d.ts +38 -0
  23. package/dist/compat/schema-basic.js +238 -0
  24. package/dist/compat/schema-list.d.ts +81 -0
  25. package/dist/compat/schema-list.js +156 -0
  26. package/dist/compat/state.d.ts +415 -0
  27. package/dist/compat/state.js +689 -0
  28. package/dist/compat/test-builder.d.ts +98 -0
  29. package/dist/compat/test-builder.js +197 -0
  30. package/dist/compat/transform.d.ts +458 -0
  31. package/dist/compat/transform.js +803 -0
  32. package/dist/compat/view.d.ts +411 -0
  33. package/dist/compat/view.js +409 -0
  34. package/dist/dropcursor.d.ts +46 -0
  35. package/dist/dropcursor.js +176 -0
  36. package/dist/extensions/defaults.d.ts +716 -0
  37. package/dist/extensions/defaults.js +209 -0
  38. package/dist/extensions/editor.d.ts +246 -0
  39. package/dist/extensions/editor.js +271 -0
  40. package/dist/extensions/extension.d.ts +375 -0
  41. package/dist/extensions/extension.js +233 -0
  42. package/dist/extensions.d.ts +4 -0
  43. package/dist/extensions.js +4 -0
  44. package/dist/gapcursor.d.ts +66 -0
  45. package/dist/gapcursor.js +273 -0
  46. package/dist/history.d.ts +178 -0
  47. package/dist/history.js +412 -0
  48. package/dist/html.d.ts +158 -0
  49. package/dist/html.js +164 -0
  50. package/dist/inputrules.d.ts +271 -0
  51. package/dist/inputrules.js +321 -0
  52. package/dist/internal/attempt.js +15 -0
  53. package/dist/internal/json.js +29 -0
  54. package/dist/keymap/keymap.d.ts +130 -0
  55. package/dist/keymap/keymap.js +159 -0
  56. package/dist/keymap.d.ts +2 -0
  57. package/dist/keymap.js +1 -0
  58. package/dist/markdown/errors.d.ts +23 -0
  59. package/dist/markdown/errors.js +26 -0
  60. package/dist/markdown/from_markdown.d.ts +185 -0
  61. package/dist/markdown/from_markdown.js +266 -0
  62. package/dist/markdown/schema.d.ts +522 -0
  63. package/dist/markdown/schema.js +292 -0
  64. package/dist/markdown/to_markdown.d.ts +251 -0
  65. package/dist/markdown/to_markdown.js +413 -0
  66. package/dist/markdown.d.ts +5 -0
  67. package/dist/markdown.js +5 -0
  68. package/dist/model/attrsCodec.js +48 -0
  69. package/dist/model/comparedeep.js +17 -0
  70. package/dist/model/content.d.ts +232 -0
  71. package/dist/model/content.js +630 -0
  72. package/dist/model/diff.js +66 -0
  73. package/dist/model/dom.d.ts +3 -0
  74. package/dist/model/errors.d.ts +90 -0
  75. package/dist/model/errors.js +76 -0
  76. package/dist/model/fragment.d.ts +131 -0
  77. package/dist/model/fragment.js +262 -0
  78. package/dist/model/from_dom.d.ts +299 -0
  79. package/dist/model/from_dom.js +618 -0
  80. package/dist/model/json.d.ts +37 -0
  81. package/dist/model/json.js +126 -0
  82. package/dist/model/mark.d.ts +73 -0
  83. package/dist/model/mark.js +121 -0
  84. package/dist/model/node.d.ts +267 -0
  85. package/dist/model/node.js +434 -0
  86. package/dist/model/replace.d.ts +78 -0
  87. package/dist/model/replace.js +207 -0
  88. package/dist/model/resolvedpos.d.ts +196 -0
  89. package/dist/model/resolvedpos.js +305 -0
  90. package/dist/model/schema.d.ts +740 -0
  91. package/dist/model/schema.js +451 -0
  92. package/dist/model/to_dom.d.ts +169 -0
  93. package/dist/model/to_dom.js +238 -0
  94. package/dist/model.d.ts +12 -0
  95. package/dist/model.js +12 -0
  96. package/dist/placeholder.d.ts +53 -0
  97. package/dist/placeholder.js +79 -0
  98. package/dist/reactive/observer.d.ts +54 -0
  99. package/dist/reactive/observer.js +61 -0
  100. package/dist/reactive/selectors.d.ts +22 -0
  101. package/dist/reactive/selectors.js +61 -0
  102. package/dist/reactive/stateref.d.ts +72 -0
  103. package/dist/reactive/stateref.js +71 -0
  104. package/dist/reactive/streams.d.ts +83 -0
  105. package/dist/reactive/streams.js +85 -0
  106. package/dist/reactive.d.ts +16 -0
  107. package/dist/reactive.js +26 -0
  108. package/dist/schema-basic.d.ts +448 -0
  109. package/dist/schema-basic.js +269 -0
  110. package/dist/schema-list/commands.d.ts +66 -0
  111. package/dist/schema-list/commands.js +203 -0
  112. package/dist/schema-list.d.ts +92 -0
  113. package/dist/schema-list.js +100 -0
  114. package/dist/state/errors.d.ts +39 -0
  115. package/dist/state/errors.js +32 -0
  116. package/dist/state/plugin.d.ts +232 -0
  117. package/dist/state/plugin.js +82 -0
  118. package/dist/state/selection.d.ts +297 -0
  119. package/dist/state/selection.js +486 -0
  120. package/dist/state/state.d.ts +212 -0
  121. package/dist/state/state.js +489 -0
  122. package/dist/state/transaction.d.ts +145 -0
  123. package/dist/state/transaction.js +195 -0
  124. package/dist/state.d.ts +6 -0
  125. package/dist/state.js +6 -0
  126. package/dist/test-builder.d.ts +3582 -0
  127. package/dist/test-builder.js +239 -0
  128. package/dist/transform/attr_step.d.ts +60 -0
  129. package/dist/transform/attr_step.js +105 -0
  130. package/dist/transform/errors.d.ts +50 -0
  131. package/dist/transform/errors.js +35 -0
  132. package/dist/transform/map.d.ts +182 -0
  133. package/dist/transform/map.js +280 -0
  134. package/dist/transform/mark.js +98 -0
  135. package/dist/transform/mark_set_step.js +69 -0
  136. package/dist/transform/mark_step.d.ts +113 -0
  137. package/dist/transform/mark_step.js +225 -0
  138. package/dist/transform/replace.d.ts +18 -0
  139. package/dist/transform/replace.js +381 -0
  140. package/dist/transform/replace_step.d.ts +109 -0
  141. package/dist/transform/replace_step.js +175 -0
  142. package/dist/transform/step.d.ts +157 -0
  143. package/dist/transform/step.js +168 -0
  144. package/dist/transform/structure.d.ts +89 -0
  145. package/dist/transform/structure.js +350 -0
  146. package/dist/transform/transform.d.ts +248 -0
  147. package/dist/transform/transform.js +373 -0
  148. package/dist/transform.d.ts +10 -0
  149. package/dist/transform.js +10 -0
  150. package/dist/view/browser.js +39 -0
  151. package/dist/view/capturekeys.js +282 -0
  152. package/dist/view/clipboard.d.ts +8 -0
  153. package/dist/view/clipboard.js +245 -0
  154. package/dist/view/decoration.d.ts +339 -0
  155. package/dist/view/decoration.js +566 -0
  156. package/dist/view/dom.d.ts +18 -0
  157. package/dist/view/dom.js +140 -0
  158. package/dist/view/domchange.js +295 -0
  159. package/dist/view/domcoords.d.ts +22 -0
  160. package/dist/view/domcoords.js +448 -0
  161. package/dist/view/domobserver.d.ts +47 -0
  162. package/dist/view/domobserver.js +328 -0
  163. package/dist/view/errors.d.ts +18 -0
  164. package/dist/view/errors.js +21 -0
  165. package/dist/view/input.d.ts +58 -0
  166. package/dist/view/input.js +704 -0
  167. package/dist/view/selection.js +198 -0
  168. package/dist/view/view.d.ts +699 -0
  169. package/dist/view/view.js +623 -0
  170. package/dist/view/viewdesc.d.ts +236 -0
  171. package/dist/view/viewdesc.js +1205 -0
  172. package/dist/view-css.d.ts +43 -0
  173. package/dist/view-css.js +124 -0
  174. package/dist/view.d.ts +6 -0
  175. package/dist/view.js +4 -0
  176. package/package.json +200 -4
@@ -0,0 +1,225 @@
1
+ import { Fragment } from "../model/fragment.js";
2
+ import { JSONError } from "../model/errors.js";
3
+ import { Mark } from "../model/mark.js";
4
+ import { Slice } from "../model/replace.js";
5
+ import { markStepGroup, pushMarkStep } from "./mark_set_step.js";
6
+ import { Step, StepResult } from "./step.js";
7
+ import * as Option from "effect/Option";
8
+ import * as Predicate from "effect/Predicate";
9
+ // src/transform/mark_step.ts
10
+ /**
11
+ * Mark steps.
12
+ *
13
+ * @since 0.1.0
14
+ */
15
+ function mapFragment(fragment, f, parent) {
16
+ const mapped = [];
17
+ for (let i = 0; i < fragment.childCount; i++) {
18
+ let child = fragment.content[i];
19
+ if (child.content.size) child = child.copy(mapFragment(child.content, f, child));
20
+ if (child.isInline) child = f(child, parent, i);
21
+ mapped.push(child);
22
+ }
23
+ return Fragment.fromArray(mapped);
24
+ }
25
+ function replaceMarked(doc, from, to, parent, f) {
26
+ const oldSlice = doc.sliceUnsafe(from, to);
27
+ const slice = new Slice(mapFragment(oldSlice.content, f, parent), oldSlice.openStart, oldSlice.openEnd);
28
+ return StepResult.fromReplace(doc, from, to, slice);
29
+ }
30
+ function invertSteps(doc, from, to, visit) {
31
+ const steps = [];
32
+ doc.nodesBetween(from, to, (node, pos) => {
33
+ if (node.isInline && node.isAtom) visit(node, Math.max(from, pos), Math.min(to, pos + node.nodeSize), steps);
34
+ });
35
+ return markStepGroup(steps);
36
+ }
37
+ const mapMarkRange = (mapping, from, to) => {
38
+ const mappedFrom = mapping.map(from, 1), mappedTo = mapping.map(to, -1);
39
+ return mappedFrom >= mappedTo ? Option.none() : Option.some([mappedFrom, mappedTo]);
40
+ };
41
+ /**
42
+ * Add a mark to all inline content between two positions.
43
+ *
44
+ * @since 0.1.0
45
+ * @category steps
46
+ */
47
+ var AddMarkStep = class AddMarkStep extends Step {
48
+ /** Create a mark step. */
49
+ constructor(from, to, mark) {
50
+ super();
51
+ this.from = from;
52
+ this.to = to;
53
+ this.mark = mark;
54
+ }
55
+ apply(doc) {
56
+ const $from = doc.resolveUnsafe(this.from);
57
+ return replaceMarked(doc, this.from, this.to, $from.node($from.sharedDepth(this.to)), (node, parent) => !node.isAtom || !parent.type.allowsMarkType(this.mark.type) ? node : node.mark(this.mark.addToSet(node.marks)));
58
+ }
59
+ invert(doc) {
60
+ return invertSteps(doc, this.from, this.to, (node, from, to, steps) => {
61
+ const added = this.mark.addToSet(node.marks);
62
+ if (Mark.sameSet(added, node.marks)) return;
63
+ pushMarkStep(RemoveMarkStep, from, to, this.mark, steps);
64
+ node.marks.forEach((mark) => {
65
+ if (!mark.isInSet(added)) pushMarkStep(AddMarkStep, from, to, mark, steps);
66
+ });
67
+ });
68
+ }
69
+ map(mapping) {
70
+ return Option.map(mapMarkRange(mapping, this.from, this.to), ([from, to]) => new AddMarkStep(from, to, this.mark));
71
+ }
72
+ merge(other) {
73
+ if (other instanceof AddMarkStep && other.mark.eq(this.mark) && this.from <= other.to && this.to >= other.from) return Option.some(new AddMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark));
74
+ return Option.none();
75
+ }
76
+ toJSON() {
77
+ return {
78
+ stepType: "addMark",
79
+ mark: this.mark.toJSON(),
80
+ from: this.from,
81
+ to: this.to
82
+ };
83
+ }
84
+ /** @internal */
85
+ static fromJSONUnsafe(schema, json) {
86
+ if (!Predicate.isNumber(json.from) || !Predicate.isNumber(json.to)) throw new JSONError({ message: "Invalid input for AddMarkStep.fromJSON" });
87
+ return new AddMarkStep(json.from, json.to, schema.markFromJSONUnsafe(json.mark));
88
+ }
89
+ };
90
+ Step.jsonID("addMark", AddMarkStep);
91
+ /**
92
+ * Remove a mark from all inline content between two positions.
93
+ *
94
+ * @since 0.1.0
95
+ * @category steps
96
+ */
97
+ var RemoveMarkStep = class RemoveMarkStep extends Step {
98
+ /** Create a mark-removing step. */
99
+ constructor(from, to, mark) {
100
+ super();
101
+ this.from = from;
102
+ this.to = to;
103
+ this.mark = mark;
104
+ }
105
+ apply(doc) {
106
+ return replaceMarked(doc, this.from, this.to, doc, (node) => node.mark(this.mark.removeFromSet(node.marks)));
107
+ }
108
+ invert(doc) {
109
+ return invertSteps(doc, this.from, this.to, (node, from, to, steps) => {
110
+ if (this.mark.isInSet(node.marks)) pushMarkStep(AddMarkStep, from, to, this.mark, steps);
111
+ });
112
+ }
113
+ map(mapping) {
114
+ return Option.map(mapMarkRange(mapping, this.from, this.to), ([from, to]) => new RemoveMarkStep(from, to, this.mark));
115
+ }
116
+ merge(other) {
117
+ if (other instanceof RemoveMarkStep && other.mark.eq(this.mark) && this.from <= other.to && this.to >= other.from) return Option.some(new RemoveMarkStep(Math.min(this.from, other.from), Math.max(this.to, other.to), this.mark));
118
+ return Option.none();
119
+ }
120
+ toJSON() {
121
+ return {
122
+ stepType: "removeMark",
123
+ mark: this.mark.toJSON(),
124
+ from: this.from,
125
+ to: this.to
126
+ };
127
+ }
128
+ /** @internal */
129
+ static fromJSONUnsafe(schema, json) {
130
+ if (!Predicate.isNumber(json.from) || !Predicate.isNumber(json.to)) throw new JSONError({ message: "Invalid input for RemoveMarkStep.fromJSON" });
131
+ return new RemoveMarkStep(json.from, json.to, schema.markFromJSONUnsafe(json.mark));
132
+ }
133
+ };
134
+ Step.jsonID("removeMark", RemoveMarkStep);
135
+ /**
136
+ * Add a mark to a specific node.
137
+ *
138
+ * @since 0.1.0
139
+ * @category steps
140
+ */
141
+ var AddNodeMarkStep = class AddNodeMarkStep extends Step {
142
+ /** Create a node mark step. */
143
+ constructor(pos, mark) {
144
+ super();
145
+ this.pos = pos;
146
+ this.mark = mark;
147
+ }
148
+ apply(doc) {
149
+ const node = doc.nodeAtOrNull(this.pos);
150
+ if (!node) return StepResult.fail("No node at mark step's position");
151
+ const updated = node.type.createUnsafe(node.attrs, null, this.mark.addToSet(node.marks));
152
+ return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
153
+ }
154
+ invert(doc) {
155
+ const node = doc.nodeAtOrNull(this.pos);
156
+ if (node) {
157
+ const newSet = this.mark.addToSet(node.marks);
158
+ if (newSet.length === node.marks.length) {
159
+ for (let i = 0; i < node.marks.length; i++) if (!node.marks[i].isInSet(newSet)) return new AddNodeMarkStep(this.pos, node.marks[i]);
160
+ return new AddNodeMarkStep(this.pos, this.mark);
161
+ }
162
+ }
163
+ return new RemoveNodeMarkStep(this.pos, this.mark);
164
+ }
165
+ map(mapping) {
166
+ const pos = mapping.mapResult(this.pos, 1);
167
+ return pos.deletedAfter ? Option.none() : Option.some(new AddNodeMarkStep(pos.pos, this.mark));
168
+ }
169
+ toJSON() {
170
+ return {
171
+ stepType: "addNodeMark",
172
+ pos: this.pos,
173
+ mark: this.mark.toJSON()
174
+ };
175
+ }
176
+ /** @internal */
177
+ static fromJSONUnsafe(schema, json) {
178
+ if (!Predicate.isNumber(json.pos)) throw new JSONError({ message: "Invalid input for AddNodeMarkStep.fromJSON" });
179
+ return new AddNodeMarkStep(json.pos, schema.markFromJSONUnsafe(json.mark));
180
+ }
181
+ };
182
+ Step.jsonID("addNodeMark", AddNodeMarkStep);
183
+ /**
184
+ * Remove a mark from a specific node.
185
+ *
186
+ * @since 0.1.0
187
+ * @category steps
188
+ */
189
+ var RemoveNodeMarkStep = class RemoveNodeMarkStep extends Step {
190
+ /** Create a mark-removing step. */
191
+ constructor(pos, mark) {
192
+ super();
193
+ this.pos = pos;
194
+ this.mark = mark;
195
+ }
196
+ apply(doc) {
197
+ const node = doc.nodeAtOrNull(this.pos);
198
+ if (!node) return StepResult.fail("No node at mark step's position");
199
+ const updated = node.type.createUnsafe(node.attrs, null, this.mark.removeFromSet(node.marks));
200
+ return StepResult.fromReplace(doc, this.pos, this.pos + 1, new Slice(Fragment.from(updated), 0, node.isLeaf ? 0 : 1));
201
+ }
202
+ invert(doc) {
203
+ const node = doc.nodeAtOrNull(this.pos);
204
+ if (!node || !this.mark.isInSet(node.marks)) return this;
205
+ return new AddNodeMarkStep(this.pos, this.mark);
206
+ }
207
+ map(mapping) {
208
+ const pos = mapping.mapResult(this.pos, 1);
209
+ return pos.deletedAfter ? Option.none() : Option.some(new RemoveNodeMarkStep(pos.pos, this.mark));
210
+ }
211
+ toJSON() {
212
+ return {
213
+ stepType: "removeNodeMark",
214
+ pos: this.pos,
215
+ mark: this.mark.toJSON()
216
+ };
217
+ }
218
+ /** @internal */
219
+ static fromJSONUnsafe(schema, json) {
220
+ if (!Predicate.isNumber(json.pos)) throw new JSONError({ message: "Invalid input for RemoveNodeMarkStep.fromJSON" });
221
+ return new RemoveNodeMarkStep(json.pos, schema.markFromJSONUnsafe(json.mark));
222
+ }
223
+ };
224
+ Step.jsonID("removeNodeMark", RemoveNodeMarkStep);
225
+ export { AddMarkStep, AddNodeMarkStep, RemoveMarkStep, RemoveNodeMarkStep };
@@ -0,0 +1,18 @@
1
+ import { Slice } from "../model/replace.js";
2
+ import { AnySchema } from "../model/schema.js";
3
+ import { Node } from "../model/node.js";
4
+ import "../model.js";
5
+ import { Step } from "./step.js";
6
+ import "./transform.js";
7
+ import * as Option from "effect/Option";
8
+ /**
9
+ * ‘Fit’ a slice into a given position in the document, producing a step
10
+ * that inserts it. Will return `None` if there's no meaningful way to
11
+ * insert the slice here, or inserting it would be a no-op (an empty
12
+ * slice over an empty range). Throws a `PositionError` when `from` or
13
+ * `to` are outside of the document.
14
+ *
15
+ * @since 0.1.0
16
+ * @category queries
17
+ */
18
+ export declare const replaceStep: <Sc extends AnySchema>(doc: Node<Sc>, from: number, to?: number, slice?: Slice<Sc>) => Option.Option<Step<Sc>>;
@@ -0,0 +1,381 @@
1
+ import { Fragment } from "../model/fragment.js";
2
+ import { Slice } from "../model/replace.js";
3
+ import { ReplaceAroundStep, ReplaceStep } from "./replace_step.js";
4
+ import { insertPointOrNull } from "./structure.js";
5
+ import * as Option from "effect/Option";
6
+ // src/transform/replace.ts
7
+ /**
8
+ * Fitting slices into documents: `replaceStep` and the implementations
9
+ * of `replaceRange`, `replaceRangeWith` and `deleteRange`.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ /**
14
+ * ‘Fit’ a slice into a given position in the document, producing a step
15
+ * that inserts it. Will return `None` if there's no meaningful way to
16
+ * insert the slice here, or inserting it would be a no-op (an empty
17
+ * slice over an empty range). Throws a `PositionError` when `from` or
18
+ * `to` are outside of the document.
19
+ *
20
+ * @since 0.1.0
21
+ * @category queries
22
+ */
23
+ const replaceStep = (doc, from, to = from, slice = Slice.empty) => Option.fromNullishOr(replaceStepOrNull(doc, from, to, slice));
24
+ /** @internal */
25
+ function replaceStepOrNull(doc, from, to = from, slice = Slice.empty) {
26
+ if (from === to && !slice.size) return null;
27
+ const $from = doc.resolveUnsafe(from), $to = doc.resolveUnsafe(to);
28
+ if (fitsTrivially($from, $to, slice)) return new ReplaceStep(from, to, slice);
29
+ return new Fitter($from, $to, slice).fit();
30
+ }
31
+ function fitsTrivially($from, $to, slice) {
32
+ return !slice.openStart && !slice.openEnd && $from.start() === $to.start() && $from.parent.canReplace($from.index(), $to.index(), slice.content);
33
+ }
34
+ var Fitter = class {
35
+ constructor($from, $to, unplaced) {
36
+ this.$from = $from;
37
+ this.$to = $to;
38
+ this.unplaced = unplaced;
39
+ this.frontier = [];
40
+ this.placed = Fragment.empty;
41
+ for (let i = 0; i <= $from.depth; i++) {
42
+ const node = $from.node(i);
43
+ this.frontier.push({
44
+ type: node.type,
45
+ match: node.contentMatchAtUnsafe($from.indexAfter(i))
46
+ });
47
+ }
48
+ for (let i = $from.depth; i > 0; i--) this.placed = Fragment.from($from.node(i).copy(this.placed));
49
+ }
50
+ get depth() {
51
+ return this.frontier.length - 1;
52
+ }
53
+ fit() {
54
+ while (this.unplaced.size) {
55
+ const fit = this.findFittable();
56
+ if (fit) this.placeNodes(fit);
57
+ else if (!this.openMore()) this.dropNode();
58
+ }
59
+ const moveInline = this.mustMoveInline(), placedSize = this.placed.size - this.depth - this.$from.depth;
60
+ const $from = this.$from, $to = this.close(moveInline < 0 ? this.$to : $from.doc.resolveUnsafe(moveInline));
61
+ if (!$to) return null;
62
+ let content = this.placed, openStart = $from.depth, openEnd = $to.depth;
63
+ while (openStart && openEnd && content.childCount === 1) {
64
+ content = content.content[0].content;
65
+ openStart--;
66
+ openEnd--;
67
+ }
68
+ const slice = new Slice(content, openStart, openEnd);
69
+ if (moveInline > -1) return new ReplaceAroundStep($from.pos, moveInline, this.$to.pos, this.$to.end(), slice, placedSize);
70
+ if (slice.size || $from.pos !== this.$to.pos) return new ReplaceStep($from.pos, $to.pos, slice);
71
+ return null;
72
+ }
73
+ findFittable() {
74
+ let startDepth = this.unplaced.openStart;
75
+ for (let cur = this.unplaced.content, d = 0, openEnd = this.unplaced.openEnd; d < startDepth; d++) {
76
+ const node = cur.content[0];
77
+ if (cur.childCount > 1) openEnd = 0;
78
+ if (node.type.spec.isolating && openEnd <= d) {
79
+ startDepth = d;
80
+ break;
81
+ }
82
+ cur = node.content;
83
+ }
84
+ for (let pass = 1; pass <= 2; pass++) for (let sliceDepth = pass === 1 ? startDepth : this.unplaced.openStart; sliceDepth >= 0; sliceDepth--) {
85
+ let fragment, parent = null;
86
+ if (sliceDepth) {
87
+ parent = contentAt(this.unplaced.content, sliceDepth - 1).content[0];
88
+ fragment = parent.content;
89
+ } else fragment = this.unplaced.content;
90
+ const first = fragment.content[0];
91
+ for (let frontierDepth = this.depth; frontierDepth >= 0; frontierDepth--) {
92
+ const { match, type } = this.frontier[frontierDepth];
93
+ let wrap = null, inject = null;
94
+ if (pass === 1 && (first ? match.matchTypeOrNull(first.type) || (inject = match.fillBeforeOrNull(Fragment.from(first), false)) : parent && type.compatibleContent(parent.type))) return {
95
+ sliceDepth,
96
+ frontierDepth,
97
+ parent,
98
+ inject
99
+ };
100
+ else if (pass === 2 && first && (wrap = match.findWrappingOrNull(first.type))) return {
101
+ sliceDepth,
102
+ frontierDepth,
103
+ parent,
104
+ wrap
105
+ };
106
+ if (parent && match.matchTypeOrNull(parent.type)) break;
107
+ }
108
+ }
109
+ }
110
+ openMore() {
111
+ const { content, openStart } = this.unplaced;
112
+ let { openEnd } = this.unplaced;
113
+ if (maxOpen(content, -1) <= openStart) return false;
114
+ if (this.unplaced.size > 1 && maxOpen(content, 1) > openEnd) openEnd++;
115
+ this.unplaced = new Slice(content, openStart + 1, openEnd);
116
+ return true;
117
+ }
118
+ dropNode() {
119
+ const { content, openEnd, openStart } = this.unplaced;
120
+ const inner = contentAt(content, openStart);
121
+ if (inner.childCount <= 1 && openStart > 0) {
122
+ const openAtEnd = content.size - openStart <= openStart + inner.size;
123
+ this.unplaced = new Slice(dropFromFragment(content, openStart - 1, 1), openStart - 1, openAtEnd ? openStart - 1 : openEnd);
124
+ } else this.unplaced = new Slice(dropFromFragment(content, openStart, 1), openStart, openEnd);
125
+ }
126
+ placeNodes({ frontierDepth, inject, parent, sliceDepth, wrap }) {
127
+ while (this.depth > frontierDepth) this.closeFrontierNode();
128
+ if (wrap) for (let i = 0; i < wrap.length; i++) this.openFrontierNode(wrap[i]);
129
+ const slice = this.unplaced, fragment = parent ? parent.content : slice.content;
130
+ const openStart = slice.openStart - sliceDepth;
131
+ let taken = 0;
132
+ const add = [];
133
+ let { match } = this.frontier[frontierDepth];
134
+ const { type } = this.frontier[frontierDepth];
135
+ if (inject) {
136
+ for (let i = 0; i < inject.childCount; i++) add.push(inject.content[i]);
137
+ match = match.matchFragmentOrNull(inject);
138
+ }
139
+ let openEndCount = fragment.size + sliceDepth - (slice.content.size - slice.openEnd);
140
+ while (taken < fragment.childCount) {
141
+ const next = fragment.content[taken], matches = match.matchTypeOrNull(next.type);
142
+ if (!matches) break;
143
+ taken++;
144
+ if (taken > 1 || openStart === 0 || next.content.size) {
145
+ match = matches;
146
+ add.push(closeNodeStart(next.mark(type.allowedMarks(next.marks)), taken === 1 ? openStart : 0, taken === fragment.childCount ? openEndCount : -1));
147
+ }
148
+ }
149
+ const toEnd = taken === fragment.childCount;
150
+ if (!toEnd) openEndCount = -1;
151
+ this.placed = addToFragment(this.placed, frontierDepth, Fragment.from(add));
152
+ this.frontier[frontierDepth].match = match;
153
+ if (toEnd && openEndCount < 0 && parent && parent.type === this.frontier[this.depth].type && this.frontier.length > 1) this.closeFrontierNode();
154
+ for (let i = 0, cur = add.at(-1); cur && i < openEndCount; i++) {
155
+ this.frontier.push({
156
+ type: cur.type,
157
+ match: cur.contentMatchAtUnsafe(cur.childCount)
158
+ });
159
+ cur = cur.content.content.at(-1);
160
+ }
161
+ this.unplaced = !toEnd ? new Slice(dropFromFragment(slice.content, sliceDepth, taken), sliceDepth, slice.openEnd) : sliceDepth === 0 ? Slice.empty : new Slice(dropFromFragment(slice.content, sliceDepth - 1, 1), sliceDepth - 1, openEndCount < 0 ? slice.openEnd : sliceDepth - 1);
162
+ }
163
+ mustMoveInline() {
164
+ if (!this.$to.parent.isTextblock) return -1;
165
+ const top = this.frontier[this.depth];
166
+ let level;
167
+ if (!top.type.isTextblock || !contentAfterFits(this.$to, this.$to.depth, top.type, top.match, false) || this.$to.depth === this.depth && (level = this.findCloseLevel(this.$to)) && level.depth === this.depth) return -1;
168
+ let { depth } = this.$to, after = this.$to.afterUnsafe(depth);
169
+ while (depth > 1 && after === this.$to.end(--depth)) ++after;
170
+ return after;
171
+ }
172
+ findCloseLevel($to) {
173
+ scan: for (let i = Math.min(this.depth, $to.depth); i >= 0; i--) {
174
+ const { match, type } = this.frontier[i];
175
+ const dropInner = i < $to.depth && $to.end(i + 1) === $to.pos + ($to.depth - (i + 1));
176
+ const fit = contentAfterFits($to, i, type, match, dropInner);
177
+ if (!fit) continue;
178
+ for (let d = i - 1; d >= 0; d--) {
179
+ const { match, type } = this.frontier[d];
180
+ const matches = contentAfterFits($to, d, type, match, true);
181
+ if (!matches || matches.childCount) continue scan;
182
+ }
183
+ return {
184
+ depth: i,
185
+ fit,
186
+ move: dropInner ? $to.doc.resolveUnsafe($to.afterUnsafe(i + 1)) : $to
187
+ };
188
+ }
189
+ }
190
+ close($to) {
191
+ const close = this.findCloseLevel($to);
192
+ if (!close) return null;
193
+ while (this.depth > close.depth) this.closeFrontierNode();
194
+ if (close.fit.childCount) this.placed = addToFragment(this.placed, close.depth, close.fit);
195
+ $to = close.move;
196
+ for (let d = close.depth + 1; d <= $to.depth; d++) {
197
+ const node = $to.node(d), add = node.type.contentMatch.fillBeforeOrNull(node.content, true, $to.index(d));
198
+ this.openFrontierNode(node.type, node.attrs, add);
199
+ }
200
+ return $to;
201
+ }
202
+ openFrontierNode(type, attrs = null, content) {
203
+ const top = this.frontier[this.depth];
204
+ top.match = top.match.matchTypeOrNull(type);
205
+ this.placed = addToFragment(this.placed, this.depth, Fragment.from(type.createUnsafe(attrs, content)));
206
+ this.frontier.push({
207
+ type,
208
+ match: type.contentMatch
209
+ });
210
+ }
211
+ closeFrontierNode() {
212
+ const add = this.frontier.pop().match.fillBeforeOrNull(Fragment.empty, true);
213
+ if (add.childCount) this.placed = addToFragment(this.placed, this.frontier.length, add);
214
+ }
215
+ };
216
+ function dropFromFragment(fragment, depth, count) {
217
+ if (depth === 0) return fragment.cutByIndex(count, fragment.childCount);
218
+ const first = fragment.content[0];
219
+ return fragment.replaceChild(0, first.copy(dropFromFragment(first.content, depth - 1, count)));
220
+ }
221
+ function addToFragment(fragment, depth, content) {
222
+ if (depth === 0) return fragment.append(content);
223
+ const last = fragment.content[fragment.childCount - 1];
224
+ return fragment.replaceChild(fragment.childCount - 1, last.copy(addToFragment(last.content, depth - 1, content)));
225
+ }
226
+ function contentAt(fragment, depth) {
227
+ for (let i = 0; i < depth; i++) fragment = fragment.content[0].content;
228
+ return fragment;
229
+ }
230
+ function closeNodeStart(node, openStart, openEnd) {
231
+ if (openStart <= 0) return node;
232
+ let frag = node.content;
233
+ if (openStart > 1) frag = frag.replaceChild(0, closeNodeStart(frag.content[0], openStart - 1, frag.childCount === 1 ? openEnd - 1 : 0));
234
+ if (openStart > 0) {
235
+ frag = node.type.contentMatch.fillBeforeOrNull(frag).append(frag);
236
+ if (openEnd <= 0) frag = frag.append(node.type.contentMatch.matchFragmentOrNull(frag).fillBeforeOrNull(Fragment.empty, true));
237
+ }
238
+ return node.copy(frag);
239
+ }
240
+ function contentAfterFits($to, depth, type, match, open) {
241
+ const node = $to.node(depth), index = open ? $to.indexAfter(depth) : $to.index(depth);
242
+ if (index === node.childCount && !type.compatibleContent(node.type)) return null;
243
+ const fit = match.fillBeforeOrNull(node.content, true, index);
244
+ return fit && !invalidMarks(type, node.content, index) ? fit : null;
245
+ }
246
+ function invalidMarks(type, fragment, start) {
247
+ for (let i = start; i < fragment.childCount; i++) if (!type.allowsMarks(fragment.content[i].marks)) return true;
248
+ return false;
249
+ }
250
+ function definesContent(type) {
251
+ return type.spec.defining || type.spec.definingForContent;
252
+ }
253
+ function maxOpen(frag, side) {
254
+ const ch = side < 0 ? frag.content[0] : frag.content.at(-1);
255
+ return !ch || ch.isAtom ? 0 : 1 + maxOpen(ch.content, side);
256
+ }
257
+ /** @internal */
258
+ function replaceRange(tr, from, to, slice) {
259
+ if (!slice.size) {
260
+ tr.deleteRangeUnsafe(from, to);
261
+ return;
262
+ }
263
+ const $from = tr.doc.resolveUnsafe(from), $to = tr.doc.resolveUnsafe(to);
264
+ if (fitsTrivially($from, $to, slice)) {
265
+ tr.stepUnsafe(new ReplaceStep(from, to, slice));
266
+ return;
267
+ }
268
+ const targetDepths = coveredDepths($from, $to);
269
+ if (targetDepths[targetDepths.length - 1] === 0) targetDepths.pop();
270
+ let preferredTarget = -($from.depth + 1);
271
+ targetDepths.unshift(preferredTarget);
272
+ for (let d = $from.depth, pos = $from.pos - 1; d > 0; d--, pos--) {
273
+ const spec = $from.node(d).type.spec;
274
+ if (spec.defining || spec.definingAsContext || spec.isolating) break;
275
+ if (targetDepths.indexOf(d) > -1) preferredTarget = d;
276
+ else if ($from.beforeUnsafe(d) === pos) targetDepths.splice(1, 0, -d);
277
+ }
278
+ const preferredTargetIndex = targetDepths.indexOf(preferredTarget);
279
+ const leftNodes = [];
280
+ let preferredDepth = slice.openStart;
281
+ for (let content = slice.content, i = 0;; i++) {
282
+ const node = content.content[0];
283
+ leftNodes.push(node);
284
+ if (i === slice.openStart) break;
285
+ content = node.content;
286
+ }
287
+ for (let d = preferredDepth - 1; d >= 0; d--) {
288
+ const leftNode = leftNodes[d], def = definesContent(leftNode.type);
289
+ if (def && !leftNode.sameMarkup($from.node(Math.abs(preferredTarget) - 1))) preferredDepth = d;
290
+ else if (def || !leftNode.type.isTextblock) break;
291
+ }
292
+ for (let j = slice.openStart; j >= 0; j--) {
293
+ const openDepth = (j + preferredDepth + 1) % (slice.openStart + 1);
294
+ const insert = leftNodes[openDepth];
295
+ if (!insert) continue;
296
+ for (let i = 0; i < targetDepths.length; i++) {
297
+ let targetDepth = targetDepths[(i + preferredTargetIndex) % targetDepths.length], expand = true;
298
+ if (targetDepth < 0) {
299
+ expand = false;
300
+ targetDepth = -targetDepth;
301
+ }
302
+ const parent = $from.node(targetDepth - 1), index = $from.index(targetDepth - 1);
303
+ if (parent.canReplaceWith(index, index, insert.type, insert.marks)) {
304
+ tr.replaceUnsafe($from.beforeUnsafe(targetDepth), expand ? $to.afterUnsafe(targetDepth) : to, new Slice(closeFragment(slice.content, 0, slice.openStart, openDepth), openDepth, slice.openEnd));
305
+ return;
306
+ }
307
+ }
308
+ }
309
+ const startSteps = tr.steps.length;
310
+ for (let i = targetDepths.length - 1; i >= 0; i--) {
311
+ tr.replaceUnsafe(from, to, slice);
312
+ if (tr.steps.length > startSteps) break;
313
+ const depth = targetDepths[i];
314
+ if (depth < 0) continue;
315
+ from = $from.beforeUnsafe(depth);
316
+ to = $to.afterUnsafe(depth);
317
+ }
318
+ }
319
+ function closeFragment(fragment, depth, oldOpen, newOpen, parent) {
320
+ if (depth < oldOpen) {
321
+ const first = fragment.content[0];
322
+ fragment = fragment.replaceChild(0, first.copy(closeFragment(first.content, depth + 1, oldOpen, newOpen, first)));
323
+ }
324
+ if (depth > newOpen) {
325
+ const match = parent.contentMatchAtUnsafe(0);
326
+ const start = match.fillBeforeOrNull(fragment).append(fragment);
327
+ fragment = start.append(match.matchFragmentOrNull(start).fillBeforeOrNull(Fragment.empty, true));
328
+ }
329
+ return fragment;
330
+ }
331
+ /** @internal */
332
+ function replaceRangeWith(tr, from, to, node) {
333
+ if (!node.isInline && from === to && tr.doc.resolveUnsafe(from).parent.content.size) {
334
+ const point = insertPointOrNull(tr.doc, from, node.type);
335
+ if (point != null) from = to = point;
336
+ }
337
+ tr.replaceRangeUnsafe(from, to, new Slice(Fragment.from(node), 0, 0));
338
+ }
339
+ /** @internal */
340
+ function deleteRange(tr, from, to) {
341
+ let $from = tr.doc.resolveUnsafe(from), $to = tr.doc.resolveUnsafe(to);
342
+ if ($from.parent.isTextblock && $to.parent.isTextblock && $from.start() !== $to.start() && $from.parentOffset === 0 && $to.parentOffset === 0) {
343
+ const shared = $from.sharedDepth(to);
344
+ let isolated = false;
345
+ for (let d = $from.depth; d > shared; d--) if ($from.node(d).type.spec.isolating) isolated = true;
346
+ for (let d = $to.depth; d > shared; d--) if ($to.node(d).type.spec.isolating) isolated = true;
347
+ if (!isolated) {
348
+ for (let d = $from.depth; d > 0 && from === $from.start(d); d--) from = $from.beforeUnsafe(d);
349
+ for (let d = $to.depth; d > 0 && to === $to.start(d); d--) to = $to.beforeUnsafe(d);
350
+ $from = tr.doc.resolveUnsafe(from);
351
+ $to = tr.doc.resolveUnsafe(to);
352
+ }
353
+ }
354
+ const covered = coveredDepths($from, $to);
355
+ for (let i = 0; i < covered.length; i++) {
356
+ const depth = covered[i], last = i === covered.length - 1;
357
+ if (last && depth === 0 || $from.node(depth).type.contentMatch.validEnd) {
358
+ tr.deleteUnsafe($from.start(depth), $to.end(depth));
359
+ return;
360
+ }
361
+ if (depth > 0 && (last || $from.node(depth - 1).canReplace($from.index(depth - 1), $to.indexAfter(depth - 1)))) {
362
+ tr.deleteUnsafe($from.beforeUnsafe(depth), $to.afterUnsafe(depth));
363
+ return;
364
+ }
365
+ }
366
+ for (let d = 1; d <= $from.depth && d <= $to.depth; d++) if (from - $from.start(d) === $from.depth - d && to > $from.end(d) && $to.end(d) - to !== $to.depth - d && $from.start(d - 1) === $to.start(d - 1) && $from.node(d - 1).canReplace($from.index(d - 1), $to.index(d - 1))) {
367
+ tr.deleteUnsafe($from.beforeUnsafe(d), to);
368
+ return;
369
+ }
370
+ tr.deleteUnsafe(from, to);
371
+ }
372
+ function coveredDepths($from, $to) {
373
+ const result = [], minDepth = Math.min($from.depth, $to.depth);
374
+ for (let d = minDepth; d >= 0; d--) {
375
+ const start = $from.start(d);
376
+ if (start < $from.pos - ($from.depth - d) || $to.end(d) > $to.pos + ($to.depth - d) || $from.node(d).type.spec.isolating || $to.node(d).type.spec.isolating) break;
377
+ if (start === $to.start(d) || d === $from.depth && d === $to.depth && $from.parent.inlineContent && $to.parent.inlineContent && d && $to.start(d - 1) === start - 1) result.push(d);
378
+ }
379
+ return result;
380
+ }
381
+ export { deleteRange, replaceRange, replaceRangeWith, replaceStep, replaceStepOrNull };