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