@ni/spright-components 6.23.0 → 6.23.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.
@@ -29797,7 +29797,6 @@ so this becomes the fallback color for the slot */ ''}
29797
29797
  if (!type)
29798
29798
  throw new RangeError(`There is no mark type ${json.type} in this schema`);
29799
29799
  let mark = type.create(json.attrs);
29800
- type.checkAttrs(mark.attrs);
29801
29800
  return mark;
29802
29801
  }
29803
29802
  /**
@@ -30777,11 +30776,11 @@ so this becomes the fallback color for the slot */ ''}
30777
30776
  */
30778
30777
  check() {
30779
30778
  this.type.checkContent(this.content);
30780
- this.type.checkAttrs(this.attrs);
30779
+ checkAttrs(this.type.attrs, this.attrs, "node", this.type.name);
30781
30780
  let copy = Mark$1.none;
30782
30781
  for (let i = 0; i < this.marks.length; i++) {
30783
30782
  let mark = this.marks[i];
30784
- mark.type.checkAttrs(mark.attrs);
30783
+ checkAttrs(mark.type.attrs, mark.attrs, "mark", mark.type.name);
30785
30784
  copy = mark.addToSet(copy);
30786
30785
  }
30787
30786
  if (!Mark$1.sameSet(copy, this.marks))
@@ -30822,7 +30821,6 @@ so this becomes the fallback color for the slot */ ''}
30822
30821
  }
30823
30822
  let content = Fragment.fromJSON(schema, json.content);
30824
30823
  let node = schema.nodeType(json.type).create(json.attrs, content, marks);
30825
- node.type.checkAttrs(node.attrs);
30826
30824
  return node;
30827
30825
  }
30828
30826
  };
@@ -30872,6 +30870,15 @@ so this becomes the fallback color for the slot */ ''}
30872
30870
  str = marks[i].type.name + "(" + str + ")";
30873
30871
  return str;
30874
30872
  }
30873
+ function checkAttrs(attrs, values, type, name) {
30874
+ for (let attr in values)
30875
+ if (!(attr in attrs))
30876
+ throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
30877
+ for (let attr in attrs) {
30878
+ if (attrs[attr].validate)
30879
+ attrs[attr].validate(values[attr]);
30880
+ }
30881
+ }
30875
30882
 
30876
30883
  /**
30877
30884
  Instances of this class represent a match state of a node type's
@@ -31326,27 +31333,21 @@ so this becomes the fallback color for the slot */ ''}
31326
31333
  function computeAttrs(attrs, value) {
31327
31334
  let built = Object.create(null);
31328
31335
  for (let name in attrs) {
31336
+ let attr = attrs[name];
31329
31337
  let given = value && value[name];
31330
31338
  if (given === undefined) {
31331
- let attr = attrs[name];
31332
31339
  if (attr.hasDefault)
31333
31340
  given = attr.default;
31334
31341
  else
31335
31342
  throw new RangeError("No value supplied for attribute " + name);
31336
31343
  }
31344
+ else if (attr.validate) {
31345
+ attr.validate(given);
31346
+ }
31337
31347
  built[name] = given;
31338
31348
  }
31339
31349
  return built;
31340
31350
  }
31341
- function checkAttrs(attrs, values, type, name) {
31342
- for (let attr in values)
31343
- if (!(attr in attrs))
31344
- throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
31345
- for (let attr in attrs) {
31346
- if (attrs[attr].validate)
31347
- attrs[attr].validate(values[attr]);
31348
- }
31349
- }
31350
31351
  function initAttrs(typeName, attrs) {
31351
31352
  let result = Object.create(null);
31352
31353
  if (attrs)
@@ -31518,11 +31519,9 @@ so this becomes the fallback color for the slot */ ''}
31518
31519
  throw new RangeError(`Invalid content for node ${this.name}: ${content.toString().slice(0, 50)}`);
31519
31520
  }
31520
31521
  /**
31521
- @internal
31522
+ @internal no longer useful, but called by old prosemirror-view versions
31522
31523
  */
31523
- checkAttrs(attrs) {
31524
- checkAttrs(this.attrs, attrs, "node", this.name);
31525
- }
31524
+ checkAttrs(attrs) { }
31526
31525
  /**
31527
31526
  Check whether the given mark type is allowed in this node.
31528
31527
  */
@@ -31669,12 +31668,6 @@ so this becomes the fallback color for the slot */ ''}
31669
31668
  return set[i];
31670
31669
  }
31671
31670
  /**
31672
- @internal
31673
- */
31674
- checkAttrs(attrs) {
31675
- checkAttrs(this.attrs, attrs, "mark", this.name);
31676
- }
31677
- /**
31678
31671
  Queries whether a given mark type is
31679
31672
  [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one.
31680
31673
  */
@@ -32865,9 +32858,12 @@ so this becomes the fallback color for the slot */ ''}
32865
32858
  if (simple)
32866
32859
  return result;
32867
32860
  let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start);
32868
- let del = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32869
- if (assoc < 0 ? pos != start : pos != end)
32870
- del |= DEL_SIDE;
32861
+ let del = 0;
32862
+ if (oldSize) {
32863
+ del |= pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32864
+ if (assoc < 0 ? pos != start : pos != end)
32865
+ del |= DEL_SIDE;
32866
+ }
32871
32867
  return new MapResult(result, del, recover);
32872
32868
  }
32873
32869
  diff += newSize - oldSize;
@@ -36805,15 +36801,15 @@ so this becomes the fallback color for the slot */ ''}
36805
36801
  return true;
36806
36802
  if (off == (dir < 0 ? 0 : nodeSize(node))) {
36807
36803
  let parent = node.parentNode;
36808
- if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36804
+ if (!parent || !isElt(parent) || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36809
36805
  node.contentEditable == "false")
36810
36806
  return false;
36811
36807
  off = domIndex(node) + (dir < 0 ? 0 : 1);
36812
36808
  node = parent;
36813
36809
  }
36814
- else if (node.nodeType == 1) {
36810
+ else if (isElt(node)) {
36815
36811
  let child = node.childNodes[off + (dir < 0 ? -1 : 0)];
36816
- if (child.nodeType == 1 && child.contentEditable == "false") {
36812
+ if (isElt(child) && child.contentEditable == "false") {
36817
36813
  if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection)
36818
36814
  off += dir;
36819
36815
  else
@@ -36832,11 +36828,16 @@ so this becomes the fallback color for the slot */ ''}
36832
36828
  function nodeSize(node) {
36833
36829
  return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
36834
36830
  }
36831
+ function isElt(node) { return node.nodeType == 1; }
36832
+ function isText(node) { return node.nodeType == 3; }
36833
+ function contains(parent, child) {
36834
+ return child ? parent.contains(isElt(child) ? child : child.parentNode) : false;
36835
+ }
36835
36836
  function textNodeBefore$1(node, offset) {
36836
36837
  for (;;) {
36837
- if (node.nodeType == 3 && offset)
36838
+ if (isText(node) && offset)
36838
36839
  return node;
36839
- if (node.nodeType == 1 && offset > 0) {
36840
+ if (isElt(node) && offset > 0) {
36840
36841
  if (node.contentEditable == "false")
36841
36842
  return null;
36842
36843
  node = node.childNodes[offset - 1];
@@ -36853,9 +36854,9 @@ so this becomes the fallback color for the slot */ ''}
36853
36854
  }
36854
36855
  function textNodeAfter$1(node, offset) {
36855
36856
  for (;;) {
36856
- if (node.nodeType == 3 && offset < node.nodeValue.length)
36857
+ if (isText(node) && offset < node.nodeValue.length)
36857
36858
  return node;
36858
- if (node.nodeType == 1 && offset < node.childNodes.length) {
36859
+ if (isElt(node) && offset < node.childNodes.length) {
36859
36860
  if (node.contentEditable == "false")
36860
36861
  return null;
36861
36862
  node = node.childNodes[offset];
@@ -36979,13 +36980,12 @@ so this becomes the fallback color for the slot */ ''}
36979
36980
  for (let parent = startDOM || view.dom;;) {
36980
36981
  if (!parent)
36981
36982
  break;
36982
- if (parent.nodeType != 1) {
36983
+ if (!isElt(parent)) {
36983
36984
  parent = parentNode(parent);
36984
36985
  continue;
36985
36986
  }
36986
- let elt = parent;
36987
- let atTop = elt == doc.body;
36988
- let bounding = atTop ? windowRect(doc) : clientRect(elt);
36987
+ let atTop = parent == doc.body;
36988
+ let bounding = atTop ? windowRect(doc) : clientRect(parent);
36989
36989
  let moveX = 0, moveY = 0;
36990
36990
  if (rect.top < bounding.top + getSide$1(scrollThreshold, "top"))
36991
36991
  moveY = -(bounding.top - rect.top + getSide$1(scrollMargin, "top"));
@@ -37002,12 +37002,12 @@ so this becomes the fallback color for the slot */ ''}
37002
37002
  doc.defaultView.scrollBy(moveX, moveY);
37003
37003
  }
37004
37004
  else {
37005
- let startX = elt.scrollLeft, startY = elt.scrollTop;
37005
+ let startX = parent.scrollLeft, startY = parent.scrollTop;
37006
37006
  if (moveY)
37007
- elt.scrollTop += moveY;
37007
+ parent.scrollTop += moveY;
37008
37008
  if (moveX)
37009
- elt.scrollLeft += moveX;
37010
- let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;
37009
+ parent.scrollLeft += moveX;
37010
+ let dX = parent.scrollLeft - startX, dY = parent.scrollTop - startY;
37011
37011
  rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
37012
37012
  }
37013
37013
  }
@@ -37082,14 +37082,15 @@ so this becomes the fallback color for the slot */ ''}
37082
37082
  }
37083
37083
  }
37084
37084
  function findOffsetInNode(node, coords) {
37085
- let closest, dxClosest = 2e8, coordsClosest, offset = 0;
37085
+ let closest;
37086
+ let dxClosest = 2e8, coordsClosest, offset = 0;
37086
37087
  let rowBot = coords.top, rowTop = coords.top;
37087
37088
  let firstBelow, coordsBelow;
37088
37089
  for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
37089
37090
  let rects;
37090
- if (child.nodeType == 1)
37091
+ if (isElt(child))
37091
37092
  rects = child.getClientRects();
37092
- else if (child.nodeType == 3)
37093
+ else if (isText(child))
37093
37094
  rects = textRange(child).getClientRects();
37094
37095
  else
37095
37096
  continue;
@@ -37103,11 +37104,11 @@ so this becomes the fallback color for the slot */ ''}
37103
37104
  if (dx < dxClosest) {
37104
37105
  closest = child;
37105
37106
  dxClosest = dx;
37106
- coordsClosest = dx && closest.nodeType == 3 ? {
37107
+ coordsClosest = dx && isText(closest) ? {
37107
37108
  left: rect.right < coords.left ? rect.right : rect.left,
37108
37109
  top: coords.top
37109
37110
  } : coords;
37110
- if (child.nodeType == 1 && dx)
37111
+ if (isElt(child) && dx)
37111
37112
  offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0);
37112
37113
  continue;
37113
37114
  }
@@ -37126,9 +37127,9 @@ so this becomes the fallback color for the slot */ ''}
37126
37127
  coordsClosest = coordsBelow;
37127
37128
  dxClosest = 0;
37128
37129
  }
37129
- if (closest && closest.nodeType == 3)
37130
+ if (closest && isText(closest))
37130
37131
  return findOffsetInText(closest, coordsClosest);
37131
- if (!closest || (dxClosest && closest.nodeType == 1))
37132
+ if (!closest || dxClosest)
37132
37133
  return { node, offset };
37133
37134
  return findOffsetInNode(closest, coordsClosest);
37134
37135
  }
@@ -37161,7 +37162,7 @@ so this becomes the fallback color for the slot */ ''}
37161
37162
  }
37162
37163
  function posFromElement(view, elt, coords) {
37163
37164
  let { node, offset } = findOffsetInNode(elt, coords), bias = -1;
37164
- if (node.nodeType == 1 && !node.firstChild) {
37165
+ if (isElt(node) && !node.firstChild) {
37165
37166
  let rect = node.getBoundingClientRect();
37166
37167
  bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
37167
37168
  }
@@ -37181,7 +37182,7 @@ so this becomes the fallback color for the slot */ ''}
37181
37182
  let desc = view.docView.nearestDesc(cur, true), rect;
37182
37183
  if (!desc)
37183
37184
  return null;
37184
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37185
+ if (isElt(desc.dom) && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37185
37186
  // Ignore elements with zero-size bounding rectangles
37186
37187
  ((rect = desc.dom.getBoundingClientRect()).width || rect.height)) {
37187
37188
  if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) {
@@ -37208,7 +37209,7 @@ so this becomes the fallback color for the slot */ ''}
37208
37209
  if (len && box.top < box.bottom) {
37209
37210
  for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {
37210
37211
  let child = element.childNodes[i];
37211
- if (child.nodeType == 1) {
37212
+ if (isElt(child)) {
37212
37213
  let rects = child.getClientRects();
37213
37214
  for (let j = 0; j < rects.length; j++) {
37214
37215
  let rect = rects[j];
@@ -37231,7 +37232,7 @@ so this becomes the fallback color for the slot */ ''}
37231
37232
  let elt = (view.root.elementFromPoint ? view.root : doc)
37232
37233
  .elementFromPoint(coords.left, coords.top);
37233
37234
  let pos;
37234
- if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {
37235
+ if (!elt || !view.dom.contains(elt)) {
37235
37236
  let box = view.dom.getBoundingClientRect();
37236
37237
  if (!inRect(coords, box))
37237
37238
  return null;
@@ -37247,7 +37248,7 @@ so this becomes the fallback color for the slot */ ''}
37247
37248
  }
37248
37249
  elt = targetKludge(elt, coords);
37249
37250
  if (node) {
37250
- if (gecko && node.nodeType == 1) {
37251
+ if (gecko && isElt(node)) {
37251
37252
  // Firefox will sometimes return offsets into <input> nodes, which
37252
37253
  // have no actual children, from caretPositionFromPoint (#953)
37253
37254
  offset = Math.min(offset, node.childNodes.length);
@@ -37262,18 +37263,18 @@ so this becomes the fallback color for the slot */ ''}
37262
37263
  }
37263
37264
  let prev;
37264
37265
  // When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.
37265
- if (webkit && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&
37266
+ if (webkit && offset && isElt(node) && isElt(prev = node.childNodes[offset - 1]) &&
37266
37267
  prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top)
37267
37268
  offset--;
37268
37269
  // Suspiciously specific kludge to work around caret*FromPoint
37269
37270
  // never returning a position at the end of the document
37270
- if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 &&
37271
+ if (node == view.dom && offset == node.childNodes.length - 1 && isElt(node.lastChild) &&
37271
37272
  coords.top > node.lastChild.getBoundingClientRect().bottom)
37272
37273
  pos = view.state.doc.content.size;
37273
37274
  // Ignore positions directly after a BR, since caret*FromPoint
37274
37275
  // 'round up' positions that would be more accurately placed
37275
37276
  // before the BR node.
37276
- else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR")
37277
+ else if (offset == 0 || !isElt(node) || node.childNodes[offset - 1].nodeName != "BR")
37277
37278
  pos = posFromCaret(view, node, offset, coords);
37278
37279
  }
37279
37280
  if (pos == null)
@@ -37299,7 +37300,7 @@ so this becomes the fallback color for the slot */ ''}
37299
37300
  function coordsAtPos(view, pos, side) {
37300
37301
  let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
37301
37302
  let supportEmptyRange = webkit || gecko;
37302
- if (node.nodeType == 3) {
37303
+ if (isText(node)) {
37303
37304
  // These browsers support querying empty text ranges. Prefer that in
37304
37305
  // bidi context or when at the end of a node.
37305
37306
  if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
@@ -37341,12 +37342,12 @@ so this becomes the fallback color for the slot */ ''}
37341
37342
  if (!$dom.parent.inlineContent) {
37342
37343
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37343
37344
  let before = node.childNodes[offset - 1];
37344
- if (before.nodeType == 1)
37345
+ if (isElt(before))
37345
37346
  return flattenH(before.getBoundingClientRect(), false);
37346
37347
  }
37347
37348
  if (atom == null && offset < nodeSize(node)) {
37348
37349
  let after = node.childNodes[offset];
37349
- if (after.nodeType == 1)
37350
+ if (isElt(after))
37350
37351
  return flattenH(after.getBoundingClientRect(), true);
37351
37352
  }
37352
37353
  return flattenH(node.getBoundingClientRect(), side >= 0);
@@ -37354,10 +37355,10 @@ so this becomes the fallback color for the slot */ ''}
37354
37355
  // Inline, not in text node (this is not Bidi-safe)
37355
37356
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37356
37357
  let before = node.childNodes[offset - 1];
37357
- let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37358
+ let target = isText(before) ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37358
37359
  // BR nodes tend to only return the rectangle before them.
37359
37360
  // Only use them if they are the last element in their parent
37360
- : before.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37361
+ : isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37361
37362
  if (target)
37362
37363
  return flattenV(singleRect(target, 1), false);
37363
37364
  }
@@ -37365,13 +37366,13 @@ so this becomes the fallback color for the slot */ ''}
37365
37366
  let after = node.childNodes[offset];
37366
37367
  while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)
37367
37368
  after = after.nextSibling;
37368
- let target = !after ? null : after.nodeType == 3 ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37369
- : after.nodeType == 1 ? after : null;
37369
+ let target = !after ? null : isText(after) ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37370
+ : isElt(after) ? after : null;
37370
37371
  if (target)
37371
37372
  return flattenV(singleRect(target, -1), true);
37372
37373
  }
37373
37374
  // All else failed, just try to get a rectangle for the target node
37374
- return flattenV(singleRect(node.nodeType == 3 ? textRange(node) : node, -side), side >= 0);
37375
+ return flattenV(singleRect(isText(node) ? textRange(node) : node, -side), side >= 0);
37375
37376
  }
37376
37377
  function flattenV(rect, left) {
37377
37378
  if (rect.width == 0)
@@ -37421,9 +37422,9 @@ so this becomes the fallback color for the slot */ ''}
37421
37422
  let coords = coordsAtPos(view, $pos.pos, 1);
37422
37423
  for (let child = dom.firstChild; child; child = child.nextSibling) {
37423
37424
  let boxes;
37424
- if (child.nodeType == 1)
37425
+ if (isElt(child))
37425
37426
  boxes = child.getClientRects();
37426
- else if (child.nodeType == 3)
37427
+ else if (isText(child))
37427
37428
  boxes = textRange(child, 0, child.nodeValue.length).getClientRects();
37428
37429
  else
37429
37430
  continue;
@@ -37463,8 +37464,7 @@ so this becomes the fallback color for the slot */ ''}
37463
37464
  sel.modify("move", dir, "character");
37464
37465
  let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
37465
37466
  let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();
37466
- let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
37467
- (oldNode == newNode && oldOff == newOff);
37467
+ let result = newNode && !contains(parentDOM, newNode) || (oldNode == newNode && oldOff == newOff);
37468
37468
  // Restore the previous selection
37469
37469
  try {
37470
37470
  sel.collapse(anchorNode, anchorOffset);
@@ -37572,7 +37572,7 @@ so this becomes the fallback color for the slot */ ''}
37572
37572
  localPosFromDOM(dom, offset, bias) {
37573
37573
  // If the DOM position is in the content, use the child desc after
37574
37574
  // it to figure out a position.
37575
- if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {
37575
+ if (this.contentDOM && contains(this.contentDOM, dom)) {
37576
37576
  if (bias < 0) {
37577
37577
  let domBefore, desc;
37578
37578
  if (dom == this.contentDOM) {
@@ -37610,7 +37610,7 @@ so this becomes the fallback color for the slot */ ''}
37610
37610
  atEnd = offset > domIndex(this.contentDOM);
37611
37611
  }
37612
37612
  else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {
37613
- atEnd = dom.compareDocumentPosition(this.contentDOM) & 2;
37613
+ atEnd = !!(dom.compareDocumentPosition(this.contentDOM) & 4);
37614
37614
  }
37615
37615
  else if (this.dom.firstChild) {
37616
37616
  if (offset == 0)
@@ -37640,7 +37640,7 @@ so this becomes the fallback color for the slot */ ''}
37640
37640
  if (desc && (!onlyNodes || desc.node)) {
37641
37641
  // If dom is outside of this desc's nodeDOM, don't count it.
37642
37642
  if (first && (nodeDOM = desc.nodeDOM) &&
37643
- !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))
37643
+ !(isElt(nodeDOM) ? contains(nodeDOM, dom) : nodeDOM == dom))
37644
37644
  first = false;
37645
37645
  else
37646
37646
  return desc;
@@ -37690,7 +37690,7 @@ so this becomes the fallback color for the slot */ ''}
37690
37690
  let i = 0, offset = 0;
37691
37691
  for (let curPos = 0; i < this.children.length; i++) {
37692
37692
  let child = this.children[i], end = curPos + child.size;
37693
- if (end > pos || child instanceof TrailingHackViewDesc) {
37693
+ if (end > pos) {
37694
37694
  offset = pos - curPos;
37695
37695
  break;
37696
37696
  }
@@ -37700,7 +37700,11 @@ so this becomes the fallback color for the slot */ ''}
37700
37700
  if (offset)
37701
37701
  return this.children[i].domFromPos(offset - this.children[i].border, side);
37702
37702
  // Go back if there were any zero-length widgets with side >= 0 before this point
37703
- for (let prev; i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }
37703
+ for (; i > 0; i--) {
37704
+ let prev = this.children[i - 1];
37705
+ if (prev.size || !(prev instanceof BufferHackViewDesc || prev instanceof WidgetViewDesc && prev.side >= 0))
37706
+ break;
37707
+ }
37704
37708
  // Scan towards the first useable node
37705
37709
  if (side <= 0) {
37706
37710
  let prev, enter = true;
@@ -37777,7 +37781,7 @@ so this becomes the fallback color for the slot */ ''}
37777
37781
  }
37778
37782
  domAfterPos(pos) {
37779
37783
  let { node, offset } = this.domFromPos(pos, 0);
37780
- if (node.nodeType != 1 || offset == node.childNodes.length)
37784
+ if (!isElt(node) || offset == node.childNodes.length)
37781
37785
  throw new RangeError("No node after pos " + pos);
37782
37786
  return node.childNodes[offset];
37783
37787
  }
@@ -37806,7 +37810,7 @@ so this becomes the fallback color for the slot */ ''}
37806
37810
  // reported position in such situations (#1092).
37807
37811
  if ((gecko || safari) && anchor == head) {
37808
37812
  let { node, offset } = anchorDOM;
37809
- if (node.nodeType == 3) {
37813
+ if (isText(node)) {
37810
37814
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
37811
37815
  // Issue #1128
37812
37816
  if (brKludge && offset == node.nodeValue.length) {
@@ -37829,7 +37833,7 @@ so this becomes the fallback color for the slot */ ''}
37829
37833
  }
37830
37834
  // Firefox can act strangely when the selection is in front of an
37831
37835
  // uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536
37832
- if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode.nodeType == 1) {
37836
+ if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && isElt(selRange.focusNode)) {
37833
37837
  let after = selRange.focusNode.childNodes[selRange.focusOffset];
37834
37838
  if (after && after.contentEditable == "false")
37835
37839
  force = true;
@@ -37928,14 +37932,12 @@ so this becomes the fallback color for the slot */ ''}
37928
37932
  return self.parent.posBeforeChild(self);
37929
37933
  });
