@ni/ok-components 1.10.0 → 1.10.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.
@@ -29805,7 +29805,6 @@ so this becomes the fallback color for the slot */ ''}
29805
29805
  if (!type)
29806
29806
  throw new RangeError(`There is no mark type ${json.type} in this schema`);
29807
29807
  let mark = type.create(json.attrs);
29808
- type.checkAttrs(mark.attrs);
29809
29808
  return mark;
29810
29809
  }
29811
29810
  /**
@@ -30785,11 +30784,11 @@ so this becomes the fallback color for the slot */ ''}
30785
30784
  */
30786
30785
  check() {
30787
30786
  this.type.checkContent(this.content);
30788
- this.type.checkAttrs(this.attrs);
30787
+ checkAttrs(this.type.attrs, this.attrs, "node", this.type.name);
30789
30788
  let copy = Mark$1.none;
30790
30789
  for (let i = 0; i < this.marks.length; i++) {
30791
30790
  let mark = this.marks[i];
30792
- mark.type.checkAttrs(mark.attrs);
30791
+ checkAttrs(mark.type.attrs, mark.attrs, "mark", mark.type.name);
30793
30792
  copy = mark.addToSet(copy);
30794
30793
  }
30795
30794
  if (!Mark$1.sameSet(copy, this.marks))
@@ -30830,7 +30829,6 @@ so this becomes the fallback color for the slot */ ''}
30830
30829
  }
30831
30830
  let content = Fragment.fromJSON(schema, json.content);
30832
30831
  let node = schema.nodeType(json.type).create(json.attrs, content, marks);
30833
- node.type.checkAttrs(node.attrs);
30834
30832
  return node;
30835
30833
  }
30836
30834
  };
@@ -30880,6 +30878,15 @@ so this becomes the fallback color for the slot */ ''}
30880
30878
  str = marks[i].type.name + "(" + str + ")";
30881
30879
  return str;
30882
30880
  }
30881
+ function checkAttrs(attrs, values, type, name) {
30882
+ for (let attr in values)
30883
+ if (!(attr in attrs))
30884
+ throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
30885
+ for (let attr in attrs) {
30886
+ if (attrs[attr].validate)
30887
+ attrs[attr].validate(values[attr]);
30888
+ }
30889
+ }
30883
30890
 
30884
30891
  /**
30885
30892
  Instances of this class represent a match state of a node type's
@@ -31334,27 +31341,21 @@ so this becomes the fallback color for the slot */ ''}
31334
31341
  function computeAttrs(attrs, value) {
31335
31342
  let built = Object.create(null);
31336
31343
  for (let name in attrs) {
31344
+ let attr = attrs[name];
31337
31345
  let given = value && value[name];
31338
31346
  if (given === undefined) {
31339
- let attr = attrs[name];
31340
31347
  if (attr.hasDefault)
31341
31348
  given = attr.default;
31342
31349
  else
31343
31350
  throw new RangeError("No value supplied for attribute " + name);
31344
31351
  }
31352
+ else if (attr.validate) {
31353
+ attr.validate(given);
31354
+ }
31345
31355
  built[name] = given;
31346
31356
  }
31347
31357
  return built;
31348
31358
  }
31349
- function checkAttrs(attrs, values, type, name) {
31350
- for (let attr in values)
31351
- if (!(attr in attrs))
31352
- throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
31353
- for (let attr in attrs) {
31354
- if (attrs[attr].validate)
31355
- attrs[attr].validate(values[attr]);
31356
- }
31357
- }
31358
31359
  function initAttrs(typeName, attrs) {
31359
31360
  let result = Object.create(null);
31360
31361
  if (attrs)
@@ -31526,11 +31527,9 @@ so this becomes the fallback color for the slot */ ''}
31526
31527
  throw new RangeError(`Invalid content for node ${this.name}: ${content.toString().slice(0, 50)}`);
31527
31528
  }
31528
31529
  /**
31529
- @internal
31530
+ @internal no longer useful, but called by old prosemirror-view versions
31530
31531
  */
31531
- checkAttrs(attrs) {
31532
- checkAttrs(this.attrs, attrs, "node", this.name);
31533
- }
31532
+ checkAttrs(attrs) { }
31534
31533
  /**
31535
31534
  Check whether the given mark type is allowed in this node.
31536
31535
  */
@@ -31677,12 +31676,6 @@ so this becomes the fallback color for the slot */ ''}
31677
31676
  return set[i];
31678
31677
  }
31679
31678
  /**
31680
- @internal
31681
- */
31682
- checkAttrs(attrs) {
31683
- checkAttrs(this.attrs, attrs, "mark", this.name);
31684
- }
31685
- /**
31686
31679
  Queries whether a given mark type is
31687
31680
  [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one.
31688
31681
  */
@@ -32873,9 +32866,12 @@ so this becomes the fallback color for the slot */ ''}
32873
32866
  if (simple)
32874
32867
  return result;
32875
32868
  let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start);
32876
- let del = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32877
- if (assoc < 0 ? pos != start : pos != end)
32878
- del |= DEL_SIDE;
32869
+ let del = 0;
32870
+ if (oldSize) {
32871
+ del |= pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32872
+ if (assoc < 0 ? pos != start : pos != end)
32873
+ del |= DEL_SIDE;
32874
+ }
32879
32875
  return new MapResult(result, del, recover);
32880
32876
  }
32881
32877
  diff += newSize - oldSize;
@@ -36813,15 +36809,15 @@ so this becomes the fallback color for the slot */ ''}
36813
36809
  return true;
36814
36810
  if (off == (dir < 0 ? 0 : nodeSize(node))) {
36815
36811
  let parent = node.parentNode;
36816
- if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36812
+ if (!parent || !isElt(parent) || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36817
36813
  node.contentEditable == "false")
36818
36814
  return false;
36819
36815
  off = domIndex(node) + (dir < 0 ? 0 : 1);
36820
36816
  node = parent;
36821
36817
  }
36822
- else if (node.nodeType == 1) {
36818
+ else if (isElt(node)) {
36823
36819
  let child = node.childNodes[off + (dir < 0 ? -1 : 0)];
36824
- if (child.nodeType == 1 && child.contentEditable == "false") {
36820
+ if (isElt(child) && child.contentEditable == "false") {
36825
36821
  if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection)
36826
36822
  off += dir;
36827
36823
  else
@@ -36840,11 +36836,16 @@ so this becomes the fallback color for the slot */ ''}
36840
36836
  function nodeSize(node) {
36841
36837
  return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
36842
36838
  }
36839
+ function isElt(node) { return node.nodeType == 1; }
36840
+ function isText(node) { return node.nodeType == 3; }
36841
+ function contains(parent, child) {
36842
+ return child ? parent.contains(isElt(child) ? child : child.parentNode) : false;
36843
+ }
36843
36844
  function textNodeBefore$1(node, offset) {
36844
36845
  for (;;) {
36845
- if (node.nodeType == 3 && offset)
36846
+ if (isText(node) && offset)
36846
36847
  return node;
36847
- if (node.nodeType == 1 && offset > 0) {
36848
+ if (isElt(node) && offset > 0) {
36848
36849
  if (node.contentEditable == "false")
36849
36850
  return null;
36850
36851
  node = node.childNodes[offset - 1];
@@ -36861,9 +36862,9 @@ so this becomes the fallback color for the slot */ ''}
36861
36862
  }
36862
36863
  function textNodeAfter$1(node, offset) {
36863
36864
  for (;;) {
36864
- if (node.nodeType == 3 && offset < node.nodeValue.length)
36865
+ if (isText(node) && offset < node.nodeValue.length)
36865
36866
  return node;
36866
- if (node.nodeType == 1 && offset < node.childNodes.length) {
36867
+ if (isElt(node) && offset < node.childNodes.length) {
36867
36868
  if (node.contentEditable == "false")
36868
36869
  return null;
36869
36870
  node = node.childNodes[offset];
@@ -36987,13 +36988,12 @@ so this becomes the fallback color for the slot */ ''}
36987
36988
  for (let parent = startDOM || view.dom;;) {
36988
36989
  if (!parent)
36989
36990
  break;
36990
- if (parent.nodeType != 1) {
36991
+ if (!isElt(parent)) {
36991
36992
  parent = parentNode(parent);
36992
36993
  continue;
36993
36994
  }
36994
- let elt = parent;
36995
- let atTop = elt == doc.body;
36996
- let bounding = atTop ? windowRect(doc) : clientRect(elt);
36995
+ let atTop = parent == doc.body;
36996
+ let bounding = atTop ? windowRect(doc) : clientRect(parent);
36997
36997
  let moveX = 0, moveY = 0;
36998
36998
  if (rect.top < bounding.top + getSide$1(scrollThreshold, "top"))
36999
36999
  moveY = -(bounding.top - rect.top + getSide$1(scrollMargin, "top"));
@@ -37010,12 +37010,12 @@ so this becomes the fallback color for the slot */ ''}
37010
37010
  doc.defaultView.scrollBy(moveX, moveY);
37011
37011
  }
37012
37012
  else {
37013
- let startX = elt.scrollLeft, startY = elt.scrollTop;
37013
+ let startX = parent.scrollLeft, startY = parent.scrollTop;
37014
37014
  if (moveY)
37015
- elt.scrollTop += moveY;
37015
+ parent.scrollTop += moveY;
37016
37016
  if (moveX)
37017
- elt.scrollLeft += moveX;
37018
- let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;
37017
+ parent.scrollLeft += moveX;
37018
+ let dX = parent.scrollLeft - startX, dY = parent.scrollTop - startY;
37019
37019
  rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
37020
37020
  }
37021
37021
  }
@@ -37090,14 +37090,15 @@ so this becomes the fallback color for the slot */ ''}
37090
37090
  }
37091
37091
  }
37092
37092
  function findOffsetInNode(node, coords) {
37093
- let closest, dxClosest = 2e8, coordsClosest, offset = 0;
37093
+ let closest;
37094
+ let dxClosest = 2e8, coordsClosest, offset = 0;
37094
37095
  let rowBot = coords.top, rowTop = coords.top;
37095
37096
  let firstBelow, coordsBelow;
37096
37097
  for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
37097
37098
  let rects;
37098
- if (child.nodeType == 1)
37099
+ if (isElt(child))
37099
37100
  rects = child.getClientRects();
37100
- else if (child.nodeType == 3)
37101
+ else if (isText(child))
37101
37102
  rects = textRange(child).getClientRects();
37102
37103
  else
37103
37104
  continue;
@@ -37111,11 +37112,11 @@ so this becomes the fallback color for the slot */ ''}
37111
37112
  if (dx < dxClosest) {
37112
37113
  closest = child;
37113
37114
  dxClosest = dx;
37114
- coordsClosest = dx && closest.nodeType == 3 ? {
37115
+ coordsClosest = dx && isText(closest) ? {
37115
37116
  left: rect.right < coords.left ? rect.right : rect.left,
37116
37117
  top: coords.top
37117
37118
  } : coords;
37118
- if (child.nodeType == 1 && dx)
37119
+ if (isElt(child) && dx)
37119
37120
  offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0);
37120
37121
  continue;
37121
37122
  }
@@ -37134,9 +37135,9 @@ so this becomes the fallback color for the slot */ ''}
37134
37135
  coordsClosest = coordsBelow;
37135
37136
  dxClosest = 0;
37136
37137
  }
37137
- if (closest && closest.nodeType == 3)
37138
+ if (closest && isText(closest))
37138
37139
  return findOffsetInText(closest, coordsClosest);
37139
- if (!closest || (dxClosest && closest.nodeType == 1))
37140
+ if (!closest || dxClosest)
37140
37141
  return { node, offset };
37141
37142
  return findOffsetInNode(closest, coordsClosest);
37142
37143
  }
@@ -37169,7 +37170,7 @@ so this becomes the fallback color for the slot */ ''}
37169
37170
  }
37170
37171
  function posFromElement(view, elt, coords) {
37171
37172
  let { node, offset } = findOffsetInNode(elt, coords), bias = -1;
37172
- if (node.nodeType == 1 && !node.firstChild) {
37173
+ if (isElt(node) && !node.firstChild) {
37173
37174
  let rect = node.getBoundingClientRect();
37174
37175
  bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
37175
37176
  }
@@ -37189,7 +37190,7 @@ so this becomes the fallback color for the slot */ ''}
37189
37190
  let desc = view.docView.nearestDesc(cur, true), rect;
37190
37191
  if (!desc)
37191
37192
  return null;
37192
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37193
+ if (isElt(desc.dom) && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37193
37194
  // Ignore elements with zero-size bounding rectangles
37194
37195
  ((rect = desc.dom.getBoundingClientRect()).width || rect.height)) {
37195
37196
  if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) {
@@ -37216,7 +37217,7 @@ so this becomes the fallback color for the slot */ ''}
37216
37217
  if (len && box.top < box.bottom) {
37217
37218
  for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {
37218
37219
  let child = element.childNodes[i];
37219
- if (child.nodeType == 1) {
37220
+ if (isElt(child)) {
37220
37221
  let rects = child.getClientRects();
37221
37222
  for (let j = 0; j < rects.length; j++) {
37222
37223
  let rect = rects[j];
@@ -37239,7 +37240,7 @@ so this becomes the fallback color for the slot */ ''}
37239
37240
  let elt = (view.root.elementFromPoint ? view.root : doc)
37240
37241
  .elementFromPoint(coords.left, coords.top);
37241
37242
  let pos;
37242
- if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {
37243
+ if (!elt || !view.dom.contains(elt)) {
37243
37244
  let box = view.dom.getBoundingClientRect();
37244
37245
  if (!inRect(coords, box))
37245
37246
  return null;
@@ -37255,7 +37256,7 @@ so this becomes the fallback color for the slot */ ''}
37255
37256
  }
37256
37257
  elt = targetKludge(elt, coords);
37257
37258
  if (node) {
37258
- if (gecko && node.nodeType == 1) {
37259
+ if (gecko && isElt(node)) {
37259
37260
  // Firefox will sometimes return offsets into <input> nodes, which
37260
37261
  // have no actual children, from caretPositionFromPoint (#953)
37261
37262
  offset = Math.min(offset, node.childNodes.length);
@@ -37270,18 +37271,18 @@ so this becomes the fallback color for the slot */ ''}
37270
37271
  }
37271
37272
  let prev;
37272
37273
  // When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.
37273
- if (webkit && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&
37274
+ if (webkit && offset && isElt(node) && isElt(prev = node.childNodes[offset - 1]) &&
37274
37275
  prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top)
37275
37276
  offset--;
37276
37277
  // Suspiciously specific kludge to work around caret*FromPoint
37277
37278
  // never returning a position at the end of the document
37278
- if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 &&
37279
+ if (node == view.dom && offset == node.childNodes.length - 1 && isElt(node.lastChild) &&
37279
37280
  coords.top > node.lastChild.getBoundingClientRect().bottom)
37280
37281
  pos = view.state.doc.content.size;
37281
37282
  // Ignore positions directly after a BR, since caret*FromPoint
37282
37283
  // 'round up' positions that would be more accurately placed
37283
37284
  // before the BR node.
37284
- else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR")
37285
+ else if (offset == 0 || !isElt(node) || node.childNodes[offset - 1].nodeName != "BR")
37285
37286
  pos = posFromCaret(view, node, offset, coords);
37286
37287
  }
37287
37288
  if (pos == null)
@@ -37307,7 +37308,7 @@ so this becomes the fallback color for the slot */ ''}
37307
37308
  function coordsAtPos(view, pos, side) {
37308
37309
  let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
37309
37310
  let supportEmptyRange = webkit || gecko;
37310
- if (node.nodeType == 3) {
37311
+ if (isText(node)) {
37311
37312
  // These browsers support querying empty text ranges. Prefer that in
37312
37313
  // bidi context or when at the end of a node.
37313
37314
  if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
@@ -37349,12 +37350,12 @@ so this becomes the fallback color for the slot */ ''}
37349
37350
  if (!$dom.parent.inlineContent) {
37350
37351
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37351
37352
  let before = node.childNodes[offset - 1];
37352
- if (before.nodeType == 1)
37353
+ if (isElt(before))
37353
37354
  return flattenH(before.getBoundingClientRect(), false);
37354
37355
  }
37355
37356
  if (atom == null && offset < nodeSize(node)) {
37356
37357
  let after = node.childNodes[offset];
37357
- if (after.nodeType == 1)
37358
+ if (isElt(after))
37358
37359
  return flattenH(after.getBoundingClientRect(), true);
37359
37360
  }
37360
37361
  return flattenH(node.getBoundingClientRect(), side >= 0);
@@ -37362,10 +37363,10 @@ so this becomes the fallback color for the slot */ ''}
37362
37363
  // Inline, not in text node (this is not Bidi-safe)
37363
37364
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37364
37365
  let before = node.childNodes[offset - 1];
37365
- let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37366
+ let target = isText(before) ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37366
37367
  // BR nodes tend to only return the rectangle before them.
37367
37368
  // Only use them if they are the last element in their parent
37368
- : before.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37369
+ : isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37369
37370
  if (target)
37370
37371
  return flattenV(singleRect(target, 1), false);
37371
37372
  }
@@ -37373,13 +37374,13 @@ so this becomes the fallback color for the slot */ ''}
37373
37374
  let after = node.childNodes[offset];
37374
37375
  while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)
37375
37376
  after = after.nextSibling;
37376
- let target = !after ? null : after.nodeType == 3 ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37377
- : after.nodeType == 1 ? after : null;
37377
+ let target = !after ? null : isText(after) ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37378
+ : isElt(after) ? after : null;
37378
37379
  if (target)
37379
37380
  return flattenV(singleRect(target, -1), true);
37380
37381
  }
37381
37382
  // All else failed, just try to get a rectangle for the target node
37382
- return flattenV(singleRect(node.nodeType == 3 ? textRange(node) : node, -side), side >= 0);
37383
+ return flattenV(singleRect(isText(node) ? textRange(node) : node, -side), side >= 0);
37383
37384
  }
37384
37385
  function flattenV(rect, left) {
37385
37386
  if (rect.width == 0)
@@ -37429,9 +37430,9 @@ so this becomes the fallback color for the slot */ ''}
37429
37430
  let coords = coordsAtPos(view, $pos.pos, 1);
37430
37431
  for (let child = dom.firstChild; child; child = child.nextSibling) {
37431
37432
  let boxes;
37432
- if (child.nodeType == 1)
37433
+ if (isElt(child))
37433
37434
  boxes = child.getClientRects();
37434
- else if (child.nodeType == 3)
37435
+ else if (isText(child))
37435
37436
  boxes = textRange(child, 0, child.nodeValue.length).getClientRects();
37436
37437
  else
37437
37438
  continue;
@@ -37471,8 +37472,7 @@ so this becomes the fallback color for the slot */ ''}
37471
37472
  sel.modify("move", dir, "character");
37472
37473
  let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
37473
37474
  let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();
37474
- let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
37475
- (oldNode == newNode && oldOff == newOff);
37475
+ let result = newNode && !contains(parentDOM, newNode) || (oldNode == newNode && oldOff == newOff);
37476
37476
  // Restore the previous selection
37477
37477
  try {
37478
37478
  sel.collapse(anchorNode, anchorOffset);
@@ -37580,7 +37580,7 @@ so this becomes the fallback color for the slot */ ''}
37580
37580
  localPosFromDOM(dom, offset, bias) {
37581
37581
  // If the DOM position is in the content, use the child desc after
37582
37582
  // it to figure out a position.
37583
- if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {
37583
+ if (this.contentDOM && contains(this.contentDOM, dom)) {
37584
37584
  if (bias < 0) {
37585
37585
  let domBefore, desc;
37586
37586
  if (dom == this.contentDOM) {
@@ -37618,7 +37618,7 @@ so this becomes the fallback color for the slot */ ''}
37618
37618
  atEnd = offset > domIndex(this.contentDOM);
37619
37619
  }
37620
37620
  else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {
37621
- atEnd = dom.compareDocumentPosition(this.contentDOM) & 2;
37621
+ atEnd = !!(dom.compareDocumentPosition(this.contentDOM) & 4);
37622
37622
  }
37623
37623
  else if (this.dom.firstChild) {
37624
37624
  if (offset == 0)
@@ -37648,7 +37648,7 @@ so this becomes the fallback color for the slot */ ''}
37648
37648
  if (desc && (!onlyNodes || desc.node)) {
37649
37649
  // If dom is outside of this desc's nodeDOM, don't count it.
37650
37650
  if (first && (nodeDOM = desc.nodeDOM) &&
37651
- !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))
37651
+ !(isElt(nodeDOM) ? contains(nodeDOM, dom) : nodeDOM == dom))
37652
37652
  first = false;
37653
37653
  else
37654
37654
  return desc;
@@ -37698,7 +37698,7 @@ so this becomes the fallback color for the slot */ ''}
37698
37698
  let i = 0, offset = 0;
37699
37699
  for (let curPos = 0; i < this.children.length; i++) {
37700
37700
  let child = this.children[i], end = curPos + child.size;
37701
- if (end > pos || child instanceof TrailingHackViewDesc) {
37701
+ if (end > pos) {
37702
37702
  offset = pos - curPos;
37703
37703
  break;
37704
37704
  }
@@ -37708,7 +37708,11 @@ so this becomes the fallback color for the slot */ ''}
37708
37708
  if (offset)
37709
37709
  return this.children[i].domFromPos(offset - this.children[i].border, side);
37710
37710
  // Go back if there were any zero-length widgets with side >= 0 before this point
37711
- for (let prev; i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }
37711
+ for (; i > 0; i--) {
37712
+ let prev = this.children[i - 1];
37713
+ if (prev.size || !(prev instanceof BufferHackViewDesc || prev instanceof WidgetViewDesc && prev.side >= 0))
37714
+ break;
37715
+ }
37712
37716
  // Scan towards the first useable node
37713
37717
  if (side <= 0) {
37714
37718
  let prev, enter = true;
@@ -37785,7 +37789,7 @@ so this becomes the fallback color for the slot */ ''}
37785
37789
  }
37786
37790
  domAfterPos(pos) {
37787
37791
  let { node, offset } = this.domFromPos(pos, 0);
37788
- if (node.nodeType != 1 || offset == node.childNodes.length)
37792
+ if (!isElt(node) || offset == node.childNodes.length)
37789
37793
  throw new RangeError("No node after pos " + pos);
37790
37794
  return node.childNodes[offset];
37791
37795
  }
@@ -37814,7 +37818,7 @@ so this becomes the fallback color for the slot */ ''}
37814
37818
  // reported position in such situations (#1092).
37815
37819
  if ((gecko || safari) && anchor == head) {
37816
37820
  let { node, offset } = anchorDOM;
37817
- if (node.nodeType == 3) {
37821
+ if (isText(node)) {
37818
37822
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
37819
37823
  // Issue #1128
37820
37824
  if (brKludge && offset == node.nodeValue.length) {
@@ -37837,7 +37841,7 @@ so this becomes the fallback color for the slot */ ''}
37837
37841
  }
37838
37842
  // Firefox can act strangely when the selection is in front of an
37839
37843
  // uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536
37840
- if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode.nodeType == 1) {
37844
+ if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && isElt(selRange.focusNode)) {
37841
37845
  let after = selRange.focusNode.childNodes[selRange.focusOffset];
37842
37846
  if (after && after.contentEditable == "false")
37843
37847
  force = true;
@@ -37936,14 +37940,12 @@ so this becomes the fallback color for the slot */ ''}
37936
37940
  return self.parent.posBeforeChild(self);
37937
37941
  });
