@bigbinary/neeto-editor 1.47.123 → 1.47.124
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/dist/Editor.js +1 -1
- package/dist/FormikEditor.js +1 -1
- package/dist/{chunk-Bmhz4YEy.js → chunk-Be5ikGpm.js} +219 -58
- package/dist/chunk-Be5ikGpm.js.map +1 -0
- package/dist/cjs/Editor.cjs.js +1 -1
- package/dist/cjs/FormikEditor.cjs.js +1 -1
- package/dist/cjs/{chunk-BXZTd0jZ.cjs.js → chunk-Ch4y-VZi.cjs.js} +219 -58
- package/dist/cjs/chunk-Ch4y-VZi.cjs.js.map +1 -0
- package/dist/cjs/index.cjs.js +1 -1
- package/dist/cjs/v2/Editor.cjs.js +1 -1
- package/dist/cjs/v2/FormikEditor.cjs.js +1 -1
- package/dist/cjs/v2/index.cjs.js +1 -1
- package/dist/editor-stats.html +19 -1
- package/dist/index.js +1 -1
- package/dist/v2/Editor.js +1 -1
- package/dist/v2/FormikEditor.js +1 -1
- package/dist/v2/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-Bmhz4YEy.js.map +0 -1
- package/dist/cjs/chunk-BXZTd0jZ.cjs.js.map +0 -1
package/dist/cjs/Editor.cjs.js
CHANGED
|
@@ -14,7 +14,7 @@ var Label = require('@bigbinary/neetoui/Label');
|
|
|
14
14
|
var ReactDOM$1 = require('react-dom');
|
|
15
15
|
var ramda = require('ramda');
|
|
16
16
|
var jsxRuntime = require('react/jsx-runtime');
|
|
17
|
-
var fuzzySearch = require('./chunk-
|
|
17
|
+
var fuzzySearch = require('./chunk-Ch4y-VZi.cjs.js');
|
|
18
18
|
var injectCss = require('./chunk-B6qYtOJe.cjs.js');
|
|
19
19
|
var utils = require('./chunk-B_7qxIrt.cjs.js');
|
|
20
20
|
var ReactDOM = require('react-dom/server');
|
|
@@ -19,7 +19,7 @@ require('zustand');
|
|
|
19
19
|
require('classnames');
|
|
20
20
|
require('./chunk-2HrSPdAV.cjs.js');
|
|
21
21
|
require('@bigbinary/neetoui/Label');
|
|
22
|
-
require('./chunk-
|
|
22
|
+
require('./chunk-Ch4y-VZi.cjs.js');
|
|
23
23
|
require('./chunk-BKvkHB8E.cjs.js');
|
|
24
24
|
require('./chunk-BJu3ubxk.cjs.js');
|
|
25
25
|
require('@bigbinary/neeto-commons-frontend/initializers');
|
|
@@ -3197,6 +3197,31 @@ const ySyncPlugin = (yXmlFragment, {
|
|
|
3197
3197
|
return plugin
|
|
3198
3198
|
};
|
|
3199
3199
|
|
|
3200
|
+
/**
|
|
3201
|
+
* Resolves one text-selection endpoint after a remote update. Falls back to
|
|
3202
|
+
* content-based matching when the Yjs resolution is missing or lands in the
|
|
3203
|
+
* wrong block, and keeps the Yjs resolution when the fallback finds nothing.
|
|
3204
|
+
*
|
|
3205
|
+
* @param {import('prosemirror-model').Node} newDoc
|
|
3206
|
+
* @param {import('prosemirror-model').Node} oldDoc
|
|
3207
|
+
* @param {number|null|undefined} oldAbs
|
|
3208
|
+
* @param {number|null} resolved
|
|
3209
|
+
* @return {number|null}
|
|
3210
|
+
*/
|
|
3211
|
+
const recoverSelectionEndpoint = (newDoc, oldDoc, oldAbs, resolved) => {
|
|
3212
|
+
if (oldAbs == null) {
|
|
3213
|
+
return resolved
|
|
3214
|
+
}
|
|
3215
|
+
const misresolved = resolved === null ||
|
|
3216
|
+
(oldAbs > 1 && resolved <= 1) ||
|
|
3217
|
+
isMisresolvedAfterStructuralChange(oldDoc, newDoc, oldAbs, resolved);
|
|
3218
|
+
if (!misresolved) {
|
|
3219
|
+
return resolved
|
|
3220
|
+
}
|
|
3221
|
+
const recovered = findAbsolutePositionAfterStructuralChange(oldDoc, newDoc, oldAbs);
|
|
3222
|
+
return recovered !== null ? recovered : resolved
|
|
3223
|
+
};
|
|
3224
|
+
|
|
3200
3225
|
/**
|
|
3201
3226
|
* @param {import('prosemirror-state').Transaction} tr
|
|
3202
3227
|
* @param {ReturnType<typeof getRelativeSelection>} relSel
|
|
@@ -3249,28 +3274,17 @@ const restoreRelativeSelection = (tr, relSel, binding, oldDoc) => {
|
|
|
3249
3274
|
relSel.head,
|
|
3250
3275
|
binding.mapping
|
|
3251
3276
|
);
|
|
3252
|
-
|
|
3253
|
-
relSel.absAnchor
|
|
3254
|
-
relSel.absHead
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
if (needsContentFallback) {
|
|
3264
|
-
anchor = findAbsolutePositionAfterStructuralChange(
|
|
3265
|
-
oldDoc,
|
|
3266
|
-
tr.doc,
|
|
3267
|
-
relSel.absAnchor
|
|
3268
|
-
);
|
|
3269
|
-
head = findAbsolutePositionAfterStructuralChange(
|
|
3270
|
-
oldDoc,
|
|
3271
|
-
tr.doc,
|
|
3272
|
-
relSel.absHead
|
|
3273
|
-
);
|
|
3277
|
+
if (oldDoc != null) {
|
|
3278
|
+
anchor = recoverSelectionEndpoint(tr.doc, oldDoc, relSel.absAnchor, anchor);
|
|
3279
|
+
head = recoverSelectionEndpoint(tr.doc, oldDoc, relSel.absHead, head);
|
|
3280
|
+
}
|
|
3281
|
+
// Collapse to the surviving endpoint instead of dropping the selection;
|
|
3282
|
+
// an unset selection maps through the full-doc replace to the doc start.
|
|
3283
|
+
if (anchor === null) {
|
|
3284
|
+
anchor = head;
|
|
3285
|
+
}
|
|
3286
|
+
if (head === null) {
|
|
3287
|
+
head = anchor;
|
|
3274
3288
|
}
|
|
3275
3289
|
if (anchor !== null && head !== null) {
|
|
3276
3290
|
tr.setSelection(index.TextSelection.between(tr.doc.resolve(anchor), tr.doc.resolve(head)));
|
|
@@ -4686,6 +4700,73 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
|
|
|
4686
4700
|
return absPos
|
|
4687
4701
|
};
|
|
4688
4702
|
|
|
4703
|
+
/**
|
|
4704
|
+
* Shallow attrs comparison. Attr values are primitives in most schemas;
|
|
4705
|
+
* non-primitive values fail the check and callers fall back to text matching.
|
|
4706
|
+
*
|
|
4707
|
+
* @param {Object<string, any>} a
|
|
4708
|
+
* @param {Object<string, any>} b
|
|
4709
|
+
* @return {boolean}
|
|
4710
|
+
*/
|
|
4711
|
+
const attrsEqual = (a, b) => {
|
|
4712
|
+
if (a === b) {
|
|
4713
|
+
return true
|
|
4714
|
+
}
|
|
4715
|
+
const aKeys = Object.keys(a);
|
|
4716
|
+
return aKeys.length === Object.keys(b).length && aKeys.every((k) => a[k] === b[k])
|
|
4717
|
+
};
|
|
4718
|
+
|
|
4719
|
+
/**
|
|
4720
|
+
* Returns true when any attr deviates from its spec default or has none.
|
|
4721
|
+
* Default-only attrs cannot tell same-type siblings apart.
|
|
4722
|
+
*
|
|
4723
|
+
* @param {import('prosemirror-model').Node} node
|
|
4724
|
+
* @return {boolean}
|
|
4725
|
+
*/
|
|
4726
|
+
const hasDistinctiveAttrs = (node) => {
|
|
4727
|
+
const specAttrs = node.type.spec.attrs || {};
|
|
4728
|
+
return Object.keys(node.attrs).some((key) => {
|
|
4729
|
+
const spec = specAttrs[key];
|
|
4730
|
+
return spec == null ||
|
|
4731
|
+
!Object.prototype.hasOwnProperty.call(spec, 'default') ||
|
|
4732
|
+
spec.default !== node.attrs[key]
|
|
4733
|
+
})
|
|
4734
|
+
};
|
|
4735
|
+
|
|
4736
|
+
/**
|
|
4737
|
+
* Remaps a position into a matched block by walking the same child-index path
|
|
4738
|
+
* it had in the old block. A raw byte offset would overshoot into a sibling
|
|
4739
|
+
* inner textblock when the old block contains local keystrokes that are not
|
|
4740
|
+
* yet part of the rebuilt document.
|
|
4741
|
+
*
|
|
4742
|
+
* @param {import('prosemirror-model').ResolvedPos} $oldPos
|
|
4743
|
+
* @param {number} newBlockStart
|
|
4744
|
+
* @param {import('prosemirror-model').Node} newBlock
|
|
4745
|
+
* @return {number|null}
|
|
4746
|
+
*/
|
|
4747
|
+
const remapIntoBlock = ($oldPos, newBlockStart, newBlock) => {
|
|
4748
|
+
let pos = newBlockStart + 1;
|
|
4749
|
+
let node = newBlock;
|
|
4750
|
+
for (let depth = 1; depth < $oldPos.depth; depth++) {
|
|
4751
|
+
const idx = $oldPos.index(depth);
|
|
4752
|
+
if (idx >= node.childCount) {
|
|
4753
|
+
return null
|
|
4754
|
+
}
|
|
4755
|
+
for (let i = 0; i < idx; i++) {
|
|
4756
|
+
pos += node.child(i).nodeSize;
|
|
4757
|
+
}
|
|
4758
|
+
pos += 1;
|
|
4759
|
+
node = node.child(idx);
|
|
4760
|
+
if (node.type !== $oldPos.node(depth + 1).type) {
|
|
4761
|
+
return null
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
if (!node.isTextblock) {
|
|
4765
|
+
return null
|
|
4766
|
+
}
|
|
4767
|
+
return pos + Math.min($oldPos.parentOffset, node.content.size)
|
|
4768
|
+
};
|
|
4769
|
+
|
|
4689
4770
|
/**
|
|
4690
4771
|
* @param {import('prosemirror-model').Node} oldDoc
|
|
4691
4772
|
* @param {import('prosemirror-model').Node} newDoc
|
|
@@ -4706,32 +4787,100 @@ const findAbsolutePositionAfterStructuralChange = (oldDoc, newDoc, absPos) => {
|
|
|
4706
4787
|
return null
|
|
4707
4788
|
}
|
|
4708
4789
|
const targetChild = oldDoc.child(targetIdx);
|
|
4709
|
-
const
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4790
|
+
const $oldPos = oldDoc.resolve(absPos);
|
|
4791
|
+
|
|
4792
|
+
/**
|
|
4793
|
+
* @param {number} newBlockStart
|
|
4794
|
+
* @param {import('prosemirror-model').Node} newBlock
|
|
4795
|
+
* @return {number|null}
|
|
4796
|
+
*/
|
|
4797
|
+
const place = (newBlockStart, newBlock) => {
|
|
4798
|
+
// Positions between top-level blocks carry no inner path; clamp them just
|
|
4799
|
+
// inside the matched block like the previous raw-offset remap did.
|
|
4800
|
+
if ($oldPos.depth === 0) {
|
|
4801
|
+
const remapped = newBlockStart + (absPos - pos);
|
|
4802
|
+
const contentStart = newBlockStart + 1;
|
|
4803
|
+
const contentEnd = newBlockStart + newBlock.nodeSize - 1;
|
|
4804
|
+
return Math.max(contentStart, Math.min(remapped, contentEnd))
|
|
4805
|
+
}
|
|
4806
|
+
return remapIntoBlock($oldPos, newBlockStart, newBlock)
|
|
4807
|
+
};
|
|
4808
|
+
|
|
4809
|
+
/**
|
|
4810
|
+
* Finds the Nth block in newDoc matching `pred`, where N is the number of
|
|
4811
|
+
* matching blocks in oldDoc up to and including the target block.
|
|
4812
|
+
*
|
|
4813
|
+
* @param {function(import('prosemirror-model').Node): boolean} pred
|
|
4814
|
+
* @param {boolean} requireUnique
|
|
4815
|
+
* @return {number|null}
|
|
4816
|
+
*/
|
|
4817
|
+
const findByPredicate = (pred, requireUnique = false) => {
|
|
4818
|
+
let occurrence = 0;
|
|
4819
|
+
for (let i = 0; i <= targetIdx; i++) {
|
|
4820
|
+
if (pred(oldDoc.child(i))) {
|
|
4821
|
+
occurrence++;
|
|
4730
4822
|
}
|
|
4731
4823
|
}
|
|
4732
|
-
|
|
4824
|
+
let matchCount = 0;
|
|
4825
|
+
let matchStart = -1;
|
|
4826
|
+
let matchBlock = null;
|
|
4827
|
+
let newPos = 0;
|
|
4828
|
+
for (let i = 0; i < newDoc.childCount; i++) {
|
|
4829
|
+
const child = newDoc.child(i);
|
|
4830
|
+
if (pred(child)) {
|
|
4831
|
+
matchCount++;
|
|
4832
|
+
if (matchCount === occurrence) {
|
|
4833
|
+
matchStart = newPos;
|
|
4834
|
+
matchBlock = child;
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
newPos += child.nodeSize;
|
|
4838
|
+
}
|
|
4839
|
+
if (matchBlock === null || (requireUnique && (occurrence !== 1 || matchCount !== 1))) {
|
|
4840
|
+
return null
|
|
4841
|
+
}
|
|
4842
|
+
return place(matchStart, matchBlock)
|
|
4843
|
+
};
|
|
4844
|
+
|
|
4845
|
+
/**
|
|
4846
|
+
* @param {import('prosemirror-model').Node} child
|
|
4847
|
+
* @return {boolean}
|
|
4848
|
+
*/
|
|
4849
|
+
const sameTypeAndAttrs = (child) =>
|
|
4850
|
+
child.type === targetChild.type && attrsEqual(child.attrs, targetChild.attrs);
|
|
4851
|
+
const oldText = targetChild.textContent;
|
|
4852
|
+
|
|
4853
|
+
const byAll = findByPredicate((child) => sameTypeAndAttrs(child) && child.textContent === oldText);
|
|
4854
|
+
if (byAll !== null) {
|
|
4855
|
+
return byAll
|
|
4856
|
+
}
|
|
4857
|
+
|
|
4858
|
+
// Text must be matched before attrs: after a remote attr-only edit, the
|
|
4859
|
+
// attrs pass would steer the cursor into a sibling that kept the old attrs.
|
|
4860
|
+
const byText = findByPredicate(
|
|
4861
|
+
(child) => child.type === targetChild.type && child.textContent === oldText
|
|
4862
|
+
);
|
|
4863
|
+
if (byText !== null) {
|
|
4864
|
+
return byText
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
// In-flight local typing diverges the text between both docs. Distinctive
|
|
4868
|
+
// attrs still identify the block; default-only attrs match every sibling.
|
|
4869
|
+
if (hasDistinctiveAttrs(targetChild)) {
|
|
4870
|
+
const byAttrs = findByPredicate(sameTypeAndAttrs, true);
|
|
4871
|
+
if (byAttrs !== null) {
|
|
4872
|
+
return byAttrs
|
|
4873
|
+
}
|
|
4733
4874
|
}
|
|
4734
|
-
|
|
4875
|
+
|
|
4876
|
+
// Trailing in-flight keystrokes leave a prefix relation between old and new
|
|
4877
|
+
// text. Empty text is a prefix of everything and must never match.
|
|
4878
|
+
return findByPredicate(
|
|
4879
|
+
(child) => sameTypeAndAttrs(child) &&
|
|
4880
|
+
oldText !== '' && child.textContent !== '' &&
|
|
4881
|
+
(oldText.startsWith(child.textContent) || child.textContent.startsWith(oldText)),
|
|
4882
|
+
true
|
|
4883
|
+
)
|
|
4735
4884
|
};
|
|
4736
4885
|
|
|
4737
4886
|
/**
|
|
@@ -4792,16 +4941,27 @@ const isMisresolvedAfterStructuralChange = (oldDoc, newDoc, oldAbs, resolvedAbs)
|
|
|
4792
4941
|
}
|
|
4793
4942
|
const $old = oldDoc.resolve(oldAbs);
|
|
4794
4943
|
const $new = newDoc.resolve(resolvedAbs);
|
|
4795
|
-
if (!$old.parent.isTextblock
|
|
4944
|
+
if (!$old.parent.isTextblock) {
|
|
4796
4945
|
return false
|
|
4797
4946
|
}
|
|
4947
|
+
// A textblock cursor cannot legitimately resolve into a non-textblock;
|
|
4948
|
+
// a structural reorder replaced the block via delete + insert.
|
|
4949
|
+
if (!$new.parent.isTextblock) {
|
|
4950
|
+
return true
|
|
4951
|
+
}
|
|
4798
4952
|
if ($old.parent.textContent !== $new.parent.textContent) {
|
|
4799
4953
|
return true
|
|
4800
4954
|
}
|
|
4801
4955
|
if ($old.parentOffset !== 0 && $new.parentOffset === 0) {
|
|
4802
4956
|
return true
|
|
4803
4957
|
}
|
|
4804
|
-
|
|
4958
|
+
const bothAtStart = $old.parentOffset === 0 && $new.parentOffset === 0;
|
|
4959
|
+
// A changed offset, type or attrs hints at a same-text sibling. When all
|
|
4960
|
+
// of them agree there is no signal left and the Yjs resolution must win.
|
|
4961
|
+
const suspicious = $old.parentOffset !== $new.parentOffset ||
|
|
4962
|
+
$old.parent.type !== $new.parent.type ||
|
|
4963
|
+
!attrsEqual($old.parent.attrs, $new.parent.attrs);
|
|
4964
|
+
if (bothAtStart || suspicious) {
|
|
4805
4965
|
const expected = findAbsolutePositionAfterStructuralChange(oldDoc, newDoc, oldAbs);
|
|
4806
4966
|
return expected !== null && expected !== resolvedAbs
|
|
4807
4967
|
}
|
|
@@ -4980,8 +5140,18 @@ const yCursorPlugin = (
|
|
|
4980
5140
|
apply (tr, prevState, oldState, newState) {
|
|
4981
5141
|
const ystate = ySyncPluginKey.getState(newState);
|
|
4982
5142
|
const yCursorState = tr.getMeta(yCursorPluginKey);
|
|
5143
|
+
const isRemoteChange = ystate && ystate.isChangeOrigin;
|
|
4983
5144
|
if (
|
|
4984
|
-
|
|
5145
|
+
tr.docChanged &&
|
|
5146
|
+
!isRemoteChange &&
|
|
5147
|
+
isStructuralTransaction(tr, oldState.doc)
|
|
5148
|
+
) {
|
|
5149
|
+
// The ProseMirror document leads the Yjs mapping during local moves.
|
|
5150
|
+
// Hide stale awareness until the collaborator publishes its new cursor.
|
|
5151
|
+
return useEditorStore.DecorationSet.empty
|
|
5152
|
+
}
|
|
5153
|
+
if (
|
|
5154
|
+
isRemoteChange ||
|
|
4985
5155
|
(yCursorState && yCursorState.awarenessUpdated)
|
|
4986
5156
|
) {
|
|
4987
5157
|
return createDecorations(
|
|
@@ -4993,15 +5163,6 @@ const yCursorPlugin = (
|
|
|
4993
5163
|
)
|
|
4994
5164
|
}
|
|
4995
5165
|
if (tr.docChanged) {
|
|
4996
|
-
if (isStructuralTransaction(tr, oldState.doc)) {
|
|
4997
|
-
return createDecorations(
|
|
4998
|
-
newState,
|
|
4999
|
-
awareness,
|
|
5000
|
-
awarenessStateFilter,
|
|
5001
|
-
cursorBuilder,
|
|
5002
|
-
selectionBuilder
|
|
5003
|
-
)
|
|
5004
|
-
}
|
|
5005
5166
|
return prevState.map(tr.mapping, tr.doc)
|
|
5006
5167
|
}
|
|
5007
5168
|
return prevState
|
|
@@ -16841,4 +17002,4 @@ exports.scrollHandler = scrollHandler;
|
|
|
16841
17002
|
exports.useDeletedArticles = useDeletedArticles;
|
|
16842
17003
|
exports.useEditorWarnings = useEditorWarnings;
|
|
16843
17004
|
exports.useFetchKbArticles = useFetchKbArticles;
|
|
16844
|
-
//# sourceMappingURL=chunk-
|
|
17005
|
+
//# sourceMappingURL=chunk-Ch4y-VZi.cjs.js.map
|