@ni/spright-components 6.23.0 → 6.23.2

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.
@@ -20872,18 +20872,27 @@ Defines an interaction area clip-path that leaves out the severity text so it is
20872
20872
  }
20873
20873
 
20874
20874
  .icon {
20875
- width: 48px;
20876
- display: flex;
20877
- justify-content: center;
20878
- margin-top: 8px;
20875
+ display: none;
20876
+ margin: 8px ${smallPadding} 0 ${standardPadding};
20879
20877
  flex: 0 0 auto;
20880
20878
  opacity: 0.6;
20881
20879
  }
20882
20880
 
20881
+ :host([severity='error']) .icon,
20882
+ :host([severity='warning']) .icon,
20883
+ :host([severity='information']) .icon {
20884
+ display: flex;
20885
+ }
20886
+
20883
20887
  .text {
20884
20888
  display: inline;
20885
- margin-top: 7px;
20886
- margin-bottom: 7px;
20889
+ margin: 7px 0 7px ${standardPadding};
20890
+ }
20891
+
20892
+ :host([severity='error']) .text,
20893
+ :host([severity='warning']) .text,
20894
+ :host([severity='information']) .text {
20895
+ margin-left: 0;
20887
20896
  }
20888
20897
 
20889
20898
  slot[name='title'] {
@@ -20914,14 +20923,20 @@ Defines an interaction area clip-path that leaves out the severity text so it is
20914
20923
  white-space: nowrap;
20915
20924
  }
20916
20925
 
20926
+ :host([prevent-dismiss]) slot[name='action'] {
20927
+ margin-right: 12px;
20928
+ }
20929
+
20917
20930
  slot[name='action']::slotted(nimble-anchor) {
20918
20931
  font-size: 12.8px;
20919
20932
  }
20920
20933
 
20921
20934
  .dismiss {
20922
- width: 48px;
20923
- display: flex;
20924
- justify-content: center;
20935
+ margin: 0 12px 0 ${standardPadding};
20936
+ }
20937
+
20938
+ :host([prevent-dismiss]) .dismiss {
20939
+ display: none;
20925
20940
  }
20926
20941
  `.withBehaviors(themeBehavior(Theme.light, css `
20927
20942
  :host {
@@ -29797,7 +29812,6 @@ so this becomes the fallback color for the slot */ ''}
29797
29812
  if (!type)
29798
29813
  throw new RangeError(`There is no mark type ${json.type} in this schema`);
29799
29814
  let mark = type.create(json.attrs);
29800
- type.checkAttrs(mark.attrs);
29801
29815
  return mark;
29802
29816
  }
29803
29817
  /**
@@ -30777,11 +30791,11 @@ so this becomes the fallback color for the slot */ ''}
30777
30791
  */
30778
30792
  check() {
30779
30793
  this.type.checkContent(this.content);
30780
- this.type.checkAttrs(this.attrs);
30794
+ checkAttrs(this.type.attrs, this.attrs, "node", this.type.name);
30781
30795
  let copy = Mark$1.none;
30782
30796
  for (let i = 0; i < this.marks.length; i++) {
30783
30797
  let mark = this.marks[i];
30784
- mark.type.checkAttrs(mark.attrs);
30798
+ checkAttrs(mark.type.attrs, mark.attrs, "mark", mark.type.name);
30785
30799
  copy = mark.addToSet(copy);
30786
30800
  }
30787
30801
  if (!Mark$1.sameSet(copy, this.marks))
@@ -30822,7 +30836,6 @@ so this becomes the fallback color for the slot */ ''}
30822
30836
  }
30823
30837
  let content = Fragment.fromJSON(schema, json.content);
30824
30838
  let node = schema.nodeType(json.type).create(json.attrs, content, marks);
30825
- node.type.checkAttrs(node.attrs);
30826
30839
  return node;
30827
30840
  }
30828
30841
  };
@@ -30872,6 +30885,15 @@ so this becomes the fallback color for the slot */ ''}
30872
30885
  str = marks[i].type.name + "(" + str + ")";
30873
30886
  return str;
30874
30887
  }
30888
+ function checkAttrs(attrs, values, type, name) {
30889
+ for (let attr in values)
30890
+ if (!(attr in attrs))
30891
+ throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
30892
+ for (let attr in attrs) {
30893
+ if (attrs[attr].validate)
30894
+ attrs[attr].validate(values[attr]);
30895
+ }
30896
+ }
30875
30897
 
30876
30898
  /**
30877
30899
  Instances of this class represent a match state of a node type's
@@ -31326,27 +31348,21 @@ so this becomes the fallback color for the slot */ ''}
31326
31348
  function computeAttrs(attrs, value) {
31327
31349
  let built = Object.create(null);
31328
31350
  for (let name in attrs) {
31351
+ let attr = attrs[name];
31329
31352
  let given = value && value[name];
31330
31353
  if (given === undefined) {
31331
- let attr = attrs[name];
31332
31354
  if (attr.hasDefault)
31333
31355
  given = attr.default;
31334
31356
  else
31335
31357
  throw new RangeError("No value supplied for attribute " + name);
31336
31358
  }
31359
+ else if (attr.validate) {
31360
+ attr.validate(given);
31361
+ }
31337
31362
  built[name] = given;
31338
31363
  }
31339
31364
  return built;
31340
31365
  }
31341
- function checkAttrs(attrs, values, type, name) {
31342
- for (let attr in values)
31343
- if (!(attr in attrs))
31344
- throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
31345
- for (let attr in attrs) {
31346
- if (attrs[attr].validate)
31347
- attrs[attr].validate(values[attr]);
31348
- }
31349
- }
31350
31366
  function initAttrs(typeName, attrs) {
31351
31367
  let result = Object.create(null);
31352
31368
  if (attrs)
@@ -31518,11 +31534,9 @@ so this becomes the fallback color for the slot */ ''}
31518
31534
  throw new RangeError(`Invalid content for node ${this.name}: ${content.toString().slice(0, 50)}`);
31519
31535
  }
31520
31536
  /**
31521
- @internal
31537
+ @internal no longer useful, but called by old prosemirror-view versions
31522
31538
  */
31523
- checkAttrs(attrs) {
31524
- checkAttrs(this.attrs, attrs, "node", this.name);
31525
- }
31539
+ checkAttrs(attrs) { }
31526
31540
  /**
31527
31541
  Check whether the given mark type is allowed in this node.
31528
31542
  */
@@ -31669,12 +31683,6 @@ so this becomes the fallback color for the slot */ ''}
31669
31683
  return set[i];
31670
31684
  }
31671
31685
  /**
31672
- @internal
31673
- */
31674
- checkAttrs(attrs) {
31675
- checkAttrs(this.attrs, attrs, "mark", this.name);
31676
- }
31677
- /**
31678
31686
  Queries whether a given mark type is
31679
31687
  [excluded](https://prosemirror.net/docs/ref/#model.MarkSpec.excludes) by this one.
31680
31688
  */
@@ -32865,9 +32873,12 @@ so this becomes the fallback color for the slot */ ''}
32865
32873
  if (simple)
32866
32874
  return result;
32867
32875
  let recover = pos == (assoc < 0 ? start : end) ? null : makeRecover(i / 3, pos - start);
32868
- let del = pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32869
- if (assoc < 0 ? pos != start : pos != end)
32870
- del |= DEL_SIDE;
32876
+ let del = 0;
32877
+ if (oldSize) {
32878
+ del |= pos == start ? DEL_AFTER : pos == end ? DEL_BEFORE : DEL_ACROSS;
32879
+ if (assoc < 0 ? pos != start : pos != end)
32880
+ del |= DEL_SIDE;
32881
+ }
32871
32882
  return new MapResult(result, del, recover);
32872
32883
  }
32873
32884
  diff += newSize - oldSize;
@@ -36805,15 +36816,15 @@ so this becomes the fallback color for the slot */ ''}
36805
36816
  return true;
36806
36817
  if (off == (dir < 0 ? 0 : nodeSize(node))) {
36807
36818
  let parent = node.parentNode;
36808
- if (!parent || parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36819
+ if (!parent || !isElt(parent) || hasBlockDesc(node) || atomElements.test(node.nodeName) ||
36809
36820
  node.contentEditable == "false")
36810
36821
  return false;
36811
36822
  off = domIndex(node) + (dir < 0 ? 0 : 1);
36812
36823
  node = parent;
36813
36824
  }
36814
- else if (node.nodeType == 1) {
36825
+ else if (isElt(node)) {
36815
36826
  let child = node.childNodes[off + (dir < 0 ? -1 : 0)];
36816
- if (child.nodeType == 1 && child.contentEditable == "false") {
36827
+ if (isElt(child) && child.contentEditable == "false") {
36817
36828
  if ((_a = child.pmViewDesc) === null || _a === void 0 ? void 0 : _a.ignoreForSelection)
36818
36829
  off += dir;
36819
36830
  else
@@ -36832,11 +36843,16 @@ so this becomes the fallback color for the slot */ ''}
36832
36843
  function nodeSize(node) {
36833
36844
  return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
36834
36845
  }
36846
+ function isElt(node) { return node.nodeType == 1; }
36847
+ function isText(node) { return node.nodeType == 3; }
36848
+ function contains(parent, child) {
36849
+ return child ? parent.contains(isElt(child) ? child : child.parentNode) : false;
36850
+ }
36835
36851
  function textNodeBefore$1(node, offset) {
36836
36852
  for (;;) {
36837
- if (node.nodeType == 3 && offset)
36853
+ if (isText(node) && offset)
36838
36854
  return node;
36839
- if (node.nodeType == 1 && offset > 0) {
36855
+ if (isElt(node) && offset > 0) {
36840
36856
  if (node.contentEditable == "false")
36841
36857
  return null;
36842
36858
  node = node.childNodes[offset - 1];
@@ -36853,9 +36869,9 @@ so this becomes the fallback color for the slot */ ''}
36853
36869
  }
36854
36870
  function textNodeAfter$1(node, offset) {
36855
36871
  for (;;) {
36856
- if (node.nodeType == 3 && offset < node.nodeValue.length)
36872
+ if (isText(node) && offset < node.nodeValue.length)
36857
36873
  return node;
36858
- if (node.nodeType == 1 && offset < node.childNodes.length) {
36874
+ if (isElt(node) && offset < node.childNodes.length) {
36859
36875
  if (node.contentEditable == "false")
36860
36876
  return null;
36861
36877
  node = node.childNodes[offset];
@@ -36979,13 +36995,12 @@ so this becomes the fallback color for the slot */ ''}
36979
36995
  for (let parent = startDOM || view.dom;;) {
36980
36996
  if (!parent)
36981
36997
  break;
36982
- if (parent.nodeType != 1) {
36998
+ if (!isElt(parent)) {
36983
36999
  parent = parentNode(parent);
36984
37000
  continue;
36985
37001
  }
36986
- let elt = parent;
36987
- let atTop = elt == doc.body;
36988
- let bounding = atTop ? windowRect(doc) : clientRect(elt);
37002
+ let atTop = parent == doc.body;
37003
+ let bounding = atTop ? windowRect(doc) : clientRect(parent);
36989
37004
  let moveX = 0, moveY = 0;
36990
37005
  if (rect.top < bounding.top + getSide$1(scrollThreshold, "top"))
36991
37006
  moveY = -(bounding.top - rect.top + getSide$1(scrollMargin, "top"));
@@ -37002,12 +37017,12 @@ so this becomes the fallback color for the slot */ ''}
37002
37017
  doc.defaultView.scrollBy(moveX, moveY);
37003
37018
  }
37004
37019
  else {
37005
- let startX = elt.scrollLeft, startY = elt.scrollTop;
37020
+ let startX = parent.scrollLeft, startY = parent.scrollTop;
37006
37021
  if (moveY)
37007
- elt.scrollTop += moveY;
37022
+ parent.scrollTop += moveY;
37008
37023
  if (moveX)
37009
- elt.scrollLeft += moveX;
37010
- let dX = elt.scrollLeft - startX, dY = elt.scrollTop - startY;
37024
+ parent.scrollLeft += moveX;
37025
+ let dX = parent.scrollLeft - startX, dY = parent.scrollTop - startY;
37011
37026
  rect = { left: rect.left - dX, top: rect.top - dY, right: rect.right - dX, bottom: rect.bottom - dY };
37012
37027
  }
37013
37028
  }
@@ -37082,14 +37097,15 @@ so this becomes the fallback color for the slot */ ''}
37082
37097
  }
37083
37098
  }
37084
37099
  function findOffsetInNode(node, coords) {
37085
- let closest, dxClosest = 2e8, coordsClosest, offset = 0;
37100
+ let closest;
37101
+ let dxClosest = 2e8, coordsClosest, offset = 0;
37086
37102
  let rowBot = coords.top, rowTop = coords.top;
37087
37103
  let firstBelow, coordsBelow;
37088
37104
  for (let child = node.firstChild, childIndex = 0; child; child = child.nextSibling, childIndex++) {
37089
37105
  let rects;
37090
- if (child.nodeType == 1)
37106
+ if (isElt(child))
37091
37107
  rects = child.getClientRects();
37092
- else if (child.nodeType == 3)
37108
+ else if (isText(child))
37093
37109
  rects = textRange(child).getClientRects();
37094
37110
  else
37095
37111
  continue;
@@ -37103,11 +37119,11 @@ so this becomes the fallback color for the slot */ ''}
37103
37119
  if (dx < dxClosest) {
37104
37120
  closest = child;
37105
37121
  dxClosest = dx;
37106
- coordsClosest = dx && closest.nodeType == 3 ? {
37122
+ coordsClosest = dx && isText(closest) ? {
37107
37123
  left: rect.right < coords.left ? rect.right : rect.left,
37108
37124
  top: coords.top
37109
37125
  } : coords;
37110
- if (child.nodeType == 1 && dx)
37126
+ if (isElt(child) && dx)
37111
37127
  offset = childIndex + (coords.left >= (rect.left + rect.right) / 2 ? 1 : 0);
37112
37128
  continue;
37113
37129
  }
@@ -37126,9 +37142,9 @@ so this becomes the fallback color for the slot */ ''}
37126
37142
  coordsClosest = coordsBelow;
37127
37143
  dxClosest = 0;
37128
37144
  }
37129
- if (closest && closest.nodeType == 3)
37145
+ if (closest && isText(closest))
37130
37146
  return findOffsetInText(closest, coordsClosest);
37131
- if (!closest || (dxClosest && closest.nodeType == 1))
37147
+ if (!closest || dxClosest)
37132
37148
  return { node, offset };
37133
37149
  return findOffsetInNode(closest, coordsClosest);
37134
37150
  }
@@ -37161,7 +37177,7 @@ so this becomes the fallback color for the slot */ ''}
37161
37177
  }
37162
37178
  function posFromElement(view, elt, coords) {
37163
37179
  let { node, offset } = findOffsetInNode(elt, coords), bias = -1;
37164
- if (node.nodeType == 1 && !node.firstChild) {
37180
+ if (isElt(node) && !node.firstChild) {
37165
37181
  let rect = node.getBoundingClientRect();
37166
37182
  bias = rect.left != rect.right && coords.left > (rect.left + rect.right) / 2 ? 1 : -1;
37167
37183
  }
@@ -37181,7 +37197,7 @@ so this becomes the fallback color for the slot */ ''}
37181
37197
  let desc = view.docView.nearestDesc(cur, true), rect;
37182
37198
  if (!desc)
37183
37199
  return null;
37184
- if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37200
+ if (isElt(desc.dom) && (desc.node.isBlock && desc.parent || !desc.contentDOM) &&
37185
37201
  // Ignore elements with zero-size bounding rectangles
37186
37202
  ((rect = desc.dom.getBoundingClientRect()).width || rect.height)) {
37187
37203
  if (desc.node.isBlock && desc.parent && !/^T(R|BODY|HEAD|FOOT)$/.test(desc.dom.nodeName)) {
@@ -37208,7 +37224,7 @@ so this becomes the fallback color for the slot */ ''}
37208
37224
  if (len && box.top < box.bottom) {
37209
37225
  for (let startI = Math.max(0, Math.min(len - 1, Math.floor(len * (coords.top - box.top) / (box.bottom - box.top)) - 2)), i = startI;;) {
37210
37226
  let child = element.childNodes[i];
37211
- if (child.nodeType == 1) {
37227
+ if (isElt(child)) {
37212
37228
  let rects = child.getClientRects();
37213
37229
  for (let j = 0; j < rects.length; j++) {
37214
37230
  let rect = rects[j];
@@ -37231,7 +37247,7 @@ so this becomes the fallback color for the slot */ ''}
37231
37247
  let elt = (view.root.elementFromPoint ? view.root : doc)
37232
37248
  .elementFromPoint(coords.left, coords.top);
37233
37249
  let pos;
37234
- if (!elt || !view.dom.contains(elt.nodeType != 1 ? elt.parentNode : elt)) {
37250
+ if (!elt || !view.dom.contains(elt)) {
37235
37251
  let box = view.dom.getBoundingClientRect();
37236
37252
  if (!inRect(coords, box))
37237
37253
  return null;
@@ -37247,7 +37263,7 @@ so this becomes the fallback color for the slot */ ''}
37247
37263
  }
37248
37264
  elt = targetKludge(elt, coords);
37249
37265
  if (node) {
37250
- if (gecko && node.nodeType == 1) {
37266
+ if (gecko && isElt(node)) {
37251
37267
  // Firefox will sometimes return offsets into <input> nodes, which
37252
37268
  // have no actual children, from caretPositionFromPoint (#953)
37253
37269
  offset = Math.min(offset, node.childNodes.length);
@@ -37262,18 +37278,18 @@ so this becomes the fallback color for the slot */ ''}
37262
37278
  }
37263
37279
  let prev;
37264
37280
  // When clicking above the right side of an uneditable node, Chrome will report a cursor position after that node.
37265
- if (webkit && offset && node.nodeType == 1 && (prev = node.childNodes[offset - 1]).nodeType == 1 &&
37281
+ if (webkit && offset && isElt(node) && isElt(prev = node.childNodes[offset - 1]) &&
37266
37282
  prev.contentEditable == "false" && prev.getBoundingClientRect().top >= coords.top)
37267
37283
  offset--;
37268
37284
  // Suspiciously specific kludge to work around caret*FromPoint
37269
37285
  // never returning a position at the end of the document
37270
- if (node == view.dom && offset == node.childNodes.length - 1 && node.lastChild.nodeType == 1 &&
37286
+ if (node == view.dom && offset == node.childNodes.length - 1 && isElt(node.lastChild) &&
37271
37287
  coords.top > node.lastChild.getBoundingClientRect().bottom)
37272
37288
  pos = view.state.doc.content.size;
37273
37289
  // Ignore positions directly after a BR, since caret*FromPoint
37274
37290
  // 'round up' positions that would be more accurately placed
37275
37291
  // before the BR node.
37276
- else if (offset == 0 || node.nodeType != 1 || node.childNodes[offset - 1].nodeName != "BR")
37292
+ else if (offset == 0 || !isElt(node) || node.childNodes[offset - 1].nodeName != "BR")
37277
37293
  pos = posFromCaret(view, node, offset, coords);
37278
37294
  }
37279
37295
  if (pos == null)
@@ -37299,7 +37315,7 @@ so this becomes the fallback color for the slot */ ''}
37299
37315
  function coordsAtPos(view, pos, side) {
37300
37316
  let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
37301
37317
  let supportEmptyRange = webkit || gecko;
37302
- if (node.nodeType == 3) {
37318
+ if (isText(node)) {
37303
37319
  // These browsers support querying empty text ranges. Prefer that in
37304
37320
  // bidi context or when at the end of a node.
37305
37321
  if (supportEmptyRange && (BIDI.test(node.nodeValue) || (side < 0 ? !offset : offset == node.nodeValue.length))) {
@@ -37341,12 +37357,12 @@ so this becomes the fallback color for the slot */ ''}
37341
37357
  if (!$dom.parent.inlineContent) {
37342
37358
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37343
37359
  let before = node.childNodes[offset - 1];
37344
- if (before.nodeType == 1)
37360
+ if (isElt(before))
37345
37361
  return flattenH(before.getBoundingClientRect(), false);
37346
37362
  }
37347
37363
  if (atom == null && offset < nodeSize(node)) {
37348
37364
  let after = node.childNodes[offset];
37349
- if (after.nodeType == 1)
37365
+ if (isElt(after))
37350
37366
  return flattenH(after.getBoundingClientRect(), true);
37351
37367
  }
37352
37368
  return flattenH(node.getBoundingClientRect(), side >= 0);
@@ -37354,10 +37370,10 @@ so this becomes the fallback color for the slot */ ''}
37354
37370
  // Inline, not in text node (this is not Bidi-safe)
37355
37371
  if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
37356
37372
  let before = node.childNodes[offset - 1];
37357
- let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37373
+ let target = isText(before) ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
37358
37374
  // BR nodes tend to only return the rectangle before them.
37359
37375
  // Only use them if they are the last element in their parent
37360
- : before.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37376
+ : isElt(before) && (before.nodeName != "BR" || !before.nextSibling) ? before : null;
37361
37377
  if (target)
37362
37378
  return flattenV(singleRect(target, 1), false);
37363
37379
  }
@@ -37365,13 +37381,13 @@ so this becomes the fallback color for the slot */ ''}
37365
37381
  let after = node.childNodes[offset];
37366
37382
  while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)
37367
37383
  after = after.nextSibling;
37368
- let target = !after ? null : after.nodeType == 3 ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37369
- : after.nodeType == 1 ? after : null;
37384
+ let target = !after ? null : isText(after) ? textRange(after, 0, (supportEmptyRange ? 0 : 1))
37385
+ : isElt(after) ? after : null;
37370
37386
  if (target)
37371
37387
  return flattenV(singleRect(target, -1), true);
37372
37388
  }
37373
37389
  // All else failed, just try to get a rectangle for the target node
37374
- return flattenV(singleRect(node.nodeType == 3 ? textRange(node) : node, -side), side >= 0);
37390
+ return flattenV(singleRect(isText(node) ? textRange(node) : node, -side), side >= 0);
37375
37391
  }
37376
37392
  function flattenV(rect, left) {
37377
37393
  if (rect.width == 0)
@@ -37421,9 +37437,9 @@ so this becomes the fallback color for the slot */ ''}
37421
37437
  let coords = coordsAtPos(view, $pos.pos, 1);
37422
37438
  for (let child = dom.firstChild; child; child = child.nextSibling) {
37423
37439
  let boxes;
37424
- if (child.nodeType == 1)
37440
+ if (isElt(child))
37425
37441
  boxes = child.getClientRects();
37426
- else if (child.nodeType == 3)
37442
+ else if (isText(child))
37427
37443
  boxes = textRange(child, 0, child.nodeValue.length).getClientRects();
37428
37444
  else
37429
37445
  continue;
@@ -37463,8 +37479,7 @@ so this becomes the fallback color for the slot */ ''}
37463
37479
  sel.modify("move", dir, "character");
37464
37480
  let parentDOM = $head.depth ? view.docView.domAfterPos($head.before()) : view.dom;
37465
37481
  let { focusNode: newNode, focusOffset: newOff } = view.domSelectionRange();
37466
- let result = newNode && !parentDOM.contains(newNode.nodeType == 1 ? newNode : newNode.parentNode) ||
37467
- (oldNode == newNode && oldOff == newOff);
37482
+ let result = newNode && !contains(parentDOM, newNode) || (oldNode == newNode && oldOff == newOff);
37468
37483
  // Restore the previous selection
37469
37484
  try {
37470
37485
  sel.collapse(anchorNode, anchorOffset);
@@ -37572,7 +37587,7 @@ so this becomes the fallback color for the slot */ ''}
37572
37587
  localPosFromDOM(dom, offset, bias) {
37573
37588
  // If the DOM position is in the content, use the child desc after
37574
37589
  // it to figure out a position.
37575
- if (this.contentDOM && this.contentDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode)) {
37590
+ if (this.contentDOM && contains(this.contentDOM, dom)) {
37576
37591
  if (bias < 0) {
37577
37592
  let domBefore, desc;
37578
37593
  if (dom == this.contentDOM) {
@@ -37610,7 +37625,7 @@ so this becomes the fallback color for the slot */ ''}
37610
37625
  atEnd = offset > domIndex(this.contentDOM);
37611
37626
  }
37612
37627
  else if (this.contentDOM && this.contentDOM != this.dom && this.dom.contains(this.contentDOM)) {
37613
- atEnd = dom.compareDocumentPosition(this.contentDOM) & 2;
37628
+ atEnd = !!(dom.compareDocumentPosition(this.contentDOM) & 4);
37614
37629
  }
37615
37630
  else if (this.dom.firstChild) {
37616
37631
  if (offset == 0)
@@ -37640,7 +37655,7 @@ so this becomes the fallback color for the slot */ ''}
37640
37655
  if (desc && (!onlyNodes || desc.node)) {
37641
37656
  // If dom is outside of this desc's nodeDOM, don't count it.
37642
37657
  if (first && (nodeDOM = desc.nodeDOM) &&
37643
- !(nodeDOM.nodeType == 1 ? nodeDOM.contains(dom.nodeType == 1 ? dom : dom.parentNode) : nodeDOM == dom))
37658
+ !(isElt(nodeDOM) ? contains(nodeDOM, dom) : nodeDOM == dom))
37644
37659
  first = false;
37645
37660
  else
37646
37661
  return desc;
@@ -37690,7 +37705,7 @@ so this becomes the fallback color for the slot */ ''}
37690
37705
  let i = 0, offset = 0;
37691
37706
  for (let curPos = 0; i < this.children.length; i++) {
37692
37707
  let child = this.children[i], end = curPos + child.size;
37693
- if (end > pos || child instanceof TrailingHackViewDesc) {
37708
+ if (end > pos) {
37694
37709
  offset = pos - curPos;
37695
37710
  break;
37696
37711
  }
@@ -37700,7 +37715,11 @@ so this becomes the fallback color for the slot */ ''}
37700
37715
  if (offset)
37701
37716
  return this.children[i].domFromPos(offset - this.children[i].border, side);
37702
37717
  // Go back if there were any zero-length widgets with side >= 0 before this point
37703
- for (let prev; i && !(prev = this.children[i - 1]).size && prev instanceof WidgetViewDesc && prev.side >= 0; i--) { }
37718
+ for (; i > 0; i--) {
37719
+ let prev = this.children[i - 1];
37720
+ if (prev.size || !(prev instanceof BufferHackViewDesc || prev instanceof WidgetViewDesc && prev.side >= 0))
37721
+ break;
37722
+ }
37704
37723
  // Scan towards the first useable node
37705
37724
  if (side <= 0) {
37706
37725
  let prev, enter = true;
@@ -37777,7 +37796,7 @@ so this becomes the fallback color for the slot */ ''}
37777
37796
  }
37778
37797
  domAfterPos(pos) {
37779
37798
  let { node, offset } = this.domFromPos(pos, 0);
37780
- if (node.nodeType != 1 || offset == node.childNodes.length)
37799
+ if (!isElt(node) || offset == node.childNodes.length)
37781
37800
  throw new RangeError("No node after pos " + pos);
37782
37801
  return node.childNodes[offset];
37783
37802
  }
@@ -37806,7 +37825,7 @@ so this becomes the fallback color for the slot */ ''}
37806
37825
  // reported position in such situations (#1092).
37807
37826
  if ((gecko || safari) && anchor == head) {
37808
37827
  let { node, offset } = anchorDOM;
37809
- if (node.nodeType == 3) {
37828
+ if (isText(node)) {
37810
37829
  brKludge = !!(offset && node.nodeValue[offset - 1] == "\n");
37811
37830
  // Issue #1128
37812
37831
  if (brKludge && offset == node.nodeValue.length) {
@@ -37829,7 +37848,7 @@ so this becomes the fallback color for the slot */ ''}
37829
37848
  }
37830
37849
  // Firefox can act strangely when the selection is in front of an
37831
37850
  // uneditable node. See #1163 and https://bugzilla.mozilla.org/show_bug.cgi?id=1709536
37832
- if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && selRange.focusNode.nodeType == 1) {
37851
+ if (gecko && selRange.focusNode && selRange.focusNode != headDOM.node && isElt(selRange.focusNode)) {
37833
37852
  let after = selRange.focusNode.childNodes[selRange.focusOffset];
37834
37853
  if (after && after.contentEditable == "false")
37835
37854
  force = true;
@@ -37928,14 +37947,12 @@ so this becomes the fallback color for the slot */ ''}
37928
37947
  return self.parent.posBeforeChild(self);
37929
37948
  });
37930
37949
  if (!widget.type.spec.raw) {
37931
- if (dom.nodeType != 1) {
37932
- let wrap = document.createElement("span");
37933
- wrap.appendChild(dom);
37934
- dom = wrap;
37935
- }
37936
- if (!dom.hasAttribute("contenteditable"))
37937
- dom.contentEditable = "false";
37938
- dom.classList.add("ProseMirror-widget");
37950
+ let elt = isElt(dom) ? dom : document.createElement("span");
37951
+ if (elt != dom)
37952
+ elt.appendChild(dom);
37953
+ if (!elt.hasAttribute("contenteditable"))
37954
+ elt.contentEditable = "false";
37955
+ elt.classList.add("ProseMirror-widget");
37939
37956
  }
37940
37957
  super(parent, [], dom, null);
37941
37958
  this.widget = widget;
@@ -38071,7 +38088,7 @@ so this becomes the fallback color for the slot */ ''}
38071
38088
  if (node.isText) {
38072
38089
  if (!dom)
38073
38090
  dom = document.createTextNode(node.text);
38074
- else if (dom.nodeType != 3)
38091
+ else if (!isText(dom))
38075
38092
  throw new RangeError("Text must be rendered as a DOM text node");
38076
38093
  }
38077
38094
  else if (!dom) {
@@ -38123,7 +38140,7 @@ so this becomes the fallback color for the slot */ ''}
38123
38140
  }
38124
38141
  if (!rule.contentElement) {
38125
38142
  let found = addedNodes &&
38126
- addedNodes.find(n => n.nodeType == 1 && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38143
+ addedNodes.find(n => isElt(n) && addedNodes.indexOf(n.parentNode) < 0 && this.dom.contains(n));
38127
38144
  if (found)
38128
38145
  rule.contentElement = found;
38129
38146
  else
@@ -38148,6 +38165,7 @@ so this becomes the fallback color for the slot */ ''}
38148
38165
  let localComposition = composition && composition.pos > -1 ? composition : null;
38149
38166
  let compositionInChild = composition && composition.pos < 0;
38150
38167
  let updater = new ViewTreeUpdater(this, localComposition && localComposition.node, view);
38168
+ let addBuffers = this.node.inlineContent, atBufferPos = addBuffers && this.node.isBlock;
38151
38169
  iterDeco(this.node, this.innerDeco, (widget, i, insideNode) => {
38152
38170
  if (widget.spec.marks)
38153
38171
  updater.syncToMarks(widget.spec.marks, inline, view, i);
@@ -38159,6 +38177,8 @@ so this becomes the fallback color for the slot */ ''}
38159
38177
  }, (child, outerDeco, innerDeco, i) => {
38160
38178
  // Make sure the wrapping mark descs match the node's marks.
38161
38179
  updater.syncToMarks(child.marks, inline, view, i);
38180
+ if (atBufferPos && child.isAtom && !child.isText)
38181
+ updater.addHackNode("IMG", updater.top);
38162
38182
  // Try several strategies for drawing this node
38163
38183
  let compIndex;
38164
38184
  if (updater.findNodeMatch(child, outerDeco, innerDeco, i)) ;
@@ -38172,6 +38192,8 @@ so this becomes the fallback color for the slot */ ''}
38172
38192
  updater.addNode(child, outerDeco, innerDeco, view, off);
38173
38193
  }
38174
38194
  off += child.nodeSize;
38195
+ if (addBuffers)
38196
+ atBufferPos = child.isAtom && !child.isText;
38175
38197
  });
38176
38198
  // Drop all remaining descs after the current position.
38177
38199
  updater.syncToMarks([], inline, view, 0);
@@ -38250,7 +38272,7 @@ so this becomes the fallback color for the slot */ ''}
38250
38272
  updateOuterDeco(outerDeco) {
38251
38273
  if (sameOuterDeco(outerDeco, this.outerDeco))
38252
38274
  return;
38253
- let needsWrap = this.nodeDOM.nodeType != 1;
38275
+ let needsWrap = !isElt(this.nodeDOM);
38254
38276
  let oldDOM = this.dom;
38255
38277
  this.dom = patchOuterDeco(this.dom, this.nodeDOM, computeOuterDeco(this.outerDeco, this.node, needsWrap), computeOuterDeco(outerDeco, this.node, needsWrap));
38256
38278
  if (this.dom != oldDOM) {
@@ -38261,7 +38283,7 @@ so this becomes the fallback color for the slot */ ''}
38261
38283
  }
38262
38284
  // Mark this node as being the selected node.
38263
38285
  selectNode() {
38264
- if (this.nodeDOM.nodeType == 1) {
38286
+ if (isElt(this.nodeDOM)) {
38265
38287
  this.nodeDOM.classList.add("ProseMirror-selectednode");
38266
38288
  if (this.contentDOM || !this.node.type.spec.draggable)
38267
38289
  this.nodeDOM.draggable = true;
@@ -38269,7 +38291,7 @@ so this becomes the fallback color for the slot */ ''}
38269
38291
  }
38270
38292
  // Remove selected node marking from this node.
38271
38293
  deselectNode() {
38272
- if (this.nodeDOM.nodeType == 1) {
38294
+ if (isElt(this.nodeDOM)) {
38273
38295
  this.nodeDOM.classList.remove("ProseMirror-selectednode");
38274
38296
  if (this.contentDOM || !this.node.type.spec.draggable)
38275
38297
  this.nodeDOM.removeAttribute("draggable");
@@ -38340,9 +38362,9 @@ so this becomes the fallback color for the slot */ ''}
38340
38362
  get domAtom() { return false; }
38341
38363
  isText(text) { return this.node.text == text; }
38342
38364
  }
38343
- // A dummy desc used to tag trailing BR or IMG nodes created to work
38365
+ // A dummy desc used to tag extra BR or IMG nodes created to work
38344
38366
  // around contentEditable terribleness.
38345
- class TrailingHackViewDesc extends ViewDesc {
38367
+ class BufferHackViewDesc extends ViewDesc {
38346
38368
  parseRule() { return { ignore: true }; }
38347
38369
  matchesHack(nodeName) { return this.dirty == NOT_DIRTY && this.dom.nodeName == nodeName; }
38348
38370
  get domAtom() { return true; }
@@ -38515,7 +38537,7 @@ so this becomes the fallback color for the slot */ ''}
38515
38537
  }
38516
38538
  }
38517
38539
  function applyOuterDeco(dom, deco, node) {
38518
- return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, dom.nodeType != 1));
38540
+ return patchOuterDeco(dom, dom, noDeco, computeOuterDeco(deco, node, !isElt(dom)));
38519
38541
  }