37938
37942
  if (!widget.type.spec.raw) {
37939
- if (dom.nodeType != 1) {
37940
- let wrap = document.createElement("span");
37941
- wrap.appendChild(dom);
37942
- dom = wrap;
37943
- }
37944
- if (!dom.hasAttribute("contenteditable"))
37945
- dom.contentEditable = "false";
37946
- dom.classList.add("ProseMirror-widget");
37943
+ let elt = isElt(dom) ? dom : document.createElement("span");
37944
+ if (elt != dom)
37945
+ elt.appendChild(dom);
37946
+ if (!elt.hasAttribute("contenteditable"))
37947
+ elt.contentEditable = "false";
37948
+ elt.classList.add("ProseMirror-widget");
37947
37949
  }
37948
37950
  super(parent, [], dom, null);
37949
37951
  this.widget = widget;
@@ -38079,7 +38081,7 @@ so this becomes the fallback color for the slot */ ''}
38079
38081
  if (node.isText) {
38080
38082
  if (!dom)
38081
38083
  dom = document.createTextNode(node.text);
38082
- else if (dom.nodeType != 3)
38084
+ else if (!isText(dom))
38083
38085
  throw new RangeError("Text must be rendered as a DOM text node");
38084
38086
  }
38085
38087
  else if (!dom) {
@@ -38131,7 +38133,7 @@ so this becomes the fallback color for the slot */ ''}
38131
38133
  }
38132
38134
  if (!rule.contentElement) {
38133
38135
  let found = addedNodes &&
38134
- addedNodes.find(n => n.nodeType == 1 && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38136
+ addedNodes.find(n => isElt(n) && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38135
38137
  if (found)
38136
38138
  rule.contentElement = found;
38137
38139
  else
@@ -38156,6 +38158,7 @@ so this becomes the fallback color for the slot */ ''}
38156
38158
  let localComposition = composition && composition.pos > -1 ? composition : null;
38157
38159
  let compositionInChild = composition && composition.pos < 0;
38158
38160
  let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);
38161
+ let addBuffers = this.node.inlineContent, atBufferPos = addBuffers && this.node.isBlock;
38159
38162
  iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => {
38160
38163
  if (widget.spec.marks)
38161
38164
  updater.syncToMarks(widget.spec.marks, inline, view, i);
@@ -38167,6 +38170,8 @@ so this becomes the fallback color for the slot */ ''}
38167
38170
  }, (child, outerDeco, innerDeco, i) => {
38168
38171
  // Make sure the wrapping mark descs match the node's marks.
38169
38172
  updater.syncToMarks(child.marks, inline, view, i);
38173
+ if (atBufferPos && child.isAtom && !child.isText)
38174
+ updater.addHackNode("IMG", updater.top);
38170
38175
  // Try several strategies for drawing this node
38171
38176
  let compIndex;
38172
38177
  if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;
@@ -38180,6 +38185,8 @@ so this becomes the fallback color for the slot */ ''}
38180
38185
  updater.addNode(child, outerDeco, innerDeco, view, off);
38181
38186
  }
38182
38187
  off += child.nodeSize;
38188
+ if (addBuffers)
38189
+ atBufferPos = child.isAtom && !child.isText;
38183
38190
  });
38184
38191
  // Drop all remaining descs after the current position.
38185
38192
  updater.syncToMarks([], inline, view, 0);
@@ -38258,7 +38265,7 @@ so this becomes the fallback color for the slot */ ''}
38258
38265
  updateOuterDeco(outerDeco) {
38259
38266
  if (sameOuterDeco(outerDeco, this.outerDeco))
38260
38267
  return;
38261
- let needsWrap = this.nodeDOM.nodeType != 1;
38268
+ let needsWrap = !isElt(this.nodeDOM);
38262
38269
  let oldDOM = this.dom;
38263
38270
  this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));
38264
38271
  if (this.dom != oldDOM) {
@@ -38269,7 +38276,7 @@ so this becomes the fallback color for the slot */ ''}
38269
38276
  }
38270
38277
  // Mark this node as being the selected node.
38271
38278
  selectNode() {
38272
- if (this.nodeDOM.nodeType == 1) {
38279
+ if (isElt(this.nodeDOM)) {
38273
38280
  this.nodeDOM.classList.add("ProseMirror-selectednode");
38274
38281
  if (this.contentDOM || !this.node.type.spec.draggable)
38275
38282
  this.nodeDOM.draggable = true;
@@ -38277,7 +38284,7 @@ so this becomes the fallback color for the slot */ ''}
38277
38284
  }
38278
38285
  // Remove selected node marking from this node.
38279
38286
  deselectNode() {
38280
- if (this.nodeDOM.nodeType == 1) {
38287
+ if (isElt(this.nodeDOM)) {
38281
38288
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
38282
38289
  if (this.contentDOM || !this.node.type.spec.draggable)
38283
38290
  this.nodeDOM.removeAttribute("draggable");
@@ -38348,9 +38355,9 @@ so this becomes the fallback color for the slot */ ''}
38348
38355
  get domAtom() { return false; }
38349
38356
  isText(text) { return this.node.text == text; }
38350
38357
  }
38351
- // A dummy desc used to tag trailing BR or IMG nodes created to work
38358
+ // A dummy desc used to tag extra BR or IMG nodes created to work
38352
38359
  // around contentEditable terribleness.
38353
- class TrailingHackViewDesc extends ViewDesc {
38360
+ class BufferHackViewDesc extends ViewDesc {
38354
38361
  parseRule() { return { ignore: true }; }
38355
38362
  matchesHack(nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; }
38356
38363
  get domAtom() { return true; }
@@ -38523,7 +38530,7 @@ so this becomes the fallback color for the slot */ ''}
38523
38530
  }
38524
38531
  }
38525
38532
  function applyOuterDeco(dom, deco, node) {
38526
- return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom.nodeType != 1));
38533
+ return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, !isElt(dom)));
38527
38534
  }
38528
38535
  function sameOuterDeco(a, b) {
38529
38536
  if (a.length != b.length)
@@ -38786,7 +38793,7 @@ so this becomes the fallback color for the slot */ ''}
38786
38793
  }
38787
38794
  if (nodeName == "BR")
38788
38795
  dom.className = "ProseMirror-trailingBreak";
38789
- let hack = new TrailingHackViewDesc(this.top, [], dom, null);
38796
+ let hack = new BufferHackViewDesc(this.top, [], dom, null);
38790
38797
  if (parent != this.top)
38791
38798
  parent.children.push(hack);
38792
38799
  else
@@ -38795,7 +38802,7 @@ so this becomes the fallback color for the slot */ ''}
38795
38802
  }
38796
38803
  }
38797
38804
  isLocked(node) {
38798
- return this.lock && (node == this.lock || node.nodeType == 1 && node.contains(this.lock.parentNode));
38805
+ return this.lock && (node == this.lock || isElt(node) && node.contains(this.lock.parentNode));
38799
38806
  }
38800
38807
  }
38801
38808
  // Iterate from the end of the fragment and array of descs to find
@@ -38997,12 +39004,27 @@ so this becomes the fallback color for the slot */ ''}
38997
39004
  anchor = head;
38998
39005
  while (nearestDesc && !nearestDesc.node)
38999
39006
  nearestDesc = nearestDesc.parent;
39000
- let nearestDescNode = nearestDesc.node;
39001
- if (nearestDesc && nearestDescNode.isAtom && NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent
39002
- && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
39007
+ if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) &&
39008
+ nearestDesc.parent &&
39009
+ !(nearestDesc.node.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
39003
39010
  let pos = nearestDesc.posBefore;
39004
39011
  selection = new NodeSelection(head == pos ? $head : doc.resolve(pos));
39005
39012
  }
39013
+ else if (gecko && origin == "key" && head > view.state.selection.to &&
39014
+ isElt(domSel.focusNode) && domSel.focusOffset == domSel.focusNode.childNodes.length &&
39015
+ nearestDesc && nearestDesc.posAtStart > view.state.selection.to) {
39016
+ // Firefox will jump across scrollable wrapper nodes on keyboard
39017
+ // cursor motion (#1594). This tries to detect this situation
39018
+ // and work around it.
39019
+ for (let scan = domSel.focusNode;; scan = scan.parentNode) {
39020
+ if (getComputedStyle(scan).overflow != "visible") {
39021
+ selection = Selection$2.findFrom(doc.resolve(nearestDesc.posAtStart), 1);
39022
+ break;
39023
+ }
39024
+ if (scan == nearestDesc.dom || scan.nextSibling || !scan.parentNode || !isElt(scan.parentNode))
39025
+ break;
39026
+ }
39027
+ }
39006
39028
  }
39007
39029
  else {
39008
39030
  if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {
@@ -39188,8 +39210,7 @@ so this becomes the fallback color for the slot */ ''}
39188
39210
  // Firefox will raise 'permission denied' errors when accessing
39189
39211
  // properties of `sel.anchorNode` when it's in a generated CSS
39190
39212
  // element.
39191
- return view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&
39192
- (view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
39213
+ return contains(view.dom, sel.anchorNode) && (view.editable || contains(view.dom, sel.focusNode));
39193
39214
  }
39194
39215
  catch (_) {
39195
39216
  return false;
@@ -39240,15 +39261,14 @@ so this becomes the fallback color for the slot */ ''}
39240
39261
  if (NodeSelection.isSelectable(node)) {
39241
39262
  return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
39242
39263
  }
39243
- else if (webkit) {
39264
+ else {
39244
39265
  // Chrome and Safari will introduce extra pointless cursor
39245
- // positions around inline uneditable nodes, so we have to
39246
- // take over and move the cursor past them (#937)
39266
+ // positions around inline uneditable nodes (#937), and
39267
+ // Firefox will sometimes just plain refuse to move across
39268
+ // them (#1592), so in this situation we move the cursor
39269
+ // ourselves.
39247
39270
  return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
39248
39271
  }
39249
- else {
39250
- return false;
39251
- }
39252
39272
  }
39253
39273
  }
39254
39274
  else if (sel instanceof NodeSelection && sel.node.isInline) {
@@ -39261,12 +39281,10 @@ so this becomes the fallback color for the slot */ ''}
39261
39281
  return false;
39262
39282
  }
39263
39283
  }
39264
- function nodeLen(node) {
39265
- return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
39266
- }
39267
39284
  function isIgnorable(dom, dir) {
39268
39285
  let desc = dom.pmViewDesc;
39269
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
39286
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
39287
+ : isElt(dom) && dom.contentEditable == "false";
39270
39288
  }
39271
39289
  function skipIgnoredNodes(view, dir) {
39272
39290
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -39282,25 +39300,23 @@ so this becomes the fallback color for the slot */ ''}
39282
39300
  // Gecko will do odd things when the selection is directly in front
39283
39301
  // of a non-editable node, so in that case, move it into the next
39284
39302
  // node if possible. Issue prosemirror/prosemirror#832.
39285
- if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
39303
+ if (gecko && isElt(node) && offset < nodeSize(node) && isIgnorable(node.childNodes[offset], -1))
39286
39304
  force = true;
39287
39305
  for (;;) {
39288
39306
  if (offset > 0) {
39289
- if (node.nodeType != 1) {
39307
+ if (!isElt(node))
39290
39308
  break;
39309
+ let before = node.childNodes[offset - 1];
39310
+ if (isIgnorable(before, -1)) {
39311
+ moveNode = node;
39312
+ moveOffset = --offset;
39313
+ }
39314
+ else if (isText(before)) {
39315
+ node = before;
39316
+ offset = node.nodeValue.length;
39291
39317
  }
39292
39318
  else {
39293
- let before = node.childNodes[offset - 1];
39294
- if (isIgnorable(before, -1)) {
39295
- moveNode = node;
39296
- moveOffset = --offset;
39297
- }
39298
- else if (before.nodeType == 3) {
39299
- node = before;
39300
- offset = node.nodeValue.length;
39301
- }
39302
- else
39303
- break;
39319
+ break;
39304
39320
  }
39305
39321
  }
39306
39322
  else if (isBlockNode(node)) {
@@ -39321,7 +39337,7 @@ so this becomes the fallback color for the slot */ ''}
39321
39337
  }
39322
39338
  else {
39323
39339
  node = prev;
39324
- offset = nodeLen(node);
39340
+ offset = nodeSize(node);
39325
39341
  }
39326
39342
  }
39327
39343
  }
@@ -39337,19 +39353,20 @@ so this becomes the fallback color for the slot */ ''}
39337
39353
  let node = sel.focusNode, offset = sel.focusOffset;
39338
39354
  if (!node)
39339
39355
  return;
39340
- let len = nodeLen(node);
39356
+ let len = nodeSize(node);
39341
39357
  let moveNode, moveOffset;
39342
39358
  for (;;) {
39343
39359
  if (offset < len) {
39344
- if (node.nodeType != 1)
39360
+ if (!isElt(node))
39345
39361
  break;
39346
39362
  let after = node.childNodes[offset];
39347
39363
  if (isIgnorable(after, 1)) {
39348
39364
  moveNode = node;
39349
39365
  moveOffset = ++offset;
39350
39366
  }
39351
- else
39367
+ else {
39352
39368
  break;
39369
+ }
39353
39370
  }
39354
39371
  else if (isBlockNode(node)) {
39355
39372
  break;
@@ -39370,7 +39387,7 @@ so this becomes the fallback color for the slot */ ''}
39370
39387
  else {
39371
39388
  node = next;
39372
39389
  offset = 0;
39373
- len = nodeLen(node);
39390
+ len = nodeSize(node);
39374
39391
  }
39375
39392
  }
39376
39393
  }
@@ -39388,9 +39405,9 @@ so this becomes the fallback color for the slot */ ''}
39388
39405
  }
39389
39406
  while (node && offset < node.childNodes.length) {
39390
39407
  let next = node.childNodes[offset];
39391
- if (next.nodeType == 3)
39408
+ if (isText(next))
39392
39409
  return next;
39393
- if (next.nodeType == 1 && next.contentEditable == "false")
39410
+ if (isElt(next) && next.contentEditable == "false")
39394
39411
  break;
39395
39412
  node = next;
39396
39413
  offset = 0;
@@ -39403,16 +39420,16 @@ so this becomes the fallback color for the slot */ ''}
39403
39420
  }
39404
39421
  while (node && offset) {
39405
39422
  let next = node.childNodes[offset - 1];
39406
- if (next.nodeType == 3)
39423
+ if (isText(next))
39407
39424
  return next;
39408
- if (next.nodeType == 1 && next.contentEditable == "false")
39425
+ if (isElt(next) && next.contentEditable == "false")
39409
39426
  break;
39410
39427
  node = next;
39411
39428
  offset = node.childNodes.length;
39412
39429
  }
39413
39430
  }
39414
39431
  function setSelFocus(view, node, offset) {
39415
- if (node.nodeType != 3) {
39432
+ if (!isText(node)) {
39416
39433
  let before, after;
39417
39434
  if (after = textNodeAfter(node, offset)) {
39418
39435
  node = after;
@@ -39522,8 +39539,8 @@ so this becomes the fallback color for the slot */ ''}
39522
39539
  if (!safari || view.state.selection.$head.parentOffset > 0)
39523
39540
  return false;
39524
39541
  let { focusNode, focusOffset } = view.domSelectionRange();
39525
- if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
39526
- focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
39542
+ if (focusNode && isElt(focusNode) && focusOffset == 0 &&
39543
+ focusNode.firstChild && isElt(focusNode.firstChild) && focusNode.firstChild.contentEditable == "false") {
39527
39544
  let child = focusNode.firstChild;
39528
39545
  switchEditable(view, child, "true");
39529
39546
  setTimeout(() => switchEditable(view, child, "false"), 20);
@@ -39594,7 +39611,7 @@ so this becomes the fallback color for the slot */ ''}
39594
39611
  let doc = detachedDoc(), wrap = doc.createElement("div");
39595
39612
  wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
39596
39613
  let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
39597
- while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39614
+ while (firstChild && isElt(firstChild) && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39598
39615
  for (let i = needsWrap.length - 1; i >= 0; i--) {
39599
39616
  let wrapper = doc.createElement(needsWrap[i]);
39600
39617
  while (wrap.firstChild)
@@ -39604,7 +39621,7 @@ so this becomes the fallback color for the slot */ ''}
39604
39621
  }
39605
39622
  firstChild = wrap.firstChild;
39606
39623
  }
39607
- if (firstChild && firstChild.nodeType == 1)
39624
+ if (firstChild && isElt(firstChild))
39608
39625
  firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
39609
39626
  let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
39610
39627
  slice.content.textBetween(0, slice.content.size, "\n\n");
@@ -39650,7 +39667,7 @@ so this becomes the fallback color for the slot */ ''}
39650
39667
  if (sliceData && sliceData[3])
39651
39668
  for (let i = +sliceData[3]; i > 0; i--) {
39652
39669
  let child = dom.firstChild;
39653
- while (child && child.nodeType != 1)
39670
+ while (child && !isElt(child))
39654
39671
  child = child.nextSibling;
39655
39672
  if (!child)
39656
39673
  break;
@@ -39855,12 +39872,11 @@ so this becomes the fallback color for the slot */ ''}
39855
39872
  if (!type || type.hasRequiredAttrs())
39856
39873
  break;
39857
39874
  try {
39858
- type.checkAttrs(array[i + 1]);
39875
+ content = Fragment.from(type.create(array[i + 1], content));
39859
39876
  }
39860
39877
  catch (e) {
39861
39878
  break;
39862
39879
  }
39863
- content = Fragment.from(type.create(array[i + 1], content));
39864
39880
  openStart++;
39865
39881
  openEnd++;
39866
39882
  }
@@ -40192,7 +40208,7 @@ so this becomes the fallback color for the slot */ ''}
40192
40208
  }
40193
40209
  const target = flushed ? null : event.target;
40194
40210
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
40195
- this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
40211
+ this.target = targetDesc && isElt(targetDesc.nodeDOM) ? targetDesc.nodeDOM : null;
40196
40212
  let { selection } = view.state;
