@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.
Files changed (176) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +118 -2
  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 +206 -3
@@ -0,0 +1,140 @@
1
+ // src/view/dom.ts
2
+ /** @internal */
3
+ const domIndex = function(node) {
4
+ for (let index = 0;; index++) {
5
+ node = node.previousSibling;
6
+ if (!node) return index;
7
+ }
8
+ };
9
+ /** @internal */
10
+ const parentNode = function(node) {
11
+ const parent = node.assignedSlot || node.parentNode;
12
+ return parent && parent.nodeType == 11 ? parent.host : parent;
13
+ };
14
+ let reusedRange = null;
15
+ /** @internal */
16
+ const textRange = function(node, from, to) {
17
+ const range = reusedRange || (reusedRange = document.createRange());
18
+ range.setEnd(node, to == null ? node.nodeValue.length : to);
19
+ range.setStart(node, from || 0);
20
+ return range;
21
+ };
22
+ /** @internal */
23
+ const clearReusedRange = function() {
24
+ reusedRange = null;
25
+ };
26
+ /** @internal */
27
+ const isEquivalentPosition = function(node, off, targetNode, targetOff) {
28
+ return !!targetNode && (scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1));
29
+ };
30
+ const atomElements = /^(img|br|input|textarea|hr)$/i;
31
+ function scanFor(node, off, targetNode, targetOff, dir) {
32
+ for (;;) {
33
+ if (node == targetNode && off == targetOff) return true;
34
+ if (off == (dir < 0 ? 0 : nodeSize(node))) {
35
+ const parent = node.parentNode;
36
+ if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) || node.contentEditable == "false") return false;
37
+ off = domIndex(node) + (dir < 0 ? 0 : 1);
38
+ node = parent;
39
+ } else if (node.nodeType == 1) {
40
+ const child = node.childNodes[off + (dir < 0 ? -1 : 0)];
41
+ if (child.nodeType == 1 && child.contentEditable == "false") {
42
+ if (child.pmViewDesc?.ignoreForSelection) off += dir;
43
+ else return false;
44
+ } else {
45
+ node = child;
46
+ off = dir < 0 ? nodeSize(node) : 0;
47
+ }
48
+ } else return false;
49
+ }
50
+ }
51
+ /** @internal */
52
+ function nodeSize(node) {
53
+ return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
54
+ }
55
+ /** @internal */
56
+ function isElt(node) {
57
+ return node.nodeType == 1;
58
+ }
59
+ /** @internal */
60
+ function textNodeBefore(node, offset) {
61
+ for (;;) {
62
+ if (node.nodeType == 3 && offset) return node;
63
+ if (node.nodeType == 1 && offset > 0) {
64
+ if (node.contentEditable == "false") return null;
65
+ node = node.childNodes[offset - 1];
66
+ offset = nodeSize(node);
67
+ } else if (node.parentNode && !hasBlockDesc(node)) {
68
+ offset = domIndex(node);
69
+ node = node.parentNode;
70
+ } else return null;
71
+ }
72
+ }
73
+ /** @internal */
74
+ function textNodeAfter(node, offset) {
75
+ for (;;) {
76
+ if (node.nodeType == 3 && offset < node.nodeValue.length) return node;
77
+ if (node.nodeType == 1 && offset < node.childNodes.length) {
78
+ if (node.contentEditable == "false") return null;
79
+ node = node.childNodes[offset];
80
+ offset = 0;
81
+ } else if (node.parentNode && !hasBlockDesc(node)) {
82
+ offset = domIndex(node) + 1;
83
+ node = node.parentNode;
84
+ } else return null;
85
+ }
86
+ }
87
+ /** @internal */
88
+ function isOnEdge(node, offset, parent) {
89
+ for (let atStart = offset == 0, atEnd = offset == nodeSize(node); atStart || atEnd;) {
90
+ if (node == parent) return true;
91
+ const index = domIndex(node);
92
+ node = node.parentNode;
93
+ if (!node) return false;
94
+ atStart = atStart && index == 0;
95
+ atEnd = atEnd && index == nodeSize(node);
96
+ }
97
+ return false;
98
+ }
99
+ /** @internal */
100
+ function hasBlockDesc(dom) {
101
+ let desc;
102
+ for (let cur = dom; cur; cur = cur.parentNode) if (desc = cur.pmViewDesc) break;
103
+ return !!desc && !!desc.node && desc.node.isBlock && (desc.dom == dom || desc.contentDOM == dom);
104
+ }
105
+ /** @internal */
106
+ const selectionCollapsed = function(domSel) {
107
+ return !!domSel.focusNode && isEquivalentPosition(domSel.focusNode, domSel.focusOffset, domSel.anchorNode, domSel.anchorOffset);
108
+ };
109
+ /** @internal */
110
+ function keyEvent(keyCode, key) {
111
+ const event = document.createEvent("Event");
112
+ event.initEvent("keydown", true, true);
113
+ event.keyCode = keyCode;
114
+ event.key = event.code = key;
115
+ return event;
116
+ }
117
+ /** @internal */
118
+ function deepActiveElement(doc) {
119
+ let elt = doc.activeElement;
120
+ while (elt && elt.shadowRoot) elt = elt.shadowRoot.activeElement;
121
+ return elt;
122
+ }
123
+ /** @internal */
124
+ function caretFromPoint(doc, x, y) {
125
+ if (doc.caretPositionFromPoint) try {
126
+ const pos = doc.caretPositionFromPoint(x, y);
127
+ if (pos) return {
128
+ node: pos.offsetNode,
129
+ offset: Math.min(nodeSize(pos.offsetNode), pos.offset)
130
+ };
131
+ } catch {}
132
+ if (doc.caretRangeFromPoint) {
133
+ const range = doc.caretRangeFromPoint(x, y);
134
+ if (range) return {
135
+ node: range.startContainer,
136
+ offset: Math.min(nodeSize(range.startContainer), range.startOffset)
137
+ };
138
+ }
139
+ }
140
+ export { caretFromPoint, clearReusedRange, deepActiveElement, domIndex, hasBlockDesc, isElt, isEquivalentPosition, isOnEdge, keyEvent, nodeSize, parentNode, selectionCollapsed, textNodeAfter, textNodeBefore, textRange };
@@ -0,0 +1,295 @@
1
+ import { DOMParser } from "../model/from_dom.js";
2
+ import { Fragment } from "../model/fragment.js";
3
+ import { TextSelection } from "../state/selection.js";
4
+ import { android, chrome, ie, ie_version, ios, safari } from "./browser.js";
5
+ import { selectionCollapsed } from "./dom.js";
6
+ import { dispatchKey } from "./input.js";
7
+ import { selectionBetween, selectionFromDOM, selectionToDOM } from "./selection.js";
8
+ import * as Arr from "effect/Array";
9
+ import * as Option from "effect/Option";
10
+ // src/view/domchange.ts
11
+ /**
12
+ * Reading DOM changes back into the document.
13
+ *
14
+ * @internal
15
+ */
16
+ function parseBetween(view, from_, to_, addedNodes) {
17
+ const range = view.docView.parseRange(from_, to_);
18
+ const { from, fromOffset, node: parent, to } = range;
19
+ let toOffset = range.toOffset;
20
+ const domSel = view.domSelectionRange();
21
+ let find;
22
+ const anchor = domSel.anchorNode;
23
+ if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
24
+ find = [{
25
+ node: anchor,
26
+ offset: domSel.anchorOffset
27
+ }];
28
+ if (!selectionCollapsed(domSel)) find.push({
29
+ node: domSel.focusNode,
30
+ offset: domSel.focusOffset
31
+ });
32
+ }
33
+ if (chrome && view.input.lastKeyCode === 8) for (let off = toOffset; off > fromOffset; off--) {
34
+ const node = parent.childNodes[off - 1], desc = node.pmViewDesc;
35
+ if (node.nodeName == "BR" && !desc) {
36
+ toOffset = off;
37
+ break;
38
+ }
39
+ if (!desc || desc.size) break;
40
+ }
41
+ const startDoc = view.state.doc;
42
+ const parser = view.someProp("domParser") || DOMParser.fromSchema(view.state.schema);
43
+ const $from = startDoc.resolveUnsafe(from);
44
+ let sel = null;
45
+ const doc = parser.parseUnsafe(parent, {
46
+ topNode: $from.parent,
47
+ topMatch: $from.parent.contentMatchAtUnsafe($from.index()),
48
+ topOpen: true,
49
+ from: fromOffset,
50
+ to: toOffset,
51
+ preserveWhitespace: $from.parent.type.whitespace == "pre" ? "full" : true,
52
+ findPositions: find,
53
+ ruleFromNode: ruleFromNode(addedNodes),
54
+ context: $from
55
+ });
56
+ if (find && find[0].pos != null) {
57
+ const anchor = find[0].pos;
58
+ let head = find[1] && find[1].pos;
59
+ if (head == null) head = anchor;
60
+ sel = {
61
+ anchor: anchor + from,
62
+ head: head + from
63
+ };
64
+ }
65
+ return {
66
+ doc,
67
+ sel,
68
+ from,
69
+ to
70
+ };
71
+ }
72
+ const ruleFromNode = (added) => (dom) => {
73
+ const desc = dom.pmViewDesc;
74
+ if (desc) return desc.parseRule(added);
75
+ else if (dom.nodeName == "BR" && dom.parentNode) {
76
+ if (safari && /^(ul|ol)$/i.test(dom.parentNode.nodeName)) {
77
+ const skip = document.createElement("div");
78
+ skip.appendChild(document.createElement("li"));
79
+ return { skip };
80
+ } else if (dom.parentNode.lastChild == dom || safari && /^(tr|table)$/i.test(dom.parentNode.nodeName)) return { ignore: true };
81
+ } else if (dom.nodeName == "IMG" && dom.getAttribute("mark-placeholder")) return { ignore: true };
82
+ return null;
83
+ };
84
+ const isInline = /^(a|abbr|acronym|b|bd[io]|big|br|button|cite|code|data(list)?|del|dfn|em|i|img|ins|kbd|label|map|mark|meter|output|q|ruby|s|samp|small|span|strong|su[bp]|time|u|tt|var)$/i;
85
+ /** @internal */
86
+ function readDOMChange(view, from, to, typeOver, addedNodes) {
87
+ const now = Date.now();
88
+ const compositionID = view.input.compositionPendingChanges || (view.composing ? view.input.compositionID : 0);
89
+ view.input.compositionPendingChanges = 0;
90
+ if (from < 0) {
91
+ const origin = view.input.lastSelectionTime > now - 50 ? view.input.lastSelectionOrigin : null;
92
+ const newSel = selectionFromDOM(view, origin);
93
+ if (newSel && !view.state.selection.eq(newSel)) {
94
+ if (chrome && android && view.input.lastKeyCode === 13 && now - 100 < view.input.lastKeyCodeTime && dispatchKey(view, "Enter")) return;
95
+ const tr = view.state.tr.setSelectionUnsafe(newSel);
96
+ if (origin == "pointer") tr.setMeta("pointer", true);
97
+ else if (origin == "key") tr.scrollIntoView();
98
+ if (compositionID) tr.setMeta("composition", compositionID);
99
+ view.dispatchInternal(tr);
100
+ }
101
+ return;
102
+ }
103
+ const $before = view.state.doc.resolveUnsafe(from);
104
+ const shared = $before.sharedDepth(to);
105
+ from = $before.beforeUnsafe(shared + 1);
106
+ to = view.state.doc.resolveUnsafe(to).afterUnsafe(shared + 1);
107
+ const sel = view.state.selection;
108
+ const parse = parseBetween(view, from, to, addedNodes);
109
+ const doc = view.state.doc, compare = doc.sliceUnsafe(parse.from, parse.to);
110
+ let preferredPos, preferredSide;
111
+ if (view.input.lastKeyCode === 8 && now - 100 < view.input.lastKeyCodeTime) {
112
+ preferredPos = view.state.selection.to;
113
+ preferredSide = "end";
114
+ } else {
115
+ preferredPos = view.state.selection.from;
116
+ preferredSide = "start";
117
+ }
118
+ view.input.lastKeyCode = null;
119
+ let change = findDiff(compare.content, parse.doc.content, parse.from, preferredPos, preferredSide);
120
+ if (change) view.input.domChangeCount++;
121
+ if ((ios && view.input.lastIOSEnter > now - 225 || android) && addedNodes.some((n) => n.nodeType == 1 && !isInline.test(n.nodeName)) && (!change || change.endA >= change.endB) && dispatchKey(view, "Enter")) {
122
+ view.input.lastIOSEnter = 0;
123
+ return;
124
+ }
125
+ if (!change) {
126
+ if (typeOver && sel instanceof TextSelection && !sel.empty && sel.$head.sameParent(sel.$anchor) && !view.composing && !(parse.sel && parse.sel.anchor != parse.sel.head)) change = {
127
+ start: sel.from,
128
+ endA: sel.to,
129
+ endB: sel.to
130
+ };
131
+ else {
132
+ if (parse.sel) {
133
+ const sel = resolveSelection(view, view.state.doc, parse.sel);
134
+ if (sel && !sel.eq(view.state.selection)) {
135
+ const tr = view.state.tr.setSelectionUnsafe(sel);
136
+ if (compositionID) tr.setMeta("composition", compositionID);
137
+ view.dispatchInternal(tr);
138
+ }
139
+ }
140
+ return;
141
+ }
142
+ }
143
+ if (view.state.selection.from < view.state.selection.to && change.start == change.endB && view.state.selection instanceof TextSelection) {
144
+ if (change.start > view.state.selection.from && change.start <= view.state.selection.from + 2 && view.state.selection.from >= parse.from) change.start = view.state.selection.from;
145
+ else if (change.endA < view.state.selection.to && change.endA >= view.state.selection.to - 2 && view.state.selection.to <= parse.to) {
146
+ change.endB += view.state.selection.to - change.endA;
147
+ change.endA = view.state.selection.to;
148
+ }
149
+ }
150
+ if (ie && ie_version <= 11 && change.endB == change.start + 1 && change.endA == change.start && change.start > parse.from && parse.doc.textBetween(change.start - parse.from - 1, change.start - parse.from + 1) == " \xA0") {
151
+ change.start--;
152
+ change.endA--;
153
+ change.endB--;
154
+ }
155
+ const $from = parse.doc.resolveNoCache(change.start - parse.from);
156
+ let $to = parse.doc.resolveNoCache(change.endB - parse.from);
157
+ const $fromA = doc.resolveUnsafe(change.start);
158
+ const inlineChange = $from.sameParent($to) && $from.parent.inlineContent && $fromA.end() >= change.endA;
159
+ if ((ios && view.input.lastIOSEnter > now - 225 && (!inlineChange || addedNodes.some((n) => n.nodeName == "DIV" || n.nodeName == "P")) || !inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos)) && dispatchKey(view, "Enter")) {
160
+ view.input.lastIOSEnter = 0;
161
+ return;
162
+ }
163
+ if (view.state.selection.anchor > change.start && (inlineChange ? change.endA > change.start && change.endB == change.start : looksLikeBlockJoin(doc, change.start, change.endA, $from, $to)) && dispatchKey(view, "Backspace")) {
164
+ if (android && chrome) view.domObserver.suppressSelectionUpdates();
165
+ return;
166
+ }
167
+ if (chrome && change.endB == change.start) view.input.lastChromeDelete = now;
168
+ if (android && !inlineChange && $from.start() != $to.start() && $to.parentOffset == 0 && $from.depth == $to.depth && parse.sel && parse.sel.anchor == parse.sel.head && parse.sel.head == change.endA) {
169
+ change.endB -= 2;
170
+ $to = parse.doc.resolveNoCache(change.endB - parse.from);
171
+ setTimeout(() => dispatchKey(view, "Enter"), 20);
172
+ }
173
+ const chFrom = change.start, chTo = change.endA;
174
+ const mkTr = (base) => {
175
+ const tr = base || view.state.tr.replaceUnsafe(chFrom, chTo, parse.doc.sliceUnsafe(change.start - parse.from, change.endB - parse.from));
176
+ if (parse.sel) {
177
+ const sel = resolveSelection(view, tr.doc, parse.sel);
178
+ if (sel && !(chrome && view.composing && sel.empty && (change.start != change.endB || view.input.lastChromeDelete < now - 100) && (sel.head == chFrom || sel.head == tr.mapping.map(chTo) - 1) || ie && sel.empty && sel.head == chFrom)) tr.setSelectionUnsafe(sel);
179
+ }
180
+ if (compositionID) tr.setMeta("composition", compositionID);
181
+ return tr.scrollIntoView();
182
+ };
183
+ let markChange;
184
+ if (inlineChange) {
185
+ if ($from.pos == $to.pos) {
186
+ if (ie && ie_version <= 11 && $from.parentOffset == 0) {
187
+ view.domObserver.suppressSelectionUpdates();
188
+ setTimeout(() => selectionToDOM(view), 20);
189
+ }
190
+ const tr = mkTr(view.state.tr.deleteUnsafe(chFrom, chTo));
191
+ const marks = doc.resolveUnsafe(change.start).marksAcrossOrNull(doc.resolveUnsafe(change.endA));
192
+ if (marks) tr.ensureMarks(marks);
193
+ view.dispatchInternal(tr);
194
+ } else if (change.endA == change.endB && (markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset), $fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))) {
195
+ const tr = mkTr(view.state.tr);
196
+ if (markChange.type == "add") tr.addMark(chFrom, chTo, markChange.mark);
197
+ else tr.removeMark(chFrom, chTo, markChange.mark);
198
+ view.dispatchInternal(tr);
199
+ } else if ($from.parent.content.content[$from.index()].isText && $from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {
200
+ const text = $from.parent.textBetween($from.parentOffset, $to.parentOffset);
201
+ const deflt = () => mkTr(view.state.tr.insertTextUnsafe(text, chFrom, chTo));
202
+ if (!view.someHandler("handleTextInput", (f) => f(view, chFrom, chTo, text, deflt))) view.dispatchInternal(deflt());
203
+ } else view.dispatchInternal(mkTr());
204
+ } else view.dispatchInternal(mkTr());
205
+ }
206
+ function resolveSelection(view, doc, parsedSel) {
207
+ if (Math.max(parsedSel.anchor, parsedSel.head) > doc.content.size) return null;
208
+ return selectionBetween(view, doc.resolveUnsafe(parsedSel.anchor), doc.resolveUnsafe(parsedSel.head));
209
+ }
210
+ function isMarkChange(cur, prev) {
211
+ const curMarks = cur.content[0].marks, prevMarks = prev.content[0].marks;
212
+ let added = curMarks, removed = prevMarks, type, mark, update;
213
+ for (let i = 0; i < prevMarks.length; i++) added = prevMarks[i].removeFromSet(added);
214
+ for (let i = 0; i < curMarks.length; i++) removed = curMarks[i].removeFromSet(removed);
215
+ if (added.length == 1 && Arr.isReadonlyArrayEmpty(removed)) {
216
+ mark = added[0];
217
+ type = "add";
218
+ update = (node) => node.mark(mark.addToSet(node.marks));
219
+ } else if (Arr.isReadonlyArrayEmpty(added) && removed.length == 1) {
220
+ mark = removed[0];
221
+ type = "remove";
222
+ update = (node) => node.mark(mark.removeFromSet(node.marks));
223
+ } else return null;
224
+ const updated = [];
225
+ for (let i = 0; i < prev.childCount; i++) updated.push(update(prev.content[i]));
226
+ if (Fragment.from(updated).eq(cur)) return {
227
+ mark,
228
+ type
229
+ };
230
+ }
231
+ function looksLikeBlockJoin(old, start, end, $newStart, $newEnd) {
232
+ if (end - start <= $newEnd.pos - $newStart.pos || skipClosingAndOpening($newStart, true, false) < $newEnd.pos) return false;
233
+ const $start = old.resolveUnsafe(start);
234
+ if (!$newStart.parent.inlineContent) {
235
+ const after = $start.nodeAfterOrNull;
236
+ return after != null && end == start + after.nodeSize;
237
+ }
238
+ if ($start.parentOffset < $start.parent.content.size || !$start.parent.isTextblock) return false;
239
+ const $next = old.resolveUnsafe(skipClosingAndOpening($start, true, true));
240
+ if (!$next.parent.isTextblock || $next.pos > end || skipClosingAndOpening($next, true, false) < end) return false;
241
+ return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
242
+ }
243
+ function looksLikeEnter(content, from, to) {
244
+ let newTextlines = 0, newLeaves = 0;
245
+ content.nodesBetween(from, to, (node, pos) => {
246
+ if (node.isTextblock && pos >= from && pos < to) newTextlines++;
247
+ else if (node.isText ? /\S/.test(node.textContent.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf) newLeaves++;
248
+ });
249
+ return newLeaves == 0 && newTextlines == 1;
250
+ }
251
+ function skipClosingAndOpening($pos, fromEnd, mayOpen) {
252
+ let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
253
+ while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
254
+ depth--;
255
+ end++;
256
+ fromEnd = false;
257
+ }
258
+ if (mayOpen) {
259
+ let next = $pos.node(depth).content.content[$pos.indexAfter(depth)];
260
+ while (next && !next.isLeaf) {
261
+ next = next.content.content[0];
262
+ end++;
263
+ }
264
+ }
265
+ return end;
266
+ }
267
+ function findDiff(a, b, pos, preferredPos, preferredSide) {
268
+ let start = Option.getOrNull(a.findDiffStart(b, pos));
269
+ const lenA = pos + a.size, lenB = pos + b.size;
270
+ if (start == null) return null;
271
+ const diffEnd = Option.getOrNull(a.findDiffEnd(b, lenA, lenB));
272
+ if (diffEnd == null) return null;
273
+ let { a: endA, b: endB } = diffEnd;
274
+ if (preferredSide == "end") {
275
+ const adjust = Math.max(0, start - Math.min(endA, endB));
276
+ preferredPos -= endA + adjust - start;
277
+ }
278
+ if (endA < start && lenA < lenB) {
279
+ const move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
280
+ start -= move;
281
+ endB = start + (endB - endA);
282
+ endA = start;
283
+ } else if (endB < start) {
284
+ const move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
285
+ start -= move;
286
+ endA = start + (endA - endB);
287
+ endB = start;
288
+ }
289
+ return {
290
+ start,
291
+ endA,
292
+ endB
293
+ };
294
+ }
295
+ export { readDOMChange };
@@ -0,0 +1,22 @@
1
+ import "../state.js";
2
+ import "./dom.js";
3
+ import "./view.js";
4
+ /**
5
+ * A rectangle in viewport coordinates.
6
+ *
7
+ * @since 0.1.0
8
+ * @category models
9
+ */
10
+ export type Rect = {
11
+ left: number;
12
+ right: number;
13
+ top: number;
14
+ bottom: number;
15
+ };
16
+ /**
17
+ * A direction for `EditorView.endOfTextblock`.
18
+ *
19
+ * @since 0.1.0
20
+ * @category models
21
+ */
22
+ export type TextblockDir = "up" | "down" | "left" | "right" | "forward" | "backward";