38520
38542
  function sameOuterDeco(a, b) {
38521
38543
  if (a.length != b.length)
@@ -38778,7 +38800,7 @@ so this becomes the fallback color for the slot */ ''}
38778
38800
  }
38779
38801
  if (nodeName == "BR")
38780
38802
  dom.className = "ProseMirror-trailingBreak";
38781
- let hack = new TrailingHackViewDesc(this.top, [], dom, null);
38803
+ let hack = new BufferHackViewDesc(this.top, [], dom, null);
38782
38804
  if (parent != this.top)
38783
38805
  parent.children.push(hack);
38784
38806
  else
@@ -38787,7 +38809,7 @@ so this becomes the fallback color for the slot */ ''}
38787
38809
  }
38788
38810
  }
38789
38811
  isLocked(node) {
38790
- return this.lock && (node == this.lock || node.nodeType == 1 && node.contains(this.lock.parentNode));
38812
+ return this.lock && (node == this.lock || isElt(node) && node.contains(this.lock.parentNode));
38791
38813
  }
38792
38814
  }
38793
38815
  // Iterate from the end of the fragment and array of descs to find
@@ -38989,12 +39011,27 @@ so this becomes the fallback color for the slot */ ''}
38989
39011
  anchor = head;
38990
39012
  while (nearestDesc && !nearestDesc.node)
38991
39013
  nearestDesc = nearestDesc.parent;
38992
- let nearestDescNode = nearestDesc.node;
38993
- if (nearestDesc && nearestDescNode.isAtom && NodeSelection.isSelectable(nearestDescNode) && nearestDesc.parent
38994
- && !(nearestDescNode.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
39014
+ if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) &&
39015
+ nearestDesc.parent &&
39016
+ !(nearestDesc.node.isInline && isOnEdge(domSel.focusNode, domSel.focusOffset, nearestDesc.dom))) {
38995
39017
  let pos = nearestDesc.posBefore;
38996
39018
  selection = new NodeSelection(head == pos ? $head : doc.resolve(pos));
38997
39019
  }
39020
+ else if (gecko && origin == "key" && head > view.state.selection.to &&
39021
+ isElt(domSel.focusNode) && domSel.focusOffset == domSel.focusNode.childNodes.length &&
39022
+ nearestDesc && nearestDesc.posAtStart > view.state.selection.to) {
39023
+ // Firefox will jump across scrollable wrapper nodes on keyboard
39024
+ // cursor motion (#1594). This tries to detect this situation
39025
+ // and work around it.
39026
+ for (let scan = domSel.focusNode;; scan = scan.parentNode) {
39027
+ if (getComputedStyle(scan).overflow != "visible") {
39028
+ selection = Selection$2.findFrom(doc.resolve(nearestDesc.posAtStart), 1);
39029
+ break;
39030
+ }
39031
+ if (scan == nearestDesc.dom || scan.nextSibling || !scan.parentNode || !isElt(scan.parentNode))
39032
+ break;
39033
+ }
39034
+ }
38998
39035
  }
38999
39036
  else {
39000
39037
  if (domSel instanceof view.dom.ownerDocument.defaultView.Selection && domSel.rangeCount > 1) {
@@ -39180,8 +39217,7 @@ so this becomes the fallback color for the slot */ ''}
39180
39217
  // Firefox will raise 'permission denied' errors when accessing
39181
39218
  // properties of `sel.anchorNode` when it's in a generated CSS
39182
39219
  // element.
39183
- return view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode) &&
39184
- (view.editable || view.dom.contains(sel.focusNode.nodeType == 3 ? sel.focusNode.parentNode : sel.focusNode));
39220
+ return contains(view.dom, sel.anchorNode) && (view.editable || contains(view.dom, sel.focusNode));
39185
39221
  }
39186
39222
  catch (_) {
39187
39223
  return false;
@@ -39232,15 +39268,14 @@ so this becomes the fallback color for the slot */ ''}
39232
39268
  if (NodeSelection.isSelectable(node)) {
39233
39269
  return apply(view, new NodeSelection(dir < 0 ? view.state.doc.resolve($head.pos - node.nodeSize) : $head));
39234
39270
  }
39235
- else if (webkit) {
39271
+ else {
39236
39272
  // Chrome and Safari will introduce extra pointless cursor
39237
- // positions around inline uneditable nodes, so we have to
39238
- // take over and move the cursor past them (#937)
39273
+ // positions around inline uneditable nodes (#937), and
39274
+ // Firefox will sometimes just plain refuse to move across
39275
+ // them (#1592), so in this situation we move the cursor
39276
+ // ourselves.
39239
39277
  return apply(view, new TextSelection(view.state.doc.resolve(dir < 0 ? nodePos : nodePos + node.nodeSize)));
39240
39278
  }
39241
- else {
39242
- return false;
39243
- }
39244
39279
  }
39245
39280
  }
39246
39281
  else if (sel instanceof NodeSelection && sel.node.isInline) {
@@ -39253,12 +39288,10 @@ so this becomes the fallback color for the slot */ ''}
39253
39288
  return false;
39254
39289
  }
39255
39290
  }
39256
- function nodeLen(node) {
39257
- return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
39258
- }
39259
39291
  function isIgnorable(dom, dir) {
39260
39292
  let desc = dom.pmViewDesc;
39261
- return desc && desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR");
39293
+ return desc ? desc.size == 0 && (dir < 0 || dom.nextSibling || dom.nodeName != "BR")
39294
+ : isElt(dom) && dom.contentEditable == "false";
39262
39295
  }
39263
39296
  function skipIgnoredNodes(view, dir) {
39264
39297
  return dir < 0 ? skipIgnoredNodesBefore(view) : skipIgnoredNodesAfter(view);
@@ -39274,25 +39307,23 @@ so this becomes the fallback color for the slot */ ''}
39274
39307
  // Gecko will do odd things when the selection is directly in front
39275
39308
  // of a non-editable node, so in that case, move it into the next
39276
39309
  // node if possible. Issue prosemirror/prosemirror#832.
39277
- if (gecko && node.nodeType == 1 && offset < nodeLen(node) && isIgnorable(node.childNodes[offset], -1))
39310
+ if (gecko && isElt(node) && offset < nodeSize(node) && isIgnorable(node.childNodes[offset], -1))
39278
39311
  force = true;
39279
39312
  for (;;) {
39280
39313
  if (offset > 0) {
39281
- if (node.nodeType != 1) {
39314
+ if (!isElt(node))
39282
39315
  break;
39316
+ let before = node.childNodes[offset - 1];
39317
+ if (isIgnorable(before, -1)) {
39318
+ moveNode = node;
39319
+ moveOffset = --offset;
39320
+ }
39321
+ else if (isText(before)) {
39322
+ node = before;
39323
+ offset = node.nodeValue.length;
39283
39324
  }
39284
39325
  else {
39285
- let before = node.childNodes[offset - 1];
39286
- if (isIgnorable(before, -1)) {
39287
- moveNode = node;
39288
- moveOffset = --offset;
39289
- }
39290
- else if (before.nodeType == 3) {
39291
- node = before;
39292
- offset = node.nodeValue.length;
39293
- }
39294
- else
39295
- break;
39326
+ break;
39296
39327
  }
39297
39328
  }
39298
39329
  else if (isBlockNode(node)) {
@@ -39313,7 +39344,7 @@ so this becomes the fallback color for the slot */ ''}
39313
39344
  }
39314
39345
  else {
39315
39346
  node = prev;
39316
- offset = nodeLen(node);
39347
+ offset = nodeSize(node);
39317
39348
  }
39318
39349
  }
39319
39350
  }
@@ -39329,19 +39360,20 @@ so this becomes the fallback color for the slot */ ''}
39329
39360
  let node = sel.focusNode, offset = sel.focusOffset;
39330
39361
  if (!node)
39331
39362
  return;
39332
- let len = nodeLen(node);
39363
+ let len = nodeSize(node);
39333
39364
  let moveNode, moveOffset;
39334
39365
  for (;;) {
39335
39366
  if (offset < len) {
39336
- if (node.nodeType != 1)
39367
+ if (!isElt(node))
39337
39368
  break;
39338
39369
  let after = node.childNodes[offset];
39339
39370
  if (isIgnorable(after, 1)) {
39340
39371
  moveNode = node;
39341
39372
  moveOffset = ++offset;
39342
39373
  }
39343
- else
39374
+ else {
39344
39375
  break;
39376
+ }
39345
39377
  }
39346
39378
  else if (isBlockNode(node)) {
39347
39379
  break;
@@ -39362,7 +39394,7 @@ so this becomes the fallback color for the slot */ ''}
39362
39394
  else {
39363
39395
  node = next;
39364
39396
  offset = 0;
39365
- len = nodeLen(node);
39397
+ len = nodeSize(node);
39366
39398
  }
39367
39399
  }
39368
39400
  }
@@ -39380,9 +39412,9 @@ so this becomes the fallback color for the slot */ ''}
39380
39412
  }
39381
39413
  while (node && offset < node.childNodes.length) {
39382
39414
  let next = node.childNodes[offset];
39383
- if (next.nodeType == 3)
39415
+ if (isText(next))
39384
39416
  return next;
39385
- if (next.nodeType == 1 && next.contentEditable == "false")
39417
+ if (isElt(next) && next.contentEditable == "false")
39386
39418
  break;
39387
39419
  node = next;
39388
39420
  offset = 0;
@@ -39395,16 +39427,16 @@ so this becomes the fallback color for the slot */ ''}
39395
39427
  }
39396
39428
  while (node && offset) {
39397
39429
  let next = node.childNodes[offset - 1];
39398
- if (next.nodeType == 3)
39430
+ if (isText(next))
39399
39431
  return next;
39400
- if (next.nodeType == 1 && next.contentEditable == "false")
39432
+ if (isElt(next) && next.contentEditable == "false")
39401
39433
  break;
39402
39434
  node = next;
39403
39435
  offset = node.childNodes.length;
39404
39436
  }
39405
39437
  }
39406
39438
  function setSelFocus(view, node, offset) {
39407
- if (node.nodeType != 3) {
39439
+ if (!isText(node)) {
39408
39440
  let before, after;
39409
39441
  if (after = textNodeAfter(node, offset)) {
39410
39442
  node = after;
@@ -39514,8 +39546,8 @@ so this becomes the fallback color for the slot */ ''}
39514
39546
  if (!safari || view.state.selection.$head.parentOffset > 0)
39515
39547
  return false;
39516
39548
  let { focusNode, focusOffset } = view.domSelectionRange();
39517
- if (focusNode && focusNode.nodeType == 1 && focusOffset == 0 &&
39518
- focusNode.firstChild && focusNode.firstChild.contentEditable == "false") {
39549
+ if (focusNode && isElt(focusNode) && focusOffset == 0 &&
39550
+ focusNode.firstChild && isElt(focusNode.firstChild) && focusNode.firstChild.contentEditable == "false") {
39519
39551
  let child = focusNode.firstChild;
39520
39552
  switchEditable(view, child, "true");
39521
39553
  setTimeout(() => switchEditable(view, child, "false"), 20);
@@ -39586,7 +39618,7 @@ so this becomes the fallback color for the slot */ ''}
39586
39618
  let doc = detachedDoc(), wrap = doc.createElement("div");
39587
39619
  wrap.appendChild(serializer.serializeFragment(content, { document: doc }));
39588
39620
  let firstChild = wrap.firstChild, needsWrap, wrappers = 0;
39589
- while (firstChild && firstChild.nodeType == 1 && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39621
+ while (firstChild && isElt(firstChild) && (needsWrap = wrapMap[firstChild.nodeName.toLowerCase()])) {
39590
39622
  for (let i = needsWrap.length - 1; i >= 0; i--) {
39591
39623
  let wrapper = doc.createElement(needsWrap[i]);
39592
39624
  while (wrap.firstChild)
@@ -39596,7 +39628,7 @@ so this becomes the fallback color for the slot */ ''}
39596
39628
  }
39597
39629
  firstChild = wrap.firstChild;
39598
39630
  }
39599
- if (firstChild && firstChild.nodeType == 1)
39631
+ if (firstChild && isElt(firstChild))
39600
39632
  firstChild.setAttribute("data-pm-slice", `${openStart} ${openEnd}${wrappers ? ` -${wrappers}` : ""} ${JSON.stringify(context)}`);
39601
39633
  let text = view.someProp("clipboardTextSerializer", f => f(slice, view)) ||
39602
39634
  slice.content.textBetween(0, slice.content.size, "\n\n");
@@ -39642,7 +39674,7 @@ so this becomes the fallback color for the slot */ ''}
39642
39674
  if (sliceData && sliceData[3])
39643
39675
  for (let i = +sliceData[3]; i > 0; i--) {
39644
39676
  let child = dom.firstChild;
39645
- while (child && child.nodeType != 1)
39677
+ while (child && !isElt(child))
39646
39678
  child = child.nextSibling;
39647
39679
  if (!child)
39648
39680
  break;
@@ -39847,12 +39879,11 @@ so this becomes the fallback color for the slot */ ''}
39847
39879
  if (!type || type.hasRequiredAttrs())
39848
39880
  break;
39849
39881
  try {
39850
- type.checkAttrs(array[i + 1]);
39882
+ content = Fragment.from(type.create(array[i + 1], content));
39851
39883
  }
39852
39884
  catch (e) {
39853
39885
  break;
39854
39886
  }
39855
- content = Fragment.from(type.create(array[i + 1], content));
39856
39887
  openStart++;
39857
39888
  openEnd++;
39858
39889
  }
@@ -40184,7 +40215,7 @@ so this becomes the fallback color for the slot */ ''}
40184
40215
  }