40197
40213
  if (event.button == 0 &&
40198
40214
  (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
@@ -40340,7 +40356,7 @@ so this becomes the fallback color for the slot */ ''}
40340
40356
  if (!view.composing) {
40341
40357
  view.domObserver.flush();
40342
40358
  let { state } = view, $pos = state.selection.$to;
40343
- if (state.selection instanceof TextSelection &&
40359
+ if (state.selection instanceof TextSelection && state.selection.empty &&
40344
40360
  (state.storedMarks ||
40345
40361
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
40346
40362
  chrome && windows$1 && selectionBeforeUneditable(view))) { // Issue #1500
@@ -40356,11 +40372,11 @@ so this becomes the fallback color for the slot */ ''}
40356
40372
  // inside if necessary.
40357
40373
  if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
40358
40374
  let sel = view.domSelectionRange();
40359
- for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
40375
+ for (let node = sel.focusNode, offset = sel.focusOffset; node && isElt(node) && offset != 0;) {
40360
40376
  let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
40361
40377
  if (!before)
40362
40378
  break;
40363
- if (before.nodeType == 3) {
40379
+ if (isText(before)) {
40364
40380
  let sel = view.domSelection();
40365
40381
  if (sel)
40366
40382
  sel.collapse(before, before.nodeValue.length);
@@ -40379,10 +40395,10 @@ so this becomes the fallback color for the slot */ ''}
40379
40395
  };
40380
40396
  function selectionBeforeUneditable(view) {
40381
40397
  let { focusNode, focusOffset } = view.domSelectionRange();
40382
- if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length)
40398
+ if (!focusNode || !isElt(focusNode) || focusOffset >= focusNode.childNodes.length)
40383
40399
  return false;
40384
40400
  let next = focusNode.childNodes[focusOffset];
40385
- return next.nodeType == 1 && next.contentEditable == "false";
40401
+ return isElt(next) && next.contentEditable == "false";
40386
40402
  }
40387
40403
  editHandlers.compositionend = (view, event) => {
40388
40404
  if (view.composing) {
@@ -40584,7 +40600,7 @@ so this becomes the fallback color for the slot */ ''}
40584
40600
  else if (mouseDown && mouseDown.mightDrag) {
40585
40601
  node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
40586
40602
  }
40587
- else if (event.target && event.target.nodeType == 1) {
40603
+ else if (event.target && isElt(event.target)) {
40588
40604
  let desc = view.docView.nearestDesc(event.target, true);
40589
40605
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
40590
40606
  node = NodeSelection.create(view.state.doc, desc.posBefore);
@@ -41555,7 +41571,7 @@ so this becomes the fallback color for the slot */ ''}
41555
41571
  let desc = container && this.view.docView.nearestDesc(container);
41556
41572
  if (desc && desc.ignoreMutation({
41557
41573
  type: "selection",
41558
- target: container.nodeType == 3 ? container.parentNode : container
41574
+ target: isText(container) ? container.parentNode : container
41559
41575
  })) {
41560
41576
  this.setCurSelection();
41561
41577
  return true;
@@ -41597,7 +41613,7 @@ so this becomes the fallback color for the slot */ ''}
41597
41613
  for (let node of added)
41598
41614
  if (node.nodeName == "BR" && node.parentNode) {
41599
41615
  let after = node.nextSibling;
41600
- while (after && after.nodeType == 1) {
41616
+ while (after && isElt(after)) {
41601
41617
  if (after.contentEditable == "false") {
41602
41618
  node.parentNode.removeChild(node);
41603
41619
  break;
@@ -41670,7 +41686,7 @@ so this becomes the fallback color for the slot */ ''}
41670
41686
  for (let i = 0; i < mut.addedNodes.length; i++) {
41671
41687
  let node = mut.addedNodes[i];
41672
41688
  added.push(node);
41673
- if (node.nodeType == 3)
41689
+ if (isText(node))
41674
41690
  this.lastChangedTextNode = node;
41675
41691
  }
41676
41692
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
@@ -41785,8 +41801,7 @@ so this becomes the fallback color for the slot */ ''}
41785
41801
  let parent = nextCell;
41786
41802
  for (;;) {
41787
41803
  let first = parent.firstChild;
41788
- if (!first || first.nodeType != 1 || first.contentEditable == "false" ||
41789
- /^(BR|IMG)$/.test(first.nodeName))
41804
+ if (!first || !isElt(first) || first.contentEditable == "false" || /^(BR|IMG)$/.test(first.nodeName))
41790
41805
  break;
41791
41806
  parent = first;
41792
41807
  }
@@ -41811,7 +41826,7 @@ so this becomes the fallback color for the slot */ ''}
41811
41826
  let domSel = view.domSelectionRange();
41812
41827
  let find;
41813
41828
  let anchor = domSel.anchorNode;
41814
- if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
41829
+ if (anchor && contains(view.dom, anchor)) {
41815
41830
  find = [{ node: anchor, offset: domSel.anchorOffset }];
41816
41831
  if (!selectionCollapsed(domSel))
41817
41832
  find.push({ node: domSel.focusNode, offset: domSel.focusOffset });
@@ -41919,7 +41934,7 @@ so this becomes the fallback color for the slot */ ''}
41919
41934
  if (change)
41920
41935
  view.input.domChangeCount++;
41921
41936
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&
41922
- addedNodes.some(n => n.nodeType == 1 && !isInline.test(n.nodeName)) &&
41937
+ addedNodes.some(n => isElt(n) && !isInline.test(n.nodeName)) &&
41923
41938
  (!change || change.endA >= change.endB) &&
41924
41939
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41925
41940
  view.input.lastIOSEnter = 0;
@@ -41977,9 +41992,7 @@ so this becomes the fallback color for the slot */ ''}
41977
41992
  // as being an iOS enter press), just dispatch an Enter key instead.
41978
41993
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
41979
41994
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
41980
- (!inlineChange && $from.pos < parse.doc.content.size &&
41981
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
41982
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
41995
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
41983
41996
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41984
41997
  view.input.lastIOSEnter = 0;
41985
41998
  return;
@@ -42130,6 +42143,16 @@ so this becomes the fallback color for the slot */ ''}
42130
42143
  // The fragments after the join point must match
42131
42144
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
42132
42145
  }
42146
+ function looksLikeEnter(content, from, to) {
42147
+ let newTextlines = 0, newLeaves = 0;
42148
+ content.nodesBetween(from, to, (node, pos) => {
42149
+ if (node.isTextblock && pos >= from && pos < to)
42150
+ newTextlines++;
42151
+ else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
42152
+ newLeaves++;
42153
+ });
42154
+ return newLeaves == 0 && newTextlines == 1;
42155
+ }
42133
42156
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
42134
42157
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
42135
42158
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
@@ -42390,11 +42413,11 @@ so this becomes the fallback color for the slot */ ''}
42390
42413
  */
42391
42414
  scrollToSelection() {
42392
42415
  let startDOM = this.domSelectionRange().focusNode;
42393
- if (!startDOM || !this.dom.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;
42416
+ if (!startDOM || !contains(this.dom, startDOM)) ;
42394
42417
  else if (this.someProp("handleScrollToSelection", f => f(this))) ;
42395
42418
  else if (this.state.selection instanceof NodeSelection) {
42396
42419
  let target = this.docView.domAfterPos(this.state.selection.from);
42397
- if (target.nodeType == 1)
42420
+ if (isElt(target))
42398
42421
  scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);
42399
42422
  }
42400
42423
  else {
@@ -42659,7 +42682,7 @@ so this becomes the fallback color for the slot */ ''}
42659
42682
  @internal
42660
42683
  */
42661
42684
  domSelectionRange() {
42662
- let sel = this.domSelection();
42685
+ let sel = this.dom.isConnected !== false && this.domSelection();
42663
42686
  if (!sel)
42664
42687
  return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 };
42665
42688
  return safari && this.root.nodeType === 11 &&
@@ -42990,399 +43013,1030 @@ so this becomes the fallback color for the slot */ ''}
42990
43013
  };
42991
43014
  }
42992
43015
 
42993
- //#region src/helpers/createChainableState.ts
42994
- /**
42995
- * Takes a Transaction & Editor State and turns it into a chainable state object
42996
- * @param config The transaction and state to create the chainable state from
42997
- * @returns A chainable Editor state object
42998
- */
42999
- function createChainableState(config) {
43000
- const { state, transaction } = config;
43001
- let { selection } = transaction;
43002
- let { doc } = transaction;
43003
- let { storedMarks } = transaction;
43004
- return {
43005
- ...state,
43006
- apply: state.apply.bind(state),
43007
- applyTransaction: state.applyTransaction.bind(state),
43008
- plugins: state.plugins,
43009
- schema: state.schema,
43010
- reconfigure: state.reconfigure.bind(state),
43011
- toJSON: state.toJSON.bind(state),
43012
- get storedMarks() {
43013
- return storedMarks;
43014
- },
43015
- get selection() {
43016
- return selection;
43017
- },
43018
- get doc() {
43019
- return doc;
43020
- },
43021
- get tr() {
43022
- selection = transaction.selection;
43023
- doc = transaction.doc;
43024
- storedMarks = transaction.storedMarks;
43025
- return transaction;
43026
- }
43027
- };
43028
- }
43029
- //#endregion
43030
- //#region src/CommandManager.ts
43031
- var CommandManager = class CommandManager {
43032
- constructor(props) {
43033
- this.editor = props.editor;
43034
- this.rawCommands = this.editor.extensionManager.commands;
43035
- this.customState = props.state;
43036
- }
43037
- get hasCustomState() {
43038
- return !!this.customState;
43039
- }
43040
- get state() {
43041
- return this.customState || this.editor.state;
43042
- }
43043
- get commands() {
43044
- const { rawCommands, editor, state } = this;
43045
- const { view } = editor;
43046
- const { tr } = state;
43047
- const props = this.buildProps(tr);
43048
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43049
- const method = (...args) => {
43050
- const callback = command(...args)(props);
43051
- if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43052
- return callback;
43053
- };
43054
- return [name, method];
43055
- }));
43056
- }
43057
- get chain() {
43058
- return () => this.createChain();
43059
- }
43060
- get can() {
43061
- return () => this.createCan();
43062
- }
43063
- createChain(startTr, shouldDispatch = true) {
43064
- const { rawCommands, editor, state } = this;
43065
- const { view } = editor;
43066
- const callbacks = [];
43067
- const hasStartTransaction = !!startTr;
43068
- const tr = startTr || state.tr;
43069
- const run = () => {
43070
- if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43071
- return callbacks.every((callback) => callback === true);
43072
- };
43073
- const chain = {
43074
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43075
- const chainedCommand = (...args) => {
43076
- const props = this.buildProps(tr, shouldDispatch);
43077
- const callback = command(...args)(props);
43078
- callbacks.push(callback);
43079
- return chain;
43080
- };
43081
- return [name, chainedCommand];
43082
- })),
43083
- run
43084
- };
43085
- return chain;
43086
- }
43087
- /**
43088
- * Creates a chain that safely returns `false` when run.
43089
- * @returns A non-dispatching command chain.
43090
- * @example
43091
- * const chain = CommandManager.createFakeChain()
43092
- * chain.focus().run() // false
43093
- */
43094
- static createFakeChain() {
43095
- const chain = new Proxy({}, { get: (_target, property) => {
43096
- if (property === "then") return;
43097
- if (property === "run") return () => false;
43098
- return () => chain;
43099
- } });
43100
- return chain;
43101
- }
43102
- createCan(startTr) {
43103
- const { rawCommands, state } = this;
43104
- const dispatch = false;
43105
- const tr = startTr || state.tr;
43106
- const props = this.buildProps(tr, dispatch);
43107
- return {
43108
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43109
- return [name, (...args) => command(...args)({
43110
- ...props,
43111
- dispatch: void 0
43112
- })];
43113
- })),
43114
- chain: () => this.createChain(tr, dispatch)
43115
- };
43116
- }
43117
- /**
43118
- * Creates capability checks that safely return `false`.
43119
- * @returns A non-dispatching capability checker.
43120
- * @example
43121
- * const can = CommandManager.createFallbackCan()
43122
- * can.focus() // false
43123
- */
43124
- static createFallbackCan() {
43125
- const chain = CommandManager.createFakeChain();
43126
- return new Proxy({ chain: () => chain }, { get: (target, property) => {
43127
- if (property === "then") return;
43128
- if (property === "chain") return target.chain;
43129
- return () => false;
43130
- } });
43131
- }
43132
- buildProps(tr, shouldDispatch = true) {
43133
- const { rawCommands, editor, state } = this;
43134
- const { view } = editor;
43135
- const props = {
43136
- tr,
43137
- editor,
43138
- view,
43139
- state: createChainableState({
43140
- state,
43141
- transaction: tr
43142
- }),
43143
- dispatch: shouldDispatch ? () => void 0 : void 0,
43144
- chain: () => this.createChain(tr, shouldDispatch),
43145
- can: () => this.createCan(tr),
43146
- get commands() {
43147
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43148
- return [name, (...args) => command(...args)(props)];
43149
- }));
43150
- }
43151
- };
43152
- return props;
43153
- }
43154
- };
43155
- //#endregion
43156
- //#region src/commands/blur.ts
43157
- const blur = () => ({ editor, view }) => {
43158
- requestAnimationFrame(() => {
43159
- if (!editor.isDestroyed) {
43160
- var _window;
43161
- view.dom.blur();
43162
- (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43163
- }
43164
- });
43165
- return true;
43166
- };
43167
- //#endregion
43168
- //#region src/commands/clearContent.ts
43169
- const clearContent = (emitUpdate = true) => ({ commands }) => {
43170
- return commands.setContent("", { emitUpdate });
43171
- };
43172
- //#endregion
43173
- //#region src/commands/clearNodes.ts
43174
- const clearNodes = () => ({ state, tr, dispatch }) => {
43175
- const { selection } = tr;
43176
- const { ranges } = selection;
43177
- if (!dispatch) return true;
43178
- ranges.forEach(({ $from, $to }) => {
43179
- state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43180
- if (node.type.isText) return;
43181
- const { doc, mapping } = tr;
43182
- const $mappedFrom = doc.resolve(mapping.map(pos));
43183
- const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43184
- const nodeRange = $mappedFrom.blockRange($mappedTo);
43185
- if (!nodeRange) return;
43186
- const targetLiftDepth = liftTarget(nodeRange);
43187
- if (node.type.isTextblock) {
43188
- const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43189
- tr.setNodeMarkup(nodeRange.start, defaultType);
43190
- }
43191
- if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43192
- });
43193
- });
43194
- return true;
43195
- };
43196
- //#endregion
43197
- //#region src/commands/command.ts
43198
- const command = (fn) => (props) => {
43199
- return fn(props);
43200
- };
43201
- //#endregion
43202
- //#region src/commands/createParagraphNear.ts
43203
- const createParagraphNear$1 = () => ({ state, dispatch }) => {
43204
- return createParagraphNear(state, dispatch);
43205
- };
43206
- //#endregion
43207
- //#region src/commands/cut.ts
43208
- const cut = (originRange, targetPos) => ({ editor, tr }) => {
43209
- const { state } = editor;
43210
- const contentSlice = state.doc.slice(originRange.from, originRange.to);
43211
- tr.deleteRange(originRange.from, originRange.to);
43212
- const newPos = tr.mapping.map(targetPos);
43213
- tr.insert(newPos, contentSlice.content);
43214
- tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43215
- return true;
43216
- };
43217
- //#endregion
43218
- //#region src/commands/deleteCurrentNode.ts
43219
- const deleteCurrentNode = () => ({ tr, dispatch }) => {
43220
- const { selection } = tr;
43221
- const currentNode = selection.$anchor.node();
43222
- if (currentNode.content.size > 0) return false;
43223
- const $pos = tr.selection.$anchor;
43224
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43225
- if (dispatch) {
43226
- const from = $pos.before(depth);
43227
- const to = $pos.after(depth);
43228
- tr.delete(from, to).scrollIntoView();
43229
- }
43230
- return true;
43231
- }
43232
- return false;
43233
- };
43234
- //#endregion
43235
- //#region src/helpers/getNodeType.ts
43236
- function getNodeType(nameOrType, schema) {
43237
- if (typeof nameOrType === "string") {
43238
- if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43239
- return schema.nodes[nameOrType];
43240
- }
43241
- return nameOrType;
43242
- }
43243
- //#endregion
43244
- //#region src/commands/deleteNode.ts
43245
- const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43246
- const type = getNodeType(typeOrName, state.schema);
43247
- const $pos = tr.selection.$anchor;
43248
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43249
- if (dispatch) {
43250
- const from = $pos.before(depth);
43251
- const to = $pos.after(depth);
43252
- tr.delete(from, to).scrollIntoView();
43253
- }
43254
- return true;
43255
- }
43256
- return false;
43016
+ var GOOD_LEAF_SIZE = 200;
43017
+
43018
+ // :: class<T> A rope sequence is a persistent sequence data structure
43019
+ // that supports appending, prepending, and slicing without doing a
43020
+ // full copy. It is represented as a mostly-balanced tree.
43021
+ var RopeSequence = function RopeSequence () {};
43022
+
43023
+ RopeSequence.prototype.append = function append (other) {
43024
+ if (!other.length) { return this }
43025
+ other = RopeSequence.from(other);
43026
+
43027
+ return (!this.length && other) ||
43028
+ (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
43029
+ (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
43030
+ this.appendInner(other)
43257
43031
  };
43258
- //#endregion
43259
- //#region src/commands/deleteRange.ts
43260
- const deleteRange = (range) => ({ tr, dispatch }) => {
43261
- const { from, to } = range;
43262
- if (dispatch) tr.delete(from, to);
43263
- return true;
43032
+
43033
+ // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
43034
+ // Prepend an array or other rope to this one, returning a new rope.
43035
+ RopeSequence.prototype.prepend = function prepend (other) {
43036
+ if (!other.length) { return this }
43037
+ return RopeSequence.from(other).append(this)
43264
43038
  };
43265
- //#endregion
43266
- //#region src/commands/deleteSelection.ts
43267
- /**
43268
- * Check if a node has text content based on its content specification.
43269
- * Returns true if the node's content spec matches text* or text+ patterns.
43270
- */
43271
- const hasTextContent = (nodeSpec) => {
43272
- if (!nodeSpec.content) return false;
43273
- return /^text(\*|\+)/.test(nodeSpec.content);
43039
+
43040
+ RopeSequence.prototype.appendInner = function appendInner (other) {
43041
+ return new Append(this, other)
43274
43042
  };
43275
- /**
43276
- * Expand selection position for a specific side (left or right) to handle inline text nodes.
43277
- * This function checks if the position is within an inline node with text content and
43278
- * expands it to include the entire node boundaries for proper deletion.
43279
- * @param $pos - The resolved position to expand
43280
- * @param schema - The ProseMirror schema
43281
- * @param side - Which side to expand ('left' or 'right')
43282
- * @returns The expanded position for deletion
43283
- */
43284
- const expandSelectionForSide = ($pos, schema, side) => {
43285
- if (!$pos.parent.isInline) return $pos.pos;
43286
- if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43287
- const parentContent = schema.nodes[$pos.parent.type.name].spec;
43288
- if (!hasTextContent(parentContent)) return $pos.pos;
43289
- return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43043
+
43044
+ // :: (?number, ?number) → RopeSequence<T>
43045
+ // Create a rope repesenting a sub-sequence of this rope.
43046
+ RopeSequence.prototype.slice = function slice (from, to) {
43047
+ if ( from === void 0 ) from = 0;
43048
+ if ( to === void 0 ) to = this.length;
43049
+
43050
+ if (from >= to) { return RopeSequence.empty }
43051
+ return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
43290
43052
  };
43291
- /**
43292
- * Expand selection range to properly handle deletion of inline text nodes.
43293
- * Inline text nodes don't collapse correctly when text inside is deleted,
43294
- * so we need to expand the selection to include the entire node.
43295
- * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43296
- */
43297
- const expandSelectionForInlineText = ($from, $to, schema) => {
43298
- return {
43299
- from: expandSelectionForSide($from, schema, "left"),
43300
- to: expandSelectionForSide($to, schema, "right")
43301
- };
43053
+
43054
+ // :: (number) → T
43055
+ // Retrieve the element at the given position from this rope.
43056
+ RopeSequence.prototype.get = function get (i) {
43057
+ if (i < 0 || i >= this.length) { return undefined }
43058
+ return this.getInner(i)
43302
43059
  };
43303
- const deleteSelection = () => ({ state, dispatch }) => {
43304
- if (state.selection.empty) return false;
43305
- if (dispatch) {
43306
- const tr = state.tr;
43307
- const { ranges } = state.selection;
43308
- const mapFrom = tr.steps.length;
43309
- ranges.forEach((range) => {
43310
- const mapping = tr.mapping.slice(mapFrom);
43311
- const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43312
- const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43313
- const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43314
- tr.deleteRange(from, to);
43315
- });
43316
- if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43317
- tr.scrollIntoView();
43318
- dispatch(tr);
43319
- }
43320
- return true;
43060
+
43061
+ // :: ((element: T, index: number) → ?bool, ?number, ?number)
43062
+ // Call the given function for each element between the given
43063
+ // indices. This tends to be more efficient than looping over the
43064
+ // indices and calling `get`, because it doesn't have to descend the
43065
+ // tree for every element.
43066
+ RopeSequence.prototype.forEach = function forEach (f, from, to) {
43067
+ if ( from === void 0 ) from = 0;
43068
+ if ( to === void 0 ) to = this.length;
43069
+
43070
+ if (from <= to)
43071
+ { this.forEachInner(f, from, to, 0); }
43072
+ else
43073
+ { this.forEachInvertedInner(f, from, to, 0); }
43321
43074
  };
43322
- //#endregion
43323
- //#region src/commands/enter.ts
43324
- const enter = () => ({ commands }) => {
43325
- return commands.keyboardShortcut("Enter");
43075
+
43076
+ // :: ((element: T, index: number) → U, ?number, ?number) → [U]
43077
+ // Map the given functions over the elements of the rope, producing
43078
+ // a flat array.
43079
+ RopeSequence.prototype.map = function map (f, from, to) {
43080
+ if ( from === void 0 ) from = 0;
43081
+ if ( to === void 0 ) to = this.length;
43082
+
43083
+ var result = [];
43084
+ this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
43085
+ return result
43326
43086
  };
43327
- //#endregion
43328
- //#region src/commands/exitCode.ts
43329
- const exitCode$1 = () => ({ state, dispatch }) => {
43330
- return exitCode(state, dispatch);
43087
+
43088
+ // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
43089
+ // Create a rope representing the given array, or return the rope
43090
+ // itself if a rope was given.
43091
+ RopeSequence.from = function from (values) {
43092
+ if (values instanceof RopeSequence) { return values }
43093
+ return values && values.length ? new Leaf(values) : RopeSequence.empty
43331
43094
  };
43332
- //#endregion
43333
- //#region src/utilities/isRegExp.ts
43334
- function isRegExp$1(value) {
43335
- return Object.prototype.toString.call(value) === "[object RegExp]";
43336
- }
43337
- //#endregion
43338
- //#region src/utilities/objectIncludes.ts
43339
- /**
43340
- * Check if object1 includes object2
43341
- * @param object1 Object
43342
- * @param object2 Object
43343
- */
43344
- function objectIncludes(object1, object2, options = { strict: true }) {
43345
- const keys = Object.keys(object2);
43346
- if (!keys.length) return true;
43347
- return keys.every((key) => {
43348
- if (options.strict) return object2[key] === object1[key];
43349
- if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
43350
- return object2[key] === object1[key];
43351
- });
43352
- }
43353
- //#endregion
43354
- //#region src/helpers/getMarkRange.ts
43355
- function findMarkInSet(marks, type, attributes = {}) {
43356
- return marks.find((item) => {
43357
- return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
43358
- });
43359
- }
43360
- function isMarkInSet(marks, type, attributes = {}) {
43361
- return !!findMarkInSet(marks, type, attributes);
43362
- }
43363
- /**
43364
- * Get the range of a mark at a resolved position.
43365
- */
43366
- function getMarkRange($pos, type, attributes) {
43367
- if (!$pos || !type) return;
43368
- let start = $pos.parent.childAfter($pos.parentOffset);
43369
- if (!start.node || !start.node.marks.some((mark) => mark.type === type)) start = $pos.parent.childBefore($pos.parentOffset);
43370
- if (!start.node || !start.node.marks.some((mark) => mark.type === type)) return;
43371
- if (!attributes) {
43372
- const firstMark = start.node.marks.find((mark) => mark.type === type);
43373
- if (firstMark) attributes = firstMark.attrs;
43374
- }
43375
- if (!findMarkInSet([...start.node.marks], type, attributes)) return;
43376
- let startIndex = start.index;
43377
- let startPos = $pos.start() + start.offset;
43378
- let endIndex = startIndex + 1;
43379
- let endPos = startPos + start.node.nodeSize;
43380
- while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
43381
- startIndex -= 1;
43382
- startPos -= $pos.parent.child(startIndex).nodeSize;
43383
- }
43384
- while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
43385
- endPos += $pos.parent.child(endIndex).nodeSize;
43095
+
43096
+ var Leaf = /*@__PURE__*/(function (RopeSequence) {
43097
+ function Leaf(values) {
43098
+ RopeSequence.call(this);
43099
+ this.values = values;
43100
+ }
43101
+
43102
+ if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
43103
+ Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43104
+ Leaf.prototype.constructor = Leaf;
43105
+
43106
+ var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
43107
+
43108
+ Leaf.prototype.flatten = function flatten () {
43109
+ return this.values
43110
+ };
43111
+
43112
+ Leaf.prototype.sliceInner = function sliceInner (from, to) {
43113
+ if (from == 0 && to == this.length) { return this }
43114
+ return new Leaf(this.values.slice(from, to))
43115
+ };
43116
+
43117
+ Leaf.prototype.getInner = function getInner (i) {
43118
+ return this.values[i]
43119
+ };
43120
+
43121
+ Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
43122
+ for (var i = from; i < to; i++)
43123
+ { if (f(this.values[i], start + i) === false) { return false } }
43124
+ };
43125
+
43126
+ Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43127
+ for (var i = from - 1; i >= to; i--)
43128
+ { if (f(this.values[i], start + i) === false) { return false } }
43129
+ };
43130
+
43131
+ Leaf.prototype.leafAppend = function leafAppend (other) {
43132
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43133
+ { return new Leaf(this.values.concat(other.flatten())) }
43134
+ };
43135
+
43136
+ Leaf.prototype.leafPrepend = function leafPrepend (other) {
43137
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43138
+ { return new Leaf(other.flatten().concat(this.values)) }
43139
+ };
43140
+
43141
+ prototypeAccessors.length.get = function () { return this.values.length };
43142
+
43143
+ prototypeAccessors.depth.get = function () { return 0 };
43144
+
43145
+ Object.defineProperties( Leaf.prototype, prototypeAccessors );
43146
+
43147
+ return Leaf;
43148
+ }(RopeSequence));
43149
+
43150
+ // :: RopeSequence
43151
+ // The empty rope sequence.
43152
+ RopeSequence.empty = new Leaf([]);
43153
+
43154
+ var Append = /*@__PURE__*/(function (RopeSequence) {
43155
+ function Append(left, right) {
43156
+ RopeSequence.call(this);
43157
+ this.left = left;
43158
+ this.right = right;
43159
+ this.length = left.length + right.length;
43160
+ this.depth = Math.max(left.depth, right.depth) + 1;
43161
+ }
43162
+
43163
+ if ( RopeSequence ) Append.__proto__ = RopeSequence;
43164
+ Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43165
+ Append.prototype.constructor = Append;
43166
+
43167
+ Append.prototype.flatten = function flatten () {
43168
+ return this.left.flatten().concat(this.right.flatten())
43169
+ };
43170
+
43171
+ Append.prototype.getInner = function getInner (i) {
43172
+ return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
43173
+ };
43174
+
43175
+ Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
43176
+ var leftLen = this.left.length;
43177
+ if (from < leftLen &&
43178
+ this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
43179
+ { return false }
43180
+ if (to > leftLen &&
43181
+ this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
43182
+ { return false }
43183
+ };
43184
+
43185
+ Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43186
+ var leftLen = this.left.length;
43187
+ if (from > leftLen &&
43188
+ this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
43189
+ { return false }
43190
+ if (to < leftLen &&
43191
+ this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
43192
+ { return false }
43193
+ };
43194
+
43195
+ Append.prototype.sliceInner = function sliceInner (from, to) {
43196
+ if (from == 0 && to == this.length) { return this }
43197
+ var leftLen = this.left.length;
43198
+ if (to <= leftLen) { return this.left.slice(from, to) }
43199
+ if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
43200
+ return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
43201
+ };
43202
+
43203
+ Append.prototype.leafAppend = function leafAppend (other) {
43204
+ var inner = this.right.leafAppend(other);
43205
+ if (inner) { return new Append(this.left, inner) }
43206
+ };
43207
+
43208
+ Append.prototype.leafPrepend = function leafPrepend (other) {
43209
+ var inner = this.left.leafPrepend(other);
43210
+ if (inner) { return new Append(inner, this.right) }
43211
+ };
43212
+
43213
+ Append.prototype.appendInner = function appendInner (other) {
43214
+ if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
43215
+ { return new Append(this.left, new Append(this.right, other)) }
43216
+ return new Append(this, other)
43217
+ };
43218
+
43219
+ return Append;
43220
+ }(RopeSequence));
43221
+
43222
+ // ProseMirror's history isn't simply a way to roll back to a previous
43223
+ // state, because ProseMirror supports applying changes without adding
43224
+ // them to the history (for example during collaboration).
43225
+ //
43226
+ // To this end, each 'Branch' (one for the undo history and one for
43227
+ // the redo history) keeps an array of 'Items', which can optionally
43228
+ // hold a step (an actual undoable change), and always hold a position
43229
+ // map (which is needed to move changes below them to apply to the
43230
+ // current document).
43231
+ //
43232
+ // An item that has both a step and a selection bookmark is the start
43233
+ // of an 'event' — a group of changes that will be undone or redone at
43234
+ // once. (It stores only the bookmark, since that way we don't have to
43235
+ // provide a document until the selection is actually applied, which
43236
+ // is useful when compressing.)
43237
+ // Used to schedule history compression
43238
+ const max_empty_items = 500;
43239
+ class Branch {
43240
+ constructor(items, eventCount) {
43241
+ this.items = items;
43242
+ this.eventCount = eventCount;
43243
+ }
43244
+ // Pop the latest event off the branch's history and apply it
43245
+ // to a document transform.
43246
+ popEvent(state, preserveItems) {
43247
+ if (this.eventCount == 0)
43248
+ return null;
43249
+ let end = this.items.length;
43250
+ for (;; end--) {
43251
+ let next = this.items.get(end - 1);
43252
+ if (next.selection) {
43253
+ --end;
43254
+ break;
43255
+ }
43256
+ }
43257
+ let remap, mapFrom;
43258
+ if (preserveItems) {
43259
+ remap = this.remapping(end, this.items.length);
43260
+ mapFrom = remap.maps.length;
43261
+ }
43262
+ let transform = state.tr;
43263
+ let selection, remaining;
43264
+ let addAfter = [], addBefore = [];
43265
+ this.items.forEach((item, i) => {
43266
+ if (!item.step) {
43267
+ if (!remap) {
43268
+ remap = this.remapping(end, i + 1);
43269
+ mapFrom = remap.maps.length;
43270
+ }
43271
+ mapFrom--;
43272
+ addBefore.push(item);
43273
+ return;
43274
+ }
43275
+ if (remap) {
43276
+ addBefore.push(new Item(item.map));
43277
+ let step = item.step.map(remap.slice(mapFrom)), map;
43278
+ if (step && transform.maybeStep(step).doc) {
43279
+ map = transform.mapping.maps[transform.mapping.maps.length - 1];
43280
+ addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
43281
+ }
43282
+ mapFrom--;
43283
+ if (map)
43284
+ remap.appendMap(map, mapFrom);
43285
+ }
43286
+ else {
43287
+ transform.maybeStep(item.step);
43288
+ }
43289
+ if (item.selection) {
43290
+ selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
43291
+ remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
43292
+ return false;
43293
+ }
43294
+ }, this.items.length, 0);
43295
+ return { remaining: remaining, transform, selection: selection };
43296
+ }
43297
+ // Create a new branch with the given transform added.
43298
+ addTransform(transform, selection, histOptions, preserveItems) {
43299
+ let newItems = [], eventCount = this.eventCount;
43300
+ let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
43301
+ for (let i = 0; i < transform.steps.length; i++) {
43302
+ let step = transform.steps[i].invert(transform.docs[i]);
43303
+ let item = new Item(transform.mapping.maps[i], step, selection), merged;
43304
+ if (merged = lastItem && lastItem.merge(item)) {
43305
+ item = merged;
43306
+ if (i)
43307
+ newItems.pop();
43308
+ else
43309
+ oldItems = oldItems.slice(0, oldItems.length - 1);
43310
+ }
43311
+ newItems.push(item);
43312
+ if (selection) {
43313
+ eventCount++;
43314
+ selection = undefined;
43315
+ }
43316
+ if (!preserveItems)
43317
+ lastItem = item;
43318
+ }
43319
+ let overflow = eventCount - histOptions.depth;
43320
+ if (overflow > DEPTH_OVERFLOW) {
43321
+ oldItems = cutOffEvents(oldItems, overflow);
43322
+ eventCount -= overflow;
43323
+ }
43324
+ return new Branch(oldItems.append(newItems), eventCount);
43325
+ }
43326
+ remapping(from, to) {
43327
+ let maps = new Mapping;
43328
+ this.items.forEach((item, i) => {
43329
+ let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
43330
+ ? maps.maps.length - item.mirrorOffset : undefined;
43331
+ maps.appendMap(item.map, mirrorPos);
43332
+ }, from, to);
43333
+ return maps;
43334
+ }
43335
+ addMaps(array) {
43336
+ if (this.eventCount == 0)
43337
+ return this;
43338
+ return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
43339
+ }
43340
+ // When the collab module receives remote changes, the history has
43341
+ // to know about those, so that it can adjust the steps that were
43342
+ // rebased on top of the remote changes, and include the position
43343
+ // maps for the remote changes in its array of items.
43344
+ rebased(rebasedTransform, rebasedCount) {
43345
+ if (!this.eventCount)
43346
+ return this;
43347
+ rebasedCount = Math.min(this.items.length, rebasedCount);
43348
+ let rebasedItems = [], start = this.items.length - rebasedCount;
43349
+ let mapping = rebasedTransform.mapping;
43350
+ let newUntil = rebasedTransform.steps.length;
43351
+ let eventCount = this.eventCount;
43352
+ this.items.forEach(item => { if (item.selection)
43353
+ eventCount--; }, start);
43354
+ let iRebased = rebasedCount;
43355
+ this.items.forEach(item => {
43356
+ let pos = mapping.getMirror(--iRebased);
43357
+ if (pos == null)
43358
+ return;
43359
+ newUntil = Math.min(newUntil, pos);
43360
+ let map = mapping.maps[pos];
43361
+ if (item.step) {
43362
+ let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
43363
+ let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
43364
+ if (selection)
43365
+ eventCount++;
43366
+ rebasedItems.push(new Item(map, step, selection));
43367
+ }
43368
+ else {
43369
+ rebasedItems.push(new Item(map));
43370
+ }
43371
+ }, start);
43372
+ let newMaps = [];
43373
+ for (let i = rebasedCount; i < newUntil; i++)
43374
+ newMaps.push(new Item(mapping.maps[i]));
43375
+ let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
43376
+ let branch = new Branch(items, eventCount);
43377
+ if (branch.emptyItemCount() > max_empty_items)
43378
+ branch = branch.compress(this.items.length - rebasedItems.length);
43379
+ return branch;
43380
+ }
43381
+ emptyItemCount() {
43382
+ let count = 0;
43383
+ this.items.forEach(item => { if (!item.step)
43384
+ count++; });
43385
+ return count;
43386
+ }
43387
+ // Compressing a branch means rewriting it to push the air (map-only
43388
+ // items) out. During collaboration, these naturally accumulate
43389
+ // because each remote change adds one. The `upto` argument is used
43390
+ // to ensure that only the items below a given level are compressed,
43391
+ // because `rebased` relies on a clean, untouched set of items in
43392
+ // order to associate old items with rebased steps.
43393
+ compress(upto = this.items.length) {
43394
+ let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
43395
+ let items = [], events = 0;
43396
+ this.items.forEach((item, i) => {
43397
+ if (i >= upto) {
43398
+ items.push(item);
43399
+ if (item.selection)
43400
+ events++;
43401
+ }
43402
+ else if (item.step) {
43403
+ let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
43404
+ mapFrom--;
43405
+ if (map)
43406
+ remap.appendMap(map, mapFrom);
43407
+ if (step) {
43408
+ let selection = item.selection && item.selection.map(remap.slice(mapFrom));
43409
+ if (selection)
43410
+ events++;
43411
+ let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
43412
+ if (merged = items.length && items[last].merge(newItem))
43413
+ items[last] = merged;
43414
+ else
43415
+ items.push(newItem);
43416
+ }
43417
+ }
43418
+ else if (item.map) {
43419
+ mapFrom--;
43420
+ }
43421
+ }, this.items.length, 0);
43422
+ return new Branch(RopeSequence.from(items.reverse()), events);
43423
+ }
43424
+ }
43425
+ Branch.empty = new Branch(RopeSequence.empty, 0);
43426
+ function cutOffEvents(items, n) {
43427
+ let cutPoint;
43428
+ items.forEach((item, i) => {
43429
+ if (item.selection && (n-- == 0)) {
43430
+ cutPoint = i;
43431
+ return false;
43432
+ }
43433
+ });
43434
+ return items.slice(cutPoint);
43435
+ }
43436
+ class Item {
43437
+ constructor(
43438
+ // The (forward) step map for this item.
43439
+ map,
43440
+ // The inverted step
43441
+ step,
43442
+ // If this is non-null, this item is the start of a group, and
43443
+ // this selection is the starting selection for the group (the one
43444
+ // that was active before the first step was applied)
43445
+ selection,
43446
+ // If this item is the inverse of a previous mapping on the stack,
43447
+ // this points at the inverse's offset
43448
+ mirrorOffset) {
43449
+ this.map = map;
43450
+ this.step = step;
43451
+ this.selection = selection;
43452
+ this.mirrorOffset = mirrorOffset;
43453
+ }
43454
+ merge(other) {
43455
+ if (this.step && other.step && !other.selection) {
43456
+ let step = other.step.merge(this.step);
43457
+ if (step)
43458
+ return new Item(step.getMap().invert(), step, this.selection);
43459
+ }
43460
+ }
43461
+ }
43462
+ // The value of the state field that tracks undo/redo history for that
43463
+ // state. Will be stored in the plugin state when the history plugin
43464
+ // is active.
43465
+ class HistoryState {
43466
+ constructor(done, undone, prevRanges, prevTime, prevComposition) {
43467
+ this.done = done;
43468
+ this.undone = undone;
43469
+ this.prevRanges = prevRanges;
43470
+ this.prevTime = prevTime;
43471
+ this.prevComposition = prevComposition;
43472
+ }
43473
+ }
43474
+ const DEPTH_OVERFLOW = 20;
43475
+ // Record a transformation in undo history.
43476
+ function applyTransaction(history, state, tr, options) {
43477
+ let historyTr = tr.getMeta(historyKey), rebased;
43478
+ if (historyTr)
43479
+ return historyTr.historyState;
43480
+ if (tr.getMeta(closeHistoryKey))
43481
+ history = new HistoryState(history.done, history.undone, null, 0, -1);
43482
+ let appended = tr.getMeta("appendedTransaction");
43483
+ if (tr.steps.length == 0) {
43484
+ return history;
43485
+ }
43486
+ else if (appended && appended.getMeta(historyKey)) {
43487
+ if (appended.getMeta(historyKey).redo)
43488
+ return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
43489
+ else
43490
+ return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
43491
+ }
43492
+ else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
43493
+ // Group transforms that occur in quick succession into one event.
43494
+ let composition = tr.getMeta("composition");
43495
+ let newGroup = history.prevTime == 0 ||
43496
+ (!appended && history.prevComposition != composition &&
43497
+ (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
43498
+ let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
43499
+ 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);
43500
+ }
43501
+ else if (rebased = tr.getMeta("rebased")) {
43502
+ // Used by the collab module to tell the history that some of its
43503
+ // content has been rebased.
43504
+ return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43505
+ }
43506
+ else {
43507
+ return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43508
+ }
43509
+ }
43510
+ function isAdjacentTo(transform, prevRanges) {
43511
+ if (!prevRanges)
43512
+ return false;
43513
+ if (!transform.docChanged)
43514
+ return true;
43515
+ let adjacent = false;
43516
+ transform.mapping.maps[0].forEach((start, end) => {
43517
+ for (let i = 0; i < prevRanges.length; i += 2)
43518
+ if (start <= prevRanges[i + 1] && end >= prevRanges[i])
43519
+ adjacent = true;
43520
+ });
43521
+ return adjacent;
43522
+ }
43523
+ function rangesFor(maps) {
43524
+ let result = [];
43525
+ for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
43526
+ maps[i].forEach((_from, _to, from, to) => result.push(from, to));
43527
+ return result;
43528
+ }
43529
+ function mapRanges(ranges, mapping) {
43530
+ if (!ranges)
43531
+ return null;
43532
+ let result = [];
43533
+ for (let i = 0; i < ranges.length; i += 2) {
43534
+ let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
43535
+ if (from <= to)
43536
+ result.push(from, to);
43537
+ }
43538
+ return result;
43539
+ }
43540
+ // Apply the latest event from one branch to the document and shift the event
43541
+ // onto the other branch.
43542
+ function histTransaction(history, state, redo) {
43543
+ let preserveItems = mustPreserveItems(state);
43544
+ let histOptions = historyKey.get(state).spec.config;
43545
+ let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
43546
+ if (!pop)
43547
+ return null;
43548
+ let selection = pop.selection.resolve(pop.transform.doc);
43549
+ let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
43550
+ let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
43551
+ return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
43552
+ }
43553
+ let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
43554
+ // Check whether any plugin in the given state has a
43555
+ // `historyPreserveItems` property in its spec, in which case we must
43556
+ // preserve steps exactly as they came in, so that they can be
43557
+ // rebased.
43558
+ function mustPreserveItems(state) {
43559
+ let plugins = state.plugins;
43560
+ if (cachedPreserveItemsPlugins != plugins) {
43561
+ cachedPreserveItems = false;
43562
+ cachedPreserveItemsPlugins = plugins;
43563
+ for (let i = 0; i < plugins.length; i++)
43564
+ if (plugins[i].spec.historyPreserveItems) {
43565
+ cachedPreserveItems = true;
43566
+ break;
43567
+ }
43568
+ }
43569
+ return cachedPreserveItems;
43570
+ }
43571
+ /**
43572
+ Set a flag on the given transaction that will prevent further steps
43573
+ from being appended to an existing history event (so that they
43574
+ require a separate undo command to undo).
43575
+ */
43576
+ function closeHistory(tr) {
43577
+ return tr.setMeta(closeHistoryKey, true);
43578
+ }
43579
+ const historyKey = new PluginKey("history");
43580
+ const closeHistoryKey = new PluginKey("closeHistory");
43581
+ /**
43582
+ Returns a plugin that enables the undo history for an editor. The
43583
+ plugin will track undo and redo stacks, which can be used with the
43584
+ [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
43585
+
43586
+ You can set an `"addToHistory"` [metadata
43587
+ property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
43588
+ to prevent it from being rolled back by undo.
43589
+ */
43590
+ function history(config = {}) {
43591
+ config = { depth: config.depth || 100,
43592
+ newGroupDelay: config.newGroupDelay || 500 };
43593
+ return new Plugin({
43594
+ key: historyKey,
43595
+ state: {
43596
+ init() {
43597
+ return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
43598
+ },
43599
+ apply(tr, hist, state) {
43600
+ return applyTransaction(hist, state, tr, config);
43601
+ }
43602
+ },
43603
+ config,
43604
+ props: {
43605
+ handleDOMEvents: {
43606
+ beforeinput(view, e) {
43607
+ let inputType = e.inputType;
43608
+ let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
43609
+ if (!command || !view.editable)
43610
+ return false;
43611
+ e.preventDefault();
43612
+ return command(view.state, view.dispatch);
43613
+ }
43614
+ }
43615
+ }
43616
+ });
43617
+ }
43618
+ function buildCommand(redo, scroll) {
43619
+ return (state, dispatch) => {
43620
+ let hist = historyKey.getState(state);
43621
+ if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
43622
+ return false;
43623
+ if (dispatch) {
43624
+ let tr = histTransaction(hist, state, redo);
43625
+ if (tr)
43626
+ dispatch(scroll ? tr.scrollIntoView() : tr);
43627
+ }
43628
+ return true;
43629
+ };
43630
+ }
43631
+ /**
43632
+ A command function that undoes the last change, if any.
43633
+ */
43634
+ const undo = buildCommand(false, true);
43635
+ /**
43636
+ A command function that redoes the last undone change, if any.
43637
+ */
43638
+ const redo = buildCommand(true, true);
43639
+ /**
43640
+ Returns true if the given transaction was generated by the history
43641
+ plugin.
43642
+ */
43643
+ function isHistoryTransaction(tr) {
43644
+ return tr.getMeta(historyKey) != null;
43645
+ }
43646
+
43647
+ //#region src/helpers/createChainableState.ts
43648
+ /**
43649
+ * Takes a Transaction & Editor State and turns it into a chainable state object
43650
+ * @param config The transaction and state to create the chainable state from
43651
+ * @returns A chainable Editor state object
43652
+ */
43653
+ function createChainableState(config) {
43654
+ const { state, transaction } = config;
43655
+ let { selection } = transaction;
43656
+ let { doc } = transaction;
43657
+ let { storedMarks } = transaction;
43658
+ return {
43659
+ ...state,
43660
+ apply: state.apply.bind(state),
43661
+ applyTransaction: state.applyTransaction.bind(state),
43662
+ plugins: state.plugins,
43663
+ schema: state.schema,
43664
+ reconfigure: state.reconfigure.bind(state),
43665
+ toJSON: state.toJSON.bind(state),
43666
+ get storedMarks() {
43667
+ return storedMarks;
43668
+ },
43669
+ get selection() {
43670
+ return selection;
43671
+ },
43672
+ get doc() {
43673
+ return doc;
43674
+ },
43675
+ get tr() {
43676
+ selection = transaction.selection;
43677
+ doc = transaction.doc;
43678
+ storedMarks = transaction.storedMarks;
43679
+ return transaction;
43680
+ }
43681
+ };
43682
+ }
43683
+ //#endregion
43684
+ //#region src/CommandManager.ts
43685
+ var CommandManager = class CommandManager {
43686
+ constructor(props) {
43687
+ this.editor = props.editor;
43688
+ this.rawCommands = this.editor.extensionManager.commands;
43689
+ this.customState = props.state;
43690
+ }
43691
+ get hasCustomState() {
43692
+ return !!this.customState;
43693
+ }
43694
+ get state() {
43695
+ return this.customState || this.editor.state;
43696
+ }
43697
+ get commands() {
43698
+ const { rawCommands, editor, state } = this;
43699
+ const { view } = editor;
43700
+ const { tr } = state;
43701
+ const props = this.buildProps(tr);
43702
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43703
+ const method = (...args) => {
43704
+ const callback = command(...args)(props);
43705
+ if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43706
+ return callback;
43707
+ };
43708
+ return [name, method];
43709
+ }));
43710
+ }
43711
+ get chain() {
43712
+ return () => this.createChain();
43713
+ }
43714
+ get can() {
43715
+ return () => this.createCan();
43716
+ }
43717
+ createChain(startTr, shouldDispatch = true) {
43718
+ const { rawCommands, editor, state } = this;
43719
+ const { view } = editor;
43720
+ const callbacks = [];
43721
+ const hasStartTransaction = !!startTr;
43722
+ const tr = startTr || state.tr;
43723
+ const run = () => {
43724
+ if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43725
+ return callbacks.every((callback) => callback === true);
43726
+ };
43727
+ const chain = {
43728
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43729
+ const chainedCommand = (...args) => {
43730
+ const props = this.buildProps(tr, shouldDispatch);
43731
+ const callback = command(...args)(props);
43732
+ callbacks.push(callback);
43733
+ return chain;
43734
+ };
43735
+ return [name, chainedCommand];
43736
+ })),
43737
+ run
43738
+ };
43739
+ return chain;
43740
+ }
43741
+ /**
43742
+ * Creates a chain that safely returns `false` when run.
43743
+ * @returns A non-dispatching command chain.
43744
+ * @example
43745
+ * const chain = CommandManager.createFakeChain()
43746
+ * chain.focus().run() // false
43747
+ */
43748
+ static createFakeChain() {
43749
+ const chain = new Proxy({}, { get: (_target, property) => {
43750
+ if (property === "then") return;
43751
+ if (property === "run") return () => false;
43752
+ return () => chain;
43753
+ } });
43754
+ return chain;
43755
+ }
43756
+ createCan(startTr) {
43757
+ const { rawCommands, state } = this;
43758
+ const dispatch = false;
43759
+ const tr = startTr || state.tr;
43760
+ const props = this.buildProps(tr, dispatch);
43761
+ return {
43762
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43763
+ return [name, (...args) => command(...args)({
43764
+ ...props,
43765
+ dispatch: void 0
43766
+ })];
43767
+ })),
43768
+ chain: () => this.createChain(tr, dispatch)
43769
+ };
43770
+ }
43771
+ /**
43772
+ * Creates capability checks that safely return `false`.
43773
+ * @returns A non-dispatching capability checker.
43774
+ * @example
43775
+ * const can = CommandManager.createFallbackCan()
43776
+ * can.focus() // false
43777
+ */
43778
+ static createFallbackCan() {
43779
+ const chain = CommandManager.createFakeChain();
43780
+ return new Proxy({ chain: () => chain }, { get: (target, property) => {
43781
+ if (property === "then") return;
43782
+ if (property === "chain") return target.chain;
43783
+ return () => false;
43784
+ } });
43785
+ }
43786
+ buildProps(tr, shouldDispatch = true) {
43787
+ const { rawCommands, editor, state } = this;
43788
+ const { view } = editor;
43789
+ const props = {
43790
+ tr,
43791
+ editor,
43792
+ view,
43793
+ state: createChainableState({
43794
+ state,
43795
+ transaction: tr
43796
+ }),
43797
+ dispatch: shouldDispatch ? () => void 0 : void 0,
43798
+ chain: () => this.createChain(tr, shouldDispatch),
43799
+ can: () => this.createCan(tr),
43800
+ get commands() {
43801
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43802
+ return [name, (...args) => command(...args)(props)];
43803
+ }));
43804
+ }
43805
+ };
43806
+ return props;
43807
+ }
43808
+ };
43809
+ //#endregion
43810
+ //#region src/commands/blur.ts
43811
+ const blur = () => ({ editor, view }) => {
43812
+ requestAnimationFrame(() => {
43813
+ if (!editor.isDestroyed) {
43814
+ var _window;
43815
+ view.dom.blur();
43816
+ (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43817
+ }
43818
+ });
43819
+ return true;
43820
+ };
43821
+ //#endregion
43822
+ //#region src/commands/clearContent.ts
43823
+ const clearContent = (emitUpdate = true) => ({ commands }) => {
43824
+ return commands.setContent("", { emitUpdate });
43825
+ };
43826
+ //#endregion
43827
+ //#region src/commands/clearNodes.ts
43828
+ const clearNodes = () => ({ state, tr, dispatch }) => {
43829
+ const { selection } = tr;
43830
+ const { ranges } = selection;
43831
+ if (!dispatch) return true;
43832
+ ranges.forEach(({ $from, $to }) => {
43833
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43834
+ if (node.type.isText) return;
43835
+ const { doc, mapping } = tr;
43836
+ const $mappedFrom = doc.resolve(mapping.map(pos));
43837
+ const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43838
+ const nodeRange = $mappedFrom.blockRange($mappedTo);
43839
+ if (!nodeRange) return;
43840
+ const targetLiftDepth = liftTarget(nodeRange);
43841
+ if (node.type.isTextblock) {
43842
+ const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43843
+ tr.setNodeMarkup(nodeRange.start, defaultType);
43844
+ }
43845
+ if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43846
+ });
43847
+ });
43848
+ return true;
43849
+ };
43850
+ //#endregion
43851
+ //#region src/commands/command.ts
43852
+ const command = (fn) => (props) => {
43853
+ return fn(props);
43854
+ };
43855
+ //#endregion
43856
+ //#region src/commands/createParagraphNear.ts
43857
+ const createParagraphNear$1 = () => ({ state, dispatch }) => {
43858
+ return createParagraphNear(state, dispatch);
43859
+ };
43860
+ //#endregion
43861
+ //#region src/commands/cut.ts
43862
+ const cut = (originRange, targetPos) => ({ editor, tr }) => {
43863
+ const { state } = editor;
43864
+ const contentSlice = state.doc.slice(originRange.from, originRange.to);
43865
+ tr.deleteRange(originRange.from, originRange.to);
43866
+ const newPos = tr.mapping.map(targetPos);
43867
+ tr.insert(newPos, contentSlice.content);
43868
+ tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43869
+ return true;
43870
+ };
43871
+ //#endregion
43872
+ //#region src/commands/deleteCurrentNode.ts
43873
+ const deleteCurrentNode = () => ({ tr, dispatch }) => {
43874
+ const { selection } = tr;
43875
+ const currentNode = selection.$anchor.node();
43876
+ if (currentNode.content.size > 0) return false;
43877
+ const $pos = tr.selection.$anchor;
43878
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43879
+ if (dispatch) {
43880
+ const from = $pos.before(depth);
43881
+ const to = $pos.after(depth);
43882
+ tr.delete(from, to).scrollIntoView();
43883
+ }
43884
+ return true;
43885
+ }
43886
+ return false;
43887
+ };
43888
+ //#endregion
43889
+ //#region src/helpers/getNodeType.ts
43890
+ function getNodeType(nameOrType, schema) {
43891
+ if (typeof nameOrType === "string") {
43892
+ if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43893
+ return schema.nodes[nameOrType];
43894
+ }
43895
+ return nameOrType;
43896
+ }
43897
+ //#endregion
43898
+ //#region src/commands/deleteNode.ts
43899
+ const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43900
+ const type = getNodeType(typeOrName, state.schema);
43901
+ const $pos = tr.selection.$anchor;
43902
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43903
+ if (dispatch) {
43904
+ const from = $pos.before(depth);
43905
+ const to = $pos.after(depth);
43906
+ tr.delete(from, to).scrollIntoView();
43907
+ }
43908
+ return true;
43909
+ }
43910
+ return false;
43911
+ };
43912
+ //#endregion
43913
+ //#region src/commands/deleteRange.ts
43914
+ const deleteRange = (range) => ({ tr, dispatch }) => {
43915
+ const { from, to } = range;
43916
+ if (dispatch) tr.delete(from, to);
43917
+ return true;
43918
+ };
43919
+ //#endregion
43920
+ //#region src/commands/deleteSelection.ts
43921
+ /**
43922
+ * Check if a node has text content based on its content specification.
43923
+ * Returns true if the node's content spec matches text* or text+ patterns.
43924
+ */
43925
+ const hasTextContent = (nodeSpec) => {
43926
+ if (!nodeSpec.content) return false;
43927
+ return /^text(\*|\+)/.test(nodeSpec.content);
43928
+ };
43929
+ /**
43930
+ * Expand selection position for a specific side (left or right) to handle inline text nodes.
43931
+ * This function checks if the position is within an inline node with text content and
43932
+ * expands it to include the entire node boundaries for proper deletion.
43933
+ * @param $pos - The resolved position to expand
43934
+ * @param schema - The ProseMirror schema
43935
+ * @param side - Which side to expand ('left' or 'right')
43936
+ * @returns The expanded position for deletion
43937
+ */
43938
+ const expandSelectionForSide = ($pos, schema, side) => {
43939
+ if (!$pos.parent.isInline) return $pos.pos;
43940
+ if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43941
+ const parentContent = schema.nodes[$pos.parent.type.name].spec;
43942
+ if (!hasTextContent(parentContent)) return $pos.pos;
43943
+ return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43944
+ };
43945
+ /**
43946
+ * Expand selection range to properly handle deletion of inline text nodes.
43947
+ * Inline text nodes don't collapse correctly when text inside is deleted,
43948
+ * so we need to expand the selection to include the entire node.
43949
+ * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43950
+ */
43951
+ const expandSelectionForInlineText = ($from, $to, schema) => {
43952
+ return {
43953
+ from: expandSelectionForSide($from, schema, "left"),
43954
+ to: expandSelectionForSide($to, schema, "right")
43955
+ };
43956
+ };
43957
+ const deleteSelection = () => ({ state, dispatch }) => {
43958
+ if (state.selection.empty) return false;
43959
+ if (dispatch) {
43960
+ const tr = state.tr;
43961
+ const { ranges } = state.selection;
43962
+ const mapFrom = tr.steps.length;
43963
+ ranges.forEach((range) => {
43964
+ const mapping = tr.mapping.slice(mapFrom);
43965
+ const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43966
+ const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43967
+ const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43968
+ tr.deleteRange(from, to);
43969
+ });
43970
+ if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43971
+ tr.scrollIntoView();
43972
+ dispatch(tr);
43973
+ }
43974
+ return true;
43975
+ };
43976
+ //#endregion
43977
+ //#region src/commands/enter.ts
43978
+ const enter = () => ({ commands }) => {
43979
+ return commands.keyboardShortcut("Enter");
43980
+ };
43981
+ //#endregion
43982
+ //#region src/commands/exitCode.ts
43983
+ const exitCode$1 = () => ({ state, dispatch }) => {
43984
+ return exitCode(state, dispatch);
43985
+ };
43986
+ //#endregion
43987
+ //#region src/utilities/isRegExp.ts
43988
+ function isRegExp$1(value) {
43989
+ return Object.prototype.toString.call(value) === "[object RegExp]";
43990
+ }
43991
+ //#endregion
43992
+ //#region src/utilities/objectIncludes.ts
43993
+ /**
43994
+ * Check if object1 includes object2
43995
+ * @param object1 Object
43996
+ * @param object2 Object
43997
+ */
43998
+ function objectIncludes(object1, object2, options = { strict: true }) {
43999
+ const keys = Object.keys(object2);
44000
+ if (!keys.length) return true;
44001
+ return keys.every((key) => {
44002
+ if (options.strict) return object2[key] === object1[key];
44003
+ if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
44004
+ return object2[key] === object1[key];
44005
+ });
44006
+ }
44007
+ //#endregion
44008
+ //#region src/helpers/getMarkRange.ts
44009
+ function findMarkInSet(marks, type, attributes = {}) {
44010
+ return marks.find((item) => {
44011
+ return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
44012
+ });
44013
+ }
44014
+ function isMarkInSet(marks, type, attributes = {}) {
44015
+ return !!findMarkInSet(marks, type, attributes);
44016
+ }
44017
+ /**
44018
+ * Get the range of a mark at a resolved position.
44019
+ */
44020
+ function getMarkRange($pos, type, attributes) {
44021
+ if (!$pos || !type) return;
44022
+ let start = $pos.parent.childAfter($pos.parentOffset);
44023
+ if (!start.node || !start.node.marks.some((mark) => mark.type === type)) start = $pos.parent.childBefore($pos.parentOffset);
44024
+ if (!start.node || !start.node.marks.some((mark) => mark.type === type)) return;
44025
+ if (!attributes) {
44026
+ const firstMark = start.node.marks.find((mark) => mark.type === type);
44027
+ if (firstMark) attributes = firstMark.attrs;
44028
+ }
44029
+ if (!findMarkInSet([...start.node.marks], type, attributes)) return;
44030
+ let startIndex = start.index;
44031
+ let startPos = $pos.start() + start.offset;
44032
+ let endIndex = startIndex + 1;
44033
+ let endPos = startPos + start.node.nodeSize;
44034
+ while (startIndex > 0 && isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes)) {
44035
+ startIndex -= 1;
44036
+ startPos -= $pos.parent.child(startIndex).nodeSize;
44037
+ }
44038
+ while (endIndex < $pos.parent.childCount && isMarkInSet([...$pos.parent.child(endIndex).marks], type, attributes)) {
44039
+ endPos += $pos.parent.child(endIndex).nodeSize;
43386
44040
  endIndex += 1;
43387
44041
  }