37930
37934
  if (!widget.type.spec.raw) {
37931
- if (dom.nodeType != 1) {
37932
- let wrap = document.createElement("span");
37933
- wrap.appendChild(dom);
37934
- dom = wrap;
37935
- }
37936
- if (!dom.hasAttribute("contenteditable"))
37937
- dom.contentEditable = "false";
37938
- dom.classList.add("ProseMirror-widget");
37935
+ let elt = isElt(dom) ? dom : document.createElement("span");
37936
+ if (elt != dom)
37937
+ elt.appendChild(dom);
37938
+ if (!elt.hasAttribute("contenteditable"))
37939
+ elt.contentEditable = "false";
37940
+ elt.classList.add("ProseMirror-widget");
37939
37941
  }
37940
37942
  super(parent, [], dom, null);
37941
37943
  this.widget = widget;
@@ -38071,7 +38073,7 @@ so this becomes the fallback color for the slot */ ''}
38071
38073
  if (node.isText) {
38072
38074
  if (!dom)
38073
38075
  dom = document.createTextNode(node.text);
38074
- else if (dom.nodeType != 3)
38076
+ else if (!isText(dom))
38075
38077
  throw new RangeError("Text must be rendered as a DOM text node");
38076
38078
  }
38077
38079
  else if (!dom) {
@@ -38123,7 +38125,7 @@ so this becomes the fallback color for the slot */ ''}
38123
38125
  }
38124
38126
  if (!rule.contentElement) {
38125
38127
  let found = addedNodes &&
38126
- addedNodes.find(n => n.nodeType == 1 && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38128
+ addedNodes.find(n => isElt(n) && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38127
38129
  if (found)
38128
38130
  rule.contentElement = found;
38129
38131
  else
@@ -38148,6 +38150,7 @@ so this becomes the fallback color for the slot */ ''}
38148
38150
  let localComposition = composition && composition.pos > -1 ? composition : null;
38149
38151
  let compositionInChild = composition && composition.pos < 0;
38150
38152
  let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);
38153
+ let addBuffers = this.node.inlineContent, atBufferPos = addBuffers && this.node.isBlock;
38151
38154
  iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => {
38152
38155
  if (widget.spec.marks)
38153
38156
  updater.syncToMarks(widget.spec.marks, inline, view, i);
@@ -38159,6 +38162,8 @@ so this becomes the fallback color for the slot */ ''}
38159
38162
  }, (child, outerDeco, innerDeco, i) => {
38160
38163
  // Make sure the wrapping mark descs match the node's marks.
38161
38164
  updater.syncToMarks(child.marks, inline, view, i);
38165
+ if (atBufferPos && child.isAtom && !child.isText)
38166
+ updater.addHackNode("IMG", updater.top);
38162
38167
  // Try several strategies for drawing this node
38163
38168
  let compIndex;
38164
38169
  if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;
@@ -38172,6 +38177,8 @@ so this becomes the fallback color for the slot */ ''}
38172
38177
  updater.addNode(child, outerDeco, innerDeco, view, off);
38173
38178
  }
38174
38179
  off += child.nodeSize;
38180
+ if (addBuffers)
38181
+ atBufferPos = child.isAtom && !child.isText;
38175
38182
  });
38176
38183
  // Drop all remaining descs after the current position.
38177
38184
  updater.syncToMarks([], inline, view, 0);
@@ -38250,7 +38257,7 @@ so this becomes the fallback color for the slot */ ''}
38250
38257
  updateOuterDeco(outerDeco) {
38251
38258
  if (sameOuterDeco(outerDeco, this.outerDeco))
38252
38259
  return;
38253
- let needsWrap = this.nodeDOM.nodeType != 1;
38260
+ let needsWrap = !isElt(this.nodeDOM);
38254
38261
  let oldDOM = this.dom;
38255
38262
  this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));
38256
38263
  if (this.dom != oldDOM) {
@@ -38261,7 +38268,7 @@ so this becomes the fallback color for the slot */ ''}
38261
38268
  }
38262
38269
  // Mark this node as being the selected node.
38263
38270
  selectNode() {
38264
- if (this.nodeDOM.nodeType == 1) {
38271
+ if (isElt(this.nodeDOM)) {
38265
38272
  this.nodeDOM.classList.add("ProseMirror-selectednode");
38266
38273
  if (this.contentDOM || !this.node.type.spec.draggable)
38267
38274
  this.nodeDOM.draggable = true;
@@ -38269,7 +38276,7 @@ so this becomes the fallback color for the slot */ ''}
38269
38276
  }
38270
38277
  // Remove selected node marking from this node.
38271
38278
  deselectNode() {
38272
- if (this.nodeDOM.nodeType == 1) {
38279
+ if (isElt(this.nodeDOM)) {
38273
38280
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
38274
38281
  if (this.contentDOM || !this.node.type.spec.draggable)
38275
38282
  this.nodeDOM.removeAttribute("draggable");
@@ -38340,9 +38347,9 @@ so this becomes the fallback color for the slot */ ''}
38340
38347
  get domAtom() { return false; }
38341
38348
  isText(text) { return this.node.text == text; }
38342
38349
  }
38343
- // A dummy desc used to tag trailing BR or IMG nodes created to work
38350
+ // A dummy desc used to tag extra BR or IMG nodes created to work
38344
38351
  // around contentEditable terribleness.
38345
- class TrailingHackViewDesc extends ViewDesc {
38352
+ class BufferHackViewDesc extends ViewDesc {
38346
38353
  parseRule() { return { ignore: true }; }
38347
38354
  matchesHack(nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; }
38348
38355
  get domAtom() { return true; }
@@ -38515,7 +38522,7 @@ so this becomes the fallback color for the slot */ ''}
38515
38522
  }
38516
38523
  }
38517
38524
  function applyOuterDeco(dom, deco, node) {
38518
- return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom.nodeType != 1));
38525
+ return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, !isElt(dom)));
38519
38526
  }
38520
38527
  function sameOuterDeco(a, b) {
38521
38528
  if (a.length != b.length)
@@ -38778,7 +38785,7 @@ so this becomes the fallback color for the slot */ ''}
38778
38785
  }
38779
38786
  if (nodeName == "BR")
38780
38787
  dom.className = "ProseMirror-trailingBreak";
38781
- let hack = new TrailingHackViewDesc(this.top, [], dom, null);
38788
+ let hack = new BufferHackViewDesc(this.top, [], dom, null);
38782
38789
  if (parent != this.top)
38783
38790
  parent.children.push(hack);
38784
38791
  else
@@ -38787,7 +38794,7 @@ so this becomes the fallback color for the slot */ ''}
38787
38794
  }
38788
38795
  }
38789
38796
  isLocked(node) {
38790
- return this.lock && (node == this.lock || node.nodeType == 1 && node.contains(this.lock.parentNode));
38797
+ return this.lock && (node == this.lock || isElt(node) && node.contains(this.lock.parentNode));
38791
38798
  }
38792
38799
  }
38793
38800
  // Iterate from the end of the fragment and array of descs to find
@@ -38989,12 +38996,27 @@ so this becomes the fallback color for the slot */ ''}
38989
38996
  anchor = head;
38990
38997
  while (nearestDesc && !nearestDesc.node)
38991
38998
  nearestDesc = nearestDesc.parent;
38992
- let nearestDescNode = nearestDesc.node;
38993
- if (nearestDesc && nearestDescNode.isAtom && NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent
38994
- && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
38999
+ if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) &&
39000
+ nearestDesc.parent &&
39001
+ !(nearestDesc.node.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
38995
39002
  let pos = nearestDesc.posBefore;
38996
39003
  selection = new NodeSelection(head == pos ? $head : doc.resolve(pos));
38997
39004
  }
39005
+ else if (gecko && origin == "key" && head > view.state.selection.to &&
39006
+ isElt(domSel.focusNode) && domSel.focusOffset == domSel.focusNode.childNodes.length &&
39007
+ nearestDesc && nearestDesc.posAtStart > view.state.selection.to) {
39008
+ // Firefox will jump across scrollable wrapper nodes on keyboard
39009
+ // cursor motion (#1594). This tries to detect this situation
39010
+ // and work around it.
39011
+ for (let scan = domSel.focusNode;; scan = scan.parentNode) {
39012
+ if (getComputedStyle(scan).overflow != "visible") {
39013
+ selection = Selection$2.findFrom(doc.resolve(nearestDesc.posAtStart), 1);
39014
+ break;
39015
+ }
39016
+ if (scan == nearestDesc.dom || scan.nextSibling || !scan.parentNode || !isElt(scan.parentNode))
39017
+ break;
39018
+ }
39019
+ }
38998
39020
  }
38999
39021
  else {
39000
39022
  if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {
@@ -39180,8 +39202,7 @@ so this becomes the fallback color for the slot */ ''}
39180
39202
  // Firefox will raise 'permission denied' errors when accessing
39181
39203
  // properties of `sel.anchorNode` when it's in a generated CSS
39182
39204
  // element.
39183
- return view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&
39184
- (view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
39205
+ return contains(view.dom, sel.anchorNode) && (view.editable || contains(view.dom, sel.focusNode));
39185
39206
  }
39186
39207
  catch (_) {
39187
39208
  return false;
@@ -39232,15 +39253,14 @@ so this becomes the fallback color for the slot */ ''}
39232
39253
  if (NodeSelection.isSelectable(node)) {
39233
39254
  return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
39234
39255
  }
39235
- else if (webkit) {
39256
+ else {
39236
39257
  // Chrome and Safari will introduce extra pointless cursor
39237
- // positions around inline uneditable nodes, so we have to
39238
- // take over and move the cursor past them (#937)
39258
+ // positions around inline uneditable nodes (#937), and
39259
+ // Firefox will sometimes just plain refuse to move across
39260
+ // them (#1592), so in this situation we move the cursor
39261
+ // ourselves.
39239
39262
  return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
39240
39263
  }
39241
- else {
39242
- return false;
39243
- }
39244
39264
  }
39245
39265
  }
39246
39266
  else if (sel instanceof NodeSelection && sel.node.isInline) {
@@ -39253,12 +39273,10 @@ so this becomes the fallback color for the slot */ ''}
39253
39273
  return false;
39254
39274
  }
39255
39275
  }
39256
- function nodeLen(node) {
39257
- return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
39258
- }
39259
39276
  function isIgnorable(dom, dir) {
39260
39277
  let desc = dom.pmViewDesc;
39261
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
39278
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
39279
+ : isElt(dom) && dom.contentEditable == "false";
39262
39280
  }
39263
39281
  function skipIgnoredNodes(view, dir) {
39264
39282
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -39274,25 +39292,23 @@ so this becomes the fallback color for the slot */ ''}
39274
39292
  // Gecko will do odd things when the selection is directly in front
39275
39293
  // of a non-editable node, so in that case, move it into the next
39276
39294
  // node if possible. Issue prosemirror/prosemirror#832.
39277
- if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
39295
+ if (gecko && isElt(node) && offset < nodeSize(node) && isIgnorable(node.childNodes[offset], -1))
39278
39296
  force = true;
39279
39297
  for (;;) {
39280
39298
  if (offset > 0) {
39281
- if (node.nodeType != 1) {
39299
+ if (!isElt(node))
39282
39300
  break;
39301
+ let before = node.childNodes[offset - 1];
39302
+ if (isIgnorable(before, -1)) {
39303
+ moveNode = node;
39304
+ moveOffset = --offset;
39305
+ }
39306
+ else if (isText(before)) {
39307
+ node = before;
39308
+ offset = node.nodeValue.length;
39283
39309
  }
39284
39310
  else {
39285
- let before = node.childNodes[offset - 1];
39286
- if (isIgnorable(before, -1)) {
39287
- moveNode = node;
39288
- moveOffset = --offset;
39289
- }
39290
- else if (before.nodeType == 3) {
39291
- node = before;
39292
- offset = node.nodeValue.length;
39293
- }
39294
- else
39295
- break;
39311
+ break;
39296
39312
  }
39297
39313
  }
39298
39314
  else if (isBlockNode(node)) {
@@ -39313,7 +39329,7 @@ so this becomes the fallback color for the slot */ ''}
39313
39329
  }
39314
39330
  else {
39315
39331
  node = prev;
39316
- offset = nodeLen(node);
39332
+ offset = nodeSize(node);
39317
39333
  }
39318
39334
  }
39319
39335
  }
@@ -39329,19 +39345,20 @@ so this becomes the fallback color for the slot */ ''}
39329
39345
  let node = sel.focusNode, offset = sel.focusOffset;
39330
39346
  if (!node)
39331
39347
  return;
39332
- let len = nodeLen(node);
39348
+ let len = nodeSize(node);
39333
39349
  let moveNode, moveOffset;
39334
39350
  for (;;) {
39335
39351
  if (offset < len) {
39336
- if (node.nodeType != 1)
39352
+ if (!isElt(node))
39337
39353
  break;
39338
39354
  let after = node.childNodes[offset];
39339
39355
  if (isIgnorable(after, 1)) {
39340
39356
  moveNode = node;
39341
39357
  moveOffset = ++offset;
39342
39358
  }
39343
- else
39359
+ else {
39344
39360
  break;
39361
+ }
39345
39362
  }
39346
39363
  else if (isBlockNode(node)) {
39347
39364
  break;
@@ -39362,7 +39379,7 @@ so this becomes the fallback color for the slot */ ''}
39362
39379
  else {
39363
39380
  node = next;
39364
39381
  offset = 0;
39365
- len = nodeLen(node);
39382
+ len = nodeSize(node);
39366
39383
  }
39367
39384
  }
39368
39385
  }
@@ -39380,9 +39397,9 @@ so this becomes the fallback color for the slot */ ''}
39380
39397
  }
39381
39398
  while (node && offset < node.childNodes.length) {
39382
39399
  let next = node.childNodes[offset];
39383
- if (next.nodeType == 3)
39400
+ if (isText(next))
39384
39401
  return next;
39385
- if (next.nodeType == 1 && next.contentEditable == "false")
39402
+ if (isElt(next) && next.contentEditable == "false")
39386
39403
  break;
39387
39404
  node = next;
39388
39405
  offset = 0;
@@ -39395,16 +39412,16 @@ so this becomes the fallback color for the slot */ ''}
39395
39412
  }
39396
39413
  while (node && offset) {
39397
39414
  let next = node.childNodes[offset - 1];
39398
- if (next.nodeType == 3)
39415
+ if (isText(next))
39399
39416
  return next;
39400
- if (next.nodeType == 1 && next.contentEditable == "false")
39417
+ if (isElt(next) && next.contentEditable == "false")
39401
39418
  break;
39402
39419
  node = next;
39403
39420
  offset = node.childNodes.length;
39404
39421
  }
39405
39422
  }
39406
39423
  function setSelFocus(view, node, offset) {
39407
- if (node.nodeType != 3) {
39424
+ if (!isText(node)) {
39408
39425
  let before, after;
39409
39426
  if (after = textNodeAfter(node, offset)) {
39410
39427
  node = after;
@@ -39514,8 +39531,8 @@ so this becomes the fallback color for the slot */ ''}
39514
39531
  if (!safari || view.state.selection.$head.parentOffset > 0)
39515
39532
  return false;
39516
39533
  let { focusNode, focusOffset } = view.domSelectionRange();
39517
- if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
39518
- focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
39534
+ if (focusNode && isElt(focusNode) && focusOffset == 0 &&
39535
+ focusNode.firstChild && isElt(focusNode.firstChild) && focusNode.firstChild.contentEditable == "false") {
39519
39536
  let child = focusNode.firstChild;
39520
39537
  switchEditable(view, child, "true");
39521
39538
  setTimeout(() => switchEditable(view, child, "false"), 20);
@@ -39586,7 +39603,7 @@ so this becomes the fallback color for the slot */ ''}
39586
39603
  let doc = detachedDoc(), wrap = doc.createElement("div");
39587
39604
  wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
39588
39605
  let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
39589
- while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39606
+ while (firstChild && isElt(firstChild) && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39590
39607
  for (let i = needsWrap.length - 1; i >= 0; i--) {
39591
39608
  let wrapper = doc.createElement(needsWrap[i]);
39592
39609
  while (wrap.firstChild)
@@ -39596,7 +39613,7 @@ so this becomes the fallback color for the slot */ ''}
39596
39613
  }
39597
39614
  firstChild = wrap.firstChild;
39598
39615
  }
39599
- if (firstChild && firstChild.nodeType == 1)
39616
+ if (firstChild && isElt(firstChild))
39600
39617
  firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
39601
39618
  let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
39602
39619
  slice.content.textBetween(0, slice.content.size, "\n\n");
@@ -39642,7 +39659,7 @@ so this becomes the fallback color for the slot */ ''}
39642
39659
  if (sliceData && sliceData[3])
39643
39660
  for (let i = +sliceData[3]; i > 0; i--) {
39644
39661
  let child = dom.firstChild;
39645
- while (child && child.nodeType != 1)
39662
+ while (child && !isElt(child))
39646
39663
  child = child.nextSibling;
39647
39664
  if (!child)
39648
39665
  break;
@@ -39847,12 +39864,11 @@ so this becomes the fallback color for the slot */ ''}
39847
39864
  if (!type || type.hasRequiredAttrs())
39848
39865
  break;
39849
39866
  try {
39850
- type.checkAttrs(array[i + 1]);
39867
+ content = Fragment.from(type.create(array[i + 1], content));
39851
39868
  }
39852
39869
  catch (e) {
39853
39870
  break;
39854
39871
  }
39855
- content = Fragment.from(type.create(array[i + 1], content));
39856
39872
  openStart++;
39857
39873
  openEnd++;
39858
39874
  }
@@ -40184,7 +40200,7 @@ so this becomes the fallback color for the slot */ ''}
40184
40200
  }
40185
40201
  const target = flushed ? null : event.target;
40186
40202
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
40187
- this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
40203
+ this.target = targetDesc && isElt(targetDesc.nodeDOM) ? targetDesc.nodeDOM : null;
40188
40204
  let { selection } = view.state;