40185
40216
  const target = flushed ? null : event.target;
40186
40217
  const targetDesc = target ? view.docView.nearestDesc(target, true) : null;
40187
- this.target = targetDesc && targetDesc.nodeDOM.nodeType == 1 ? targetDesc.nodeDOM : null;
40218
+ this.target = targetDesc && isElt(targetDesc.nodeDOM) ? targetDesc.nodeDOM : null;
40188
40219
  let { selection } = view.state;
40189
40220
  if (event.button == 0 &&
40190
40221
  (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
@@ -40332,7 +40363,7 @@ so this becomes the fallback color for the slot */ ''}
40332
40363
  if (!view.composing) {
40333
40364
  view.domObserver.flush();
40334
40365
  let { state } = view, $pos = state.selection.$to;
40335
- if (state.selection instanceof TextSelection &&
40366
+ if (state.selection instanceof TextSelection && state.selection.empty &&
40336
40367
  (state.storedMarks ||
40337
40368
  (!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore.marks.some(m => m.type.spec.inclusive === false)) ||
40338
40369
  chrome && windows$1 && selectionBeforeUneditable(view))) { // Issue #1500
@@ -40348,11 +40379,11 @@ so this becomes the fallback color for the slot */ ''}
40348
40379
  // inside if necessary.
40349
40380
  if (gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore.marks.length) {
40350
40381
  let sel = view.domSelectionRange();
40351
- for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
40382
+ for (let node = sel.focusNode, offset = sel.focusOffset; node && isElt(node) && offset != 0;) {
40352
40383
  let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1];
40353
40384
  if (!before)
40354
40385
  break;
40355
- if (before.nodeType == 3) {
40386
+ if (isText(before)) {
40356
40387
  let sel = view.domSelection();
40357
40388
  if (sel)
40358
40389
  sel.collapse(before, before.nodeValue.length);
@@ -40371,10 +40402,10 @@ so this becomes the fallback color for the slot */ ''}
40371
40402
  };
40372
40403
  function selectionBeforeUneditable(view) {
40373
40404
  let { focusNode, focusOffset } = view.domSelectionRange();
40374
- if (!focusNode || focusNode.nodeType != 1 || focusOffset >= focusNode.childNodes.length)
40405
+ if (!focusNode || !isElt(focusNode) || focusOffset >= focusNode.childNodes.length)
40375
40406
  return false;
40376
40407
  let next = focusNode.childNodes[focusOffset];
40377
- return next.nodeType == 1 && next.contentEditable == "false";
40408
+ return isElt(next) && next.contentEditable == "false";
40378
40409
  }
40379
40410
  editHandlers.compositionend = (view, event) => {
40380
40411
  if (view.composing) {
@@ -40576,7 +40607,7 @@ so this becomes the fallback color for the slot */ ''}
40576
40607
  else if (mouseDown && mouseDown.mightDrag) {
40577
40608
  node = NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos);
40578
40609
  }
40579
- else if (event.target && event.target.nodeType == 1) {
40610
+ else if (event.target && isElt(event.target)) {
40580
40611
  let desc = view.docView.nearestDesc(event.target, true);
40581
40612
  if (desc && desc.node.type.spec.draggable && desc != view.docView)
40582
40613
  node = NodeSelection.create(view.state.doc, desc.posBefore);
@@ -41547,7 +41578,7 @@ so this becomes the fallback color for the slot */ ''}
41547
41578
  let desc = container && this.view.docView.nearestDesc(container);
41548
41579
  if (desc && desc.ignoreMutation({
41549
41580
  type: "selection",
41550
- target: container.nodeType == 3 ? container.parentNode : container
41581
+ target: isText(container) ? container.parentNode : container
41551
41582
  })) {
41552
41583
  this.setCurSelection();
41553
41584
  return true;
@@ -41589,7 +41620,7 @@ so this becomes the fallback color for the slot */ ''}
41589
41620
  for (let node of added)
41590
41621
  if (node.nodeName == "BR" && node.parentNode) {
41591
41622
  let after = node.nextSibling;
41592
- while (after && after.nodeType == 1) {
41623
+ while (after && isElt(after)) {
41593
41624
  if (after.contentEditable == "false") {
41594
41625
  node.parentNode.removeChild(node);
41595
41626
  break;
@@ -41662,7 +41693,7 @@ so this becomes the fallback color for the slot */ ''}
41662
41693
  for (let i = 0; i < mut.addedNodes.length; i++) {
41663
41694
  let node = mut.addedNodes[i];
41664
41695
  added.push(node);
41665
- if (node.nodeType == 3)
41696
+ if (isText(node))
41666
41697
  this.lastChangedTextNode = node;
41667
41698
  }
41668
41699
  if (desc.contentDOM && desc.contentDOM != desc.dom && !desc.contentDOM.contains(mut.target))
@@ -41777,8 +41808,7 @@ so this becomes the fallback color for the slot */ ''}
41777
41808
  let parent = nextCell;
41778
41809
  for (;;) {
41779
41810
  let first = parent.firstChild;
41780
- if (!first || first.nodeType != 1 || first.contentEditable == "false" ||
41781
- /^(BR|IMG)$/.test(first.nodeName))
41811
+ if (!first || !isElt(first) || first.contentEditable == "false" || /^(BR|IMG)$/.test(first.nodeName))
41782
41812
  break;
41783
41813
  parent = first;
41784
41814
  }
@@ -41803,7 +41833,7 @@ so this becomes the fallback color for the slot */ ''}
41803
41833
  let domSel = view.domSelectionRange();
41804
41834
  let find;
41805
41835
  let anchor = domSel.anchorNode;
41806
- if (anchor && view.dom.contains(anchor.nodeType == 1 ? anchor : anchor.parentNode)) {
41836
+ if (anchor && contains(view.dom, anchor)) {
41807
41837
  find = [{ node: anchor, offset: domSel.anchorOffset }];
41808
41838
  if (!selectionCollapsed(domSel))
41809
41839
  find.push({ node: domSel.focusNode, offset: domSel.focusOffset });
@@ -41911,7 +41941,7 @@ so this becomes the fallback color for the slot */ ''}
41911
41941
  if (change)
41912
41942
  view.input.domChangeCount++;
41913
41943
  if ((ios && view.input.lastIOSEnter > Date.now() - 225 || android) &&
41914
- addedNodes.some(n => n.nodeType == 1 && !isInline.test(n.nodeName)) &&
41944
+ addedNodes.some(n => isElt(n) && !isInline.test(n.nodeName)) &&
41915
41945
  (!change || change.endA >= change.endB) &&
41916
41946
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41917
41947
  view.input.lastIOSEnter = 0;
@@ -41969,9 +41999,7 @@ so this becomes the fallback color for the slot */ ''}
41969
41999
  // as being an iOS enter press), just dispatch an Enter key instead.
41970
42000
  if (((ios && view.input.lastIOSEnter > Date.now() - 225 &&
41971
42001
  (!inlineChange || addedNodes.some(n => n.nodeName == "DIV" || n.nodeName == "P"))) ||
41972
- (!inlineChange && $from.pos < parse.doc.content.size &&
41973
- (!$from.sameParent($to) || !$from.parent.inlineContent) &&
41974
- $from.pos < $to.pos && !/\S/.test(parse.doc.textBetween($from.pos, $to.pos, "", "")))) &&
42002
+ (!inlineChange && looksLikeEnter(parse.doc, $from.pos, $to.pos))) &&
41975
42003
  view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))) {
41976
42004
  view.input.lastIOSEnter = 0;
41977
42005
  return;
@@ -42122,6 +42150,16 @@ so this becomes the fallback color for the slot */ ''}
42122
42150
  // The fragments after the join point must match
42123
42151
  return $newStart.parent.content.cut($newStart.parentOffset).eq($next.parent.content);
42124
42152
  }
42153
+ function looksLikeEnter(content, from, to) {
42154
+ let newTextlines = 0, newLeaves = 0;
42155
+ content.nodesBetween(from, to, (node, pos) => {
42156
+ if (node.isTextblock && pos >= from && pos < to)
42157
+ newTextlines++;
42158
+ else if (node.isText ? /\S/.test(node.text.slice(Math.max(0, from - pos), Math.min(node.nodeSize, to - pos))) : node.isLeaf)
42159
+ newLeaves++;
42160
+ });
42161
+ return newLeaves == 0 && newTextlines == 1;
42162
+ }
42125
42163
  function skipClosingAndOpening($pos, fromEnd, mayOpen) {
42126
42164
  let depth = $pos.depth, end = fromEnd ? $pos.end() : $pos.pos;
42127
42165
  while (depth > 0 && (fromEnd || $pos.indexAfter(depth) == $pos.node(depth).childCount)) {
@@ -42382,11 +42420,11 @@ so this becomes the fallback color for the slot */ ''}
42382
42420
  */
42383
42421
  scrollToSelection() {
42384
42422
  let startDOM = this.domSelectionRange().focusNode;
42385
- if (!startDOM || !this.dom.contains(startDOM.nodeType == 1 ? startDOM : startDOM.parentNode)) ;
42423
+ if (!startDOM || !contains(this.dom, startDOM)) ;
42386
42424
  else if (this.someProp("handleScrollToSelection", f => f(this))) ;
42387
42425
  else if (this.state.selection instanceof NodeSelection) {
42388
42426
  let target = this.docView.domAfterPos(this.state.selection.from);
42389
- if (target.nodeType == 1)
42427
+ if (isElt(target))
42390
42428
  scrollRectIntoView(this, target.getBoundingClientRect(), startDOM);
42391
42429
  }
42392
42430
  else {
@@ -42651,7 +42689,7 @@ so this becomes the fallback color for the slot */ ''}
42651
42689
  @internal
42652
42690
  */
42653
42691
  domSelectionRange() {
42654
- let sel = this.domSelection();
42692
+ let sel = this.dom.isConnected !== false && this.domSelection();
42655
42693
  if (!sel)
42656
42694
  return { focusNode: null, focusOffset: 0, anchorNode: null, anchorOffset: 0 };
42657
42695
  return safari && this.root.nodeType === 11 &&
@@ -42982,382 +43020,1013 @@ so this becomes the fallback color for the slot */ ''}
42982
43020
  };
42983
43021
  }
42984
43022
 
42985
- //#region src/helpers/createChainableState.ts
42986
- /**
42987
- * Takes a Transaction & Editor State and turns it into a chainable state object
42988
- * @param config The transaction and state to create the chainable state from
42989
- * @returns A chainable Editor state object
42990
- */
42991
- function createChainableState(config) {
42992
- const { state, transaction } = config;
42993
- let { selection } = transaction;
42994
- let { doc } = transaction;
42995
- let { storedMarks } = transaction;
42996
- return {
42997
- ...state,
42998
- apply: state.apply.bind(state),
42999
- applyTransaction: state.applyTransaction.bind(state),
43000
- plugins: state.plugins,
43001
- schema: state.schema,
43002
- reconfigure: state.reconfigure.bind(state),
43003
- toJSON: state.toJSON.bind(state),
43004
- get storedMarks() {
43005
- return storedMarks;
43006
- },
43007
- get selection() {
43008
- return selection;
43009
- },
43010
- get doc() {
43011
- return doc;
43012
- },
43013
- get tr() {
43014
- selection = transaction.selection;
43015
- doc = transaction.doc;
43016
- storedMarks = transaction.storedMarks;
43017
- return transaction;
43018
- }
43019
- };
43020
- }
43021
- //#endregion
43022
- //#region src/CommandManager.ts
43023
- var CommandManager = class CommandManager {
43024
- constructor(props) {
43025
- this.editor = props.editor;
43026
- this.rawCommands = this.editor.extensionManager.commands;
43027
- this.customState = props.state;
43028
- }
43029
- get hasCustomState() {
43030
- return !!this.customState;
43031
- }
43032
- get state() {
43033
- return this.customState || this.editor.state;
43034
- }
43035
- get commands() {
43036
- const { rawCommands, editor, state } = this;
43037
- const { view } = editor;
43038
- const { tr } = state;
43039
- const props = this.buildProps(tr);
43040
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43041
- const method = (...args) => {
43042
- const callback = command(...args)(props);
43043
- if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43044
- return callback;
43045
- };
43046
- return [name, method];
43047
- }));
43048
- }
43049
- get chain() {
43050
- return () => this.createChain();
43051
- }
43052
- get can() {
43053
- return () => this.createCan();
43054
- }
43055
- createChain(startTr, shouldDispatch = true) {
43056
- const { rawCommands, editor, state } = this;
43057
- const { view } = editor;
43058
- const callbacks = [];
43059
- const hasStartTransaction = !!startTr;
43060
- const tr = startTr || state.tr;
43061
- const run = () => {
43062
- if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43063
- return callbacks.every((callback) => callback === true);
43064
- };
43065
- const chain = {
43066
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43067
- const chainedCommand = (...args) => {
43068
- const props = this.buildProps(tr, shouldDispatch);
43069
- const callback = command(...args)(props);
43070
- callbacks.push(callback);
43071
- return chain;
43072
- };
43073
- return [name, chainedCommand];
43074
- })),
43075
- run
43076
- };
43077
- return chain;
43078
- }
43079
- /**
43080
- * Creates a chain that safely returns `false` when run.
43081
- * @returns A non-dispatching command chain.
43082
- * @example
43083
- * const chain = CommandManager.createFakeChain()
43084
- * chain.focus().run() // false
43085
- */
43086
- static createFakeChain() {
43087
- const chain = new Proxy({}, { get: (_target, property) => {
43088
- if (property === "then") return;
43089
- if (property === "run") return () => false;
43090
- return () => chain;
43091
- } });
43092
- return chain;
43093
- }
43094
- createCan(startTr) {
43095
- const { rawCommands, state } = this;
43096
- const dispatch = false;
43097
- const tr = startTr || state.tr;
43098
- const props = this.buildProps(tr, dispatch);
43099
- return {
43100
- ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43101
- return [name, (...args) => command(...args)({
43102
- ...props,
43103
- dispatch: void 0
43104
- })];
43105
- })),
43106
- chain: () => this.createChain(tr, dispatch)
43107
- };
43108
- }
43109
- /**
43110
- * Creates capability checks that safely return `false`.
43111
- * @returns A non-dispatching capability checker.
43112
- * @example
43113
- * const can = CommandManager.createFallbackCan()
43114
- * can.focus() // false
43115
- */
43116
- static createFallbackCan() {
43117
- const chain = CommandManager.createFakeChain();
43118
- return new Proxy({ chain: () => chain }, { get: (target, property) => {
43119
- if (property === "then") return;
43120
- if (property === "chain") return target.chain;
43121
- return () => false;
43122
- } });
43123
- }
43124
- buildProps(tr, shouldDispatch = true) {
43125
- const { rawCommands, editor, state } = this;
43126
- const { view } = editor;
43127
- const props = {
43128
- tr,
43129
- editor,
43130
- view,
43131
- state: createChainableState({
43132
- state,
43133
- transaction: tr
43134
- }),
43135
- dispatch: shouldDispatch ? () => void 0 : void 0,
43136
- chain: () => this.createChain(tr, shouldDispatch),
43137
- can: () => this.createCan(tr),
43138
- get commands() {
43139
- return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43140
- return [name, (...args) => command(...args)(props)];
43141
- }));
43142
- }
43143
- };
43144
- return props;
43145
- }
43146
- };
43147
- //#endregion
43148
- //#region src/commands/blur.ts
43149
- const blur = () => ({ editor, view }) => {
43150
- requestAnimationFrame(() => {
43151
- if (!editor.isDestroyed) {
43152
- var _window;
43153
- view.dom.blur();
43154
- (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43155
- }
43156
- });
43157
- return true;
43158
- };
43159
- //#endregion
43160
- //#region src/commands/clearContent.ts
43161
- const clearContent = (emitUpdate = true) => ({ commands }) => {
43162
- return commands.setContent("", { emitUpdate });
43163
- };
43164
- //#endregion
43165
- //#region src/commands/clearNodes.ts
43166
- const clearNodes = () => ({ state, tr, dispatch }) => {
43167
- const { selection } = tr;
43168
- const { ranges } = selection;
43169
- if (!dispatch) return true;
43170
- ranges.forEach(({ $from, $to }) => {
43171
- state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43172
- if (node.type.isText) return;
43173
- const { doc, mapping } = tr;
43174
- const $mappedFrom = doc.resolve(mapping.map(pos));
43175
- const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43176
- const nodeRange = $mappedFrom.blockRange($mappedTo);
43177
- if (!nodeRange) return;
43178
- const targetLiftDepth = liftTarget(nodeRange);
43179
- if (node.type.isTextblock) {
43180
- const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43181
- tr.setNodeMarkup(nodeRange.start, defaultType);
43182
- }
43183
- if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43184
- });
43185
- });
43186
- return true;
43187
- };
43188
- //#endregion
43189
- //#region src/commands/command.ts
43190
- const command = (fn) => (props) => {
43191
- return fn(props);
43192
- };
43193
- //#endregion
43194
- //#region src/commands/createParagraphNear.ts
43195
- const createParagraphNear$1 = () => ({ state, dispatch }) => {
43196
- return createParagraphNear(state, dispatch);
43197
- };
43198
- //#endregion
43199
- //#region src/commands/cut.ts
43200
- const cut = (originRange, targetPos) => ({ editor, tr }) => {
43201
- const { state } = editor;
43202
- const contentSlice = state.doc.slice(originRange.from, originRange.to);
43203
- tr.deleteRange(originRange.from, originRange.to);
43204
- const newPos = tr.mapping.map(targetPos);
43205
- tr.insert(newPos, contentSlice.content);
43206
- tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43207
- return true;
43208
- };
43209
- //#endregion
43210
- //#region src/commands/deleteCurrentNode.ts
43211
- const deleteCurrentNode = () => ({ tr, dispatch }) => {
43212
- const { selection } = tr;
43213
- const currentNode = selection.$anchor.node();
43214
- if (currentNode.content.size > 0) return false;
43215
- const $pos = tr.selection.$anchor;
43216
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43217
- if (dispatch) {
43218
- const from = $pos.before(depth);
43219
- const to = $pos.after(depth);
43220
- tr.delete(from, to).scrollIntoView();
43221
- }
43222
- return true;
43223
- }
43224
- return false;
43225
- };
43226
- //#endregion
43227
- //#region src/helpers/getNodeType.ts
43228
- function getNodeType(nameOrType, schema) {
43229
- if (typeof nameOrType === "string") {
43230
- if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43231
- return schema.nodes[nameOrType];
43232
- }
43233
- return nameOrType;
43234
- }
43235
- //#endregion
43236
- //#region src/commands/deleteNode.ts
43237
- const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43238
- const type = getNodeType(typeOrName, state.schema);
43239
- const $pos = tr.selection.$anchor;
43240
- for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43241
- if (dispatch) {
43242
- const from = $pos.before(depth);
43243
- const to = $pos.after(depth);
43244
- tr.delete(from, to).scrollIntoView();
43245
- }
43246
- return true;
43247
- }
43248
- return false;
43023
+ var GOOD_LEAF_SIZE = 200;
43024
+
43025
+ // :: class<T> A rope sequence is a persistent sequence data structure
43026
+ // that supports appending, prepending, and slicing without doing a
43027
+ // full copy. It is represented as a mostly-balanced tree.
43028
+ var RopeSequence = function RopeSequence () {};
43029
+
43030
+ RopeSequence.prototype.append = function append (other) {
43031
+ if (!other.length) { return this }
43032
+ other = RopeSequence.from(other);
43033
+
43034
+ return (!this.length && other) ||
43035
+ (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
43036
+ (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
43037
+ this.appendInner(other)
43249
43038
  };
43250
- //#endregion
43251
- //#region src/commands/deleteRange.ts
43252
- const deleteRange = (range) => ({ tr, dispatch }) => {
43253
- const { from, to } = range;
43254
- if (dispatch) tr.delete(from, to);
43255
- return true;
43039
+
43040
+ // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
43041
+ // Prepend an array or other rope to this one, returning a new rope.
43042
+ RopeSequence.prototype.prepend = function prepend (other) {
43043
+ if (!other.length) { return this }
43044
+ return RopeSequence.from(other).append(this)
43256
43045
  };
43257
- //#endregion
43258
- //#region src/commands/deleteSelection.ts
43259
- /**
43260
- * Check if a node has text content based on its content specification.
43261
- * Returns true if the node's content spec matches text* or text+ patterns.
43262
- */
43263
- const hasTextContent = (nodeSpec) => {
43264
- if (!nodeSpec.content) return false;
43265
- return /^text(\*|\+)/.test(nodeSpec.content);
43046
+
43047
+ RopeSequence.prototype.appendInner = function appendInner (other) {
43048
+ return new Append(this, other)
43266
43049
  };
43267
- /**
43268
- * Expand selection position for a specific side (left or right) to handle inline text nodes.
43269
- * This function checks if the position is within an inline node with text content and
43270
- * expands it to include the entire node boundaries for proper deletion.
43271
- * @param $pos - The resolved position to expand
43272
- * @param schema - The ProseMirror schema
43273
- * @param side - Which side to expand ('left' or 'right')
43274
- * @returns The expanded position for deletion
43275
- */
43276
- const expandSelectionForSide = ($pos, schema, side) => {
43277
- if (!$pos.parent.isInline) return $pos.pos;
43278
- if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43279
- const parentContent = schema.nodes[$pos.parent.type.name].spec;
43280
- if (!hasTextContent(parentContent)) return $pos.pos;
43281
- return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43050
+
43051
+ // :: (?number, ?number) → RopeSequence<T>
43052
+ // Create a rope repesenting a sub-sequence of this rope.
43053
+ RopeSequence.prototype.slice = function slice (from, to) {
43054
+ if ( from === void 0 ) from = 0;
43055
+ if ( to === void 0 ) to = this.length;
43056
+
43057
+ if (from >= to) { return RopeSequence.empty }
43058
+ return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
43282
43059
  };
43283
- /**
43284
- * Expand selection range to properly handle deletion of inline text nodes.
43285
- * Inline text nodes don't collapse correctly when text inside is deleted,
43286
- * so we need to expand the selection to include the entire node.
43287
- * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43288
- */
43289
- const expandSelectionForInlineText = ($from, $to, schema) => {
43290
- return {
43291
- from: expandSelectionForSide($from, schema, "left"),
43292
- to: expandSelectionForSide($to, schema, "right")
43293
- };
43060
+
43061
+ // :: (number) → T
43062
+ // Retrieve the element at the given position from this rope.
43063
+ RopeSequence.prototype.get = function get (i) {
43064
+ if (i < 0 || i >= this.length) { return undefined }
43065
+ return this.getInner(i)
43294
43066
  };
43295
- const deleteSelection = () => ({ state, dispatch }) => {
43296
- if (state.selection.empty) return false;
43297
- if (dispatch) {
43298
- const tr = state.tr;
43299
- const { ranges } = state.selection;
43300
- const mapFrom = tr.steps.length;
43301
- ranges.forEach((range) => {
43302
- const mapping = tr.mapping.slice(mapFrom);
43303
- const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43304
- const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43305
- const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43306
- tr.deleteRange(from, to);
43307
- });
43308
- if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43309
- tr.scrollIntoView();
43310
- dispatch(tr);
43311
- }
43312
- return true;
43067
+
43068
+ // :: ((element: T, index: number) → ?bool, ?number, ?number)
43069
+ // Call the given function for each element between the given
43070
+ // indices. This tends to be more efficient than looping over the
43071
+ // indices and calling `get`, because it doesn't have to descend the
43072
+ // tree for every element.
43073
+ RopeSequence.prototype.forEach = function forEach (f, from, to) {
43074
+ if ( from === void 0 ) from = 0;
43075
+ if ( to === void 0 ) to = this.length;
43076
+
43077
+ if (from <= to)
43078
+ { this.forEachInner(f, from, to, 0); }
43079
+ else
43080
+ { this.forEachInvertedInner(f, from, to, 0); }
43313
43081
  };
43314
- //#endregion
43315
- //#region src/commands/enter.ts
43316
- const enter = () => ({ commands }) => {
43317
- return commands.keyboardShortcut("Enter");
43082
+
43083
+ // :: ((element: T, index: number) → U, ?number, ?number) → [U]
43084
+ // Map the given functions over the elements of the rope, producing
43085
+ // a flat array.
43086
+ RopeSequence.prototype.map = function map (f, from, to) {
43087
+ if ( from === void 0 ) from = 0;
43088
+ if ( to === void 0 ) to = this.length;
43089
+
43090
+ var result = [];
43091
+ this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
43092
+ return result
43318
43093
  };
43319
- //#endregion
43320
- //#region src/commands/exitCode.ts
43321
- const exitCode$1 = () => ({ state, dispatch }) => {
43322
- return exitCode(state, dispatch);
43094
+
43095
+ // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
43096
+ // Create a rope representing the given array, or return the rope
43097
+ // itself if a rope was given.
43098
+ RopeSequence.from = function from (values) {
43099
+ if (values instanceof RopeSequence) { return values }
43100
+ return values && values.length ? new Leaf(values) : RopeSequence.empty
43323
43101
  };
43324
- //#endregion
43325
- //#region src/utilities/isRegExp.ts
43326
- function isRegExp$1(value) {
43327
- return Object.prototype.toString.call(value) === "[object RegExp]";
43328
- }
43329
- //#endregion
43330
- //#region src/utilities/objectIncludes.ts
43331
- /**
43332
- * Check if object1 includes object2
43333
- * @param object1 Object
43334
- * @param object2 Object
43335
- */
43336
- function objectIncludes(object1, object2, options = { strict: true }) {
43337
- const keys = Object.keys(object2);
43338
- if (!keys.length) return true;
43339
- return keys.every((key) => {
43340
- if (options.strict) return object2[key] === object1[key];
43341
- if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
43342
- return object2[key] === object1[key];
43343
- });
43344
- }
43345
- //#endregion
43346
- //#region src/helpers/getMarkRange.ts
43347
- function findMarkInSet(marks, type, attributes = {}) {
43348
- return marks.find((item) => {
43349
- return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
43350
- });
43351
- }
43352
- function isMarkInSet(marks, type, attributes = {}) {
43353
- return !!findMarkInSet(marks, type, attributes);
43354
- }
43355
- /**
43356
- * Get the range of a mark at a resolved position.
43357
- */
43358
- function getMarkRange($pos, type, attributes) {
43359
- if (!$pos || !type) return;
43360
- let start = $pos.parent.childAfter($pos.parentOffset);
43102
+
43103
+ var Leaf = /*@__PURE__*/(function (RopeSequence) {
43104
+ function Leaf(values) {
43105
+ RopeSequence.call(this);
43106
+ this.values = values;
43107
+ }
43108
+
43109
+ if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
43110
+ Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43111
+ Leaf.prototype.constructor = Leaf;
43112
+
43113
+ var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
43114
+
43115
+ Leaf.prototype.flatten = function flatten () {
43116
+ return this.values
43117
+ };
43118
+
43119
+ Leaf.prototype.sliceInner = function sliceInner (from, to) {
43120
+ if (from == 0 && to == this.length) { return this }
43121
+ return new Leaf(this.values.slice(from, to))
43122
+ };
43123
+
43124
+ Leaf.prototype.getInner = function getInner (i) {
43125
+ return this.values[i]
43126
+ };
43127
+
43128
+ Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
43129
+ for (var i = from; i < to; i++)
43130
+ { if (f(this.values[i], start + i) === false) { return false } }
43131
+ };
43132
+
43133
+ Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43134
+ for (var i = from - 1; i >= to; i--)
43135
+ { if (f(this.values[i], start + i) === false) { return false } }
43136
+ };
43137
+
43138
+ Leaf.prototype.leafAppend = function leafAppend (other) {
43139
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43140
+ { return new Leaf(this.values.concat(other.flatten())) }
43141
+ };
43142
+
43143
+ Leaf.prototype.leafPrepend = function leafPrepend (other) {
43144
+ if (this.length + other.length <= GOOD_LEAF_SIZE)
43145
+ { return new Leaf(other.flatten().concat(this.values)) }
43146
+ };
43147
+
43148
+ prototypeAccessors.length.get = function () { return this.values.length };
43149
+
43150
+ prototypeAccessors.depth.get = function () { return 0 };
43151
+
43152
+ Object.defineProperties( Leaf.prototype, prototypeAccessors );
43153
+
43154
+ return Leaf;
43155
+ }(RopeSequence));
43156
+
43157
+ // :: RopeSequence
43158
+ // The empty rope sequence.
43159
+ RopeSequence.empty = new Leaf([]);
43160
+
43161
+ var Append = /*@__PURE__*/(function (RopeSequence) {
43162
+ function Append(left, right) {
43163
+ RopeSequence.call(this);
43164
+ this.left = left;
43165
+ this.right = right;
43166
+ this.length = left.length + right.length;
43167
+ this.depth = Math.max(left.depth, right.depth) + 1;
43168
+ }
43169
+
43170
+ if ( RopeSequence ) Append.__proto__ = RopeSequence;
43171
+ Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
43172
+ Append.prototype.constructor = Append;
43173
+
43174
+ Append.prototype.flatten = function flatten () {
43175
+ return this.left.flatten().concat(this.right.flatten())
43176
+ };
43177
+
43178
+ Append.prototype.getInner = function getInner (i) {
43179
+ return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
43180
+ };
43181
+
43182
+ Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
43183
+ var leftLen = this.left.length;
43184
+ if (from < leftLen &&
43185
+ this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
43186
+ { return false }
43187
+ if (to > leftLen &&
43188
+ this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
43189
+ { return false }
43190
+ };
43191
+
43192
+ Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
43193
+ var leftLen = this.left.length;
43194
+ if (from > leftLen &&
43195
+ this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
43196
+ { return false }
43197
+ if (to < leftLen &&
43198
+ this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
43199
+ { return false }
43200
+ };
43201
+
43202
+ Append.prototype.sliceInner = function sliceInner (from, to) {
43203
+ if (from == 0 && to == this.length) { return this }
43204
+ var leftLen = this.left.length;
43205
+ if (to <= leftLen) { return this.left.slice(from, to) }
43206
+ if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
43207
+ return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
43208
+ };
43209
+
43210
+ Append.prototype.leafAppend = function leafAppend (other) {
43211
+ var inner = this.right.leafAppend(other);
43212
+ if (inner) { return new Append(this.left, inner) }
43213
+ };
43214
+
43215
+ Append.prototype.leafPrepend = function leafPrepend (other) {
43216
+ var inner = this.left.leafPrepend(other);
43217
+ if (inner) { return new Append(inner, this.right) }
43218
+ };
43219
+
43220
+ Append.prototype.appendInner = function appendInner (other) {
43221
+ if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
43222
+ { return new Append(this.left, new Append(this.right, other)) }
43223
+ return new Append(this, other)
43224
+ };
43225
+
43226
+ return Append;
43227
+ }(RopeSequence));
43228
+
43229
+ // ProseMirror's history isn't simply a way to roll back to a previous
43230
+ // state, because ProseMirror supports applying changes without adding
43231
+ // them to the history (for example during collaboration).
43232
+ //
43233
+ // To this end, each 'Branch' (one for the undo history and one for
43234
+ // the redo history) keeps an array of 'Items', which can optionally
43235
+ // hold a step (an actual undoable change), and always hold a position
43236
+ // map (which is needed to move changes below them to apply to the
43237
+ // current document).
43238
+ //
43239
+ // An item that has both a step and a selection bookmark is the start
43240
+ // of an 'event' — a group of changes that will be undone or redone at
43241
+ // once. (It stores only the bookmark, since that way we don't have to
43242
+ // provide a document until the selection is actually applied, which
43243
+ // is useful when compressing.)
43244
+ // Used to schedule history compression
43245
+ const max_empty_items = 500;
43246
+ class Branch {
43247
+ constructor(items, eventCount) {
43248
+ this.items = items;
43249
+ this.eventCount = eventCount;
43250
+ }
43251
+ // Pop the latest event off the branch's history and apply it
43252
+ // to a document transform.
43253
+ popEvent(state, preserveItems) {
43254
+ if (this.eventCount == 0)
43255
+ return null;
43256
+ let end = this.items.length;
43257
+ for (;; end--) {
43258
+ let next = this.items.get(end - 1);
43259
+ if (next.selection) {
43260
+ --end;
43261
+ break;
43262
+ }
43263
+ }
43264
+ let remap, mapFrom;
43265
+ if (preserveItems) {
43266
+ remap = this.remapping(end, this.items.length);
43267
+ mapFrom = remap.maps.length;
43268
+ }
43269
+ let transform = state.tr;
43270
+ let selection, remaining;
43271
+ let addAfter = [], addBefore = [];
43272
+ this.items.forEach((item, i) => {
43273
+ if (!item.step) {
43274
+ if (!remap) {
43275
+ remap = this.remapping(end, i + 1);
43276
+ mapFrom = remap.maps.length;
43277
+ }
43278
+ mapFrom--;
43279
+ addBefore.push(item);
43280
+ return;
43281
+ }
43282
+ if (remap) {
43283
+ addBefore.push(new Item(item.map));
43284
+ let step = item.step.map(remap.slice(mapFrom)), map;
43285
+ if (step && transform.maybeStep(step).doc) {
43286
+ map = transform.mapping.maps[transform.mapping.maps.length - 1];
43287
+ addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
43288
+ }
43289
+ mapFrom--;
43290
+ if (map)
43291
+ remap.appendMap(map, mapFrom);
43292
+ }
43293
+ else {
43294
+ transform.maybeStep(item.step);
43295
+ }
43296
+ if (item.selection) {
43297
+ selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
43298
+ remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
43299
+ return false;
43300
+ }
43301
+ }, this.items.length, 0);
43302
+ return { remaining: remaining, transform, selection: selection };
43303
+ }
43304
+ // Create a new branch with the given transform added.
43305
+ addTransform(transform, selection, histOptions, preserveItems) {
43306
+ let newItems = [], eventCount = this.eventCount;
43307
+ let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
43308
+ for (let i = 0; i < transform.steps.length; i++) {
43309
+ let step = transform.steps[i].invert(transform.docs[i]);
43310
+ let item = new Item(transform.mapping.maps[i], step, selection), merged;
43311
+ if (merged = lastItem && lastItem.merge(item)) {
43312
+ item = merged;
43313
+ if (i)
43314
+ newItems.pop();
43315
+ else
43316
+ oldItems = oldItems.slice(0, oldItems.length - 1);
43317
+ }
43318
+ newItems.push(item);
43319
+ if (selection) {
43320
+ eventCount++;
43321
+ selection = undefined;
43322
+ }
43323
+ if (!preserveItems)
43324
+ lastItem = item;
43325
+ }
43326
+ let overflow = eventCount - histOptions.depth;
43327
+ if (overflow > DEPTH_OVERFLOW) {
43328
+ oldItems = cutOffEvents(oldItems, overflow);
43329
+ eventCount -= overflow;
43330
+ }
43331
+ return new Branch(oldItems.append(newItems), eventCount);
43332
+ }
43333
+ remapping(from, to) {
43334
+ let maps = new Mapping;
43335
+ this.items.forEach((item, i) => {
43336
+ let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
43337
+ ? maps.maps.length - item.mirrorOffset : undefined;
43338
+ maps.appendMap(item.map, mirrorPos);
43339
+ }, from, to);
43340
+ return maps;
43341
+ }
43342
+ addMaps(array) {
43343
+ if (this.eventCount == 0)
43344
+ return this;
43345
+ return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
43346
+ }
43347
+ // When the collab module receives remote changes, the history has
43348
+ // to know about those, so that it can adjust the steps that were
43349
+ // rebased on top of the remote changes, and include the position
43350
+ // maps for the remote changes in its array of items.
43351
+ rebased(rebasedTransform, rebasedCount) {
43352
+ if (!this.eventCount)
43353
+ return this;
43354
+ rebasedCount = Math.min(this.items.length, rebasedCount);
43355
+ let rebasedItems = [], start = this.items.length - rebasedCount;
43356
+ let mapping = rebasedTransform.mapping;
43357
+ let newUntil = rebasedTransform.steps.length;
43358
+ let eventCount = this.eventCount;
43359
+ this.items.forEach(item => { if (item.selection)
43360
+ eventCount--; }, start);
43361
+ let iRebased = rebasedCount;
43362
+ this.items.forEach(item => {
43363
+ let pos = mapping.getMirror(--iRebased);
43364
+ if (pos == null)
43365
+ return;
43366
+ newUntil = Math.min(newUntil, pos);
43367
+ let map = mapping.maps[pos];
43368
+ if (item.step) {
43369
+ let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
43370
+ let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
43371
+ if (selection)
43372
+ eventCount++;
43373
+ rebasedItems.push(new Item(map, step, selection));
43374
+ }
43375
+ else {
43376
+ rebasedItems.push(new Item(map));
43377
+ }
43378
+ }, start);
43379
+ let newMaps = [];
43380
+ for (let i = rebasedCount; i < newUntil; i++)
43381
+ newMaps.push(new Item(mapping.maps[i]));
43382
+ let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
43383
+ let branch = new Branch(items, eventCount);
43384
+ if (branch.emptyItemCount() > max_empty_items)
43385
+ branch = branch.compress(this.items.length - rebasedItems.length);
43386
+ return branch;
43387
+ }
43388
+ emptyItemCount() {
43389
+ let count = 0;
43390
+ this.items.forEach(item => { if (!item.step)
43391
+ count++; });
43392
+ return count;
43393
+ }
43394
+ // Compressing a branch means rewriting it to push the air (map-only
43395
+ // items) out. During collaboration, these naturally accumulate
43396
+ // because each remote change adds one. The `upto` argument is used
43397
+ // to ensure that only the items below a given level are compressed,
43398
+ // because `rebased` relies on a clean, untouched set of items in
43399
+ // order to associate old items with rebased steps.
43400
+ compress(upto = this.items.length) {
43401
+ let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
43402
+ let items = [], events = 0;
43403
+ this.items.forEach((item, i) => {
43404
+ if (i >= upto) {
43405
+ items.push(item);
43406
+ if (item.selection)
43407
+ events++;
43408
+ }
43409
+ else if (item.step) {
43410
+ let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
43411
+ mapFrom--;
43412
+ if (map)
43413
+ remap.appendMap(map, mapFrom);
43414
+ if (step) {
43415
+ let selection = item.selection && item.selection.map(remap.slice(mapFrom));
43416
+ if (selection)
43417
+ events++;
43418
+ let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
43419
+ if (merged = items.length && items[last].merge(newItem))
43420
+ items[last] = merged;
43421
+ else
43422
+ items.push(newItem);
43423
+ }
43424
+ }
43425
+ else if (item.map) {
43426
+ mapFrom--;
43427
+ }
43428
+ }, this.items.length, 0);
43429
+ return new Branch(RopeSequence.from(items.reverse()), events);
43430
+ }
43431
+ }
43432
+ Branch.empty = new Branch(RopeSequence.empty, 0);
43433
+ function cutOffEvents(items, n) {
43434
+ let cutPoint;
43435
+ items.forEach((item, i) => {
43436
+ if (item.selection && (n-- == 0)) {
43437
+ cutPoint = i;
43438
+ return false;
43439
+ }
43440
+ });
43441
+ return items.slice(cutPoint);
43442
+ }
43443
+ class Item {
43444
+ constructor(
43445
+ // The (forward) step map for this item.
43446
+ map,
43447
+ // The inverted step
43448
+ step,
43449
+ // If this is non-null, this item is the start of a group, and
43450
+ // this selection is the starting selection for the group (the one
43451
+ // that was active before the first step was applied)
43452
+ selection,
43453
+ // If this item is the inverse of a previous mapping on the stack,
43454
+ // this points at the inverse's offset
43455
+ mirrorOffset) {
43456
+ this.map = map;
43457
+ this.step = step;
43458
+ this.selection = selection;
43459
+ this.mirrorOffset = mirrorOffset;
43460
+ }
43461
+ merge(other) {
43462
+ if (this.step && other.step && !other.selection) {
43463
+ let step = other.step.merge(this.step);
43464
+ if (step)
43465
+ return new Item(step.getMap().invert(), step, this.selection);
43466
+ }
43467
+ }
43468
+ }
43469
+ // The value of the state field that tracks undo/redo history for that
43470
+ // state. Will be stored in the plugin state when the history plugin
43471
+ // is active.
43472
+ class HistoryState {
43473
+ constructor(done, undone, prevRanges, prevTime, prevComposition) {
43474
+ this.done = done;
43475
+ this.undone = undone;
43476
+ this.prevRanges = prevRanges;
43477
+ this.prevTime = prevTime;
43478
+ this.prevComposition = prevComposition;
43479
+ }
43480
+ }
43481
+ const DEPTH_OVERFLOW = 20;
43482
+ // Record a transformation in undo history.
43483
+ function applyTransaction(history, state, tr, options) {
43484
+ let historyTr = tr.getMeta(historyKey), rebased;
43485
+ if (historyTr)
43486
+ return historyTr.historyState;
43487
+ if (tr.getMeta(closeHistoryKey))
43488
+ history = new HistoryState(history.done, history.undone, null, 0, -1);
43489
+ let appended = tr.getMeta("appendedTransaction");
43490
+ if (tr.steps.length == 0) {
43491
+ return history;
43492
+ }
43493
+ else if (appended && appended.getMeta(historyKey)) {
43494
+ if (appended.getMeta(historyKey).redo)
43495
+ return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
43496
+ else
43497
+ return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
43498
+ }
43499
+ else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
43500
+ // Group transforms that occur in quick succession into one event.
43501
+ let composition = tr.getMeta("composition");
43502
+ let newGroup = history.prevTime == 0 ||
43503
+ (!appended && history.prevComposition != composition &&
43504
+ (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
43505
+ let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
43506
+ 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);
43507
+ }
43508
+ else if (rebased = tr.getMeta("rebased")) {
43509
+ // Used by the collab module to tell the history that some of its
43510
+ // content has been rebased.
43511
+ return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43512
+ }
43513
+ else {
43514
+ return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
43515
+ }
43516
+ }
43517
+ function isAdjacentTo(transform, prevRanges) {
43518
+ if (!prevRanges)
43519
+ return false;
43520
+ if (!transform.docChanged)
43521
+ return true;
43522
+ let adjacent = false;
43523
+ transform.mapping.maps[0].forEach((start, end) => {
43524
+ for (let i = 0; i < prevRanges.length; i += 2)
43525
+ if (start <= prevRanges[i + 1] && end >= prevRanges[i])
43526
+ adjacent = true;
43527
+ });
43528
+ return adjacent;
43529
+ }
43530
+ function rangesFor(maps) {
43531
+ let result = [];
43532
+ for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
43533
+ maps[i].forEach((_from, _to, from, to) => result.push(from, to));
43534
+ return result;
43535
+ }
43536
+ function mapRanges(ranges, mapping) {
43537
+ if (!ranges)
43538
+ return null;
43539
+ let result = [];
43540
+ for (let i = 0; i < ranges.length; i += 2) {
43541
+ let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
43542
+ if (from <= to)
43543
+ result.push(from, to);
43544
+ }
43545
+ return result;
43546
+ }
43547
+ // Apply the latest event from one branch to the document and shift the event
43548
+ // onto the other branch.
43549
+ function histTransaction(history, state, redo) {
43550
+ let preserveItems = mustPreserveItems(state);
43551
+ let histOptions = historyKey.get(state).spec.config;
43552
+ let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
43553
+ if (!pop)
43554
+ return null;
43555
+ let selection = pop.selection.resolve(pop.transform.doc);
43556
+ let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
43557
+ let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
43558
+ return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
43559
+ }
43560
+ let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
43561
+ // Check whether any plugin in the given state has a
43562
+ // `historyPreserveItems` property in its spec, in which case we must
43563
+ // preserve steps exactly as they came in, so that they can be
43564
+ // rebased.
43565
+ function mustPreserveItems(state) {
43566
+ let plugins = state.plugins;
43567
+ if (cachedPreserveItemsPlugins != plugins) {
43568
+ cachedPreserveItems = false;
43569
+ cachedPreserveItemsPlugins = plugins;
43570
+ for (let i = 0; i < plugins.length; i++)
43571
+ if (plugins[i].spec.historyPreserveItems) {
43572
+ cachedPreserveItems = true;
43573
+ break;
43574
+ }
43575
+ }
43576
+ return cachedPreserveItems;
43577
+ }
43578
+ /**
43579
+ Set a flag on the given transaction that will prevent further steps
43580
+ from being appended to an existing history event (so that they
43581
+ require a separate undo command to undo).
43582
+ */
43583
+ function closeHistory(tr) {
43584
+ return tr.setMeta(closeHistoryKey, true);
43585
+ }
43586
+ const historyKey = new PluginKey("history");
43587
+ const closeHistoryKey = new PluginKey("closeHistory");
43588
+ /**
43589
+ Returns a plugin that enables the undo history for an editor. The
43590
+ plugin will track undo and redo stacks, which can be used with the
43591
+ [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
43592
+
43593
+ You can set an `"addToHistory"` [metadata
43594
+ property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
43595
+ to prevent it from being rolled back by undo.
43596
+ */
43597
+ function history(config = {}) {
43598
+ config = { depth: config.depth || 100,
43599
+ newGroupDelay: config.newGroupDelay || 500 };
43600
+ return new Plugin({
43601
+ key: historyKey,
43602
+ state: {
43603
+ init() {
43604
+ return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
43605
+ },
43606
+ apply(tr, hist, state) {
43607
+ return applyTransaction(hist, state, tr, config);
43608
+ }
43609
+ },
43610
+ config,
43611
+ props: {
43612
+ handleDOMEvents: {
43613
+ beforeinput(view, e) {
43614
+ let inputType = e.inputType;
43615
+ let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
43616
+ if (!command || !view.editable)
43617
+ return false;
43618
+ e.preventDefault();
43619
+ return command(view.state, view.dispatch);
43620
+ }
43621
+ }
43622
+ }
43623
+ });
43624
+ }
43625
+ function buildCommand(redo, scroll) {
43626
+ return (state, dispatch) => {
43627
+ let hist = historyKey.getState(state);
43628
+ if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
43629
+ return false;
43630
+ if (dispatch) {
43631
+ let tr = histTransaction(hist, state, redo);
43632
+ if (tr)
43633
+ dispatch(scroll ? tr.scrollIntoView() : tr);
43634
+ }
43635
+ return true;
43636
+ };
43637
+ }
43638
+ /**
43639
+ A command function that undoes the last change, if any.
43640
+ */
43641
+ const undo = buildCommand(false, true);
43642
+ /**
43643
+ A command function that redoes the last undone change, if any.
43644
+ */
43645
+ const redo = buildCommand(true, true);
43646
+ /**
43647
+ Returns true if the given transaction was generated by the history
43648
+ plugin.
43649
+ */
43650
+ function isHistoryTransaction(tr) {
43651
+ return tr.getMeta(historyKey) != null;
43652
+ }
43653
+
43654
+ //#region src/helpers/createChainableState.ts
43655
+ /**
43656
+ * Takes a Transaction & Editor State and turns it into a chainable state object
43657
+ * @param config The transaction and state to create the chainable state from
43658
+ * @returns A chainable Editor state object
43659
+ */
43660
+ function createChainableState(config) {
43661
+ const { state, transaction } = config;
43662
+ let { selection } = transaction;
43663
+ let { doc } = transaction;
43664
+ let { storedMarks } = transaction;
43665
+ return {
43666
+ ...state,
43667
+ apply: state.apply.bind(state),
43668
+ applyTransaction: state.applyTransaction.bind(state),
43669
+ plugins: state.plugins,
43670
+ schema: state.schema,
43671
+ reconfigure: state.reconfigure.bind(state),
43672
+ toJSON: state.toJSON.bind(state),
43673
+ get storedMarks() {
43674
+ return storedMarks;
43675
+ },
43676
+ get selection() {
43677
+ return selection;
43678
+ },
43679
+ get doc() {
43680
+ return doc;
43681
+ },
43682
+ get tr() {
43683
+ selection = transaction.selection;
43684
+ doc = transaction.doc;
43685
+ storedMarks = transaction.storedMarks;
43686
+ return transaction;
43687
+ }
43688
+ };
43689
+ }
43690
+ //#endregion
43691
+ //#region src/CommandManager.ts
43692
+ var CommandManager = class CommandManager {
43693
+ constructor(props) {
43694
+ this.editor = props.editor;
43695
+ this.rawCommands = this.editor.extensionManager.commands;
43696
+ this.customState = props.state;
43697
+ }
43698
+ get hasCustomState() {
43699
+ return !!this.customState;
43700
+ }
43701
+ get state() {
43702
+ return this.customState || this.editor.state;
43703
+ }
43704
+ get commands() {
43705
+ const { rawCommands, editor, state } = this;
43706
+ const { view } = editor;
43707
+ const { tr } = state;
43708
+ const props = this.buildProps(tr);
43709
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43710
+ const method = (...args) => {
43711
+ const callback = command(...args)(props);
43712
+ if (!tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43713
+ return callback;
43714
+ };
43715
+ return [name, method];
43716
+ }));
43717
+ }
43718
+ get chain() {
43719
+ return () => this.createChain();
43720
+ }
43721
+ get can() {
43722
+ return () => this.createCan();
43723
+ }
43724
+ createChain(startTr, shouldDispatch = true) {
43725
+ const { rawCommands, editor, state } = this;
43726
+ const { view } = editor;
43727
+ const callbacks = [];
43728
+ const hasStartTransaction = !!startTr;
43729
+ const tr = startTr || state.tr;
43730
+ const run = () => {
43731
+ if (!hasStartTransaction && shouldDispatch && !tr.getMeta("preventDispatch") && !this.hasCustomState) view.dispatch(tr);
43732
+ return callbacks.every((callback) => callback === true);
43733
+ };
43734
+ const chain = {
43735
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43736
+ const chainedCommand = (...args) => {
43737
+ const props = this.buildProps(tr, shouldDispatch);
43738
+ const callback = command(...args)(props);
43739
+ callbacks.push(callback);
43740
+ return chain;
43741
+ };
43742
+ return [name, chainedCommand];
43743
+ })),
43744
+ run
43745
+ };
43746
+ return chain;
43747
+ }
43748
+ /**
43749
+ * Creates a chain that safely returns `false` when run.
43750
+ * @returns A non-dispatching command chain.
43751
+ * @example
43752
+ * const chain = CommandManager.createFakeChain()
43753
+ * chain.focus().run() // false
43754
+ */
43755
+ static createFakeChain() {
43756
+ const chain = new Proxy({}, { get: (_target, property) => {
43757
+ if (property === "then") return;
43758
+ if (property === "run") return () => false;
43759
+ return () => chain;
43760
+ } });
43761
+ return chain;
43762
+ }
43763
+ createCan(startTr) {
43764
+ const { rawCommands, state } = this;
43765
+ const dispatch = false;
43766
+ const tr = startTr || state.tr;
43767
+ const props = this.buildProps(tr, dispatch);
43768
+ return {
43769
+ ...Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43770
+ return [name, (...args) => command(...args)({
43771
+ ...props,
43772
+ dispatch: void 0
43773
+ })];
43774
+ })),
43775
+ chain: () => this.createChain(tr, dispatch)
43776
+ };
43777
+ }
43778
+ /**
43779
+ * Creates capability checks that safely return `false`.
43780
+ * @returns A non-dispatching capability checker.
43781
+ * @example
43782
+ * const can = CommandManager.createFallbackCan()
43783
+ * can.focus() // false
43784
+ */
43785
+ static createFallbackCan() {
43786
+ const chain = CommandManager.createFakeChain();
43787
+ return new Proxy({ chain: () => chain }, { get: (target, property) => {
43788
+ if (property === "then") return;
43789
+ if (property === "chain") return target.chain;
43790
+ return () => false;
43791
+ } });
43792
+ }
43793
+ buildProps(tr, shouldDispatch = true) {
43794
+ const { rawCommands, editor, state } = this;
43795
+ const { view } = editor;
43796
+ const props = {
43797
+ tr,
43798
+ editor,
43799
+ view,
43800
+ state: createChainableState({
43801
+ state,
43802
+ transaction: tr
43803
+ }),
43804
+ dispatch: shouldDispatch ? () => void 0 : void 0,
43805
+ chain: () => this.createChain(tr, shouldDispatch),
43806
+ can: () => this.createCan(tr),
43807
+ get commands() {
43808
+ return Object.fromEntries(Object.entries(rawCommands).map(([name, command]) => {
43809
+ return [name, (...args) => command(...args)(props)];
43810
+ }));
43811
+ }
43812
+ };
43813
+ return props;
43814
+ }
43815
+ };
43816
+ //#endregion
43817
+ //#region src/commands/blur.ts
43818
+ const blur = () => ({ editor, view }) => {
43819
+ requestAnimationFrame(() => {
43820
+ if (!editor.isDestroyed) {
43821
+ var _window;
43822
+ view.dom.blur();
43823
+ (_window = window) === null || _window === void 0 || (_window = _window.getSelection()) === null || _window === void 0 || _window.removeAllRanges();
43824
+ }
43825
+ });
43826
+ return true;
43827
+ };
43828
+ //#endregion
43829
+ //#region src/commands/clearContent.ts
43830
+ const clearContent = (emitUpdate = true) => ({ commands }) => {
43831
+ return commands.setContent("", { emitUpdate });
43832
+ };
43833
+ //#endregion
43834
+ //#region src/commands/clearNodes.ts
43835
+ const clearNodes = () => ({ state, tr, dispatch }) => {
43836
+ const { selection } = tr;
43837
+ const { ranges } = selection;
43838
+ if (!dispatch) return true;
43839
+ ranges.forEach(({ $from, $to }) => {
43840
+ state.doc.nodesBetween($from.pos, $to.pos, (node, pos) => {
43841
+ if (node.type.isText) return;
43842
+ const { doc, mapping } = tr;
43843
+ const $mappedFrom = doc.resolve(mapping.map(pos));
43844
+ const $mappedTo = doc.resolve(mapping.map(pos + node.nodeSize));
43845
+ const nodeRange = $mappedFrom.blockRange($mappedTo);
43846
+ if (!nodeRange) return;
43847
+ const targetLiftDepth = liftTarget(nodeRange);
43848
+ if (node.type.isTextblock) {
43849
+ const { defaultType } = $mappedFrom.parent.contentMatchAt($mappedFrom.index());
43850
+ tr.setNodeMarkup(nodeRange.start, defaultType);
43851
+ }
43852
+ if (targetLiftDepth || targetLiftDepth === 0) tr.lift(nodeRange, targetLiftDepth);
43853
+ });
43854
+ });
43855
+ return true;
43856
+ };
43857
+ //#endregion
43858
+ //#region src/commands/command.ts
43859
+ const command = (fn) => (props) => {
43860
+ return fn(props);
43861
+ };
43862
+ //#endregion
43863
+ //#region src/commands/createParagraphNear.ts
43864
+ const createParagraphNear$1 = () => ({ state, dispatch }) => {
43865
+ return createParagraphNear(state, dispatch);
43866
+ };
43867
+ //#endregion
43868
+ //#region src/commands/cut.ts
43869
+ const cut = (originRange, targetPos) => ({ editor, tr }) => {
43870
+ const { state } = editor;
43871
+ const contentSlice = state.doc.slice(originRange.from, originRange.to);
43872
+ tr.deleteRange(originRange.from, originRange.to);
43873
+ const newPos = tr.mapping.map(targetPos);
43874
+ tr.insert(newPos, contentSlice.content);
43875
+ tr.setSelection(new TextSelection(tr.doc.resolve(Math.max(newPos - 1, 0))));
43876
+ return true;
43877
+ };
43878
+ //#endregion
43879
+ //#region src/commands/deleteCurrentNode.ts
43880
+ const deleteCurrentNode = () => ({ tr, dispatch }) => {
43881
+ const { selection } = tr;
43882
+ const currentNode = selection.$anchor.node();
43883
+ if (currentNode.content.size > 0) return false;
43884
+ const $pos = tr.selection.$anchor;
43885
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === currentNode.type) {
43886
+ if (dispatch) {
43887
+ const from = $pos.before(depth);
43888
+ const to = $pos.after(depth);
43889
+ tr.delete(from, to).scrollIntoView();
43890
+ }
43891
+ return true;
43892
+ }
43893
+ return false;
43894
+ };
43895
+ //#endregion
43896
+ //#region src/helpers/getNodeType.ts
43897
+ function getNodeType(nameOrType, schema) {
43898
+ if (typeof nameOrType === "string") {
43899
+ if (!schema.nodes[nameOrType]) throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
43900
+ return schema.nodes[nameOrType];
43901
+ }
43902
+ return nameOrType;
43903
+ }
43904
+ //#endregion
43905
+ //#region src/commands/deleteNode.ts
43906
+ const deleteNode = (typeOrName) => ({ tr, state, dispatch }) => {
43907
+ const type = getNodeType(typeOrName, state.schema);
43908
+ const $pos = tr.selection.$anchor;
43909
+ for (let depth = $pos.depth; depth > 0; depth -= 1) if ($pos.node(depth).type === type) {
43910
+ if (dispatch) {
43911
+ const from = $pos.before(depth);
43912
+ const to = $pos.after(depth);
43913
+ tr.delete(from, to).scrollIntoView();
43914
+ }
43915
+ return true;
43916
+ }
43917
+ return false;
43918
+ };
43919
+ //#endregion
43920
+ //#region src/commands/deleteRange.ts
43921
+ const deleteRange = (range) => ({ tr, dispatch }) => {
43922
+ const { from, to } = range;
43923
+ if (dispatch) tr.delete(from, to);
43924
+ return true;
43925
+ };
43926
+ //#endregion
43927
+ //#region src/commands/deleteSelection.ts
43928
+ /**
43929
+ * Check if a node has text content based on its content specification.
43930
+ * Returns true if the node's content spec matches text* or text+ patterns.
43931
+ */
43932
+ const hasTextContent = (nodeSpec) => {
43933
+ if (!nodeSpec.content) return false;
43934
+ return /^text(\*|\+)/.test(nodeSpec.content);
43935
+ };
43936
+ /**
43937
+ * Expand selection position for a specific side (left or right) to handle inline text nodes.
43938
+ * This function checks if the position is within an inline node with text content and
43939
+ * expands it to include the entire node boundaries for proper deletion.
43940
+ * @param $pos - The resolved position to expand
43941
+ * @param schema - The ProseMirror schema
43942
+ * @param side - Which side to expand ('left' or 'right')
43943
+ * @returns The expanded position for deletion
43944
+ */
43945
+ const expandSelectionForSide = ($pos, schema, side) => {
43946
+ if (!$pos.parent.isInline) return $pos.pos;
43947
+ if (side === "left" && $pos.pos > $pos.start() || side === "right" && $pos.pos < $pos.end()) return $pos.pos;
43948
+ const parentContent = schema.nodes[$pos.parent.type.name].spec;
43949
+ if (!hasTextContent(parentContent)) return $pos.pos;
43950
+ return side === "left" ? $pos.start() - 1 : $pos.end() + 1;
43951
+ };
43952
+ /**
43953
+ * Expand selection range to properly handle deletion of inline text nodes.
43954
+ * Inline text nodes don't collapse correctly when text inside is deleted,
43955
+ * so we need to expand the selection to include the entire node.
43956
+ * See: https://code.haverbeke.berlin/prosemirror/prosemirror/issues/1365
43957
+ */
43958
+ const expandSelectionForInlineText = ($from, $to, schema) => {
43959
+ return {
43960
+ from: expandSelectionForSide($from, schema, "left"),
43961
+ to: expandSelectionForSide($to, schema, "right")
43962
+ };
43963
+ };
43964
+ const deleteSelection = () => ({ state, dispatch }) => {
43965
+ if (state.selection.empty) return false;
43966
+ if (dispatch) {
43967
+ const tr = state.tr;
43968
+ const { ranges } = state.selection;
43969
+ const mapFrom = tr.steps.length;
43970
+ ranges.forEach((range) => {
43971
+ const mapping = tr.mapping.slice(mapFrom);
43972
+ const $from = tr.doc.resolve(mapping.map(range.$from.pos));
43973
+ const $to = tr.doc.resolve(mapping.map(range.$to.pos));
43974
+ const { from, to } = expandSelectionForInlineText($from, $to, state.schema);
43975
+ tr.deleteRange(from, to);
43976
+ });
43977
+ if (!tr.selection.empty) tr.setSelection(TextSelection.near(tr.doc.resolve(tr.selection.from)));
43978
+ tr.scrollIntoView();
43979
+ dispatch(tr);
43980
+ }
43981
+ return true;
43982
+ };
43983
+ //#endregion
43984
+ //#region src/commands/enter.ts
43985
+ const enter = () => ({ commands }) => {
43986
+ return commands.keyboardShortcut("Enter");
43987
+ };
43988
+ //#endregion
43989
+ //#region src/commands/exitCode.ts
43990
+ const exitCode$1 = () => ({ state, dispatch }) => {
43991
+ return exitCode(state, dispatch);
43992
+ };
43993
+ //#endregion
43994
+ //#region src/utilities/isRegExp.ts
43995
+ function isRegExp$1(value) {
43996
+ return Object.prototype.toString.call(value) === "[object RegExp]";
43997
+ }
43998
+ //#endregion
43999
+ //#region src/utilities/objectIncludes.ts
44000
+ /**
44001
+ * Check if object1 includes object2
44002
+ * @param object1 Object
44003
+ * @param object2 Object
44004
+ */
44005
+ function objectIncludes(object1, object2, options = { strict: true }) {
44006
+ const keys = Object.keys(object2);
44007
+ if (!keys.length) return true;
44008
+ return keys.every((key) => {
44009
+ if (options.strict) return object2[key] === object1[key];
44010
+ if (isRegExp$1(object2[key])) return object2[key].test(object1[key]);
44011
+ return object2[key] === object1[key];
44012
+ });
44013
+ }
44014
+ //#endregion
44015
+ //#region src/helpers/getMarkRange.ts
44016
+ function findMarkInSet(marks, type, attributes = {}) {
44017
+ return marks.find((item) => {
44018
+ return item.type === type && objectIncludes(Object.fromEntries(Object.keys(attributes).map((k) => [k, item.attrs[k]])), attributes);
44019
+ });
44020
+ }
44021
+ function isMarkInSet(marks, type, attributes = {}) {
44022
+ return !!findMarkInSet(marks, type, attributes);
44023
+ }
44024
+ /**
44025
+ * Get the range of a mark at a resolved position.
44026
+ */
44027
+ function getMarkRange($pos, type, attributes) {
44028
+ if (!$pos || !type) return;
44029
+ let start = $pos.parent.childAfter($pos.parentOffset);
43361
44030
  if (!start.node || !start.node.marks.some((mark) => mark.type === type)) start = $pos.parent.childBefore($pos.parentOffset);
43362
44031
  if (!start.node || !start.node.marks.some((mark) => mark.type === type)) return;
43363
44032
  if (!attributes) {
@@ -43784,11 +44453,21 @@ so this becomes the fallback color for the slot */ ''}
43784
44453
  return joinForward(state, dispatch);
43785
44454
  };
43786
44455
  //#endregion
44456
+ //#region src/commands/canJoinItemsAt.ts
44457
+ const canJoinItemsAt = (doc, pos) => {
44458
+ const $pos = doc.resolve(pos);
44459
+ const before = $pos.nodeBefore;
44460
+ const after = $pos.nodeAfter;
44461
+ if (!before || !after) return false;
44462
+ return !before.type.spec.isolating && !after.type.spec.isolating;
44463
+ };
44464
+ //#endregion
43787
44465
  //#region src/commands/joinItemBackward.ts
43788
44466
  const joinItemBackward = () => ({ state, dispatch, tr }) => {
43789
44467
  try {
43790
44468
  const point = joinPoint(state.doc, state.selection.$from.pos, -1);
43791
44469
  if (point === null || point === void 0) return false;
44470
+ if (!canJoinItemsAt(state.doc, point)) return false;
43792
44471
  tr.join(point, 2);
43793
44472
  if (dispatch) dispatch(tr);
43794
44473
  return true;
@@ -43802,6 +44481,7 @@ so this becomes the fallback color for the slot */ ''}
43802
44481
  try {
43803
44482
  const point = joinPoint(state.doc, state.selection.$from.pos, 1);
43804
44483
  if (point === null || point === void 0) return false;
44484
+ if (!canJoinItemsAt(state.doc, point)) return false;
43805
44485
  tr.join(point, 2);
43806
44486
  if (dispatch) dispatch(tr);
43807
44487
  return true;
@@ -45208,8 +45888,14 @@ so this becomes the fallback color for the slot */ ''}
45208
45888
  type: deflt,
45209
45889
  attrs: newAttributes
45210
45890
  }] : void 0;