43388
44042
  return {
@@ -43792,11 +44446,21 @@ so this becomes the fallback color for the slot */ ''}
43792
44446
  return joinForward(state, dispatch);
43793
44447
  };
43794
44448
  //#endregion
44449
+ //#region src/commands/canJoinItemsAt.ts
44450
+ const canJoinItemsAt = (doc, pos) => {
44451
+ const $pos = doc.resolve(pos);
44452
+ const before = $pos.nodeBefore;
44453
+ const after = $pos.nodeAfter;
44454
+ if (!before || !after) return false;
44455
+ return !before.type.spec.isolating && !after.type.spec.isolating;
44456
+ };
44457
+ //#endregion
43795
44458
  //#region src/commands/joinItemBackward.ts
43796
44459
  const joinItemBackward = () => ({ state, dispatch, tr }) => {
43797
44460
  try {
43798
44461
  const point = joinPoint(state.doc, state.selection.$from.pos, -1);
43799
44462
  if (point === null || point === void 0) return false;
44463
+ if (!canJoinItemsAt(state.doc, point)) return false;
43800
44464
  tr.join(point, 2);
43801
44465
  if (dispatch) dispatch(tr);
43802
44466
  return true;
@@ -43810,6 +44474,7 @@ so this becomes the fallback color for the slot */ ''}
43810
44474
  try {
43811
44475
  const point = joinPoint(state.doc, state.selection.$from.pos, 1);
43812
44476
  if (point === null || point === void 0) return false;
44477
+ if (!canJoinItemsAt(state.doc, point)) return false;
43813
44478
  tr.join(point, 2);
43814
44479
  if (dispatch) dispatch(tr);
43815
44480
  return true;
@@ -45216,8 +45881,14 @@ so this becomes the fallback color for the slot */ ''}
45216
45881
  type: deflt,
45217
45882
  attrs: newAttributes
45218
45883
  }] : void 0;
