prosemirror-view 1.39.2 → 1.40.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/CHANGELOG.md +20 -0
- package/dist/index.cjs +67 -40
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.js +66 -57
- package/package.json +1 -1
- package/src/decoration.ts +13 -0
- package/src/dom.ts +8 -3
- package/src/domchange.ts +33 -26
- package/src/index.ts +10 -7
- package/src/input.ts +10 -8
- package/src/viewdesc.ts +4 -0
- package/src/#index.ts# +0 -822
package/src/domchange.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {Fragment, DOMParser, TagParseRule, Node, Mark, ResolvedPos} from "prosemirror-model"
|
|
2
|
-
import {Selection, TextSelection} from "prosemirror-state"
|
|
2
|
+
import {Selection, TextSelection, Transaction} from "prosemirror-state"
|
|
3
3
|
|
|
4
4
|
import {selectionBetween, selectionFromDOM, selectionToDOM} from "./selection"
|
|
5
5
|
import {selectionCollapsed, keyEvent, DOMNode} from "./dom"
|
|
@@ -223,7 +223,27 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
223
223
|
|
|
224
224
|
let chFrom = change.start, chTo = change.endA
|
|
225
225
|
|
|
226
|
-
let
|
|
226
|
+
let mkTr = (base?: Transaction) => {
|
|
227
|
+
let tr = base || view.state.tr.replace(chFrom, chTo, parse.doc.slice(change!.start - parse.from,
|
|
228
|
+
change!.endB - parse.from))
|
|
229
|
+
if (parse.sel) {
|
|
230
|
+
let sel = resolveSelection(view, tr.doc, parse.sel)
|
|
231
|
+
// Chrome will sometimes, during composition, report the
|
|
232
|
+
// selection in the wrong place. If it looks like that is
|
|
233
|
+
// happening, don't update the selection.
|
|
234
|
+
// Edge just doesn't move the cursor forward when you start typing
|
|
235
|
+
// in an empty block or between br nodes.
|
|
236
|
+
if (sel && !(browser.chrome && view.composing && sel.empty &&
|
|
237
|
+
(change!.start != change!.endB || view.input.lastChromeDelete < Date.now() - 100) &&
|
|
238
|
+
(sel.head == chFrom || sel.head == tr.mapping.map(chTo) - 1) ||
|
|
239
|
+
browser.ie && sel.empty && sel.head == chFrom))
|
|
240
|
+
tr.setSelection(sel)
|
|
241
|
+
}
|
|
242
|
+
if (compositionID) tr.setMeta("composition", compositionID)
|
|
243
|
+
return tr.scrollIntoView()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let markChange
|
|
227
247
|
if (inlineChange) {
|
|
228
248
|
if ($from.pos == $to.pos) { // Deletion
|
|
229
249
|
// IE11 sometimes weirdly moves the DOM selection around after
|
|
@@ -232,42 +252,29 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
232
252
|
view.domObserver.suppressSelectionUpdates()
|
|
233
253
|
setTimeout(() => selectionToDOM(view), 20)
|
|
234
254
|
}
|
|
235
|
-
tr = view.state.tr.delete(chFrom, chTo)
|
|
236
|
-
|
|
255
|
+
let tr = mkTr(view.state.tr.delete(chFrom, chTo))
|
|
256
|
+
let marks = doc.resolve(change.start).marksAcross(doc.resolve(change.endA))
|
|
257
|
+
if (marks) tr.ensureMarks(marks)
|
|
258
|
+
view.dispatch(tr)
|
|
237
259
|
} else if ( // Adding or removing a mark
|
|
238
260
|
change.endA == change.endB &&
|
|
239
261
|
(markChange = isMarkChange($from.parent.content.cut($from.parentOffset, $to.parentOffset),
|
|
240
262
|
$fromA.parent.content.cut($fromA.parentOffset, change.endA - $fromA.start())))
|
|
241
263
|
) {
|
|
242
|
-
tr = view.state.tr
|
|
264
|
+
let tr = mkTr(view.state.tr)
|
|
243
265
|
if (markChange.type == "add") tr.addMark(chFrom, chTo, markChange.mark)
|
|
244
266
|
else tr.removeMark(chFrom, chTo, markChange.mark)
|
|
267
|
+
view.dispatch(tr)
|
|
245
268
|
} else if ($from.parent.child($from.index()).isText && $from.index() == $to.index() - ($to.textOffset ? 0 : 1)) {
|
|
246
269
|
// Both positions in the same text node -- simply insert text
|
|
247
270
|
let text = $from.parent.textBetween($from.parentOffset, $to.parentOffset)
|
|
248
|
-
|
|
249
|
-
|
|
271
|
+
let deflt = () => mkTr(view.state.tr.insertText(text, chFrom, chTo))
|
|
272
|
+
if (!view.someProp("handleTextInput", f => f(view, chFrom, chTo, text, deflt)))
|
|
273
|
+
view.dispatch(deflt())
|
|
250
274
|
}
|
|
275
|
+
} else {
|
|
276
|
+
view.dispatch(mkTr())
|
|
251
277
|
}
|
|
252
|
-
|
|
253
|
-
if (!tr)
|
|
254
|
-
tr = view.state.tr.replace(chFrom, chTo, parse.doc.slice(change.start - parse.from, change.endB - parse.from))
|
|
255
|
-
if (parse.sel) {
|
|
256
|
-
let sel = resolveSelection(view, tr.doc, parse.sel)
|
|
257
|
-
// Chrome will sometimes, during composition, report the
|
|
258
|
-
// selection in the wrong place. If it looks like that is
|
|
259
|
-
// happening, don't update the selection.
|
|
260
|
-
// Edge just doesn't move the cursor forward when you start typing
|
|
261
|
-
// in an empty block or between br nodes.
|
|
262
|
-
if (sel && !(browser.chrome && view.composing && sel.empty &&
|
|
263
|
-
(change.start != change.endB || view.input.lastChromeDelete < Date.now() - 100) &&
|
|
264
|
-
(sel.head == chFrom || sel.head == tr.mapping.map(chTo) - 1) ||
|
|
265
|
-
browser.ie && sel.empty && sel.head == chFrom))
|
|
266
|
-
tr.setSelection(sel)
|
|
267
|
-
}
|
|
268
|
-
if (storedMarks) tr.ensureMarks(storedMarks)
|
|
269
|
-
if (compositionID) tr.setMeta("composition", compositionID)
|
|
270
|
-
view.dispatch(tr.scrollIntoView())
|
|
271
278
|
}
|
|
272
279
|
|
|
273
280
|
function resolveSelection(view: EditorView, doc: Node, parsedSel: {anchor: number, head: number}) {
|
package/src/index.ts
CHANGED
|
@@ -28,7 +28,8 @@ export const __endComposition = endComposition
|
|
|
28
28
|
/// editable document. Its state and behavior are determined by its
|
|
29
29
|
/// [props](#view.DirectEditorProps).
|
|
30
30
|
export class EditorView {
|
|
31
|
-
|
|
31
|
+
/// @internal
|
|
32
|
+
_props: DirectEditorProps
|
|
32
33
|
private directPlugins: readonly Plugin[]
|
|
33
34
|
private _root: Document | ShadowRoot | null = null
|
|
34
35
|
/// @internal
|
|
@@ -490,11 +491,7 @@ export class EditorView {
|
|
|
490
491
|
/// [`updateState`](#view.EditorView.updateState) with the result.
|
|
491
492
|
/// This method is bound to the view instance, so that it can be
|
|
492
493
|
/// easily passed around.
|
|
493
|
-
dispatch(tr: Transaction)
|
|
494
|
-
let dispatchTransaction = this._props.dispatchTransaction
|
|
495
|
-
if (dispatchTransaction) dispatchTransaction.call(this, tr)
|
|
496
|
-
else this.updateState(this.state.apply(tr))
|
|
497
|
-
}
|
|
494
|
+
declare dispatch: (tr: Transaction) => void
|
|
498
495
|
|
|
499
496
|
/// @internal
|
|
500
497
|
domSelectionRange(): DOMSelectionRange {
|
|
@@ -510,6 +507,12 @@ export class EditorView {
|
|
|
510
507
|
}
|
|
511
508
|
}
|
|
512
509
|
|
|
510
|
+
EditorView.prototype.dispatch = function(tr: Transaction) {
|
|
511
|
+
let dispatchTransaction = this._props.dispatchTransaction
|
|
512
|
+
if (dispatchTransaction) dispatchTransaction.call(this, tr)
|
|
513
|
+
else this.updateState(this.state.apply(tr))
|
|
514
|
+
}
|
|
515
|
+
|
|
513
516
|
function computeDocDeco(view: EditorView) {
|
|
514
517
|
let attrs = Object.create(null)
|
|
515
518
|
attrs.class = "ProseMirror"
|
|
@@ -635,7 +638,7 @@ export interface EditorProps<P = any> {
|
|
|
635
638
|
/// Whenever the user directly input text, this handler is called
|
|
636
639
|
/// before the input is applied. If it returns `true`, the default
|
|
637
640
|
/// behavior of actually inserting the text is suppressed.
|
|
638
|
-
handleTextInput?: (this: P, view: EditorView, from: number, to: number, text: string) => boolean | void
|
|
641
|
+
handleTextInput?: (this: P, view: EditorView, from: number, to: number, text: string, deflt: () => Transaction) => boolean | void
|
|
639
642
|
|
|
640
643
|
/// Called for each node around a click, from the inside out. The
|
|
641
644
|
/// `direct` flag will be true for the inner node.
|
package/src/input.ts
CHANGED
|
@@ -21,7 +21,7 @@ export class InputState {
|
|
|
21
21
|
mouseDown: MouseDown | null = null
|
|
22
22
|
lastKeyCode: number | null = null
|
|
23
23
|
lastKeyCodeTime = 0
|
|
24
|
-
lastClick = {time: 0, x: 0, y: 0, type: ""}
|
|
24
|
+
lastClick = {time: 0, x: 0, y: 0, type: "", button: 0}
|
|
25
25
|
lastSelectionOrigin: string | null = null
|
|
26
26
|
lastSelectionTime = 0
|
|
27
27
|
lastIOSEnter = 0
|
|
@@ -151,8 +151,9 @@ editHandlers.keypress = (view, _event) => {
|
|
|
151
151
|
let sel = view.state.selection
|
|
152
152
|
if (!(sel instanceof TextSelection) || !sel.$from.sameParent(sel.$to)) {
|
|
153
153
|
let text = String.fromCharCode(event.charCode)
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
let deflt = () => view.state.tr.insertText(text).scrollIntoView()
|
|
155
|
+
if (!/[\r\n]/.test(text) && !view.someProp("handleTextInput", f => f(view, sel.$from.pos, sel.$to.pos, text, deflt)))
|
|
156
|
+
view.dispatch(deflt())
|
|
156
157
|
event.preventDefault()
|
|
157
158
|
}
|
|
158
159
|
}
|
|
@@ -278,11 +279,12 @@ handlers.mousedown = (view, _event) => {
|
|
|
278
279
|
view.input.shiftKey = event.shiftKey
|
|
279
280
|
let flushed = forceDOMFlush(view)
|
|
280
281
|
let now = Date.now(), type = "singleClick"
|
|
281
|
-
if (now - view.input.lastClick.time < 500 && isNear(event, view.input.lastClick) && !event[selectNodeModifier]
|
|
282
|
+
if (now - view.input.lastClick.time < 500 && isNear(event, view.input.lastClick) && !event[selectNodeModifier] &&
|
|
283
|
+
view.input.lastClick.button == event.button) {
|
|
282
284
|
if (view.input.lastClick.type == "singleClick") type = "doubleClick"
|
|
283
285
|
else if (view.input.lastClick.type == "doubleClick") type = "tripleClick"
|
|
284
286
|
}
|
|
285
|
-
view.input.lastClick = {time: now, x: event.clientX, y: event.clientY, type}
|
|
287
|
+
view.input.lastClick = {time: now, x: event.clientX, y: event.clientY, type, button: event.button}
|
|
286
288
|
|
|
287
289
|
let pos = view.posAtCoords(eventCoords(event))
|
|
288
290
|
if (!pos) return
|
|
@@ -544,9 +546,9 @@ export function endComposition(view: EditorView, restarting = false) {
|
|
|
544
546
|
view.domObserver.forceFlush()
|
|
545
547
|
clearComposition(view)
|
|
546
548
|
if (restarting || view.docView && view.docView.dirty) {
|
|
547
|
-
let sel = selectionFromDOM(view)
|
|
548
|
-
if (sel && !sel.eq(
|
|
549
|
-
else if ((view.markCursor || restarting) && !
|
|
549
|
+
let sel = selectionFromDOM(view), cur = view.state.selection
|
|
550
|
+
if (sel && !sel.eq(cur)) view.dispatch(view.state.tr.setSelection(sel))
|
|
551
|
+
else if ((view.markCursor || restarting) && !cur.$from.node(cur.$from.sharedDepth(cur.to)).inlineContent) view.dispatch(view.state.tr.deleteSelection())
|
|
550
552
|
else view.updateState(view.state)
|
|
551
553
|
return true
|
|
552
554
|
}
|
package/src/viewdesc.ts
CHANGED
|
@@ -528,6 +528,8 @@ export class ViewDesc {
|
|
|
528
528
|
|
|
529
529
|
get ignoreForCoords() { return false }
|
|
530
530
|
|
|
531
|
+
get ignoreForSelection() { return false }
|
|
532
|
+
|
|
531
533
|
isText(text: string) { return false }
|
|
532
534
|
}
|
|
533
535
|
|
|
@@ -576,6 +578,8 @@ class WidgetViewDesc extends ViewDesc {
|
|
|
576
578
|
|
|
577
579
|
get domAtom() { return true }
|
|
578
580
|
|
|
581
|
+
get ignoreForSelection() { return !!this.widget.type.spec.relaxedSide }
|
|
582
|
+
|
|
579
583
|
get side() { return (this.widget.type as any).side as number }
|
|
580
584
|
}
|
|
581
585
|
|