45211
- let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types);
45212
- if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : void 0)) {
45891
+ const deletedTr = selection instanceof TextSelection && !selection.empty ? EditorState.create({
45892
+ doc: tr.doc,
45893
+ selection
45894
+ }).tr.deleteSelection() : null;
45895
+ const splitDoc = deletedTr ? deletedTr.doc : tr.doc;
45896
+ const splitPos = deletedTr ? deletedTr.mapping.map($from.pos) : $from.pos;
45897
+ let can = canSplit(splitDoc, splitPos, 1, types);
45898
+ if (!types && !can && canSplit(splitDoc, splitPos, 1, deflt ? [{ type: deflt }] : void 0)) {
45213
45899
  can = true;
45214
45900
  types = deflt ? [{
45215
45901
  type: deflt,
@@ -45218,12 +45904,13 @@ so this becomes the fallback color for the slot */ ''}
45218
45904
  }
45219
45905
  if (dispatch) {
45220
45906
  if (can) {
45907
+ const mapFrom = tr.steps.length;
45221
45908
  if (selection instanceof TextSelection) tr.deleteSelection();
45222
- tr.split(tr.mapping.map($from.pos), 1, types);
45909
+ tr.split(tr.mapping.slice(mapFrom).map($from.pos), 1, types);
45223
45910
  if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
45224
- const first = tr.mapping.map($from.before());
45911
+ const first = tr.mapping.slice(mapFrom).map($from.before());
45225
45912
  const $first = tr.doc.resolve(first);
45226
- if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
45913
+ if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) tr.setNodeMarkup(tr.mapping.slice(mapFrom).map($from.before()), deflt);
45227
45914
  }
45228
45915
  }
45229
45916
  if (keepMarks) ensureMarks(state, editor.extensionManager.splittableMarks);
@@ -45276,16 +45963,19 @@ so this becomes the fallback color for the slot */ ''}
45276
45963
  ...getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs),