45219
- let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types);
45220
- if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
45884
+ const deletedTr = selection instanceof TextSelection && !selection.empty ? EditorState.create({
45885
+ doc: tr.doc,
45886
+ selection
45887
+ }).tr.deleteSelection() : null;
45888
+ const splitDoc = deletedTr ? deletedTr.doc : tr.doc;
45889
+ const splitPos = deletedTr ? deletedTr.mapping.map($from.pos) : $from.pos;
45890
+ let can = canSplit(splitDoc, splitPos, 1, types);
45891
+ if (!types && !can && canSplit(splitDoc, splitPos, 1, deflt ? [{ type: deflt }] : void 0)) {
45221
45892
  can = true;
45222
45893
  types = deflt ? [{
45223
45894
  type: deflt,
@@ -45226,12 +45897,13 @@ so this becomes the fallback color for the slot */ ''}
45226
45897
  }
45227
45898
  if (dispatch) {
45228
45899
  if (can) {
45900
+ const mapFrom = tr.steps.length;
45229
45901
  if (selection instanceof TextSelection) tr.deleteSelection();
45230
- tr.split(tr.mapping.map($from.pos), 1, types);
45902
+ tr.split(tr.mapping.slice(mapFrom).map($from.pos), 1, types);
45231
45903
  if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
45232
- const first = tr.mapping.map($from.before());
45904
+ const first = tr.mapping.slice(mapFrom).map($from.before());
45233
45905
  const $first = tr.doc.resolve(first);
45234
- if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
45906
+ if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.slice(mapFrom).map($from.before()), deflt);
45235
45907
  }
45236
45908
  }
45237
45909
  if (keepMarks) ensureMarks(state, editor.extensionManager.splittableMarks);
@@ -45284,16 +45956,19 @@ so this becomes the fallback color for the slot */ ''}
45284
45956
  ...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
45285
45957
  ...overrideAttrs
45286
45958
  };
45959
+ const splitsAtStartOfItem = $from.parentOffset === 0 && $from.index(-1) === 0;
45960
+ const itemStart = $from.before(-1);
45287
45961
  tr.delete($from.pos, $to.pos);
45962
+ const trailingTypeAttributes = splitsAtStartOfItem ? grandParent.attrs : newTypeAttributes;
45288
45963
  const types = nextType ? [{
45289
45964
  type,
45290
- attrs: newTypeAttributes
45965
+ attrs: trailingTypeAttributes
45291
45966
  }, {
45292
45967
  type: nextType,
45293
45968
  attrs: newNextTypeAttributes
45294
45969
  }] : [{
45295
45970
  type,
45296
- attrs: newTypeAttributes
45971
+ attrs: trailingTypeAttributes
45297
45972
  }];
45298
45973
  if (!canSplit(tr.doc, $from.pos, 2)) return false;
45299
45974
  if (dispatch) {
@@ -45301,6 +45976,7 @@ so this becomes the fallback color for the slot */ ''}
45301
45976
  const { splittableMarks } = editor.extensionManager;
45302
45977
  const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
45303
45978
  tr.split($from.pos, 2, types).scrollIntoView();
45979
+ if (splitsAtStartOfItem) tr.setNodeMarkup(itemStart, void 0, newTypeAttributes);
45304
45980
  if (!marks || !dispatch) return true;
45305
45981
  const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
45306
45982
  tr.ensureMarks(filteredMarks);
@@ -46833,55 +47509,106 @@ so this becomes the fallback color for the slot */ ''}
46833
47509
  }
46834
47510
  return result;
46835
47511
  };