40189
40205
  if (event.button == 0 &&
40190
40206
  (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
@@ -40332,7 +40348,7 @@ so this becomes the fallback color for the slot */ ''}
40332
40348
  if (!view.composing) {
40333
40349
  view.domObserver.flush();
40334
40350
  let { state } = view, $pos = state.selection.$to;
40335
- if (state.selection instanceof TextSelection &&
40351
+ if (state.selection instanceof TextSelection && state.selection.empty &&
40336
40352
  (state.storedMarks ||
40337
40353
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
40338
40354
  chrome && windows$1 && selectionBeforeUneditable(view))) { // Issue #1500
@@ -40348,11 +40364,11 @@ so this becomes the fallback color for the slot */ ''}
40348
40364
  // inside if necessary.
40349
40365
  if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
40350
40366
  let sel = view.domSelectionRange();
40351
- for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
40367
+ for (let node = sel.focusNode, offset = sel.focusOffset; node && isElt(node) && offset != 0;) {
40352
40368
  let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
40353
40369
  if (!before)
40354
40370
  break;
40355
- if (before.nodeType == 3) {
40371
+ if (isText(before)) {
40356
40372
  let sel = view.domSelection();
40357
40373
  if (sel)
40358
40374
  sel.collapse(before, before.nodeValue.length);
@@ -40371,10 +40387,10 @@ so this becomes the fallback color for the slot */ ''}
40371
40387
  };
40372
40388
  function selectionBeforeUneditable(view) {
40373
40389
  let { focusNode, focusOffset } = view.domSelectionRange();
40374
- if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length)
40390
+ if (!focusNode || !isElt(focusNode) || focusOffset >= focusNode.childNodes.length)
40375
40391
  return false;
40376
40392
  let next = focusNode.childNodes[focusOffset];
40377
- return next.nodeType == 1 && next.contentEditable == "false";
40393
+ return isElt(next) && next.contentEditable == "false";
40378
40394
  }
40379
40395
  editHandlers.compositionend = (view, event) => {
40380
40396
  if (view.composing) {
@@ -40576,7 +40592,7 @@ so this becomes the fallback color for the slot */ ''}
40576
40592
  else if (mouseDown && mouseDown.mightDrag) {
40577
40593
  node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
40578
40594
  }
40579
- else if (event.target && event.target.nodeType == 1) {
40595
+ else if (event.target && isElt(event.target)) {
40580
40596
  let desc = view.docView.nearestDesc(event.target, true);
40581
40597
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
40582
40598
  node = NodeSelection.create(view.state.doc, desc.posBefore);
@@ -41547,7 +41563,7 @@ so this becomes the fallback color for the slot */ ''}
41547
41563
  let desc = container && this.view.docView.nearestDesc(container);
41548
41564
  if (desc && desc.ignoreMutation({
41549
41565
  type: "selection",
41550
- target: container.nodeType == 3 ? container.parentNode : container
41566
+ target: isText(container) ? container.parentNode : container
41551
41567
  })) {
41552
41568
  this.setCurSelection();
41553
41569
  return true;
@@ -41589,7 +41605,7 @@ so this becomes the fallback color for the slot */ ''}
41589
41605
  for (let node of added)
41590
41606
  if (node.nodeName == "BR" && node.parentNode) {
41591
41607
  let after = node.nextSibling;
41592
- while (after && after.nodeType == 1) {
41608
+ while (after && isElt(after)) {
41593
41609
  if (after.contentEditable == "false") {
41594
41610
  node.parentNode.removeChild(node);
41595
41611
  break;
@@ -41662,7 +41678,7 @@ so this becomes the fallback color for the slot */ ''}
41662
41678
  for (let i = 0; i < mut.addedNodes.length; i++) {
41663
41679
  let node = mut.addedNodes[i];
41664
41680
  added.push(node);
41665
- if (node.nodeType == 3)
41681
+ if (isText(node))
41666
41682
  this.lastChangedTextNode = node;
41667
41683
  }
41668
41684
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
@@ -41777,8 +41793,7 @@ so this becomes the fallback color for the slot */ ''}
41777
41793
  let parent = nextCell;
41778
41794
  for (;;) {
41779
41795
  let first = parent.firstChild;
41780
- if (!first || first.nodeType != 1 || first.contentEditable == "false" ||
41781
- /^(BR|IMG)$/.test(first.nodeName))
41796
+ if (!first || !isElt(first) || first.contentEditable == "false" || /^(BR|IMG)$/.test(first.nodeName))
41782
41797
  break;
41783
41798
  parent = first;
41784
41799
  }
@@ -41803,7 +41818,7 @@ so this becomes the fallback color for the slot */ ''}
41803
41818
  let domSel = view.domSelectionRange();
41804
41819
  let find;
41805
41820
  let anchor = domSel.anchorNode;
41806
- if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
41821
+ if (anchor && contains(view.dom, anchor)) {
41807
41822
  find = [{ node: anchor, offset: domSel.anchorOffset }];
41808
41823
  if (!selectionCollapsed(domSel))
41809
41824
  find.push({ node: domSel.focusNode, offset: domSel.focusOffset });
@@ -41911,7 +41926,7 @@ so this becomes the fallback color for the slot */ ''}
41911
41926
  if (change)
41912
41927
  view.input.domChangeCount++;
41913
41928
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&
41914
- addedNodes.some(n => n.nodeType == 1 && !isInline.test(n.nodeName)) &&
41929
+ addedNodes.some(n => isElt(n) && !isInline.test(n.nodeName)) &&
41915
41930
  (!change || change.endA >= change.endB) &&
41916
41931
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41917
41932
  view.input.lastIOSEnter = 0;
@@ -41969,9 +41984,7 @@ so this becomes the fallback color for the slot */ ''}
41969
41984
  // as being an iOS enter press), just dispatch an Enter key instead.
41970
41985
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
41971
41986
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
41972
- (!inlineChange && $from.pos < parse.doc.content.size &&
41973
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
41974
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
41987
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
41975
41988
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41976
41989
  view.input.lastIOSEnter = 0;
41977
41990
  return;
@@ -42122,6 +42135,16 @@ so this becomes the fallback color for the slot */ ''}
42122
42135
  // The fragments after the join point must match
42123
42136
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
42124
42137
  }
42138
+ function looksLikeEnter(content, from, to) {
42139
+ let newTextlines = 0, newLeaves = 0;
42140
+ content.nodesBetween(from, to, (node, pos) => {
42141
+ if (node.isTextblock && pos >= from && pos < to)
42142
+ newTextlines++;
42143
+ else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
42144
+ newLeaves++;
42145
+ });
42146
+ return newLeaves == 0 && newTextlines == 1;
42147
+ }
42125
42148
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
42126
42149
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
42127
42150
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
@@ -42382,11 +42405,11 @@ so this becomes the fallback color for the slot */ ''}
42382
42405
  */
42383
42406
  scrollToSelection() {
42384
42407
  let startDOM = this.domSelectionRange().focusNode;
42385
- if (!startDOM || !this.dom.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;
42408
+ if (!startDOM || !contains(this.dom, startDOM)) ;
42386
42409
  else if (this.someProp("handleScrollToSelection", f => f(this))) ;
42387
42410
  else if (this.state.selection instanceof NodeSelection) {
42388
42411
  let target = this.docView.domAfterPos(this.state.selection.from);
42389
- if (target.nodeType == 1)
42412
+ if (isElt(target))
42390
42413
  scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);
42391
42414
  }
42392
42415
  else {
@@ -42651,7 +42674,7 @@ so this becomes the fallback color for the slot */ ''}
42651
42674
  @internal
42652
42675
  */
42653
42676
  domSelectionRange() {
42654
- let sel = this.domSelection();
42677
+ let sel = this.dom.isConnected !== false && this.domSelection();
42655
42678
  if (!sel)
42656
42679
  return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 };
42657
42680
  return safari && this.root.nodeType === 11 &&
@@ -42982,399 +43005,1030 @@ so this becomes the fallback color for the slot */ ''}
42982
43005
  };
42983
43006
  }
42984
43007
 
42985
- //#region src/helpers/createChainableState.ts
42986
- /**
42987
- * Takes a Transaction & Editor State and turns it into a chainable state object
42988
- * @param config The transaction and state to create the chainable state from
42989
- * @returns A chainable Editor state object
42990
- */
42991
- function createChainableState(config) {
42992
- const { state, transaction } = config;
42993
- let { selection } = transaction;
42994
- let { doc } = transaction;
42995
- let { storedMarks } = transaction;
42996
- return {
42997
- ...state,
42998
- apply: state.apply.bind(state),
42999
- applyTransaction: state.applyTransaction.bind(state),
43000
- plugins: state.plugins,
43001
- schema: state.schema,
43002
- reconfigure: state.reconfigure.bind(state),
43003
- toJSON: state.toJSON.bind(state),
43004
- get storedMarks() {
43005
- return storedMarks;
43006
- },
43007
- get selection() {
43008
- return selection;
43009
- },
43010
- get doc() {
43011
- return doc;
43012
- },
43013
- get tr() {
43014
- selection = transaction.selection;
43015
- doc = transaction.doc;
43016
- storedMarks = transaction.storedMarks;
43017
- return transaction;
43018
- }
43019
- };
43020
- }
43021
- //#endregion
43022
- //#region src/CommandManager.ts
43023
- var CommandManager = class CommandManager {
43024
- constructor(props) {
43025
- this.editor = props.editor;
43026
- this.rawCommands = this.editor.extensionManager.commands;
43027
- this.customState = props.state;
43028
- }
43029
- get hasCustomState() {
43030
- return !!this.customState;
43031
- }
43032
- get state() {
43033
- return this.customState || this.editor.state;
43034
- }
43035
- get commands() {
43036
- const { rawCommands, editor, state } = this;
43037
- const { view } = editor;
43038
- const { tr } = state;
43039
- const props = this.buildProps(tr);
43040
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43041
- const method = (...args) => {
43042
- const callback = command(...args)(props);
43043
- if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43044
- return callback;
43045
- };
43046
- return [name, method];
43047
- }));
43048
- }
43049
- get chain() {
43050
- return () => this.createChain();
43051
- }
43052
- get can() {
43053
- return () => this.createCan();
43054
- }
43055
- createChain(startTr, shouldDispatch = true) {
43056
- const { rawCommands, editor, state } = this;
43057
- const { view } = editor;
43058
- const callbacks = [];
43059
- const hasStartTransaction = !!startTr;
43060
- const tr = startTr || state.tr;
43061
- const run = () => {
43062
- if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43063
- return callbacks.every((callback) => callback === true);
43064
- };
43065
- const chain = {
43066
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43067
- const chainedCommand = (...args) => {
43068
- const props = this.buildProps(tr, shouldDispatch);
43069
- const callback = command(...args)(props);
43070
- callbacks.push(callback);
43071
- return chain;
43072
- };
43073
- return [name, chainedCommand];
43074
- })),
43075
- run
43076
- };
43077
- return chain;
43078
- }
43079
- /**
43080
- * Creates a chain that safely returns `false` when run.
43081
- * @returns A non-dispatching command chain.
43082
- * @example
43083
- * const chain = CommandManager.createFakeChain()
43084
- * chain.focus().run() // false
43085
- */
43086
- static createFakeChain() {
43087
- const chain = new Proxy({}, { get: (_target, property) => {
43088
- if (property === "then") return;
43089
- if (property === "run") return () => false;
43090
- return () => chain;
43091
- } });
43092
- return chain;
43093
- }
43094
- createCan(startTr) {
43095
- const { rawCommands, state } = this;
43096
- const dispatch = false;
43097
- const tr = startTr || state.tr;
43098
- const props = this.buildProps(tr, dispatch);
43099
- return {
43100
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43101
- return [name, (...args) => command(...args)({
43102
- ...props,
43103
- dispatch: void 0
43104
- })];
43105
- })),
43106
- chain: () => this.createChain(tr, dispatch)
43107
- };
43108
- }
43109
- /**
43110
- * Creates capability checks that safely return `false`.
43111
- * @returns A non-dispatching capability checker.
43112
- * @example
43113
- * const can = CommandManager.createFallbackCan()
43114
- * can.focus() // false
43115
- */
43116
- static createFallbackCan() {
43117
- const chain = CommandManager.createFakeChain();
43118
- return new Proxy({ chain: () => chain }, { get: (target, property) => {
43119
- if (property === "then") return;
43120
- if (property === "chain") return target.chain;
43121
- return () => false;
43122
- } });
43123
- }
43124
- buildProps(tr, shouldDispatch = true) {
43125
- const { rawCommands, editor, state } = this;
43126
- const { view } = editor;
43127
- const props = {
43128
- tr,
43129
- editor,
43130
- view,
43131
- state: createChainableState({
43132
- state,
43133
- transaction: tr
43134
- }),
43135
- dispatch: shouldDispatch ? () => void 0 : void 0,
43136
- chain: () => this.createChain(tr, shouldDispatch),
43137
- can: () => this.createCan(tr),
43138
- get commands() {
43139
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43140
- return [name, (...args) => command(...args)(props)];
43141
- }));
43142
- }
43143
- };
43144
- return props;
43145
- }
43146
- };
43147
- //#endregion
43148
- //#region src/commands/blur.ts
43149
- const blur = () => ({ editor, view }) => {
43150
- requestAnimationFrame(() => {
43151
- if (!editor.isDestroyed) {
43152
- var _window;
43153
- view.dom.blur();
43154
- (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43155
- }
43156
- });
43157
- return true;
43158
- };
43159
- //#endregion
43160
- //#region src/commands/clearContent.ts
43161
- const clearContent = (emitUpdate = true) => ({ commands }) => {
43162
- return commands.setContent("", { emitUpdate });
43163
- };
43164
- //#endregion
43165
- //#region src/commands/clearNodes.ts
43166
- const clearNodes = () => ({ state, tr, dispatch }) => {
43167
- const { selection } = tr;
43168
- const { ranges } = selection;
43169
- if (!dispatch) return true;
43170
- ranges.forEach(({ $from, $to }) => {
43171
- state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43172
- if (node.type.isText) return;
43173
- const { doc, mapping } = tr;
43174
- const $mappedFrom = doc.resolve(mapping.map(pos));
43175
- const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43176
- const nodeRange = $mappedFrom.blockRange($mappedTo);
43177
- if (!nodeRange) return;
43178
- const targetLiftDepth = liftTarget(nodeRange);
43179
- if (node.type.isTextblock) {
43180
- const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43181
- tr.setNodeMarkup(nodeRange.start, defaultType);
43182
- }
43183
- if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43184
- });
43185
- });
43186
- return true;
43187
- };
43188
- //#endregion
43189
- //#region src/commands/command.ts
43190
- const command = (fn) => (props) => {
43191
- return fn(props);
43192
- };
43193
- //#endregion
43194
- //#region src/commands/createParagraphNear.ts
43195
- const createParagraphNear$1 = () => ({ state, dispatch }) => {
43196
- return createParagraphNear(state, dispatch);
43197
- };
43198
- //#endregion
43199
- //#region src/commands/cut.ts
43200
- const cut = (originRange, targetPos) => ({ editor, tr }) => {
43201
- const { state } = editor;
43202
- const contentSlice = state.doc.slice(originRange.from, originRange.to);
43203
- tr.deleteRange(originRange.from, originRange.to);
43204
- const newPos = tr.mapping.map(targetPos);
43205
- tr.insert(newPos, contentSlice.content);
43206
- tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43207
- return true;
43208
- };
43209
- //#endregion
43210
- //#region src/commands/deleteCurrentNode.ts
43211
- const deleteCurrentNode = () => ({ tr, dispatch }) => {
43212
- const { selection } = tr;
43213
- const currentNode = selection.$anchor.node();
43214
- if (currentNode.content.size > 0) return false;
43215
- const $pos = tr.selection.$anchor;
43216
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43217
- if (dispatch) {
43218
- const from = $pos.before(depth);
43219
- const to = $pos.after(depth);
43220
- tr.delete(from, to).scrollIntoView();
43221
- }
43222
- return true;
43223
- }
43224
- return false;
43225
- };
43226
- //#endregion
43227
- //#region src/helpers/getNodeType.ts
43228
- function getNodeType(nameOrType, schema) {
43229
- if (typeof nameOrType === "string") {
43230
- if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43231
- return schema.nodes[nameOrType];
43232
- }
43233
- return nameOrType;
43234
- }
43235
- //#endregion
43236
- //#region src/commands/deleteNode.ts
43237
- const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43238
- const type = getNodeType(typeOrName, state.schema);
43239
- const $pos = tr.selection.$anchor;
43240
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43241
- if (dispatch) {
43242
- const from = $pos.before(depth);
43243
- const to = $pos.after(depth);
43244
- tr.delete(from, to).scrollIntoView();
43245
- }
43246
- return true;
43247
- }
43248
- return false;
43008
+ var GOOD_LEAF_SIZE = 200;
43009
+
43010
+ // :: class<T> A rope sequence is a persistent sequence data structure
43011
+ // that supports appending, prepending, and slicing without doing a
43012
+ // full copy. It is represented as a mostly-balanced tree.
43013
+ var RopeSequence = function RopeSequence () {};
43014
+
43015
+ RopeSequence.prototype.append = function append (other) {
43016
+ if (!other.length) { return this }
43017
+ other = RopeSequence.from(other);
43018
+
43019
+ return (!this.length && other) ||
43020
+ (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
43021
+ (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
43022
+ this.appendInner(other)
43249
43023
  };
43250
- //#endregion
43251
- //#region src/commands/deleteRange.ts
43252
- const deleteRange = (range) => ({ tr, dispatch }) => {
43253
- const { from, to } = range;
43254
- if (dispatch) tr.delete(from, to);
43255
- return true;
43024
+
43025
+ // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
43026
+ // Prepend an array or other rope to this one, returning a new rope.
43027
+ RopeSequence.prototype.prepend = function prepend (other) {
43028
+ if (!other.length) { return this }
43029
+ return RopeSequence.from(other).append(this)
43256
43030
  };
43257
- //#endregion
43258
- //#region src/commands/deleteSelection.ts
43259
- /**
43260
- * Check if a node has text content based on its content specification.
43261
- * Returns true if the node's content spec matches text* or text+ patterns.
43262
- */
43263
- const hasTextContent = (nodeSpec) => {
43264
- if (!nodeSpec.content) return false;
43265
- return /^text(\*|\+)/.test(nodeSpec.content);
43031
+
43032
+ RopeSequence.prototype.appendInner = function appendInner (other) {
43033
+ return new Append(this, other)
43266
43034
  };
43267
- /**
43268
- * Expand selection position for a specific side (left or right) to handle inline text nodes.
43269
- * This function checks if the position is within an inline node with text content and
43270
- * expands it to include the entire node boundaries for proper deletion.
43271
- * @param $pos - The resolved position to expand
43272
- * @param schema - The ProseMirror schema
43273
- * @param side - Which side to expand ('left' or 'right')
43274
- * @returns The expanded position for deletion
43275
- */
43276
- const expandSelectionForSide = ($pos, schema, side) => {
43277
- if (!$pos.parent.isInline) return $pos.pos;
43278
- if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43279
- const parentContent = schema.nodes[$pos.parent.type.name].spec;
43280
- if (!hasTextContent(parentContent)) return $pos.pos;
43281
- return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43035
+
43036
+ // :: (?number, ?number) → RopeSequence<T>
43037
+ // Create a rope repesenting a sub-sequence of this rope.
43038
+ RopeSequence.prototype.slice = function slice (from, to) {
43039
+ if ( from === void 0 ) from = 0;
43040
+ if ( to === void 0 ) to = this.length;
43041
+
43042
+ if (from >= to) { return RopeSequence.empty }
43043
+ return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
43282
43044
  };
43283
- /**
43284
- * Expand selection range to properly handle deletion of inline text nodes.
43285
- * Inline text nodes don't collapse correctly when text inside is deleted,
43286
- * so we need to expand the selection to include the entire node.
43287
- * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43288
- */
43289
- const expandSelectionForInlineText = ($from, $to, schema) => {
43290
- return {
43291
- from: expandSelectionForSide($from, schema, "left"),
43292
- to: expandSelectionForSide($to, schema, "right")
43293
- };
43045
+
43046
+ // :: (number) → T
43047
+ // Retrieve the element at the given position from this rope.
43048
+ RopeSequence.prototype.get = function get (i) {
43049
+ if (i < 0 || i >= this.length) { return undefined }
43050
+ return this.getInner(i)
43294
43051
  };
43295
- const deleteSelection = () => ({ state, dispatch }) => {
43296
- if (state.selection.empty) return false;
43297
- if (dispatch) {
43298
- const tr = state.tr;
43299
- const { ranges } = state.selection;
43300
- const mapFrom = tr.steps.length;
43301
- ranges.forEach((range) => {
43302
- const mapping = tr.mapping.slice(mapFrom);
43303
- const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43304
- const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43305
- const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43306
- tr.deleteRange(from, to);
43307
- });
43308
- if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43309
- tr.scrollIntoView();
43310
- dispatch(tr);
43311
- }
43312
- return true;
43052
+
43053
+ // :: ((element: T, index: number) → ?bool, ?number, ?number)
43054
+ // Call the given function for each element between the given
43055
+ // indices. This tends to be more efficient than looping over the
43056
+ // indices and calling `get`, because it doesn't have to descend the
43057
+ // tree for every element.
43058
+ RopeSequence.prototype.forEach = function forEach (f, from, to) {
43059
+ if ( from === void 0 ) from = 0;
43060
+ if ( to === void 0 ) to = this.length;
43061
+
43062
+ if (from <= to)
43063
+ { this.forEachInner(f, from, to, 0); }
43064
+ else
43065
+ { this.forEachInvertedInner(f, from, to, 0); }
43313
43066
  };
43314
- //#endregion
43315
- //#region src/commands/enter.ts
43316
- const enter = () => ({ commands }) => {
43317
- return commands.keyboardShortcut("Enter");
43067
+
43068
+ // :: ((element: T, index: number) → U, ?number, ?number) → [U]
43069
+ // Map the given functions over the elements of the rope, producing
43070
+ // a flat array.
43071
+ RopeSequence.prototype.map = function map (f, from, to) {
43072
+ if ( from === void 0 ) from = 0;
43073
+ if ( to === void 0 ) to = this.length;
43074
+
43075
+ var result = [];
43076
+ this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
43077
+ return result
43318
43078
  };
43319
- //#endregion
43320
- //#region src/commands/exitCode.ts
43321
- const exitCode$1 = () => ({ state, dispatch }) => {
43322
- return exitCode(state, dispatch);
43079
+
43080
+ // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
43081
+ // Create a rope representing the given array, or return the rope
43082
+ // itself if a rope was given.
43083
+ RopeSequence.from = function from (values) {
43084
+ if (values instanceof RopeSequence) { return values }
43085
+ return values && values.length ? new Leaf(values) : RopeSequence.empty
43323
43086
  };
43324
- //#endregion
43325
- //#region src/utilities/isRegExp.ts
43326
- function isRegExp$1(value) {
43327
- return Object.prototype.toString.call(value) === "[object RegExp]";
43328
- }
43329
- //#endregion
43330
- //#region src/utilities/objectIncludes.ts
43331
- /**
43332
- * Check if object1 includes object2
43333
- * @param object1 Object
43334
- * @param object2 Object
43335
- */
43336
- function objectIncludes(object1, object2, options = { strict: true }) {
43337
- const keys = Object.keys(object2);
43338
- if (!keys.length) return true;
43339
- return keys.every((key) => {
43340
- if (options.strict) return object2[key] === object1[key];
43341
- if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
43342
- return object2[key] === object1[key];
43343
- });
43344
- }
43345
- //#endregion
43346
- //#region src/helpers/getMarkRange.ts
43347
- function findMarkInSet(marks, type, attributes = {}) {
43348
- return marks.find((item) => {
43349
- return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
43350
- });
43351
- }
43352
- function isMarkInSet(marks, type, attributes = {}) {
43353
- return !!findMarkInSet(marks, type, attributes);
43354
- }
43355
- /**
43356
- * Get the range of a mark at a resolved position.
43357
- */
43358
- function getMarkRange($pos, type, attributes) {
43359
- if (!$pos || !type) return;
43360
- let start = $pos.parent.childAfter($pos.parentOffset);
43361
- if (!start.node || !start.node.marks.some((mark) => mark.type === type)) start = $pos.parent.childBefore($pos.parentOffset);
43362
- if (!start.node || !start.node.marks.some((mark) => mark.type === type)) return;
43363
- if (!attributes) {
43364
- const firstMark = start.node.marks.find((mark) => mark.type === type);
43365
- if (firstMark) attributes = firstMark.attrs;
43366
- }
43367
- if (!findMarkInSet([...start.node.marks], type, attributes)) return;
43368
- let startIndex = start.index;
43369
- let startPos = $pos.start() + start.offset;
43370
- let endIndex = startIndex + 1;
43371
- let endPos = startPos + start.node.nodeSize;
43372
- while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
43373
- startIndex -= 1;
43374
- startPos -= $pos.parent.child(startIndex).nodeSize;
43375
- }
43376
- while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
43377
- endPos += $pos.parent.child(endIndex).nodeSize;
43087
+
43088
+ var Leaf = /*@__PURE__*/(function (RopeSequence) {
43089
+ function Leaf(values) {
43090
+ RopeSequence.call(this);
43091
+ this.values = values;
43092
+ }
43093
+
43094
+ if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
43095
+ Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43096
+ Leaf.prototype.constructor = Leaf;
43097
+
43098
+ var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
43099
+
43100
+ Leaf.prototype.flatten = function flatten () {
43101
+ return this.values
43102
+ };
43103
+
43104
+ Leaf.prototype.sliceInner = function sliceInner (from, to) {
43105
+ if (from == 0 && to == this.length) { return this }
43106
+ return new Leaf(this.values.slice(from, to))
43107
+ };
43108
+
43109
+ Leaf.prototype.getInner = function getInner (i) {
43110
+ return this.values[i]
43111
+ };
43112
+
43113
+ Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
43114
+ for (var i = from; i < to; i++)
43115
+ { if (f(this.values[i], start + i) === false) { return false } }
43116
+ };
43117
+
43118
+ Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43119
+ for (var i = from - 1; i >= to; i--)
43120
+ { if (f(this.values[i], start + i) === false) { return false } }
43121
+ };
43122
+
43123
+ Leaf.prototype.leafAppend = function leafAppend (other) {
43124
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43125
+ { return new Leaf(this.values.concat(other.flatten())) }
43126
+ };
43127
+
43128
+ Leaf.prototype.leafPrepend = function leafPrepend (other) {
43129
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43130
+ { return new Leaf(other.flatten().concat(this.values)) }
43131
+ };
43132
+
43133
+ prototypeAccessors.length.get = function () { return this.values.length };
43134
+
43135
+ prototypeAccessors.depth.get = function () { return 0 };
43136
+
43137
+ Object.defineProperties( Leaf.prototype, prototypeAccessors );
43138
+
43139
+ return Leaf;
43140
+ }(RopeSequence));
43141
+
43142
+ // :: RopeSequence
43143
+ // The empty rope sequence.
43144
+ RopeSequence.empty = new Leaf([]);
43145
+
43146
+ var Append = /*@__PURE__*/(function (RopeSequence) {
43147
+ function Append(left, right) {
43148
+ RopeSequence.call(this);
43149
+ this.left = left;
43150
+ this.right = right;
43151
+ this.length = left.length + right.length;
43152
+ this.depth = Math.max(left.depth, right.depth) + 1;
43153
+ }
43154
+
43155
+ if ( RopeSequence ) Append.__proto__ = RopeSequence;
43156
+ Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43157
+ Append.prototype.constructor = Append;
43158
+
43159
+ Append.prototype.flatten = function flatten () {
43160
+ return this.left.flatten().concat(this.right.flatten())
43161
+ };
43162
+
43163
+ Append.prototype.getInner = function getInner (i) {
43164
+ return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
43165
+ };
43166
+
43167
+ Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
43168
+ var leftLen = this.left.length;
43169
+ if (from < leftLen &&
43170
+ this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
43171
+ { return false }
43172
+ if (to > leftLen &&
43173
+ this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
43174
+ { return false }
43175
+ };
43176
+
43177
+ Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43178
+ var leftLen = this.left.length;
43179
+ if (from > leftLen &&
43180
+ this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
43181
+ { return false }
43182
+ if (to < leftLen &&
43183
+ this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
43184
+ { return false }
43185
+ };
43186
+
43187
+ Append.prototype.sliceInner = function sliceInner (from, to) {
43188
+ if (from == 0 && to == this.length) { return this }
43189
+ var leftLen = this.left.length;
43190
+ if (to <= leftLen) { return this.left.slice(from, to) }
43191
+ if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
43192
+ return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
43193
+ };
43194
+
43195
+ Append.prototype.leafAppend = function leafAppend (other) {
43196
+ var inner = this.right.leafAppend(other);
43197
+ if (inner) { return new Append(this.left, inner) }
43198
+ };
43199
+
43200
+ Append.prototype.leafPrepend = function leafPrepend (other) {
43201
+ var inner = this.left.leafPrepend(other);
43202
+ if (inner) { return new Append(inner, this.right) }
43203
+ };
43204
+
43205
+ Append.prototype.appendInner = function appendInner (other) {
43206
+ if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
43207
+ { return new Append(this.left, new Append(this.right, other)) }
43208
+ return new Append(this, other)
43209
+ };
43210
+
43211
+ return Append;
43212
+ }(RopeSequence));
43213
+
43214
+ // ProseMirror's history isn't simply a way to roll back to a previous
43215
+ // state, because ProseMirror supports applying changes without adding
43216
+ // them to the history (for example during collaboration).
43217
+ //
43218
+ // To this end, each 'Branch' (one for the undo history and one for
43219
+ // the redo history) keeps an array of 'Items', which can optionally
43220
+ // hold a step (an actual undoable change), and always hold a position
43221
+ // map (which is needed to move changes below them to apply to the
43222
+ // current document).
43223
+ //
43224
+ // An item that has both a step and a selection bookmark is the start
43225
+ // of an 'event' — a group of changes that will be undone or redone at
43226
+ // once. (It stores only the bookmark, since that way we don't have to
43227
+ // provide a document until the selection is actually applied, which
43228
+ // is useful when compressing.)
43229
+ // Used to schedule history compression
43230
+ const max_empty_items = 500;
43231
+ class Branch {
43232
+ constructor(items, eventCount) {
43233
+ this.items = items;
43234
+ this.eventCount = eventCount;
43235
+ }
43236
+ // Pop the latest event off the branch's history and apply it
43237
+ // to a document transform.
43238
+ popEvent(state, preserveItems) {
43239
+ if (this.eventCount == 0)
43240
+ return null;
43241
+ let end = this.items.length;
43242
+ for (;; end--) {
43243
+ let next = this.items.get(end - 1);
43244
+ if (next.selection) {
43245
+ --end;
43246
+ break;
43247
+ }
43248
+ }
43249
+ let remap, mapFrom;
43250
+ if (preserveItems) {
43251
+ remap = this.remapping(end, this.items.length);
43252
+ mapFrom = remap.maps.length;
43253
+ }
43254
+ let transform = state.tr;
43255
+ let selection, remaining;
43256
+ let addAfter = [], addBefore = [];
43257
+ this.items.forEach((item, i) => {
43258
+ if (!item.step) {
43259
+ if (!remap) {
43260
+ remap = this.remapping(end, i + 1);
43261
+ mapFrom = remap.maps.length;
43262
+ }
43263
+ mapFrom--;
43264
+ addBefore.push(item);
43265
+ return;
43266
+ }
43267
+ if (remap) {
43268
+ addBefore.push(new Item(item.map));
43269
+ let step = item.step.map(remap.slice(mapFrom)), map;
43270
+ if (step && transform.maybeStep(step).doc) {
43271
+ map = transform.mapping.maps[transform.mapping.maps.length - 1];
43272
+ addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
43273
+ }
43274
+ mapFrom--;
43275
+ if (map)
43276
+ remap.appendMap(map, mapFrom);
43277
+ }
43278
+ else {
43279
+ transform.maybeStep(item.step);
43280
+ }
43281
+ if (item.selection) {
43282
+ selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
43283
+ remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
43284
+ return false;
43285
+ }
43286
+ }, this.items.length, 0);
43287
+ return { remaining: remaining, transform, selection: selection };
43288
+ }
43289
+ // Create a new branch with the given transform added.
43290
+ addTransform(transform, selection, histOptions, preserveItems) {
43291
+ let newItems = [], eventCount = this.eventCount;
43292
+ let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
43293
+ for (let i = 0; i < transform.steps.length; i++) {
43294
+ let step = transform.steps[i].invert(transform.docs[i]);
43295
+ let item = new Item(transform.mapping.maps[i], step, selection), merged;
43296
+ if (merged = lastItem && lastItem.merge(item)) {
43297
+ item = merged;
43298
+ if (i)
43299
+ newItems.pop();
43300
+ else
43301
+ oldItems = oldItems.slice(0, oldItems.length - 1);
43302
+ }
43303
+ newItems.push(item);
43304
+ if (selection) {
43305
+ eventCount++;
43306
+ selection = undefined;
43307
+ }
43308
+ if (!preserveItems)
43309
+ lastItem = item;
43310
+ }
43311
+ let overflow = eventCount - histOptions.depth;
43312
+ if (overflow > DEPTH_OVERFLOW) {
43313
+ oldItems = cutOffEvents(oldItems, overflow);
43314
+ eventCount -= overflow;
43315
+ }
43316
+ return new Branch(oldItems.append(newItems), eventCount);
43317
+ }
43318
+ remapping(from, to) {
43319
+ let maps = new Mapping;
43320
+ this.items.forEach((item, i) => {
43321
+ let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
43322
+ ? maps.maps.length - item.mirrorOffset : undefined;
43323
+ maps.appendMap(item.map, mirrorPos);
43324
+ }, from, to);
43325
+ return maps;
43326
+ }
43327
+ addMaps(array) {
43328
+ if (this.eventCount == 0)
43329
+ return this;
43330
+ return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
43331
+ }
43332
+ // When the collab module receives remote changes, the history has
43333
+ // to know about those, so that it can adjust the steps that were
43334
+ // rebased on top of the remote changes, and include the position
43335
+ // maps for the remote changes in its array of items.
43336
+ rebased(rebasedTransform, rebasedCount) {
43337
+ if (!this.eventCount)
43338
+ return this;
43339
+ rebasedCount = Math.min(this.items.length, rebasedCount);
43340
+ let rebasedItems = [], start = this.items.length - rebasedCount;
43341
+ let mapping = rebasedTransform.mapping;
43342
+ let newUntil = rebasedTransform.steps.length;
43343
+ let eventCount = this.eventCount;
43344
+ this.items.forEach(item => { if (item.selection)
43345
+ eventCount--; }, start);
43346
+ let iRebased = rebasedCount;
43347
+ this.items.forEach(item => {
43348
+ let pos = mapping.getMirror(--iRebased);
43349
+ if (pos == null)
43350
+ return;
43351
+ newUntil = Math.min(newUntil, pos);
43352
+ let map = mapping.maps[pos];
43353
+ if (item.step) {
43354
+ let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
43355
+ let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
43356
+ if (selection)
43357
+ eventCount++;
43358
+ rebasedItems.push(new Item(map, step, selection));
43359
+ }
43360
+ else {
43361
+ rebasedItems.push(new Item(map));
43362
+ }
43363
+ }, start);
43364
+ let newMaps = [];
43365
+ for (let i = rebasedCount; i < newUntil; i++)
43366
+ newMaps.push(new Item(mapping.maps[i]));
43367
+ let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
43368
+ let branch = new Branch(items, eventCount);
43369
+ if (branch.emptyItemCount() > max_empty_items)
43370
+ branch = branch.compress(this.items.length - rebasedItems.length);
43371
+ return branch;
43372
+ }
43373
+ emptyItemCount() {
43374
+ let count = 0;
43375
+ this.items.forEach(item => { if (!item.step)
43376
+ count++; });
43377
+ return count;
43378
+ }
43379
+ // Compressing a branch means rewriting it to push the air (map-only
43380
+ // items) out. During collaboration, these naturally accumulate
43381
+ // because each remote change adds one. The `upto` argument is used
43382
+ // to ensure that only the items below a given level are compressed,
43383
+ // because `rebased` relies on a clean, untouched set of items in
43384
+ // order to associate old items with rebased steps.
43385
+ compress(upto = this.items.length) {
43386
+ let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
43387
+ let items = [], events = 0;
43388
+ this.items.forEach((item, i) => {
43389
+ if (i >= upto) {
43390
+ items.push(item);
43391
+ if (item.selection)
43392
+ events++;
43393
+ }
43394
+ else if (item.step) {
43395
+ let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
43396
+ mapFrom--;
43397
+ if (map)
43398
+ remap.appendMap(map, mapFrom);
43399
+ if (step) {
43400
+ let selection = item.selection && item.selection.map(remap.slice(mapFrom));
43401
+ if (selection)
43402
+ events++;
43403
+ let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
43404
+ if (merged = items.length && items[last].merge(newItem))
43405
+ items[last] = merged;
43406
+ else
43407
+ items.push(newItem);
43408
+ }
43409
+ }
43410
+ else if (item.map) {
43411
+ mapFrom--;
43412
+ }
43413
+ }, this.items.length, 0);
43414
+ return new Branch(RopeSequence.from(items.reverse()), events);
43415
+ }
43416
+ }
43417
+ Branch.empty = new Branch(RopeSequence.empty, 0);
43418
+ function cutOffEvents(items, n) {
43419
+ let cutPoint;
43420
+ items.forEach((item, i) => {
43421
+ if (item.selection && (n-- == 0)) {
43422
+ cutPoint = i;
43423
+ return false;
43424
+ }
43425
+ });
43426
+ return items.slice(cutPoint);
43427
+ }
43428
+ class Item {
43429
+ constructor(
43430
+ // The (forward) step map for this item.
43431
+ map,
43432
+ // The inverted step
43433
+ step,
43434
+ // If this is non-null, this item is the start of a group, and
43435
+ // this selection is the starting selection for the group (the one
43436
+ // that was active before the first step was applied)
43437
+ selection,
43438
+ // If this item is the inverse of a previous mapping on the stack,
43439
+ // this points at the inverse's offset
43440
+ mirrorOffset) {
43441
+ this.map = map;
43442
+ this.step = step;
43443
+ this.selection = selection;
43444
+ this.mirrorOffset = mirrorOffset;
43445
+ }
43446
+ merge(other) {
43447
+ if (this.step && other.step && !other.selection) {
43448
+ let step = other.step.merge(this.step);
43449
+ if (step)
43450
+ return new Item(step.getMap().invert(), step, this.selection);
43451
+ }
43452
+ }
43453
+ }
43454
+ // The value of the state field that tracks undo/redo history for that
43455
+ // state. Will be stored in the plugin state when the history plugin
43456
+ // is active.
43457
+ class HistoryState {
43458
+ constructor(done, undone, prevRanges, prevTime, prevComposition) {
43459
+ this.done = done;
43460
+ this.undone = undone;
43461
+ this.prevRanges = prevRanges;
43462
+ this.prevTime = prevTime;
43463
+ this.prevComposition = prevComposition;
43464
+ }
43465
+ }
43466
+ const DEPTH_OVERFLOW = 20;
43467
+ // Record a transformation in undo history.
43468
+ function applyTransaction(history, state, tr, options) {
43469
+ let historyTr = tr.getMeta(historyKey), rebased;
43470
+ if (historyTr)
43471
+ return historyTr.historyState;
43472
+ if (tr.getMeta(closeHistoryKey))
43473
+ history = new HistoryState(history.done, history.undone, null, 0, -1);
43474
+ let appended = tr.getMeta("appendedTransaction");
43475
+ if (tr.steps.length == 0) {
43476
+ return history;
43477
+ }
43478
+ else if (appended && appended.getMeta(historyKey)) {
43479
+ if (appended.getMeta(historyKey).redo)
43480
+ return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
43481
+ else
43482
+ return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
43483
+ }
43484
+ else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
43485
+ // Group transforms that occur in quick succession into one event.
43486
+ let composition = tr.getMeta("composition");
43487
+ let newGroup = history.prevTime == 0 ||
43488
+ (!appended && history.prevComposition != composition &&
43489
+ (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
43490
+ let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
43491
+ return new HistoryState(history.done.addTransform(tr, newGroup ? state.selection.getBookmark() : undefined, options, mustPreserveItems(state)), Branch.empty, prevRanges, tr.time, composition == null ? history.prevComposition : composition);
43492
+ }
43493
+ else if (rebased = tr.getMeta("rebased")) {
43494
+ // Used by the collab module to tell the history that some of its
43495
+ // content has been rebased.
43496
+ return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43497
+ }
43498
+ else {
43499
+ return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43500
+ }
43501
+ }
43502
+ function isAdjacentTo(transform, prevRanges) {
43503
+ if (!prevRanges)
43504
+ return false;
43505
+ if (!transform.docChanged)
43506
+ return true;
43507
+ let adjacent = false;
43508
+ transform.mapping.maps[0].forEach((start, end) => {
43509
+ for (let i = 0; i < prevRanges.length; i += 2)
43510
+ if (start <= prevRanges[i + 1] && end >= prevRanges[i])
43511
+ adjacent = true;
43512
+ });
43513
+ return adjacent;
43514
+ }
43515
+ function rangesFor(maps) {
43516
+ let result = [];
43517
+ for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
43518
+ maps[i].forEach((_from, _to, from, to) => result.push(from, to));
43519
+ return result;
43520
+ }
43521
+ function mapRanges(ranges, mapping) {
43522
+ if (!ranges)
43523
+ return null;
43524
+ let result = [];
43525
+ for (let i = 0; i < ranges.length; i += 2) {
43526
+ let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
43527
+ if (from <= to)
43528
+ result.push(from, to);
43529
+ }
43530
+ return result;
43531
+ }
43532
+ // Apply the latest event from one branch to the document and shift the event
43533
+ // onto the other branch.
43534
+ function histTransaction(history, state, redo) {
43535
+ let preserveItems = mustPreserveItems(state);
43536
+ let histOptions = historyKey.get(state).spec.config;
43537
+ let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
43538
+ if (!pop)
43539
+ return null;
43540
+ let selection = pop.selection.resolve(pop.transform.doc);
43541
+ let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
43542
+ let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
43543
+ return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
43544
+ }
43545
+ let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
43546
+ // Check whether any plugin in the given state has a
43547
+ // `historyPreserveItems` property in its spec, in which case we must
43548
+ // preserve steps exactly as they came in, so that they can be
43549
+ // rebased.
43550
+ function mustPreserveItems(state) {
43551
+ let plugins = state.plugins;
43552
+ if (cachedPreserveItemsPlugins != plugins) {
43553
+ cachedPreserveItems = false;
43554
+ cachedPreserveItemsPlugins = plugins;
43555
+ for (let i = 0; i < plugins.length; i++)
43556
+ if (plugins[i].spec.historyPreserveItems) {
43557
+ cachedPreserveItems = true;
43558
+ break;
43559
+ }
43560
+ }
43561
+ return cachedPreserveItems;
43562
+ }
43563
+ /**
43564
+ Set a flag on the given transaction that will prevent further steps
43565
+ from being appended to an existing history event (so that they
43566
+ require a separate undo command to undo).
43567
+ */
43568
+ function closeHistory(tr) {
43569
+ return tr.setMeta(closeHistoryKey, true);
43570
+ }
43571
+ const historyKey = new PluginKey("history");
43572
+ const closeHistoryKey = new PluginKey("closeHistory");
43573
+ /**
43574
+ Returns a plugin that enables the undo history for an editor. The
43575
+ plugin will track undo and redo stacks, which can be used with the
43576
+ [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
43577
+
43578
+ You can set an `"addToHistory"` [metadata
43579
+ property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
43580
+ to prevent it from being rolled back by undo.
43581
+ */
43582
+ function history(config = {}) {
43583
+ config = { depth: config.depth || 100,
43584
+ newGroupDelay: config.newGroupDelay || 500 };
43585
+ return new Plugin({
43586
+ key: historyKey,
43587
+ state: {
43588
+ init() {
43589
+ return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
43590
+ },
43591
+ apply(tr, hist, state) {
43592
+ return applyTransaction(hist, state, tr, config);
43593
+ }
43594
+ },
43595
+ config,
43596
+ props: {
43597
+ handleDOMEvents: {
43598
+ beforeinput(view, e) {
43599
+ let inputType = e.inputType;
43600
+ let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
43601
+ if (!command || !view.editable)
43602
+ return false;
43603
+ e.preventDefault();
43604
+ return command(view.state, view.dispatch);
43605
+ }
43606
+ }
43607
+ }
43608
+ });
43609
+ }
43610
+ function buildCommand(redo, scroll) {
43611
+ return (state, dispatch) => {
43612
+ let hist = historyKey.getState(state);
43613
+ if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
43614
+ return false;
43615
+ if (dispatch) {
43616
+ let tr = histTransaction(hist, state, redo);
43617
+ if (tr)
43618
+ dispatch(scroll ? tr.scrollIntoView() : tr);
43619
+ }
43620
+ return true;
43621
+ };
43622
+ }
43623
+ /**
43624
+ A command function that undoes the last change, if any.
43625
+ */
43626
+ const undo = buildCommand(false, true);
43627
+ /**
43628
+ A command function that redoes the last undone change, if any.
43629
+ */
43630
+ const redo = buildCommand(true, true);
43631
+ /**
43632
+ Returns true if the given transaction was generated by the history
43633
+ plugin.
43634
+ */
43635
+ function isHistoryTransaction(tr) {
43636
+ return tr.getMeta(historyKey) != null;
43637
+ }
43638
+
43639
+ //#region src/helpers/createChainableState.ts
43640
+ /**
43641
+ * Takes a Transaction & Editor State and turns it into a chainable state object
43642
+ * @param config The transaction and state to create the chainable state from
43643
+ * @returns A chainable Editor state object
43644
+ */
43645
+ function createChainableState(config) {
43646
+ const { state, transaction } = config;
43647
+ let { selection } = transaction;
43648
+ let { doc } = transaction;
43649
+ let { storedMarks } = transaction;
43650
+ return {
43651
+ ...state,
43652
+ apply: state.apply.bind(state),
43653
+ applyTransaction: state.applyTransaction.bind(state),
43654
+ plugins: state.plugins,
43655
+ schema: state.schema,
43656
+ reconfigure: state.reconfigure.bind(state),
43657
+ toJSON: state.toJSON.bind(state),
43658
+ get storedMarks() {
43659
+ return storedMarks;
43660
+ },
43661
+ get selection() {
43662
+ return selection;
43663
+ },
43664
+ get doc() {
43665
+ return doc;
43666
+ },
43667
+ get tr() {
43668
+ selection = transaction.selection;
43669
+ doc = transaction.doc;
43670
+ storedMarks = transaction.storedMarks;
43671
+ return transaction;
43672
+ }
43673
+ };
43674
+ }
43675
+ //#endregion
43676
+ //#region src/CommandManager.ts
43677
+ var CommandManager = class CommandManager {
43678
+ constructor(props) {
43679
+ this.editor = props.editor;
43680
+ this.rawCommands = this.editor.extensionManager.commands;
43681
+ this.customState = props.state;
43682
+ }
43683
+ get hasCustomState() {
43684
+ return !!this.customState;
43685
+ }
43686
+ get state() {
43687
+ return this.customState || this.editor.state;
43688
+ }
43689
+ get commands() {
43690
+ const { rawCommands, editor, state } = this;
43691
+ const { view } = editor;
43692
+ const { tr } = state;
43693
+ const props = this.buildProps(tr);
43694
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43695
+ const method = (...args) => {
43696
+ const callback = command(...args)(props);
43697
+ if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43698
+ return callback;
43699
+ };
43700
+ return [name, method];
43701
+ }));
43702
+ }
43703
+ get chain() {
43704
+ return () => this.createChain();
43705
+ }
43706
+ get can() {
43707
+ return () => this.createCan();
43708
+ }
43709
+ createChain(startTr, shouldDispatch = true) {
43710
+ const { rawCommands, editor, state } = this;
43711
+ const { view } = editor;
43712
+ const callbacks = [];
43713
+ const hasStartTransaction = !!startTr;
43714
+ const tr = startTr || state.tr;
43715
+ const run = () => {
43716
+ if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43717
+ return callbacks.every((callback) => callback === true);
43718
+ };
43719
+ const chain = {
43720
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43721
+ const chainedCommand = (...args) => {
43722
+ const props = this.buildProps(tr, shouldDispatch);
43723
+ const callback = command(...args)(props);
43724
+ callbacks.push(callback);
43725
+ return chain;
43726
+ };
43727
+ return [name, chainedCommand];
43728
+ })),
43729
+ run
43730
+ };
43731
+ return chain;
43732
+ }
43733
+ /**
43734
+ * Creates a chain that safely returns `false` when run.
43735
+ * @returns A non-dispatching command chain.
43736
+ * @example
43737
+ * const chain = CommandManager.createFakeChain()
43738
+ * chain.focus().run() // false
43739
+ */
43740
+ static createFakeChain() {
43741
+ const chain = new Proxy({}, { get: (_target, property) => {
43742
+ if (property === "then") return;
43743
+ if (property === "run") return () => false;
43744
+ return () => chain;
43745
+ } });
43746
+ return chain;
43747
+ }
43748
+ createCan(startTr) {
43749
+ const { rawCommands, state } = this;
43750
+ const dispatch = false;
43751
+ const tr = startTr || state.tr;
43752
+ const props = this.buildProps(tr, dispatch);
43753
+ return {
43754
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43755
+ return [name, (...args) => command(...args)({
43756
+ ...props,
43757
+ dispatch: void 0
43758
+ })];
43759
+ })),
43760
+ chain: () => this.createChain(tr, dispatch)
43761
+ };
43762
+ }
43763
+ /**
43764
+ * Creates capability checks that safely return `false`.
43765
+ * @returns A non-dispatching capability checker.
43766
+ * @example
43767
+ * const can = CommandManager.createFallbackCan()
43768
+ * can.focus() // false
43769
+ */
43770
+ static createFallbackCan() {
43771
+ const chain = CommandManager.createFakeChain();
43772
+ return new Proxy({ chain: () => chain }, { get: (target, property) => {
43773
+ if (property === "then") return;
43774
+ if (property === "chain") return target.chain;
43775
+ return () => false;
43776
+ } });
43777
+ }
43778
+ buildProps(tr, shouldDispatch = true) {
43779
+ const { rawCommands, editor, state } = this;
43780
+ const { view } = editor;
43781
+ const props = {
43782
+ tr,
43783
+ editor,
43784
+ view,
43785
+ state: createChainableState({
43786
+ state,
43787
+ transaction: tr
43788
+ }),
43789
+ dispatch: shouldDispatch ? () => void 0 : void 0,
43790
+ chain: () => this.createChain(tr, shouldDispatch),
43791
+ can: () => this.createCan(tr),
43792
+ get commands() {
43793
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43794
+ return [name, (...args) => command(...args)(props)];
43795
+ }));
43796
+ }
43797
+ };
43798
+ return props;
43799
+ }
43800
+ };
43801
+ //#endregion
43802
+ //#region src/commands/blur.ts
43803
+ const blur = () => ({ editor, view }) => {
43804
+ requestAnimationFrame(() => {
43805
+ if (!editor.isDestroyed) {
43806
+ var _window;
43807
+ view.dom.blur();
43808
+ (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43809
+ }
43810
+ });
43811
+ return true;
43812
+ };
43813
+ //#endregion
43814
+ //#region src/commands/clearContent.ts
43815
+ const clearContent = (emitUpdate = true) => ({ commands }) => {
43816
+ return commands.setContent("", { emitUpdate });
43817
+ };
43818
+ //#endregion
43819
+ //#region src/commands/clearNodes.ts
43820
+ const clearNodes = () => ({ state, tr, dispatch }) => {
43821
+ const { selection } = tr;
43822
+ const { ranges } = selection;
43823
+ if (!dispatch) return true;
43824
+ ranges.forEach(({ $from, $to }) => {
43825
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43826
+ if (node.type.isText) return;
43827
+ const { doc, mapping } = tr;
43828
+ const $mappedFrom = doc.resolve(mapping.map(pos));
43829
+ const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43830
+ const nodeRange = $mappedFrom.blockRange($mappedTo);
43831
+ if (!nodeRange) return;
43832
+ const targetLiftDepth = liftTarget(nodeRange);
43833
+ if (node.type.isTextblock) {
43834
+ const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43835
+ tr.setNodeMarkup(nodeRange.start, defaultType);
43836
+ }
43837
+ if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43838
+ });
43839
+ });
43840
+ return true;
43841
+ };
43842
+ //#endregion
43843
+ //#region src/commands/command.ts
43844
+ const command = (fn) => (props) => {
43845
+ return fn(props);
43846
+ };
43847
+ //#endregion
43848
+ //#region src/commands/createParagraphNear.ts
43849
+ const createParagraphNear$1 = () => ({ state, dispatch }) => {
43850
+ return createParagraphNear(state, dispatch);
43851
+ };
43852
+ //#endregion
43853
+ //#region src/commands/cut.ts
43854
+ const cut = (originRange, targetPos) => ({ editor, tr }) => {
43855
+ const { state } = editor;
43856
+ const contentSlice = state.doc.slice(originRange.from, originRange.to);
43857
+ tr.deleteRange(originRange.from, originRange.to);
43858
+ const newPos = tr.mapping.map(targetPos);
43859
+ tr.insert(newPos, contentSlice.content);
43860
+ tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43861
+ return true;
43862
+ };
43863
+ //#endregion
43864
+ //#region src/commands/deleteCurrentNode.ts
43865
+ const deleteCurrentNode = () => ({ tr, dispatch }) => {
43866
+ const { selection } = tr;
43867
+ const currentNode = selection.$anchor.node();
43868
+ if (currentNode.content.size > 0) return false;
43869
+ const $pos = tr.selection.$anchor;
43870
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43871
+ if (dispatch) {
43872
+ const from = $pos.before(depth);
43873
+ const to = $pos.after(depth);
43874
+ tr.delete(from, to).scrollIntoView();
43875
+ }
43876
+ return true;
43877
+ }
43878
+ return false;
43879
+ };
43880
+ //#endregion
43881
+ //#region src/helpers/getNodeType.ts
43882
+ function getNodeType(nameOrType, schema) {
43883
+ if (typeof nameOrType === "string") {
43884
+ if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43885
+ return schema.nodes[nameOrType];
43886
+ }
43887
+ return nameOrType;
43888
+ }
43889
+ //#endregion
43890
+ //#region src/commands/deleteNode.ts
43891
+ const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43892
+ const type = getNodeType(typeOrName, state.schema);
43893
+ const $pos = tr.selection.$anchor;
43894
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43895
+ if (dispatch) {
43896
+ const from = $pos.before(depth);
43897
+ const to = $pos.after(depth);
43898
+ tr.delete(from, to).scrollIntoView();
43899
+ }
43900
+ return true;
43901
+ }
43902
+ return false;
43903
+ };
43904
+ //#endregion
43905
+ //#region src/commands/deleteRange.ts
43906
+ const deleteRange = (range) => ({ tr, dispatch }) => {
43907
+ const { from, to } = range;
43908
+ if (dispatch) tr.delete(from, to);
43909
+ return true;
43910
+ };
43911
+ //#endregion
43912
+ //#region src/commands/deleteSelection.ts
43913
+ /**
43914
+ * Check if a node has text content based on its content specification.
43915
+ * Returns true if the node's content spec matches text* or text+ patterns.
43916
+ */
43917
+ const hasTextContent = (nodeSpec) => {
43918
+ if (!nodeSpec.content) return false;
43919
+ return /^text(\*|\+)/.test(nodeSpec.content);
43920
+ };
43921
+ /**
43922
+ * Expand selection position for a specific side (left or right) to handle inline text nodes.
43923
+ * This function checks if the position is within an inline node with text content and
43924
+ * expands it to include the entire node boundaries for proper deletion.
43925
+ * @param $pos - The resolved position to expand
43926
+ * @param schema - The ProseMirror schema
43927
+ * @param side - Which side to expand ('left' or 'right')
43928
+ * @returns The expanded position for deletion
43929
+ */
43930
+ const expandSelectionForSide = ($pos, schema, side) => {
43931
+ if (!$pos.parent.isInline) return $pos.pos;
43932
+ if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43933
+ const parentContent = schema.nodes[$pos.parent.type.name].spec;
43934
+ if (!hasTextContent(parentContent)) return $pos.pos;
43935
+ return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43936
+ };
43937
+ /**
43938
+ * Expand selection range to properly handle deletion of inline text nodes.
43939
+ * Inline text nodes don't collapse correctly when text inside is deleted,
43940
+ * so we need to expand the selection to include the entire node.
43941
+ * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43942
+ */
43943
+ const expandSelectionForInlineText = ($from, $to, schema) => {
43944
+ return {
43945
+ from: expandSelectionForSide($from, schema, "left"),
43946
+ to: expandSelectionForSide($to, schema, "right")
43947
+ };
43948
+ };
43949
+ const deleteSelection = () => ({ state, dispatch }) => {
43950
+ if (state.selection.empty) return false;
43951
+ if (dispatch) {
43952
+ const tr = state.tr;
43953
+ const { ranges } = state.selection;
43954
+ const mapFrom = tr.steps.length;
43955
+ ranges.forEach((range) => {
43956
+ const mapping = tr.mapping.slice(mapFrom);
43957
+ const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43958
+ const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43959
+ const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43960
+ tr.deleteRange(from, to);
43961
+ });
43962
+ if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43963
+ tr.scrollIntoView();
43964
+ dispatch(tr);
43965
+ }
43966
+ return true;
43967
+ };
43968
+ //#endregion
43969
+ //#region src/commands/enter.ts
43970
+ const enter = () => ({ commands }) => {
43971
+ return commands.keyboardShortcut("Enter");
43972
+ };
43973
+ //#endregion
43974
+ //#region src/commands/exitCode.ts
43975
+ const exitCode$1 = () => ({ state, dispatch }) => {
43976
+ return exitCode(state, dispatch);
43977
+ };
43978
+ //#endregion
43979
+ //#region src/utilities/isRegExp.ts
43980
+ function isRegExp$1(value) {
43981
+ return Object.prototype.toString.call(value) === "[object RegExp]";
43982
+ }
43983
+ //#endregion
43984
+ //#region src/utilities/objectIncludes.ts
43985
+ /**
43986
+ * Check if object1 includes object2
43987
+ * @param object1 Object
43988
+ * @param object2 Object
43989
+ */
43990
+ function objectIncludes(object1, object2, options = { strict: true }) {
43991
+ const keys = Object.keys(object2);
43992
+ if (!keys.length) return true;
43993
+ return keys.every((key) => {
43994
+ if (options.strict) return object2[key] === object1[key];
43995
+ if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
43996
+ return object2[key] === object1[key];
43997
+ });
43998
+ }
43999
+ //#endregion
44000
+ //#region src/helpers/getMarkRange.ts
44001
+ function findMarkInSet(marks, type, attributes = {}) {
44002
+ return marks.find((item) => {
44003
+ return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
44004
+ });
44005
+ }
44006
+ function isMarkInSet(marks, type, attributes = {}) {
44007
+ return !!findMarkInSet(marks, type, attributes);
44008
+ }
44009
+ /**
44010
+ * Get the range of a mark at a resolved position.
44011
+ */
44012
+ function getMarkRange($pos, type, attributes) {
44013
+ if (!$pos || !type) return;
44014
+ let start = $pos.parent.childAfter($pos.parentOffset);
44015
+ if (!start.node || !start.node.marks.some((mark) => mark.type === type)) start = $pos.parent.childBefore($pos.parentOffset);
44016
+ if (!start.node || !start.node.marks.some((mark) => mark.type === type)) return;
44017
+ if (!attributes) {
44018
+ const firstMark = start.node.marks.find((mark) => mark.type === type);
44019
+ if (firstMark) attributes = firstMark.attrs;
44020
+ }
44021
+ if (!findMarkInSet([...start.node.marks], type, attributes)) return;
44022
+ let startIndex = start.index;
44023
+ let startPos = $pos.start() + start.offset;
44024
+ let endIndex = startIndex + 1;
44025
+ let endPos = startPos + start.node.nodeSize;
44026
+ while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
44027
+ startIndex -= 1;
44028
+ startPos -= $pos.parent.child(startIndex).nodeSize;
44029
+ }
44030
+ while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
44031
+ endPos += $pos.parent.child(endIndex).nodeSize;
43378
44032
  endIndex += 1;