45277
45964
  ...overrideAttrs
45278
45965
  };
45966
+ const splitsAtStartOfItem = $from.parentOffset === 0 && $from.index(-1) === 0;
45967
+ const itemStart = $from.before(-1);
45279
45968
  tr.delete($from.pos, $to.pos);
45969
+ const trailingTypeAttributes = splitsAtStartOfItem ? grandParent.attrs : newTypeAttributes;
45280
45970
  const types = nextType ? [{
45281
45971
  type,
45282
- attrs: newTypeAttributes
45972
+ attrs: trailingTypeAttributes
45283
45973
  }, {
45284
45974
  type: nextType,
45285
45975
  attrs: newNextTypeAttributes
45286
45976
  }] : [{
45287
45977
  type,
45288
- attrs: newTypeAttributes
45978
+ attrs: trailingTypeAttributes
45289
45979
  }];
45290
45980
  if (!canSplit(tr.doc, $from.pos, 2)) return false;
45291
45981
  if (dispatch) {
@@ -45293,6 +45983,7 @@ so this becomes the fallback color for the slot */ ''}
45293
45983
  const { splittableMarks } = editor.extensionManager;
45294
45984
  const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
45295
45985
  tr.split($from.pos, 2, types).scrollIntoView();
45986
+ if (splitsAtStartOfItem) tr.setNodeMarkup(itemStart, void 0, newTypeAttributes);
45296
45987
  if (!marks || !dispatch) return true;
45297
45988
  const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
45298
45989
  tr.ensureMarks(filteredMarks);
@@ -46825,55 +47516,106 @@ so this becomes the fallback color for the slot */ ''}
46825
47516
  }
46826
47517
  return result;
46827
47518
  };
47519
+ /**
47520
+ * Prepares the typed text so the rule handler can inspect the resulting document.
47521
+ */
47522
+ function createRuleTransaction(config) {
47523
+ const { editor, from, to, text, insertText } = config;
47524
+ if (!insertText) return {
47525
+ inputTransaction: null,
47526
+ tr: editor.view.state.tr
47527
+ };
47528
+ const inputTransaction = editor.view.state.tr.insertText(text, from, to);
47529
+ return {
47530
+ inputTransaction,
47531
+ tr: EditorState.create({
47532
+ doc: inputTransaction.doc,
47533
+ selection: inputTransaction.selection,
47534
+ storedMarks: inputTransaction.storedMarks
47535
+ }).tr
47536
+ };
47537
+ }
47538
+ /**
47539
+ * Runs a matching rule and dispatches the typed text before its conversion.
47540
+ */
47541
+ function applyRule(config) {
47542
+ const { editor, from, to, text, rule, match, plugin, insertText } = config;
47543
+ const { view } = editor;
47544
+ const { inputTransaction, tr } = createRuleTransaction({
47545
+ editor,
47546
+ from,
47547
+ to,
47548
+ text,
47549
+ insertText
47550
+ });
47551
+ const inputEnd = inputTransaction ? from + text.length : to;
47552
+ const state = createChainableState({
47553
+ state: view.state,
47554
+ transaction: tr
47555
+ });
47556
+ const range = {
47557
+ from: from - (match[0].length - text.length),
47558
+ to: inputEnd
47559
+ };
47560
+ const { commands, chain, can } = new CommandManager({
47561
+ editor,
47562
+ state
47563
+ });
47564
+ if (rule.handler({
47565
+ state,
47566
+ range,
47567
+ match,
47568
+ commands,
47569
+ chain,
47570
+ can
47571
+ }) === null || !tr.steps.length) return false;
47572
+ if (inputTransaction) {
47573
+ view.dispatch(inputTransaction);
47574
+ if (!view.state.doc.eq(inputTransaction.doc)) return true;
47575
+ }
47576
+ closeHistory(tr);
47577
+ tr.setMeta("inputRule", true);
47578
+ if (rule.undoable) tr.setMeta(plugin, {
47579
+ transform: tr,
47580
+ from,
47581
+ to: inputEnd,
47582
+ text
47583
+ });
47584
+ view.dispatch(tr);
47585
+ return true;
47586
+ }
47587
+ /**
47588
+ * Checks that the part of a match already in the document has matching positions.
47589
+ */
47590
+ function matchesDocument($from, match, text) {
47591
+ const matchedDocLength = match[0].length - text.length;
47592
+ if (matchedDocLength <= 0) return true;
47593
+ const matchStartOffset = $from.parentOffset - matchedDocLength;
47594
+ return matchStartOffset >= 0 && $from.parent.textBetween(matchStartOffset, $from.parentOffset) === match[0].slice(0, matchedDocLength);
47595
+ }
46828
47596
  function run$1$1(config) {
46829
47597
  var _ref;
46830
- const { editor, from, to, text, rules, plugin } = config;
47598
+ const { editor, from, to, text, rules, plugin, insertText } = config;
46831
47599
  const { view } = editor;
46832
47600
  if (view.composing) return false;
46833
47601
  const $from = view.state.doc.resolve(from);
46834
47602
  if ($from.parent.type.spec.code || !!((_ref = $from.nodeBefore || $from.nodeAfter) === null || _ref === void 0 ? void 0 : _ref.marks.find((mark) => mark.type.spec.code))) return false;
46835
- let matched = false;
46836
47603
  const textBefore = getTextContentFromNodes($from) + text;
46837
- rules.forEach((rule) => {
46838
- if (matched) return;
47604
+ for (const rule of rules) {
46839
47605
  const match = inputRuleMatcherHandler(textBefore, rule.find);
46840
- if (!match) return;
46841
- const matchedDocLength = match[0].length - text.length;
46842
- if (matchedDocLength > 0) {
46843
- const matchStartOffset = $from.parentOffset - matchedDocLength;
46844
- if (matchStartOffset < 0 || $from.parent.textBetween(matchStartOffset, $from.parentOffset) !== match[0].slice(0, matchedDocLength)) return;
46845
- }
46846
- const tr = view.state.tr;
46847
- const state = createChainableState({
46848
- state: view.state,
46849
- transaction: tr
46850
- });
46851
- const range = {
46852
- from: from - (match[0].length - text.length),
46853
- to
46854
- };
46855
- const { commands, chain, can } = new CommandManager({
47606
+ if (!match || !matchesDocument($from, match, text)) continue;
47607
+ if (applyRule({
46856
47608
  editor,
46857
- state
46858
- });
46859
- if (rule.handler({
46860
- state,
46861
- range,
46862
- match,
46863
- commands,
46864
- chain,
46865
- can
46866
- }) === null || !tr.steps.length) return;
46867
- if (rule.undoable) tr.setMeta(plugin, {
46868
- transform: tr,
46869
47609
  from,
46870
47610
  to,
46871
- text
46872
- });
46873
- view.dispatch(tr);
46874
- matched = true;
46875
- });
46876
- return matched;
47611
+ text,
47612
+ rule,
47613
+ match,
47614
+ plugin,
47615
+ insertText
47616
+ })) return true;
47617
+ }
47618
+ return false;
46877
47619
  }