47512
+ /**
47513
+ * Prepares the typed text so the rule handler can inspect the resulting document.
47514
+ */
47515
+ function createRuleTransaction(config) {
47516
+ const { editor, from, to, text, insertText } = config;
47517
+ if (!insertText) return {
47518
+ inputTransaction: null,
47519
+ tr: editor.view.state.tr
47520
+ };
47521
+ const inputTransaction = editor.view.state.tr.insertText(text, from, to);
47522
+ return {
47523
+ inputTransaction,
47524
+ tr: EditorState.create({
47525
+ doc: inputTransaction.doc,
47526
+ selection: inputTransaction.selection,
47527
+ storedMarks: inputTransaction.storedMarks
47528
+ }).tr
47529
+ };
47530
+ }
47531
+ /**
47532
+ * Runs a matching rule and dispatches the typed text before its conversion.
47533
+ */
47534
+ function applyRule(config) {
47535
+ const { editor, from, to, text, rule, match, plugin, insertText } = config;
47536
+ const { view } = editor;
47537
+ const { inputTransaction, tr } = createRuleTransaction({
47538
+ editor,
47539
+ from,
47540
+ to,
47541
+ text,
47542
+ insertText
47543
+ });
47544
+ const inputEnd = inputTransaction ? from + text.length : to;
47545
+ const state = createChainableState({
47546
+ state: view.state,
47547
+ transaction: tr
47548
+ });
47549
+ const range = {
47550
+ from: from - (match[0].length - text.length),
47551
+ to: inputEnd
47552
+ };
47553
+ const { commands, chain, can } = new CommandManager({
47554
+ editor,
47555
+ state
47556
+ });
47557
+ if (rule.handler({
47558
+ state,
47559
+ range,
47560
+ match,
47561
+ commands,
47562
+ chain,
47563
+ can
47564
+ }) === null || !tr.steps.length) return false;
47565
+ if (inputTransaction) {
47566
+ view.dispatch(inputTransaction);
47567
+ if (!view.state.doc.eq(inputTransaction.doc)) return true;
47568
+ }
47569
+ closeHistory(tr);
47570
+ tr.setMeta("inputRule", true);
47571
+ if (rule.undoable) tr.setMeta(plugin, {
47572
+ transform: tr,
47573
+ from,
47574
+ to: inputEnd,
47575
+ text
47576
+ });
47577
+ view.dispatch(tr);
47578
+ return true;
47579
+ }
47580
+ /**
47581
+ * Checks that the part of a match already in the document has matching positions.
47582
+ */
47583
+ function matchesDocument($from, match, text) {
47584
+ const matchedDocLength = match[0].length - text.length;
47585
+ if (matchedDocLength <= 0) return true;
47586
+ const matchStartOffset = $from.parentOffset - matchedDocLength;
47587
+ return matchStartOffset >= 0 && $from.parent.textBetween(matchStartOffset, $from.parentOffset) === match[0].slice(0, matchedDocLength);
47588
+ }
46836
47589
  function run$1$1(config) {
46837
47590
  var _ref;
46838
- const { editor, from, to, text, rules, plugin } = config;
47591
+ const { editor, from, to, text, rules, plugin, insertText } = config;
46839
47592
  const { view } = editor;
46840
47593
  if (view.composing) return false;
46841
47594
  const $from = view.state.doc.resolve(from);
46842
47595
  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;
46843
- let matched = false;
46844
47596
  const textBefore = getTextContentFromNodes($from) + text;
46845
- rules.forEach((rule) => {
46846
- if (matched) return;
47597
+ for (const rule of rules) {
46847
47598
  const match = inputRuleMatcherHandler(textBefore, rule.find);
46848
- if (!match) return;
46849
- const matchedDocLength = match[0].length - text.length;
46850
- if (matchedDocLength > 0) {
46851
- const matchStartOffset = $from.parentOffset - matchedDocLength;
46852
- if (matchStartOffset < 0 || $from.parent.textBetween(matchStartOffset, $from.parentOffset) !== match[0].slice(0, matchedDocLength)) return;
46853
- }
46854
- const tr = view.state.tr;
46855
- const state = createChainableState({
46856
- state: view.state,
46857
- transaction: tr
46858
- });
46859
- const range = {
46860
- from: from - (match[0].length - text.length),
46861
- to
46862
- };
46863
- const { commands, chain, can } = new CommandManager({
47599
+ if (!match || !matchesDocument($from, match, text)) continue;
47600
+ if (applyRule({
46864
47601
  editor,
46865
- state
46866
- });
46867
- if (rule.handler({
46868
- state,
46869
- range,
46870
- match,
46871
- commands,
46872
- chain,
46873
- can
46874
- }) === null || !tr.steps.length) return;
46875
- if (rule.undoable) tr.setMeta(plugin, {
46876
- transform: tr,
46877
47602
  from,
46878
47603
  to,
46879
- text
46880
- });
46881
- view.dispatch(tr);
46882
- matched = true;
46883
- });
46884
- return matched;
47604
+ text,
47605
+ rule,
47606
+ match,
47607
+ plugin,
47608
+ insertText
47609
+ })) return true;
47610
+ }
47611
+ return false;
46885
47612
  }
46886
47613
  /**
46887
47614
  * Create an input rules plugin. When enabled, it will cause text
@@ -46925,7 +47652,8 @@ so this becomes the fallback color for the slot */ ''}
46925
47652
  to,
46926
47653
  text,
46927
47654
  rules,
46928
- plugin
47655
+ plugin,
47656
+ insertText: true
46929
47657
  });
46930
47658
  },
46931
47659
  handleDOMEvents: { compositionend: (view) => {
@@ -47161,6 +47889,9 @@ so this becomes the fallback color for the slot */ ''}
47161
47889
  pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
47162
47890
  return tr;
47163
47891
  };