43379
44033
  }
43380
44034
  return {
@@ -43784,11 +44438,21 @@ so this becomes the fallback color for the slot */ ''}
43784
44438
  return joinForward(state, dispatch);
43785
44439
  };
43786
44440
  //#endregion
44441
+ //#region src/commands/canJoinItemsAt.ts
44442
+ const canJoinItemsAt = (doc, pos) => {
44443
+ const $pos = doc.resolve(pos);
44444
+ const before = $pos.nodeBefore;
44445
+ const after = $pos.nodeAfter;
44446
+ if (!before || !after) return false;
44447
+ return !before.type.spec.isolating && !after.type.spec.isolating;
44448
+ };
44449
+ //#endregion
43787
44450
  //#region src/commands/joinItemBackward.ts
43788
44451
  const joinItemBackward = () => ({ state, dispatch, tr }) => {
43789
44452
  try {
43790
44453
  const point = joinPoint(state.doc, state.selection.$from.pos, -1);
43791
44454
  if (point === null || point === void 0) return false;
44455
+ if (!canJoinItemsAt(state.doc, point)) return false;
43792
44456
  tr.join(point, 2);
43793
44457
  if (dispatch) dispatch(tr);
43794
44458
  return true;
@@ -43802,6 +44466,7 @@ so this becomes the fallback color for the slot */ ''}
43802
44466
  try {
43803
44467
  const point = joinPoint(state.doc, state.selection.$from.pos, 1);
43804
44468
  if (point === null || point === void 0) return false;
44469
+ if (!canJoinItemsAt(state.doc, point)) return false;
43805
44470
  tr.join(point, 2);
43806
44471
  if (dispatch) dispatch(tr);
43807
44472
  return true;
@@ -45208,8 +45873,14 @@ so this becomes the fallback color for the slot */ ''}
45208
45873
  type: deflt,
45209
45874
  attrs: newAttributes
45210
45875
  }] : void 0;
