prosemirror-view 1.27.2 → 1.28.1
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 +16 -0
- package/dist/index.cjs +31 -10
- package/dist/index.d.ts +5 -0
- package/dist/index.js +30 -7
- package/package.json +1 -1
- package/src/clipboard.ts +2 -0
- package/src/index.ts +28 -5
- package/src/input.ts +1 -1
- package/src/selection.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 1.28.1 (2022-09-21)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where the editor would reset its scroll position to the top of the document for any state reconfiguration, even if the document was unchanged.
|
|
6
|
+
|
|
7
|
+
## 1.28.0 (2022-09-09)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Fix an issue where the editor wouldn't realize it was focused on IE when IE's resize controls are on an element inside the content. Adjust Chrome click-override behavior to only happen for invisible selections
|
|
12
|
+
|
|
13
|
+
### New features
|
|
14
|
+
|
|
15
|
+
The new `transformCopied` prop can be used to transform a copied/cut slice before it is serialized to the clipboard. Adjust doc comment
|
|
16
|
+
|
|
1
17
|
## 1.27.2 (2022-08-19)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -2590,7 +2590,7 @@ function selectionBetween(view, $anchor, $head, bias) {
|
|
|
2590
2590
|
}
|
|
2591
2591
|
|
|
2592
2592
|
function hasFocusAndSelection(view) {
|
|
2593
|
-
if (view.editable && view.
|
|
2593
|
+
if (view.editable && !view.hasFocus()) return false;
|
|
2594
2594
|
return hasSelection(view);
|
|
2595
2595
|
}
|
|
2596
2596
|
|
|
@@ -2887,10 +2887,14 @@ function captureKeyDown(view, event) {
|
|
|
2887
2887
|
}
|
|
2888
2888
|
|
|
2889
2889
|
function serializeForClipboard(view, slice) {
|
|
2890
|
+
view.someProp("transformCopied", function (f) {
|
|
2891
|
+
slice = f(slice);
|
|
2892
|
+
});
|
|
2890
2893
|
var context = [],
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
+
_slice = slice,
|
|
2895
|
+
content = _slice.content,
|
|
2896
|
+
openStart = _slice.openStart,
|
|
2897
|
+
openEnd = _slice.openEnd;
|
|
2894
2898
|
|
|
2895
2899
|
while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
|
|
2896
2900
|
openStart--;
|
|
@@ -3562,7 +3566,7 @@ var MouseDown = function () {
|
|
|
3562
3566
|
setSelectionOrigin(this.view, "pointer");
|
|
3563
3567
|
} else if (handleSingleClick(this.view, pos.pos, pos.inside, event, this.selectNode)) {
|
|
3564
3568
|
event.preventDefault();
|
|
3565
|
-
} else if (event.button == 0 && (this.flushed || safari && this.mightDrag && !this.mightDrag.node.isAtom || chrome && !
|
|
3569
|
+
} else if (event.button == 0 && (this.flushed || safari && this.mightDrag && !this.mightDrag.node.isAtom || chrome && !this.view.state.selection.visible && Math.min(Math.abs(pos.pos - this.view.state.selection.from), Math.abs(pos.pos - this.view.state.selection.to)) <= 2)) {
|
|
3566
3570
|
updateSelection(this.view, prosemirrorState.Selection.near(this.view.state.doc.resolve(pos.pos)), "pointer");
|
|
3567
3571
|
event.preventDefault();
|
|
3568
3572
|
} else {
|
|
@@ -5419,6 +5423,7 @@ var EditorView = function () {
|
|
|
5419
5423
|
key: "update",
|
|
5420
5424
|
value: function update(props) {
|
|
5421
5425
|
if (props.handleDOMEvents != this._props.handleDOMEvents) ensureListeners(this);
|
|
5426
|
+
var prevProps = this._props;
|
|
5422
5427
|
this._props = props;
|
|
5423
5428
|
|
|
5424
5429
|
if (props.plugins) {
|
|
@@ -5426,7 +5431,7 @@ var EditorView = function () {
|
|
|
5426
5431
|
this.directPlugins = props.plugins;
|
|
5427
5432
|
}
|
|
5428
5433
|
|
|
5429
|
-
this.updateStateInner(props.state,
|
|
5434
|
+
this.updateStateInner(props.state, prevProps);
|
|
5430
5435
|
}
|
|
5431
5436
|
}, {
|
|
5432
5437
|
key: "setProps",
|
|
@@ -5448,11 +5453,11 @@ var EditorView = function () {
|
|
|
5448
5453
|
}, {
|
|
5449
5454
|
key: "updateState",
|
|
5450
5455
|
value: function updateState(state) {
|
|
5451
|
-
this.updateStateInner(state, this.
|
|
5456
|
+
this.updateStateInner(state, this._props);
|
|
5452
5457
|
}
|
|
5453
5458
|
}, {
|
|
5454
5459
|
key: "updateStateInner",
|
|
5455
|
-
value: function updateStateInner(state,
|
|
5460
|
+
value: function updateStateInner(state, prevProps) {
|
|
5456
5461
|
var prev = this.state,
|
|
5457
5462
|
redraw = false,
|
|
5458
5463
|
updateSel = false;
|
|
@@ -5463,15 +5468,18 @@ var EditorView = function () {
|
|
|
5463
5468
|
}
|
|
5464
5469
|
|
|
5465
5470
|
this.state = state;
|
|
5471
|
+
var pluginsChanged = prev.plugins != state.plugins || this._props.plugins != prevProps.plugins;
|
|
5466
5472
|
|
|
5467
|
-
if (
|
|
5473
|
+
if (pluginsChanged || this._props.plugins != prevProps.plugins || this._props.nodeViews != prevProps.nodeViews) {
|
|
5468
5474
|
var nodeViews = buildNodeViews(this);
|
|
5469
5475
|
|
|
5470
5476
|
if (changedNodeViews(nodeViews, this.nodeViews)) {
|
|
5471
5477
|
this.nodeViews = nodeViews;
|
|
5472
5478
|
redraw = true;
|
|
5473
5479
|
}
|
|
5480
|
+
}
|
|
5474
5481
|
|
|
5482
|
+
if (pluginsChanged || prevProps.handleDOMEvents != this._props.handleDOMEvents) {
|
|
5475
5483
|
ensureListeners(this);
|
|
5476
5484
|
}
|
|
5477
5485
|
|
|
@@ -5479,7 +5487,7 @@ var EditorView = function () {
|
|
|
5479
5487
|
updateCursorWrapper(this);
|
|
5480
5488
|
var innerDeco = viewDecorations(this),
|
|
5481
5489
|
outerDeco = computeDocDeco(this);
|
|
5482
|
-
var scroll =
|
|
5490
|
+
var scroll = prev.plugins != state.plugins && !prev.doc.eq(state.doc) ? "reset" : state.scrollToSelection > prev.scrollToSelection ? "to selection" : "preserve";
|
|
5483
5491
|
var updateDoc = redraw || !this.docView.matchesNode(state.doc, outerDeco, innerDeco);
|
|
5484
5492
|
if (updateDoc || !state.selection.eq(prev.selection)) updateSel = true;
|
|
5485
5493
|
var oldScrollPos = scroll == "preserve" && updateSel && this.dom.style.overflowAnchor == null && storeScrollPos(this);
|
|
@@ -5588,6 +5596,19 @@ var EditorView = function () {
|
|
|
5588
5596
|
}, {
|
|
5589
5597
|
key: "hasFocus",
|
|
5590
5598
|
value: function hasFocus() {
|
|
5599
|
+
if (ie) {
|
|
5600
|
+
var node = this.root.activeElement;
|
|
5601
|
+
if (node == this.dom) return true;
|
|
5602
|
+
if (!node || !this.dom.contains(node)) return false;
|
|
5603
|
+
|
|
5604
|
+
while (node && this.dom != node && this.dom.contains(node)) {
|
|
5605
|
+
if (node.contentEditable == 'false') return false;
|
|
5606
|
+
node = node.parentElement;
|
|
5607
|
+
}
|
|
5608
|
+
|
|
5609
|
+
return true;
|
|
5610
|
+
}
|
|
5611
|
+
|
|
5591
5612
|
return this.root.activeElement == this.dom;
|
|
5592
5613
|
}
|
|
5593
5614
|
}, {
|
package/dist/index.d.ts
CHANGED
|
@@ -701,6 +701,11 @@ interface EditorProps<P = any> {
|
|
|
701
701
|
*/
|
|
702
702
|
transformPasted?: (this: P, slice: Slice) => Slice;
|
|
703
703
|
/**
|
|
704
|
+
Can be used to transform copied or cut content before it is
|
|
705
|
+
serialized to the clipboard.
|
|
706
|
+
*/
|
|
707
|
+
transformCopied?: (this: P, slice: Slice) => Slice;
|
|
708
|
+
/**
|
|
704
709
|
Allows you to pass custom rendering and behavior logic for
|
|
705
710
|
nodes. Should map node names to constructor functions that
|
|
706
711
|
produce a [`NodeView`](https://prosemirror.net/docs/ref/#view.NodeView) object implementing the
|
package/dist/index.js
CHANGED
|
@@ -2203,7 +2203,7 @@ function selectionBetween(view, $anchor, $head, bias) {
|
|
|
2203
2203
|
|| TextSelection.between($anchor, $head, bias);
|
|
2204
2204
|
}
|
|
2205
2205
|
function hasFocusAndSelection(view) {
|
|
2206
|
-
if (view.editable && view.
|
|
2206
|
+
if (view.editable && !view.hasFocus())
|
|
2207
2207
|
return false;
|
|
2208
2208
|
return hasSelection(view);
|
|
2209
2209
|
}
|
|
@@ -2532,6 +2532,7 @@ function captureKeyDown(view, event) {
|
|
|
2532
2532
|
}
|
|
2533
2533
|
|
|
2534
2534
|
function serializeForClipboard(view, slice) {
|
|
2535
|
+
view.someProp("transformCopied", f => { slice = f(slice); });
|
|
2535
2536
|
let context = [], { content, openStart, openEnd } = slice;
|
|
2536
2537
|
while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
|
|
2537
2538
|
openStart--;
|
|
@@ -3129,7 +3130,7 @@ class MouseDown {
|
|
|
3129
3130
|
// (hidden) cursor is doesn't change the selection, and
|
|
3130
3131
|
// thus doesn't get a reaction from ProseMirror. This
|
|
3131
3132
|
// works around that.
|
|
3132
|
-
(chrome && !
|
|
3133
|
+
(chrome && !this.view.state.selection.visible &&
|
|
3133
3134
|
Math.min(Math.abs(pos.pos - this.view.state.selection.from), Math.abs(pos.pos - this.view.state.selection.to)) <= 2))) {
|
|
3134
3135
|
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(pos.pos)), "pointer");
|
|
3135
3136
|
event.preventDefault();
|
|
@@ -4906,12 +4907,13 @@ class EditorView {
|
|
|
4906
4907
|
update(props) {
|
|
4907
4908
|
if (props.handleDOMEvents != this._props.handleDOMEvents)
|
|
4908
4909
|
ensureListeners(this);
|
|
4910
|
+
let prevProps = this._props;
|
|
4909
4911
|
this._props = props;
|
|
4910
4912
|
if (props.plugins) {
|
|
4911
4913
|
props.plugins.forEach(checkStateComponent);
|
|
4912
4914
|
this.directPlugins = props.plugins;
|
|
4913
4915
|
}
|
|
4914
|
-
this.updateStateInner(props.state,
|
|
4916
|
+
this.updateStateInner(props.state, prevProps);
|
|
4915
4917
|
}
|
|
4916
4918
|
/**
|
|
4917
4919
|
Update the view by updating existing props object with the object
|
|
@@ -4932,9 +4934,9 @@ class EditorView {
|
|
|
4932
4934
|
other props.
|
|
4933
4935
|
*/
|
|
4934
4936
|
updateState(state) {
|
|
4935
|
-
this.updateStateInner(state, this.
|
|
4937
|
+
this.updateStateInner(state, this._props);
|
|
4936
4938
|
}
|
|
4937
|
-
updateStateInner(state,
|
|
4939
|
+
updateStateInner(state, prevProps) {
|
|
4938
4940
|
let prev = this.state, redraw = false, updateSel = false;
|
|
4939
4941
|
// When stored marks are added, stop composition, so that they can
|
|
4940
4942
|
// be displayed.
|
|
@@ -4943,18 +4945,21 @@ class EditorView {
|
|
|
4943
4945
|
updateSel = true;
|
|
4944
4946
|
}
|
|
4945
4947
|
this.state = state;
|
|
4946
|
-
|
|
4948
|
+
let pluginsChanged = prev.plugins != state.plugins || this._props.plugins != prevProps.plugins;
|
|
4949
|
+
if (pluginsChanged || this._props.plugins != prevProps.plugins || this._props.nodeViews != prevProps.nodeViews) {
|
|
4947
4950
|
let nodeViews = buildNodeViews(this);
|
|
4948
4951
|
if (changedNodeViews(nodeViews, this.nodeViews)) {
|
|
4949
4952
|
this.nodeViews = nodeViews;
|
|
4950
4953
|
redraw = true;
|
|
4951
4954
|
}
|
|
4955
|
+
}
|
|
4956
|
+
if (pluginsChanged || prevProps.handleDOMEvents != this._props.handleDOMEvents) {
|
|
4952
4957
|
ensureListeners(this);
|
|
4953
4958
|
}
|
|
4954
4959
|
this.editable = getEditable(this);
|
|
4955
4960
|
updateCursorWrapper(this);
|
|
4956
4961
|
let innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this);
|
|
4957
|
-
let scroll =
|
|
4962
|
+
let scroll = prev.plugins != state.plugins && !prev.doc.eq(state.doc) ? "reset"
|
|
4958
4963
|
: state.scrollToSelection > prev.scrollToSelection ? "to selection" : "preserve";
|
|
4959
4964
|
let updateDoc = redraw || !this.docView.matchesNode(state.doc, outerDeco, innerDeco);
|
|
4960
4965
|
if (updateDoc || !state.selection.eq(prev.selection))
|
|
@@ -5073,6 +5078,24 @@ class EditorView {
|
|
|
5073
5078
|
Query whether the view has focus.
|
|
5074
5079
|
*/
|
|
5075
5080
|
hasFocus() {
|
|
5081
|
+
// Work around IE not handling focus correctly if resize handles are shown.
|
|
5082
|
+
// If the cursor is inside an element with resize handles, activeElement
|
|
5083
|
+
// will be that element instead of this.dom.
|
|
5084
|
+
if (ie) {
|
|
5085
|
+
// If activeElement is within this.dom, and there are no other elements
|
|
5086
|
+
// setting `contenteditable` to false in between, treat it as focused.
|
|
5087
|
+
let node = this.root.activeElement;
|
|
5088
|
+
if (node == this.dom)
|
|
5089
|
+
return true;
|
|
5090
|
+
if (!node || !this.dom.contains(node))
|
|
5091
|
+
return false;
|
|
5092
|
+
while (node && this.dom != node && this.dom.contains(node)) {
|
|
5093
|
+
if (node.contentEditable == 'false')
|
|
5094
|
+
return false;
|
|
5095
|
+
node = node.parentElement;
|
|
5096
|
+
}
|
|
5097
|
+
return true;
|
|
5098
|
+
}
|
|
5076
5099
|
return this.root.activeElement == this.dom;
|
|
5077
5100
|
}
|
|
5078
5101
|
/**
|
package/package.json
CHANGED
package/src/clipboard.ts
CHANGED
|
@@ -3,6 +3,8 @@ import * as browser from "./browser"
|
|
|
3
3
|
import {EditorView} from "./index"
|
|
4
4
|
|
|
5
5
|
export function serializeForClipboard(view: EditorView, slice: Slice) {
|
|
6
|
+
view.someProp("transformCopied", f => { slice = f(slice!) })
|
|
7
|
+
|
|
6
8
|
let context = [], {content, openStart, openEnd} = slice
|
|
7
9
|
while (openStart > 1 && openEnd > 1 && content.childCount == 1 && content.firstChild!.childCount == 1) {
|
|
8
10
|
openStart--
|
package/src/index.ts
CHANGED
|
@@ -124,12 +124,13 @@ export class EditorView {
|
|
|
124
124
|
/// the DOM.
|
|
125
125
|
update(props: DirectEditorProps) {
|
|
126
126
|
if (props.handleDOMEvents != this._props.handleDOMEvents) ensureListeners(this)
|
|
127
|
+
let prevProps = this._props
|
|
127
128
|
this._props = props
|
|
128
129
|
if (props.plugins) {
|
|
129
130
|
props.plugins.forEach(checkStateComponent)
|
|
130
131
|
this.directPlugins = props.plugins
|
|
131
132
|
}
|
|
132
|
-
this.updateStateInner(props.state,
|
|
133
|
+
this.updateStateInner(props.state, prevProps)
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
/// Update the view by updating existing props object with the object
|
|
@@ -146,10 +147,10 @@ export class EditorView {
|
|
|
146
147
|
/// Update the editor's `state` prop, without touching any of the
|
|
147
148
|
/// other props.
|
|
148
149
|
updateState(state: EditorState) {
|
|
149
|
-
this.updateStateInner(state, this.
|
|
150
|
+
this.updateStateInner(state, this._props)
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
private updateStateInner(state: EditorState,
|
|
153
|
+
private updateStateInner(state: EditorState, prevProps: DirectEditorProps) {
|
|
153
154
|
let prev = this.state, redraw = false, updateSel = false
|
|
154
155
|
// When stored marks are added, stop composition, so that they can
|
|
155
156
|
// be displayed.
|
|
@@ -158,12 +159,15 @@ export class EditorView {
|
|
|
158
159
|
updateSel = true
|
|
159
160
|
}
|
|
160
161
|
this.state = state
|
|
161
|
-
|
|
162
|
+
let pluginsChanged = prev.plugins != state.plugins || this._props.plugins != prevProps.plugins
|
|
163
|
+
if (pluginsChanged || this._props.plugins != prevProps.plugins || this._props.nodeViews != prevProps.nodeViews) {
|
|
162
164
|
let nodeViews = buildNodeViews(this)
|
|
163
165
|
if (changedNodeViews(nodeViews, this.nodeViews)) {
|
|
164
166
|
this.nodeViews = nodeViews
|
|
165
167
|
redraw = true
|
|
166
168
|
}
|
|
169
|
+
}
|
|
170
|
+
if (pluginsChanged || prevProps.handleDOMEvents != this._props.handleDOMEvents) {
|
|
167
171
|
ensureListeners(this)
|
|
168
172
|
}
|
|
169
173
|
|
|
@@ -171,7 +175,7 @@ export class EditorView {
|
|
|
171
175
|
updateCursorWrapper(this)
|
|
172
176
|
let innerDeco = viewDecorations(this), outerDeco = computeDocDeco(this)
|
|
173
177
|
|
|
174
|
-
let scroll =
|
|
178
|
+
let scroll = prev.plugins != state.plugins && !prev.doc.eq(state.doc) ? "reset"
|
|
175
179
|
: (state as any).scrollToSelection > (prev as any).scrollToSelection ? "to selection" : "preserve"
|
|
176
180
|
let updateDoc = redraw || !this.docView.matchesNode(state.doc, outerDeco, innerDeco)
|
|
177
181
|
if (updateDoc || !state.selection.eq(prev.selection)) updateSel = true
|
|
@@ -292,6 +296,21 @@ export class EditorView {
|
|
|
292
296
|
|
|
293
297
|
/// Query whether the view has focus.
|
|
294
298
|
hasFocus() {
|
|
299
|
+
// Work around IE not handling focus correctly if resize handles are shown.
|
|
300
|
+
// If the cursor is inside an element with resize handles, activeElement
|
|
301
|
+
// will be that element instead of this.dom.
|
|
302
|
+
if (browser.ie) {
|
|
303
|
+
// If activeElement is within this.dom, and there are no other elements
|
|
304
|
+
// setting `contenteditable` to false in between, treat it as focused.
|
|
305
|
+
let node = this.root.activeElement
|
|
306
|
+
if (node == this.dom) return true
|
|
307
|
+
if (!node || !this.dom.contains(node)) return false
|
|
308
|
+
while (node && this.dom != node && this.dom.contains(node)) {
|
|
309
|
+
if ((node as HTMLElement).contentEditable == 'false') return false
|
|
310
|
+
node = node.parentElement
|
|
311
|
+
}
|
|
312
|
+
return true
|
|
313
|
+
}
|
|
295
314
|
return this.root.activeElement == this.dom
|
|
296
315
|
}
|
|
297
316
|
|
|
@@ -636,6 +655,10 @@ export interface EditorProps<P = any> {
|
|
|
636
655
|
/// before it is applied to the document.
|
|
637
656
|
transformPasted?: (this: P, slice: Slice) => Slice
|
|
638
657
|
|
|
658
|
+
/// Can be used to transform copied or cut content before it is
|
|
659
|
+
/// serialized to the clipboard.
|
|
660
|
+
transformCopied?: (this: P, slice: Slice) => Slice
|
|
661
|
+
|
|
639
662
|
/// Allows you to pass custom rendering and behavior logic for
|
|
640
663
|
/// nodes. Should map node names to constructor functions that
|
|
641
664
|
/// produce a [`NodeView`](#view.NodeView) object implementing the
|
package/src/input.ts
CHANGED
|
@@ -388,7 +388,7 @@ class MouseDown {
|
|
|
388
388
|
// (hidden) cursor is doesn't change the selection, and
|
|
389
389
|
// thus doesn't get a reaction from ProseMirror. This
|
|
390
390
|
// works around that.
|
|
391
|
-
(browser.chrome && !
|
|
391
|
+
(browser.chrome && !this.view.state.selection.visible &&
|
|
392
392
|
Math.min(Math.abs(pos.pos - this.view.state.selection.from),
|
|
393
393
|
Math.abs(pos.pos - this.view.state.selection.to)) <= 2))) {
|
|
394
394
|
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(pos.pos)), "pointer")
|
package/src/selection.ts
CHANGED
|
@@ -181,7 +181,7 @@ export function selectionBetween(view: EditorView, $anchor: ResolvedPos, $head:
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export function hasFocusAndSelection(view: EditorView) {
|
|
184
|
-
if (view.editable && view.
|
|
184
|
+
if (view.editable && !view.hasFocus()) return false
|
|
185
185
|
return hasSelection(view)
|
|
186
186
|
}
|
|
187
187
|
|