47892
+ editor.on("destroy", () => {
47893
+ if (tiptapDragFromOtherEditor === editor) tiptapDragFromOtherEditor = null;
47894
+ });
47164
47895
  return rules.map((rule) => {
47165
47896
  return new Plugin({
47166
47897
  view(view) {
@@ -47186,6 +47917,7 @@ so this becomes the fallback color for the slot */ ''}
47186
47917
  if (!isDroppedFromProseMirror) {
47187
47918
  const dragFromOtherEditor = tiptapDragFromOtherEditor;
47188
47919
  if (dragFromOtherEditor === null || dragFromOtherEditor === void 0 ? void 0 : dragFromOtherEditor.isEditable) setTimeout(() => {
47920
+ if (dragFromOtherEditor.isDestroyed) return;
47189
47921
  const selection = dragFromOtherEditor.state.selection;
47190
47922
  if (selection) dragFromOtherEditor.commands.deleteRange({
47191
47923
  from: selection.from,
@@ -48355,7 +49087,10 @@ img.ProseMirror-separator {
48355
49087
  ...options
48356
49088
  };
48357
49089
  if (!this.editorView || !this.state || this.isDestroyed) return;
48358
- if (this.options.editorProps) this.view.setProps(this.options.editorProps);
49090
+ if (this.options.editorProps) this.view.setProps({
49091
+ ...this.options.editorProps,
49092
+ attributes: this.getEditorViewAttributes()
49093
+ });
48359
49094
  this.view.updateState(this.state);
48360
49095
  }
48361
49096
  /**
@@ -48511,6 +49246,23 @@ img.ProseMirror-separator {
48511
49246
  return doc;
48512
49247
  }
48513
49248
  /**
49249
+ * Returns the attributes for the editor element.
49250
+ * Merges the default `role="textbox"` with the attributes from `editorProps`,
49251
+ * so the role is kept no matter when the props are applied.
49252
+ */
49253
+ getEditorViewAttributes() {
49254
+ var _this$options$editorP;
49255
+ const attributes = (_this$options$editorP = this.options.editorProps) === null || _this$options$editorP === void 0 ? void 0 : _this$options$editorP.attributes;
49256
+ if (isFunction$3(attributes)) return (state) => ({
49257
+ role: "textbox",
49258
+ ...attributes(state)
49259
+ });
49260
+ return {
49261
+ role: "textbox",
49262
+ ...attributes
49263
+ };
49264
+ }
49265
+ /**
48514
49266
  * Creates a ProseMirror view.
48515
49267
  */
48516
49268
  createView(element) {
@@ -48521,10 +49273,7 @@ img.ProseMirror-separator {
48521
49273
  const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
48522
49274
  this.editorView = new EditorView(element, {
48523
49275
  ...editorProps,
48524
- attributes: {
48525
- role: "textbox",
48526
- ...editorProps === null || editorProps === void 0 ? void 0 : editorProps.attributes
48527
- },
49276
+ attributes: this.getEditorViewAttributes(),
48528
49277
  dispatchTransaction: dispatch,
48529
49278
  transformPastedHTML,
48530
49279
  state: this.editorState,
@@ -58227,7 +58976,7 @@ img.ProseMirror-separator {
58227
58976
  toDOM() { return ["div", ["hr"]]; }
58228
58977
  },
58229
58978
  heading: {
58230
- attrs: { level: { default: 1 } },
58979
+ attrs: { level: { default: 1, validate: "number" } },
58231
58980
  content: "(text | image)*",
58232
58981
  group: "block",
58233
58982
  defining: true,
@@ -58237,7 +58986,7 @@ img.ProseMirror-separator {
58237
58986
  { tag: "h4", attrs: { level: 4 } },
58238
58987
  { tag: "h5", attrs: { level: 5 } },
58239
58988
  { tag: "h6", attrs: { level: 6 } }],
58240
- toDOM(node) { return ["h" + node.attrs.level, 0]; }
58989
+ toDOM(node) { return ["h" + +node.attrs.level, 0]; }
58241
58990
  },
58242
58991
  code_block: {
58243
58992
  content: "text*",
@@ -61734,8 +62483,27 @@ img.ProseMirror-separator {
61734
62483
  const UNICODE_WHITESPACE_PATTERN = "[\0- \xA0 ᠎ -\u2029  ]";
61735
62484
  const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN);
61736
62485
  const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`);
62486
+ const UNICODE_WHITESPACE_REGEX_TRAILING = new RegExp(`${UNICODE_WHITESPACE_PATTERN}+$`);
61737
62487
  const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, "g");
61738
62488
  //#endregion
62489
+ //#region src/helpers/unlinkTrailingWhitespace.ts
62490
+ function unlinkTrailingWhitespace(tr, range, type) {
62491
+ var _rangeEnd$nodeBefore, _insertedText$match;
62492
+ const rangeEnd = tr.doc.resolve(range.to);
62493
+ if (!((_rangeEnd$nodeBefore = rangeEnd.nodeBefore) === null || _rangeEnd$nodeBefore === void 0 ? void 0 : _rangeEnd$nodeBefore.isText)) return;
62494
+ 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];
62495
+ if (!trailingWhitespace) return;
62496
+ const whitespaceFrom = range.to - trailingWhitespace.length;
62497
+ const linkMarks = getMarksBetween(whitespaceFrom, range.to, tr.doc).filter((item) => item.mark.type === type);
62498
+ if (!linkMarks.length) return;
62499
+ const { nodeAfter } = rangeEnd;
62500
+ if (!!nodeAfter && linkMarks.some((item) => item.mark.isInSet(nodeAfter.marks))) return;
62501
+ const storedMarks = tr.storedMarks;
62502
+ tr.removeMark(whitespaceFrom, range.to, type);
62503
+ tr.setStoredMarks(storedMarks);
62504
+ if (tr.selection.empty && tr.selection.from === range.to) tr.removeStoredMark(type);
62505
+ }
62506
+ //#endregion
61739
62507
  //#region src/helpers/autolink.ts
61740
62508
  /**
61741
62509
  * Check if the provided tokens form a valid link structure, which can either be a single link token
@@ -61776,6 +62544,21 @@ img.ProseMirror-separator {
61776
62544
  if (!docChanges || preventAutolink) return;
61777
62545
  const { tr } = newState;
61778
62546
  const transform = combineTransactionSteps(oldState.doc, [...transactions]);
62547
+ if (!transactions.some(isHistoryTransaction)) {
62548
+ const insertedRanges = [];
62549
+ transform.steps.forEach((step, index) => {
62550
+ if (!(step instanceof ReplaceStep) || !step.slice.size) return;
62551
+ const mapping = transform.mapping.slice(index + 1);
62552
+ const from = mapping.map(step.from, 1);
62553
+ const to = mapping.map(step.from + step.slice.size, -1);
62554
+ if (from < to) insertedRanges.push({
62555
+ from,
62556
+ to
62557
+ });
62558
+ });
62559
+ insertedRanges.sort((left, right) => right.to - left.to);
62560
+ insertedRanges.forEach((range) => unlinkTrailingWhitespace(tr, range, options.type));
62561
+ }
61779
62562
  getChangedRanges(transform).forEach(({ newRange }) => {
61780
62563
  const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, (node) => node.isTextblock);
61781
62564
  let textBlock;
@@ -63162,6 +63945,54 @@ img.ProseMirror-separator {
63162
63945
  });
63163
63946
  }
63164
63947
  //#endregion
63948
+ //#region src/ordered-list/collectOrderedListItemsFromSource.ts
63949
+ const ORDERED_LIST_SCAN_WINDOW = 64;
63950
+ function takeLines(source, max) {
63951
+ const lines = [];
63952
+ let start = 0;
63953
+ while (lines.length < max) {
63954
+ const lineEnd = source.indexOf("\n", start);
63955
+ if (lineEnd === -1) {
63956
+ lines.push(source.slice(start));
63957
+ return lines;
63958
+ }
63959
+ lines.push(source.slice(start, lineEnd));
63960
+ start = lineEnd + 1;
63961
+ }
63962
+ return lines;
63963
+ }
63964
+ /**
63965
+ * Collect ordered list items from the start of `source`, reading only the lines the list needs.
63966
+ *
63967
+ * @param source Markdown beginning at a block boundary.
63968
+ * @returns The items, how many lines they consumed, and the lines that were read.
63969
+ * @example
63970
+ * collectOrderedListItemsFromSource('1. one\n2. two\n\nAfter')
63971
+ * // → [[item, item], 3, ['1. one', '2. two', '', 'After']]
63972
+ */
63973
+ function collectOrderedListItemsFromSource(source) {
63974
+ const firstLineEnd = source.indexOf("\n");
63975
+ const firstLine = firstLineEnd === -1 ? source : source.slice(0, firstLineEnd);
63976
+ if (!ORDERED_LIST_ITEM_REGEX.test(firstLine)) return [
63977
+ [],
63978
+ 0,
63979
+ []
63980
+ ];
63981
+ let windowSize = ORDERED_LIST_SCAN_WINDOW;
63982
+ let lines = takeLines(source, windowSize);
63983
+ let collected = collectOrderedListItems(lines);
63984
+ while (collected[1] === lines.length && lines.length === windowSize) {
63985
+ windowSize *= 2;
63986
+ lines = takeLines(source, windowSize);
63987
+ collected = collectOrderedListItems(lines);
63988
+ }
63989
+ return [
63990
+ collected[0],
63991
+ collected[1],
63992
+ lines
63993
+ ];
63994
+ }
63995
+ //#endregion
63165
63996
  //#region src/ordered-list/ordered-list.ts
63166
63997
  const ListItemName = "listItem";
63167
63998
  const TextStyleName = "textStyle";
@@ -63280,8 +64111,7 @@ img.ProseMirror-separator {
63280
64111
  start: () => -1,
63281
64112
  tokenize: (src, _tokens, lexer) => {
63282
64113
  var _listItems$, _listItems$2;
63283
- const lines = src.split("\n");
63284
- const [listItems, consumed] = collectOrderedListItems(lines);
64114
+ const [listItems, consumed, lines] = collectOrderedListItemsFromSource(src);
63285
64115
  if (listItems.length === 0) return;
63286
64116
  const items = buildNestedStructure(listItems, listItems[0].indent, lexer);
63287
64117
  if (items.length === 0) return;
@@ -66054,1026 +66884,412 @@ img.ProseMirror-separator {
66054
66884
  * This extension allows you to create text nodes.
66055
66885
  * @see https://www.tiptap.dev/api/nodes/text
66056
66886
  */
66057
- const Text = Node$1.create({
66058
- name: "text",
66059
- group: "inline",
66060
- parseMarkdown: (token) => {
66061
- return {
66062
- type: "text",
66063
- text: token.text || ""
66064
- };
66065
- },
66066
- renderMarkdown: (node) => node.text || ""
66067
- });
66068
- //#endregion
66069
- //#region src/index.ts
66070
- var src_default = Text;
66071
-
66072
- /**
66073
- Create a plugin that, when added to a ProseMirror instance,
66074
- causes a decoration to show up at the drop position when something
66075
- is dragged over the editor.
66076
-
66077
- Nodes may add a `disableDropCursor` property to their spec to
66078
- control the showing of a drop cursor inside them. This may be a
66079
- boolean or a function, which will be called with a view and a
66080
- position, and should return a boolean.
66081
- */
66082
- function dropCursor(options = {}) {
66083
- return new Plugin({
66084
- view(editorView) { return new DropCursorView(editorView, options); }
66085
- });
66086
- }
66087
- class DropCursorView {
66088
- constructor(editorView, options) {
66089
- var _a;
66090
- this.editorView = editorView;
66091
- this.cursorPos = null;
66092
- this.element = null;
66093
- this.timeout = -1;
66094
- this.lastDragEvent = null;
66095
- this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66096
- this.color = options.color === false ? undefined : (options.color || "black");
66097
- this.class = options.class;
66098
- this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66099
- let handler = (e) => { this[name](e); };
66100
- editorView.dom.addEventListener(name, handler);
66101
- return { name, handler };
66102
- });
66103
- }
66104
- destroy() {
66105
- this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66106
- }
66107
- update(editorView, prevState) {
66108
- if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66109
- // if we currently have an on-going drag event
66110
- // we need to update the cursor position again and update the overlay
66111
- if (this.lastDragEvent) {
66112
- let target = this.computeTarget(this.lastDragEvent);
66113
- if (target == this.cursorPos)
66114
- this.updateOverlay();
66115
- else
66116
- this.setCursor(target);
66117
- }
66118
- else {
66119
- this.updateOverlay();
66120
- }
66121
- }
66122
- }
66123
- setCursor(pos) {
66124
- if (pos == this.cursorPos)
66125
- return;
66126
- this.cursorPos = pos;
66127
- if (pos == null) {
66128
- this.element.parentNode.removeChild(this.element);
66129
- this.element = null;
66130
- }
66131
- else {
66132
- this.updateOverlay();
66133
- }
66134
- }
66135
- updateOverlay() {
66136
- let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66137
- let isBlock = !$pos.parent.inlineContent, rect;
66138
- let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66139
- let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66140
- if (isBlock) {
66141
- let before = $pos.nodeBefore, after = $pos.nodeAfter;
66142
- if (before || after) {
66143
- let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66144
- if (node) {
66145
- let nodeRect = node.getBoundingClientRect();
66146
- let top = before ? nodeRect.bottom : nodeRect.top;
66147
- if (before && after)
66148
- top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66149
- let halfWidth = (this.width / 2) * scaleY;
66150
- rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66151
- }
66152
- }
66153
- }
66154
- if (!rect) {
66155
- let coords = this.editorView.coordsAtPos(this.cursorPos);
66156
- let halfWidth = (this.width / 2) * scaleX;
66157
- rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66158
- }
66159
- let parent = this.editorView.dom.offsetParent;
66160
- if (!this.element) {
66161
- this.element = parent.appendChild(document.createElement("div"));
66162
- if (this.class)
66163
- this.element.className = this.class;
66164
- this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
66165
- if (this.color) {
66166
- this.element.style.backgroundColor = this.color;
66167
- }
66168
- }
66169
- this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
66170
- this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
66171
- let parentLeft, parentTop;
66172
- if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
66173
- parentLeft = -pageXOffset;
66174
- parentTop = -pageYOffset;
66175
- }
66176
- else {
66177
- let rect = parent.getBoundingClientRect();
66178
- let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
66179
- parentLeft = rect.left - parent.scrollLeft * parentScaleX;
66180
- parentTop = rect.top - parent.scrollTop * parentScaleY;
66181
- }
66182
- this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
66183
- this.element.style.top = (rect.top - parentTop) / scaleY + "px";
66184
- this.element.style.width = (rect.right - rect.left) / scaleX + "px";
66185
- this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66186
- }
66187
- scheduleRemoval(timeout) {
66188
- clearTimeout(this.timeout);
66189
- this.timeout = setTimeout(() => this.setCursor(null), timeout);
66190
- }
66191
- computeTarget(event) {
66192
- let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
66193
- let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
66194
- let disableDropCursor = node && node.type.spec.disableDropCursor;
66195
- let disabled = typeof disableDropCursor == "function"
66196
- ? disableDropCursor(this.editorView, pos, event)
66197
- : disableDropCursor;
66198
- if (!pos || disabled)
66199
- return null;
66200
- let target = pos.pos;
66201
- if (this.editorView.dragging && this.editorView.dragging.slice) {
66202
- let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
66203
- if (point != null)
66204
- target = point;
66205
- }
66206
- return target;
66207
- }
66208
- dragover(event) {
66209
- if (!this.editorView.editable)
66210
- return;
66211
- this.lastDragEvent = event;
66212
- let target = this.computeTarget(event);
66213
- if (target != null) {
66214
- this.setCursor(target);
66215
- this.scheduleRemoval(5000);
66216
- }
66217
- }
66218
- dragend() {
66219
- this.scheduleRemoval(20);
66220
- }
66221
- drop() {
66222
- this.scheduleRemoval(20);
66223
- }
66224
- dragleave(event) {
66225
- if (!this.editorView.dom.contains(event.relatedTarget))
66226
- this.setCursor(null);
66227
- }
66228
- }
66229
-
66230
- /**
66231
- Gap cursor selections are represented using this class. Its
66232
- `$anchor` and `$head` properties both point at the cursor position.
66233
- */
66234
- class GapCursor extends Selection$2 {
66235
- /**
66236
- Create a gap cursor.
66237
- */
66238
- constructor($pos) {
66239
- super($pos, $pos);
66240
- }
66241
- map(doc, mapping) {
66242
- let $pos = doc.resolve(mapping.map(this.head));
66243
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66244
- }
66245
- content() { return Slice.empty; }
66246
- eq(other) {
66247
- return other instanceof GapCursor && other.head == this.head;
66248
- }
66249
- toJSON() {
66250
- return { type: "gapcursor", pos: this.head };
66251
- }
66252
- /**
66253
- @internal
66254
- */
66255
- static fromJSON(doc, json) {
66256
- if (typeof json.pos != "number")
66257
- throw new RangeError("Invalid input for GapCursor.fromJSON");
66258
- return new GapCursor(doc.resolve(json.pos));
66259
- }
66260
- /**
66261
- @internal
66262
- */
66263
- getBookmark() { return new GapBookmark(this.anchor); }
66264
- /**
66265
- @internal
66266
- */
66267
- static valid($pos) {
66268
- let parent = $pos.parent;
66269
- if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
66270
- return false;
66271
- let override = parent.type.spec.allowGapCursor;
66272
- if (override != null)
66273
- return override;
66274
- let deflt = parent.contentMatchAt($pos.index()).defaultType;
66275
- return deflt && deflt.isTextblock;
66276
- }
66277
- /**
66278
- @internal
66279
- */
66280
- static findGapCursorFrom($pos, dir, mustMove = false) {
66281
- search: for (;;) {
66282
- if (!mustMove && GapCursor.valid($pos))
66283
- return $pos;
66284
- let pos = $pos.pos, next = null;
66285
- // Scan up from this position
66286
- for (let d = $pos.depth;; d--) {
66287
- let parent = $pos.node(d);
66288
- if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
66289
- next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
66290
- break;
66291
- }
66292
- else if (d == 0) {
66293
- return null;
66294
- }
66295
- pos += dir;
66296
- let $cur = $pos.doc.resolve(pos);
66297
- if (GapCursor.valid($cur))
66298
- return $cur;
66299
- }
66300
- // And then down into the next node
66301
- for (;;) {
66302
- let inside = dir > 0 ? next.firstChild : next.lastChild;
66303
- if (!inside) {
66304
- if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
66305
- $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
66306
- mustMove = false;
66307
- continue search;
66308
- }
66309
- break;
66310
- }
66311
- next = inside;
66312
- pos += dir;
66313
- let $cur = $pos.doc.resolve(pos);
66314
- if (GapCursor.valid($cur))
66315
- return $cur;
66316
- }
66317
- return null;
66318
- }
66319
- }
66320
- }
66321
- GapCursor.prototype.visible = false;
66322
- GapCursor.findFrom = GapCursor.findGapCursorFrom;
66323
- Selection$2.jsonID("gapcursor", GapCursor);
66324
- class GapBookmark {
66325
- constructor(pos) {
66326
- this.pos = pos;
66327
- }
66328
- map(mapping) {
66329
- return new GapBookmark(mapping.map(this.pos));
66330
- }
66331
- resolve(doc) {
66332
- let $pos = doc.resolve(this.pos);
66333
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66334
- }
66335
- }
66336
- function needsGap(type) {
66337
- return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66338
- }
66339
- function closedBefore($pos) {
66340
- for (let d = $pos.depth; d >= 0; d--) {
66341
- let index = $pos.index(d), parent = $pos.node(d);
66342
- // At the start of this parent, look at next one
66343
- if (index == 0) {
66344
- if (parent.type.spec.isolating)
66345
- return true;
66346
- continue;
66347
- }
66348
- // See if the node before (or its first ancestor) is closed
66349
- for (let before = parent.child(index - 1);; before = before.lastChild) {
66350
- if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
66351
- return true;
66352
- if (before.inlineContent)
66353
- return false;
66354
- }
66355
- }
66356
- // Hit start of document
66357
- return true;
66358
- }
66359
- function closedAfter($pos) {
66360
- for (let d = $pos.depth; d >= 0; d--) {
66361
- let index = $pos.indexAfter(d), parent = $pos.node(d);
66362
- if (index == parent.childCount) {
66363
- if (parent.type.spec.isolating)
66364
- return true;
66365
- continue;
66366
- }
66367
- for (let after = parent.child(index);; after = after.firstChild) {
66368
- if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
66369
- return true;
66370
- if (after.inlineContent)
66371
- return false;
66372
- }
66373
- }
66374
- return true;
66375
- }
66887
+ const Text = Node$1.create({
66888
+ name: "text",
66889
+ group: "inline",
66890
+ parseMarkdown: (token) => {
66891
+ return {
66892
+ type: "text",
66893
+ text: token.text || ""
66894
+ };
66895
+ },
66896
+ renderMarkdown: (node) => node.text || ""
66897
+ });
66898
+ //#endregion
66899
+ //#region src/index.ts
66900
+ var src_default = Text;
66376
66901
 
66377
66902
  /**
66378
- Create a gap cursor plugin. When enabled, this will capture clicks
66379
- near and arrow-key-motion past places that don't have a normally
66380
- selectable position nearby, and create a gap cursor selection for
66381
- them. The cursor is drawn as an element with class
66382
- `ProseMirror-gapcursor`. You can either include
66383
- `style/gapcursor.css` from the package's directory or add your own
66384
- styles to make it visible.
66903
+ Create a plugin that, when added to a ProseMirror instance,
66904
+ causes a decoration to show up at the drop position when something
66905
+ is dragged over the editor.
66906
+
66907
+ Nodes may add a `disableDropCursor` property to their spec to
66908
+ control the showing of a drop cursor inside them. This may be a
66909
+ boolean or a function, which will be called with a view and a
66910
+ position, and should return a boolean.
66385
66911
  */
66386
- function gapCursor() {
66912
+ function dropCursor(options = {}) {
66387
66913
  return new Plugin({
66388
- props: {
66389
- decorations: drawGapCursor,
66390
- createSelectionBetween(_view, $anchor, $head) {
66391
- return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
66392
- },
66393
- handleClick,
66394
- handleKeyDown,
66395
- handleDOMEvents: { beforeinput: beforeinput }
66396
- }
66914
+ view(editorView) { return new DropCursorView(editorView, options); }
66397
66915
  });
66398
66916
  }
66399
- const handleKeyDown = keydownHandler({
66400
- "ArrowLeft": arrow("horiz", -1),
66401
- "ArrowRight": arrow("horiz", 1),
66402
- "ArrowUp": arrow("vert", -1),
66403
- "ArrowDown": arrow("vert", 1)
66404
- });
66405
- function arrow(axis, dir) {
66406
- const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
66407
- return function (state, dispatch, view) {
66408
- let sel = state.selection;
66409
- let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
66410
- if (sel instanceof TextSelection) {
66411
- if (!view.endOfTextblock(dirStr) || $start.depth == 0)
66412
- return false;
66413
- mustMove = false;
66414
- $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
66415
- }
66416
- let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
66417
- if (!$found)
66418
- return false;
66419
- if (dispatch)
66420
- dispatch(state.tr.setSelection(new GapCursor($found)));
66421
- return true;
66422
- };
66423
- }
66424
- function handleClick(view, pos, event) {
66425
- if (!view || !view.editable)
66426
- return false;
66427
- let $pos = view.state.doc.resolve(pos);
66428
- if (!GapCursor.valid($pos))
66429
- return false;
66430
- let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
66431
- if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
66432
- return false;
66433
- view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
66434
- return true;
66435
- }
66436
- // This is a hack that, when a composition starts while a gap cursor
66437
- // is active, quickly creates an inline context for the composition to
66438
- // happen in, to avoid it being aborted by the DOM selection being
66439
- // moved into a valid position.
66440
- function beforeinput(view, event) {
66441
- if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
66442
- return false;
66443
- let { $from } = view.state.selection;
66444
- let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
66445
- if (!insert)
66446
- return false;
66447
- let frag = Fragment.empty;
66448
- for (let i = insert.length - 1; i >= 0; i--)
66449
- frag = Fragment.from(insert[i].createAndFill(null, frag));
66450
- let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
66451
- tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
66452
- view.dispatch(tr);
66453
- return false;
66454
- }
66455
- function drawGapCursor(state) {
66456
- if (!(state.selection instanceof GapCursor))
66457
- return null;
66458
- let node = document.createElement("div");
66459
- node.className = "ProseMirror-gapcursor";
66460
- return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
66461
- }
66462
-
66463
- var GOOD_LEAF_SIZE = 200;
66464
-
66465
- // :: class<T> A rope sequence is a persistent sequence data structure
66466
- // that supports appending, prepending, and slicing without doing a
66467
- // full copy. It is represented as a mostly-balanced tree.
66468
- var RopeSequence = function RopeSequence () {};
66469
-
66470
- RopeSequence.prototype.append = function append (other) {
66471
- if (!other.length) { return this }
66472
- other = RopeSequence.from(other);
66473
-
66474
- return (!this.length && other) ||
66475
- (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
66476
- (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
66477
- this.appendInner(other)
66478
- };
66479
-
66480
- // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
66481
- // Prepend an array or other rope to this one, returning a new rope.
66482
- RopeSequence.prototype.prepend = function prepend (other) {
66483
- if (!other.length) { return this }
66484
- return RopeSequence.from(other).append(this)
66485
- };
66486
-
66487
- RopeSequence.prototype.appendInner = function appendInner (other) {
66488
- return new Append(this, other)
66489
- };
66490
-
66491
- // :: (?number, ?number) → RopeSequence<T>
66492
- // Create a rope repesenting a sub-sequence of this rope.
66493
- RopeSequence.prototype.slice = function slice (from, to) {
66494
- if ( from === void 0 ) from = 0;
66495
- if ( to === void 0 ) to = this.length;
66496
-
66497
- if (from >= to) { return RopeSequence.empty }
66498
- return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
66499
- };
66500
-
66501
- // :: (number) → T
66502
- // Retrieve the element at the given position from this rope.
66503
- RopeSequence.prototype.get = function get (i) {
66504
- if (i < 0 || i >= this.length) { return undefined }
66505
- return this.getInner(i)
66506
- };
66507
-
66508
- // :: ((element: T, index: number) → ?bool, ?number, ?number)
66509
- // Call the given function for each element between the given
66510
- // indices. This tends to be more efficient than looping over the
66511
- // indices and calling `get`, because it doesn't have to descend the
66512
- // tree for every element.
66513
- RopeSequence.prototype.forEach = function forEach (f, from, to) {
66514
- if ( from === void 0 ) from = 0;
66515
- if ( to === void 0 ) to = this.length;
66516
-
66517
- if (from <= to)
66518
- { this.forEachInner(f, from, to, 0); }
66519
- else
66520
- { this.forEachInvertedInner(f, from, to, 0); }
66521
- };
66522
-
66523
- // :: ((element: T, index: number) → U, ?number, ?number) → [U]
66524
- // Map the given functions over the elements of the rope, producing
66525
- // a flat array.
66526
- RopeSequence.prototype.map = function map (f, from, to) {
66527
- if ( from === void 0 ) from = 0;
66528
- if ( to === void 0 ) to = this.length;
66529
-
66530
- var result = [];
66531
- this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
66532
- return result
66533
- };
66534
-
66535
- // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
66536
- // Create a rope representing the given array, or return the rope
66537
- // itself if a rope was given.
66538
- RopeSequence.from = function from (values) {
66539
- if (values instanceof RopeSequence) { return values }
66540
- return values && values.length ? new Leaf(values) : RopeSequence.empty
66541
- };
66542
-
66543
- var Leaf = /*@__PURE__*/(function (RopeSequence) {
66544
- function Leaf(values) {
66545
- RopeSequence.call(this);
66546
- this.values = values;
66547
- }
66548
-
66549
- if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
66550
- Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66551
- Leaf.prototype.constructor = Leaf;
66552
-
66553
- var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
66554
-
66555
- Leaf.prototype.flatten = function flatten () {
66556
- return this.values
66557
- };
66558
-
66559
- Leaf.prototype.sliceInner = function sliceInner (from, to) {
66560
- if (from == 0 && to == this.length) { return this }
66561
- return new Leaf(this.values.slice(from, to))
66562
- };
66563
-
66564
- Leaf.prototype.getInner = function getInner (i) {
66565
- return this.values[i]
66566
- };
66567
-
66568
- Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
66569
- for (var i = from; i < to; i++)
66570
- { if (f(this.values[i], start + i) === false) { return false } }
66571
- };
66572
-
66573
- Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66574
- for (var i = from - 1; i >= to; i--)
66575
- { if (f(this.values[i], start + i) === false) { return false } }
66576
- };
66577
-
66578
- Leaf.prototype.leafAppend = function leafAppend (other) {
66579
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66580
- { return new Leaf(this.values.concat(other.flatten())) }
66581
- };
66582
-
66583
- Leaf.prototype.leafPrepend = function leafPrepend (other) {
66584
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66585
- { return new Leaf(other.flatten().concat(this.values)) }
66586
- };
66587
-
66588
- prototypeAccessors.length.get = function () { return this.values.length };
66589
-
66590
- prototypeAccessors.depth.get = function () { return 0 };
66591
-
66592
- Object.defineProperties( Leaf.prototype, prototypeAccessors );
66593
-
66594
- return Leaf;
66595
- }(RopeSequence));
66596
-
66597
- // :: RopeSequence
66598
- // The empty rope sequence.
66599
- RopeSequence.empty = new Leaf([]);
66600
-
66601
- var Append = /*@__PURE__*/(function (RopeSequence) {
66602
- function Append(left, right) {
66603
- RopeSequence.call(this);
66604
- this.left = left;
66605
- this.right = right;
66606
- this.length = left.length + right.length;
66607
- this.depth = Math.max(left.depth, right.depth) + 1;
66608
- }
66609
-
66610
- if ( RopeSequence ) Append.__proto__ = RopeSequence;
66611
- Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66612
- Append.prototype.constructor = Append;
66613
-
66614
- Append.prototype.flatten = function flatten () {
66615
- return this.left.flatten().concat(this.right.flatten())
66616
- };
66617
-
66618
- Append.prototype.getInner = function getInner (i) {
66619
- return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
66620
- };
66621
-
66622
- Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
66623
- var leftLen = this.left.length;
66624
- if (from < leftLen &&
66625
- this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
66626
- { return false }
66627
- if (to > leftLen &&
66628
- this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
66629
- { return false }
66630
- };
66631
-
66632
- Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66633
- var leftLen = this.left.length;
66634
- if (from > leftLen &&
66635
- this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
66636
- { return false }
66637
- if (to < leftLen &&
66638
- this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
66639
- { return false }
66640
- };
66641
-
66642
- Append.prototype.sliceInner = function sliceInner (from, to) {
66643
- if (from == 0 && to == this.length) { return this }
66644
- var leftLen = this.left.length;
66645
- if (to <= leftLen) { return this.left.slice(from, to) }
66646
- if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
66647
- return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
66648
- };
66649
-
66650
- Append.prototype.leafAppend = function leafAppend (other) {
66651
- var inner = this.right.leafAppend(other);
66652
- if (inner) { return new Append(this.left, inner) }
66653
- };
66654
-
66655
- Append.prototype.leafPrepend = function leafPrepend (other) {
66656
- var inner = this.left.leafPrepend(other);
66657
- if (inner) { return new Append(inner, this.right) }
66658
- };
66659
-
66660
- Append.prototype.appendInner = function appendInner (other) {
66661
- if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
66662
- { return new Append(this.left, new Append(this.right, other)) }
66663
- return new Append(this, other)
66664
- };
66665
-
66666
- return Append;
66667
- }(RopeSequence));
66668
-
66669
- // ProseMirror's history isn't simply a way to roll back to a previous
66670
- // state, because ProseMirror supports applying changes without adding
66671
- // them to the history (for example during collaboration).
66672
- //
66673
- // To this end, each 'Branch' (one for the undo history and one for
66674
- // the redo history) keeps an array of 'Items', which can optionally
66675
- // hold a step (an actual undoable change), and always hold a position
66676
- // map (which is needed to move changes below them to apply to the
66677
- // current document).
66678
- //
66679
- // An item that has both a step and a selection bookmark is the start
66680
- // of an 'event' — a group of changes that will be undone or redone at
66681
- // once. (It stores only the bookmark, since that way we don't have to
66682
- // provide a document until the selection is actually applied, which
66683
- // is useful when compressing.)
66684
- // Used to schedule history compression
66685
- const max_empty_items = 500;
66686
- class Branch {
66687
- constructor(items, eventCount) {
66688
- this.items = items;
66689
- this.eventCount = eventCount;
66690
- }
66691
- // Pop the latest event off the branch's history and apply it
66692
- // to a document transform.
66693
- popEvent(state, preserveItems) {
66694
- if (this.eventCount == 0)
66695
- return null;
66696
- let end = this.items.length;
66697
- for (;; end--) {
66698
- let next = this.items.get(end - 1);
66699
- if (next.selection) {
66700
- --end;
66701
- break;
66702
- }
66703
- }
66704
- let remap, mapFrom;
66705
- if (preserveItems) {
66706
- remap = this.remapping(end, this.items.length);
66707
- mapFrom = remap.maps.length;
66708
- }
66709
- let transform = state.tr;
66710
- let selection, remaining;
66711
- let addAfter = [], addBefore = [];
66712
- this.items.forEach((item, i) => {
66713
- if (!item.step) {
66714
- if (!remap) {
66715
- remap = this.remapping(end, i + 1);
66716
- mapFrom = remap.maps.length;
66717
- }
66718
- mapFrom--;
66719
- addBefore.push(item);
66720
- return;
66721
- }
66722
- if (remap) {
66723
- addBefore.push(new Item(item.map));
66724
- let step = item.step.map(remap.slice(mapFrom)), map;
66725
- if (step && transform.maybeStep(step).doc) {
66726
- map = transform.mapping.maps[transform.mapping.maps.length - 1];
66727
- addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
66728
- }
66729
- mapFrom--;
66730
- if (map)
66731
- remap.appendMap(map, mapFrom);
66732
- }
66733
- else {
66734
- transform.maybeStep(item.step);
66735
- }
66736
- if (item.selection) {
66737
- selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
66738
- remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
66739
- return false;
66740
- }
66741
- }, this.items.length, 0);
66742
- return { remaining: remaining, transform, selection: selection };
66743
- }
66744
- // Create a new branch with the given transform added.
66745
- addTransform(transform, selection, histOptions, preserveItems) {
66746
- let newItems = [], eventCount = this.eventCount;
66747
- let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
66748
- for (let i = 0; i < transform.steps.length; i++) {
66749
- let step = transform.steps[i].invert(transform.docs[i]);
66750
- let item = new Item(transform.mapping.maps[i], step, selection), merged;
66751
- if (merged = lastItem && lastItem.merge(item)) {
66752
- item = merged;
66753
- if (i)
66754
- newItems.pop();
66755
- else
66756
- oldItems = oldItems.slice(0, oldItems.length - 1);
66757
- }
66758
- newItems.push(item);
66759
- if (selection) {
66760
- eventCount++;
66761
- selection = undefined;
66762
- }
66763
- if (!preserveItems)
66764
- lastItem = item;
66765
- }
66766
- let overflow = eventCount - histOptions.depth;
66767
- if (overflow > DEPTH_OVERFLOW) {
66768
- oldItems = cutOffEvents(oldItems, overflow);
66769
- eventCount -= overflow;
66770
- }
66771
- return new Branch(oldItems.append(newItems), eventCount);
66772
- }
66773
- remapping(from, to) {
66774
- let maps = new Mapping;
66775
- this.items.forEach((item, i) => {
66776
- let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
66777
- ? maps.maps.length - item.mirrorOffset : undefined;
66778
- maps.appendMap(item.map, mirrorPos);
66779
- }, from, to);
66780
- return maps;
66781
- }
66782
- addMaps(array) {
66783
- if (this.eventCount == 0)
66784
- return this;
66785
- return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
66786
- }
66787
- // When the collab module receives remote changes, the history has
66788
- // to know about those, so that it can adjust the steps that were
66789
- // rebased on top of the remote changes, and include the position
66790
- // maps for the remote changes in its array of items.
66791
- rebased(rebasedTransform, rebasedCount) {
66792
- if (!this.eventCount)
66793
- return this;
66794
- let rebasedItems = [], start = Math.max(0, this.items.length - rebasedCount);
66795
- let mapping = rebasedTransform.mapping;
66796
- let newUntil = rebasedTransform.steps.length;
66797
- let eventCount = this.eventCount;
66798
- this.items.forEach(item => { if (item.selection)
66799
- eventCount--; }, start);
66800
- let iRebased = rebasedCount;
66801
- this.items.forEach(item => {
66802
- let pos = mapping.getMirror(--iRebased);
66803
- if (pos == null)
66804
- return;
66805
- newUntil = Math.min(newUntil, pos);
66806
- let map = mapping.maps[pos];
66807
- if (item.step) {
66808
- let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
66809
- let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
66810
- if (selection)
66811
- eventCount++;
66812
- rebasedItems.push(new Item(map, step, selection));
66813
- }
66814
- else {
66815
- rebasedItems.push(new Item(map));
66816
- }
66817
- }, start);
66818
- let newMaps = [];
66819
- for (let i = rebasedCount; i < newUntil; i++)
66820
- newMaps.push(new Item(mapping.maps[i]));
66821
- let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
66822
- let branch = new Branch(items, eventCount);
66823
- if (branch.emptyItemCount() > max_empty_items)
66824
- branch = branch.compress(this.items.length - rebasedItems.length);
66825
- return branch;
66917
+ class DropCursorView {
66918
+ constructor(editorView, options) {
66919
+ var _a;
66920
+ this.editorView = editorView;
66921
+ this.cursorPos = null;
66922
+ this.element = null;
66923
+ this.timeout = -1;
66924
+ this.lastDragEvent = null;
66925
+ this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66926
+ this.color = options.color === false ? undefined : (options.color || "black");
66927
+ this.class = options.class;
66928
+ this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66929
+ let handler = (e) => { this[name](e); };
66930
+ editorView.dom.addEventListener(name, handler);
66931
+ return { name, handler };
66932
+ });
66826
66933
  }
66827
- emptyItemCount() {
66828
- let count = 0;
66829
- this.items.forEach(item => { if (!item.step)
66830
- count++; });
66831
- return count;
66934
+ destroy() {
66935
+ this.setCursor(null);
66936
+ this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66832
66937
  }
66833
- // Compressing a branch means rewriting it to push the air (map-only
66834
- // items) out. During collaboration, these naturally accumulate
66835
- // because each remote change adds one. The `upto` argument is used
66836
- // to ensure that only the items below a given level are compressed,
66837
- // because `rebased` relies on a clean, untouched set of items in
66838
- // order to associate old items with rebased steps.
66839
- compress(upto = this.items.length) {
66840
- let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
66841
- let items = [], events = 0;
66842
- this.items.forEach((item, i) => {
66843
- if (i >= upto) {
66844
- items.push(item);
66845
- if (item.selection)
66846
- events++;
66938
+ update(editorView, prevState) {
66939
+ if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66940
+ // if we currently have an on-going drag event
66941
+ // we need to update the cursor position again and update the overlay
66942
+ if (this.lastDragEvent) {
66943
+ let target = this.computeTarget(this.lastDragEvent);
66944
+ if (target == this.cursorPos)
66945
+ this.updateOverlay();
66946
+ else
66947
+ this.setCursor(target);
66847
66948
  }
66848
- else if (item.step) {
66849
- let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
66850
- mapFrom--;
66851
- if (map)
66852
- remap.appendMap(map, mapFrom);
66853
- if (step) {
66854
- let selection = item.selection && item.selection.map(remap.slice(mapFrom));
66855
- if (selection)
66856
- events++;
66857
- let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
66858
- if (merged = items.length && items[last].merge(newItem))
66859
- items[last] = merged;
66860
- else
66861
- items.push(newItem);
66949
+ else {
66950
+ this.updateOverlay();
66951
+ }
66952
+ }
66953
+ }
66954
+ setCursor(pos) {
66955
+ if (pos == this.cursorPos)
66956
+ return;
66957
+ this.cursorPos = pos;
66958
+ if (pos == null) {
66959
+ this.element.parentNode.removeChild(this.element);
66960
+ this.element = null;
66961
+ }
66962
+ else {
66963
+ this.updateOverlay();
66964
+ }
66965
+ }
66966
+ updateOverlay() {
66967
+ let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66968
+ let isBlock = !$pos.parent.inlineContent, rect;
66969
+ let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66970
+ let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66971
+ if (isBlock) {
66972
+ let before = $pos.nodeBefore, after = $pos.nodeAfter;
66973
+ if (before || after) {
66974
+ let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66975
+ if (node) {
66976
+ let nodeRect = node.getBoundingClientRect();
66977
+ let top = before ? nodeRect.bottom : nodeRect.top;
66978
+ if (before && after)
66979
+ top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66980
+ let halfWidth = (this.width / 2) * scaleY;
66981
+ rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66862
66982
  }
66863
66983
  }
66864
- else if (item.map) {
66865
- mapFrom--;
66984
+ }
66985
+ if (!rect) {
66986
+ let coords = this.editorView.coordsAtPos(this.cursorPos);
66987
+ let halfWidth = (this.width / 2) * scaleX;
66988
+ rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66989
+ }
66990
+ let parent = this.editorView.dom.offsetParent;
66991
+ if (!this.element) {
66992
+ this.element = parent.appendChild(document.createElement("div"));
66993
+ if (this.class)
66994
+ this.element.className = this.class;
66995
+ this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
66996
+ if (this.color) {
66997
+ this.element.style.backgroundColor = this.color;
66866
66998
  }
66867
- }, this.items.length, 0);
66868
- return new Branch(RopeSequence.from(items.reverse()), events);
66999
+ }
67000
+ this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
67001
+ this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
67002
+ let parentLeft, parentTop;
67003
+ if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
67004
+ parentLeft = -pageXOffset;
67005
+ parentTop = -pageYOffset;
67006
+ }
67007
+ else {
67008
+ let rect = parent.getBoundingClientRect();
67009
+ let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
67010
+ parentLeft = rect.left - parent.scrollLeft * parentScaleX;
67011
+ parentTop = rect.top - parent.scrollTop * parentScaleY;
67012
+ }
67013
+ this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
67014
+ this.element.style.top = (rect.top - parentTop) / scaleY + "px";
67015
+ this.element.style.width = (rect.right - rect.left) / scaleX + "px";
67016
+ this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66869
67017
  }
66870
- }
66871
- Branch.empty = new Branch(RopeSequence.empty, 0);
66872
- function cutOffEvents(items, n) {
66873
- let cutPoint;
66874
- items.forEach((item, i) => {
66875
- if (item.selection && (n-- == 0)) {
66876
- cutPoint = i;
66877
- return false;
67018
+ scheduleRemoval(timeout) {
67019
+ clearTimeout(this.timeout);
67020
+ this.timeout = setTimeout(() => this.setCursor(null), timeout);
67021
+ }
67022
+ computeTarget(event) {
67023
+ let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
67024
+ let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
67025
+ let disableDropCursor = node && node.type.spec.disableDropCursor;
67026
+ let disabled = typeof disableDropCursor == "function"
67027
+ ? disableDropCursor(this.editorView, pos, event)
67028
+ : disableDropCursor;
67029
+ if (!pos || disabled)
67030
+ return null;
67031
+ let target = pos.pos;
67032
+ if (this.editorView.dragging && this.editorView.dragging.slice) {
67033
+ let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
67034
+ if (point != null)
67035
+ target = point;
66878
67036
  }
66879
- });
66880
- return items.slice(cutPoint);
66881
- }
66882
- class Item {
66883
- constructor(
66884
- // The (forward) step map for this item.
66885
- map,
66886
- // The inverted step
66887
- step,
66888
- // If this is non-null, this item is the start of a group, and
66889
- // this selection is the starting selection for the group (the one
66890
- // that was active before the first step was applied)
66891
- selection,
66892
- // If this item is the inverse of a previous mapping on the stack,
66893
- // this points at the inverse's offset
66894
- mirrorOffset) {
66895
- this.map = map;
66896
- this.step = step;
66897
- this.selection = selection;
66898
- this.mirrorOffset = mirrorOffset;
67037
+ return target;
66899
67038
  }
66900
- merge(other) {
66901
- if (this.step && other.step && !other.selection) {
66902
- let step = other.step.merge(this.step);
66903
- if (step)
66904
- return new Item(step.getMap().invert(), step, this.selection);
67039
+ dragover(event) {
67040
+ if (!this.editorView.editable)
67041
+ return;
67042
+ this.lastDragEvent = event;
67043
+ let target = this.computeTarget(event);
67044
+ if (target != null) {
67045
+ this.setCursor(target);
67046
+ this.scheduleRemoval(5000);
66905
67047
  }
66906
67048
  }
66907
- }
66908
- // The value of the state field that tracks undo/redo history for that
66909
- // state. Will be stored in the plugin state when the history plugin
66910
- // is active.
66911
- class HistoryState {
66912
- constructor(done, undone, prevRanges, prevTime, prevComposition) {
66913
- this.done = done;
66914
- this.undone = undone;
66915
- this.prevRanges = prevRanges;
66916
- this.prevTime = prevTime;
66917
- this.prevComposition = prevComposition;
67049
+ dragend() {
67050
+ this.scheduleRemoval(20);
67051
+ }
67052
+ drop() {
67053
+ this.scheduleRemoval(20);
67054
+ }
67055
+ dragleave(event) {
67056
+ if (!this.editorView.dom.contains(event.relatedTarget))
67057
+ this.setCursor(null);
66918
67058
  }
66919
67059
  }
66920
- const DEPTH_OVERFLOW = 20;
66921
- // Record a transformation in undo history.
66922
- function applyTransaction(history, state, tr, options) {
66923
- let historyTr = tr.getMeta(historyKey), rebased;
66924
- if (historyTr)
66925
- return historyTr.historyState;
66926
- if (tr.getMeta(closeHistoryKey))
66927
- history = new HistoryState(history.done, history.undone, null, 0, -1);
66928
- let appended = tr.getMeta("appendedTransaction");
66929
- if (tr.steps.length == 0) {
66930
- return history;
67060
+
67061
+ /**
67062
+ Gap cursor selections are represented using this class. Its
67063
+ `$anchor` and `$head` properties both point at the cursor position.
67064
+ */
67065
+ class GapCursor extends Selection$2 {
67066
+ /**
67067
+ Create a gap cursor.
67068
+ */
67069
+ constructor($pos) {
67070
+ super($pos, $pos);
66931
67071
  }
66932
- else if (appended && appended.getMeta(historyKey)) {
66933
- if (appended.getMeta(historyKey).redo)
66934
- return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
66935
- else
66936
- return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
67072
+ map(doc, mapping) {
67073
+ let $pos = doc.resolve(mapping.map(this.head));
67074
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66937
67075
  }
66938
- else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
66939
- // Group transforms that occur in quick succession into one event.
66940
- let composition = tr.getMeta("composition");
66941
- let newGroup = history.prevTime == 0 ||
66942
- (!appended && history.prevComposition != composition &&
66943
- (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
66944
- let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
66945
- 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);
67076
+ content() { return Slice.empty; }
67077
+ eq(other) {
67078
+ return other instanceof GapCursor && other.head == this.head;
66946
67079
  }
66947
- else if (rebased = tr.getMeta("rebased")) {
66948
- // Used by the collab module to tell the history that some of its
66949
- // content has been rebased.
66950
- return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67080
+ toJSON() {
67081
+ return { type: "gapcursor", pos: this.head };
66951
67082
  }
66952
- else {
66953
- return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67083
+ /**
67084
+ @internal
67085
+ */
67086
+ static fromJSON(doc, json) {
67087
+ if (typeof json.pos != "number")
67088
+ throw new RangeError("Invalid input for GapCursor.fromJSON");
67089
+ return new GapCursor(doc.resolve(json.pos));
67090
+ }
67091
+ /**
67092
+ @internal
67093
+ */
67094
+ getBookmark() { return new GapBookmark(this.anchor); }
67095
+ /**
67096
+ @internal
67097
+ */
67098
+ static valid($pos) {
67099
+ let parent = $pos.parent;
67100
+ if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
67101
+ return false;
67102
+ let override = parent.type.spec.allowGapCursor;
67103
+ if (override != null)
67104
+ return override;
67105
+ let deflt = parent.contentMatchAt($pos.index()).defaultType;
67106
+ return deflt && deflt.isTextblock;
67107
+ }
67108
+ /**
67109
+ @internal
67110
+ */
67111
+ static findGapCursorFrom($pos, dir, mustMove = false) {
67112
+ search: for (;;) {
67113
+ if (!mustMove && GapCursor.valid($pos))
67114
+ return $pos;
67115
+ let pos = $pos.pos, next = null;
67116
+ // Scan up from this position
67117
+ for (let d = $pos.depth;; d--) {
67118
+ let parent = $pos.node(d);
67119
+ if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
67120
+ next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
67121
+ break;
67122
+ }
67123
+ else if (d == 0) {
67124
+ return null;
67125
+ }
67126
+ pos += dir;
67127
+ let $cur = $pos.doc.resolve(pos);
67128
+ if (GapCursor.valid($cur))
67129
+ return $cur;
67130
+ }
67131
+ // And then down into the next node
67132
+ for (;;) {
67133
+ let inside = dir > 0 ? next.firstChild : next.lastChild;
67134
+ if (!inside) {
67135
+ if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
67136
+ $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
67137
+ mustMove = false;
67138
+ continue search;
67139
+ }
67140
+ break;
67141
+ }
67142
+ next = inside;
67143
+ pos += dir;
67144
+ let $cur = $pos.doc.resolve(pos);
67145
+ if (GapCursor.valid($cur))
67146
+ return $cur;
67147
+ }
67148
+ return null;
67149
+ }
66954
67150
  }
66955
67151
  }
66956
- function isAdjacentTo(transform, prevRanges) {
66957
- if (!prevRanges)
66958
- return false;
66959
- if (!transform.docChanged)
66960
- return true;
66961
- let adjacent = false;
66962
- transform.mapping.maps[0].forEach((start, end) => {
66963
- for (let i = 0; i < prevRanges.length; i += 2)
66964
- if (start <= prevRanges[i + 1] && end >= prevRanges[i])
66965
- adjacent = true;
66966
- });
66967
- return adjacent;
67152
+ GapCursor.prototype.visible = false;
67153
+ GapCursor.findFrom = GapCursor.findGapCursorFrom;
67154
+ Selection$2.jsonID("gapcursor", GapCursor);
67155
+ class GapBookmark {
67156
+ constructor(pos) {
67157
+ this.pos = pos;
67158
+ }
67159
+ map(mapping) {
67160
+ return new GapBookmark(mapping.map(this.pos));
67161
+ }
67162
+ resolve(doc) {
67163
+ let $pos = doc.resolve(this.pos);
67164
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
67165
+ }
66968
67166
  }
66969
- function rangesFor(maps) {
66970
- let result = [];
66971
- for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
66972
- maps[i].forEach((_from, _to, from, to) => result.push(from, to));
66973
- return result;
67167
+ function needsGap(type) {
67168
+ return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66974
67169
  }
66975
- function mapRanges(ranges, mapping) {
66976
- if (!ranges)
66977
- return null;
66978
- let result = [];
66979
- for (let i = 0; i < ranges.length; i += 2) {
66980
- let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
66981
- if (from <= to)
66982
- result.push(from, to);
67170
+ function closedBefore($pos) {
67171
+ for (let d = $pos.depth; d >= 0; d--) {
67172
+ let index = $pos.index(d), parent = $pos.node(d);
67173
+ // At the start of this parent, look at next one
67174
+ if (index == 0) {
67175
+ if (parent.type.spec.isolating)
67176
+ return true;
67177
+ continue;
67178
+ }
67179
+ // See if the node before (or its first ancestor) is closed
67180
+ for (let before = parent.child(index - 1);; before = before.lastChild) {
67181
+ if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
67182
+ return true;
67183
+ if (before.inlineContent)
67184
+ return false;
67185
+ }
66983
67186
  }
66984
- return result;
66985
- }
66986
- // Apply the latest event from one branch to the document and shift the event
66987
- // onto the other branch.
66988
- function histTransaction(history, state, redo) {
66989
- let preserveItems = mustPreserveItems(state);
66990
- let histOptions = historyKey.get(state).spec.config;
66991
- let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
66992
- if (!pop)
66993
- return null;
66994
- let selection = pop.selection.resolve(pop.transform.doc);
66995
- let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
66996
- let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
66997
- return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
67187
+ // Hit start of document
67188
+ return true;
66998
67189
  }
66999
- let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
67000
- // Check whether any plugin in the given state has a
67001
- // `historyPreserveItems` property in its spec, in which case we must
67002
- // preserve steps exactly as they came in, so that they can be
67003
- // rebased.
67004
- function mustPreserveItems(state) {
67005
- let plugins = state.plugins;
67006
- if (cachedPreserveItemsPlugins != plugins) {
67007
- cachedPreserveItems = false;
67008
- cachedPreserveItemsPlugins = plugins;
67009
- for (let i = 0; i < plugins.length; i++)
67010
- if (plugins[i].spec.historyPreserveItems) {
67011
- cachedPreserveItems = true;
67012
- break;
67013
- }
67190
+ function closedAfter($pos) {
67191
+ for (let d = $pos.depth; d >= 0; d--) {
67192
+ let index = $pos.indexAfter(d), parent = $pos.node(d);
67193
+ if (index == parent.childCount) {
67194
+ if (parent.type.spec.isolating)
67195
+ return true;
67196
+ continue;
67197
+ }
67198
+ for (let after = parent.child(index);; after = after.firstChild) {
67199
+ if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
67200
+ return true;
67201
+ if (after.inlineContent)
67202
+ return false;
67203
+ }
67014
67204
  }
67015
- return cachedPreserveItems;
67205
+ return true;
67016
67206
  }
67017
- const historyKey = new PluginKey("history");
67018
- const closeHistoryKey = new PluginKey("closeHistory");
67019
- /**
67020
- Returns a plugin that enables the undo history for an editor. The
67021
- plugin will track undo and redo stacks, which can be used with the
67022
- [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
67023
67207
 
67024
- You can set an `"addToHistory"` [metadata
67025
- property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
67026
- to prevent it from being rolled back by undo.
67208
+ /**
67209
+ Create a gap cursor plugin. When enabled, this will capture clicks
67210
+ near and arrow-key-motion past places that don't have a normally
67211
+ selectable position nearby, and create a gap cursor selection for
67212
+ them. The cursor is drawn as an element with class
67213
+ `ProseMirror-gapcursor`. You can either include
67214
+ `style/gapcursor.css` from the package's directory or add your own
67215
+ styles to make it visible.
67027
67216
  */
67028
- function history(config = {}) {
67029
- config = { depth: config.depth || 100,
67030
- newGroupDelay: config.newGroupDelay || 500 };
67217
+ function gapCursor() {
67031
67218
  return new Plugin({
67032
- key: historyKey,
67033
- state: {
67034
- init() {
67035
- return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
67036
- },
67037
- apply(tr, hist, state) {
67038
- return applyTransaction(hist, state, tr, config);
67039
- }
67040
- },
67041
- config,
67042
67219
  props: {
67043
- handleDOMEvents: {
67044
- beforeinput(view, e) {
67045
- let inputType = e.inputType;
67046
- let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
67047
- if (!command || !view.editable)
67048
- return false;
67049
- e.preventDefault();
67050
- return command(view.state, view.dispatch);
67051
- }
67052
- }
67220
+ decorations: drawGapCursor,
67221
+ createSelectionBetween(_view, $anchor, $head) {
67222
+ return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
67223
+ },
67224
+ handleClick,
67225
+ handleKeyDown,
67226
+ handleDOMEvents: { beforeinput: beforeinput }
67053
67227
  }
67054
67228
  });
67055
67229
  }
67056
- function buildCommand(redo, scroll) {
67057
- return (state, dispatch) => {
67058
- let hist = historyKey.getState(state);
67059
- if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
67060
- return false;
67061
- if (dispatch) {
67062
- let tr = histTransaction(hist, state, redo);
67063
- if (tr)
67064
- dispatch(scroll ? tr.scrollIntoView() : tr);
67230
+ const handleKeyDown = keydownHandler({
67231
+ "ArrowLeft": arrow("horiz", -1),
67232
+ "ArrowRight": arrow("horiz", 1),
67233
+ "ArrowUp": arrow("vert", -1),
67234
+ "ArrowDown": arrow("vert", 1)
67235
+ });
67236
+ function arrow(axis, dir) {
67237
+ const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
67238
+ return function (state, dispatch, view) {
67239
+ let sel = state.selection;
67240
+ let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
67241
+ if (sel instanceof TextSelection) {
67242
+ if (!view.endOfTextblock(dirStr) || $start.depth == 0)
67243
+ return false;
67244
+ mustMove = false;
67245
+ $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
67065
67246
  }
67247
+ let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
67248
+ if (!$found)
67249
+ return false;
67250
+ if (dispatch)
67251
+ dispatch(state.tr.setSelection(new GapCursor($found)));
67066
67252
  return true;
67067
67253
  };
67068
67254
  }
67069
- /**
67070
- A command function that undoes the last change, if any.
67071
- */
67072
- const undo = buildCommand(false, true);
67073
- /**
67074
- A command function that redoes the last undone change, if any.
67075
- */
67076
- const redo = buildCommand(true, true);
67255
+ function handleClick(view, pos, event) {
67256
+ if (!view || !view.editable)
67257
+ return false;
67258
+ let $pos = view.state.doc.resolve(pos);
67259
+ if (!GapCursor.valid($pos))
67260
+ return false;
67261
+ let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
67262
+ if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
67263
+ return false;
67264
+ view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
67265
+ return true;
67266
+ }
67267
+ // This is a hack that, when a composition starts while a gap cursor
67268
+ // is active, quickly creates an inline context for the composition to
67269
+ // happen in, to avoid it being aborted by the DOM selection being
67270
+ // moved into a valid position.
67271
+ function beforeinput(view, event) {
67272
+ if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
67273
+ return false;
67274
+ let { $from } = view.state.selection;
67275
+ let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
67276
+ if (!insert)
67277
+ return false;
67278
+ let frag = Fragment.empty;
67279
+ for (let i = insert.length - 1; i >= 0; i--)
67280
+ frag = Fragment.from(insert[i].createAndFill(null, frag));
67281
+ let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
67282
+ tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
67283
+ view.dispatch(tr);
67284
+ return false;
67285
+ }
67286
+ function drawGapCursor(state) {
67287
+ if (!(state.selection instanceof GapCursor))
67288
+ return null;
67289
+ let node = document.createElement("div");
67290
+ node.className = "ProseMirror-gapcursor";
67291
+ return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
67292
+ }
67077
67293
 
67078
67294
  //#region src/character-count/character-count.ts
67079
67295
  /**
@@ -97669,12 +97885,12 @@ focus outline in that case.
97669
97885
  toDOMStream(options) {
97670
97886
  return streamAdapters.toDOMStream((this._closedPromiseResolve || this._error)
97671
97887
  ? this
97672
- : this._values, options);
97888
+ : this._values);
97673
97889
  }
97674
97890
  toNodeStream(options) {
97675
97891
  return streamAdapters.toNodeStream((this._closedPromiseResolve || this._error)
97676
97892
  ? this
97677
- : this._values, options);
97893
+ : this._values);
97678
97894
  }
97679
97895
  throw(_) {
97680
97896
  return __awaiter(this, void 0, void 0, function* () { yield this.abort(_); return ITERATOR_DONE; });
@@ -100065,7 +100281,7 @@ focus outline in that case.
100065
100281
  toNodeStream() {
100066
100282
  return streamAdapters.toNodeStream((this.isSync()
100067
100283
  ? { [Symbol.iterator]: () => this }
100068
- : { [Symbol.asyncIterator]: () => this }), { objectMode: true });
100284
+ : { [Symbol.asyncIterator]: () => this }));
100069
100285
  }
100070
100286
  /** @nocollapse */
100071
100287
  // @ts-ignore
@@ -106734,15 +106950,17 @@ focus outline in that case.
106734
106950
  id="${(_, c) => `${c.parent.menuId}-option-${c.index}`}"
106735
106951
  class="chip-selector-option"
106736
106952
  data-option-value="${x => x}"
106953
+ aria-selected="${(_, c) => String(c.index === c.parent.activeOptionIndex)}"
106737
106954
  >
106738
106955
  ${x => x}
106739
106956
  </${menuItemTag}>
106740
- `)}
106957
+ `, { positioning: true })}
106741
106958
  ${when(x => x.customValueCandidate.length > 0, html `
106742
106959
  <${menuItemTag}
106743
106960
  id="${x => `${x.menuId}-option-create`}"
106744
106961
  class="chip-selector-option chip-selector-create-option"
106745
106962
  data-option-value="${x => x.customValueCandidate}"
106963
+ aria-selected="${x => String(x.activeOptionIndex === x.visibleOptionList.length)}"
106746
106964
  >
106747
106965
  ${x => x.createOptionLabel}
106748
106966
  </${menuItemTag}>
@@ -107007,10 +107225,6 @@ focus outline in that case.
107007
107225
  }
107008
107226
  }
107009
107227
  syncActiveOption() {
107010
- const options = Array.from(this.shadowRoot?.querySelectorAll('.chip-selector-option') ?? []);
107011
- options.forEach((option, index) => {
107012
- option.setAttribute('aria-selected', String(index === this.activeOptionIndex));
107013
- });
107014
107228
  if (this.activeOptionIndex < 0) {
107015
107229
  this.activeOptionId = null;
107016
107230
  }