45211
- let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types);
45212
- if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
45876
+ const deletedTr = selection instanceof TextSelection && !selection.empty ? EditorState.create({
45877
+ doc: tr.doc,
45878
+ selection
45879
+ }).tr.deleteSelection() : null;
45880
+ const splitDoc = deletedTr ? deletedTr.doc : tr.doc;
45881
+ const splitPos = deletedTr ? deletedTr.mapping.map($from.pos) : $from.pos;
45882
+ let can = canSplit(splitDoc, splitPos, 1, types);
45883
+ if (!types && !can && canSplit(splitDoc, splitPos, 1, deflt ? [{ type: deflt }] : void 0)) {
45213
45884
  can = true;
45214
45885
  types = deflt ? [{
45215
45886
  type: deflt,
@@ -45218,12 +45889,13 @@ so this becomes the fallback color for the slot */ ''}
45218
45889
  }
45219
45890
  if (dispatch) {
45220
45891
  if (can) {
45892
+ const mapFrom = tr.steps.length;
45221
45893
  if (selection instanceof TextSelection) tr.deleteSelection();
45222
- tr.split(tr.mapping.map($from.pos), 1, types);
45894
+ tr.split(tr.mapping.slice(mapFrom).map($from.pos), 1, types);
45223
45895
  if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
45224
- const first = tr.mapping.map($from.before());
45896
+ const first = tr.mapping.slice(mapFrom).map($from.before());
45225
45897
  const $first = tr.doc.resolve(first);
45226
- if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
45898
+ if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.slice(mapFrom).map($from.before()), deflt);
45227
45899
  }
45228
45900
  }
45229
45901
  if (keepMarks) ensureMarks(state, editor.extensionManager.splittableMarks);
@@ -45276,16 +45948,19 @@ so this becomes the fallback color for the slot */ ''}
45276
45948
  ...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
45277
45949
  ...overrideAttrs
45278
45950
  };
45951
+ const splitsAtStartOfItem = $from.parentOffset === 0 && $from.index(-1) === 0;
45952
+ const itemStart = $from.before(-1);
45279
45953
  tr.delete($from.pos, $to.pos);
45954
+ const trailingTypeAttributes = splitsAtStartOfItem ? grandParent.attrs : newTypeAttributes;
45280
45955
  const types = nextType ? [{
45281
45956
  type,
45282
- attrs: newTypeAttributes
45957
+ attrs: trailingTypeAttributes
45283
45958
  }, {
45284
45959
  type: nextType,
45285
45960
  attrs: newNextTypeAttributes
45286
45961
  }] : [{
45287
45962
  type,
45288
- attrs: newTypeAttributes
45963
+ attrs: trailingTypeAttributes
45289
45964
  }];
45290
45965
  if (!canSplit(tr.doc, $from.pos, 2)) return false;
45291
45966
  if (dispatch) {
@@ -45293,6 +45968,7 @@ so this becomes the fallback color for the slot */ ''}
45293
45968
  const { splittableMarks } = editor.extensionManager;
45294
45969
  const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
45295
45970
  tr.split($from.pos, 2, types).scrollIntoView();
45971
+ if (splitsAtStartOfItem) tr.setNodeMarkup(itemStart, void 0, newTypeAttributes);
45296
45972
  if (!marks || !dispatch) return true;
45297
45973
  const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
45298
45974
  tr.ensureMarks(filteredMarks);
@@ -46825,55 +47501,106 @@ so this becomes the fallback color for the slot */ ''}
46825
47501
  }
46826
47502
  return result;
46827
47503
  };
