@bigbinary/neeto-editor 1.47.123 → 1.47.125
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 +7 -2
- package/dist/Editor.js.map +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 +7 -2
- package/dist/cjs/Editor.cjs.js.map +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 +1 -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/FormikEditor.js
CHANGED
|
@@ -17,7 +17,7 @@ import 'zustand';
|
|
|
17
17
|
import 'classnames';
|
|
18
18
|
import './chunk-DDwycKmK.js';
|
|
19
19
|
import '@bigbinary/neetoui/Label';
|
|
20
|
-
import './chunk-
|
|
20
|
+
import './chunk-Be5ikGpm.js';
|
|
21
21
|
import './chunk-Qg4uQqj3.js';
|
|
22
22
|
import './chunk-BFTU3MAI.js';
|
|
23
23
|
import '@bigbinary/neeto-commons-frontend/initializers';
|
|
@@ -3168,6 +3168,31 @@ const ySyncPlugin = (yXmlFragment, {
|
|
|
3168
3168
|
return plugin
|
|
3169
3169
|
};
|
|
3170
3170
|
|
|
3171
|
+
/**
|
|
3172
|
+
* Resolves one text-selection endpoint after a remote update. Falls back to
|
|
3173
|
+
* content-based matching when the Yjs resolution is missing or lands in the
|
|
3174
|
+
* wrong block, and keeps the Yjs resolution when the fallback finds nothing.
|
|
3175
|
+
*
|
|
3176
|
+
* @param {import('prosemirror-model').Node} newDoc
|
|
3177
|
+
* @param {import('prosemirror-model').Node} oldDoc
|
|
3178
|
+
* @param {number|null|undefined} oldAbs
|
|
3179
|
+
* @param {number|null} resolved
|
|
3180
|
+
* @return {number|null}
|
|
3181
|
+
*/
|
|
3182
|
+
const recoverSelectionEndpoint = (newDoc, oldDoc, oldAbs, resolved) => {
|
|
3183
|
+
if (oldAbs == null) {
|
|
3184
|
+
return resolved
|
|
3185
|
+
}
|
|
3186
|
+
const misresolved = resolved === null ||
|
|
3187
|
+
(oldAbs > 1 && resolved <= 1) ||
|
|
3188
|
+
isMisresolvedAfterStructuralChange(oldDoc, newDoc, oldAbs, resolved);
|
|
3189
|
+
if (!misresolved) {
|
|
3190
|
+
return resolved
|
|
3191
|
+
}
|
|
3192
|
+
const recovered = findAbsolutePositionAfterStructuralChange(oldDoc, newDoc, oldAbs);
|
|
3193
|
+
return recovered !== null ? recovered : resolved
|
|
3194
|
+
};
|
|
3195
|
+
|
|
3171
3196
|
/**
|
|
3172
3197
|
* @param {import('prosemirror-state').Transaction} tr
|
|
3173
3198
|
* @param {ReturnType<typeof getRelativeSelection>} relSel
|
|
@@ -3220,28 +3245,17 @@ const restoreRelativeSelection = (tr, relSel, binding, oldDoc) => {
|
|
|
3220
3245
|
relSel.head,
|
|
3221
3246
|
binding.mapping
|
|
3222
3247
|
);
|
|
3223
|
-
|
|
3224
|
-
relSel.absAnchor
|
|
3225
|
-
relSel.absHead
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
if (needsContentFallback) {
|
|
3235
|
-
anchor = findAbsolutePositionAfterStructuralChange(
|
|
3236
|
-
oldDoc,
|
|
3237
|
-
tr.doc,
|
|
3238
|
-
relSel.absAnchor
|
|
3239
|
-
);
|
|
3240
|
-
head = findAbsolutePositionAfterStructuralChange(
|
|
3241
|
-
oldDoc,
|
|
3242
|
-
tr.doc,
|
|
3243
|
-
relSel.absHead
|
|
3244
|
-
);
|
|
3248
|
+
if (oldDoc != null) {
|
|
3249
|
+
anchor = recoverSelectionEndpoint(tr.doc, oldDoc, relSel.absAnchor, anchor);
|
|
3250
|
+
head = recoverSelectionEndpoint(tr.doc, oldDoc, relSel.absHead, head);
|
|
3251
|
+
}
|
|
3252
|
+
// Collapse to the surviving endpoint instead of dropping the selection;
|
|
3253
|
+
// an unset selection maps through the full-doc replace to the doc start.
|
|
3254
|
+
if (anchor === null) {
|
|
3255
|
+
anchor = head;
|
|
3256
|
+
}
|
|
3257
|
+
if (head === null) {
|
|
3258
|
+
head = anchor;
|
|
3245
3259
|
}
|
|
3246
3260
|
if (anchor !== null && head !== null) {
|
|
3247
3261
|
tr.setSelection(TextSelection$1.between(tr.doc.resolve(anchor), tr.doc.resolve(head)));
|
|
@@ -4657,6 +4671,73 @@ const relativePositionToAbsolutePosition = (y, documentType, relPos, mapping) =>
|
|
|
4657
4671
|
return absPos
|
|
4658
4672
|
};
|
|
4659
4673
|
|
|
4674
|
+
/**
|
|
4675
|
+
* Shallow attrs comparison. Attr values are primitives in most schemas;
|
|
4676
|
+
* non-primitive values fail the check and callers fall back to text matching.
|
|
4677
|
+
*
|
|
4678
|
+
* @param {Object<string, any>} a
|
|
4679
|
+
* @param {Object<string, any>} b
|
|
4680
|
+
* @return {boolean}
|
|
4681
|
+
*/
|
|
4682
|
+
const attrsEqual = (a, b) => {
|
|
4683
|
+
if (a === b) {
|
|
4684
|
+
return true
|
|
4685
|
+
}
|
|
4686
|
+
const aKeys = Object.keys(a);
|
|
4687
|
+
return aKeys.length === Object.keys(b).length && aKeys.every((k) => a[k] === b[k])
|
|
4688
|
+
};
|
|
4689
|
+
|
|
4690
|
+
/**
|
|
4691
|
+
* Returns true when any attr deviates from its spec default or has none.
|
|
4692
|
+
* Default-only attrs cannot tell same-type siblings apart.
|
|
4693
|
+
*
|
|
4694
|
+
* @param {import('prosemirror-model').Node} node
|
|
4695
|
+
* @return {boolean}
|
|
4696
|
+
*/
|
|
4697
|
+
const hasDistinctiveAttrs = (node) => {
|
|
4698
|
+
const specAttrs = node.type.spec.attrs || {};
|
|
4699
|
+
return Object.keys(node.attrs).some((key) => {
|
|
4700
|
+
const spec = specAttrs[key];
|
|
4701
|
+
return spec == null ||
|
|
4702
|
+
!Object.prototype.hasOwnProperty.call(spec, 'default') ||
|
|
4703
|
+
spec.default !== node.attrs[key]
|
|
4704
|
+
})
|
|
4705
|
+
};
|
|
4706
|
+
|
|
4707
|
+
/**
|
|
4708
|
+
* Remaps a position into a matched block by walking the same child-index path
|
|
4709
|
+
* it had in the old block. A raw byte offset would overshoot into a sibling
|
|
4710
|
+
* inner textblock when the old block contains local keystrokes that are not
|
|
4711
|
+
* yet part of the rebuilt document.
|
|
4712
|
+
*
|
|
4713
|
+
* @param {import('prosemirror-model').ResolvedPos} $oldPos
|
|
4714
|
+
* @param {number} newBlockStart
|
|
4715
|
+
* @param {import('prosemirror-model').Node} newBlock
|
|
4716
|
+
* @return {number|null}
|
|
4717
|
+
*/
|
|
4718
|
+
const remapIntoBlock = ($oldPos, newBlockStart, newBlock) => {
|
|
4719
|
+
let pos = newBlockStart + 1;
|
|
4720
|
+
let node = newBlock;
|
|
4721
|
+
for (let depth = 1; depth < $oldPos.depth; depth++) {
|
|
4722
|
+
const idx = $oldPos.index(depth);
|
|
4723
|
+
if (idx >= node.childCount) {
|
|
4724
|
+
return null
|
|
4725
|
+
}
|
|
4726
|
+
for (let i = 0; i < idx; i++) {
|
|
4727
|
+
pos += node.child(i).nodeSize;
|
|
4728
|
+
}
|
|
4729
|
+
pos += 1;
|
|
4730
|
+
node = node.child(idx);
|
|
4731
|
+
if (node.type !== $oldPos.node(depth + 1).type) {
|
|
4732
|
+
return null
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
if (!node.isTextblock) {
|
|
4736
|
+
return null
|
|
4737
|
+
}
|
|
4738
|
+
return pos + Math.min($oldPos.parentOffset, node.content.size)
|
|
4739
|
+
};
|
|
4740
|
+
|
|
4660
4741
|
/**
|
|
4661
4742
|
* @param {import('prosemirror-model').Node} oldDoc
|
|
4662
4743
|
* @param {import('prosemirror-model').Node} newDoc
|
|
@@ -4677,32 +4758,100 @@ const findAbsolutePositionAfterStructuralChange = (oldDoc, newDoc, absPos) => {
|
|
|
4677
4758
|
return null
|
|
4678
4759
|
}
|
|
4679
4760
|
const targetChild = oldDoc.child(targetIdx);
|
|
4680
|
-
const
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4761
|
+
const $oldPos = oldDoc.resolve(absPos);
|
|
4762
|
+
|
|
4763
|
+
/**
|
|
4764
|
+
* @param {number} newBlockStart
|
|
4765
|
+
* @param {import('prosemirror-model').Node} newBlock
|
|
4766
|
+
* @return {number|null}
|
|
4767
|
+
*/
|
|
4768
|
+
const place = (newBlockStart, newBlock) => {
|
|
4769
|
+
// Positions between top-level blocks carry no inner path; clamp them just
|
|
4770
|
+
// inside the matched block like the previous raw-offset remap did.
|
|
4771
|
+
if ($oldPos.depth === 0) {
|
|
4772
|
+
const remapped = newBlockStart + (absPos - pos);
|
|
4773
|
+
const contentStart = newBlockStart + 1;
|
|
4774
|
+
const contentEnd = newBlockStart + newBlock.nodeSize - 1;
|
|
4775
|
+
return Math.max(contentStart, Math.min(remapped, contentEnd))
|
|
4776
|
+
}
|
|
4777
|
+
return remapIntoBlock($oldPos, newBlockStart, newBlock)
|
|
4778
|
+
};
|
|
4779
|
+
|
|
4780
|
+
/**
|
|
4781
|
+
* Finds the Nth block in newDoc matching `pred`, where N is the number of
|
|
4782
|
+
* matching blocks in oldDoc up to and including the target block.
|
|
4783
|
+
*
|
|
4784
|
+
* @param {function(import('prosemirror-model').Node): boolean} pred
|
|
4785
|
+
* @param {boolean} requireUnique
|
|
4786
|
+
* @return {number|null}
|
|
4787
|
+
*/
|
|
4788
|
+
const findByPredicate = (pred, requireUnique = false) => {
|
|
4789
|
+
let occurrence = 0;
|
|
4790
|
+
for (let i = 0; i <= targetIdx; i++) {
|
|
4791
|
+
if (pred(oldDoc.child(i))) {
|
|
4792
|
+
occurrence++;
|
|
4701
4793
|
}
|
|
4702
4794
|
}
|
|
4703
|
-
|
|
4795
|
+
let matchCount = 0;
|
|
4796
|
+
let matchStart = -1;
|
|
4797
|
+
let matchBlock = null;
|
|
4798
|
+
let newPos = 0;
|
|
4799
|
+
for (let i = 0; i < newDoc.childCount; i++) {
|
|
4800
|
+
const child = newDoc.child(i);
|
|
4801
|
+
if (pred(child)) {
|
|
4802
|
+
matchCount++;
|
|
4803
|
+
if (matchCount === occurrence) {
|
|
4804
|
+
matchStart = newPos;
|
|
4805
|
+
matchBlock = child;
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
newPos += child.nodeSize;
|
|
4809
|
+
}
|
|
4810
|
+
if (matchBlock === null || (requireUnique && (occurrence !== 1 || matchCount !== 1))) {
|
|
4811
|
+
return null
|
|
4812
|
+
}
|
|
4813
|
+
return place(matchStart, matchBlock)
|
|
4814
|
+
};
|
|
4815
|
+
|
|
4816
|
+
/**
|
|
4817
|
+
* @param {import('prosemirror-model').Node} child
|
|
4818
|
+
* @return {boolean}
|
|
4819
|
+
*/
|
|
4820
|
+
const sameTypeAndAttrs = (child) =>
|
|
4821
|
+
child.type === targetChild.type && attrsEqual(child.attrs, targetChild.attrs);
|
|
4822
|
+
const oldText = targetChild.textContent;
|
|
4823
|
+
|
|
4824
|
+
const byAll = findByPredicate((child) => sameTypeAndAttrs(child) && child.textContent === oldText);
|
|
4825
|
+
if (byAll !== null) {
|
|
4826
|
+
return byAll
|
|
4827
|
+
}
|
|
4828
|
+
|
|
4829
|
+
// Text must be matched before attrs: after a remote attr-only edit, the
|
|
4830
|
+
// attrs pass would steer the cursor into a sibling that kept the old attrs.
|
|
4831
|
+
const byText = findByPredicate(
|
|
4832
|
+
(child) => child.type === targetChild.type && child.textContent === oldText
|
|
4833
|
+
);
|
|
4834
|
+
if (byText !== null) {
|
|
4835
|
+
return byText
|
|
4836
|
+
}
|
|
4837
|
+
|
|
4838
|
+
// In-flight local typing diverges the text between both docs. Distinctive
|
|
4839
|
+
// attrs still identify the block; default-only attrs match every sibling.
|
|
4840
|
+
if (hasDistinctiveAttrs(targetChild)) {
|
|
4841
|
+
const byAttrs = findByPredicate(sameTypeAndAttrs, true);
|
|
4842
|
+
if (byAttrs !== null) {
|
|
4843
|
+
return byAttrs
|
|
4844
|
+
}
|
|
4704
4845
|
}
|
|
4705
|
-
|
|
4846
|
+
|
|
4847
|
+
// Trailing in-flight keystrokes leave a prefix relation between old and new
|
|
4848
|
+
// text. Empty text is a prefix of everything and must never match.
|
|
4849
|
+
return findByPredicate(
|
|
4850
|
+
(child) => sameTypeAndAttrs(child) &&
|
|
4851
|
+
oldText !== '' && child.textContent !== '' &&
|
|
4852
|
+
(oldText.startsWith(child.textContent) || child.textContent.startsWith(oldText)),
|
|
4853
|
+
true
|
|
4854
|
+
)
|
|
4706
4855
|
};
|
|
4707
4856
|
|
|
4708
4857
|
/**
|
|
@@ -4763,16 +4912,27 @@ const isMisresolvedAfterStructuralChange = (oldDoc, newDoc, oldAbs, resolvedAbs)
|
|
|
4763
4912
|
}
|
|
4764
4913
|
const $old = oldDoc.resolve(oldAbs);
|
|
4765
4914
|
const $new = newDoc.resolve(resolvedAbs);
|
|
4766
|
-
if (!$old.parent.isTextblock
|
|
4915
|
+
if (!$old.parent.isTextblock) {
|
|
4767
4916
|
return false
|
|
4768
4917
|
}
|
|
4918
|
+
// A textblock cursor cannot legitimately resolve into a non-textblock;
|
|
4919
|
+
// a structural reorder replaced the block via delete + insert.
|
|
4920
|
+
if (!$new.parent.isTextblock) {
|
|
4921
|
+
return true
|
|
4922
|
+
}
|
|
4769
4923
|
if ($old.parent.textContent !== $new.parent.textContent) {
|
|
4770
4924
|
return true
|
|
4771
4925
|
}
|
|
4772
4926
|
if ($old.parentOffset !== 0 && $new.parentOffset === 0) {
|
|
4773
4927
|
return true
|
|
4774
4928
|
}
|
|
4775
|
-
|
|
4929
|
+
const bothAtStart = $old.parentOffset === 0 && $new.parentOffset === 0;
|
|
4930
|
+
// A changed offset, type or attrs hints at a same-text sibling. When all
|
|
4931
|
+
// of them agree there is no signal left and the Yjs resolution must win.
|
|
4932
|
+
const suspicious = $old.parentOffset !== $new.parentOffset ||
|
|
4933
|
+
$old.parent.type !== $new.parent.type ||
|
|
4934
|
+
!attrsEqual($old.parent.attrs, $new.parent.attrs);
|
|
4935
|
+
if (bothAtStart || suspicious) {
|
|
4776
4936
|
const expected = findAbsolutePositionAfterStructuralChange(oldDoc, newDoc, oldAbs);
|
|
4777
4937
|
return expected !== null && expected !== resolvedAbs
|
|
4778
4938
|
}
|
|
@@ -4951,8 +5111,18 @@ const yCursorPlugin = (
|
|
|
4951
5111
|
apply (tr, prevState, oldState, newState) {
|
|
4952
5112
|
const ystate = ySyncPluginKey.getState(newState);
|
|
4953
5113
|
const yCursorState = tr.getMeta(yCursorPluginKey);
|
|
5114
|
+
const isRemoteChange = ystate && ystate.isChangeOrigin;
|
|
4954
5115
|
if (
|
|
4955
|
-
|
|
5116
|
+
tr.docChanged &&
|
|
5117
|
+
!isRemoteChange &&
|
|
5118
|
+
isStructuralTransaction(tr, oldState.doc)
|
|
5119
|
+
) {
|
|
5120
|
+
// The ProseMirror document leads the Yjs mapping during local moves.
|
|
5121
|
+
// Hide stale awareness until the collaborator publishes its new cursor.
|
|
5122
|
+
return DecorationSet.empty
|
|
5123
|
+
}
|
|
5124
|
+
if (
|
|
5125
|
+
isRemoteChange ||
|
|
4956
5126
|
(yCursorState && yCursorState.awarenessUpdated)
|
|
4957
5127
|
) {
|
|
4958
5128
|
return createDecorations(
|
|
@@ -4964,15 +5134,6 @@ const yCursorPlugin = (
|
|
|
4964
5134
|
)
|
|
4965
5135
|
}
|
|
4966
5136
|
if (tr.docChanged) {
|
|
4967
|
-
if (isStructuralTransaction(tr, oldState.doc)) {
|
|
4968
|
-
return createDecorations(
|
|
4969
|
-
newState,
|
|
4970
|
-
awareness,
|
|
4971
|
-
awarenessStateFilter,
|
|
4972
|
-
cursorBuilder,
|
|
4973
|
-
selectionBuilder
|
|
4974
|
-
)
|
|
4975
|
-
}
|
|
4976
5137
|
return prevState.map(tr.mapping, tr.doc)
|
|
4977
5138
|
}
|
|
4978
5139
|
return prevState
|
|
@@ -16774,4 +16935,4 @@ var fuzzySearch = function fuzzySearch(items, query) {
|
|
|
16774
16935
|
};
|
|
16775
16936
|
|
|
16776
16937
|
export { MODAL_TRANSFORM_X as A, BulletList as B, CharacterCount as C, MODAL_BOTTOM_MARGIN as D, buildArticleFullUrl as E, Focus as F, useEditorWarnings as G, useDeletedArticles as H, Link as L, MODE as M, OrderedList as O, Resizable as R, Table as T, index_default$1 as a, index_default$4 as b, index_default as c, index_default$7 as d, TaskList as e, fuzzySearch as f, TaskItem as g, index_default$a as h, index_default$2 as i, index_default$6 as j, TextStyle as k, index_default$5 as l, index_default$3 as m, TableRow as n, TableHeader as o, TableCell as p, Color as q, ListItem as r, scrollHandler as s, index_default$9 as t, index_default$8 as u, useFetchKbArticles as v, createArticleOptions as w, MODAL_LEFT_OFFSET as x, MODAL_TOP_OFFSET as y, MODAL_TRANSFORM_Y as z };
|
|
16777
|
-
//# sourceMappingURL=chunk-
|
|
16938
|
+
//# sourceMappingURL=chunk-Be5ikGpm.js.map
|