46878
47620
  /**
46879
47621
  * Create an input rules plugin. When enabled, it will cause text
@@ -46917,7 +47659,8 @@ so this becomes the fallback color for the slot */ ''}
46917
47659
  to,
46918
47660
  text,
46919
47661
  rules,
46920
- plugin
47662
+ plugin,
47663
+ insertText: true
46921
47664
  });
46922
47665
  },
46923
47666
  handleDOMEvents: { compositionend: (view) => {
@@ -47153,6 +47896,9 @@ so this becomes the fallback color for the slot */ ''}
47153
47896
  pasteEvent = typeof ClipboardEvent !== "undefined" ? new ClipboardEvent("paste") : null;
47154
47897
  return tr;
47155
47898
  };
47899
+ editor.on("destroy", () => {
47900
+ if (tiptapDragFromOtherEditor === editor) tiptapDragFromOtherEditor = null;
47901
+ });
47156
47902
  return rules.map((rule) => {
47157
47903
  return new Plugin({
47158
47904
  view(view) {
@@ -47178,6 +47924,7 @@ so this becomes the fallback color for the slot */ ''}
47178
47924
  if (!isDroppedFromProseMirror) {
47179
47925
  const dragFromOtherEditor = tiptapDragFromOtherEditor;
47180
47926
  if (dragFromOtherEditor === null || dragFromOtherEditor === void 0 ? void 0 : dragFromOtherEditor.isEditable) setTimeout(() => {
47927
+ if (dragFromOtherEditor.isDestroyed) return;
47181
47928
  const selection = dragFromOtherEditor.state.selection;
47182
47929
  if (selection) dragFromOtherEditor.commands.deleteRange({
47183
47930
  from: selection.from,
@@ -48347,7 +49094,10 @@ img.ProseMirror-separator {
48347
49094
  ...options
48348
49095
  };
48349
49096
  if (!this.editorView || !this.state || this.isDestroyed) return;
48350
- if (this.options.editorProps) this.view.setProps(this.options.editorProps);
49097
+ if (this.options.editorProps) this.view.setProps({
49098
+ ...this.options.editorProps,
49099
+ attributes: this.getEditorViewAttributes()
49100
+ });
48351
49101
  this.view.updateState(this.state);
48352
49102
  }
48353
49103
  /**
@@ -48503,6 +49253,23 @@ img.ProseMirror-separator {
48503
49253
  return doc;
48504
49254
  }
48505
49255
  /**
49256
+ * Returns the attributes for the editor element.
49257
+ * Merges the default `role="textbox"` with the attributes from `editorProps`,
49258
+ * so the role is kept no matter when the props are applied.
49259
+ */
49260
+ getEditorViewAttributes() {
49261
+ var _this$options$editorP;
49262
+ const attributes = (_this$options$editorP = this.options.editorProps) === null || _this$options$editorP === void 0 ? void 0 : _this$options$editorP.attributes;
49263
+ if (isFunction$3(attributes)) return (state) => ({
49264
+ role: "textbox",
49265
+ ...attributes(state)
49266
+ });
49267
+ return {
49268
+ role: "textbox",
49269
+ ...attributes
49270
+ };
49271
+ }
49272
+ /**
48506
49273
  * Creates a ProseMirror view.
48507
49274
  */
48508
49275
  createView(element) {
@@ -48513,10 +49280,7 @@ img.ProseMirror-separator {
48513
49280
  const transformPastedHTML = this.extensionManager.transformPastedHTML(baseTransformPastedHTML);
48514
49281
  this.editorView = new EditorView(element, {
48515
49282
  ...editorProps,
48516
- attributes: {
48517
- role: "textbox",
48518
- ...editorProps === null || editorProps === void 0 ? void 0 : editorProps.attributes
48519
- },
49283
+ attributes: this.getEditorViewAttributes(),
48520
49284
  dispatchTransaction: dispatch,
48521
49285
  transformPastedHTML,
48522
49286
  state: this.editorState,
@@ -58219,7 +58983,7 @@ img.ProseMirror-separator {
58219
58983
  toDOM() { return ["div", ["hr"]]; }
58220
58984
  },
58221
58985
  heading: {
58222
- attrs: { level: { default: 1 } },
58986
+ attrs: { level: { default: 1, validate: "number" } },
58223
58987
  content: "(text | image)*",
58224
58988
  group: "block",
58225
58989
  defining: true,
@@ -58229,7 +58993,7 @@ img.ProseMirror-separator {
58229
58993
  { tag: "h4", attrs: { level: 4 } },
58230
58994
  { tag: "h5", attrs: { level: 5 } },
58231
58995
  { tag: "h6", attrs: { level: 6 } }],
58232
- toDOM(node) { return ["h" + node.attrs.level, 0]; }
58996
+ toDOM(node) { return ["h" + +node.attrs.level, 0]; }
58233
58997
  },
58234
58998
  code_block: {
58235
58999
  content: "text*",
@@ -61726,8 +62490,27 @@ img.ProseMirror-separator {
61726
62490
  const UNICODE_WHITESPACE_PATTERN = "[\0- \xA0 ᠎ -\u2029  ]";
61727
62491
  const UNICODE_WHITESPACE_REGEX = new RegExp(UNICODE_WHITESPACE_PATTERN);
61728
62492
  const UNICODE_WHITESPACE_REGEX_END = new RegExp(`${UNICODE_WHITESPACE_PATTERN}$`);
62493
+ const UNICODE_WHITESPACE_REGEX_TRAILING = new RegExp(`${UNICODE_WHITESPACE_PATTERN}+$`);
61729
62494
  const UNICODE_WHITESPACE_REGEX_GLOBAL = new RegExp(UNICODE_WHITESPACE_PATTERN, "g");
61730
62495
  //#endregion
62496
+ //#region src/helpers/unlinkTrailingWhitespace.ts
62497
+ function unlinkTrailingWhitespace(tr, range, type) {
62498
+ var _rangeEnd$nodeBefore, _insertedText$match;
62499
+ const rangeEnd = tr.doc.resolve(range.to);
62500
+ if (!((_rangeEnd$nodeBefore = rangeEnd.nodeBefore) === null || _rangeEnd$nodeBefore === void 0 ? void 0 : _rangeEnd$nodeBefore.isText)) return;
62501
+ 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];
62502
+ if (!trailingWhitespace) return;
62503
+ const whitespaceFrom = range.to - trailingWhitespace.length;
62504
+ const linkMarks = getMarksBetween(whitespaceFrom, range.to, tr.doc).filter((item) => item.mark.type === type);
62505
+ if (!linkMarks.length) return;
62506
+ const { nodeAfter } = rangeEnd;
62507
+ if (!!nodeAfter && linkMarks.some((item) => item.mark.isInSet(nodeAfter.marks))) return;
62508
+ const storedMarks = tr.storedMarks;
62509
+ tr.removeMark(whitespaceFrom, range.to, type);
62510
+ tr.setStoredMarks(storedMarks);
62511
+ if (tr.selection.empty && tr.selection.from === range.to) tr.removeStoredMark(type);
62512
+ }
62513
+ //#endregion
61731
62514
  //#region src/helpers/autolink.ts
61732
62515
  /**
61733
62516
  * Check if the provided tokens form a valid link structure, which can either be a single link token
@@ -61768,6 +62551,21 @@ img.ProseMirror-separator {
61768
62551
  if (!docChanges || preventAutolink) return;
61769
62552
  const { tr } = newState;
61770
62553
  const transform = combineTransactionSteps(oldState.doc, [...transactions]);
62554
+ if (!transactions.some(isHistoryTransaction)) {
62555
+ const insertedRanges = [];
62556
+ transform.steps.forEach((step, index) => {
62557
+ if (!(step instanceof ReplaceStep) || !step.slice.size) return;
62558
+ const mapping = transform.mapping.slice(index + 1);
62559
+ const from = mapping.map(step.from, 1);
62560
+ const to = mapping.map(step.from + step.slice.size, -1);
62561
+ if (from < to) insertedRanges.push({
62562
+ from,
62563
+ to
62564
+ });
62565
+ });
62566
+ insertedRanges.sort((left, right) => right.to - left.to);
62567
+ insertedRanges.forEach((range) => unlinkTrailingWhitespace(tr, range, options.type));
62568
+ }
61771
62569
  getChangedRanges(transform).forEach(({ newRange }) => {
61772
62570
  const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, (node) => node.isTextblock);
61773
62571
  let textBlock;
@@ -63154,6 +63952,54 @@ img.ProseMirror-separator {
63154
63952
  });
63155
63953
  }
63156
63954
  //#endregion
63955
+ //#region src/ordered-list/collectOrderedListItemsFromSource.ts
63956
+ const ORDERED_LIST_SCAN_WINDOW = 64;
63957
+ function takeLines(source, max) {
63958
+ const lines = [];
63959
+ let start = 0;
63960
+ while (lines.length < max) {
63961
+ const lineEnd = source.indexOf("\n", start);
63962
+ if (lineEnd === -1) {
63963
+ lines.push(source.slice(start));
63964
+ return lines;
63965
+ }
63966
+ lines.push(source.slice(start, lineEnd));
63967
+ start = lineEnd + 1;
63968
+ }
63969
+ return lines;
63970
+ }
63971
+ /**
63972
+ * Collect ordered list items from the start of `source`, reading only the lines the list needs.
63973
+ *
63974
+ * @param source Markdown beginning at a block boundary.
63975
+ * @returns The items, how many lines they consumed, and the lines that were read.
63976
+ * @example
63977
+ * collectOrderedListItemsFromSource('1. one\n2. two\n\nAfter')
63978
+ * // → [[item, item], 3, ['1. one', '2. two', '', 'After']]
63979
+ */
63980
+ function collectOrderedListItemsFromSource(source) {
63981
+ const firstLineEnd = source.indexOf("\n");
63982
+ const firstLine = firstLineEnd === -1 ? source : source.slice(0, firstLineEnd);
63983
+ if (!ORDERED_LIST_ITEM_REGEX.test(firstLine)) return [
63984
+ [],
63985
+ 0,
63986
+ []
63987
+ ];
63988
+ let windowSize = ORDERED_LIST_SCAN_WINDOW;
63989
+ let lines = takeLines(source, windowSize);
63990
+ let collected = collectOrderedListItems(lines);
63991
+ while (collected[1] === lines.length && lines.length === windowSize) {
63992
+ windowSize *= 2;
63993
+ lines = takeLines(source, windowSize);
63994
+ collected = collectOrderedListItems(lines);
63995
+ }
63996
+ return [
63997
+ collected[0],
63998
+ collected[1],
63999
+ lines
64000
+ ];
64001
+ }
64002
+ //#endregion
63157
64003
  //#region src/ordered-list/ordered-list.ts
63158
64004
  const ListItemName = "listItem";
63159
64005
  const TextStyleName = "textStyle";
@@ -63272,8 +64118,7 @@ img.ProseMirror-separator {
63272
64118
  start: () => -1,
63273
64119
  tokenize: (src, _tokens, lexer) => {
63274
64120
  var _listItems$, _listItems$2;
63275
- const lines = src.split("\n");
63276
- const [listItems, consumed] = collectOrderedListItems(lines);
64121
+ const [listItems, consumed, lines] = collectOrderedListItemsFromSource(src);
63277
64122
  if (listItems.length === 0) return;
63278
64123
  const items = buildNestedStructure(listItems, listItems[0].indent, lexer);
63279
64124
  if (items.length === 0) return;
@@ -66044,1028 +66889,414 @@ img.ProseMirror-separator {
66044
66889
  //#region src/text.ts
66045
66890
  /**
66046
66891
  * This extension allows you to create text nodes.
66047
- * @see https://www.tiptap.dev/api/nodes/text
66048
- */
66049
- const Text = Node$1.create({
66050
- name: "text",
66051
- group: "inline",
66052
- parseMarkdown: (token) => {
66053
- return {
66054
- type: "text",
66055
- text: token.text || ""
66056
- };
66057
- },
66058
- renderMarkdown: (node) => node.text || ""
66059
- });
66060
- //#endregion
66061
- //#region src/index.ts
66062
- var src_default = Text;
66063
-
66064
- /**
66065
- Create a plugin that, when added to a ProseMirror instance,
66066
- causes a decoration to show up at the drop position when something
66067
- is dragged over the editor.
66068
-
66069
- Nodes may add a `disableDropCursor` property to their spec to
66070
- control the showing of a drop cursor inside them. This may be a
66071
- boolean or a function, which will be called with a view and a
66072
- position, and should return a boolean.
66073
- */
66074
- function dropCursor(options = {}) {
66075
- return new Plugin({
66076
- view(editorView) { return new DropCursorView(editorView, options); }
66077
- });
66078
- }
66079
- class DropCursorView {
66080
- constructor(editorView, options) {
66081
- var _a;
66082
- this.editorView = editorView;
66083
- this.cursorPos = null;
66084
- this.element = null;
66085
- this.timeout = -1;
66086
- this.lastDragEvent = null;
66087
- this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66088
- this.color = options.color === false ? undefined : (options.color || "black");
66089
- this.class = options.class;
66090
- this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66091
- let handler = (e) => { this[name](e); };
66092
- editorView.dom.addEventListener(name, handler);
66093
- return { name, handler };
66094
- });
66095
- }
66096
- destroy() {
66097
- this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66098
- }
66099
- update(editorView, prevState) {
66100
- if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66101
- // if we currently have an on-going drag event
66102
- // we need to update the cursor position again and update the overlay
66103
- if (this.lastDragEvent) {
66104
- let target = this.computeTarget(this.lastDragEvent);
66105
- if (target == this.cursorPos)
66106
- this.updateOverlay();
66107
- else
66108
- this.setCursor(target);
66109
- }
66110
- else {
66111
- this.updateOverlay();
66112
- }
66113
- }
66114
- }
66115
- setCursor(pos) {
66116
- if (pos == this.cursorPos)
66117
- return;
66118
- this.cursorPos = pos;
66119
- if (pos == null) {
66120
- this.element.parentNode.removeChild(this.element);
66121
- this.element = null;
66122
- }
66123
- else {
66124
- this.updateOverlay();
66125
- }
66126
- }
66127
- updateOverlay() {
66128
- let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66129
- let isBlock = !$pos.parent.inlineContent, rect;
66130
- let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66131
- let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66132
- if (isBlock) {
66133
- let before = $pos.nodeBefore, after = $pos.nodeAfter;
66134
- if (before || after) {
66135
- let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66136
- if (node) {
66137
- let nodeRect = node.getBoundingClientRect();
66138
- let top = before ? nodeRect.bottom : nodeRect.top;
66139
- if (before && after)
66140
- top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66141
- let halfWidth = (this.width / 2) * scaleY;
66142
- rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66143
- }
66144
- }
66145
- }
66146
- if (!rect) {
66147
- let coords = this.editorView.coordsAtPos(this.cursorPos);
66148
- let halfWidth = (this.width / 2) * scaleX;
66149
- rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66150
- }
66151
- let parent = this.editorView.dom.offsetParent;
66152
- if (!this.element) {
66153
- this.element = parent.appendChild(document.createElement("div"));
66154
- if (this.class)
66155
- this.element.className = this.class;
66156
- this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
66157
- if (this.color) {
66158
- this.element.style.backgroundColor = this.color;
66159
- }
66160
- }
66161
- this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
66162
- this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
66163
- let parentLeft, parentTop;
66164
- if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
66165
- parentLeft = -pageXOffset;
66166
- parentTop = -pageYOffset;
66167
- }
66168
- else {
66169
- let rect = parent.getBoundingClientRect();
66170
- let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
66171
- parentLeft = rect.left - parent.scrollLeft * parentScaleX;
66172
- parentTop = rect.top - parent.scrollTop * parentScaleY;
66173
- }
66174
- this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
66175
- this.element.style.top = (rect.top - parentTop) / scaleY + "px";
66176
- this.element.style.width = (rect.right - rect.left) / scaleX + "px";
66177
- this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66178
- }
66179
- scheduleRemoval(timeout) {
66180
- clearTimeout(this.timeout);
66181
- this.timeout = setTimeout(() => this.setCursor(null), timeout);
66182
- }
66183
- computeTarget(event) {
66184
- let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
66185
- let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
66186
- let disableDropCursor = node && node.type.spec.disableDropCursor;
66187
- let disabled = typeof disableDropCursor == "function"
66188
- ? disableDropCursor(this.editorView, pos, event)
66189
- : disableDropCursor;
66190
- if (!pos || disabled)
66191
- return null;
66192
- let target = pos.pos;
66193
- if (this.editorView.dragging && this.editorView.dragging.slice) {
66194
- let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
66195
- if (point != null)
66196
- target = point;
66197
- }
66198
- return target;
66199
- }
66200
- dragover(event) {
66201
- if (!this.editorView.editable)
66202
- return;
66203
- this.lastDragEvent = event;
66204
- let target = this.computeTarget(event);
66205
- if (target != null) {
66206
- this.setCursor(target);
66207
- this.scheduleRemoval(5000);
66208
- }
66209
- }
66210
- dragend() {
66211
- this.scheduleRemoval(20);
66212
- }
66213
- drop() {
66214
- this.scheduleRemoval(20);
66215
- }
66216
- dragleave(event) {
66217
- if (!this.editorView.dom.contains(event.relatedTarget))
66218
- this.setCursor(null);
66219
- }
66220
- }
66221
-
66222
- /**
66223
- Gap cursor selections are represented using this class. Its
66224
- `$anchor` and `$head` properties both point at the cursor position.
66225
- */
66226
- class GapCursor extends Selection$2 {
66227
- /**
66228
- Create a gap cursor.
66229
- */
66230
- constructor($pos) {
66231
- super($pos, $pos);
66232
- }
66233
- map(doc, mapping) {
66234
- let $pos = doc.resolve(mapping.map(this.head));
66235
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66236
- }
66237
- content() { return Slice.empty; }
66238
- eq(other) {
66239
- return other instanceof GapCursor && other.head == this.head;
66240
- }
66241
- toJSON() {
66242
- return { type: "gapcursor", pos: this.head };
66243
- }
66244
- /**
66245
- @internal
66246
- */
66247
- static fromJSON(doc, json) {
66248
- if (typeof json.pos != "number")
66249
- throw new RangeError("Invalid input for GapCursor.fromJSON");
66250
- return new GapCursor(doc.resolve(json.pos));
66251
- }
66252
- /**
66253
- @internal
66254
- */
66255
- getBookmark() { return new GapBookmark(this.anchor); }
66256
- /**
66257
- @internal
66258
- */
66259
- static valid($pos) {
66260
- let parent = $pos.parent;
66261
- if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
66262
- return false;
66263
- let override = parent.type.spec.allowGapCursor;
66264
- if (override != null)
66265
- return override;
66266
- let deflt = parent.contentMatchAt($pos.index()).defaultType;
66267
- return deflt && deflt.isTextblock;
66268
- }
66269
- /**
66270
- @internal
66271
- */
66272
- static findGapCursorFrom($pos, dir, mustMove = false) {
66273
- search: for (;;) {
66274
- if (!mustMove && GapCursor.valid($pos))
66275
- return $pos;
66276
- let pos = $pos.pos, next = null;
66277
- // Scan up from this position
66278
- for (let d = $pos.depth;; d--) {
66279
- let parent = $pos.node(d);
66280
- if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
66281
- next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
66282
- break;
66283
- }
66284
- else if (d == 0) {
66285
- return null;
66286
- }
66287
- pos += dir;
66288
- let $cur = $pos.doc.resolve(pos);
66289
- if (GapCursor.valid($cur))
66290
- return $cur;
66291
- }
66292
- // And then down into the next node
66293
- for (;;) {
66294
- let inside = dir > 0 ? next.firstChild : next.lastChild;
66295
- if (!inside) {
66296
- if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
66297
- $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
66298
- mustMove = false;
66299
- continue search;
66300
- }
66301
- break;
66302
- }
66303
- next = inside;
66304
- pos += dir;
66305
- let $cur = $pos.doc.resolve(pos);
66306
- if (GapCursor.valid($cur))
66307
- return $cur;
66308
- }
66309
- return null;
66310
- }
66311
- }
66312
- }
66313
- GapCursor.prototype.visible = false;
66314
- GapCursor.findFrom = GapCursor.findGapCursorFrom;
66315
- Selection$2.jsonID("gapcursor", GapCursor);
66316
- class GapBookmark {
66317
- constructor(pos) {
66318
- this.pos = pos;
66319
- }
66320
- map(mapping) {
66321
- return new GapBookmark(mapping.map(this.pos));
66322
- }
66323
- resolve(doc) {
66324
- let $pos = doc.resolve(this.pos);
66325
- return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66326
- }
66327
- }
66328
- function needsGap(type) {
66329
- return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66330
- }
66331
- function closedBefore($pos) {
66332
- for (let d = $pos.depth; d >= 0; d--) {
66333
- let index = $pos.index(d), parent = $pos.node(d);
66334
- // At the start of this parent, look at next one
66335
- if (index == 0) {
66336
- if (parent.type.spec.isolating)
66337
- return true;
66338
- continue;
66339
- }
66340
- // See if the node before (or its first ancestor) is closed
66341
- for (let before = parent.child(index - 1);; before = before.lastChild) {
66342
- if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
66343
- return true;
66344
- if (before.inlineContent)
66345
- return false;
66346
- }
66347
- }
66348
- // Hit start of document
66349
- return true;
66350
- }
66351
- function closedAfter($pos) {
66352
- for (let d = $pos.depth; d >= 0; d--) {
66353
- let index = $pos.indexAfter(d), parent = $pos.node(d);
66354
- if (index == parent.childCount) {
66355
- if (parent.type.spec.isolating)
66356
- return true;
66357
- continue;
66358
- }
66359
- for (let after = parent.child(index);; after = after.firstChild) {
66360
- if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
66361
- return true;
66362
- if (after.inlineContent)
66363
- return false;
66364
- }
66365
- }
66366
- return true;
66367
- }
66892
+ * @see https://www.tiptap.dev/api/nodes/text
66893
+ */
66894
+ const Text = Node$1.create({
66895
+ name: "text",
66896
+ group: "inline",
66897
+ parseMarkdown: (token) => {
66898
+ return {
66899
+ type: "text",
66900
+ text: token.text || ""
66901
+ };
66902
+ },
66903
+ renderMarkdown: (node) => node.text || ""
66904
+ });
66905
+ //#endregion
66906
+ //#region src/index.ts
66907
+ var src_default = Text;
66368
66908
 
66369
66909
  /**
66370
- Create a gap cursor plugin. When enabled, this will capture clicks
66371
- near and arrow-key-motion past places that don't have a normally
66372
- selectable position nearby, and create a gap cursor selection for
66373
- them. The cursor is drawn as an element with class
66374
- `ProseMirror-gapcursor`. You can either include
66375
- `style/gapcursor.css` from the package's directory or add your own
66376
- styles to make it visible.
66910
+ Create a plugin that, when added to a ProseMirror instance,
66911
+ causes a decoration to show up at the drop position when something
66912
+ is dragged over the editor.
66913
+
66914
+ Nodes may add a `disableDropCursor` property to their spec to
66915
+ control the showing of a drop cursor inside them. This may be a
66916
+ boolean or a function, which will be called with a view and a
66917
+ position, and should return a boolean.
66377
66918
  */
66378
- function gapCursor() {
66919
+ function dropCursor(options = {}) {
66379
66920
  return new Plugin({
66380
- props: {
66381
- decorations: drawGapCursor,
66382
- createSelectionBetween(_view, $anchor, $head) {
66383
- return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
66384
- },
66385
- handleClick,
66386
- handleKeyDown,
66387
- handleDOMEvents: { beforeinput: beforeinput }
66388
- }
66921
+ view(editorView) { return new DropCursorView(editorView, options); }
66389
66922
  });
66390
66923
  }
66391
- const handleKeyDown = keydownHandler({
66392
- "ArrowLeft": arrow("horiz", -1),
66393
- "ArrowRight": arrow("horiz", 1),
66394
- "ArrowUp": arrow("vert", -1),
66395
- "ArrowDown": arrow("vert", 1)
66396
- });
66397
- function arrow(axis, dir) {
66398
- const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
66399
- return function (state, dispatch, view) {
66400
- let sel = state.selection;
66401
- let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
66402
- if (sel instanceof TextSelection) {
66403
- if (!view.endOfTextblock(dirStr) || $start.depth == 0)
66404
- return false;
66405
- mustMove = false;
66406
- $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
66407
- }
66408
- let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
66409
- if (!$found)
66410
- return false;
66411
- if (dispatch)
66412
- dispatch(state.tr.setSelection(new GapCursor($found)));
66413
- return true;
66414
- };
66415
- }
66416
- function handleClick(view, pos, event) {
66417
- if (!view || !view.editable)
66418
- return false;
66419
- let $pos = view.state.doc.resolve(pos);
66420
- if (!GapCursor.valid($pos))
66421
- return false;
66422
- let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
66423
- if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
66424
- return false;
66425
- view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
66426
- return true;
66427
- }
66428
- // This is a hack that, when a composition starts while a gap cursor
66429
- // is active, quickly creates an inline context for the composition to
66430
- // happen in, to avoid it being aborted by the DOM selection being
66431
- // moved into a valid position.
66432
- function beforeinput(view, event) {
66433
- if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
66434
- return false;
66435
- let { $from } = view.state.selection;
66436
- let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
66437
- if (!insert)
66438
- return false;
66439
- let frag = Fragment.empty;
66440
- for (let i = insert.length - 1; i >= 0; i--)
66441
- frag = Fragment.from(insert[i].createAndFill(null, frag));
66442
- let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
66443
- tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
66444
- view.dispatch(tr);
66445
- return false;
66446
- }
66447
- function drawGapCursor(state) {
66448
- if (!(state.selection instanceof GapCursor))
66449
- return null;
66450
- let node = document.createElement("div");
66451
- node.className = "ProseMirror-gapcursor";
66452
- return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
66453
- }
66454
-
66455
- var GOOD_LEAF_SIZE = 200;
66456
-
66457
- // :: class<T> A rope sequence is a persistent sequence data structure
66458
- // that supports appending, prepending, and slicing without doing a
66459
- // full copy. It is represented as a mostly-balanced tree.
66460
- var RopeSequence = function RopeSequence () {};
66461
-
66462
- RopeSequence.prototype.append = function append (other) {
66463
- if (!other.length) { return this }
66464
- other = RopeSequence.from(other);
66465
-
66466
- return (!this.length && other) ||
66467
- (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
66468
- (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
66469
- this.appendInner(other)
66470
- };
66471
-
66472
- // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
66473
- // Prepend an array or other rope to this one, returning a new rope.
66474
- RopeSequence.prototype.prepend = function prepend (other) {
66475
- if (!other.length) { return this }
66476
- return RopeSequence.from(other).append(this)
66477
- };
66478
-
66479
- RopeSequence.prototype.appendInner = function appendInner (other) {
66480
- return new Append(this, other)
66481
- };
66482
-
66483
- // :: (?number, ?number) → RopeSequence<T>
66484
- // Create a rope repesenting a sub-sequence of this rope.
66485
- RopeSequence.prototype.slice = function slice (from, to) {
66486
- if ( from === void 0 ) from = 0;
66487
- if ( to === void 0 ) to = this.length;
66488
-
66489
- if (from >= to) { return RopeSequence.empty }
66490
- return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
66491
- };
66492
-
66493
- // :: (number) → T
66494
- // Retrieve the element at the given position from this rope.
66495
- RopeSequence.prototype.get = function get (i) {
66496
- if (i < 0 || i >= this.length) { return undefined }
66497
- return this.getInner(i)
66498
- };
66499
-
66500
- // :: ((element: T, index: number) → ?bool, ?number, ?number)
66501
- // Call the given function for each element between the given
66502
- // indices. This tends to be more efficient than looping over the
66503
- // indices and calling `get`, because it doesn't have to descend the
66504
- // tree for every element.
66505
- RopeSequence.prototype.forEach = function forEach (f, from, to) {
66506
- if ( from === void 0 ) from = 0;
66507
- if ( to === void 0 ) to = this.length;
66508
-
66509
- if (from <= to)
66510
- { this.forEachInner(f, from, to, 0); }
66511
- else
66512
- { this.forEachInvertedInner(f, from, to, 0); }
66513
- };
66514
-
66515
- // :: ((element: T, index: number) → U, ?number, ?number) → [U]
66516
- // Map the given functions over the elements of the rope, producing
66517
- // a flat array.
66518
- RopeSequence.prototype.map = function map (f, from, to) {
66519
- if ( from === void 0 ) from = 0;
66520
- if ( to === void 0 ) to = this.length;
66521
-
66522
- var result = [];
66523
- this.forEach(function (elt, i) { return result.push(f(elt, i)); }, from, to);
66524
- return result
66525
- };
66526
-
66527
- // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
66528
- // Create a rope representing the given array, or return the rope
66529
- // itself if a rope was given.
66530
- RopeSequence.from = function from (values) {
66531
- if (values instanceof RopeSequence) { return values }
66532
- return values && values.length ? new Leaf(values) : RopeSequence.empty
66533
- };
66534
-
66535
- var Leaf = /*@__PURE__*/(function (RopeSequence) {
66536
- function Leaf(values) {
66537
- RopeSequence.call(this);
66538
- this.values = values;
66539
- }
66540
-
66541
- if ( RopeSequence ) Leaf.__proto__ = RopeSequence;
66542
- Leaf.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66543
- Leaf.prototype.constructor = Leaf;
66544
-
66545
- var prototypeAccessors = { length: { configurable: true },depth: { configurable: true } };
66546
-
66547
- Leaf.prototype.flatten = function flatten () {
66548
- return this.values
66549
- };
66550
-
66551
- Leaf.prototype.sliceInner = function sliceInner (from, to) {
66552
- if (from == 0 && to == this.length) { return this }
66553
- return new Leaf(this.values.slice(from, to))
66554
- };
66555
-
66556
- Leaf.prototype.getInner = function getInner (i) {
66557
- return this.values[i]
66558
- };
66559
-
66560
- Leaf.prototype.forEachInner = function forEachInner (f, from, to, start) {
66561
- for (var i = from; i < to; i++)
66562
- { if (f(this.values[i], start + i) === false) { return false } }
66563
- };
66564
-
66565
- Leaf.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66566
- for (var i = from - 1; i >= to; i--)
66567
- { if (f(this.values[i], start + i) === false) { return false } }
66568
- };
66569
-
66570
- Leaf.prototype.leafAppend = function leafAppend (other) {
66571
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66572
- { return new Leaf(this.values.concat(other.flatten())) }
66573
- };
66574
-
66575
- Leaf.prototype.leafPrepend = function leafPrepend (other) {
66576
- if (this.length + other.length <= GOOD_LEAF_SIZE)
66577
- { return new Leaf(other.flatten().concat(this.values)) }
66578
- };
66579
-
66580
- prototypeAccessors.length.get = function () { return this.values.length };
66581
-
66582
- prototypeAccessors.depth.get = function () { return 0 };
66583
-
66584
- Object.defineProperties( Leaf.prototype, prototypeAccessors );
66585
-
66586
- return Leaf;
66587
- }(RopeSequence));
66588
-
66589
- // :: RopeSequence
66590
- // The empty rope sequence.
66591
- RopeSequence.empty = new Leaf([]);
66592
-
66593
- var Append = /*@__PURE__*/(function (RopeSequence) {
66594
- function Append(left, right) {
66595
- RopeSequence.call(this);
66596
- this.left = left;
66597
- this.right = right;
66598
- this.length = left.length + right.length;
66599
- this.depth = Math.max(left.depth, right.depth) + 1;
66600
- }
66601
-
66602
- if ( RopeSequence ) Append.__proto__ = RopeSequence;
66603
- Append.prototype = Object.create( RopeSequence && RopeSequence.prototype );
66604
- Append.prototype.constructor = Append;
66605
-
66606
- Append.prototype.flatten = function flatten () {
66607
- return this.left.flatten().concat(this.right.flatten())
66608
- };
66609
-
66610
- Append.prototype.getInner = function getInner (i) {
66611
- return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
66612
- };
66613
-
66614
- Append.prototype.forEachInner = function forEachInner (f, from, to, start) {
66615
- var leftLen = this.left.length;
66616
- if (from < leftLen &&
66617
- this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
66618
- { return false }
66619
- if (to > leftLen &&
66620
- this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
66621
- { return false }
66622
- };
66623
-
66624
- Append.prototype.forEachInvertedInner = function forEachInvertedInner (f, from, to, start) {
66625
- var leftLen = this.left.length;
66626
- if (from > leftLen &&
66627
- this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
66628
- { return false }
66629
- if (to < leftLen &&
66630
- this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
66631
- { return false }
66632
- };
66633
-
66634
- Append.prototype.sliceInner = function sliceInner (from, to) {
66635
- if (from == 0 && to == this.length) { return this }
66636
- var leftLen = this.left.length;
66637
- if (to <= leftLen) { return this.left.slice(from, to) }
66638
- if (from >= leftLen) { return this.right.slice(from - leftLen, to - leftLen) }
66639
- return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
66640
- };
66641
-
66642
- Append.prototype.leafAppend = function leafAppend (other) {
66643
- var inner = this.right.leafAppend(other);
66644
- if (inner) { return new Append(this.left, inner) }
66645
- };
66646
-
66647
- Append.prototype.leafPrepend = function leafPrepend (other) {
66648
- var inner = this.left.leafPrepend(other);
66649
- if (inner) { return new Append(inner, this.right) }
66650
- };
66651
-
66652
- Append.prototype.appendInner = function appendInner (other) {
66653
- if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
66654
- { return new Append(this.left, new Append(this.right, other)) }
66655
- return new Append(this, other)
66656
- };
66657
-
66658
- return Append;
66659
- }(RopeSequence));
66660
-
66661
- // ProseMirror's history isn't simply a way to roll back to a previous
66662
- // state, because ProseMirror supports applying changes without adding
66663
- // them to the history (for example during collaboration).
66664
- //
66665
- // To this end, each 'Branch' (one for the undo history and one for
66666
- // the redo history) keeps an array of 'Items', which can optionally
66667
- // hold a step (an actual undoable change), and always hold a position
66668
- // map (which is needed to move changes below them to apply to the
66669
- // current document).
66670
- //
66671
- // An item that has both a step and a selection bookmark is the start
66672
- // of an 'event' — a group of changes that will be undone or redone at
66673
- // once. (It stores only the bookmark, since that way we don't have to
66674
- // provide a document until the selection is actually applied, which
66675
- // is useful when compressing.)
66676
- // Used to schedule history compression
66677
- const max_empty_items = 500;
66678
- class Branch {
66679
- constructor(items, eventCount) {
66680
- this.items = items;
66681
- this.eventCount = eventCount;
66682
- }
66683
- // Pop the latest event off the branch's history and apply it
66684
- // to a document transform.
66685
- popEvent(state, preserveItems) {
66686
- if (this.eventCount == 0)
66687
- return null;
66688
- let end = this.items.length;
66689
- for (;; end--) {
66690
- let next = this.items.get(end - 1);
66691
- if (next.selection) {
66692
- --end;
66693
- break;
66694
- }
66695
- }
66696
- let remap, mapFrom;
66697
- if (preserveItems) {
66698
- remap = this.remapping(end, this.items.length);
66699
- mapFrom = remap.maps.length;
66700
- }
66701
- let transform = state.tr;
66702
- let selection, remaining;
66703
- let addAfter = [], addBefore = [];
66704
- this.items.forEach((item, i) => {
66705
- if (!item.step) {
66706
- if (!remap) {
66707
- remap = this.remapping(end, i + 1);
66708
- mapFrom = remap.maps.length;
66709
- }
66710
- mapFrom--;
66711
- addBefore.push(item);
66712
- return;
66713
- }
66714
- if (remap) {
66715
- addBefore.push(new Item(item.map));
66716
- let step = item.step.map(remap.slice(mapFrom)), map;
66717
- if (step && transform.maybeStep(step).doc) {
66718
- map = transform.mapping.maps[transform.mapping.maps.length - 1];
66719
- addAfter.push(new Item(map, undefined, undefined, addAfter.length + addBefore.length));
66720
- }
66721
- mapFrom--;
66722
- if (map)
66723
- remap.appendMap(map, mapFrom);
66724
- }
66725
- else {
66726
- transform.maybeStep(item.step);
66727
- }
66728
- if (item.selection) {
66729
- selection = remap ? item.selection.map(remap.slice(mapFrom)) : item.selection;
66730
- remaining = new Branch(this.items.slice(0, end).append(addBefore.reverse().concat(addAfter)), this.eventCount - 1);
66731
- return false;
66732
- }
66733
- }, this.items.length, 0);
66734
- return { remaining: remaining, transform, selection: selection };
66735
- }
66736
- // Create a new branch with the given transform added.
66737
- addTransform(transform, selection, histOptions, preserveItems) {
66738
- let newItems = [], eventCount = this.eventCount;
66739
- let oldItems = this.items, lastItem = !preserveItems && oldItems.length ? oldItems.get(oldItems.length - 1) : null;
66740
- for (let i = 0; i < transform.steps.length; i++) {
66741
- let step = transform.steps[i].invert(transform.docs[i]);
66742
- let item = new Item(transform.mapping.maps[i], step, selection), merged;
66743
- if (merged = lastItem && lastItem.merge(item)) {
66744
- item = merged;
66745
- if (i)
66746
- newItems.pop();
66747
- else
66748
- oldItems = oldItems.slice(0, oldItems.length - 1);
66749
- }
66750
- newItems.push(item);
66751
- if (selection) {
66752
- eventCount++;
66753
- selection = undefined;
66754
- }
66755
- if (!preserveItems)
66756
- lastItem = item;
66757
- }
66758
- let overflow = eventCount - histOptions.depth;
66759
- if (overflow > DEPTH_OVERFLOW) {
66760
- oldItems = cutOffEvents(oldItems, overflow);
66761
- eventCount -= overflow;
66762
- }
66763
- return new Branch(oldItems.append(newItems), eventCount);
66764
- }
66765
- remapping(from, to) {
66766
- let maps = new Mapping;
66767
- this.items.forEach((item, i) => {
66768
- let mirrorPos = item.mirrorOffset != null && i - item.mirrorOffset >= from
66769
- ? maps.maps.length - item.mirrorOffset : undefined;
66770
- maps.appendMap(item.map, mirrorPos);
66771
- }, from, to);
66772
- return maps;
66773
- }
66774
- addMaps(array) {
66775
- if (this.eventCount == 0)
66776
- return this;
66777
- return new Branch(this.items.append(array.map(map => new Item(map))), this.eventCount);
66778
- }
66779
- // When the collab module receives remote changes, the history has
66780
- // to know about those, so that it can adjust the steps that were
66781
- // rebased on top of the remote changes, and include the position
66782
- // maps for the remote changes in its array of items.
66783
- rebased(rebasedTransform, rebasedCount) {
66784
- if (!this.eventCount)
66785
- return this;
66786
- let rebasedItems = [], start = Math.max(0, this.items.length - rebasedCount);
66787
- let mapping = rebasedTransform.mapping;
66788
- let newUntil = rebasedTransform.steps.length;
66789
- let eventCount = this.eventCount;
66790
- this.items.forEach(item => { if (item.selection)
66791
- eventCount--; }, start);
66792
- let iRebased = rebasedCount;
66793
- this.items.forEach(item => {
66794
- let pos = mapping.getMirror(--iRebased);
66795
- if (pos == null)
66796
- return;
66797
- newUntil = Math.min(newUntil, pos);
66798
- let map = mapping.maps[pos];
66799
- if (item.step) {
66800
- let step = rebasedTransform.steps[pos].invert(rebasedTransform.docs[pos]);
66801
- let selection = item.selection && item.selection.map(mapping.slice(iRebased + 1, pos));
66802
- if (selection)
66803
- eventCount++;
66804
- rebasedItems.push(new Item(map, step, selection));
66805
- }
66806
- else {
66807
- rebasedItems.push(new Item(map));
66808
- }
66809
- }, start);
66810
- let newMaps = [];
66811
- for (let i = rebasedCount; i < newUntil; i++)
66812
- newMaps.push(new Item(mapping.maps[i]));
66813
- let items = this.items.slice(0, start).append(newMaps).append(rebasedItems);
66814
- let branch = new Branch(items, eventCount);
66815
- if (branch.emptyItemCount() > max_empty_items)
66816
- branch = branch.compress(this.items.length - rebasedItems.length);
66817
- return branch;
66924
+ class DropCursorView {
66925
+ constructor(editorView, options) {
66926
+ var _a;
66927
+ this.editorView = editorView;
66928
+ this.cursorPos = null;
66929
+ this.element = null;
66930
+ this.timeout = -1;
66931
+ this.lastDragEvent = null;
66932
+ this.width = (_a = options.width) !== null && _a !== void 0 ? _a : 1;
66933
+ this.color = options.color === false ? undefined : (options.color || "black");
66934
+ this.class = options.class;
66935
+ this.handlers = ["dragover", "dragend", "drop", "dragleave"].map(name => {
66936
+ let handler = (e) => { this[name](e); };
66937
+ editorView.dom.addEventListener(name, handler);
66938
+ return { name, handler };
66939
+ });
66818
66940
  }
66819
- emptyItemCount() {
66820
- let count = 0;
66821
- this.items.forEach(item => { if (!item.step)
66822
- count++; });
66823
- return count;
66941
+ destroy() {
66942
+ this.setCursor(null);
66943
+ this.handlers.forEach(({ name, handler }) => this.editorView.dom.removeEventListener(name, handler));
66824
66944
  }
66825
- // Compressing a branch means rewriting it to push the air (map-only
66826
- // items) out. During collaboration, these naturally accumulate
66827
- // because each remote change adds one. The `upto` argument is used
66828
- // to ensure that only the items below a given level are compressed,
66829
- // because `rebased` relies on a clean, untouched set of items in
66830
- // order to associate old items with rebased steps.
66831
- compress(upto = this.items.length) {
66832
- let remap = this.remapping(0, upto), mapFrom = remap.maps.length;
66833
- let items = [], events = 0;
66834
- this.items.forEach((item, i) => {
66835
- if (i >= upto) {
66836
- items.push(item);
66837
- if (item.selection)
66838
- events++;
66945
+ update(editorView, prevState) {
66946
+ if (this.cursorPos != null && prevState.doc != editorView.state.doc) {
66947
+ // if we currently have an on-going drag event
66948
+ // we need to update the cursor position again and update the overlay
66949
+ if (this.lastDragEvent) {
66950
+ let target = this.computeTarget(this.lastDragEvent);
66951
+ if (target == this.cursorPos)
66952
+ this.updateOverlay();
66953
+ else
66954
+ this.setCursor(target);
66839
66955
  }
66840
- else if (item.step) {
66841
- let step = item.step.map(remap.slice(mapFrom)), map = step && step.getMap();
66842
- mapFrom--;
66843
- if (map)
66844
- remap.appendMap(map, mapFrom);
66845
- if (step) {
66846
- let selection = item.selection && item.selection.map(remap.slice(mapFrom));
66847
- if (selection)
66848
- events++;
66849
- let newItem = new Item(map.invert(), step, selection), merged, last = items.length - 1;
66850
- if (merged = items.length && items[last].merge(newItem))
66851
- items[last] = merged;
66852
- else
66853
- items.push(newItem);
66956
+ else {
66957
+ this.updateOverlay();
66958
+ }
66959
+ }
66960
+ }
66961
+ setCursor(pos) {
66962
+ if (pos == this.cursorPos)
66963
+ return;
66964
+ this.cursorPos = pos;
66965
+ if (pos == null) {
66966
+ this.element.parentNode.removeChild(this.element);
66967
+ this.element = null;
66968
+ }
66969
+ else {
66970
+ this.updateOverlay();
66971
+ }
66972
+ }
66973
+ updateOverlay() {
66974
+ let $pos = this.editorView.state.doc.resolve(this.cursorPos);
66975
+ let isBlock = !$pos.parent.inlineContent, rect;
66976
+ let editorDOM = this.editorView.dom, editorRect = editorDOM.getBoundingClientRect();
66977
+ let scaleX = editorRect.width / editorDOM.offsetWidth, scaleY = editorRect.height / editorDOM.offsetHeight;
66978
+ if (isBlock) {
66979
+ let before = $pos.nodeBefore, after = $pos.nodeAfter;
66980
+ if (before || after) {
66981
+ let node = this.editorView.nodeDOM(this.cursorPos - (before ? before.nodeSize : 0));
66982
+ if (node) {
66983
+ let nodeRect = node.getBoundingClientRect();
66984
+ let top = before ? nodeRect.bottom : nodeRect.top;
66985
+ if (before && after)
66986
+ top = (top + this.editorView.nodeDOM(this.cursorPos).getBoundingClientRect().top) / 2;
66987
+ let halfWidth = (this.width / 2) * scaleY;
66988
+ rect = { left: nodeRect.left, right: nodeRect.right, top: top - halfWidth, bottom: top + halfWidth };
66854
66989
  }
66855
66990
  }
66856
- else if (item.map) {
66857
- mapFrom--;
66991
+ }
66992
+ if (!rect) {
66993
+ let coords = this.editorView.coordsAtPos(this.cursorPos);
66994
+ let halfWidth = (this.width / 2) * scaleX;
66995
+ rect = { left: coords.left - halfWidth, right: coords.left + halfWidth, top: coords.top, bottom: coords.bottom };
66996
+ }
66997
+ let parent = this.editorView.dom.offsetParent;
66998
+ if (!this.element) {
66999
+ this.element = parent.appendChild(document.createElement("div"));
67000
+ if (this.class)
67001
+ this.element.className = this.class;
67002
+ this.element.style.cssText = "position: absolute; z-index: 50; pointer-events: none;";
67003
+ if (this.color) {
67004
+ this.element.style.backgroundColor = this.color;
66858
67005
  }
66859
- }, this.items.length, 0);
66860
- return new Branch(RopeSequence.from(items.reverse()), events);
67006
+ }
67007
+ this.element.classList.toggle("prosemirror-dropcursor-block", isBlock);
67008
+ this.element.classList.toggle("prosemirror-dropcursor-inline", !isBlock);
67009
+ let parentLeft, parentTop;
67010
+ if (!parent || parent == document.body && getComputedStyle(parent).position == "static") {
67011
+ parentLeft = -pageXOffset;
67012
+ parentTop = -pageYOffset;
67013
+ }
67014
+ else {
67015
+ let rect = parent.getBoundingClientRect();
67016
+ let parentScaleX = rect.width / parent.offsetWidth, parentScaleY = rect.height / parent.offsetHeight;
67017
+ parentLeft = rect.left - parent.scrollLeft * parentScaleX;
67018
+ parentTop = rect.top - parent.scrollTop * parentScaleY;
67019
+ }
67020
+ this.element.style.left = (rect.left - parentLeft) / scaleX + "px";
67021
+ this.element.style.top = (rect.top - parentTop) / scaleY + "px";
67022
+ this.element.style.width = (rect.right - rect.left) / scaleX + "px";
67023
+ this.element.style.height = (rect.bottom - rect.top) / scaleY + "px";
66861
67024
  }
66862
- }
66863
- Branch.empty = new Branch(RopeSequence.empty, 0);
66864
- function cutOffEvents(items, n) {
66865
- let cutPoint;
66866
- items.forEach((item, i) => {
66867
- if (item.selection && (n-- == 0)) {
66868
- cutPoint = i;
66869
- return false;
67025
+ scheduleRemoval(timeout) {
67026
+ clearTimeout(this.timeout);
67027
+ this.timeout = setTimeout(() => this.setCursor(null), timeout);
67028
+ }
67029
+ computeTarget(event) {
67030
+ let pos = this.editorView.posAtCoords({ left: event.clientX, top: event.clientY });
67031
+ let node = pos && pos.inside >= 0 && this.editorView.state.doc.nodeAt(pos.inside);
67032
+ let disableDropCursor = node && node.type.spec.disableDropCursor;
67033
+ let disabled = typeof disableDropCursor == "function"
67034
+ ? disableDropCursor(this.editorView, pos, event)
67035
+ : disableDropCursor;
67036
+ if (!pos || disabled)
67037
+ return null;
67038
+ let target = pos.pos;
67039
+ if (this.editorView.dragging && this.editorView.dragging.slice) {
67040
+ let point = dropPoint(this.editorView.state.doc, target, this.editorView.dragging.slice);
67041
+ if (point != null)
67042
+ target = point;
66870
67043
  }
66871
- });
66872
- return items.slice(cutPoint);
66873
- }
66874
- class Item {
66875
- constructor(
66876
- // The (forward) step map for this item.
66877
- map,
66878
- // The inverted step
66879
- step,
66880
- // If this is non-null, this item is the start of a group, and
66881
- // this selection is the starting selection for the group (the one
66882
- // that was active before the first step was applied)
66883
- selection,
66884
- // If this item is the inverse of a previous mapping on the stack,
66885
- // this points at the inverse's offset
66886
- mirrorOffset) {
66887
- this.map = map;
66888
- this.step = step;
66889
- this.selection = selection;
66890
- this.mirrorOffset = mirrorOffset;
67044
+ return target;
66891
67045
  }
66892
- merge(other) {
66893
- if (this.step && other.step && !other.selection) {
66894
- let step = other.step.merge(this.step);
66895
- if (step)
66896
- return new Item(step.getMap().invert(), step, this.selection);
67046
+ dragover(event) {
67047
+ if (!this.editorView.editable)
67048
+ return;
67049
+ this.lastDragEvent = event;
67050
+ let target = this.computeTarget(event);
67051
+ if (target != null) {
67052
+ this.setCursor(target);
67053
+ this.scheduleRemoval(5000);
66897
67054
  }
66898
67055
  }
66899
- }
66900
- // The value of the state field that tracks undo/redo history for that
66901
- // state. Will be stored in the plugin state when the history plugin
66902
- // is active.
66903
- class HistoryState {
66904
- constructor(done, undone, prevRanges, prevTime, prevComposition) {
66905
- this.done = done;
66906
- this.undone = undone;
66907
- this.prevRanges = prevRanges;
66908
- this.prevTime = prevTime;
66909
- this.prevComposition = prevComposition;
67056
+ dragend() {
67057
+ this.scheduleRemoval(20);
67058
+ }
67059
+ drop() {
67060
+ this.scheduleRemoval(20);
67061
+ }
67062
+ dragleave(event) {
67063
+ if (!this.editorView.dom.contains(event.relatedTarget))
67064
+ this.setCursor(null);
66910
67065
  }
66911
67066
  }
66912
- const DEPTH_OVERFLOW = 20;
66913
- // Record a transformation in undo history.
66914
- function applyTransaction(history, state, tr, options) {
66915
- let historyTr = tr.getMeta(historyKey), rebased;
66916
- if (historyTr)
66917
- return historyTr.historyState;
66918
- if (tr.getMeta(closeHistoryKey))
66919
- history = new HistoryState(history.done, history.undone, null, 0, -1);
66920
- let appended = tr.getMeta("appendedTransaction");
66921
- if (tr.steps.length == 0) {
66922
- return history;
67067
+
67068
+ /**
67069
+ Gap cursor selections are represented using this class. Its
67070
+ `$anchor` and `$head` properties both point at the cursor position.
67071
+ */
67072
+ class GapCursor extends Selection$2 {
67073
+ /**
67074
+ Create a gap cursor.
67075
+ */
67076
+ constructor($pos) {
67077
+ super($pos, $pos);
66923
67078
  }
66924
- else if (appended && appended.getMeta(historyKey)) {
66925
- if (appended.getMeta(historyKey).redo)
66926
- return new HistoryState(history.done.addTransform(tr, undefined, options, mustPreserveItems(state)), history.undone, rangesFor(tr.mapping.maps), history.prevTime, history.prevComposition);
66927
- else
66928
- return new HistoryState(history.done, history.undone.addTransform(tr, undefined, options, mustPreserveItems(state)), null, history.prevTime, history.prevComposition);
67079
+ map(doc, mapping) {
67080
+ let $pos = doc.resolve(mapping.map(this.head));
67081
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
66929
67082
  }
66930
- else if (tr.getMeta("addToHistory") !== false && !(appended && appended.getMeta("addToHistory") === false)) {
66931
- // Group transforms that occur in quick succession into one event.
66932
- let composition = tr.getMeta("composition");
66933
- let newGroup = history.prevTime == 0 ||
66934
- (!appended && history.prevComposition != composition &&
66935
- (history.prevTime < (tr.time || 0) - options.newGroupDelay || !isAdjacentTo(tr, history.prevRanges)));
66936
- let prevRanges = appended ? mapRanges(history.prevRanges, tr.mapping) : rangesFor(tr.mapping.maps);
66937
- return new HistoryState(history.done.addTransform(tr, newGroup ? state.selection.getBookmark() : undefined, options, mustPreserveItems(state)), Branch.empty, prevRanges, tr.time, composition == null ? history.prevComposition : composition);
67083
+ content() { return Slice.empty; }
67084
+ eq(other) {
67085
+ return other instanceof GapCursor && other.head == this.head;
66938
67086
  }
66939
- else if (rebased = tr.getMeta("rebased")) {
66940
- // Used by the collab module to tell the history that some of its
66941
- // content has been rebased.
66942
- return new HistoryState(history.done.rebased(tr, rebased), history.undone.rebased(tr, rebased), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67087
+ toJSON() {
67088
+ return { type: "gapcursor", pos: this.head };
66943
67089
  }
66944
- else {
66945
- return new HistoryState(history.done.addMaps(tr.mapping.maps), history.undone.addMaps(tr.mapping.maps), mapRanges(history.prevRanges, tr.mapping), history.prevTime, history.prevComposition);
67090
+ /**
67091
+ @internal
67092
+ */
67093
+ static fromJSON(doc, json) {
67094
+ if (typeof json.pos != "number")
67095
+ throw new RangeError("Invalid input for GapCursor.fromJSON");
67096
+ return new GapCursor(doc.resolve(json.pos));
67097
+ }
67098
+ /**
67099
+ @internal
67100
+ */
67101
+ getBookmark() { return new GapBookmark(this.anchor); }
67102
+ /**
67103
+ @internal
67104
+ */
67105
+ static valid($pos) {
67106
+ let parent = $pos.parent;
67107
+ if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
67108
+ return false;
67109
+ let override = parent.type.spec.allowGapCursor;
67110
+ if (override != null)
67111
+ return override;
67112
+ let deflt = parent.contentMatchAt($pos.index()).defaultType;
67113
+ return deflt && deflt.isTextblock;
67114
+ }
67115
+ /**
67116
+ @internal
67117
+ */
67118
+ static findGapCursorFrom($pos, dir, mustMove = false) {
67119
+ search: for (;;) {
67120
+ if (!mustMove && GapCursor.valid($pos))
67121
+ return $pos;
67122
+ let pos = $pos.pos, next = null;
67123
+ // Scan up from this position
67124
+ for (let d = $pos.depth;; d--) {
67125
+ let parent = $pos.node(d);
67126
+ if (dir > 0 ? $pos.indexAfter(d) < parent.childCount : $pos.index(d) > 0) {
67127
+ next = parent.child(dir > 0 ? $pos.indexAfter(d) : $pos.index(d) - 1);
67128
+ break;
67129
+ }
67130
+ else if (d == 0) {
67131
+ return null;
67132
+ }
67133
+ pos += dir;
67134
+ let $cur = $pos.doc.resolve(pos);
67135
+ if (GapCursor.valid($cur))
67136
+ return $cur;
67137
+ }
67138
+ // And then down into the next node
67139
+ for (;;) {
67140
+ let inside = dir > 0 ? next.firstChild : next.lastChild;
67141
+ if (!inside) {
67142
+ if (next.isAtom && !next.isText && !NodeSelection.isSelectable(next)) {
67143
+ $pos = $pos.doc.resolve(pos + next.nodeSize * dir);
67144
+ mustMove = false;
67145
+ continue search;
67146
+ }
67147
+ break;
67148
+ }
67149
+ next = inside;
67150
+ pos += dir;
67151
+ let $cur = $pos.doc.resolve(pos);
67152
+ if (GapCursor.valid($cur))
67153
+ return $cur;
67154
+ }
67155
+ return null;
67156
+ }
66946
67157
  }
66947
67158
  }
66948
- function isAdjacentTo(transform, prevRanges) {
66949
- if (!prevRanges)
66950
- return false;
66951
- if (!transform.docChanged)
66952
- return true;
66953
- let adjacent = false;
66954
- transform.mapping.maps[0].forEach((start, end) => {
66955
- for (let i = 0; i < prevRanges.length; i += 2)
66956
- if (start <= prevRanges[i + 1] && end >= prevRanges[i])
66957
- adjacent = true;
66958
- });
66959
- return adjacent;
67159
+ GapCursor.prototype.visible = false;
67160
+ GapCursor.findFrom = GapCursor.findGapCursorFrom;
67161
+ Selection$2.jsonID("gapcursor", GapCursor);
67162
+ class GapBookmark {
67163
+ constructor(pos) {
67164
+ this.pos = pos;
67165
+ }
67166
+ map(mapping) {
67167
+ return new GapBookmark(mapping.map(this.pos));
67168
+ }
67169
+ resolve(doc) {
67170
+ let $pos = doc.resolve(this.pos);
67171
+ return GapCursor.valid($pos) ? new GapCursor($pos) : Selection$2.near($pos);
67172
+ }
66960
67173
  }
66961
- function rangesFor(maps) {
66962
- let result = [];
66963
- for (let i = maps.length - 1; i >= 0 && result.length == 0; i--)
66964
- maps[i].forEach((_from, _to, from, to) => result.push(from, to));
66965
- return result;
67174
+ function needsGap(type) {
67175
+ return type.isAtom || type.spec.isolating || type.spec.createGapCursor;
66966
67176
  }
66967
- function mapRanges(ranges, mapping) {
66968
- if (!ranges)
66969
- return null;
66970
- let result = [];
66971
- for (let i = 0; i < ranges.length; i += 2) {
66972
- let from = mapping.map(ranges[i], 1), to = mapping.map(ranges[i + 1], -1);
66973
- if (from <= to)
66974
- result.push(from, to);
67177
+ function closedBefore($pos) {
67178
+ for (let d = $pos.depth; d >= 0; d--) {
67179
+ let index = $pos.index(d), parent = $pos.node(d);
67180
+ // At the start of this parent, look at next one
67181
+ if (index == 0) {
67182
+ if (parent.type.spec.isolating)
67183
+ return true;
67184
+ continue;
67185
+ }
67186
+ // See if the node before (or its first ancestor) is closed
67187
+ for (let before = parent.child(index - 1);; before = before.lastChild) {
67188
+ if ((before.childCount == 0 && !before.inlineContent) || needsGap(before.type))
67189
+ return true;
67190
+ if (before.inlineContent)
67191
+ return false;
67192
+ }
66975
67193
  }
66976
- return result;
66977
- }
66978
- // Apply the latest event from one branch to the document and shift the event
66979
- // onto the other branch.
66980
- function histTransaction(history, state, redo) {
66981
- let preserveItems = mustPreserveItems(state);
66982
- let histOptions = historyKey.get(state).spec.config;
66983
- let pop = (redo ? history.undone : history.done).popEvent(state, preserveItems);
66984
- if (!pop)
66985
- return null;
66986
- let selection = pop.selection.resolve(pop.transform.doc);
66987
- let added = (redo ? history.done : history.undone).addTransform(pop.transform, state.selection.getBookmark(), histOptions, preserveItems);
66988
- let newHist = new HistoryState(redo ? added : pop.remaining, redo ? pop.remaining : added, null, 0, -1);
66989
- return pop.transform.setSelection(selection).setMeta(historyKey, { redo, historyState: newHist });
67194
+ // Hit start of document
67195
+ return true;
66990
67196
  }
66991
- let cachedPreserveItems = false, cachedPreserveItemsPlugins = null;
66992
- // Check whether any plugin in the given state has a
66993
- // `historyPreserveItems` property in its spec, in which case we must
66994
- // preserve steps exactly as they came in, so that they can be
66995
- // rebased.
66996
- function mustPreserveItems(state) {
66997
- let plugins = state.plugins;
66998
- if (cachedPreserveItemsPlugins != plugins) {
66999
- cachedPreserveItems = false;
67000
- cachedPreserveItemsPlugins = plugins;
67001
- for (let i = 0; i < plugins.length; i++)
67002
- if (plugins[i].spec.historyPreserveItems) {
67003
- cachedPreserveItems = true;
67004
- break;
67005
- }
67197
+ function closedAfter($pos) {
67198
+ for (let d = $pos.depth; d >= 0; d--) {
67199
+ let index = $pos.indexAfter(d), parent = $pos.node(d);
67200
+ if (index == parent.childCount) {
67201
+ if (parent.type.spec.isolating)
67202
+ return true;
67203
+ continue;
67204
+ }
67205
+ for (let after = parent.child(index);; after = after.firstChild) {
67206
+ if ((after.childCount == 0 && !after.inlineContent) || needsGap(after.type))
67207
+ return true;
67208
+ if (after.inlineContent)
67209
+ return false;
67210
+ }
67006
67211
  }
67007
- return cachedPreserveItems;
67212
+ return true;
67008
67213
  }
67009
- const historyKey = new PluginKey("history");
67010
- const closeHistoryKey = new PluginKey("closeHistory");
67011
- /**
67012
- Returns a plugin that enables the undo history for an editor. The
67013
- plugin will track undo and redo stacks, which can be used with the
67014
- [`undo`](https://prosemirror.net/docs/ref/#history.undo) and [`redo`](https://prosemirror.net/docs/ref/#history.redo) commands.
67015
67214
 
67016
- You can set an `"addToHistory"` [metadata
67017
- property](https://prosemirror.net/docs/ref/#state.Transaction.setMeta) of `false` on a transaction
67018
- to prevent it from being rolled back by undo.
67215
+ /**
67216
+ Create a gap cursor plugin. When enabled, this will capture clicks
67217
+ near and arrow-key-motion past places that don't have a normally
67218
+ selectable position nearby, and create a gap cursor selection for
67219
+ them. The cursor is drawn as an element with class
67220
+ `ProseMirror-gapcursor`. You can either include
67221
+ `style/gapcursor.css` from the package's directory or add your own
67222
+ styles to make it visible.
67019
67223
  */
67020
- function history(config = {}) {
67021
- config = { depth: config.depth || 100,
67022
- newGroupDelay: config.newGroupDelay || 500 };
67224
+ function gapCursor() {
67023
67225
  return new Plugin({
67024
- key: historyKey,
67025
- state: {
67026
- init() {
67027
- return new HistoryState(Branch.empty, Branch.empty, null, 0, -1);
67028
- },
67029
- apply(tr, hist, state) {
67030
- return applyTransaction(hist, state, tr, config);
67031
- }
67032
- },
67033
- config,
67034
67226
  props: {
67035
- handleDOMEvents: {
67036
- beforeinput(view, e) {
67037
- let inputType = e.inputType;
67038
- let command = inputType == "historyUndo" ? undo : inputType == "historyRedo" ? redo : null;
67039
- if (!command || !view.editable)
67040
- return false;
67041
- e.preventDefault();
67042
- return command(view.state, view.dispatch);
67043
- }
67044
- }
67227
+ decorations: drawGapCursor,
67228
+ createSelectionBetween(_view, $anchor, $head) {
67229
+ return $anchor.pos == $head.pos && GapCursor.valid($head) ? new GapCursor($head) : null;
67230
+ },
67231
+ handleClick,
67232
+ handleKeyDown,
67233
+ handleDOMEvents: { beforeinput: beforeinput }
67045
67234
  }
67046
67235
  });
67047
67236
  }
67048
- function buildCommand(redo, scroll) {
67049
- return (state, dispatch) => {
67050
- let hist = historyKey.getState(state);
67051
- if (!hist || (redo ? hist.undone : hist.done).eventCount == 0)
67052
- return false;
67053
- if (dispatch) {
67054
- let tr = histTransaction(hist, state, redo);
67055
- if (tr)
67056
- dispatch(scroll ? tr.scrollIntoView() : tr);
67237
+ const handleKeyDown = keydownHandler({
67238
+ "ArrowLeft": arrow("horiz", -1),
67239
+ "ArrowRight": arrow("horiz", 1),
67240
+ "ArrowUp": arrow("vert", -1),
67241
+ "ArrowDown": arrow("vert", 1)
67242
+ });
67243
+ function arrow(axis, dir) {
67244
+ const dirStr = axis == "vert" ? (dir > 0 ? "down" : "up") : (dir > 0 ? "right" : "left");
67245
+ return function (state, dispatch, view) {
67246
+ let sel = state.selection;
67247
+ let $start = dir > 0 ? sel.$to : sel.$from, mustMove = sel.empty;
67248
+ if (sel instanceof TextSelection) {
67249
+ if (!view.endOfTextblock(dirStr) || $start.depth == 0)
67250
+ return false;
67251
+ mustMove = false;
67252
+ $start = state.doc.resolve(dir > 0 ? $start.after() : $start.before());
67057
67253
  }
67254
+ let $found = GapCursor.findGapCursorFrom($start, dir, mustMove);
67255
+ if (!$found)
67256
+ return false;
67257
+ if (dispatch)
67258
+ dispatch(state.tr.setSelection(new GapCursor($found)));
67058
67259
  return true;
67059
67260
  };
67060
67261
  }
67061
- /**
67062
- A command function that undoes the last change, if any.
67063
- */
67064
- const undo = buildCommand(false, true);
67065
- /**
67066
- A command function that redoes the last undone change, if any.
67067
- */
67068
- const redo = buildCommand(true, true);
67262
+ function handleClick(view, pos, event) {
67263
+ if (!view || !view.editable)
67264
+ return false;
67265
+ let $pos = view.state.doc.resolve(pos);
67266
+ if (!GapCursor.valid($pos))
67267
+ return false;
67268
+ let clickPos = view.posAtCoords({ left: event.clientX, top: event.clientY });
67269
+ if (clickPos && clickPos.inside > -1 && NodeSelection.isSelectable(view.state.doc.nodeAt(clickPos.inside)))
67270
+ return false;
67271
+ view.dispatch(view.state.tr.setSelection(new GapCursor($pos)));
67272
+ return true;
67273
+ }
67274
+ // This is a hack that, when a composition starts while a gap cursor
67275
+ // is active, quickly creates an inline context for the composition to
67276
+ // happen in, to avoid it being aborted by the DOM selection being
67277
+ // moved into a valid position.
67278
+ function beforeinput(view, event) {
67279
+ if (event.inputType != "insertCompositionText" || !(view.state.selection instanceof GapCursor))
67280
+ return false;
67281
+ let { $from } = view.state.selection;
67282
+ let insert = $from.parent.contentMatchAt($from.index()).findWrapping(view.state.schema.nodes.text);
67283
+ if (!insert)
67284
+ return false;
67285
+ let frag = Fragment.empty;
67286
+ for (let i = insert.length - 1; i >= 0; i--)
67287
+ frag = Fragment.from(insert[i].createAndFill(null, frag));
67288
+ let tr = view.state.tr.replace($from.pos, $from.pos, new Slice(frag, 0, 0));
67289
+ tr.setSelection(TextSelection.near(tr.doc.resolve($from.pos + 1)));
67290
+ view.dispatch(tr);
67291
+ return false;
67292
+ }
67293
+ function drawGapCursor(state) {
67294
+ if (!(state.selection instanceof GapCursor))
67295
+ return null;
67296
+ let node = document.createElement("div");
67297
+ node.className = "ProseMirror-gapcursor";
67298
+ return DecorationSet.create(state.doc, [Decoration.widget(state.selection.head, node, { key: "gapcursor" })]);
67299
+ }
67069
67300
 
67070
67301
  //#region src/character-count/character-count.ts
67071
67302
  /**
@@ -97660,12 +97891,12 @@ focus outline in that case.
97660
97891
  toDOMStream(options) {
97661
97892
  return streamAdapters.toDOMStream((this._closedPromiseResolve || this._error)
97662
97893
  ? this
97663
- : this._values, options);
97894
+ : this._values);
97664
97895
  }
97665
97896
  toNodeStream(options) {
97666
97897
  return streamAdapters.toNodeStream((this._closedPromiseResolve || this._error)
97667
97898
  ? this
97668
- : this._values, options);
97899
+ : this._values);
97669
97900
  }
97670
97901
  throw(_) {
97671
97902
  return __awaiter(this, void 0, void 0, function* () { yield this.abort(_); return ITERATOR_DONE; });
@@ -100056,7 +100287,7 @@ focus outline in that case.
100056
100287
  toNodeStream() {
100057
100288
  return streamAdapters.toNodeStream((this.isSync()
100058
100289
  ? { [Symbol.iterator]: () => this }
100059
- : { [Symbol.asyncIterator]: () => this }), { objectMode: true });
100290
+ : { [Symbol.asyncIterator]: () => this }));
100060
100291
  }
100061
100292
  /** @nocollapse */
100062
100293
  // @ts-ignore