47504
+ /**
47505
+ * Prepares the typed text so the rule handler can inspect the resulting document.
47506
+ */
47507
+ function createRuleTransaction(config) {
47508
+ const { editor, from, to, text, insertText } = config;
47509
+ if (!insertText) return {
47510
+ inputTransaction: null,
47511
+ tr: editor.view.state.tr
47512
+ };
47513
+ const inputTransaction = editor.view.state.tr.insertText(text, from, to);
47514
+ return {
47515
+ inputTransaction,
47516
+ tr: EditorState.create({
47517
+ doc: inputTransaction.doc,
47518
+ selection: inputTransaction.selection,
47519
+ storedMarks: inputTransaction.storedMarks
47520
+ }).tr
47521
+ };
47522
+ }
47523
+ /**
47524
+ * Runs a matching rule and dispatches the typed text before its conversion.
47525
+ */
47526
+ function applyRule(config) {
47527
+ const { editor, from, to, text, rule, match, plugin, insertText } = config;
47528
+ const { view } = editor;
47529
+ const { inputTransaction, tr } = createRuleTransaction({
47530
+ editor,
47531
+ from,
47532
+ to,
47533
+ text,
47534
+ insertText
47535
+ });
47536
+ const inputEnd = inputTransaction ? from + text.length : to;
47537
+ const state = createChainableState({
47538
+ state: view.state,
47539
+ transaction: tr
47540
+ });
47541
+ const range = {
47542
+ from: from - (match[0].length - text.length),
47543
+ to: inputEnd
47544
+ };
47545
+ const { commands, chain, can } = new CommandManager({
47546
+ editor,
47547
+ state
47548
+ });
47549
+ if (rule.handler({
47550
+ state,
47551
+ range,
47552
+ match,
47553
+ commands,
47554
+ chain,
47555
+ can
47556
+ }) === null || !tr.steps.length) return false;
47557
+ if (inputTransaction) {
47558
+ view.dispatch(inputTransaction);
47559
+ if (!view.state.doc.eq(inputTransaction.doc)) return true;
47560
+ }
47561
+ closeHistory(tr);
47562
+ tr.setMeta("inputRule", true);
47563
+ if (rule.undoable) tr.setMeta(plugin, {
47564
+ transform: tr,
47565
+ from,
47566
+ to: inputEnd,
47567
+ text
47568
+ });
47569
+ view.dispatch(tr);
47570
+ return true;
47571
+ }
47572
+ /**
47573
+ * Checks that the part of a match already in the document has matching positions.
47574
+ */
47575
+ function matchesDocument($from, match, text) {
47576
+ const matchedDocLength = match[0].length - text.length;
47577
+ if (matchedDocLength <= 0) return true;
47578
+ const matchStartOffset = $from.parentOffset - matchedDocLength;
47579
+ return matchStartOffset >= 0 && $from.parent.textBetween(matchStartOffset, $from.parentOffset) === match[0].slice(0, matchedDocLength);
47580
+ }
46828
47581
  function run$1$1(config) {
46829
47582
  var _ref;
46830
- const { editor, from, to, text, rules, plugin } = config;
47583
+ const { editor, from, to, text, rules, plugin, insertText } = config;
46831
47584
  const { view } = editor;
46832
47585
  if (view.composing) return false;
46833
47586
  const $from = view.state.doc.resolve(from);
46834
47587
  if ($from.parent.type.spec.code || !!((_ref = $from.nodeBefore || $from.nodeAfter) === null || _ref === void 0 ? void 0 : _ref.marks.find((mark) => mark.type.spec.code))) return false;
46835
- let matched = false;
46836
47588
  const textBefore = getTextContentFromNodes($from) + text;
46837
- rules.forEach((rule) => {
46838
- if (matched) return;
47589
+ for (const rule of rules) {
46839
47590
  const match = inputRuleMatcherHandler(textBefore, rule.find);
46840
- if (!match) return;
46841
- const matchedDocLength = match[0].length - text.length;
46842
- if (matchedDocLength > 0) {
46843
- const matchStartOffset = $from.parentOffset - matchedDocLength;
46844
- if (matchStartOffset < 0 || $from.parent.textBetween(matchStartOffset, $from.parentOffset) !== match[0].slice(0, matchedDocLength)) return;
46845
- }
46846
- const tr = view.state.tr;
46847
- const state = createChainableState({
46848
- state: view.state,
46849
- transaction: tr
46850
- });
46851
- const range = {
46852
- from: from - (match[0].length - text.length),
46853
- to
46854
- };
46855
- const { commands, chain, can } = new CommandManager({
47591
+ if (!match || !matchesDocument($from, match, text)) continue;
47592
+ if (applyRule({
46856
47593
  editor,
46857
- state
46858
- });
46859
- if (rule.handler({
46860
- state,
46861
- range,
46862
- match,
46863
- commands,
46864
- chain,
46865
- can
46866
- }) === null || !tr.steps.length) return;
46867
- if (rule.undoable) tr.setMeta(plugin, {
46868
- transform: tr,
46869
47594
  from,
46870
47595
  to,
46871
- text
46872
- });
46873
- view.dispatch(tr);
46874
- matched = true;
46875
- });
46876
- return matched;
47596
+ text,
47597
+ rule,
47598
+ match,
47599
+ plugin,
47600
+ insertText
47601
+ })) return true;
47602
+ }
47603
+ return false;
46877
47604
  }
46878
47605
  /**
46879
47606
  * Create an input rules plugin. When enabled, it will cause text
@@ -46917,7 +47644,8 @@ so this becomes the fallback color for the slot */ ''}
46917
47644
  to,
46918
47645
  text,
46919
47646
  rules,
46920
- plugin
47647
+ plugin,
47648
+ insertText: true
46921
47649
  });
46922
47650
  },
46923
47651
  handleDOMEvents: { compositionend: (view) => {
@@ -47153,6 +47881,9 @@ so this becomes the fallback color for the slot */ ''}
47153
47881
  pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
47154
47882
  return tr;
47155
47883
  };
47884
+ editor.on("destroy", () => {
47885
+ if (tiptapDragFromOtherEditor === editor) tiptapDragFromOtherEditor = null;
47886
+ });
47156
47887
  return rules.map((rule) => {
47157
47888
  return new Plugin({
47158
47889
  view(view) {
@@ -47178,6 +47909,7 @@ so this becomes the fallback color for the slot */ ''}
47178
47909
  if (!isDroppedFromProseMirror) {
47179
47910
  const dragFromOtherEditor = tiptapDragFromOtherEditor;
47180
47911
  if (dragFromOtherEditor === null || dragFromOtherEditor === void 0 ? void 0 : dragFromOtherEditor.isEditable) setTimeout(() => {
47912
+ if (dragFromOtherEditor.isDestroyed) return;
47181
47913
  const selection = dragFromOtherEditor.state.selection;
47182
47914
  if (selection) dragFromOtherEditor.commands.deleteRange({
47183
47915
  from: selection.from,
@@ -48347,7 +49079,10 @@ img.ProseMirror-separator {
48347
49079
  ...options
48348
49080
  };
48349
49081
  if (!this.editorView || !this.state || this.isDestroyed) return;
48350
- if (this.options.editorProps) this.view.setProps(this.options.editorProps);
49082
+ if (this.options.editorProps) this.view.setProps({
49083
+ ...this.options.editorProps,
49084
+ attributes: this.getEditorViewAttributes()
49085
+ });
48351
49086
  this.view.updateState(this.state);
48352
49087
  }
48353
49088
  /**
@@ -48503,6 +49238,23 @@ img.ProseMirror-separator {
48503
49238
  return doc;
48504
49239
  }
48505
49240
  /**
49241
+ * Returns the attributes for the editor element.
49242
+ * Merges the default `role="textbox"` with the attributes from `editorProps`,
49243
+ * so the role is kept no matter when the props are applied.
49244
+ */
49245
+ getEditorViewAttributes() {
49246
+ var _this$options$editorP;
49247
+ const attributes = (_this$options$editorP = this.options.editorProps) === null || _this$options$editorP === void 0 ? void 0 : _this$options$editorP.attributes;
49248
+ if (isFunction$3(attributes)) return (state) => ({
49249
+ role: "textbox",
49250
+ ...attributes(state)
49251
+ });
49252
+ return {
49253
+ role: "textbox",
49254
+ ...attributes
49255
+ };
49256
+ }
49257
+ /**
48506
49258
  * Creates a ProseMirror view.
48507
49259
  */
48508
49260
  createView(element) {
@@ -48513,10 +49265,7 @@ img.ProseMirror-separator {
48513
49265
  const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
48514
49266
  this.editorView = new EditorView(element, {
48515
49267
  ...editorProps,
48516
- attributes: {
48517
- role: "textbox",
48518
- ...editorProps === null || editorProps === void 0 ? void 0 : editorProps.attributes
48519
- },
49268
+ attributes: this.getEditorViewAttributes(),
48520
49269
  dispatchTransaction: dispatch,
48521
49270
  transformPastedHTML,
48522
49271
  state: this.editorState,
@@ -58219,7 +58968,7 @@ img.ProseMirror-separator {
58219
58968
  toDOM() { return ["div", ["hr"]]; }
58220
58969
  },
58221
58970
  heading: {
58222
- attrs: { level: { default: 1 } },
58971
+ attrs: { level: { default: 1, validate: "number" } },
58223
58972
  content: "(text | image)*",
58224
58973
  group: "block",
58225
58974
  defining: true,
@@ -58229,7 +58978,7 @@ img.ProseMirror-separator {
58229
58978
  { tag: "h4", attrs: { level: 4 } },
58230
58979
  { tag: "h5", attrs: { level: 5 } },
58231
58980
  { tag: "h6", attrs: { level: 6 } }],
58232
- toDOM(node) { return ["h" + node.attrs.level, 0]; }
58981
+ toDOM(node) { return ["h" + +node.attrs.level, 0]; }
58233
58982
  },
58234
58983
  code_block: {
58235
58984
  content: "text*",
@@ -61726,8 +62475,27 @@ img.ProseMirror-separator {
61726
62475
  const UNICODE_WHITESPACE_PATTERN = "[\0- \xA0 ᠎ -\u2029  ]";
61727
62476
  const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN);
61728
62477
  const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`);
62478
+ const UNICODE_WHITESPACE_REGEX_TRAILING = new RegExp(`${UNICODE_WHITESPACE_PATTERN}+$`);
61729
62479
  const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, "g");
61730
62480
  //#endregion
62481
+ //#region src/helpers/unlinkTrailingWhitespace.ts
62482
+ function unlinkTrailingWhitespace(tr, range, type) {
62483
+ var _rangeEnd$nodeBefore, _insertedText$match;
62484
+ const rangeEnd = tr.doc.resolve(range.to);
62485
+ if (!((_rangeEnd$nodeBefore = rangeEnd.nodeBefore) === null || _rangeEnd$nodeBefore === void 0 ? void 0 : _rangeEnd$nodeBefore.isText)) return;
62486
+ const trailingWhitespace = (_insertedText$match = tr.doc.textBetween(range.from, range.to, "", "").match(UNICODE_WHITESPACE_REGEX_TRAILING)) === null || _insertedText$match === void 0 ? void 0 : _insertedText$match[0];
62487
+ if (!trailingWhitespace) return;
62488
+ const whitespaceFrom = range.to - trailingWhitespace.length;
62489
+ const linkMarks = getMarksBetween(whitespaceFrom, range.to, tr.doc).filter((item) => item.mark.type === type);
62490
+ if (!linkMarks.length) return;
62491
+ const { nodeAfter } = rangeEnd;
62492
+ if (!!nodeAfter && linkMarks.some((item) => item.mark.isInSet(nodeAfter.marks))) return;
62493
+ const storedMarks = tr.storedMarks;
62494
+ tr.removeMark(whitespaceFrom, range.to, type);
62495
+ tr.setStoredMarks(storedMarks);
62496
+ if (tr.selection.empty && tr.selection.from === range.to) tr.removeStoredMark(type);
62497
+ }
62498
+ //#endregion
61731
62499
  //#region src/helpers/autolink.ts
61732
62500
  /**
61733
62501
  * Check if the provided tokens form a valid link structure, which can either be a single link token
@@ -61768,6 +62536,21 @@ img.ProseMirror-separator {
61768
62536
  if (!docChanges || preventAutolink) return;
61769
62537
  const { tr } = newState;
61770
62538
  const transform = combineTransactionSteps(oldState.doc, [...transactions]);
62539
+ if (!transactions.some(isHistoryTransaction)) {
62540
+ const insertedRanges = [];
62541
+ transform.steps.forEach((step, index) => {
62542
+ if (!(step instanceof ReplaceStep) || !step.slice.size) return;
62543
+ const mapping = transform.mapping.slice(index + 1);
62544
+ const from = mapping.map(step.from, 1);
62545
+ const to = mapping.map(step.from + step.slice.size, -1);
62546
+ if (from < to) insertedRanges.push({
62547
+ from,
62548
+ to
62549
+ });
62550
+ });
62551
+ insertedRanges.sort((left, right) => right.to - left.to);
62552
+ insertedRanges.forEach((range) => unlinkTrailingWhitespace(tr, range, options.type));
62553
+ }
61771
62554
  getChangedRanges(transform).forEach(({ newRange }) => {
61772
62555
  const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, (node) => node.isTextblock);
61773
62556
  let textBlock;
@@ -63154,6 +63937,54 @@ img.ProseMirror-separator {
63154
63937
  });
63155
63938
  }
63156
63939
  //#endregion
63940
+ //#region src/ordered-list/collectOrderedListItemsFromSource.ts
63941
+ const ORDERED_LIST_SCAN_WINDOW = 64;
63942
+ function takeLines(source, max) {
63943
+ const lines = [];
63944
+ let start = 0;
63945
+ while (lines.length < max) {
63946
+ const lineEnd = source.indexOf("\n", start);
63947
+ if (lineEnd === -1) {
63948
+ lines.push(source.slice(start));
63949
+ return lines;
63950
+ }
63951
+ lines.push(source.slice(start, lineEnd));
63952
+ start = lineEnd + 1;
63953
+ }
63954
+ return lines;
63955
+ }
63956
+ /**
63957
+ * Collect ordered list items from the start of `source`, reading only the lines the list needs.
63958
+ *
63959
+ * @param source Markdown beginning at a block boundary.
63960
+ * @returns The items, how many lines they consumed, and the lines that were read.
63961
+ * @example
63962
+ * collectOrderedListItemsFromSource('1. one\n2. two\n\nAfter')
63963
+ * // → [[item, item], 3, ['1. one', '2. two', '', 'After']]
63964
+ */
63965
+ function collectOrderedListItemsFromSource(source) {
63966
+ const firstLineEnd = source.indexOf("\n");
63967
+ const firstLine = firstLineEnd === -1 ? source : source.slice(0, firstLineEnd);
63968
+ if (!ORDERED_LIST_ITEM_REGEX.test(firstLine)) return [
63969
+ [],
63970
+ 0,
63971
+ []
63972
+ ];
63973
+ let windowSize = ORDERED_LIST_SCAN_WINDOW;
63974
+ let lines = takeLines(source, windowSize);
63975
+ let collected = collectOrderedListItems(lines);
63976
+ while (collected[1] === lines.length && lines.length === windowSize) {
63977
+ windowSize *= 2;
63978
+ lines = takeLines(source, windowSize);
63979
+ collected = collectOrderedListItems(lines);
63980
+ }
63981
+ return [
63982
+ collected[0],
63983
+ collected[1],
63984
+ lines
63985
+ ];
63986
+ }
63987
+ //#endregion
63157
63988
  //#region src/ordered-list/ordered-list.ts
63158
63989
  const ListItemName = "listItem";
63159
63990
  const TextStyleName = "textStyle";
@@ -63272,8 +64103,7 @@ img.ProseMirror-separator {
63272
64103
  start: () => -1,
63273
64104
  tokenize: (src, _tokens, lexer) => {
63274
64105
  var _listItems$, _listItems$2;
63275
- const lines = src.split("\n");
63276
- const [listItems, consumed] = collectOrderedListItems(lines);
64106
+ const [listItems, consumed, lines] = collectOrderedListItemsFromSource(src);
63277
64107
  if (listItems.length === 0) return;
63278
64108
  const items = buildNestedStructure(listItems, listItems[0].indent, lexer);
63279
64109
  if (items.length === 0) return;
@@ -66044,1028 +66874,414 @@ img.ProseMirror-separator {
66044
66874
  //#region src/text.ts
66045
66875
  /**
66046
66876
  * This extension allows you to create text nodes.
66047
- * @see https://www.tiptap.dev/api/nodes/text
66048
- */
66049
- const Text = Node$1.create({
66050
- name: "text",
66051
- group: "inline",
66052
- parseMarkdown: (token) => {
66053
- return {
66054
- type: "text",
66055
- text: token.text || ""
66056
- };
66057
- },
66058
- renderMarkdown: (node) => node.text || ""
66059
- });
66060
- //#endregion
66061
- //#region src/index.ts
66062
- var src_default = Text;
66063
-
66064
- /**
66065
- Create a plugin that, when added to a ProseMirror instance,
66066
- causes a decoration to show up at the drop position when something
66067
- is dragged over the editor.
66068
-
66069
- Nodes may add a `disableDropCursor` property to their spec to
66070
- control the showing of a drop cursor inside them. This may be a
66071
- boolean or a function, which will be called with a view and a
66072
- position, and should return a boolean.
66073
- */
66074
- function dropCursor(options = {}) {
66075
- return new Plugin({
66076
- view(editorView) { return new DropCursorView(editorView, options); }
66077
- });
66078
- }
66079
- class DropCursorView {
66080
- constructor(editorView, options) {
66081
- var _a;
66082
- this.editorView = editorView;
66083
- this.cursorPos = null;
66084
- this.element = null;
66085
- this.timeout = -1;
66086
- this.lastDragEvent = null;
66087
- this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66088
- this.color = options.color === false ? undefined : (options.color || "black");
66089
- this.class = options.class;
66090
- this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66091
- let handler = (e) => { this[name](e); };
66092
- editorView.dom.addEventListener(name, handler);
66093
- return { name, handler };
66094
- });
66095
- }
66096
- destroy() {
66097
- this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66098
- }
66099
- update(editorView, prevState) {
66100
- if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66101
- // if we currently have an on-going drag event
66102
- // we need to update the cursor position again and update the overlay
66103
- if (this.lastDragEvent) {
66104
- let target = this.computeTarget(this.lastDragEvent);
66105
- if (target == this.cursorPos)
66106
- this.updateOverlay();
66107
- else
66108
- this.setCursor(target);
66109
- }
66110
- else {
66111
- this.updateOverlay();
66112
- }
66113
- }
66114
- }
66115
- setCursor(pos) {
66116
- if (pos == this.cursorPos)
66117
- return;
66118
- this.cursorPos = pos;
66119
- if (pos == null) {
66120
- this.element.parentNode.removeChild(this.element);
66121
- this.element = null;
66122
- }
66123
- else {
66124
- this.updateOverlay();
66125
- }
66126
- }
66127
- updateOverlay() {
66128
- let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66129
- let isBlock = !$pos.parent.inlineContent, rect;
66130
- let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66131
- let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66132
- if (isBlock) {
66133
- let before = $pos.nodeBefore, after = $pos.nodeAfter;
66134
- if (before || after) {
66135
- let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66136
- if (node) {
66137
- let nodeRect = node.getBoundingClientRect();
66138
- let top = before ? nodeRect.bottom : nodeRect.top;
66139
- if (before && after)
66140
- top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66141
- let halfWidth = (this.width / 2) * scaleY;
66142
- rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66143
- }
66144
- }
66145
- }
66146
- if (!rect) {
66147
- let coords = this.editorView.coordsAtPos(this.cursorPos);
66148
- let halfWidth = (this.width / 2) * scaleX;
66149
- rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66150
- }
66151
- let parent = this.editorView.dom.offsetParent;
66152
- if (!this.element) {
66153
- this.element = parent.appendChild(document.createElement("div"));
66154
- if (this.class)
66155
- this.element.className = this.class;
66156
- this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
66157
- if (this.color) {
66158
- this.element.style.backgroundColor = this.color;
66159
- }
66160
- }
66161
- this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
66162
- this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
66163
- let parentLeft, parentTop;
66164
- if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
66165
- parentLeft = -pageXOffset;
66166
- parentTop = -pageYOffset;
66167
- }
66168
- else {
66169
- let rect = parent.getBoundingClientRect();
66170
- let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
66171
- parentLeft = rect.left - parent.scrollLeft * parentScaleX;
66172
- parentTop = rect.top - parent.scrollTop * parentScaleY;
66173
- }
66174
- this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
66175
- this.element.style.top = (rect.top - parentTop) / scaleY + "px";
66176
- this.element.style.width = (rect.right - rect.left) / scaleX + "px";
66177
- this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66178
- }
66179
- scheduleRemoval(timeout) {
66180
- clearTimeout(this.timeout);
66181
- this.timeout = setTimeout(() => this.setCursor(null), timeout);
66182
- }
66183
- computeTarget(event) {
66184
- let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
66185
- let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
66186
- let disableDropCursor = node && node.type.spec.disableDropCursor;
66187
- let disabled = typeof disableDropCursor == "function"
66188
- ? disableDropCursor(this.editorView, pos, event)
66189
- : disableDropCursor;
66190
- if (!pos || disabled)
66191
- return null;
66192
- let target = pos.pos;
66193
- if (this.editorView.dragging && this.editorView.dragging.slice) {
66194
- let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
66195
- if (point != null)
66196
- target = point;
66197
- }
66198
- return target;
66199
- }
66200
- dragover(event) {
66201
- if (!this.editorView.editable)
66202
- return;
66203
- this.lastDragEvent = event;
66204
- let target = this.computeTarget(event);
66205
- if (target != null) {
66206
- this.setCursor(target);
66207
- this.scheduleRemoval(5000);
66208
- }
66209
- }
66210
- dragend() {
66211
- this.scheduleRemoval(20);
66212
- }
66213
- drop() {
66214
- this.scheduleRemoval(20);
66215
- }
66216
- dragleave(event) {
66217
- if (!this.editorView.dom.contains(event.relatedTarget))
66218
- this.setCursor(null);
66219
- }
66220
- }
66221
-
66222
- /**
66223
- Gap cursor selections are represented using this class. Its
66224
- `$anchor` and `$head` properties both point at the cursor position.
66225
- */
66226
- class GapCursor extends Selection$2 {
66227
- /**
66228
- Create a gap cursor.
66229
- */
66230
- constructor($pos) {
66231
- super($pos, $pos);
66232
- }
66233
- map(doc, mapping) {
66234
- let $pos = doc.resolve(mapping.map(this.head));
66235
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66236
- }
66237
- content() { return Slice.empty; }
66238
- eq(other) {
66239
- return other instanceof GapCursor && other.head == this.head;
66240
- }
66241
- toJSON() {
66242
- return { type: "gapcursor", pos: this.head };
66243
- }
66244
- /**
66245
- @internal
66246
- */
66247
- static fromJSON(doc, json) {
66248
- if (typeof json.pos != "number")
66249
- throw new RangeError("Invalid input for GapCursor.fromJSON");
66250
- return new GapCursor(doc.resolve(json.pos));
66251
- }
66252
- /**
66253
- @internal
66254
- */
66255
- getBookmark() { return new GapBookmark(this.anchor); }
66256
- /**
66257
- @internal
66258
- */
66259
- static valid($pos) {
66260
- let parent = $pos.parent;
66261
- if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
66262
- return false;
66263
- let override = parent.type.spec.allowGapCursor;
66264
- if (override != null)
66265
- return override;
66266
- let deflt = parent.contentMatchAt($pos.index()).defaultType;
66267
- return deflt && deflt.isTextblock;
66268
- }
66269
- /**
66270
- @internal
66271
- */
66272
- static findGapCursorFrom($pos, dir, mustMove = false) {
66273
- search: for (;;) {
66274
- if (!mustMove && GapCursor.valid($pos))
66275
- return $pos;
66276
- let pos = $pos.pos, next = null;
66277
- // Scan up from this position
66278
- for (let d = $pos.depth;; d--) {
66279
- let parent = $pos.node(d);
66280
- if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
66281
- next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
66282
- break;
66283
- }
66284
- else if (d == 0) {
66285
- return null;
66286
- }
66287
- pos += dir;
66288
- let $cur = $pos.doc.resolve(pos);
66289
- if (GapCursor.valid($cur))
66290
- return $cur;
66291
- }
66292
- // And then down into the next node
66293
- for (;;) {
66294
- let inside = dir > 0 ? next.firstChild : next.lastChild;
66295
- if (!inside) {
66296
- if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
66297
- $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
66298
- mustMove = false;
66299
- continue search;
66300
- }
66301
- break;
66302
- }
66303
- next = inside;
66304
- pos += dir;
66305
- let $cur = $pos.doc.resolve(pos);
66306
- if (GapCursor.valid($cur))
66307
- return $cur;
66308
- }
66309
- return null;
66310
- }
66311
- }
66312
- }
66313
- GapCursor.prototype.visible = false;
66314
- GapCursor.findFrom = GapCursor.findGapCursorFrom;
66315
- Selection$2.jsonID("gapcursor", GapCursor);
66316
- class GapBookmark {
66317
- constructor(pos) {
66318
- this.pos = pos;
66319
- }
66320
- map(mapping) {
66321
- return new GapBookmark(mapping.map(this.pos));
66322
- }
66323
- resolve(doc) {
66324
- let $pos = doc.resolve(this.pos);
66325
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66326
- }
66327
- }
66328
- function needsGap(type) {
66329
- return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66330
- }
66331
- function closedBefore($pos) {
66332
- for (let d = $pos.depth; d >= 0; d--) {
66333
- let index = $pos.index(d), parent = $pos.node(d);
66334
- // At the start of this parent, look at next one
66335
- if (index == 0) {
66336
- if (parent.type.spec.isolating)
66337
- return true;
66338
- continue;
66339
- }
66340
- // See if the node before (or its first ancestor) is closed
66341
- for (let before = parent.child(index - 1);; before = before.lastChild) {
66342
- if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
66343
- return true;
66344
- if (before.inlineContent)
66345
- return false;
66346
- }
66347
- }
66348
- // Hit start of document
66349
- return true;
66350
- }
66351
- function closedAfter($pos) {
66352
- for (let d = $pos.depth; d >= 0; d--) {
66353
- let index = $pos.indexAfter(d), parent = $pos.node(d);
66354
- if (index == parent.childCount) {
66355
- if (parent.type.spec.isolating)
66356
- return true;
66357
- continue;
66358
- }
66359
- for (let after = parent.child(index);; after = after.firstChild) {
66360
- if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
66361
- return true;
66362
- if (after.inlineContent)
66363
- return false;
66364
- }
66365
- }
66366
- return true;
66367
- }
66877
+ * @see https://www.tiptap.dev/api/nodes/text
66878
+ */
66879
+ const Text = Node$1.create({
66880
+ name: "text",
66881
+ group: "inline",
66882
+ parseMarkdown: (token) => {
66883
+ return {
66884
+ type: "text",
66885
+ text: token.text || ""
66886
+ };
66887
+ },
66888
+ renderMarkdown: (node) => node.text || ""
66889
+ });
66890
+ //#endregion
66891
+ //#region src/index.ts
66892
+ var src_default = Text;
66368
66893
 
66369
66894
  /**
66370
- Create a gap cursor plugin. When enabled, this will capture clicks
66371
- near and arrow-key-motion past places that don't have a normally
66372
- selectable position nearby, and create a gap cursor selection for
66373
- them. The cursor is drawn as an element with class
66374
- `ProseMirror-gapcursor`. You can either include
66375
- `style/gapcursor.css` from the package's directory or add your own
66376
- styles to make it visible.
66895
+ Create a plugin that, when added to a ProseMirror instance,
66896
+ causes a decoration to show up at the drop position when something
66897
+ is dragged over the editor.
66898
+
66899
+ Nodes may add a `disableDropCursor` property to their spec to
66900
+ control the showing of a drop cursor inside them. This may be a
66901
+ boolean or a function, which will be called with a view and a
66902
+ position, and should return a boolean.
66377
66903
  */
66378
- function gapCursor() {
66904
+ function dropCursor(options = {}) {
66379
66905
  return new Plugin({
66380
- props: {
66381
- decorations: drawGapCursor,
66382
- createSelectionBetween(_view, $anchor, $head) {
66383
- return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
66384
- },
66385
- handleClick,
66386
- handleKeyDown,
66387
- handleDOMEvents: { beforeinput: beforeinput }
66388
- }
66906
+ view(editorView) { return new DropCursorView(editorView, options); }
66389
66907
  });
66390
66908
  }
66391
- const handleKeyDown = keydownHandler({
66392
- "ArrowLeft": arrow("horiz", -1),
66393
- "ArrowRight": arrow("horiz", 1),
66394
- "ArrowUp": arrow("vert", -1),
66395
- "ArrowDown": arrow("vert", 1)
66396
- });
66397
- function arrow(axis, dir) {
66398
- const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
66399
- return function (state, dispatch, view) {
66400
- let sel = state.selection;
66401
- let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
66402
- if (sel instanceof TextSelection) {
66403
- if (!view.endOfTextblock(dirStr) || $start.depth == 0)
66404
- return false;
66405
- mustMove = false;
66406
- $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
66407
- }
66408
- let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
66409
- if (!$found)
66410
- return false;
66411
- if (dispatch)
66412
- dispatch(state.tr.setSelection(new GapCursor($found)));
66413
- return true;
66414
- };
66415
- }
66416
- function handleClick(view, pos, event) {
66417
- if (!view || !view.editable)
66418
- return false;
66419
- let $pos = view.state.doc.resolve(pos);
66420
- if (!GapCursor.valid($pos))
66421
- return false;
66422
- let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
66423
- if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
66424
- return false;
66425
- view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
66426
- return true;
66427
- }
66428
- // This is a hack that, when a composition starts while a gap cursor
66429
- // is active, quickly creates an inline context for the composition to
66430
- // happen in, to avoid it being aborted by the DOM selection being
66431
- // moved into a valid position.
66432
- function beforeinput(view, event) {
66433
- if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
66434
- return false;
66435
- let { $from } = view.state.selection;
66436
- let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
66437
- if (!insert)
66438
- return false;
66439
- let frag = Fragment.empty;
66440
- for (let i = insert.length - 1; i >= 0; i--)
66441
- frag = Fragment.from(insert[i].createAndFill(null, frag));
66442
- let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
66443
- tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
66444
- view.dispatch(tr);
66445
- return false;
66446
- }
66447
- function drawGapCursor(state) {
66448
- if (!(state.selection instanceof GapCursor))
66449
- return null;
66450
- let node = document.createElement("div");
66451
- node.className = "ProseMirror-gapcursor";
66452
- return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
66453
- }
66454
-
66455
- var GOOD_LEAF_SIZE = 200;
66456
-
66457
- // :: class<T> A rope sequence is a persistent sequence data structure
66458
- // that supports appending, prepending, and slicing without doing a
66459
- // full copy. It is represented as a mostly-balanced tree.
66460
- var RopeSequence = function RopeSequence () {};
66461
-
66462
- RopeSequence.prototype.append = function append (other) {
66463
- if (!other.length) { return this }
66464
- other = RopeSequence.from(other);
66465
-
66466
- return (!this.length && other) ||
66467
- (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
66468
- (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
66469
- this.appendInner(other)
66470
- };
66471
-
66472
- // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
66473
- // Prepend an array or other rope to this one, returning a new rope.
66474
- RopeSequence.prototype.prepend = function prepend (other) {
66475
- if (!other.length) { return this }
66476
- return RopeSequence.from(other).append(this)
66477
- };
66478
-
66479
- RopeSequence.prototype.appendInner = function appendInner (other) {
66480
- return new Append(this, other)
66481
- };
66482
-
66483
- // :: (?number, ?number) → RopeSequence<T>
66484
- // Create a rope repesenting a sub-sequence of this rope.
66485
- RopeSequence.prototype.slice = function slice (from, to) {
66486
- if ( from === void 0 ) from = 0;
66487
- if ( to === void 0 ) to = this.length;
66488
-
66489
- if (from >= to) { return RopeSequence.empty }
66490
- return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
66491
- };
66492
-
66493
- // :: (number) → T
66494
- // Retrieve the element at the given position from this rope.
66495
- RopeSequence.prototype.get = function get (i) {
66496
- if (i < 0 || i >= this.length) { return undefined }
66497
- return this.getInner(i)
66498
- };
66499
-
66500
- // :: ((element: T, index: number) → ?bool, ?number, ?number)
66501
- // Call the given function for each element between the given
66502
- // indices. This tends to be more efficient than looping over the
66503
- // indices and calling `get`, because it doesn't have to descend the
66504
- // tree for every element.
66505
- RopeSequence.prototype.forEach = function forEach (f, from, to) {
66506
- if ( from === void 0 ) from = 0;
66507
- if ( to === void 0 ) to = this.length;
66508
-
66509
- if (from <= to)
66510
- { this.forEachInner(f, from, to, 0); }
66511
- else
66512
- { this.forEachInvertedInner(f, from, to, 0); }
66513
- };
66514
-
66515
- // :: ((element: T, index: number) → U, ?number, ?number) → [U]
66516
- // Map the given functions over the elements of the rope, producing
66517
- // a flat array.
66518
- RopeSequence.prototype.map = function map (f, from, to) {
66519
- if ( from === void 0 ) from = 0;
66520
- if ( to === void 0 ) to = this.length;
66521
-
66522
- var result = [];
66523
- this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
66524
- return result
66525
- };
66526
-
66527
- // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
66528
- // Create a rope representing the given array, or return the rope
66529
- // itself if a rope was given.
66530
- RopeSequence.from = function from (values) {
66531
- if (values instanceof RopeSequence) { return values }
66532
- return values && values.length ? new Leaf(values) : RopeSequence.empty
66533
- };
66534
-
66535
- var Leaf = /*@__PURE__*/(function (RopeSequence) {
66536
- function Leaf(values) {
66537
- RopeSequence.call(this);
66538
- this.values = values;
66539
- }
66540
-
66541
- if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
66542
- Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66543
- Leaf.prototype.constructor = Leaf;
66544
-
66545
- var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
66546
-
66547
- Leaf.prototype.flatten = function flatten () {
66548
- return this.values
66549
- };
66550
-
66551
- Leaf.prototype.sliceInner = function sliceInner (from, to) {
66552
- if (from == 0 && to == this.length) { return this }
66553
- return new Leaf(this.values.slice(from, to))
66554
- };
66555
-
66556
- Leaf.prototype.getInner = function getInner (i) {
66557
- return this.values[i]
66558
- };
66559
-
66560
- Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
66561
- for (var i = from; i < to; i++)
66562
- { if (f(this.values[i], start + i) === false) { return false } }
66563
- };
66564
-
66565
- Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66566
- for (var i = from - 1; i >= to; i--)
66567
- { if (f(this.values[i], start + i) === false) { return false } }
66568
- };
66569
-
66570
- Leaf.prototype.leafAppend = function leafAppend (other) {
66571
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66572
- { return new Leaf(this.values.concat(other.flatten())) }
66573
- };
66574
-
66575
- Leaf.prototype.leafPrepend = function leafPrepend (other) {
66576
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66577
- { return new Leaf(other.flatten().concat(this.values)) }
66578
- };
66579
-
66580
- prototypeAccessors.length.get = function () { return this.values.length };
66581
-
66582
- prototypeAccessors.depth.get = function () { return 0 };
66583
-
66584
- Object.defineProperties( Leaf.prototype, prototypeAccessors );
66585
-
66586
- return Leaf;
66587
- }(RopeSequence));
66588
-
66589
- // :: RopeSequence
66590
- // The empty rope sequence.
66591
- RopeSequence.empty = new Leaf([]);
66592
-
66593
- var Append = /*@__PURE__*/(function (RopeSequence) {
66594
- function Append(left, right) {
66595
- RopeSequence.call(this);
66596
- this.left = left;
66597
- this.right = right;
66598
- this.length = left.length + right.length;
66599
- this.depth = Math.max(left.depth, right.depth) + 1;
66600
- }
66601
-
66602
- if ( RopeSequence ) Append.__proto__ = RopeSequence;
66603
- Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66604
- Append.prototype.constructor = Append;
66605
-
66606
- Append.prototype.flatten = function flatten () {
66607
- return this.left.flatten().concat(this.right.flatten())
66608
- };
66609
-
66610
- Append.prototype.getInner = function getInner (i) {
66611
- return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
66612
- };
66613
-
66614
- Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
66615
- var leftLen = this.left.length;
66616
- if (from < leftLen &&
66617
- this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
66618
- { return false }
66619
- if (to > leftLen &&
66620
- this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
66621
- { return false }
66622
- };
66623
-
66624
- Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66625
- var leftLen = this.left.length;
66626
- if (from > leftLen &&
66627
- this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
66628
- { return false }
66629
- if (to < leftLen &&
66630
- this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
66631
- { return false }
66632
- };
66633
-
66634
- Append.prototype.sliceInner = function sliceInner (from, to) {
66635
- if (from == 0 && to == this.length) { return this }
66636
- var leftLen = this.left.length;
66637
- if (to <= leftLen) { return this.left.slice(from, to) }
66638
- if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
66639
- return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
66640
- };
66641
-
66642
- Append.prototype.leafAppend = function leafAppend (other) {
66643
- var inner = this.right.leafAppend(other);
66644
- if (inner) { return new Append(this.left, inner) }
66645
- };
66646
-
66647
- Append.prototype.leafPrepend = function leafPrepend (other) {
66648
- var inner = this.left.leafPrepend(other);
66649
- if (inner) { return new Append(inner, this.right) }
66650
- };
66651
-
66652
- Append.prototype.appendInner = function appendInner (other) {
66653
- if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
66654
- { return new Append(this.left, new Append(this.right, other)) }
66655
- return new Append(this, other)
66656
- };
66657
-
66658
- return Append;
66659
- }(RopeSequence));
66660
-
66661
- // ProseMirror's history isn't simply a way to roll back to a previous
66662
- // state, because ProseMirror supports applying changes without adding
66663
- // them to the history (for example during collaboration).
66664
- //
66665
- // To this end, each 'Branch' (one for the undo history and one for
66666
- // the redo history) keeps an array of 'Items', which can optionally
66667
- // hold a step (an actual undoable change), and always hold a position
66668
- // map (which is needed to move changes below them to apply to the
66669
- // current document).
66670
- //
66671
- // An item that has both a step and a selection bookmark is the start
66672
- // of an 'event' — a group of changes that will be undone or redone at
66673
- // once. (It stores only the bookmark, since that way we don't have to
66674
- // provide a document until the selection is actually applied, which
66675
- // is useful when compressing.)
66676
- // Used to schedule history compression
66677
- const max_empty_items = 500;
66678
- class Branch {
66679
- constructor(items, eventCount) {
66680
- this.items = items;
66681
- this.eventCount = eventCount;
66682
- }
66683
- // Pop the latest event off the branch's history and apply it
66684
- // to a document transform.
66685
- popEvent(state, preserveItems) {
66686
- if (this.eventCount == 0)
66687
- return null;
66688
- let end = this.items.length;
66689
- for (;; end--) {
66690
- let next = this.items.get(end - 1);
66691
- if (next.selection) {
66692
- --end;
66693
- break;
66694
- }
66695
- }
66696
- let remap, mapFrom;
66697
- if (preserveItems) {
66698
- remap = this.remapping(end, this.items.length);
66699
- mapFrom = remap.maps.length;
66700
- }
66701
- let transform = state.tr;
66702
- let selection, remaining;
66703
- let addAfter = [], addBefore = [];
66704
- this.items.forEach((item, i) => {
66705
- if (!item.step) {
66706
- if (!remap) {
66707
- remap = this.remapping(end, i + 1);
66708
- mapFrom = remap.maps.length;
66709
- }
66710
- mapFrom--;
66711
- addBefore.push(item);
66712
- return;
66713
- }
66714
- if (remap) {
66715
- addBefore.push(new Item(item.map));
66716
- let step = item.step.map(remap.slice(mapFrom)), map;
66717
- if (step && transform.maybeStep(step).doc) {
66718
- map = transform.mapping.maps[transform.mapping.maps.length - 1];
66719
- addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
66720
- }
66721
- mapFrom--;
66722
- if (map)
66723
- remap.appendMap(map, mapFrom);
66724
- }
66725
- else {
66726
- transform.maybeStep(item.step);
66727
- }
66728
- if (item.selection) {
66729
- selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
66730
- remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
66731
- return false;
66732
- }
66733
- }, this.items.length, 0);
66734
- return { remaining: remaining, transform, selection: selection };
66735
- }
66736
- // Create a new branch with the given transform added.
66737
- addTransform(transform, selection, histOptions, preserveItems) {
66738
- let newItems = [], eventCount = this.eventCount;
66739
- let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
66740
- for (let i = 0; i < transform.steps.length; i++) {
66741
- let step = transform.steps[i].invert(transform.docs[i]);
66742
- let item = new Item(transform.mapping.maps[i], step, selection), merged;
66743
- if (merged = lastItem && lastItem.merge(item)) {
66744
- item = merged;
66745
- if (i)
66746
- newItems.pop();
66747
- else
66748
- oldItems = oldItems.slice(0, oldItems.length - 1);
66749
- }
66750
- newItems.push(item);
66751
- if (selection) {
66752
- eventCount++;
66753
- selection = undefined;
66754
- }
66755
- if (!preserveItems)
66756
- lastItem = item;
66757
- }
66758
- let overflow = eventCount - histOptions.depth;
66759
- if (overflow > DEPTH_OVERFLOW) {
66760
- oldItems = cutOffEvents(oldItems, overflow);
66761
- eventCount -= overflow;
66762
- }
66763
- return new Branch(oldItems.append(newItems), eventCount);
66764
- }
66765
- remapping(from, to) {
66766
- let maps = new Mapping;
66767
- this.items.forEach((item, i) => {
66768
- let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
66769
- ? maps.maps.length - item.mirrorOffset : undefined;
66770
- maps.appendMap(item.map, mirrorPos);
66771
- }, from, to);
66772
- return maps;
66773
- }
66774
- addMaps(array) {
66775
- if (this.eventCount == 0)
66776
- return this;
66777
- return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
66778
- }
66779
- // When the collab module receives remote changes, the history has
66780
- // to know about those, so that it can adjust the steps that were
66781
- // rebased on top of the remote changes, and include the position
66782
- // maps for the remote changes in its array of items.
66783
- rebased(rebasedTransform, rebasedCount) {
66784
- if (!this.eventCount)
66785
- return this;
66786
- let rebasedItems = [], start = Math.max(0, this.items.length - rebasedCount);
66787
- let mapping = rebasedTransform.mapping;
66788
- let newUntil = rebasedTransform.steps.length;
66789
- let eventCount = this.eventCount;
66790
- this.items.forEach(item => { if (item.selection)
66791
- eventCount--; }, start);
66792
- let iRebased = rebasedCount;
66793
- this.items.forEach(item => {
66794
- let pos = mapping.getMirror(--iRebased);
66795
- if (pos == null)
66796
- return;
66797
- newUntil = Math.min(newUntil, pos);
66798
- let map = mapping.maps[pos];
66799
- if (item.step) {
66800
- let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
66801
- let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
66802
- if (selection)
66803
- eventCount++;
66804
- rebasedItems.push(new Item(map, step, selection));
66805
- }
66806
- else {
66807
- rebasedItems.push(new Item(map));
66808
- }
66809
- }, start);
66810
- let newMaps = [];
66811
- for (let i = rebasedCount; i < newUntil; i++)
66812
- newMaps.push(new Item(mapping.maps[i]));
66813
- let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
66814
- let branch = new Branch(items, eventCount);
66815
- if (branch.emptyItemCount() > max_empty_items)
66816
- branch = branch.compress(this.items.length - rebasedItems.length);
66817
- return branch;
66909
+ class DropCursorView {
66910
+ constructor(editorView, options) {
66911
+ var _a;
66912
+ this.editorView = editorView;
66913
+ this.cursorPos = null;
66914
+ this.element = null;
66915
+ this.timeout = -1;
66916
+ this.lastDragEvent = null;
66917
+ this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66918
+ this.color = options.color === false ? undefined : (options.color || "black");
66919
+ this.class = options.class;
66920
+ this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66921
+ let handler = (e) => { this[name](e); };
66922
+ editorView.dom.addEventListener(name, handler);
66923
+ return { name, handler };
66924
+ });
66818
66925
  }
66819
- emptyItemCount() {
66820
- let count = 0;
66821
- this.items.forEach(item => { if (!item.step)
66822
- count++; });
66823
- return count;
66926
+ destroy() {
66927
+ this.setCursor(null);
66928
+ this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66824
66929
  }
66825
- // Compressing a branch means rewriting it to push the air (map-only
66826
- // items) out. During collaboration, these naturally accumulate
66827
- // because each remote change adds one. The `upto` argument is used
66828
- // to ensure that only the items below a given level are compressed,
66829
- // because `rebased` relies on a clean, untouched set of items in
66830
- // order to associate old items with rebased steps.
66831
- compress(upto = this.items.length) {
66832
- let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
66833
- let items = [], events = 0;
66834
- this.items.forEach((item, i) => {
66835
- if (i >= upto) {
66836
- items.push(item);
66837
- if (item.selection)
66838
- events++;
66930
+ update(editorView, prevState) {
66931
+ if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66932
+ // if we currently have an on-going drag event
66933
+ // we need to update the cursor position again and update the overlay
66934
+ if (this.lastDragEvent) {
66935
+ let target = this.computeTarget(this.lastDragEvent);
66936
+ if (target == this.cursorPos)
66937
+ this.updateOverlay();
66938
+ else
66939
+ this.setCursor(target);
66839
66940
  }
66840
- else if (item.step) {
66841
- let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
66842
- mapFrom--;
66843
- if (map)
66844
- remap.appendMap(map, mapFrom);
66845
- if (step) {
66846
- let selection = item.selection && item.selection.map(remap.slice(mapFrom));
66847
- if (selection)
66848
- events++;
66849
- let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
66850
- if (merged = items.length && items[last].merge(newItem))
66851
- items[last] = merged;
66852
- else
66853
- items.push(newItem);
66941
+ else {
66942
+ this.updateOverlay();
66943
+ }
66944
+ }
66945
+ }
66946
+ setCursor(pos) {
66947
+ if (pos == this.cursorPos)
66948
+ return;
66949
+ this.cursorPos = pos;
66950
+ if (pos == null) {
66951
+ this.element.parentNode.removeChild(this.element);
66952
+ this.element = null;
66953
+ }
66954
+ else {
66955
+ this.updateOverlay();
66956
+ }
66957
+ }
66958
+ updateOverlay() {
66959
+ let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66960
+ let isBlock = !$pos.parent.inlineContent, rect;
66961
+ let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66962
+ let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66963
+ if (isBlock) {
66964
+ let before = $pos.nodeBefore, after = $pos.nodeAfter;
66965
+ if (before || after) {
66966
+ let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66967
+ if (node) {
66968
+ let nodeRect = node.getBoundingClientRect();
66969
+ let top = before ? nodeRect.bottom : nodeRect.top;
66970
+ if (before && after)
66971
+ top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66972
+ let halfWidth = (this.width / 2) * scaleY;
66973
+ rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66854
66974
  }
66855
66975
  }
66856
- else if (item.map) {
66857
- mapFrom--;
66976
+ }
66977
+ if (!rect) {
66978
+ let coords = this.editorView.coordsAtPos(this.cursorPos);
66979
+ let halfWidth = (this.width / 2) * scaleX;
66980
+ rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66981
+ }
66982
+ let parent = this.editorView.dom.offsetParent;
66983
+ if (!this.element) {
66984
+ this.element = parent.appendChild(document.createElement("div"));
66985
+ if (this.class)
66986
+ this.element.className = this.class;
66987
+ this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
66988
+ if (this.color) {
66989
+ this.element.style.backgroundColor = this.color;
66858
66990
  }
66859
- }, this.items.length, 0);
66860
- return new Branch(RopeSequence.from(items.reverse()), events);
66991
+ }
66992
+ this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
66993
+ this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
66994
+ let parentLeft, parentTop;
66995
+ if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
66996
+ parentLeft = -pageXOffset;
66997
+ parentTop = -pageYOffset;
66998
+ }
66999
+ else {
67000
+ let rect = parent.getBoundingClientRect();
67001
+ let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
67002
+ parentLeft = rect.left - parent.scrollLeft * parentScaleX;
67003
+ parentTop = rect.top - parent.scrollTop * parentScaleY;
67004
+ }
67005
+ this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
67006
+ this.element.style.top = (rect.top - parentTop) / scaleY + "px";
67007
+ this.element.style.width = (rect.right - rect.left) / scaleX + "px";
67008
+ this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66861
67009
  }
66862
- }
66863
- Branch.empty = new Branch(RopeSequence.empty, 0);
66864
- function cutOffEvents(items, n) {
66865
- let cutPoint;
66866
- items.forEach((item, i) => {
66867
- if (item.selection && (n-- == 0)) {
66868
- cutPoint = i;
66869
- return false;
67010
+ scheduleRemoval(timeout) {
67011
+ clearTimeout(this.timeout);
67012
+ this.timeout = setTimeout(() => this.setCursor(null), timeout);
67013
+ }
67014
+ computeTarget(event) {
67015
+ let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
67016
+ let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
67017
+ let disableDropCursor = node && node.type.spec.disableDropCursor;
67018
+ let disabled = typeof disableDropCursor == "function"
67019
+ ? disableDropCursor(this.editorView, pos, event)
67020
+ : disableDropCursor;
67021
+ if (!pos || disabled)
67022
+ return null;
67023
+ let target = pos.pos;
67024
+ if (this.editorView.dragging && this.editorView.dragging.slice) {
67025
+ let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
67026
+ if (point != null)
67027
+ target = point;
66870
67028
  }
66871
- });
66872
- return items.slice(cutPoint);
66873
- }
66874
- class Item {
66875
- constructor(
66876
- // The (forward) step map for this item.
66877
- map,
66878
- // The inverted step
66879
- step,
66880
- // If this is non-null, this item is the start of a group, and
66881
- // this selection is the starting selection for the group (the one
66882
- // that was active before the first step was applied)
66883
- selection,
66884
- // If this item is the inverse of a previous mapping on the stack,
66885
- // this points at the inverse's offset
66886
- mirrorOffset) {
66887
- this.map = map;
66888
- this.step = step;
66889
- this.selection = selection;
66890
- this.mirrorOffset = mirrorOffset;
67029
+ return target;
66891
67030
  }
66892
- merge(other) {
66893
- if (this.step && other.step && !other.selection) {
66894
- let step = other.step.merge(this.step);
66895
- if (step)
66896
- return new Item(step.getMap().invert(), step, this.selection);
67031
+ dragover(event) {
67032
+ if (!this.editorView.editable)
67033
+ return;
67034
+ this.lastDragEvent = event;
67035
+ let target = this.computeTarget(event);
67036
+ if (target != null) {
67037
+ this.setCursor(target);
67038
+ this.scheduleRemoval(5000);
66897
67039
  }
66898
67040
  }
66899
- }
66900
- // The value of the state field that tracks undo/redo history for that
66901
- // state. Will be stored in the plugin state when the history plugin
66902
- // is active.
66903
- class HistoryState {
66904
- constructor(done, undone, prevRanges, prevTime, prevComposition) {
66905
- this.done = done;
66906
- this.undone = undone;
66907
- this.prevRanges = prevRanges;
66908
- this.prevTime = prevTime;
66909
- this.prevComposition = prevComposition;
67041
+ dragend() {
67042
+ this.scheduleRemoval(20);
67043
+ }
67044
+ drop() {
67045
+ this.scheduleRemoval(20);
67046
+ }
67047
+ dragleave(event) {
67048
+ if (!this.editorView.dom.contains(event.relatedTarget))
67049
+ this.setCursor(null);
66910
67050
  }
66911
67051
  }
66912
- const DEPTH_OVERFLOW = 20;
66913
- // Record a transformation in undo history.
66914
- function applyTransaction(history, state, tr, options) {
66915
- let historyTr = tr.getMeta(historyKey), rebased;
66916
- if (historyTr)
66917
- return historyTr.historyState;
66918
- if (tr.getMeta(closeHistoryKey))
66919
- history = new HistoryState(history.done, history.undone, null, 0, -1);
66920
- let appended = tr.getMeta("appendedTransaction");
66921
- if (tr.steps.length == 0) {
66922
- return history;
67052
+
67053
+ /**
67054
+ Gap cursor selections are represented using this class. Its
67055
+ `$anchor` and `$head` properties both point at the cursor position.
67056
+ */
67057
+ class GapCursor extends Selection$2 {
67058
+ /**
67059
+ Create a gap cursor.
67060
+ */
67061
+ constructor($pos) {
67062
+ super($pos, $pos);
66923
67063
  }
66924
- else if (appended && appended.getMeta(historyKey)) {
66925
- if (appended.getMeta(historyKey).redo)
66926
- return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
66927
- else
66928
- return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
67064
+ map(doc, mapping) {
67065
+ let $pos = doc.resolve(mapping.map(this.head));
67066
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66929
67067
  }
66930
- else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
66931
- // Group transforms that occur in quick succession into one event.
66932
- let composition = tr.getMeta("composition");
66933
- let newGroup = history.prevTime == 0 ||
66934
- (!appended && history.prevComposition != composition &&
66935
- (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
66936
- let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
66937
- return new HistoryState(history.done.addTransform(tr, newGroup ? state.selection.getBookmark() : undefined, options, mustPreserveItems(state)), Branch.empty, prevRanges, tr.time, composition == null ? history.prevComposition : composition);
67068
+ content() { return Slice.empty; }
67069
+ eq(other) {
67070
+ return other instanceof GapCursor && other.head == this.head;
66938
67071
  }
66939
- else if (rebased = tr.getMeta("rebased")) {
66940
- // Used by the collab module to tell the history that some of its
66941
- // content has been rebased.
66942
- return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67072
+ toJSON() {
67073
+ return { type: "gapcursor", pos: this.head };
66943
67074
  }
66944
- else {
66945
- return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67075
+ /**
67076
+ @internal
67077
+ */
67078
+ static fromJSON(doc, json) {
67079
+ if (typeof json.pos != "number")
67080
+ throw new RangeError("Invalid input for GapCursor.fromJSON");
67081
+ return new GapCursor(doc.resolve(json.pos));
67082
+ }
67083
+ /**
67084
+ @internal
67085
+ */
67086
+ getBookmark() { return new GapBookmark(this.anchor); }
67087
+ /**
67088
+ @internal
67089
+ */
67090
+ static valid($pos) {
67091
+ let parent = $pos.parent;
67092
+ if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
67093
+ return false;
67094
+ let override = parent.type.spec.allowGapCursor;
67095
+ if (override != null)
67096
+ return override;
67097
+ let deflt = parent.contentMatchAt($pos.index()).defaultType;
67098
+ return deflt && deflt.isTextblock;
67099
+ }
67100
+ /**
67101
+ @internal
67102
+ */
67103
+ static findGapCursorFrom($pos, dir, mustMove = false) {
67104
+ search: for (;;) {
67105
+ if (!mustMove && GapCursor.valid($pos))
67106
+ return $pos;
67107
+ let pos = $pos.pos, next = null;
67108
+ // Scan up from this position
67109
+ for (let d = $pos.depth;; d--) {
67110
+ let parent = $pos.node(d);
67111
+ if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
67112
+ next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
67113
+ break;
67114
+ }
67115
+ else if (d == 0) {
67116
+ return null;
67117
+ }
67118
+ pos += dir;
67119
+ let $cur = $pos.doc.resolve(pos);
67120
+ if (GapCursor.valid($cur))
67121
+ return $cur;
67122
+ }
67123
+ // And then down into the next node
67124
+ for (;;) {
67125
+ let inside = dir > 0 ? next.firstChild : next.lastChild;
67126
+ if (!inside) {
67127
+ if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
67128
+ $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
67129
+ mustMove = false;
67130
+ continue search;
67131
+ }
67132
+ break;
67133
+ }
67134
+ next = inside;
67135
+ pos += dir;
67136
+ let $cur = $pos.doc.resolve(pos);
67137
+ if (GapCursor.valid($cur))
67138
+ return $cur;
67139
+ }
67140
+ return null;
67141
+ }
66946
67142
  }
66947
67143
  }
66948
- function isAdjacentTo(transform, prevRanges) {
66949
- if (!prevRanges)
66950
- return false;
66951
- if (!transform.docChanged)
66952
- return true;
66953
- let adjacent = false;
66954
- transform.mapping.maps[0].forEach((start, end) => {
66955
- for (let i = 0; i < prevRanges.length; i += 2)
66956
- if (start <= prevRanges[i + 1] && end >= prevRanges[i])
66957
- adjacent = true;
66958
- });
66959
- return adjacent;
67144
+ GapCursor.prototype.visible = false;
67145
+ GapCursor.findFrom = GapCursor.findGapCursorFrom;
67146
+ Selection$2.jsonID("gapcursor", GapCursor);
67147
+ class GapBookmark {
67148
+ constructor(pos) {
67149
+ this.pos = pos;
67150
+ }
67151
+ map(mapping) {
67152
+ return new GapBookmark(mapping.map(this.pos));
67153
+ }
67154
+ resolve(doc) {
67155
+ let $pos = doc.resolve(this.pos);
67156
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
67157
+ }
66960
67158
  }
66961
- function rangesFor(maps) {
66962
- let result = [];
66963
- for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
66964
- maps[i].forEach((_from, _to, from, to) => result.push(from, to));
66965
- return result;
67159
+ function needsGap(type) {
67160
+ return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66966
67161
  }
66967
- function mapRanges(ranges, mapping) {
66968
- if (!ranges)
66969
- return null;
66970
- let result = [];
66971
- for (let i = 0; i < ranges.length; i += 2) {
66972
- let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
66973
- if (from <= to)
66974
- result.push(from, to);
67162
+ function closedBefore($pos) {
67163
+ for (let d = $pos.depth; d >= 0; d--) {
67164
+ let index = $pos.index(d), parent = $pos.node(d);
67165
+ // At the start of this parent, look at next one
67166
+ if (index == 0) {
67167
+ if (parent.type.spec.isolating)
67168
+ return true;
67169
+ continue;
67170
+ }
67171
+ // See if the node before (or its first ancestor) is closed
67172
+ for (let before = parent.child(index - 1);; before = before.lastChild) {
67173
+ if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
67174
+ return true;
67175
+ if (before.inlineContent)
67176
+ return false;
67177
+ }
66975
67178
  }
66976
- return result;
66977
- }
66978
- // Apply the latest event from one branch to the document and shift the event
66979
- // onto the other branch.
66980
- function histTransaction(history, state, redo) {
66981
- let preserveItems = mustPreserveItems(state);
66982
- let histOptions = historyKey.get(state).spec.config;
66983
- let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
66984
- if (!pop)
66985
- return null;
66986
- let selection = pop.selection.resolve(pop.transform.doc);
66987
- let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
66988
- let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
66989
- return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
67179
+ // Hit start of document
67180
+ return true;
66990
67181
  }
66991
- let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
66992
- // Check whether any plugin in the given state has a
66993
- // `historyPreserveItems` property in its spec, in which case we must
66994
- // preserve steps exactly as they came in, so that they can be
66995
- // rebased.
66996
- function mustPreserveItems(state) {
66997
- let plugins = state.plugins;
66998
- if (cachedPreserveItemsPlugins != plugins) {
66999
- cachedPreserveItems = false;
67000
- cachedPreserveItemsPlugins = plugins;
67001
- for (let i = 0; i < plugins.length; i++)
67002
- if (plugins[i].spec.historyPreserveItems) {
67003
- cachedPreserveItems = true;
67004
- break;
67005
- }
67182
+ function closedAfter($pos) {
67183
+ for (let d = $pos.depth; d >= 0; d--) {
67184
+ let index = $pos.indexAfter(d), parent = $pos.node(d);
67185
+ if (index == parent.childCount) {
67186
+ if (parent.type.spec.isolating)
67187
+ return true;
67188
+ continue;
67189
+ }
67190
+ for (let after = parent.child(index);; after = after.firstChild) {
67191
+ if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
67192
+ return true;
67193
+ if (after.inlineContent)
67194
+ return false;
67195
+ }
67006
67196
  }
67007
- return cachedPreserveItems;
67197
+ return true;
67008
67198
  }
67009
- const historyKey = new PluginKey("history");
67010
- const closeHistoryKey = new PluginKey("closeHistory");
67011
- /**
67012
- Returns a plugin that enables the undo history for an editor. The
67013
- plugin will track undo and redo stacks, which can be used with the
67014
- [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
67015
67199
 
67016
- You can set an `"addToHistory"` [metadata
67017
- property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
67018
- to prevent it from being rolled back by undo.
67200
+ /**
67201
+ Create a gap cursor plugin. When enabled, this will capture clicks
67202
+ near and arrow-key-motion past places that don't have a normally
67203
+ selectable position nearby, and create a gap cursor selection for
67204
+ them. The cursor is drawn as an element with class
67205
+ `ProseMirror-gapcursor`. You can either include
67206
+ `style/gapcursor.css` from the package's directory or add your own
67207
+ styles to make it visible.
67019
67208
  */
67020
- function history(config = {}) {
67021
- config = { depth: config.depth || 100,
67022
- newGroupDelay: config.newGroupDelay || 500 };
67209
+ function gapCursor() {
67023
67210
  return new Plugin({
67024
- key: historyKey,
67025
- state: {
67026
- init() {
67027
- return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
67028
- },
67029
- apply(tr, hist, state) {
67030
- return applyTransaction(hist, state, tr, config);
67031
- }
67032
- },
67033
- config,
67034
67211
  props: {
67035
- handleDOMEvents: {
67036
- beforeinput(view, e) {
67037
- let inputType = e.inputType;
67038
- let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
67039
- if (!command || !view.editable)
67040
- return false;
67041
- e.preventDefault();
67042
- return command(view.state, view.dispatch);
67043
- }
67044
- }
67212
+ decorations: drawGapCursor,
67213
+ createSelectionBetween(_view, $anchor, $head) {
67214
+ return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
67215
+ },
67216
+ handleClick,
67217
+ handleKeyDown,
67218
+ handleDOMEvents: { beforeinput: beforeinput }
67045
67219
  }
67046
67220
  });
67047
67221
  }
67048
- function buildCommand(redo, scroll) {
67049
- return (state, dispatch) => {
67050
- let hist = historyKey.getState(state);
67051
- if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
67052
- return false;
67053
- if (dispatch) {
67054
- let tr = histTransaction(hist, state, redo);
67055
- if (tr)
67056
- dispatch(scroll ? tr.scrollIntoView() : tr);
67222
+ const handleKeyDown = keydownHandler({
67223
+ "ArrowLeft": arrow("horiz", -1),
67224
+ "ArrowRight": arrow("horiz", 1),
67225
+ "ArrowUp": arrow("vert", -1),
67226
+ "ArrowDown": arrow("vert", 1)
67227
+ });
67228
+ function arrow(axis, dir) {
67229
+ const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
67230
+ return function (state, dispatch, view) {
67231
+ let sel = state.selection;
67232
+ let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
67233
+ if (sel instanceof TextSelection) {
67234
+ if (!view.endOfTextblock(dirStr) || $start.depth == 0)
67235
+ return false;
67236
+ mustMove = false;
67237
+ $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
67057
67238
  }
67239
+ let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
67240
+ if (!$found)
67241
+ return false;
67242
+ if (dispatch)
67243
+ dispatch(state.tr.setSelection(new GapCursor($found)));
67058
67244
  return true;
67059
67245
  };
67060
67246
  }
67061
- /**
67062
- A command function that undoes the last change, if any.
67063
- */
67064
- const undo = buildCommand(false, true);
67065
- /**
67066
- A command function that redoes the last undone change, if any.
67067
- */
67068
- const redo = buildCommand(true, true);
67247
+ function handleClick(view, pos, event) {
67248
+ if (!view || !view.editable)
67249
+ return false;
67250
+ let $pos = view.state.doc.resolve(pos);
67251
+ if (!GapCursor.valid($pos))
67252
+ return false;
67253
+ let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
67254
+ if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
67255
+ return false;
67256
+ view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
67257
+ return true;
67258
+ }
67259
+ // This is a hack that, when a composition starts while a gap cursor
67260
+ // is active, quickly creates an inline context for the composition to
67261
+ // happen in, to avoid it being aborted by the DOM selection being
67262
+ // moved into a valid position.
67263
+ function beforeinput(view, event) {
67264
+ if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
67265
+ return false;
67266
+ let { $from } = view.state.selection;
67267
+ let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
67268
+ if (!insert)
67269
+ return false;
67270
+ let frag = Fragment.empty;
67271
+ for (let i = insert.length - 1; i >= 0; i--)
67272
+ frag = Fragment.from(insert[i].createAndFill(null, frag));
67273
+ let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
67274
+ tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
67275
+ view.dispatch(tr);
67276
+ return false;
67277
+ }
67278
+ function drawGapCursor(state) {
67279
+ if (!(state.selection instanceof GapCursor))
67280
+ return null;
67281
+ let node = document.createElement("div");
67282
+ node.className = "ProseMirror-gapcursor";
67283
+ return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
67284
+ }
67069
67285
 
67070
67286
  //#region src/character-count/character-count.ts
67071
67287
  /**
@@ -97660,12 +97876,12 @@ focus outline in that case.
97660
97876
  toDOMStream(options) {
97661
97877
  return streamAdapters.toDOMStream((this._closedPromiseResolve || this._error)
97662
97878
  ? this
97663
- : this._values, options);
97879
+ : this._values);
97664
97880
  }
97665
97881
  toNodeStream(options) {
97666
97882
  return streamAdapters.toNodeStream((this._closedPromiseResolve || this._error)
97667
97883
  ? this
97668
- : this._values, options);
97884
+ : this._values);
97669
97885
  }
97670
97886
  throw(_) {
97671
97887
  return __awaiter(this, void 0, void 0, function* () { yield this.abort(_); return ITERATOR_DONE; });
@@ -100056,7 +100272,7 @@ focus outline in that case.
100056
100272
  toNodeStream() {
100057
100273
  return streamAdapters.toNodeStream((this.isSync()
100058
100274
  ? { [Symbol.iterator]: () => this }
100059
- : { [Symbol.asyncIterator]: () => this }), { objectMode: true });
100275
+ : { [Symbol.asyncIterator]: () => this }));
100060
100276
  }
100061
100277
  /** @nocollapse */
100062
100278
  // @ts-ignore