@ni/spright-components 6.20.3 → 6.21.0

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.
Files changed (35) hide show
  1. package/dist/all-components-bundle.js +1602 -474
  2. package/dist/all-components-bundle.js.map +1 -1
  3. package/dist/all-components-bundle.min.js +5374 -5086
  4. package/dist/all-components-bundle.min.js.map +1 -1
  5. package/dist/custom-elements.json +51 -0
  6. package/dist/custom-elements.md +10 -6
  7. package/dist/esm/chat/conversation/index.d.ts +22 -0
  8. package/dist/esm/chat/conversation/index.js +47 -0
  9. package/dist/esm/chat/conversation/index.js.map +1 -1
  10. package/dist/esm/chat/conversation/models/auto-scroll-manager.d.ts +53 -0
  11. package/dist/esm/chat/conversation/models/auto-scroll-manager.js +222 -0
  12. package/dist/esm/chat/conversation/models/auto-scroll-manager.js.map +1 -0
  13. package/dist/esm/chat/conversation/styles.js +18 -1
  14. package/dist/esm/chat/conversation/styles.js.map +1 -1
  15. package/dist/esm/chat/conversation/template.js +9 -2
  16. package/dist/esm/chat/conversation/template.js.map +1 -1
  17. package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.d.ts +55 -0
  18. package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.js +194 -0
  19. package/dist/esm/chat/conversation/testing/chat-conversation.pageobject.js.map +1 -0
  20. package/dist/esm/chat/message/inbound/index.d.ts +3 -0
  21. package/dist/esm/chat/message/inbound/index.js +3 -0
  22. package/dist/esm/chat/message/inbound/index.js.map +1 -1
  23. package/dist/esm/chat/message/models/chat-message-internals.d.ts +38 -0
  24. package/dist/esm/chat/message/models/chat-message-internals.js +39 -0
  25. package/dist/esm/chat/message/models/chat-message-internals.js.map +1 -0
  26. package/dist/esm/chat/message/outbound/index.d.ts +3 -0
  27. package/dist/esm/chat/message/outbound/index.js +8 -0
  28. package/dist/esm/chat/message/outbound/index.js.map +1 -1
  29. package/dist/esm/chat/message/system/index.d.ts +3 -0
  30. package/dist/esm/chat/message/system/index.js +6 -0
  31. package/dist/esm/chat/message/system/index.js.map +1 -1
  32. package/dist/esm/chat/message/testing/chat-message.pageobject.d.ts +18 -0
  33. package/dist/esm/chat/message/testing/chat-message.pageobject.js +27 -0
  34. package/dist/esm/chat/message/testing/chat-message.pageobject.js.map +1 -0
  35. package/package.json +2 -2
@@ -10094,12 +10094,12 @@
10094
10094
  /* eslint-enable @typescript-eslint/no-non-null-assertion */
10095
10095
 
10096
10096
  /*!
10097
- * tabbable 6.4.0
10097
+ * tabbable 6.5.0
10098
10098
  * @license MIT, https://github.com/focus-trap/tabbable/blob/master/LICENSE
10099
10099
  */
10100
10100
  // NOTE: separate `:not()` selectors has broader browser support than the newer
10101
10101
  // `:not([inert], [inert] *)` (Feb 2023)
10102
- var candidateSelectors = ['input:not([inert]):not([inert] *)', 'select:not([inert]):not([inert] *)', 'textarea:not([inert]):not([inert] *)', 'a[href]:not([inert]):not([inert] *)', 'button:not([inert]):not([inert] *)', '[tabindex]:not(slot):not([inert]):not([inert] *)', 'audio[controls]:not([inert]):not([inert] *)', 'video[controls]:not([inert]):not([inert] *)', '[contenteditable]:not([contenteditable="false"]):not([inert]):not([inert] *)', 'details>summary:first-of-type:not([inert]):not([inert] *)', 'details:not([inert]):not([inert] *)'];
10102
+ var candidateSelectors = ['input:not([inert]):not([inert] *)', 'select:not([inert]):not([inert] *)', 'textarea:not([inert]):not([inert] *)', 'a[href]:not([inert]):not([inert] *)', 'area[href]:not([inert]):not([inert] *)', 'button:not([inert]):not([inert] *)', '[tabindex]:not(slot):not([inert]):not([inert] *)', 'audio[controls]:not([inert]):not([inert] *)', 'video[controls]:not([inert]):not([inert] *)', '[contenteditable]:not([contenteditable="false"]):not([inert]):not([inert] *)', 'details>summary:first-of-type:not([inert]):not([inert] *)', 'details:not([inert]):not([inert] *)'];
10103
10103
  var NoElement = typeof Element === 'undefined';
10104
10104
  var matches$1 = NoElement ? function () {} : Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
10105
10105
  var getRootNode = !NoElement && Element.prototype.getRootNode ? function (element) {
@@ -10204,7 +10204,9 @@
10204
10204
  // (this is legacy behavior from a very long way back)
10205
10205
  // NOTE: we check this regardless of `displayCheck="none"` because this is a
10206
10206
  // _visibility_ check, not a _display_ check
10207
- if (getComputedStyle(node).visibility === 'hidden') {
10207
+ var _getComputedStyle = getComputedStyle(node),
10208
+ visibility = _getComputedStyle.visibility;
10209
+ if (visibility === 'hidden' || visibility === 'collapse') {
10208
10210
  return true;
10209
10211
  }
10210
10212
  var isDirectSummary = matches$1.call(node, 'details>summary:first-of-type');
@@ -28862,8 +28864,11 @@ so this becomes the fallback color for the slot */ ''}
28862
28864
  if (!childA.sameMarkup(childB))
28863
28865
  return pos;
28864
28866
  if (childA.isText && childA.text != childB.text) {
28865
- for (let j = 0; childA.text[j] == childB.text[j]; j++)
28867
+ let tA = childA.text, tB = childB.text, j = 0;
28868
+ for (; tA[j] == tB[j]; j++)
28866
28869
  pos++;
28870
+ if (j && j < tA.length && j < tB.length && surrogateHigh(tA.charCodeAt(j - 1)) && surrogateLow(tA.charCodeAt(j)))
28871
+ pos--;
28867
28872
  return pos;
28868
28873
  }
28869
28874
  if (childA.content.size || childB.content.size) {
@@ -28887,12 +28892,17 @@ so this becomes the fallback color for the slot */ ''}
28887
28892
  if (!childA.sameMarkup(childB))
28888
28893
  return { a: posA, b: posB };
28889
28894
  if (childA.isText && childA.text != childB.text) {
28890
- let same = 0, minSize = Math.min(childA.text.length, childB.text.length);
28891
- while (same < minSize && childA.text[childA.text.length - same - 1] == childB.text[childB.text.length - same - 1]) {
28892
- same++;
28895
+ let tA = childA.text, tB = childB.text, iA = tA.length, iB = tB.length;
28896
+ while (iA > 0 && iB > 0 && tA[iA - 1] == tB[iB - 1]) {
28897
+ iA--;
28898
+ iB--;
28893
28899
  posA--;
28894
28900
  posB--;
28895
28901
  }
28902
+ if (iA && iB && iA < tA.length && surrogateHigh(tA.charCodeAt(iA - 1)) && surrogateLow(tA.charCodeAt(iA))) {
28903
+ posA++;
28904
+ posB++;
28905
+ }
28896
28906
  return { a: posA, b: posB };
28897
28907
  }
28898
28908
  if (childA.content.size || childB.content.size) {
@@ -28904,6 +28914,8 @@ so this becomes the fallback color for the slot */ ''}
28904
28914
  posB -= size;
28905
28915
  }
28906
28916
  }
28917
+ function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; }
28918
+ function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; }
28907
28919
 
28908
28920
  /**
28909
28921
  A fragment represents a node's collection of child nodes.
@@ -29584,7 +29596,8 @@ so this becomes the fallback color for the slot */ ''}
29584
29596
  addNode($end.nodeBefore, target);
29585
29597
  }
29586
29598
  function close(node, content) {
29587
- node.type.checkContent(content);
29599
+ if (!node.type.validContent(content))
29600
+ throw new ReplaceError("Invalid content for node " + node.type.name);
29588
29601
  return node.copy(content);
29589
29602
  }
29590
29603
  function replaceThreeWay($from, $start, $end, $to, depth) {
@@ -30895,13 +30908,12 @@ so this becomes the fallback color for the slot */ ''}
30895
30908
  return built;
30896
30909
  }
30897
30910
  function checkAttrs(attrs, values, type, name) {
30898
- for (let name in values)
30899
- if (!(name in attrs))
30900
- throw new RangeError(`Unsupported attribute ${name} for ${type} of type ${name}`);
30901
- for (let name in attrs) {
30902
- let attr = attrs[name];
30903
- if (attr.validate)
30904
- attr.validate(values[name]);
30911
+ for (let attr in values)
30912
+ if (!(attr in attrs))
30913
+ throw new RangeError(`Unsupported attribute ${attr} for ${type} of type ${name}`);
30914
+ for (let attr in attrs) {
30915
+ if (attrs[attr].validate)
30916
+ attrs[attr].validate(values[attr]);
30905
30917
  }
30906
30918
  }
30907
30919
  function initAttrs(typeName, attrs) {
@@ -38554,14 +38566,14 @@ so this becomes the fallback color for the slot */ ''}
38554
38566
  syncNodeSelection(view, sel);
38555
38567
  if (!editorOwnsSelection(view))
38556
38568
  return;
38557
- // The delayed drag selection causes issues with Cell Selections
38558
- // in Safari. And the drag selection delay is to workarond issues
38559
- // which only present in Chrome.
38560
- if (!force && view.input.mouseDown && view.input.mouseDown.allowDefault && chrome) {
38569
+ // Need to delay selection normalization during a native selection
38570
+ // drag on Chrome, or it will cause further dragging to glitch.
38571
+ let mouseDown = view.input.mouseDown;
38572
+ if (!force && chrome && mouseDown) {
38561
38573
  let domSel = view.domSelectionRange(), curSel = view.domObserver.currentSelection;
38562
38574
  if (domSel.anchorNode && curSel.anchorNode &&
38563
- isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset)) {
38564
- view.input.mouseDown.delayedSelectionSync = true;
38575
+ isEquivalentPosition(domSel.anchorNode, domSel.anchorOffset, curSel.anchorNode, curSel.anchorOffset) &&
38576
+ mouseDown.delaySelUpdate()) {
38565
38577
  view.domObserver.setCurSelection();
38566
38578
  return;
38567
38579
  }
@@ -39413,6 +39425,8 @@ so this becomes the fallback color for the slot */ ''}
39413
39425
  view.input.lastSelectionTime = Date.now();
39414
39426
  }
39415
39427
  function destroyInput(view) {
39428
+ if (view.input.mouseDown)
39429
+ view.input.mouseDown.done();
39416
39430
  view.domObserver.stop();
39417
39431
  for (let type in view.input.eventHandlers)
39418
39432
  view.dom.removeEventListener(type, view.input.eventHandlers[type]);
@@ -39451,7 +39465,7 @@ so this becomes the fallback color for the slot */ ''}
39451
39465
  editHandlers.keydown = (view, _event) => {
39452
39466
  let event = _event;
39453
39467
  view.input.shiftKey = event.keyCode == 16 || event.shiftKey;
39454
- if (inOrNearComposition(view, event))
39468
+ if (inOrNearComposition(view))
39455
39469
  return;
39456
39470
  view.input.lastKeyCode = event.keyCode;
39457
39471
  view.input.lastKeyCodeTime = Date.now();
@@ -39489,7 +39503,7 @@ so this becomes the fallback color for the slot */ ''}
39489
39503
  };
39490
39504
  editHandlers.keypress = (view, _event) => {
39491
39505
  let event = _event;
39492
- if (inOrNearComposition(view, event) || !event.charCode ||
39506
+ if (inOrNearComposition(view) || !event.charCode ||
39493
39507
  event.ctrlKey && !event.altKey || mac$2 && event.metaKey)
39494
39508
  return;
39495
39509
  if (view.someProp("handleKeyPress", f => f(view, event))) {
@@ -39583,26 +39597,28 @@ so this becomes the fallback color for the slot */ ''}
39583
39597
  function defaultTripleClick(view, inside, event) {
39584
39598
  if (event.button != 0)
39585
39599
  return false;
39586
- let doc = view.state.doc;
39587
- if (inside == -1) {
39588
- if (doc.inlineContent) {
39589
- updateSelection(view, TextSelection.create(doc, 0, doc.content.size));
39590
- return true;
39591
- }
39600
+ let selection = selectionForTripleClick(view, inside, true), doc = view.state.doc;
39601
+ if (!selection)
39592
39602
  return false;
39593
- }
39603
+ updateSelection(view, selection);
39604
+ if (selection instanceof TextSelection && doc.eq(view.state.doc))
39605
+ view.input.mouseDown = new TripleClickDrag(view, selection);
39606
+ return true;
39607
+ }
39608
+ function selectionForTripleClick(view, inside, selectNodes) {
39609
+ let doc = view.state.doc;
39610
+ if (inside == -1)
39611
+ return doc.inlineContent ? TextSelection.create(doc, 0, doc.content.size) : null;
39594
39612
  let $pos = doc.resolve(inside);
39595
39613
  for (let i = $pos.depth + 1; i > 0; i--) {
39596
39614
  let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i);
39597
39615
  let nodePos = $pos.before(i);
39598
39616
  if (node.inlineContent)
39599
- updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size));
39600
- else if (NodeSelection.isSelectable(node))
39601
- updateSelection(view, NodeSelection.create(doc, nodePos));
39602
- else
39603
- continue;
39604
- return true;
39617
+ return TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size);
39618
+ else if (selectNodes && NodeSelection.isSelectable(node))
39619
+ return NodeSelection.create(doc, nodePos);
39605
39620
  }
39621
+ return null;
39606
39622
  }
39607
39623
  function forceDOMFlush(view) {
39608
39624
  return endComposition(view);
@@ -39621,13 +39637,13 @@ so this becomes the fallback color for the slot */ ''}
39621
39637
  type = "tripleClick";
39622
39638
  }
39623
39639
  view.input.lastClick = { time: now, x: event.clientX, y: event.clientY, type, button: event.button };
39640
+ if (view.input.mouseDown)
39641
+ view.input.mouseDown.done();
39624
39642
  let pos = view.posAtCoords(eventCoords(event));
39625
39643
  if (!pos)
39626
39644
  return;
39627
39645
  if (type == "singleClick") {
39628
- if (view.input.mouseDown)
39629
- view.input.mouseDown.done();
39630
- view.input.mouseDown = new MouseDown(view, pos, event, !!flushed);
39646
+ view.input.mouseDown = new LeftMouseDown(view, pos, event, !!flushed);
39631
39647
  }
39632
39648
  else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
39633
39649
  event.preventDefault();
@@ -39637,13 +39653,34 @@ so this becomes the fallback color for the slot */ ''}
39637
39653
  }
39638
39654
  };
39639
39655
  class MouseDown {
39640
- constructor(view, pos, event, flushed) {
39656
+ constructor(view) {
39641
39657
  this.view = view;
39658
+ this.mightDrag = null;
39659
+ view.root.addEventListener("mouseup", this.up = this.up.bind(this));
39660
+ view.root.addEventListener("mousemove", this.move = this.move.bind(this));
39661
+ }
39662
+ up(event) {
39663
+ this.done();
39664
+ }
39665
+ move(event) {
39666
+ if (event.buttons == 0)
39667
+ this.done();
39668
+ }
39669
+ done() {
39670
+ this.view.root.removeEventListener("mouseup", this.up);
39671
+ this.view.root.removeEventListener("mousemove", this.move);
39672
+ if (this.view.input.mouseDown == this)
39673
+ this.view.input.mouseDown = null;
39674
+ }
39675
+ delaySelUpdate() { return false; }
39676
+ }
39677
+ class LeftMouseDown extends MouseDown {
39678
+ constructor(view, pos, event, flushed) {
39679
+ super(view);
39642
39680
  this.pos = pos;
39643
39681
  this.event = event;
39644
39682
  this.flushed = flushed;
39645
39683
  this.delayedSelectionSync = false;
39646
- this.mightDrag = null;
39647
39684
  this.startDoc = view.state.doc;
39648
39685
  this.selectNode = !!event[selectNodeModifier];
39649
39686
  this.allowDefault = event.shiftKey;
@@ -39681,13 +39718,10 @@ so this becomes the fallback color for the slot */ ''}
39681
39718
  }, 20);
39682
39719
  this.view.domObserver.start();
39683
39720
  }
39684
- view.root.addEventListener("mouseup", this.up = this.up.bind(this));
39685
- view.root.addEventListener("mousemove", this.move = this.move.bind(this));
39686
39721
  setSelectionOrigin(view, "pointer");
39687
39722
  }
39688
39723
  done() {
39689
- this.view.root.removeEventListener("mouseup", this.up);
39690
- this.view.root.removeEventListener("mousemove", this.move);
39724
+ super.done();
39691
39725
  if (this.mightDrag && this.target) {
39692
39726
  this.view.domObserver.stop();
39693
39727
  if (this.mightDrag.addAttr)
@@ -39697,8 +39731,10 @@ so this becomes the fallback color for the slot */ ''}
39697
39731
  this.view.domObserver.start();
39698
39732
  }
39699
39733
  if (this.delayedSelectionSync)
39700
- setTimeout(() => selectionToDOM(this.view));
39701
- this.view.input.mouseDown = null;
39734
+ setTimeout(() => {
39735
+ if (!this.view.isDestroyed)
39736
+ selectionToDOM(this.view);
39737
+ });
39702
39738
  }
39703
39739
  up(event) {
39704
39740
  this.done();
@@ -39737,14 +39773,41 @@ so this becomes the fallback color for the slot */ ''}
39737
39773
  move(event) {
39738
39774
  this.updateAllowDefault(event);
39739
39775
  setSelectionOrigin(this.view, "pointer");
39740
- if (event.buttons == 0)
39741
- this.done();
39776
+ super.move(event);
39742
39777
  }
39743
39778
  updateAllowDefault(event) {
39744
39779
  if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
39745
39780
  Math.abs(this.event.y - event.clientY) > 4))
39746
39781
  this.allowDefault = true;
39747
39782
  }
39783
+ delaySelUpdate() {
39784
+ if (!this.allowDefault)
39785
+ return false;
39786
+ this.delayedSelectionSync = true;
39787
+ return true;
39788
+ }
39789
+ }
39790
+ class TripleClickDrag extends MouseDown {
39791
+ constructor(view, startSelection) {
39792
+ super(view);
39793
+ this.startSelection = startSelection;
39794
+ this.startDoc = view.state.doc;
39795
+ }
39796
+ move(event) {
39797
+ if (event.buttons == 0 || this.view.isDestroyed || !this.view.state.doc.eq(this.startDoc)) {
39798
+ this.done();
39799
+ return;
39800
+ }
39801
+ event.preventDefault();
39802
+ setSelectionOrigin(this.view, "pointer");
39803
+ let pos = this.view.posAtCoords(eventCoords(event));
39804
+ let target = pos && selectionForTripleClick(this.view, pos.inside, false);
39805
+ if (!target)
39806
+ return;
39807
+ let { doc } = this.view.state, start = this.startSelection;
39808
+ let [anchor, head] = target.from < start.from ? [start.to, target.from] : [start.from, target.to];
39809
+ updateSelection(this.view, TextSelection.create(doc, anchor, head));
39810
+ }
39748
39811
  }
39749
39812
  handlers.touchstart = view => {
39750
39813
  view.input.lastTouch = Date.now();
@@ -39769,7 +39832,7 @@ so this becomes the fallback color for the slot */ ''}
39769
39832
  // This guards against the case where compositionend is triggered without the keyboard
39770
39833
  // (e.g. character confirmation may be done with the mouse), and keydown is triggered
39771
39834
  // afterwards- we wouldn't want to ignore the keydown event in this case.
39772
- if (safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
39835
+ if (safari && Math.abs(Date.now() - view.input.compositionEndedAt) < 500) {
39773
39836
  view.input.compositionEndedAt = -2e8;
39774
39837
  return true;
39775
39838
  }
@@ -39828,7 +39891,7 @@ so this becomes the fallback color for the slot */ ''}
39828
39891
  editHandlers.compositionend = (view, event) => {
39829
39892
  if (view.composing) {
39830
39893
  view.input.composing = false;
39831
- view.input.compositionEndedAt = event.timeStamp;
39894
+ view.input.compositionEndedAt = Date.now();
39832
39895
  view.input.compositionPendingChanges = view.domObserver.pendingRecords().length ? view.input.compositionID : 0;
39833
39896
  view.input.compositionNode = null;
39834
39897
  if (view.input.badSafariComposition)
@@ -39847,7 +39910,7 @@ so this becomes the fallback color for the slot */ ''}
39847
39910
  function clearComposition(view) {
39848
39911
  if (view.composing) {
39849
39912
  view.input.composing = false;
39850
- view.input.compositionEndedAt = timestampFromCustomEvent();
39913
+ view.input.compositionEndedAt = Date.now();
39851
39914
  }
39852
39915
  while (view.input.compositionNodes.length > 0)
39853
39916
  view.input.compositionNodes.pop().markParentsDirty();
@@ -39873,11 +39936,6 @@ so this becomes the fallback color for the slot */ ''}
39873
39936
  }
39874
39937
  return textBefore || textAfter;
39875
39938
  }
39876
- function timestampFromCustomEvent() {
39877
- let event = document.createEvent("Event");
39878
- event.initEvent("event", true, true);
39879
- return event.timeStamp;
39880
- }
39881
39939
  /**
39882
39940
  @internal
39883
39941
  */
@@ -41034,7 +41092,10 @@ so this becomes the fallback color for the slot */ ''}
41034
41092
  }
41035
41093
  }
41036
41094
  }
41037
- if (added.some(n => n.nodeName == "BR") && (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46)) {
41095
+ if (added.some(n => n.nodeName == "BR") &&
41096
+ (view.input.lastKeyCode == 8 || view.input.lastKeyCode == 46 ||
41097
+ chrome && (view.composing || view.input.compositionEndedAt > Date.now() - 50) &&
41098
+ mutations.some(m => m.type == "childList" && m.removedNodes.length))) {
41038
41099
  // Browsers sometimes insert a bogus break node if you
41039
41100
  // backspace out the last bit of text before an inline-flex node (#1552)
41040
41101
  for (let node of added)
@@ -41590,38 +41651,28 @@ so this becomes the fallback color for the slot */ ''}
41590
41651
  return end;
41591
41652
  }
41592
41653
  function findDiff(a, b, pos, preferredPos, preferredSide) {
41593
- let start = a.findDiffStart(b, pos);
41654
+ let start = a.findDiffStart(b, pos), lenA = pos + a.size, lenB = pos + b.size;
41594
41655
  if (start == null)
41595
41656
  return null;
41596
- let { a: endA, b: endB } = a.findDiffEnd(b, pos + a.size, pos + b.size);
41657
+ let { a: endA, b: endB } = a.findDiffEnd(b, lenA, lenB);
41597
41658
  if (preferredSide == "end") {
41598
41659
  let adjust = Math.max(0, start - Math.min(endA, endB));
41599
41660
  preferredPos -= endA + adjust - start;
41600
41661
  }
41601
- if (endA < start && a.size < b.size) {
41662
+ if (endA < start && lenA < lenB) {
41602
41663
  let move = preferredPos <= start && preferredPos >= endA ? start - preferredPos : 0;
41603
41664
  start -= move;
41604
- if (start && start < b.size && isSurrogatePair(b.textBetween(start - 1, start + 1)))
41605
- start += move ? 1 : -1;
41606
41665
  endB = start + (endB - endA);
41607
41666
  endA = start;
41608
41667
  }
41609
41668
  else if (endB < start) {
41610
41669
  let move = preferredPos <= start && preferredPos >= endB ? start - preferredPos : 0;
41611
41670
  start -= move;
41612
- if (start && start < a.size && isSurrogatePair(a.textBetween(start - 1, start + 1)))
41613
- start += move ? 1 : -1;
41614
41671
  endA = start + (endA - endB);
41615
41672
  endB = start;
41616
41673
  }
41617
41674
  return { start, endA, endB };
41618
41675
  }
41619
- function isSurrogatePair(str) {
41620
- if (str.length != 2)
41621
- return false;
41622
- let a = str.charCodeAt(0), b = str.charCodeAt(1);
41623
- return a >= 0xDC00 && a <= 0xDFFF && b >= 0xD800 && b <= 0xDBFF;
41624
- }
41625
41676
  /**
41626
41677
  An editor view manages the DOM structure that represents an
41627
41678
  editable document. Its state and behavior are determined by its
@@ -41813,9 +41864,10 @@ so this becomes the fallback color for the slot */ ''}
41813
41864
  // a DOM selection change and the "selectionchange" event for it
41814
41865
  // can cause a spurious DOM selection update, disrupting mouse
41815
41866
  // drag selection.
41867
+ let mouseDown = this.input.mouseDown;
41816
41868
  if (forceSelUpdate ||
41817
- !(this.input.mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
41818
- anchorInRightPlace(this))) {
41869
+ !(mouseDown && this.domObserver.currentSelection.eq(this.domSelectionRange()) &&
41870
+ anchorInRightPlace(this) && mouseDown.delaySelUpdate())) {
41819
41871
  selectionToDOM(this, forceSelUpdate);
41820
41872
  }
41821
41873
  else {
@@ -42741,7 +42793,9 @@ so this becomes the fallback color for the slot */ ''}
42741
42793
  function getNodeType(nameOrType, schema) {
42742
42794
  if (typeof nameOrType === "string") {
42743
42795
  if (!schema.nodes[nameOrType]) {
42744
- throw Error(`There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`);
42796
+ throw Error(
42797
+ `There is no node type named '${nameOrType}'. Maybe you forgot to add the extension?`
42798
+ );
42745
42799
  }
42746
42800
  return schema.nodes[nameOrType];
42747
42801
  }
@@ -42900,7 +42954,9 @@ so this becomes the fallback color for the slot */ ''}
42900
42954
  function getMarkType(nameOrType, schema) {
42901
42955
  if (typeof nameOrType === "string") {
42902
42956
  if (!schema.marks[nameOrType]) {
42903
- throw Error(`There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`);
42957
+ throw Error(
42958
+ `There is no mark type named '${nameOrType}'. Maybe you forgot to add the extension?`
42959
+ );
42904
42960
  }
42905
42961
  return schema.marks[nameOrType];
42906
42962
  }
@@ -42957,9 +43013,17 @@ so this becomes the fallback color for the slot */ ''}
42957
43013
  const minPos = selectionAtStart.from;
42958
43014
  const maxPos = selectionAtEnd.to;
42959
43015
  if (position === "all") {
42960
- return TextSelection.create(doc, minMax(0, minPos, maxPos), minMax(doc.content.size, minPos, maxPos));
43016
+ return TextSelection.create(
43017
+ doc,
43018
+ minMax(0, minPos, maxPos),
43019
+ minMax(doc.content.size, minPos, maxPos)
43020
+ );
42961
43021
  }
42962
- return TextSelection.create(doc, minMax(position, minPos, maxPos), minMax(position, minPos, maxPos));
43022
+ return TextSelection.create(
43023
+ doc,
43024
+ minMax(position, minPos, maxPos),
43025
+ minMax(position, minPos, maxPos)
43026
+ );
42963
43027
  }
42964
43028
 
42965
43029
  // src/utilities/isAndroid.ts
@@ -42969,7 +43033,9 @@ so this becomes the fallback color for the slot */ ''}
42969
43033
 
42970
43034
  // src/utilities/isiOS.ts
42971
43035
  function isiOS() {
42972
- return ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes(navigator.platform) || // iPad on iOS 13 detection
43036
+ return ["iPad Simulator", "iPhone Simulator", "iPod Simulator", "iPad", "iPhone", "iPod"].includes(
43037
+ navigator.platform
43038
+ ) || // iPad on iOS 13 detection
42973
43039
  navigator.userAgent.includes("Mac") && "ontouchend" in document;
42974
43040
  }
42975
43041
 
@@ -43032,7 +43098,11 @@ so this becomes the fallback color for the slot */ ''}
43032
43098
 
43033
43099
  // src/commands/insertContent.ts
43034
43100
  var insertContent = (value, options) => ({ tr, commands }) => {
43035
- return commands.insertContentAt({ from: tr.selection.from, to: tr.selection.to }, value, options);
43101
+ return commands.insertContentAt(
43102
+ { from: tr.selection.from, to: tr.selection.to },
43103
+ value,
43104
+ options
43105
+ );
43036
43106
  };
43037
43107
 
43038
43108
  // src/utilities/elementFromString.ts
@@ -43050,7 +43120,9 @@ so this becomes the fallback color for the slot */ ''}
43050
43120
  };
43051
43121
  function elementFromString(value) {
43052
43122
  if (typeof window === "undefined") {
43053
- throw new Error("[tiptap error]: there is no window object available, so this function cannot be used");
43123
+ throw new Error(
43124
+ "[tiptap error]: there is no window object available, so this function cannot be used"
43125
+ );
43054
43126
  }
43055
43127
  const wrappedValue = `<body>${value}</body>`;
43056
43128
  const html = new window.DOMParser().parseFromString(wrappedValue, "text/html").body;
@@ -43115,9 +43187,15 @@ so this becomes the fallback color for the slot */ ''}
43115
43187
  })
43116
43188
  });
43117
43189
  if (options.slice) {
43118
- DOMParser.fromSchema(contentCheckSchema).parseSlice(elementFromString(content), options.parseOptions);
43190
+ DOMParser.fromSchema(contentCheckSchema).parseSlice(
43191
+ elementFromString(content),
43192
+ options.parseOptions
43193
+ );
43119
43194
  } else {
43120
- DOMParser.fromSchema(contentCheckSchema).parse(elementFromString(content), options.parseOptions);
43195
+ DOMParser.fromSchema(contentCheckSchema).parse(
43196
+ elementFromString(content),
43197
+ options.parseOptions
43198
+ );
43121
43199
  }
43122
43200
  if (options.errorOnInvalidContent && hasInvalidContent) {
43123
43201
  throw new Error("[tiptap error]: Invalid HTML content", {
@@ -43487,7 +43565,11 @@ so this becomes the fallback color for the slot */ ''}
43487
43565
  if (markType === mark.type) {
43488
43566
  canReset = true;
43489
43567
  if (dispatch) {
43490
- tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)));
43568
+ tr.addMark(
43569
+ pos,
43570
+ pos + node.nodeSize,
43571
+ markType.create(deleteProps(mark.attrs, attributes))
43572
+ );
43491
43573
  }
43492
43574
  }
43493
43575
  });
@@ -43656,7 +43738,11 @@ so this becomes the fallback color for the slot */ ''}
43656
43738
  options: extension.options,
43657
43739
  storage: extension.storage
43658
43740
  };
43659
- const addExtensions = getExtensionField(extension, "addExtensions", context);
43741
+ const addExtensions = getExtensionField(
43742
+ extension,
43743
+ "addExtensions",
43744
+ context
43745
+ );
43660
43746
  if (addExtensions) {
43661
43747
  return [extension, ...flattenExtensions(addExtensions())];
43662
43748
  }
@@ -43694,7 +43780,9 @@ so this becomes the fallback color for the slot */ ''}
43694
43780
 
43695
43781
  // src/helpers/splitExtensions.ts
43696
43782
  function splitExtensions(extensions) {
43697
- const baseExtensions = extensions.filter((extension) => extension.type === "extension");
43783
+ const baseExtensions = extensions.filter(
43784
+ (extension) => extension.type === "extension"
43785
+ );
43698
43786
  const nodeExtensions = extensions.filter((extension) => extension.type === "node");
43699
43787
  const markExtensions = extensions.filter((extension) => extension.type === "mark");
43700
43788
  return {
@@ -43770,11 +43858,7 @@ so this becomes the fallback color for the slot */ ''}
43770
43858
  options: extension.options,
43771
43859
  storage: extension.storage
43772
43860
  };
43773
- const addAttributes = getExtensionField(
43774
- extension,
43775
- "addAttributes",
43776
- context
43777
- );
43861
+ const addAttributes = getExtensionField(extension, "addAttributes", context);
43778
43862
  if (!addAttributes) {
43779
43863
  return;
43780
43864
  }
@@ -43874,10 +43958,15 @@ so this becomes the fallback color for the slot */ ''}
43874
43958
  if (key === "class") {
43875
43959
  const valueClasses = value ? String(value).split(" ") : [];
43876
43960
  const existingClasses = mergedAttributes[key] ? mergedAttributes[key].split(" ") : [];
43877
- const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
43961
+ const insertClasses = valueClasses.filter(
43962
+ (valueClass) => !existingClasses.includes(valueClass)
43963
+ );
43878
43964
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
43879
43965
  } else if (key === "style") {
43880
- const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)]);
43966
+ const styleMap = new Map([
43967
+ ...parseStyleEntries(mergedAttributes[key]),
43968
+ ...parseStyleEntries(value)
43969
+ ]);
43881
43970
  mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
43882
43971
  } else {
43883
43972
  mergedAttributes[key] = value;
@@ -43973,7 +44062,9 @@ so this becomes the fallback color for the slot */ ''}
43973
44062
  const topNode = (_a = nodeExtensions.find((extension) => getExtensionField(extension, "topNode"))) == null ? void 0 : _a.name;
43974
44063
  const nodes = Object.fromEntries(
43975
44064
  nodeExtensions.map((extension) => {
43976
- const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
44065
+ const extensionAttributes = allAttributes.filter(
44066
+ (attribute) => attribute.type === extension.name
44067
+ );
43977
44068
  const context = {
43978
44069
  name: extension.name,
43979
44070
  options: extension.options,
@@ -43981,7 +44072,11 @@ so this becomes the fallback color for the slot */ ''}
43981
44072
  editor
43982
44073
  };
43983
44074
  const extraNodeFields = extensions.reduce((fields, e) => {
43984
- const extendNodeSchema = getExtensionField(e, "extendNodeSchema", context);
44075
+ const extendNodeSchema = getExtensionField(
44076
+ e,
44077
+ "extendNodeSchema",
44078
+ context
44079
+ );
43985
44080
  return {
43986
44081
  ...fields,
43987
44082
  ...extendNodeSchema ? extendNodeSchema(extension) : {}
@@ -43989,36 +44084,62 @@ so this becomes the fallback color for the slot */ ''}
43989
44084
  }, {});
43990
44085
  const schema = cleanUpSchemaItem({
43991
44086
  ...extraNodeFields,
43992
- content: callOrReturn(getExtensionField(extension, "content", context)),
44087
+ content: callOrReturn(
44088
+ getExtensionField(extension, "content", context)
44089
+ ),
43993
44090
  marks: callOrReturn(getExtensionField(extension, "marks", context)),
43994
44091
  group: callOrReturn(getExtensionField(extension, "group", context)),
43995
44092
  inline: callOrReturn(getExtensionField(extension, "inline", context)),
43996
44093
  atom: callOrReturn(getExtensionField(extension, "atom", context)),
43997
- selectable: callOrReturn(getExtensionField(extension, "selectable", context)),
43998
- draggable: callOrReturn(getExtensionField(extension, "draggable", context)),
44094
+ selectable: callOrReturn(
44095
+ getExtensionField(extension, "selectable", context)
44096
+ ),
44097
+ draggable: callOrReturn(
44098
+ getExtensionField(extension, "draggable", context)
44099
+ ),
43999
44100
  code: callOrReturn(getExtensionField(extension, "code", context)),
44000
- whitespace: callOrReturn(getExtensionField(extension, "whitespace", context)),
44101
+ whitespace: callOrReturn(
44102
+ getExtensionField(extension, "whitespace", context)
44103
+ ),
44001
44104
  linebreakReplacement: callOrReturn(
44002
- getExtensionField(extension, "linebreakReplacement", context)
44105
+ getExtensionField(
44106
+ extension,
44107
+ "linebreakReplacement",
44108
+ context
44109
+ )
44110
+ ),
44111
+ defining: callOrReturn(
44112
+ getExtensionField(extension, "defining", context)
44113
+ ),
44114
+ isolating: callOrReturn(
44115
+ getExtensionField(extension, "isolating", context)
44003
44116
  ),
44004
- defining: callOrReturn(getExtensionField(extension, "defining", context)),
44005
- isolating: callOrReturn(getExtensionField(extension, "isolating", context)),
44006
44117
  attrs: Object.fromEntries(extensionAttributes.map(buildAttributeSpec))
44007
44118
  });
44008
- const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
44119
+ const parseHTML = callOrReturn(
44120
+ getExtensionField(extension, "parseHTML", context)
44121
+ );
44009
44122
  if (parseHTML) {
44010
44123
  schema.parseDOM = parseHTML.map(
44011
44124
  (parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes)
44012
44125
  );
44013
44126
  }
44014
- const renderHTML = getExtensionField(extension, "renderHTML", context);
44127
+ const renderHTML = getExtensionField(
44128
+ extension,
44129
+ "renderHTML",
44130
+ context
44131
+ );
44015
44132
  if (renderHTML) {
44016
44133
  schema.toDOM = (node) => renderHTML({
44017
44134
  node,
44018
44135
  HTMLAttributes: getRenderedAttributes(node, extensionAttributes)
44019
44136
  });
44020
44137
  }
44021
- const renderText = getExtensionField(extension, "renderText", context);
44138
+ const renderText = getExtensionField(
44139
+ extension,
44140
+ "renderText",
44141
+ context
44142
+ );
44022
44143
  if (renderText) {
44023
44144
  schema.toText = renderText;
44024
44145
  }
@@ -44027,7 +44148,9 @@ so this becomes the fallback color for the slot */ ''}
44027
44148
  );
44028
44149
  const marks = Object.fromEntries(
44029
44150
  markExtensions.map((extension) => {
44030
- const extensionAttributes = allAttributes.filter((attribute) => attribute.type === extension.name);
44151
+ const extensionAttributes = allAttributes.filter(
44152
+ (attribute) => attribute.type === extension.name
44153
+ );
44031
44154
  const context = {
44032
44155
  name: extension.name,
44033
44156
  options: extension.options,
@@ -44035,7 +44158,11 @@ so this becomes the fallback color for the slot */ ''}
44035
44158
  editor
44036
44159
  };
44037
44160
  const extraMarkFields = extensions.reduce((fields, e) => {
44038
- const extendMarkSchema = getExtensionField(e, "extendMarkSchema", context);
44161
+ const extendMarkSchema = getExtensionField(
44162
+ e,
44163
+ "extendMarkSchema",
44164
+ context
44165
+ );
44039
44166
  return {
44040
44167
  ...fields,
44041
44168
  ...extendMarkSchema ? extendMarkSchema(extension) : {}
@@ -44043,20 +44170,32 @@ so this becomes the fallback color for the slot */ ''}
44043
44170
  }, {});
44044
44171
  const schema = cleanUpSchemaItem({
44045
44172
  ...extraMarkFields,
44046
- inclusive: callOrReturn(getExtensionField(extension, "inclusive", context)),
44047
- excludes: callOrReturn(getExtensionField(extension, "excludes", context)),
44173
+ inclusive: callOrReturn(
44174
+ getExtensionField(extension, "inclusive", context)
44175
+ ),
44176
+ excludes: callOrReturn(
44177
+ getExtensionField(extension, "excludes", context)
44178
+ ),
44048
44179
  group: callOrReturn(getExtensionField(extension, "group", context)),
44049
- spanning: callOrReturn(getExtensionField(extension, "spanning", context)),
44180
+ spanning: callOrReturn(
44181
+ getExtensionField(extension, "spanning", context)
44182
+ ),
44050
44183
  code: callOrReturn(getExtensionField(extension, "code", context)),
44051
44184
  attrs: Object.fromEntries(extensionAttributes.map(buildAttributeSpec))
44052
44185
  });
44053
- const parseHTML = callOrReturn(getExtensionField(extension, "parseHTML", context));
44186
+ const parseHTML = callOrReturn(
44187
+ getExtensionField(extension, "parseHTML", context)
44188
+ );
44054
44189
  if (parseHTML) {
44055
44190
  schema.parseDOM = parseHTML.map(
44056
44191
  (parseRule) => injectExtensionAttributesToParseRule(parseRule, extensionAttributes)
44057
44192
  );
44058
44193
  }
44059
- const renderHTML = getExtensionField(extension, "renderHTML", context);
44194
+ const renderHTML = getExtensionField(
44195
+ extension,
44196
+ "renderHTML",
44197
+ context
44198
+ );
44060
44199
  if (renderHTML) {
44061
44200
  schema.toDOM = (mark) => renderHTML({
44062
44201
  mark,
@@ -44310,16 +44449,20 @@ so this becomes the fallback color for the slot */ ''}
44310
44449
  var getTextContentFromNodes = ($from, maxMatch = 500) => {
44311
44450
  let textBefore = "";
44312
44451
  const sliceEndPos = $from.parentOffset;
44313
- $from.parent.nodesBetween(Math.max(0, sliceEndPos - maxMatch), sliceEndPos, (node, pos, parent, index) => {
44314
- var _a, _b;
44315
- const chunk = ((_b = (_a = node.type.spec).toText) == null ? void 0 : _b.call(_a, {
44316
- node,
44317
- pos,
44318
- parent,
44319
- index
44320
- })) || node.textContent || "%leaf%";
44321
- textBefore += node.isAtom && !node.isText ? chunk : chunk.slice(0, Math.max(0, sliceEndPos - pos));
44322
- });
44452
+ $from.parent.nodesBetween(
44453
+ Math.max(0, sliceEndPos - maxMatch),
44454
+ sliceEndPos,
44455
+ (node, pos, parent, index) => {
44456
+ var _a, _b;
44457
+ const chunk = ((_b = (_a = node.type.spec).toText) == null ? void 0 : _b.call(_a, {
44458
+ node,
44459
+ pos,
44460
+ parent,
44461
+ index
44462
+ })) || node.textContent || "%leaf%";
44463
+ textBefore += node.isAtom && !node.isText ? chunk : chunk.slice(0, Math.max(0, sliceEndPos - pos));
44464
+ }
44465
+ );
44323
44466
  return textBefore;
44324
44467
  };
44325
44468
 
@@ -44690,7 +44833,11 @@ so this becomes the fallback color for the slot */ ''}
44690
44833
  const { selection, doc } = tr;
44691
44834
  const { $from, $to } = selection;
44692
44835
  const extensionAttributes = editor.extensionManager.attributes;
44693
- const newAttributes = getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs);
44836
+ const newAttributes = getSplittedAttributes(
44837
+ extensionAttributes,
44838
+ $from.node().type.name,
44839
+ $from.node().attrs
44840
+ );
44694
44841
  if (selection instanceof NodeSelection && selection.node.isBlock) {
44695
44842
  if (!$from.parentOffset || !canSplit(doc, $from.pos)) {
44696
44843
  return false;
@@ -44769,7 +44916,7 @@ so this becomes the fallback color for the slot */ ''}
44769
44916
  wrap = Fragment.from($from.node(d).copy(wrap));
44770
44917
  }
44771
44918
  const depthAfter = (
44772
- // eslint-disable-next-line no-nested-ternary
44919
+ // oxlint-disable-next-line no-nested-ternary
44773
44920
  $from.indexAfter(-1) < $from.node(-2).childCount ? 1 : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3
44774
44921
  );
44775
44922
  const newNextTypeAttributes2 = {
@@ -44998,15 +45145,22 @@ so this becomes the fallback color for the slot */ ''}
44998
45145
  };
44999
45146
 
45000
45147
  // src/commands/unsetAllMarks.ts
45001
- var unsetAllMarks = () => ({ tr, dispatch }) => {
45148
+ var unsetAllMarks = (options = {}) => ({ tr, dispatch, editor }) => {
45149
+ const { ignoreClearable = false } = options;
45002
45150
  const { selection } = tr;
45003
45151
  const { empty, ranges } = selection;
45004
45152
  if (empty) {
45005
45153
  return true;
45006
45154
  }
45155
+ const { nonClearableMarks } = editor.extensionManager;
45007
45156
  if (dispatch) {
45157
+ const clearableMarkTypes = Object.values(editor.schema.marks).filter(
45158
+ (markType) => ignoreClearable || !nonClearableMarks.includes(markType.name)
45159
+ );
45008
45160
  ranges.forEach((range) => {
45009
- tr.removeMark(range.$from.pos, range.$to.pos);
45161
+ for (const markType of clearableMarkTypes) {
45162
+ tr.removeMark(range.$from.pos, range.$to.pos, markType);
45163
+ }
45010
45164
  });
45011
45165
  }
45012
45166
  return true;
@@ -45241,7 +45395,9 @@ so this becomes the fallback color for the slot */ ''}
45241
45395
  result.data = inputRuleMatch.data;
45242
45396
  if (inputRuleMatch.replaceWith) {
45243
45397
  if (!inputRuleMatch.text.includes(inputRuleMatch.replaceWith)) {
45244
- console.warn('[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".');
45398
+ console.warn(
45399
+ '[tiptap warn]: "inputRuleMatch.replaceWith" must be part of "inputRuleMatch.text".'
45400
+ );
45245
45401
  }
45246
45402
  result.push(inputRuleMatch.replaceWith);
45247
45403
  }
@@ -45449,7 +45605,7 @@ so this becomes the fallback color for the slot */ ''}
45449
45605
  getExtensionField(this, "addOptions", {
45450
45606
  name: this.name
45451
45607
  })
45452
- ) || {}
45608
+ )
45453
45609
  };
45454
45610
  }
45455
45611
  get storage() {
@@ -45459,7 +45615,7 @@ so this becomes the fallback color for the slot */ ''}
45459
45615
  name: this.name,
45460
45616
  options: this.options
45461
45617
  })
45462
- ) || {}
45618
+ )
45463
45619
  };
45464
45620
  }
45465
45621
  configure(options = {}) {
@@ -45553,7 +45709,9 @@ so this becomes the fallback color for the slot */ ''}
45553
45709
  result.data = pasteRuleMatch.data;
45554
45710
  if (pasteRuleMatch.replaceWith) {
45555
45711
  if (!pasteRuleMatch.text.includes(pasteRuleMatch.replaceWith)) {
45556
- console.warn('[tiptap warn]: "pasteRuleMatch.replaceWith" must be part of "pasteRuleMatch.text".');
45712
+ console.warn(
45713
+ '[tiptap warn]: "pasteRuleMatch.replaceWith" must be part of "pasteRuleMatch.text".'
45714
+ );
45557
45715
  }
45558
45716
  result.push(pasteRuleMatch.replaceWith);
45559
45717
  }
@@ -45695,7 +45853,10 @@ so this becomes the fallback color for the slot */ ''}
45695
45853
  setTimeout(() => {
45696
45854
  const selection = dragFromOtherEditor.state.selection;
45697
45855
  if (selection) {
45698
- dragFromOtherEditor.commands.deleteRange({ from: selection.from, to: selection.to });
45856
+ dragFromOtherEditor.commands.deleteRange({
45857
+ from: selection.from,
45858
+ to: selection.to
45859
+ });
45699
45860
  }
45700
45861
  }, 10);
45701
45862
  }
@@ -45760,6 +45921,7 @@ so this becomes the fallback color for the slot */ ''}
45760
45921
  var ExtensionManager = class {
45761
45922
  constructor(extensions, editor) {
45762
45923
  this.splittableMarks = [];
45924
+ this.nonClearableMarks = [];
45763
45925
  this.editor = editor;
45764
45926
  this.baseExtensions = extensions;
45765
45927
  this.extensions = resolveExtensions(extensions);
@@ -45779,7 +45941,11 @@ so this becomes the fallback color for the slot */ ''}
45779
45941
  editor: this.editor,
45780
45942
  type: getSchemaTypeByName(extension.name, this.schema)
45781
45943
  };
45782
- const addCommands = getExtensionField(extension, "addCommands", context);
45944
+ const addCommands = getExtensionField(
45945
+ extension,
45946
+ "addCommands",
45947
+ context
45948
+ );
45783
45949
  if (!addCommands) {
45784
45950
  return commands;
45785
45951
  }
@@ -45824,7 +45990,11 @@ so this becomes the fallback color for the slot */ ''}
45824
45990
  }
45825
45991
  const keyMapPlugin = keymap(defaultBindings);
45826
45992
  plugins.push(keyMapPlugin);
45827
- const addInputRules = getExtensionField(extension, "addInputRules", context);
45993
+ const addInputRules = getExtensionField(
45994
+ extension,
45995
+ "addInputRules",
45996
+ context
45997
+ );
45828
45998
  if (isExtensionRulesEnabled(extension, editor.options.enableInputRules) && addInputRules) {
45829
45999
  const rules = addInputRules();
45830
46000
  if (rules && rules.length) {
@@ -45836,7 +46006,11 @@ so this becomes the fallback color for the slot */ ''}
45836
46006
  plugins.push(...inputPlugins);
45837
46007
  }
45838
46008
  }
45839
- const addPasteRules = getExtensionField(extension, "addPasteRules", context);
46009
+ const addPasteRules = getExtensionField(
46010
+ extension,
46011
+ "addPasteRules",
46012
+ context
46013
+ );
45840
46014
  if (isExtensionRulesEnabled(extension, editor.options.enablePasteRules) && addPasteRules) {
45841
46015
  const rules = addPasteRules();
45842
46016
  if (rules && rules.length) {
@@ -45873,7 +46047,9 @@ so this becomes the fallback color for the slot */ ''}
45873
46047
  const { nodeExtensions } = splitExtensions(this.extensions);
45874
46048
  return Object.fromEntries(
45875
46049
  nodeExtensions.filter((extension) => !!getExtensionField(extension, "addNodeView")).map((extension) => {
45876
- const extensionAttributes = this.attributes.filter((attribute) => attribute.type === extension.name);
46050
+ const extensionAttributes = this.attributes.filter(
46051
+ (attribute) => attribute.type === extension.name
46052
+ );
45877
46053
  const context = {
45878
46054
  name: extension.name,
45879
46055
  options: extension.options,
@@ -45881,7 +46057,11 @@ so this becomes the fallback color for the slot */ ''}
45881
46057
  editor,
45882
46058
  type: getNodeType(extension.name, this.schema)
45883
46059
  };
45884
- const addNodeView = getExtensionField(extension, "addNodeView", context);
46060
+ const addNodeView = getExtensionField(
46061
+ extension,
46062
+ "addNodeView",
46063
+ context
46064
+ );
45885
46065
  if (!addNodeView) {
45886
46066
  return [];
45887
46067
  }
@@ -45975,7 +46155,9 @@ so this becomes the fallback color for the slot */ ''}
45975
46155
  const { markExtensions } = splitExtensions(this.extensions);
45976
46156
  return Object.fromEntries(
45977
46157
  markExtensions.filter((extension) => !!getExtensionField(extension, "addMarkView")).map((extension) => {
45978
- const extensionAttributes = this.attributes.filter((attribute) => attribute.type === extension.name);
46158
+ const extensionAttributes = this.attributes.filter(
46159
+ (attribute) => attribute.type === extension.name
46160
+ );
45979
46161
  const context = {
45980
46162
  name: extension.name,
45981
46163
  options: extension.options,
@@ -45983,7 +46165,11 @@ so this becomes the fallback color for the slot */ ''}
45983
46165
  editor,
45984
46166
  type: getMarkType(extension.name, this.schema)
45985
46167
  };
45986
- const addMarkView = getExtensionField(extension, "addMarkView", context);
46168
+ const addMarkView = getExtensionField(
46169
+ extension,
46170
+ "addMarkView",
46171
+ context
46172
+ );
45987
46173
  if (!addMarkView) {
45988
46174
  return [];
45989
46175
  }
@@ -46047,7 +46233,7 @@ so this becomes the fallback color for the slot */ ''}
46047
46233
  extensions.map((extension) => [extension.name, extension.storage])
46048
46234
  );
46049
46235
  extensions.forEach((extension) => {
46050
- var _a;
46236
+ var _a, _b;
46051
46237
  const context = {
46052
46238
  name: extension.name,
46053
46239
  options: extension.options,
@@ -46060,8 +46246,18 @@ so this becomes the fallback color for the slot */ ''}
46060
46246
  if (keepOnSplit) {
46061
46247
  this.splittableMarks.push(extension.name);
46062
46248
  }
46249
+ const clearable = (_b = callOrReturn(
46250
+ getExtensionField(extension, "clearable", context)
46251
+ )) != null ? _b : true;
46252
+ if (!clearable) {
46253
+ this.nonClearableMarks.push(extension.name);
46254
+ }
46063
46255
  }
46064
- const onBeforeCreate = getExtensionField(extension, "onBeforeCreate", context);
46256
+ const onBeforeCreate = getExtensionField(
46257
+ extension,
46258
+ "onBeforeCreate",
46259
+ context
46260
+ );
46065
46261
  const onCreate = getExtensionField(extension, "onCreate", context);
46066
46262
  const onUpdate = getExtensionField(extension, "onUpdate", context);
46067
46263
  const onSelectionUpdate = getExtensionField(
@@ -46069,7 +46265,11 @@ so this becomes the fallback color for the slot */ ''}
46069
46265
  "onSelectionUpdate",
46070
46266
  context
46071
46267
  );
46072
- const onTransaction = getExtensionField(extension, "onTransaction", context);
46268
+ const onTransaction = getExtensionField(
46269
+ extension,
46270
+ "onTransaction",
46271
+ context
46272
+ );
46073
46273
  const onFocus = getExtensionField(extension, "onFocus", context);
46074
46274
  const onBlur = getExtensionField(extension, "onBlur", context);
46075
46275
  const onDestroy = getExtensionField(extension, "onDestroy", context);
@@ -46160,15 +46360,16 @@ so this becomes the fallback color for the slot */ ''}
46160
46360
  const { editor } = this;
46161
46361
  const { state, schema } = editor;
46162
46362
  const { doc, selection } = state;
46163
- const { ranges } = selection;
46164
- const from = Math.min(...ranges.map((range2) => range2.$from.pos));
46165
- const to = Math.max(...ranges.map((range2) => range2.$to.pos));
46166
46363
  const textSerializers = getTextSerializersFromSchema(schema);
46167
- const range = { from, to };
46168
- return getTextBetween(doc, range, {
46169
- ...this.options.blockSeparator !== void 0 ? { blockSeparator: this.options.blockSeparator } : {},
46364
+ const { blockSeparator } = this.options;
46365
+ const options = {
46366
+ ...blockSeparator !== void 0 ? { blockSeparator } : {},
46170
46367
  textSerializers
46171
- });
46368
+ };
46369
+ const sortedRanges = [...selection.ranges].sort((a, b) => a.$from.pos - b.$from.pos);
46370
+ return sortedRanges.map(
46371
+ ({ $from, $to }) => getTextBetween(doc, { from: $from.pos, to: $to.pos }, options)
46372
+ ).join(blockSeparator != null ? blockSeparator : "\n\n");
46172
46373
  }
46173
46374
  }
46174
46375
  })
@@ -46194,28 +46395,35 @@ so this becomes the fallback color for the slot */ ''}
46194
46395
  if ((_d = (_c2 = (_b2 = (_a2 = this.editor.options.coreExtensionOptions) == null ? void 0 : _a2.delete) == null ? void 0 : _b2.filterTransaction) == null ? void 0 : _c2.call(_b2, transaction)) != null ? _d : transaction.getMeta("y-sync$")) {
46195
46396
  return;
46196
46397
  }
46197
- const nextTransaction = combineTransactionSteps(transaction.before, [transaction, ...appendedTransactions]);
46398
+ const nextTransaction = combineTransactionSteps(transaction.before, [
46399
+ transaction,
46400
+ ...appendedTransactions
46401
+ ]);
46198
46402
  const changes = getChangedRanges(nextTransaction);
46199
46403
  changes.forEach((change) => {
46200
46404
  if (nextTransaction.mapping.mapResult(change.oldRange.from).deletedAfter && nextTransaction.mapping.mapResult(change.oldRange.to).deletedBefore) {
46201
- nextTransaction.before.nodesBetween(change.oldRange.from, change.oldRange.to, (node, from) => {
46202
- const to = from + node.nodeSize - 2;
46203
- const isFullyWithinRange = change.oldRange.from <= from && to <= change.oldRange.to;
46204
- this.editor.emit("delete", {
46205
- type: "node",
46206
- node,
46207
- from,
46208
- to,
46209
- newFrom: nextTransaction.mapping.map(from),
46210
- newTo: nextTransaction.mapping.map(to),
46211
- deletedRange: change.oldRange,
46212
- newRange: change.newRange,
46213
- partial: !isFullyWithinRange,
46214
- editor: this.editor,
46215
- transaction,
46216
- combinedTransform: nextTransaction
46217
- });
46218
- });
46405
+ nextTransaction.before.nodesBetween(
46406
+ change.oldRange.from,
46407
+ change.oldRange.to,
46408
+ (node, from) => {
46409
+ const to = from + node.nodeSize - 2;
46410
+ const isFullyWithinRange = change.oldRange.from <= from && to <= change.oldRange.to;
46411
+ this.editor.emit("delete", {
46412
+ type: "node",
46413
+ node,
46414
+ from,
46415
+ to,
46416
+ newFrom: nextTransaction.mapping.map(from),
46417
+ newTo: nextTransaction.mapping.map(to),
46418
+ deletedRange: change.oldRange,
46419
+ newRange: change.newRange,
46420
+ partial: !isFullyWithinRange,
46421
+ editor: this.editor,
46422
+ transaction,
46423
+ combinedTransform: nextTransaction
46424
+ });
46425
+ }
46426
+ );
46219
46427
  }
46220
46428
  });
46221
46429
  const mapping = nextTransaction.mapping;
@@ -46395,7 +46603,9 @@ so this becomes the fallback color for the slot */ ''}
46395
46603
  return;
46396
46604
  }
46397
46605
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
46398
- const ignoreTr = transactions.some((transaction) => transaction.getMeta("preventClearDocument"));
46606
+ const ignoreTr = transactions.some(
46607
+ (transaction) => transaction.getMeta("preventClearDocument")
46608
+ );
46399
46609
  if (!docChanges || ignoreTr) {
46400
46610
  return;
46401
46611
  }
@@ -46564,7 +46774,9 @@ so this becomes the fallback color for the slot */ ''}
46564
46774
  let to = this.to;
46565
46775
  if (this.isBlock) {
46566
46776
  if (this.content.size === 0) {
46567
- console.error(`You can\u2019t set content on a block node. Tried to set content on ${this.name} at ${this.pos}`);
46777
+ console.error(
46778
+ `You can\u2019t set content on a block node. Tried to set content on ${this.name} at ${this.pos}`
46779
+ );
46568
46780
  return;
46569
46781
  }
46570
46782
  from = this.from + 1;
@@ -46635,7 +46847,12 @@ so this becomes the fallback color for the slot */ ''}
46635
46847
  if (!isBlock && !isInline && $pos.depth <= this.depth) {
46636
46848
  return;
46637
46849
  }
46638
- const childNodePos = new _NodePos($pos, this.editor, isBlock, isBlock || isInline ? node : null);
46850
+ const childNodePos = new _NodePos(
46851
+ $pos,
46852
+ this.editor,
46853
+ isBlock,
46854
+ isBlock || isInline ? node : null
46855
+ );
46639
46856
  if (isBlock) {
46640
46857
  childNodePos.actualDepth = this.depth + 1;
46641
46858
  }
@@ -46686,7 +46903,9 @@ so this becomes the fallback color for the slot */ ''}
46686
46903
  return;
46687
46904
  }
46688
46905
  if (childPos.node.type.name === selector) {
46689
- const doesAllAttributesMatch = attrKeys.every((key) => attributes[key] === childPos.node.attrs[key]);
46906
+ const doesAllAttributesMatch = attrKeys.every(
46907
+ (key) => attributes[key] === childPos.node.attrs[key]
46908
+ );
46690
46909
  if (doesAllAttributesMatch) {
46691
46910
  nodes.push(childPos);
46692
46911
  }
@@ -46783,7 +47002,7 @@ img.ProseMirror-separator {
46783
47002
 
46784
47003
  // src/utilities/createStyleTag.ts
46785
47004
  function createStyleTag(style2, nonce, suffix) {
46786
- const tiptapStyleTag = document.querySelector(`style[data-tiptap-style${""}]`);
47005
+ const tiptapStyleTag = document.querySelector(`style[data-tiptap-style${suffix ? `-${suffix}` : ""}]`);
46787
47006
  if (tiptapStyleTag !== null) {
46788
47007
  return tiptapStyleTag;
46789
47008
  }
@@ -46791,7 +47010,7 @@ img.ProseMirror-separator {
46791
47010
  if (nonce) {
46792
47011
  styleNode.setAttribute("nonce", nonce);
46793
47012
  }
46794
- styleNode.setAttribute(`data-tiptap-style${""}`, "");
47013
+ styleNode.setAttribute(`data-tiptap-style${suffix ? `-${suffix}` : ""}`, "");
46795
47014
  styleNode.innerHTML = style2;
46796
47015
  document.getElementsByTagName("head")[0].appendChild(styleNode);
46797
47016
  return styleNode;
@@ -47150,7 +47369,9 @@ img.ProseMirror-separator {
47150
47369
  errorOnInvalidContent: this.options.enableContentCheck
47151
47370
  });
47152
47371
  } catch (e) {
47153
- if (!(e instanceof Error) || !["[tiptap error]: Invalid JSON content", "[tiptap error]: Invalid HTML content"].includes(e.message)) {
47372
+ if (!(e instanceof Error) || !["[tiptap error]: Invalid JSON content", "[tiptap error]: Invalid HTML content"].includes(
47373
+ e.message
47374
+ )) {
47154
47375
  throw e;
47155
47376
  }
47156
47377
  this.emit("contentError", {
@@ -47160,7 +47381,9 @@ img.ProseMirror-separator {
47160
47381
  if ("collaboration" in this.storage && typeof this.storage.collaboration === "object" && this.storage.collaboration) {
47161
47382
  this.storage.collaboration.isDisabled = true;
47162
47383
  }
47163
- this.options.extensions = this.options.extensions.filter((extension) => extension.name !== "collaboration");
47384
+ this.options.extensions = this.options.extensions.filter(
47385
+ (extension) => extension.name !== "collaboration"
47386
+ );
47164
47387
  this.createExtensionManager();
47165
47388
  }
47166
47389
  });
@@ -47278,7 +47501,7 @@ img.ProseMirror-separator {
47278
47501
  this.emit("focus", {
47279
47502
  editor: this,
47280
47503
  event: focus2.event,
47281
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
47504
+ // oxlint-disable-next-lineno-non-null-assertion
47282
47505
  transaction: mostRecentFocusTr
47283
47506
  });
47284
47507
  }
@@ -47286,7 +47509,7 @@ img.ProseMirror-separator {
47286
47509
  this.emit("blur", {
47287
47510
  editor: this,
47288
47511
  event: blur2.event,
47289
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
47512
+ // oxlint-disable-next-lineno-non-null-assertion
47290
47513
  transaction: mostRecentFocusTr
47291
47514
  });
47292
47515
  }
@@ -47804,7 +48027,9 @@ ${renderedContent}
47804
48027
  return index !== void 0 ? index : -1;
47805
48028
  },
47806
48029
  tokenize(src, _tokens, _lexer) {
47807
- const tokenPattern = selfClosing ? new RegExp(`^\\[${escapedShortcode}\\s*([^\\]]*)\\]`) : new RegExp(`^\\[${escapedShortcode}\\s*([^\\]]*)\\]([\\s\\S]*?)\\[\\/${escapedShortcode}\\]`);
48030
+ const tokenPattern = selfClosing ? new RegExp(`^\\[${escapedShortcode}\\s*([^\\]]*)\\]`) : new RegExp(
48031
+ `^\\[${escapedShortcode}\\s*([^\\]]*)\\]([\\s\\S]*?)\\[\\/${escapedShortcode}\\]`
48032
+ );
47808
48033
  const match = src.match(tokenPattern);
47809
48034
  if (!match) {
47810
48035
  return void 0;
@@ -48100,7 +48325,9 @@ ${indentedChild}`;
48100
48325
  const marks = storedMarks || selection.$to.parentOffset && selection.$from.marks();
48101
48326
  return chain().insertContent({ type: this.name }).command(({ tr, dispatch }) => {
48102
48327
  if (dispatch && marks && keepMarks) {
48103
- const filteredMarks = marks.filter((mark) => splittableMarks.includes(mark.type.name));
48328
+ const filteredMarks = marks.filter(
48329
+ (mark) => splittableMarks.includes(mark.type.name)
48330
+ );
48104
48331
  tr.ensureMarks(filteredMarks);
48105
48332
  }
48106
48333
  return true;
@@ -58286,7 +58513,7 @@ ${indentedChild}`;
58286
58513
  href: {},
58287
58514
  rel: { default: 'noopener noreferrer' },
58288
58515
  // Adding `class` here is a workaround to render two mentions without a whitespace as display names
58289
- // This attribute can be removed when the below issue is resolved
58516
+ // For more details on this behavior, refer to the issue below:
58290
58517
  // https://github.com/ni/nimble/issues/1707
58291
58518
  class: { default: '' }
58292
58519
  },
@@ -58325,7 +58552,7 @@ ${indentedChild}`;
58325
58552
  : null,
58326
58553
  rel: node.attrs.rel,
58327
58554
  // Adding `class` here is a workaround to render two mentions without a whitespace as display names
58328
- // This attribute can be removed when the below issue is resolved
58555
+ // For more details on this behavior, refer to the issue below:
58329
58556
  // https://github.com/ni/nimble/issues/1707
58330
58557
  class: href,
58331
58558
  'underline-hidden': _a$4.startsWithHttpOrHttps(href)
@@ -58871,7 +59098,9 @@ ${indentedChild}`;
58871
59098
  }
58872
59099
  const { children, ...rest } = attributes != null ? attributes : {};
58873
59100
  if (tag === "svg") {
58874
- throw new Error("SVG elements are not supported in the JSX syntax, use the array syntax instead");
59101
+ throw new Error(
59102
+ "SVG elements are not supported in the JSX syntax, use the array syntax instead"
59103
+ );
58875
59104
  }
58876
59105
  return [tag, rest, children];
58877
59106
  };
@@ -60842,7 +61071,9 @@ ${indentedChild}`;
60842
61071
  key: new PluginKey("autolink"),
60843
61072
  appendTransaction: (transactions, oldState, newState) => {
60844
61073
  const docChanges = transactions.some((transaction) => transaction.docChanged) && !oldState.doc.eq(newState.doc);
60845
- const preventAutolink = transactions.some((transaction) => transaction.getMeta("preventAutolink"));
61074
+ const preventAutolink = transactions.some(
61075
+ (transaction) => transaction.getMeta("preventAutolink")
61076
+ );
60846
61077
  if (!docChanges || preventAutolink) {
60847
61078
  return;
60848
61079
  }
@@ -60850,7 +61081,11 @@ ${indentedChild}`;
60850
61081
  const transform = combineTransactionSteps(oldState.doc, [...transactions]);
60851
61082
  const changes = getChangedRanges(transform);
60852
61083
  changes.forEach(({ newRange }) => {
60853
- const nodesInChangedRanges = findChildrenInRange(newState.doc, newRange, (node) => node.isTextblock);
61084
+ const nodesInChangedRanges = findChildrenInRange(
61085
+ newState.doc,
61086
+ newRange,
61087
+ (node) => node.isTextblock
61088
+ );
60854
61089
  let textBlock;
60855
61090
  let textBeforeWhitespace;
60856
61091
  if (nodesInChangedRanges.length > 1) {
@@ -60867,7 +61102,12 @@ ${indentedChild}`;
60867
61102
  return;
60868
61103
  }
60869
61104
  textBlock = nodesInChangedRanges[0];
60870
- textBeforeWhitespace = newState.doc.textBetween(textBlock.pos, newRange.to, void 0, " ");
61105
+ textBeforeWhitespace = newState.doc.textBetween(
61106
+ textBlock.pos,
61107
+ newRange.to,
61108
+ void 0,
61109
+ " "
61110
+ );
60871
61111
  }
60872
61112
  if (textBlock && textBeforeWhitespace) {
60873
61113
  const wordsBeforeWhitespace = textBeforeWhitespace.split(UNICODE_WHITESPACE_REGEX).filter(Boolean);
@@ -60879,7 +61119,9 @@ ${indentedChild}`;
60879
61119
  if (!lastWordBeforeSpace) {
60880
61120
  return false;
60881
61121
  }
60882
- const linksBeforeSpace = tokenize(lastWordBeforeSpace).map((t) => t.toObject(options.defaultProtocol));
61122
+ const linksBeforeSpace = tokenize(lastWordBeforeSpace).map(
61123
+ (t) => t.toObject(options.defaultProtocol)
61124
+ );
60883
61125
  if (!isValidLinkStructure(linksBeforeSpace)) {
60884
61126
  return false;
60885
61127
  }
@@ -60893,7 +61135,9 @@ ${indentedChild}`;
60893
61135
  }
60894
61136
  return !newState.doc.rangeHasMark(link.from, link.to, newState.schema.marks.code);
60895
61137
  }).filter((link) => options.validate(link.value)).filter((link) => options.shouldAutoLink(link.value)).forEach((link) => {
60896
- if (getMarksBetween(link.from, link.to, newState.doc).some((item) => item.mark.type === options.type)) {
61138
+ if (getMarksBetween(link.from, link.to, newState.doc).some(
61139
+ (item) => item.mark.type === options.type
61140
+ )) {
60897
61141
  return;
60898
61142
  }
60899
61143
  tr.addMark(
@@ -60991,7 +61235,18 @@ ${indentedChild}`;
60991
61235
  });
60992
61236
  }
60993
61237
  function isAllowedUri(uri, protocols) {
60994
- const allowedProtocols = ["http", "https", "ftp", "ftps", "mailto", "tel", "callto", "sms", "cid", "xmpp"];
61238
+ const allowedProtocols = [
61239
+ "http",
61240
+ "https",
61241
+ "ftp",
61242
+ "ftps",
61243
+ "mailto",
61244
+ "tel",
61245
+ "callto",
61246
+ "sms",
61247
+ "cid",
61248
+ "xmpp"
61249
+ ];
60995
61250
  if (protocols) {
60996
61251
  protocols.forEach((protocol) => {
60997
61252
  const nextProtocol = typeof protocol === "string" ? protocol : protocol.scheme;
@@ -61002,7 +61257,7 @@ ${indentedChild}`;
61002
61257
  }
61003
61258
  return !uri || uri.replace(UNICODE_WHITESPACE_REGEX_GLOBAL, "").match(
61004
61259
  new RegExp(
61005
- // eslint-disable-next-line no-useless-escape
61260
+ // oxlint-disable-next-line no-useless-escape
61006
61261
  `^(?:(?:${allowedProtocols.join("|")}):|[^a-z]|[a-z0-9+.-]+(?:[^a-z+.-:]|$))`,
61007
61262
  "i"
61008
61263
  )
@@ -61016,7 +61271,9 @@ ${indentedChild}`;
61016
61271
  onCreate() {
61017
61272
  if (this.options.validate && !this.options.shouldAutoLink) {
61018
61273
  this.options.shouldAutoLink = this.options.validate;
61019
- console.warn("The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead.");
61274
+ console.warn(
61275
+ "The `validate` option is deprecated. Rename to the `shouldAutoLink` option instead."
61276
+ );
61020
61277
  }
61021
61278
  this.options.protocols.forEach((protocol) => {
61022
61279
  if (typeof protocol === "string") {
@@ -61323,6 +61580,109 @@ ${indentedChild}`;
61323
61580
  return [inputRule];
61324
61581
  }
61325
61582
  });
61583
+
61584
+ // src/helpers/getBranchingNestedListAtCursor.ts
61585
+ var getBranchingNestedListAtCursor = (state, itemName, wrapperNames) => {
61586
+ const { selection } = state;
61587
+ if (!selection.empty) {
61588
+ return null;
61589
+ }
61590
+ const { $from } = selection;
61591
+ if (!$from.parent.isTextblock) {
61592
+ return null;
61593
+ }
61594
+ if ($from.parentOffset !== $from.parent.content.size) {
61595
+ return null;
61596
+ }
61597
+ let listItemDepth = -1;
61598
+ for (let depth = $from.depth; depth > 0; depth -= 1) {
61599
+ if ($from.node(depth).type.name === itemName) {
61600
+ listItemDepth = depth;
61601
+ break;
61602
+ }
61603
+ }
61604
+ if (listItemDepth < 0) {
61605
+ return null;
61606
+ }
61607
+ const listItem = $from.node(listItemDepth);
61608
+ const indexInListItem = $from.index(listItemDepth);
61609
+ if (indexInListItem + 1 >= listItem.childCount) {
61610
+ return null;
61611
+ }
61612
+ const nextChild = listItem.child(indexInListItem + 1);
61613
+ if (!wrapperNames.includes(nextChild.type.name)) {
61614
+ return null;
61615
+ }
61616
+ const itemType = state.schema.nodes[itemName];
61617
+ let hasBranching = false;
61618
+ nextChild.forEach((child) => {
61619
+ if (child.type === itemType && child.childCount > 1) {
61620
+ hasBranching = true;
61621
+ }
61622
+ });
61623
+ if (!hasBranching) {
61624
+ return null;
61625
+ }
61626
+ const nodeAfter = state.doc.resolve($from.after()).nodeAfter;
61627
+ if (!nodeAfter || !wrapperNames.includes(nodeAfter.type.name)) {
61628
+ return null;
61629
+ }
61630
+ const items = [];
61631
+ nodeAfter.forEach((child) => {
61632
+ items.push(child);
61633
+ });
61634
+ if (items.length === 0) {
61635
+ return null;
61636
+ }
61637
+ return {
61638
+ listItemDepth,
61639
+ nestedList: nodeAfter,
61640
+ nestedListPos: $from.after(),
61641
+ insertPos: $from.after(listItemDepth),
61642
+ items
61643
+ };
61644
+ };
61645
+
61646
+ // src/helpers/hoistBranchingNestedList.ts
61647
+ var hoistBranchingNestedList = (state, dispatch, itemName, wrapperNames) => {
61648
+ const context = getBranchingNestedListAtCursor(state, itemName, wrapperNames);
61649
+ if (!context) {
61650
+ return false;
61651
+ }
61652
+ const { selection } = state;
61653
+ const { nestedList, nestedListPos, insertPos, items } = context;
61654
+ const tr = state.tr;
61655
+ tr.delete(nestedListPos, nestedListPos + nestedList.nodeSize);
61656
+ const mappedInsertPos = tr.mapping.map(insertPos);
61657
+ tr.insert(mappedInsertPos, Fragment.from(items));
61658
+ tr.setSelection(selection.map(tr.doc, tr.mapping));
61659
+ if (dispatch) {
61660
+ dispatch(tr);
61661
+ }
61662
+ return true;
61663
+ };
61664
+
61665
+ // src/helpers/handleDeleteBranchingNestedList.ts
61666
+ var handleDeleteBranchingNestedList = (editor, itemName, wrapperNames) => {
61667
+ return hoistBranchingNestedList(editor.state, editor.view.dispatch, itemName, wrapperNames);
61668
+ };
61669
+
61670
+ // src/helpers/createBranchingListDeleteKeymap.ts
61671
+ var createBranchingListDeleteKeymap = (itemName, wrapperNames) => {
61672
+ return Extension.create({
61673
+ name: `${itemName}BranchingDeleteKeymap`,
61674
+ priority: 101,
61675
+ addKeyboardShortcuts() {
61676
+ const handleDelete2 = () => handleDeleteBranchingNestedList(this.editor, itemName, wrapperNames);
61677
+ return {
61678
+ Delete: handleDelete2,
61679
+ "Mod-Delete": handleDelete2
61680
+ };
61681
+ }
61682
+ });
61683
+ };
61684
+
61685
+ // src/item/list-item.ts
61326
61686
  function isSameLineOrderedListToken(token) {
61327
61687
  var _a, _b;
61328
61688
  const nestedToken = (_a = token.tokens) == null ? void 0 : _a[0];
@@ -61437,6 +61797,14 @@ ${indentedChild}`;
61437
61797
  ctx
61438
61798
  );
61439
61799
  },
61800
+ addExtensions() {
61801
+ return [
61802
+ createBranchingListDeleteKeymap(this.name, [
61803
+ this.options.bulletListTypeName,
61804
+ this.options.orderedListTypeName
61805
+ ])
61806
+ ];
61807
+ },
61440
61808
  addKeyboardShortcuts() {
61441
61809
  return {
61442
61810
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -61501,33 +61869,6 @@ ${indentedChild}`;
61501
61869
  return true;
61502
61870
  };
61503
61871
 
61504
- // src/keymap/listHelpers/hasListItemBefore.ts
61505
- var hasListItemBefore = (typeOrName, state) => {
61506
- var _a;
61507
- const { $anchor } = state.selection;
61508
- const $targetPos = state.doc.resolve($anchor.pos - 2);
61509
- if ($targetPos.index() === 0) {
61510
- return false;
61511
- }
61512
- if (((_a = $targetPos.nodeBefore) == null ? void 0 : _a.type.name) !== typeOrName) {
61513
- return false;
61514
- }
61515
- return true;
61516
- };
61517
- var listItemHasSubList = (typeOrName, state, node) => {
61518
- if (!node) {
61519
- return false;
61520
- }
61521
- const nodeType = getNodeType(typeOrName, state.schema);
61522
- let hasSubList = false;
61523
- node.descendants((child) => {
61524
- if (child.type === nodeType) {
61525
- hasSubList = true;
61526
- }
61527
- });
61528
- return hasSubList;
61529
- };
61530
-
61531
61872
  // src/keymap/listHelpers/handleBackspace.ts
61532
61873
  var handleBackspace = (editor, name, parentListTypes) => {
61533
61874
  if (editor.commands.undoInputRule()) {
@@ -61558,16 +61899,6 @@ ${indentedChild}`;
61558
61899
  if (!isAtStartOfNode(editor.state)) {
61559
61900
  return false;
61560
61901
  }
61561
- const listItemPos = findListItemPos(name, editor.state);
61562
- if (!listItemPos) {
61563
- return false;
61564
- }
61565
- const $prev = editor.state.doc.resolve(listItemPos.$pos.pos - 2);
61566
- const prevNode = $prev.node(listItemPos.depth);
61567
- const previousListItemHasSubList = listItemHasSubList(name, editor.state, prevNode);
61568
- if (hasListItemBefore(name, editor.state) && !previousListItemHasSubList) {
61569
- return editor.commands.joinItemBackward();
61570
- }
61571
61902
  return editor.chain().liftListItem(name).run();
61572
61903
  };
61573
61904
 
@@ -61633,6 +61964,33 @@ ${indentedChild}`;
61633
61964
  return true;
61634
61965
  };
61635
61966
 
61967
+ // src/keymap/listHelpers/hasListItemBefore.ts
61968
+ var hasListItemBefore = (typeOrName, state) => {
61969
+ var _a;
61970
+ const { $anchor } = state.selection;
61971
+ const $targetPos = state.doc.resolve($anchor.pos - 2);
61972
+ if ($targetPos.index() === 0) {
61973
+ return false;
61974
+ }
61975
+ if (((_a = $targetPos.nodeBefore) == null ? void 0 : _a.type.name) !== typeOrName) {
61976
+ return false;
61977
+ }
61978
+ return true;
61979
+ };
61980
+ var listItemHasSubList = (typeOrName, state, node) => {
61981
+ if (!node) {
61982
+ return false;
61983
+ }
61984
+ const nodeType = getNodeType(typeOrName, state.schema);
61985
+ let hasSubList = false;
61986
+ node.descendants((child) => {
61987
+ if (child.type === nodeType) {
61988
+ hasSubList = true;
61989
+ }
61990
+ });
61991
+ return hasSubList;
61992
+ };
61993
+
61636
61994
  // src/keymap/list-keymap.ts
61637
61995
  var ListKeymap = Extension.create({
61638
61996
  name: "listKeymap",
@@ -61709,7 +62067,14 @@ ${indentedChild}`;
61709
62067
  var INDENTED_LINE_REGEX = /^\s/;
61710
62068
  function isBlockContentLine(line) {
61711
62069
  const trimmedLine = line.trimStart();
61712
- return /^[-+*]\s+/.test(trimmedLine) || /^\d+\.\s+/.test(trimmedLine) || /^>\s?/.test(trimmedLine) || /^```/.test(trimmedLine) || /^~~~/.test(trimmedLine);
62070
+ return (
62071
+ // oxlint-disable-next-line prefer-string-starts-ends-with
62072
+ /^[-+*]\s+/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
62073
+ /^\d+\.\s+/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
62074
+ /^>\s?/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
62075
+ /^```/.test(trimmedLine) || // oxlint-disable-next-line prefer-string-starts-ends-with
62076
+ /^~~~/.test(trimmedLine)
62077
+ );
61713
62078
  }
61714
62079
  function splitItemContent(contentLines) {
61715
62080
  const paragraphLines = [];
@@ -62085,6 +62450,12 @@ ${indentedChild}`;
62085
62450
  const prefix = `- [${checkedChar}] `;
62086
62451
  return renderNestedMarkdownContent(node, h, prefix);
62087
62452
  },
62453
+ addExtensions() {
62454
+ if (!this.options.nested) {
62455
+ return [];
62456
+ }
62457
+ return [createBranchingListDeleteKeymap(this.name, [this.options.taskListTypeName])];
62458
+ },
62088
62459
  addKeyboardShortcuts() {
62089
62460
  const shortcuts = {
62090
62461
  Enter: () => this.editor.commands.splitListItem(this.name),
@@ -62223,7 +62594,11 @@ ${indentedChild}`;
62223
62594
  ];
62224
62595
  },
62225
62596
  renderHTML({ HTMLAttributes }) {
62226
- return ["ul", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }), 0];
62597
+ return [
62598
+ "ul",
62599
+ mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }),
62600
+ 0
62601
+ ];
62227
62602
  },
62228
62603
  parseMarkdown: (token, h) => {
62229
62604
  return h.createNode("taskList", {}, h.parseChildren(token.items || []));
@@ -62360,7 +62735,14 @@ ${indentedChild}`;
62360
62735
  // src/suggestion.ts
62361
62736
  function findSuggestionMatch(config) {
62362
62737
  var _a;
62363
- const { char, allowSpaces: allowSpacesOption, allowToIncludeChar, allowedPrefixes, startOfLine, $position } = config;
62738
+ const {
62739
+ char,
62740
+ allowSpaces: allowSpacesOption,
62741
+ allowToIncludeChar,
62742
+ allowedPrefixes,
62743
+ startOfLine,
62744
+ $position
62745
+ } = config;
62364
62746
  const allowSpaces = allowSpacesOption && !allowToIncludeChar;
62365
62747
  const escapedChar = escapeForRegEx(char);
62366
62748
  const suffix = new RegExp(`\\s${escapedChar}$`);
@@ -62493,7 +62875,11 @@ ${indentedChild}`;
62493
62875
  text: (state == null ? void 0 : state.text) || null,
62494
62876
  items: [],
62495
62877
  command: (commandProps) => {
62496
- return command({ editor, range: (state == null ? void 0 : state.range) || { from: 0, to: 0 }, props: commandProps });
62878
+ return command({
62879
+ editor,
62880
+ range: (state == null ? void 0 : state.range) || { from: 0, to: 0 },
62881
+ props: commandProps
62882
+ });
62497
62883
  },
62498
62884
  decorationNode,
62499
62885
  clientRect: clientRectFor(view, decorationNode)
@@ -62523,7 +62909,9 @@ ${indentedChild}`;
62523
62909
  return;
62524
62910
  }
62525
62911
  const state = handleExit && !handleStart ? prev : next;
62526
- const decorationNode = view.dom.querySelector(`[data-decoration-id="${state.decorationId}"]`);
62912
+ const decorationNode = view.dom.querySelector(
62913
+ `[data-decoration-id="${state.decorationId}"]`
62914
+ );
62527
62915
  props = {
62528
62916
  editor,
62529
62917
  range: state.range,
@@ -62875,7 +63263,11 @@ ${indentedChild}`;
62875
63263
  suggestion
62876
63264
  });
62877
63265
  if (typeof html === "string") {
62878
- return ["span", mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes), html];
63266
+ return [
63267
+ "span",
63268
+ mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes),
63269
+ html
63270
+ ];
62879
63271
  }
62880
63272
  return html;
62881
63273
  },
@@ -64208,6 +64600,9 @@ ${indentedChild}`;
64208
64600
  };
64209
64601
  }
64210
64602
  });
64603
+ var DEFAULT_DATA_ATTRIBUTE = "placeholder";
64604
+ var PLUGIN_KEY = new PluginKey("tiptap__placeholder");
64605
+ var VIEWPORT_OVERSCAN_PX = 200;
64211
64606
  function createPlaceholderDecoration(options) {
64212
64607
  const {
64213
64608
  editor,
@@ -64234,6 +64629,96 @@ ${indentedChild}`;
64234
64629
  });
64235
64630
  }
64236
64631
 
64632
+ // src/placeholder/utils/buildPlaceholderDecorations.ts
64633
+ function resolveEmptyNodeClass(emptyNodeClass, props) {
64634
+ return typeof emptyNodeClass === "function" ? emptyNodeClass(props) : emptyNodeClass;
64635
+ }
64636
+ function buildPlaceholderDecorations({
64637
+ editor,
64638
+ options,
64639
+ dataAttribute,
64640
+ doc,
64641
+ selection
64642
+ }) {
64643
+ var _a, _b;
64644
+ const active = editor.isEditable || !options.showOnlyWhenEditable;
64645
+ if (!active) {
64646
+ return null;
64647
+ }
64648
+ const { anchor } = selection;
64649
+ const decorations = [];
64650
+ const isEmptyDoc = editor.isEmpty;
64651
+ const useResolvedPath = options.showOnlyCurrent && !options.includeChildren;
64652
+ if (useResolvedPath) {
64653
+ const resolved = doc.resolve(anchor);
64654
+ const node = resolved.depth > 0 ? resolved.node(1) : resolved.nodeAfter;
64655
+ const nodeStart = resolved.depth > 0 ? resolved.before(1) : anchor;
64656
+ if (node && node.type.isTextblock && isNodeEmpty(node)) {
64657
+ const hasAnchor = anchor >= nodeStart && anchor <= nodeStart + node.nodeSize;
64658
+ decorations.push(
64659
+ createPlaceholderDecoration({
64660
+ editor,
64661
+ isEmptyDoc,
64662
+ dataAttribute,
64663
+ hasAnchor,
64664
+ placeholder: options.placeholder,
64665
+ classes: {
64666
+ emptyEditor: options.emptyEditorClass,
64667
+ emptyNode: resolveEmptyNodeClass(options.emptyNodeClass, {
64668
+ editor,
64669
+ node,
64670
+ pos: nodeStart,
64671
+ hasAnchor
64672
+ })
64673
+ },
64674
+ node,
64675
+ pos: nodeStart
64676
+ })
64677
+ );
64678
+ }
64679
+ } else {
64680
+ const pluginState = PLUGIN_KEY.getState(editor.state);
64681
+ const from = (_a = pluginState == null ? void 0 : pluginState.topPos) != null ? _a : 0;
64682
+ const to = (_b = pluginState == null ? void 0 : pluginState.bottomPos) != null ? _b : doc.content.size;
64683
+ doc.nodesBetween(from, to, (node, pos) => {
64684
+ const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
64685
+ const isEmpty = !node.isLeaf && isNodeEmpty(node);
64686
+ if (!node.type.isTextblock) {
64687
+ return options.includeChildren;
64688
+ }
64689
+ if ((hasAnchor || !options.showOnlyCurrent) && isEmpty) {
64690
+ decorations.push(
64691
+ createPlaceholderDecoration({
64692
+ editor,
64693
+ isEmptyDoc,
64694
+ dataAttribute,
64695
+ hasAnchor,
64696
+ placeholder: options.placeholder,
64697
+ classes: {
64698
+ emptyEditor: options.emptyEditorClass,
64699
+ emptyNode: resolveEmptyNodeClass(options.emptyNodeClass, {
64700
+ editor,
64701
+ node,
64702
+ pos,
64703
+ hasAnchor
64704
+ })
64705
+ },
64706
+ node,
64707
+ pos
64708
+ })
64709
+ );
64710
+ }
64711
+ return options.includeChildren;
64712
+ });
64713
+ }
64714
+ return DecorationSet.create(doc, decorations);
64715
+ }
64716
+
64717
+ // src/placeholder/utils/preparePlaceholderAttribute.ts
64718
+ function preparePlaceholderAttribute(attr) {
64719
+ return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
64720
+ }
64721
+
64237
64722
  // src/placeholder/utils/findScrollParent.ts
64238
64723
  function isScrollable(el) {
64239
64724
  const style = getComputedStyle(el);
@@ -64274,8 +64759,8 @@ ${indentedChild}`;
64274
64759
  }) {
64275
64760
  const editorRect = view.dom.getBoundingClientRect();
64276
64761
  const containerRect = scrollContainer ? getContainerRect(scrollContainer) : { top: 0, bottom: window.innerHeight };
64277
- const visibleTop = Math.max(editorRect.top, containerRect.top);
64278
- const visibleBottom = Math.min(editorRect.bottom, containerRect.bottom);
64762
+ const visibleTop = Math.max(editorRect.top, containerRect.top) - VIEWPORT_OVERSCAN_PX;
64763
+ const visibleBottom = Math.min(editorRect.bottom, containerRect.bottom) + VIEWPORT_OVERSCAN_PX;
64279
64764
  if (visibleTop >= visibleBottom) {
64280
64765
  return { top: 0, bottom: doc.content.size };
64281
64766
  }
@@ -64289,33 +64774,97 @@ ${indentedChild}`;
64289
64774
  };
64290
64775
  }
64291
64776
 
64292
- // src/placeholder/utils/throttle.ts
64293
- function throttle(fn, delay) {
64294
- let timer = null;
64295
- const call = ((...args) => {
64296
- if (timer) {
64777
+ // src/placeholder/utils/viewportTracking.ts
64778
+ var viewportPluginState = {
64779
+ /**
64780
+ * Initialises the viewport state with no known positions.
64781
+ * @returns The initial viewport state.
64782
+ */
64783
+ init() {
64784
+ return { topPos: null, bottomPos: null };
64785
+ },
64786
+ /**
64787
+ * Updates the viewport state from incoming transactions.
64788
+ * @param tr - The transaction being applied.
64789
+ * @param prev - The previous viewport state.
64790
+ * @returns The next viewport state.
64791
+ */
64792
+ apply(tr, prev) {
64793
+ const meta = tr.getMeta(PLUGIN_KEY);
64794
+ if (meta == null ? void 0 : meta.positions) {
64795
+ return { topPos: meta.positions.top, bottomPos: meta.positions.bottom };
64796
+ }
64797
+ if (!tr.docChanged) {
64798
+ return prev;
64799
+ }
64800
+ return {
64801
+ topPos: prev.topPos !== null ? tr.mapping.map(prev.topPos) : null,
64802
+ bottomPos: prev.bottomPos !== null ? tr.mapping.map(prev.bottomPos) : null
64803
+ };
64804
+ }
64805
+ };
64806
+ function createViewportPluginView(view) {
64807
+ const scrollContainer = findScrollParent(view.dom);
64808
+ const computeAndDispatch = () => {
64809
+ const positions = getViewportBoundaryPositions({
64810
+ view,
64811
+ doc: view.state.doc,
64812
+ scrollContainer
64813
+ });
64814
+ const prev = PLUGIN_KEY.getState(view.state);
64815
+ if ((prev == null ? void 0 : prev.topPos) === positions.top && (prev == null ? void 0 : prev.bottomPos) === positions.bottom) {
64297
64816
  return;
64298
64817
  }
64299
- fn(...args);
64300
- timer = setTimeout(() => {
64301
- timer = null;
64302
- }, delay);
64303
- });
64304
- const cancel = () => {
64305
- if (timer) {
64306
- clearTimeout(timer);
64307
- timer = null;
64818
+ const tr = view.state.tr.setMeta(PLUGIN_KEY, { positions });
64819
+ view.dispatch(tr);
64820
+ };
64821
+ let frame = null;
64822
+ let lastCompute = 0;
64823
+ const MIN_SCROLL_INTERVAL = 150;
64824
+ const scheduleFrame = () => {
64825
+ if (frame !== null) return;
64826
+ frame = requestAnimationFrame(() => {
64827
+ frame = null;
64828
+ const now = performance.now();
64829
+ if (now - lastCompute >= MIN_SCROLL_INTERVAL) {
64830
+ lastCompute = now;
64831
+ computeAndDispatch();
64832
+ } else {
64833
+ scheduleFrame();
64834
+ }
64835
+ });
64836
+ };
64837
+ scrollContainer.addEventListener("scroll", scheduleFrame, { passive: true });
64838
+ computeAndDispatch();
64839
+ return {
64840
+ update(_view, prevState) {
64841
+ if (view.state.doc.content.size !== prevState.doc.content.size) {
64842
+ scheduleFrame();
64843
+ }
64844
+ },
64845
+ destroy: () => {
64846
+ if (frame !== null) {
64847
+ cancelAnimationFrame(frame);
64848
+ }
64849
+ scrollContainer.removeEventListener("scroll", scheduleFrame);
64308
64850
  }
64309
64851
  };
64310
- return { call, cancel };
64311
64852
  }
64312
64853
 
64313
- // src/placeholder/placeholder.ts
64314
- var DEFAULT_DATA_ATTRIBUTE = "placeholder";
64315
- function preparePlaceholderAttribute(attr) {
64316
- return attr.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").replace(/^[0-9-]+/, "").replace(/^-+/, "").toLowerCase();
64854
+ // src/placeholder/plugins/PlaceholderPlugin.ts
64855
+ function createPlaceholderPlugin({ editor, options }) {
64856
+ const dataAttribute = options.dataAttribute ? `data-${preparePlaceholderAttribute(options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
64857
+ return new Plugin({
64858
+ key: PLUGIN_KEY,
64859
+ state: viewportPluginState,
64860
+ view: createViewportPluginView,
64861
+ props: {
64862
+ decorations: ({ doc, selection }) => buildPlaceholderDecorations({ editor, options, dataAttribute, doc, selection })
64863
+ }
64864
+ });
64317
64865
  }
64318
- var PLUGIN_KEY = new PluginKey("tiptap__placeholder");
64866
+
64867
+ // src/placeholder/placeholder.ts
64319
64868
  var Placeholder = Extension.create({
64320
64869
  name: "placeholder",
64321
64870
  addOptions() {
@@ -64330,134 +64879,16 @@ ${indentedChild}`;
64330
64879
  };
64331
64880
  },
64332
64881
  addProseMirrorPlugins() {
64333
- const dataAttribute = this.options.dataAttribute ? `data-${preparePlaceholderAttribute(this.options.dataAttribute)}` : `data-${DEFAULT_DATA_ATTRIBUTE}`;
64334
- return [
64335
- new Plugin({
64336
- state: {
64337
- init() {
64338
- return {
64339
- // null means "no viewport info yet" — decoration callback falls
64340
- // back to full document scan until the scroll handler fires.
64341
- topPos: null,
64342
- bottomPos: null
64343
- };
64344
- },
64345
- apply(tr, prev) {
64346
- const meta = tr.getMeta(PLUGIN_KEY);
64347
- if (meta == null ? void 0 : meta.positions) {
64348
- return {
64349
- topPos: meta.positions.top,
64350
- bottomPos: meta.positions.bottom
64351
- };
64352
- }
64353
- if (!tr.docChanged) {
64354
- return prev;
64355
- }
64356
- return {
64357
- topPos: prev.topPos !== null ? tr.mapping.map(prev.topPos) : null,
64358
- bottomPos: prev.bottomPos !== null ? tr.mapping.map(prev.bottomPos) : null
64359
- };
64360
- }
64361
- },
64362
- key: PLUGIN_KEY,
64363
- view(view) {
64364
- const scrollContainer = findScrollParent(view.dom);
64365
- const computeAndDispatch = () => {
64366
- const positions = getViewportBoundaryPositions({
64367
- view,
64368
- doc: view.state.doc,
64369
- scrollContainer
64370
- });
64371
- const prev = PLUGIN_KEY.getState(view.state);
64372
- if (prev.topPos === positions.top && prev.bottomPos === positions.bottom) {
64373
- return;
64374
- }
64375
- const tr = view.state.tr.setMeta(PLUGIN_KEY, { positions }).setMeta("tiptap__viewportUpdate", true);
64376
- view.dispatch(tr);
64377
- };
64378
- const { call: throttledUpdate, cancel: cancelThrottle } = throttle(computeAndDispatch, 250);
64379
- const scrollParent = scrollContainer;
64380
- scrollParent.addEventListener("scroll", throttledUpdate, { passive: true });
64381
- computeAndDispatch();
64382
- return {
64383
- update(_, prevState) {
64384
- if (view.state.doc.content.size !== prevState.doc.content.size) {
64385
- computeAndDispatch();
64386
- }
64387
- },
64388
- destroy: () => {
64389
- cancelThrottle();
64390
- scrollParent.removeEventListener("scroll", throttledUpdate);
64391
- }
64392
- };
64393
- },
64394
- props: {
64395
- decorations: ({ doc, selection }) => {
64396
- var _a, _b;
64397
- const active = this.editor.isEditable || !this.options.showOnlyWhenEditable;
64398
- if (!active) {
64399
- return null;
64400
- }
64401
- const { anchor } = selection;
64402
- const decorations = [];
64403
- const isEmptyDoc = this.editor.isEmpty;
64404
- const useResolvedPath = this.options.showOnlyCurrent && !this.options.includeChildren;
64405
- if (useResolvedPath) {
64406
- const resolved = doc.resolve(anchor);
64407
- if (resolved.depth > 0) {
64408
- const node = resolved.node(1);
64409
- const nodeStart = resolved.before(1);
64410
- if (node.type.isTextblock && isNodeEmpty(node)) {
64411
- const hasAnchor = anchor >= nodeStart && anchor <= nodeStart + node.nodeSize;
64412
- const decoration = createPlaceholderDecoration({
64413
- node,
64414
- dataAttribute,
64415
- hasAnchor,
64416
- placeholder: this.options.placeholder,
64417
- classes: {
64418
- emptyEditor: this.options.emptyEditorClass,
64419
- emptyNode: this.options.emptyNodeClass
64420
- },
64421
- editor: this.editor,
64422
- isEmptyDoc,
64423
- pos: resolved.before(1)
64424
- });
64425
- decorations.push(decoration);
64426
- }
64427
- }
64428
- } else {
64429
- const pluginState = PLUGIN_KEY.getState(this.editor.state);
64430
- const from = (_a = pluginState.topPos) != null ? _a : 0;
64431
- const to = (_b = pluginState.bottomPos) != null ? _b : doc.content.size;
64432
- doc.nodesBetween(from, to, (node, pos) => {
64433
- const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
64434
- const isEmpty = !node.isLeaf && isNodeEmpty(node);
64435
- if (!node.type.isTextblock) {
64436
- return this.options.includeChildren;
64437
- }
64438
- if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
64439
- const decoration = createPlaceholderDecoration({
64440
- classes: { emptyEditor: this.options.emptyEditorClass, emptyNode: this.options.emptyNodeClass },
64441
- editor: this.editor,
64442
- isEmptyDoc,
64443
- dataAttribute,
64444
- hasAnchor,
64445
- placeholder: this.options.placeholder,
64446
- node,
64447
- pos
64448
- });
64449
- decorations.push(decoration);
64450
- }
64451
- return this.options.includeChildren;
64452
- });
64453
- }
64454
- return DecorationSet.create(doc, decorations);
64455
- }
64456
- }
64457
- })
64458
- ];
64882
+ return [createPlaceholderPlugin({ editor: this.editor, options: this.options })];
64459
64883
  }
64460
64884
  });
64885
+ var selectionStyle = `.ProseMirror:not(.ProseMirror-focused) *::selection {
64886
+ background: transparent;
64887
+ }
64888
+
64889
+ .ProseMirror:not(.ProseMirror-focused) *::-moz-selection {
64890
+ background: transparent;
64891
+ }`;
64461
64892
  Extension.create({
64462
64893
  name: "selection",
64463
64894
  addOptions() {
@@ -64467,6 +64898,9 @@ ${indentedChild}`;
64467
64898
  },
64468
64899
  addProseMirrorPlugins() {
64469
64900
  const { editor, options } = this;
64901
+ if (editor.options.injectCSS && typeof document !== "undefined") {
64902
+ createStyleTag(selectionStyle, editor.options.injectNonce, "selection");
64903
+ }
64470
64904
  return [
64471
64905
  new Plugin({
64472
64906
  key: new PluginKey("selection"),
@@ -64487,7 +64921,10 @@ ${indentedChild}`;
64487
64921
  }
64488
64922
  });
64489
64923
  var skipTrailingNodeMeta = "skipTrailingNode";
64490
- function nodeEqualsType({ types, node }) {
64924
+ function nodeEqualsType({
64925
+ types,
64926
+ node
64927
+ }) {
64491
64928
  return node && Array.isArray(types) && types.includes(node.type) || (node == null ? void 0 : node.type) === types;
64492
64929
  }
64493
64930
  Extension.create({
@@ -64672,7 +65109,7 @@ ${indentedChild}`;
64672
65109
  rel: 'noopener noreferrer',
64673
65110
  target: null,
64674
65111
  // Adding `class` here is a workaround to render two mentions without a whitespace as display names
64675
- // This attribute can be removed when the below issue is resolved
65112
+ // For more details on this behavior, refer to the issue below:
64676
65113
  // https://github.com/ni/nimble/issues/1707
64677
65114
  class: ''
64678
65115
  },
@@ -71146,6 +71583,12 @@ ${indentedChild}`;
71146
71583
  canLoadChildren: 'can-load-children',
71147
71584
  loadingChildren: 'loading-children'
71148
71585
  };
71586
+ /**
71587
+ * The possible pin locations for a table column.
71588
+ */
71589
+ const TableColumnPinLocation = {
71590
+ left: 'left'
71591
+ };
71149
71592
  /**
71150
71593
  * The possible directions a table column can be sorted in.
71151
71594
  */
@@ -71486,6 +71929,9 @@ ${indentedChild}`;
71486
71929
  __decorate([
71487
71930
  observable
71488
71931
  ], ColumnInternals.prototype, "currentSortDirection", void 0);
71932
+ __decorate([
71933
+ observable
71934
+ ], ColumnInternals.prototype, "pinLocation", void 0);
71489
71935
  function isColumnInternalsProperty(changedProperty, ...args) {
71490
71936
  for (const arg of args) {
71491
71937
  if (changedProperty === arg) {
@@ -71559,6 +72005,7 @@ ${indentedChild}`;
71559
72005
  this.idFieldNameNotConfigured = false;
71560
72006
  this.invalidColumnConfiguration = false;
71561
72007
  this.invalidParentIdConfiguration = false;
72008
+ this.invalidPinnedColumnConfiguration = false;
71562
72009
  this.recordIds = new Set();
71563
72010
  }
71564
72011
  getValidity() {
@@ -71572,7 +72019,8 @@ ${indentedChild}`;
71572
72019
  duplicateGroupIndex: this.duplicateGroupIndex,
71573
72020
  idFieldNameNotConfigured: this.idFieldNameNotConfigured,
71574
72021
  invalidColumnConfiguration: this.invalidColumnConfiguration,
71575
- invalidParentIdConfiguration: this.invalidParentIdConfiguration
72022
+ invalidParentIdConfiguration: this.invalidParentIdConfiguration,
72023
+ invalidPinnedColumnConfiguration: this.invalidPinnedColumnConfiguration
71576
72024
  };
71577
72025
  }
71578
72026
  isValid() {
@@ -71655,6 +72103,12 @@ ${indentedChild}`;
71655
72103
  this.invalidColumnConfiguration = columns.some(x => !x.columnInternals.validator.isColumnValid);
71656
72104
  return !this.invalidColumnConfiguration;
71657
72105
  }
72106
+ validatePinnedColumnConfigurations(columns) {
72107
+ this.invalidPinnedColumnConfiguration = columns.some(x => x.columnInternals.pinLocation === TableColumnPinLocation.left
72108
+ && (x.columnInternals.pixelWidth === undefined
72109
+ || !x.columnInternals.resizingDisabled));
72110
+ return !this.invalidPinnedColumnConfiguration;
72111
+ }
71658
72112
  getPresentRecordIds(requestedRecordIds) {
71659
72113
  return requestedRecordIds.filter(id => this.recordIds.has(id));
71660
72114
  }
@@ -71714,12 +72168,7 @@ focus outline in that case.
71714
72168
  .header-row-container {
71715
72169
  position: sticky;
71716
72170
  top: 0;
71717
- }
71718
-
71719
- .header-row {
71720
72171
  display: flex;
71721
- background: ${applicationBackgroundColor};
71722
- position: relative;
71723
72172
  width: fit-content;
71724
72173
  min-width: max(
71725
72174
  100%,
@@ -71728,8 +72177,16 @@ focus outline in that case.
71728
72177
  var(--ni-private-table-header-container-margin-right)
71729
72178
  )
71730
72179
  );
72180
+ }
72181
+
72182
+ .header-row {
72183
+ display: flex;
72184
+ background: ${applicationBackgroundColor};
72185
+ position: relative;
72186
+ width: fit-content;
71731
72187
  left: var(--ni-private-table-scroll-x);
71732
72188
  align-items: center;
72189
+ flex: 1;
71733
72190
  }
71734
72191
 
71735
72192
  .header-row-action-container {
@@ -71781,6 +72238,17 @@ focus outline in that case.
71781
72238
  overflow: hidden;
71782
72239
  }
71783
72240
 
72241
+ .pinned-columns-header-container {
72242
+ display: grid;
72243
+ grid-template-columns: var(--ni-private-table-pinned-columns-row-grid-columns);
72244
+ position: sticky;
72245
+ left: 0;
72246
+ align-self: stretch;
72247
+ background: ${applicationBackgroundColor};
72248
+ z-index: ${ZIndexLevels.zIndex1};
72249
+ box-shadow: inset -2px 0 0 0 ${tableRowBorderColor};
72250
+ }
72251
+
71784
72252
  .column-divider {
71785
72253
  border-left: var(--ni-private-column-divider-width) solid
71786
72254
  ${popupBorderColor};
@@ -71881,6 +72349,10 @@ focus outline in that case.
71881
72349
  ${accessiblyHidden}
71882
72350
  }
71883
72351
  `.withBehaviors(themeBehavior(Theme.color, css `
72352
+ .pinned-columns-header-container {
72353
+ box-shadow: inset -2px 0 0 0 ${hexToRgbaCssColor(White, 0.1)};
72354
+ }
72355
+
71884
72356
  .table-row-container::before {
71885
72357
  content: '';
71886
72358
  width: 100%;
@@ -72062,7 +72534,7 @@ focus outline in that case.
72062
72534
  position: absolute;
72063
72535
  }
72064
72536
 
72065
- :host([selectable]:not([selected])[allow-hover]:hover)::before {
72537
+ :host([selectable][allow-hover]:hover)::before {
72066
72538
  background-color: ${fillHoverColor};
72067
72539
  }
72068
72540
 
@@ -72135,6 +72607,46 @@ focus outline in that case.
72135
72607
  width: ${mediumPadding};
72136
72608
  }
72137
72609
 
72610
+ .pinned-cell-container {
72611
+ display: grid;
72612
+ grid-template-columns: var(--ni-private-table-pinned-columns-row-grid-columns);
72613
+ position: sticky;
72614
+ left: 0;
72615
+ background: ${applicationBackgroundColor};
72616
+ z-index: ${ZIndexLevels.zIndex1};
72617
+ box-shadow: inset -2px 0 0 0 ${tableRowBorderColor};
72618
+ }
72619
+
72620
+ :host([selectable][allow-hover]:hover) .pinned-cell-container {
72621
+ background: linear-gradient(${fillHoverColor}, ${fillHoverColor}),
72622
+ ${applicationBackgroundColor};
72623
+ }
72624
+
72625
+ :host([selected]) .pinned-cell-container {
72626
+ background: linear-gradient(${fillSelectedColor}, ${fillSelectedColor}),
72627
+ ${applicationBackgroundColor};
72628
+ }
72629
+
72630
+ :host([selected][allow-hover]:hover) .pinned-cell-container {
72631
+ background: linear-gradient(
72632
+ ${fillHoverSelectedColor},
72633
+ ${fillHoverSelectedColor}
72634
+ ),
72635
+ ${applicationBackgroundColor};
72636
+ }
72637
+
72638
+ :host(${focusVisible}) .pinned-cell-container {
72639
+ box-shadow:
72640
+ inset calc(2 * ${borderWidth}) 0 0 ${borderHoverColor},
72641
+ inset 0 calc(2 * ${borderWidth}) 0 ${borderHoverColor},
72642
+ inset 0 calc(-2 * ${borderWidth}) 0 ${borderHoverColor},
72643
+ inset -2px 0 0 0 ${tableRowBorderColor};
72644
+ }
72645
+ ${'' /* Pushing the pinned-cell-container to a higher z-index for breakpoint menu behavior (not required by table directly) */}
72646
+ :host([menu-open]) .pinned-cell-container {
72647
+ z-index: ${ZIndexLevels.zIndex1000};
72648
+ }
72649
+
72138
72650
  .cell-container {
72139
72651
  display: grid;
72140
72652
  width: 100%;
@@ -72210,6 +72722,42 @@ focus outline in that case.
72210
72722
  :host([selected][allow-hover]:hover)::before {
72211
72723
  background-color: ${hexToRgbaCssColor(White, 0.2)};
72212
72724
  }
72725
+
72726
+ .pinned-cell-container {
72727
+ box-shadow: inset -2px 0 0 0 ${hexToRgbaCssColor(White, 0.1)};
72728
+ }
72729
+
72730
+ :host([selectable][allow-hover]:hover) .pinned-cell-container {
72731
+ background: linear-gradient(
72732
+ ${hexToRgbaCssColor(White, 0.05)},
72733
+ ${hexToRgbaCssColor(White, 0.05)}
72734
+ ),
72735
+ ${applicationBackgroundColor};
72736
+ }
72737
+
72738
+ :host([selected]) .pinned-cell-container {
72739
+ background: linear-gradient(
72740
+ ${hexToRgbaCssColor(White, 0.25)},
72741
+ ${hexToRgbaCssColor(White, 0.25)}
72742
+ ),
72743
+ ${applicationBackgroundColor};
72744
+ }
72745
+
72746
+ :host([selected][allow-hover]:hover) .pinned-cell-container {
72747
+ background: linear-gradient(
72748
+ ${hexToRgbaCssColor(White, 0.2)},
72749
+ ${hexToRgbaCssColor(White, 0.2)}
72750
+ ),
72751
+ ${applicationBackgroundColor};
72752
+ }
72753
+
72754
+ :host(${focusVisible}) .pinned-cell-container {
72755
+ box-shadow:
72756
+ inset calc(2 * ${borderWidth}) 0 0 ${borderHoverColor},
72757
+ inset 0 calc(2 * ${borderWidth}) 0 ${borderHoverColor},
72758
+ inset 0 calc(-2 * ${borderWidth}) 0 ${borderHoverColor},
72759
+ inset -2px 0 0 0 ${hexToRgbaCssColor(White, 0.1)};
72760
+ }
72213
72761
  `));
72214
72762
 
72215
72763
  const styles$y = css `
@@ -72360,6 +72908,37 @@ focus outline in that case.
72360
72908
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleTableCell());
72361
72909
  const tableCellTag = 'nimble-table-cell';
72362
72910
 
72911
+ const rowCellTemplate = html `
72912
+ <${tableCellTag}
72913
+ class="cell"
72914
+ :cellState="${(_, c) => c.parent.cellStates[c.index]}"
72915
+ :cellViewTemplate="${x => x.columnInternals.cellViewTemplate}"
72916
+ :column="${x => x}"
72917
+ column-id="${x => x.columnId}"
72918
+ :recordId="${(_, c) => c.parent.recordId}"
72919
+ ?has-action-menu="${x => !!x.actionMenuSlot}"
72920
+ action-menu-label="${x => x.actionMenuLabel}"
72921
+ @cell-action-menu-beforetoggle="${(x, c) => c.parent.onCellActionMenuBeforeToggle(c.event, x)}"
72922
+ @cell-action-menu-toggle="${(x, c) => c.parent.onCellActionMenuToggle(c.event, x)}"
72923
+ @cell-view-slots-request="${(x, c) => c.parent.onCellViewSlotsRequest(x, c.event)}"
72924
+ :nestingLevel="${(_, c) => c.parent.cellIndentLevels[c.index]}"
72925
+ >
72926
+
72927
+ ${when((x, c) => (c.parent.currentActionMenuColumn === x) && x.actionMenuSlot, html `
72928
+ <slot
72929
+ name="${x => `row-action-menu-${x.actionMenuSlot}`}"
72930
+ slot="cellActionMenu"
72931
+ ></slot>
72932
+ `)}
72933
+
72934
+ ${repeat(x => x.columnInternals.slotNames, html `
72935
+ <slot
72936
+ name="${(x, c) => uniquifySlotNameForColumn(c.parent, x)}"
72937
+ slot="${(x, c) => uniquifySlotNameForColumn(c.parent, x)}"
72938
+ ></slot>
72939
+ `)}
72940
+ </${tableCellTag}>
72941
+ `;
72363
72942
  const template$z = html `
72364
72943
  <template
72365
72944
  role="row"
@@ -72367,6 +72946,14 @@ focus outline in that case.
72367
72946
  aria-expanded=${x => x.expanded}
72368
72947
  style="--ni-private-table-row-indent-level: ${x => x.nestingLevel};"
72369
72948
  >
72949
+ <span class="pinned-cell-container">
72950
+ ${repeat(x => x.columns, html `
72951
+ ${when(x => !x.columnHidden && x.columnInternals.pinLocation === TableColumnPinLocation.left, html `
72952
+ ${rowCellTemplate}
72953
+ `)}
72954
+ `, { recycle: false, positioning: true })}
72955
+ </span>
72956
+
72370
72957
  ${when(x => !x.rowOperationGridCellHidden, html `
72371
72958
  <span role="gridcell" class="row-operations-container">
72372
72959
  ${when(x => x.showSelectionCheckbox, html `
@@ -72384,7 +72971,7 @@ focus outline in that case.
72384
72971
  `)}
72385
72972
  </span>
72386
72973
  `)}
72387
- <span class="row-front-spacer ${x => (x.isTopLevelParentRow || !x.reserveCollapseSpace ? 'reduced-size-spacer' : '')}"></span>
72974
+ <span class="row-front-spacer ${x => (x.isTopLevelParentRow || !x.reserveCollapseSpace ? 'reduced-size-spacer' : '')} ${x => (x.showSelectionCheckbox ? 'selectable' : '')}"></span>
72388
72975
  ${when(x => x.isParentRow, html `
72389
72976
  ${when(x => x.loading, html `
72390
72977
  <span class="spinner-container">
@@ -72415,36 +73002,8 @@ focus outline in that case.
72415
73002
  class="cell-container ${x => (x.isNestedParent ? 'nested-parent' : '')}"
72416
73003
  >
72417
73004
  ${repeat(x => x.columns, html `
72418
- ${when(x => !x.columnHidden, html `
72419
- <${tableCellTag}
72420
- class="cell"
72421
- :cellState="${(_, c) => c.parent.cellStates[c.index]}"
72422
- :cellViewTemplate="${x => x.columnInternals.cellViewTemplate}"
72423
- :column="${x => x}"
72424
- column-id="${x => x.columnId}"
72425
- :recordId="${(_, c) => c.parent.recordId}"
72426
- ?has-action-menu="${x => !!x.actionMenuSlot}"
72427
- action-menu-label="${x => x.actionMenuLabel}"
72428
- @cell-action-menu-beforetoggle="${(x, c) => c.parent.onCellActionMenuBeforeToggle(c.event, x)}"
72429
- @cell-action-menu-toggle="${(x, c) => c.parent.onCellActionMenuToggle(c.event, x)}"
72430
- @cell-view-slots-request="${(x, c) => c.parent.onCellViewSlotsRequest(x, c.event)}"
72431
- :nestingLevel="${(_, c) => c.parent.cellIndentLevels[c.index]}"
72432
- >
72433
-
72434
- ${when((x, c) => (c.parent.currentActionMenuColumn === x) && x.actionMenuSlot, html `
72435
- <slot
72436
- name="${x => `row-action-menu-${x.actionMenuSlot}`}"
72437
- slot="cellActionMenu"
72438
- ></slot>
72439
- `)}
72440
-
72441
- ${repeat(x => x.columnInternals.slotNames, html `
72442
- <slot
72443
- name="${(x, c) => uniquifySlotNameForColumn(c.parent, x)}"
72444
- slot="${(x, c) => uniquifySlotNameForColumn(c.parent, x)}"
72445
- ></slot>
72446
- `)}
72447
- </${tableCellTag}>
73005
+ ${when(x => !x.columnHidden && x.columnInternals.pinLocation !== TableColumnPinLocation.left, html `
73006
+ ${rowCellTemplate}
72448
73007
  `)}
72449
73008
  `, { recycle: false, positioning: true })}
72450
73009
  </span>
@@ -72627,8 +73186,9 @@ focus outline in that case.
72627
73186
  this.updateCellIndentLevels();
72628
73187
  }
72629
73188
  updateCellIndentLevels() {
73189
+ const firstNonPinnedIndex = this.columns.findIndex(col => col.columnInternals.pinLocation !== TableColumnPinLocation.left);
72630
73190
  this.cellIndentLevels = this.columns.map((_, i) => {
72631
- return i === 0 ? this.nestingLevel : 0;
73191
+ return i === firstNonPinnedIndex ? this.nestingLevel : 0;
72632
73192
  });
72633
73193
  }
72634
73194
  removeColumnObservers() {
@@ -72770,6 +73330,7 @@ focus outline in that case.
72770
73330
  height: calc(${controlHeight} + 2 * ${borderWidth});
72771
73331
  border-top: calc(2 * ${borderWidth}) solid ${applicationBackgroundColor};
72772
73332
  grid-template-columns:
73333
+ calc(var(--ni-private-table-group-row-pinned-column-offset))
72773
73334
  calc(
72774
73335
  ${controlHeight} *
72775
73336
  (var(--ni-private-table-group-row-indent-level) + 1)
@@ -72779,6 +73340,7 @@ focus outline in that case.
72779
73340
 
72780
73341
  :host([selectable]) {
72781
73342
  grid-template-columns:
73343
+ calc(var(--ni-private-table-group-row-pinned-column-offset))
72782
73344
  ${controlHeight}
72783
73345
  calc(
72784
73346
  ${controlHeight} *
@@ -72805,6 +73367,37 @@ focus outline in that case.
72805
73367
  outline-offset: calc(-2 * ${borderWidth});
72806
73368
  }
72807
73369
 
73370
+ :host([has-pinned-columns]) .pinned-column-spacer {
73371
+ display: block;
73372
+ height: 100%;
73373
+ position: sticky;
73374
+ left: 0;
73375
+ background: ${tableRowBorderColor};
73376
+ z-index: ${ZIndexLevels.zIndex1};
73377
+ }
73378
+
73379
+ :host([allow-hover][has-pinned-columns]:hover) .pinned-column-spacer {
73380
+ background: linear-gradient(${fillHoverColor}, ${fillHoverColor}),
73381
+ ${tableRowBorderColor};
73382
+ }
73383
+
73384
+ :host([has-pinned-columns]${focusVisible}) .pinned-column-spacer {
73385
+ box-shadow: inset 2px -2px 0 ${borderHoverColor};
73386
+ }
73387
+
73388
+ .checkbox-container {
73389
+ display: flex;
73390
+ }
73391
+
73392
+ :host([has-pinned-columns]) .checkbox-container {
73393
+ position: relative;
73394
+ }
73395
+
73396
+ :host([allow-hover][has-pinned-columns]:hover) .checkbox-container {
73397
+ background: linear-gradient(${fillHoverColor}, ${fillHoverColor}),
73398
+ ${tableRowBorderColor};
73399
+ }
73400
+
72808
73401
  .expand-collapse-button {
72809
73402
  margin-left: calc(
72810
73403
  ${mediumPadding} + ${standardPadding} * 2 *
@@ -72830,10 +73423,6 @@ focus outline in that case.
72830
73423
  ${userSelectNone}
72831
73424
  }
72832
73425
 
72833
- .checkbox-container {
72834
- display: flex;
72835
- }
72836
-
72837
73426
  .selection-checkbox {
72838
73427
  margin-left: ${standardPadding};
72839
73428
  }
@@ -72845,10 +73434,66 @@ focus outline in that case.
72845
73434
  :host([allow-hover]:hover)::before {
72846
73435
  background-color: ${hexToRgbaCssColor(White, 0.05)};
72847
73436
  }
73437
+
73438
+ :host([has-pinned-columns]) .pinned-column-spacer {
73439
+ background: linear-gradient(
73440
+ ${hexToRgbaCssColor(White, 0.1)},
73441
+ ${hexToRgbaCssColor(White, 0.1)}
73442
+ ),
73443
+ ${tableRowBorderColor};
73444
+ }
73445
+
73446
+ :host([allow-hover][has-pinned-columns]:hover) .pinned-column-spacer {
73447
+ background: linear-gradient(
73448
+ ${hexToRgbaCssColor(White, 0.05)},
73449
+ ${hexToRgbaCssColor(White, 0.05)}
73450
+ ),
73451
+ linear-gradient(
73452
+ ${hexToRgbaCssColor(White, 0.1)},
73453
+ ${hexToRgbaCssColor(White, 0.1)}
73454
+ ),
73455
+ ${tableRowBorderColor};
73456
+ }
73457
+
73458
+ :host([has-pinned-columns]) .checkbox-container {
73459
+ background: linear-gradient(
73460
+ ${hexToRgbaCssColor(White, 0.1)},
73461
+ ${hexToRgbaCssColor(White, 0.1)}
73462
+ ),
73463
+ ${tableRowBorderColor};
73464
+ }
73465
+
73466
+ :host([allow-hover][has-pinned-columns]:hover) .checkbox-container {
73467
+ background: linear-gradient(
73468
+ ${hexToRgbaCssColor(White, 0.05)},
73469
+ ${hexToRgbaCssColor(White, 0.05)}
73470
+ ),
73471
+ linear-gradient(
73472
+ ${hexToRgbaCssColor(White, 0.1)},
73473
+ ${hexToRgbaCssColor(White, 0.1)}
73474
+ ),
73475
+ ${tableRowBorderColor};
73476
+ }
72848
73477
  `), themeBehavior(Theme.dark, css `
72849
73478
  :host([allow-hover]:hover)::before {
72850
73479
  background-color: ${hexToRgbaCssColor(White, 0.1)};
72851
73480
  }
73481
+
73482
+ :host([allow-hover][has-pinned-columns]:hover) .pinned-column-spacer {
73483
+ background: linear-gradient(
73484
+ ${hexToRgbaCssColor(White, 0.1)},
73485
+ ${hexToRgbaCssColor(White, 0.1)}
73486
+ ),
73487
+ ${tableRowBorderColor};
73488
+ }
73489
+
73490
+ :host([allow-hover][has-pinned-columns]:hover) .checkbox-container {
73491
+ background: linear-gradient(
73492
+ ${hexToRgbaCssColor(White, 0.1)},
73493
+ ${hexToRgbaCssColor(White, 0.1)}
73494
+ ),
73495
+ ${tableRowBorderColor};
73496
+ }
72852
73497
  `));
72853
73498
 
72854
73499
  const template$y = html `
@@ -72856,8 +73501,13 @@ focus outline in that case.
72856
73501
  role="row"
72857
73502
  @click=${x => x.onGroupExpandToggle()}
72858
73503
  aria-expanded=${x => x.expanded}
72859
- style="--ni-private-table-group-row-indent-level: ${x => x.nestingLevel};"
73504
+ style="
73505
+ --ni-private-table-group-row-indent-level: ${x => x.nestingLevel};
73506
+ --ni-private-table-group-row-pinned-column-offset: ${x => x.pinnedColumnOffset}px;
73507
+ "
72860
73508
  >
73509
+ <span class="pinned-column-spacer"></span>
73510
+
72861
73511
  ${when(x => x.selectable, html `
72862
73512
  <span role="gridcell" class="checkbox-container">
72863
73513
  <${checkboxTag}
@@ -72900,6 +73550,11 @@ focus outline in that case.
72900
73550
  constructor() {
72901
73551
  super(...arguments);
72902
73552
  this.nestingLevel = 0;
73553
+ this.pinnedColumnOffset = 0;
73554
+ /**
73555
+ * @internal
73556
+ */
73557
+ this.hasPinnedColumns = false;
72903
73558
  this.expanded = false;
72904
73559
  this.selectable = false;
72905
73560
  this.selectionState = TableRowSelectionState.notSelected;
@@ -72957,6 +73612,9 @@ focus outline in that case.
72957
73612
  cells: []
72958
73613
  };
72959
73614
  }
73615
+ pinnedColumnOffsetChanged() {
73616
+ this.hasPinnedColumns = this.pinnedColumnOffset > 0;
73617
+ }
72960
73618
  selectionStateChanged() {
72961
73619
  this.setSelectionCheckboxState();
72962
73620
  }
@@ -72979,6 +73637,12 @@ focus outline in that case.
72979
73637
  __decorate([
72980
73638
  observable
72981
73639
  ], TableGroupRow.prototype, "nestingLevel", void 0);
73640
+ __decorate([
73641
+ observable
73642
+ ], TableGroupRow.prototype, "pinnedColumnOffset", void 0);
73643
+ __decorate([
73644
+ attr({ attribute: 'has-pinned-columns', mode: 'boolean' })
73645
+ ], TableGroupRow.prototype, "hasPinnedColumns", void 0);
72982
73646
  __decorate([
72983
73647
  observable
72984
73648
  ], TableGroupRow.prototype, "resolvedRowIndex", void 0);
@@ -73014,6 +73678,21 @@ focus outline in that case.
73014
73678
  DesignSystem.getOrCreate().withPrefix('nimble').register(nimbleTableGroupRow());
73015
73679
  const tableGroupRowTag = 'nimble-table-group-row';
73016
73680
 
73681
+ const tableHeaderTemplate = html `
73682
+ <${tableHeaderTag}
73683
+ class="header"
73684
+ ${'' /* tabindex managed dynamically by KeyboardNavigationManager (if column sorting not disabled) */}
73685
+ sort-direction="${x => (typeof x.columnInternals.currentSortIndex === 'number' ? x.columnInternals.currentSortDirection : TableColumnSortDirection.none)}"
73686
+ ?first-sorted-column="${(x, c) => x === c.parent.firstSortedColumn}"
73687
+ ?indicators-hidden="${x => x.columnInternals.hideHeaderIndicators}"
73688
+ @keydown="${(x, c) => c.parent.onHeaderKeyDown(x, c.event)}"
73689
+ @click="${(x, c) => c.parent.toggleColumnSort(x, c.event.shiftKey)}"
73690
+ :alignment="${x => x.columnInternals.headerAlignment}"
73691
+ :isGrouped="${x => (typeof x.columnInternals.groupIndex === 'number' && !x.columnInternals.groupingDisabled) || undefined}"
73692
+ >
73693
+ <slot name="${x => x.slot}"></slot>
73694
+ </${tableHeaderTag}>
73695
+ `;
73017
73696
  const template$x = html `
73018
73697
  <template
73019
73698
  role="treegrid"
@@ -73031,8 +73710,14 @@ focus outline in that case.
73031
73710
  --ni-private-table-row-grid-columns: ${x => (x.rowGridColumns ? x.rowGridColumns : '')};
73032
73711
  --ni-private-table-cursor-override: ${x => (x.layoutManager.isColumnBeingSized ? 'col-resize' : 'default')};
73033
73712
  --ni-private-table-scrollable-min-width: ${x => x.tableScrollableMinWidth}px;
73713
+ --ni-private-table-pinned-columns-row-grid-columns: ${x => x.pinnedColumnsGridTemplateColumns};
73034
73714
  ">
73035
73715
  <div role="rowgroup" class="header-row-container">
73716
+ <div class="pinned-columns-header-container">
73717
+ ${repeat(x => x.pinnedColumns, html `
73718
+ ${tableHeaderTemplate}
73719
+ `, { positioning: true })}
73720
+ </div>
73036
73721
  <div class="header-row" role="row">
73037
73722
  <span role="${x => (x.showRowOperationColumn ? 'columnheader' : '')}" class="header-row-action-container" ${ref('headerRowActionContainer')}>
73038
73723
  ${when(x => x.showRowOperationColumn, html `
@@ -73085,19 +73770,7 @@ focus outline in that case.
73085
73770
  @pointerdown="${(_, c) => c.parent.onLeftDividerPointerDown(c.event, c.index)}">
73086
73771
  </div>
73087
73772
  `)}
73088
- <${tableHeaderTag}
73089
- class="header"
73090
- ${'' /* tabindex managed dynamically by KeyboardNavigationManager (if column sorting not disabled) */}
73091
- sort-direction="${x => (typeof x.columnInternals.currentSortIndex === 'number' ? x.columnInternals.currentSortDirection : TableColumnSortDirection.none)}"
73092
- ?first-sorted-column="${(x, c) => x === c.parent.firstSortedColumn}"
73093
- ?indicators-hidden="${x => x.columnInternals.hideHeaderIndicators}"
73094
- @keydown="${(x, c) => c.parent.onHeaderKeyDown(x, c.event)}"
73095
- @click="${(x, c) => c.parent.toggleColumnSort(x, c.event.shiftKey)}"
73096
- :alignment="${x => x.columnInternals.headerAlignment}"
73097
- :isGrouped=${x => (typeof x.columnInternals.groupIndex === 'number' && !x.columnInternals.groupingDisabled)}
73098
- >
73099
- <slot name="${x => x.slot}"></slot>
73100
- </${tableHeaderTag}>
73773
+ ${tableHeaderTemplate}
73101
73774
  ${when((_, c) => c.index < c.length - 1, html `
73102
73775
  <div
73103
73776
  class="
@@ -73130,6 +73803,7 @@ focus outline in that case.
73130
73803
  :groupRowValue="${(x, c) => c.parent.tableData[x.index]?.groupRowValue}"
73131
73804
  ?expanded="${(x, c) => c.parent.tableData[x.index]?.isExpanded}"
73132
73805
  :nestingLevel="${(x, c) => c.parent.tableData[x.index]?.nestingLevel}"
73806
+ :pinnedColumnOffset="${(_, c) => c.parent.pinnedColumnOffset}"
73133
73807
  :immediateChildCount="${(x, c) => c.parent.tableData[x.index]?.immediateChildCount}"
73134
73808
  :groupColumn="${(x, c) => c.parent.tableData[x.index]?.groupColumn}"
73135
73809
  ?selectable="${(_, c) => c.parent.selectionMode === TableRowSelectionMode.multiple}"
@@ -73389,6 +74063,11 @@ focus outline in that case.
73389
74063
  return horizontal ? el.scrollLeft * (isRtl && -1 || 1) : el.scrollTop;
73390
74064
  });
73391
74065
  const measureElement = (element, entry, instance) => {
74066
+ if (instance.options.useCachedMeasurements) {
74067
+ const index = instance.indexFromElement(element);
74068
+ const key = instance.options.getItemKey(index);
74069
+ return instance.itemSizeCache.get(key) ?? instance.options.estimateSize(index);
74070
+ }
73392
74071
  if (entry == null ? void 0 : entry.borderBoxSize) {
73393
74072
  const box = entry.borderBoxSize[0];
73394
74073
  if (box) {
@@ -73398,6 +74077,14 @@ focus outline in that case.
73398
74077
  return size;
73399
74078
  }
73400
74079
  }
74080
+ if (!entry) {
74081
+ const index = instance.indexFromElement(element);
74082
+ const key = instance.options.getItemKey(index);
74083
+ const cachedSize = instance.itemSizeCache.get(key);
74084
+ if (cachedSize !== void 0) {
74085
+ return cachedSize;
74086
+ }
74087
+ }
73401
74088
  return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
73402
74089
  };
73403
74090
  const scrollWithAdjustments = (offset, {
@@ -73524,7 +74211,8 @@ focus outline in that case.
73524
74211
  isRtl: false,
73525
74212
  useScrollendEvent: false,
73526
74213
  useAnimationFrameWithResizeObserver: false,
73527
- laneAssignmentMode: "estimate"
74214
+ laneAssignmentMode: "estimate",
74215
+ useCachedMeasurements: false
73528
74216
  };
73529
74217
  for (const key in opts2) {
73530
74218
  const v = opts2[key];
@@ -73533,6 +74221,7 @@ focus outline in that case.
73533
74221
  const prevOptions = this.options;
73534
74222
  let anchor = null;
73535
74223
  let followOnAppend = null;
74224
+ let edgeKeysChanged = false;
73536
74225
  if (prevOptions !== void 0 && prevOptions.enabled && merged.enabled && merged.anchorTo === "end" && this.scrollElement !== null) {
73537
74226
  const prevCount = prevOptions.count;
73538
74227
  const nextCount = merged.count;
@@ -73542,6 +74231,7 @@ focus outline in that case.
73542
74231
  const didCountChange = nextCount !== prevCount;
73543
74232
  const didEdgeKeysChange = didCountChange || prevCount > 0 && nextCount > 0 && (merged.getItemKey(0) !== prevFirstKey || merged.getItemKey(nextCount - 1) !== prevLastKey);
73544
74233
  if (didEdgeKeysChange) {
74234
+ edgeKeysChanged = true;
73545
74235
  const item = prevCount > 0 ? this.getVirtualItemForOffset(this.getScrollOffset()) ?? measurements[0] : null;
73546
74236
  if (item) {
73547
74237
  anchor = [item.key, this.getScrollOffset() - item.start];
@@ -73553,11 +74243,38 @@ focus outline in that case.
73553
74243
  }
73554
74244
  }
73555
74245
  this.options = merged;
73556
- if (anchor || followOnAppend) {
74246
+ if (edgeKeysChanged) {
74247
+ this.pendingMin = 0;
74248
+ this.itemSizeCacheVersion++;
74249
+ }
74250
+ let anchorResolved = false;
74251
+ let anchorDelta = 0;
74252
+ if (anchor && this.scrollOffset !== null) {
74253
+ const [anchorKey, anchorOffset] = anchor;
74254
+ const newMeasurements = this.getMeasurements();
74255
+ const { count, getItemKey } = this.options;
74256
+ let idx = 0;
74257
+ while (idx < count && getItemKey(idx) !== anchorKey) {
74258
+ idx++;
74259
+ }
74260
+ if (idx < count) {
74261
+ const anchorItem = newMeasurements[idx];
74262
+ if (anchorItem) {
74263
+ const newOffset = anchorItem.start + anchorOffset;
74264
+ if (newOffset !== this.scrollOffset) {
74265
+ anchorDelta = newOffset - this.scrollOffset;
74266
+ this.scrollOffset = newOffset;
74267
+ anchorResolved = true;
74268
+ }
74269
+ }
74270
+ }
74271
+ }
74272
+ if (anchorResolved || followOnAppend) {
73557
74273
  this.pendingScrollAnchor = [
73558
- (anchor == null ? void 0 : anchor[0]) ?? null,
73559
- (anchor == null ? void 0 : anchor[1]) ?? 0,
73560
- followOnAppend
74274
+ anchorResolved ? anchor[0] : null,
74275
+ anchorResolved ? anchor[1] : 0,
74276
+ followOnAppend,
74277
+ anchorDelta
73561
74278
  ];
73562
74279
  }
73563
74280
  };
@@ -73694,19 +74411,17 @@ focus outline in that case.
73694
74411
  const anchor = this.pendingScrollAnchor;
73695
74412
  this.pendingScrollAnchor = null;
73696
74413
  if (anchor && this.scrollElement && this.options.enabled) {
73697
- const [key, offset, followOnAppend] = anchor;
73698
- if (key !== null) {
73699
- const { count, getItemKey } = this.options;
73700
- let index = 0;
73701
- while (index < count && getItemKey(index) !== key) {
73702
- index++;
73703
- }
73704
- const item = index < count ? this.getMeasurements()[index] : void 0;
73705
- if (item) {
73706
- const delta = item.start + offset - this.getScrollOffset();
73707
- if (!approxEqual(delta, 0)) {
73708
- this.applyScrollAdjustment(delta);
74414
+ const [key, _offset, followOnAppend, anchorDelta] = anchor;
74415
+ if (key !== null && !followOnAppend) {
74416
+ if (isIOSWebKit() && (this.isScrolling || this._iosTouching || this._iosJustTouchEnded)) {
74417
+ if (anchorDelta !== 0) {
74418
+ this._iosDeferredAdjustment += anchorDelta;
73709
74419
  }
74420
+ } else {
74421
+ this._scrollToOffset(this.getScrollOffset(), {
74422
+ adjustments: void 0,
74423
+ behavior: void 0
74424
+ });
73710
74425
  }
73711
74426
  }
73712
74427
  if (followOnAppend) {
@@ -74074,13 +74789,13 @@ focus outline in that case.
74074
74789
  delta,
74075
74790
  this
74076
74791
  ) : (
74077
- // Default: adjust scrollTop only when the resize is an above-
74078
- // viewport item AND we're not actively scrolling backward.
74079
- // Adjusting during backward scroll fights the user's scroll
74080
- // direction and produces the "items jump while scrolling up"
74081
- // jank reported across many issues. Users who want the old
74082
- // behavior can pass shouldAdjustScrollPositionOnItemSizeChange.
74083
- itemStart < this.getScrollOffset() + this.scrollAdjustments && this.scrollDirection !== "backward"
74792
+ // Default: adjust when the resize is an above-viewport item.
74793
+ // First measurement (!has(key)): always adjust — the item
74794
+ // has never been sized, so the estimate→actual delta must
74795
+ // be compensated regardless of scroll direction.
74796
+ // Re-measurement (has(key)): skip during backward scroll
74797
+ // to avoid the "items jump while scrolling up" cascade.
74798
+ itemStart < this.getScrollOffset() + this.scrollAdjustments && (!this.itemSizeCache.has(key) || this.scrollDirection !== "backward")
74084
74799
  ));
74085
74800
  if (this.pendingMin === null || index < this.pendingMin) {
74086
74801
  this.pendingMin = index;
@@ -74673,7 +75388,7 @@ focus outline in that case.
74673
75388
  };
74674
75389
  }
74675
75390
  getGridTemplateColumns() {
74676
- return this.getVisibleColumns()
75391
+ return this.getUnpinnedVisibleColumns()
74677
75392
  .map(column => {
74678
75393
  const { minPixelWidth, currentPixelWidth, currentFractionalWidth } = column.columnInternals;
74679
75394
  if (currentPixelWidth !== undefined) {
@@ -74699,7 +75414,7 @@ focus outline in that case.
74699
75414
  this.activeColumnIndex = this.leftColumnIndex + (this.activeColumnDivider % 2);
74700
75415
  this.dragStart = dragStart;
74701
75416
  this.currentTotalDelta = 0;
74702
- this.visibleColumns = this.getVisibleColumns();
75417
+ this.visibleColumns = this.getUnpinnedVisibleColumns();
74703
75418
  this.setColumnsToFixedSize();
74704
75419
  this.initialTableScrollableWidth = this.table.viewport.scrollWidth;
74705
75420
  this.initialTableScrollableMinWidth = this.table.tableScrollableMinWidth;
@@ -74770,7 +75485,7 @@ focus outline in that case.
74770
75485
  */
74771
75486
  getFirstLeftResizableColumnIndex(columnIndex) {
74772
75487
  const visibleColumns = this.visibleColumns.length === 0
74773
- ? this.getVisibleColumns()
75488
+ ? this.getUnpinnedVisibleColumns()
74774
75489
  : this.visibleColumns;
74775
75490
  for (let i = columnIndex; i >= 0; i--) {
74776
75491
  const column = visibleColumns[i];
@@ -74790,7 +75505,7 @@ focus outline in that case.
74790
75505
  */
74791
75506
  getFirstRightResizableColumnIndex(columnIndex) {
74792
75507
  const visibleColumns = this.visibleColumns.length === 0
74793
- ? this.getVisibleColumns()
75508
+ ? this.getUnpinnedVisibleColumns()
74794
75509
  : this.visibleColumns;
74795
75510
  for (let i = columnIndex; i < visibleColumns.length; i++) {
74796
75511
  const column = visibleColumns[i];
@@ -74887,8 +75602,9 @@ focus outline in that case.
74887
75602
  }
74888
75603
  }
74889
75604
  }
74890
- getVisibleColumns() {
74891
- return this.table.columns.filter(column => !column.columnHidden);
75605
+ getUnpinnedVisibleColumns() {
75606
+ return this.table.columns.filter(column => !column.columnHidden
75607
+ && column.columnInternals.pinLocation !== TableColumnPinLocation.left);
74892
75608
  }
74893
75609
  getLeftColumnIndexFromDivider(dividerIndex) {
74894
75610
  return Math.floor(dividerIndex / 2);
@@ -74924,7 +75640,8 @@ focus outline in that case.
74924
75640
  'columnDefinition',
74925
75641
  'actionMenuSlots',
74926
75642
  'selectionMode',
74927
- 'actionMenusPreserveSelection'
75643
+ 'actionMenusPreserveSelection',
75644
+ 'columnPinned'
74928
75645
  ];
74929
75646
  /**
74930
75647
  * Helper class to track what updates are needed to the table based on configuration
@@ -74983,6 +75700,7 @@ focus outline in that case.
74983
75700
  return (this.isTracked('columnSortDisabled')
74984
75701
  || this.isTracked('columnDefinition')
74985
75702
  || this.isTracked('columnHidden')
75703
+ || this.isTracked('columnPinned')
74986
75704
  || this.isTracked('selectionMode')
74987
75705
  || this.isTracked('actionMenuSlots'));
74988
75706
  }
@@ -75014,6 +75732,10 @@ focus outline in that case.
75014
75732
  this.track('columnWidths');
75015
75733
  this.track('columnHidden');
75016
75734
  }
75735
+ else if (isColumnInternalsProperty(changedColumnProperty, 'pinLocation')) {
75736
+ this.track('columnWidths');
75737
+ this.track('columnPinned');
75738
+ }
75017
75739
  else if (isColumnProperty(changedColumnProperty, 'actionMenuSlot')) {
75018
75740
  this.track('actionMenuSlots');
75019
75741
  }
@@ -76715,6 +77437,34 @@ focus outline in that case.
76715
77437
  }
76716
77438
  return '';
76717
77439
  }
77440
+ /**
77441
+ * @internal
77442
+ */
77443
+ get pinnedColumnOffset() {
77444
+ let offset = 0;
77445
+ for (const column of this.pinnedColumns) {
77446
+ const resolvedPixelWidth = this.getPinnedColumnResolvedPixelWidth(column);
77447
+ if (resolvedPixelWidth !== undefined) {
77448
+ const coercedPixelWidth = Math.max(column.columnInternals.minPixelWidth, resolvedPixelWidth);
77449
+ offset += coercedPixelWidth;
77450
+ }
77451
+ }
77452
+ return offset;
77453
+ }
77454
+ /**
77455
+ * @internal
77456
+ */
77457
+ get pinnedColumnsGridTemplateColumns() {
77458
+ return this.pinnedColumns.map(column => {
77459
+ const resolvedPixelWidth = this.getPinnedColumnResolvedPixelWidth(column);
77460
+ if (resolvedPixelWidth !== undefined) {
77461
+ const coercedPixelWidth = Math.max(column.columnInternals.minPixelWidth, resolvedPixelWidth);
77462
+ return `${coercedPixelWidth}px`;
77463
+ }
77464
+ return '';
77465
+ })
77466
+ .join(' ');
77467
+ }
76718
77468
  /**
76719
77469
  * @internal
76720
77470
  */
@@ -76765,6 +77515,10 @@ focus outline in that case.
76765
77515
  * @internal
76766
77516
  */
76767
77517
  this.visibleColumns = [];
77518
+ /**
77519
+ * @internal
77520
+ */
77521
+ this.pinnedColumns = [];
76768
77522
  /**
76769
77523
  * @internal
76770
77524
  * This value determines the size of the viewport area when a user has created horizontal scrollable
@@ -77117,7 +77871,10 @@ focus outline in that case.
77117
77871
  }
77118
77872
  if (this.tableUpdateTracker.updateColumnWidths) {
77119
77873
  this.rowGridColumns = this.layoutManager.getGridTemplateColumns();
77120
- this.visibleColumns = this.columns.filter(column => !column.columnHidden);
77874
+ this.visibleColumns = this.columns.filter(column => !column.columnHidden
77875
+ && column.columnInternals.pinLocation !== TableColumnPinLocation.left);
77876
+ this.pinnedColumns = this.columns.filter(column => !column.columnHidden
77877
+ && column.columnInternals.pinLocation === TableColumnPinLocation.left);
77121
77878
  }
77122
77879
  if (this.tableUpdateTracker.requiresKeyboardFocusReset) {
77123
77880
  this.keyboardNavigationManager.resetFocusState();
@@ -77195,6 +77952,10 @@ focus outline in that case.
77195
77952
  this.observeColumns();
77196
77953
  this.tableUpdateTracker.trackColumnInstancesChanged();
77197
77954
  }
77955
+ getPinnedColumnResolvedPixelWidth(column) {
77956
+ const { currentPixelWidth } = column.columnInternals;
77957
+ return currentPixelWidth;
77958
+ }
77198
77959
  updateRequestedSlotsForOpeningActionMenu(openActionMenuRecordId) {
77199
77960
  for (const actionMenuSlot of this.actionMenuSlots) {
77200
77961
  this.requestedSlots.set(actionMenuSlot, {
@@ -77369,6 +78130,7 @@ focus outline in that case.
77369
78130
  this.tableValidator.validateColumnSortIndices(this.getColumnsParticipatingInSorting().map(x => x.columnInternals.currentSortIndex));
77370
78131
  this.tableValidator.validateColumnGroupIndices(this.getColumnsParticipatingInGrouping().map(x => x.columnInternals.groupIndex));
77371
78132
  this.tableValidator.validateColumnConfigurations(this.columns);
78133
+ this.tableValidator.validatePinnedColumnConfigurations(this.columns);
77372
78134
  if (this.dataHierarchyManager) {
77373
78135
  this.validateWithData(this.dataHierarchyManager.getAllRecords());
77374
78136
  }
@@ -77641,12 +78403,21 @@ focus outline in that case.
77641
78403
  __decorate([
77642
78404
  volatile
77643
78405
  ], Table$1.prototype, "collapseButtonVisibility", null);
78406
+ __decorate([
78407
+ volatile
78408
+ ], Table$1.prototype, "pinnedColumnOffset", null);
78409
+ __decorate([
78410
+ volatile
78411
+ ], Table$1.prototype, "pinnedColumnsGridTemplateColumns", null);
77644
78412
  __decorate([
77645
78413
  observable
77646
78414
  ], Table$1.prototype, "firstSortedColumn", void 0);
77647
78415
  __decorate([
77648
78416
  observable
77649
78417
  ], Table$1.prototype, "visibleColumns", void 0);
78418
+ __decorate([
78419
+ observable
78420
+ ], Table$1.prototype, "pinnedColumns", void 0);
77650
78421
  __decorate([
77651
78422
  observable
77652
78423
  ], Table$1.prototype, "tableScrollableMinWidth", void 0);
@@ -78945,6 +79716,23 @@ focus outline in that case.
78945
79716
 
78946
79717
  const template$s = html `${template$w}<slot ${slotted('mappings')} name="mapping"></slot>`;
78947
79718
 
79719
+ // As the returned class is internal to the function, we can't write a signature that uses is directly, so rely on inference
79720
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/explicit-function-return-type
79721
+ function mixinPinnableColumnAPI(base) {
79722
+ /**
79723
+ * The Mixin that provides a concrete column with the API to allow pinning
79724
+ * a fixed-width column within a table.
79725
+ */
79726
+ class PinnableColumn extends base {
79727
+ /** @internal */
79728
+ pinLocationChanged() {
79729
+ this.columnInternals.pinLocation = this.pinLocation;
79730
+ }
79731
+ }
79732
+ attr({ attribute: 'pin-location' })(PinnableColumn.prototype, 'pinLocation');
79733
+ return PinnableColumn;
79734
+ }
79735
+
78948
79736
  const enumBaseValidityFlagNames = [
78949
79737
  'invalidMappingKeyValueForType',
78950
79738
  'duplicateMappingKey',
@@ -79333,7 +80121,7 @@ focus outline in that case.
79333
80121
  * Table column that maps number, boolean, or string values to an icon, a spinner,
79334
80122
  * text, or an icon/spinner with text.
79335
80123
  */
79336
- class TableColumnMapping extends mixinGroupableColumnAPI(mixinFractionalWidthColumnAPI(mixinSortableColumnAPI((TableColumnEnumBase)))) {
80124
+ class TableColumnMapping extends mixinGroupableColumnAPI(mixinFractionalWidthColumnAPI(mixinPinnableColumnAPI(mixinSortableColumnAPI((TableColumnEnumBase))))) {
79337
80125
  minPixelWidthChanged() {
79338
80126
  if (this.widthMode !== TableColumnMappingWidthMode.iconSize) {
79339
80127
  this.columnInternals.minPixelWidth = this.getConfiguredMinPixelWidth();
@@ -99290,6 +100078,7 @@ focus outline in that case.
99290
100078
  ${display('flex')}
99291
100079
 
99292
100080
  :host {
100081
+ height: 480px;
99293
100082
  flex-direction: column;
99294
100083
  background: ${applicationBackgroundColor};
99295
100084
  }
@@ -99337,12 +100126,28 @@ focus outline in that case.
99337
100126
  flex: 1;
99338
100127
  display: flex;
99339
100128
  flex-direction: column;
99340
- justify-content: flex-start;
99341
100129
  row-gap: 32px;
99342
100130
  padding: ${mediumPadding} ${standardPadding} ${mediumPadding}
99343
100131
  ${standardPadding};
99344
100132
  background: ${sectionBackgroundImage};
99345
100133
  overflow-y: auto;
100134
+ overflow-anchor: none;
100135
+ }
100136
+
100137
+ .messages-history,
100138
+ .messages-anchored {
100139
+ flex: none;
100140
+ display: flex;
100141
+ flex-direction: column;
100142
+ row-gap: 32px;
100143
+ }
100144
+
100145
+ .messages-history.region-empty {
100146
+ display: none;
100147
+ }
100148
+
100149
+ .messages-anchored.anchor-active {
100150
+ min-height: 100%;
99346
100151
  }
99347
100152
 
99348
100153
  :host([appearance='overlay']) .messages {
@@ -99366,7 +100171,14 @@ focus outline in that case.
99366
100171
  <div class="start ${x => (x.startEmpty ? 'start-empty' : '')}">
99367
100172
  <slot name="start" ${slotted({ property: 'slottedStartElements' })}></slot>
99368
100173
  </div>
99369
- <div class="messages"><slot></slot></div>
100174
+ <div class="messages" ${ref('messagesContainer')}>
100175
+ <div class="messages-history ${x => (x.historyEmpty ? 'region-empty' : '')}">
100176
+ <slot name="history" ${slotted({ property: 'slottedHistoryMessages' })}></slot>
100177
+ </div>
100178
+ <div class="messages-anchored ${x => (x.autoScrollManager.anchorActive ? 'anchor-active' : '')}" ${ref('anchoredContainer')}>
100179
+ <slot ${slotted({ property: 'slottedMessages' })}></slot>
100180
+ </div>
100181
+ </div>
99370
100182
  <div class="input ${x => (x.inputEmpty ? 'input-empty' : '')}">
99371
100183
  <slot name="input" ${slotted({ property: 'slottedInputElements' })}>
99372
100184
  </slot>
@@ -99383,6 +100195,262 @@ focus outline in that case.
99383
100195
  const ChatConversationAppearance = {
99384
100196
  default: undefined};
99385
100197
 
100198
+ /**
100199
+ * Internal state for a chat message
100200
+ * @internal
100201
+ */
100202
+ class ChatMessageInternals {
100203
+ constructor(host, options) {
100204
+ /**
100205
+ * True when this message is the one the conversation anchors to while
100206
+ * auto-scrolling.
100207
+ */
100208
+ this.isScrollAnchor = false;
100209
+ this.host = host;
100210
+ this.anchorOnInsert = options?.anchorOnInsert ?? false;
100211
+ }
100212
+ get slot() {
100213
+ return this.slotName;
100214
+ }
100215
+ set slot(value) {
100216
+ if (value === this.slotName) {
100217
+ return;
100218
+ }
100219
+ this.slotName = value;
100220
+ if (value === undefined) {
100221
+ this.host.removeAttribute('slot');
100222
+ }
100223
+ else {
100224
+ this.host.setAttribute('slot', value);
100225
+ }
100226
+ }
100227
+ static elementHasMessageInternals(element) {
100228
+ return element.messageInternals instanceof ChatMessageInternals;
100229
+ }
100230
+ }
100231
+ __decorate([
100232
+ observable
100233
+ ], ChatMessageInternals.prototype, "isScrollAnchor", void 0);
100234
+
100235
+ // Distance from the bottom (px) within which the conversation is considered "at the bottom".
100236
+ const scrollingPixelThreshold = 10;
100237
+ // Slot name for messages that precede the current turn's anchor message.
100238
+ const historySlotName = 'history';
100239
+ /**
100240
+ * Manages auto-scroll behavior for the chat conversation:
100241
+ * - Splits messages into `default` and `history` slots so the top message of the
100242
+ * `default` slot becomes the anchor: it is moved to the top of the viewport and scrolled to on insert
100243
+ * - Implements auto scroll when at the bottom of the window as content is added until the user scrolls away
100244
+ * @internal
100245
+ */
100246
+ class AutoScrollManager {
100247
+ get isActive() {
100248
+ return this.resizeObserver !== undefined;
100249
+ }
100250
+ constructor(conversation) {
100251
+ this.conversation = conversation;
100252
+ /**
100253
+ * Whether auto-scroll is currently following new content. Set to false when
100254
+ * the user scrolls away from the bottom and back to true when they return.
100255
+ */
100256
+ this.autoScrollEngaged = true;
100257
+ /**
100258
+ * Whether the anchored region is reserving a viewport of space
100259
+ */
100260
+ this.anchorActive = false;
100261
+ this.scrollUpdatePending = false;
100262
+ this.pendingAnchorInsert = false;
100263
+ this.previousMessages = [];
100264
+ this.onScroll = () => {
100265
+ const container = this.conversation.messagesContainer;
100266
+ if (this.programmaticScrollTarget !== undefined) {
100267
+ // The programmatic scroll always targets the bottom, so treat it as
100268
+ // settled once we reach that target or the bottom itself.
100269
+ const reachedTarget = Math.abs(container.scrollTop - this.programmaticScrollTarget) <= 1;
100270
+ const reachedBottom = this.getDistanceFromBottom() <= scrollingPixelThreshold;
100271
+ if (reachedTarget || reachedBottom) {
100272
+ this.programmaticScrollTarget = undefined;
100273
+ }
100274
+ return;
100275
+ }
100276
+ this.autoScrollEngaged = this.getDistanceFromBottom() <= scrollingPixelThreshold;
100277
+ };
100278
+ this.conversationNotifier = Observable.getNotifier(this.conversation);
100279
+ }
100280
+ connect() {
100281
+ this.autoScrollEngaged = true;
100282
+ this.previousMessages = this.getOrderedMessages();
100283
+ this.conversationNotifier.subscribe(this, 'slottedMessages');
100284
+ this.conversationNotifier.subscribe(this, 'slottedHistoryMessages');
100285
+ this.conversation.messagesContainer.addEventListener('scroll', this.onScroll, { passive: true });
100286
+ this.resizeObserver = new ResizeObserver(() => {
100287
+ this.onContentSizeChanged();
100288
+ });
100289
+ // Observe the anchored region for streamed content growth and the scroll
100290
+ // viewport so the conversation stays pinned when its height changes.
100291
+ this.resizeObserver.observe(this.conversation.anchoredContainer);
100292
+ this.resizeObserver.observe(this.conversation.messagesContainer);
100293
+ this.repartition(this.previousMessages);
100294
+ }
100295
+ disconnect() {
100296
+ this.conversationNotifier.unsubscribe(this, 'slottedMessages');
100297
+ this.conversationNotifier.unsubscribe(this, 'slottedHistoryMessages');
100298
+ this.conversation.messagesContainer.removeEventListener('scroll', this.onScroll);
100299
+ this.resizeObserver?.disconnect();
100300
+ this.resizeObserver = undefined;
100301
+ this.setScrollAnchorMessage(undefined);
100302
+ this.clearSlotAssignments();
100303
+ this.anchorActive = false;
100304
+ this.previousMessages = [];
100305
+ }
100306
+ handleChange(source, args) {
100307
+ if (source === this.conversation
100308
+ && (args === 'slottedMessages' || args === 'slottedHistoryMessages')) {
100309
+ this.onMessagesChanged();
100310
+ }
100311
+ }
100312
+ onMessagesChanged() {
100313
+ const current = this.getOrderedMessages();
100314
+ const previousSet = new Set(this.previousMessages);
100315
+ const addedMessages = current.filter(message => !previousSet.has(message));
100316
+ this.previousMessages = current;
100317
+ this.repartition(current);
100318
+ if (addedMessages.length === 0) {
100319
+ return;
100320
+ }
100321
+ const hasAnchorMessage = addedMessages.some(message => message.messageInternals.anchorOnInsert);
100322
+ this.scheduleScrollUpdate(hasAnchorMessage);
100323
+ }
100324
+ repartition(messages) {
100325
+ const anchorIndex = this.findLatestAnchorIndex(messages);
100326
+ messages.forEach((message, index) => {
100327
+ message.messageInternals.slot = anchorIndex >= 0 && index < anchorIndex
100328
+ ? historySlotName
100329
+ : undefined;
100330
+ });
100331
+ this.anchorActive = anchorIndex >= 0;
100332
+ }
100333
+ clearSlotAssignments() {
100334
+ for (const message of this.getOrderedMessages()) {
100335
+ message.messageInternals.slot = undefined;
100336
+ }
100337
+ }
100338
+ scheduleScrollUpdate(hasAnchorMessage) {
100339
+ this.pendingAnchorInsert = this.pendingAnchorInsert || hasAnchorMessage;
100340
+ if (this.scrollUpdatePending) {
100341
+ return;
100342
+ }
100343
+ this.scrollUpdatePending = true;
100344
+ requestAnimationFrame(() => {
100345
+ this.scrollUpdatePending = false;
100346
+ const anchorInsert = this.pendingAnchorInsert;
100347
+ this.pendingAnchorInsert = false;
100348
+ if (anchorInsert) {
100349
+ this.anchorToLastInsertedMessage();
100350
+ }
100351
+ else if (this.autoScrollEngaged) {
100352
+ this.followContent();
100353
+ }
100354
+ });
100355
+ }
100356
+ /**
100357
+ * Pins the most recently inserted anchor message near the top of the
100358
+ * viewport.
100359
+ */
100360
+ anchorToLastInsertedMessage() {
100361
+ const message = this.getLastAnchorMessage();
100362
+ if (message === undefined) {
100363
+ return;
100364
+ }
100365
+ this.setScrollAnchorMessage(message);
100366
+ this.autoScrollEngaged = true;
100367
+ this.smoothScrollTo(this.getMaxScrollTop());
100368
+ }
100369
+ followContent() {
100370
+ this.instantScrollTo(this.getMaxScrollTop());
100371
+ }
100372
+ onContentSizeChanged() {
100373
+ // Reacts to streamed content growth and viewport height changes.
100374
+ // While a pending or in-progress anchor insert owns positioning, let its
100375
+ // smooth scroll settle instead of competing with an instant follow.
100376
+ if (this.pendingAnchorInsert
100377
+ || this.programmaticScrollTarget !== undefined) {
100378
+ return;
100379
+ }
100380
+ if (this.autoScrollEngaged) {
100381
+ this.followContent();
100382
+ }
100383
+ }
100384
+ getDistanceFromBottom() {
100385
+ const { scrollTop, scrollHeight, clientHeight } = this.conversation.messagesContainer;
100386
+ return scrollHeight - scrollTop - clientHeight;
100387
+ }
100388
+ getMaxScrollTop() {
100389
+ const { scrollHeight, clientHeight } = this.conversation.messagesContainer;
100390
+ return Math.max(0, scrollHeight - clientHeight);
100391
+ }
100392
+ smoothScrollTo(scrollTop) {
100393
+ const container = this.conversation.messagesContainer;
100394
+ if (Math.abs(container.scrollTop - scrollTop) <= 1) {
100395
+ // No movement is needed, so `scrollTo` would not emit a scroll event
100396
+ // to clear the programmatic guard. Snap to the exact target and
100397
+ // leave the guard clear so streamed content keeps being followed.
100398
+ this.programmaticScrollTarget = undefined;
100399
+ container.scrollTop = scrollTop;
100400
+ return;
100401
+ }
100402
+ this.programmaticScrollTarget = scrollTop;
100403
+ container.scrollTo({
100404
+ top: scrollTop,
100405
+ behavior: 'smooth'
100406
+ });
100407
+ }
100408
+ instantScrollTo(scrollTop) {
100409
+ this.conversation.messagesContainer.scrollTop = scrollTop;
100410
+ }
100411
+ setScrollAnchorMessage(message) {
100412
+ if (this.scrollAnchorMessage === message) {
100413
+ return;
100414
+ }
100415
+ if (this.scrollAnchorMessage !== undefined) {
100416
+ this.scrollAnchorMessage.messageInternals.isScrollAnchor = false;
100417
+ }
100418
+ this.scrollAnchorMessage = message;
100419
+ if (message !== undefined) {
100420
+ message.messageInternals.isScrollAnchor = true;
100421
+ }
100422
+ }
100423
+ getLastAnchorMessage() {
100424
+ const messages = this.getOrderedMessages();
100425
+ const index = this.findLatestAnchorIndex(messages);
100426
+ return index >= 0 ? messages[index] : undefined;
100427
+ }
100428
+ findLatestAnchorIndex(messages) {
100429
+ for (let i = messages.length - 1; i >= 0; i--) {
100430
+ const message = messages[i];
100431
+ if (message?.messageInternals.anchorOnInsert) {
100432
+ return i;
100433
+ }
100434
+ }
100435
+ return -1;
100436
+ }
100437
+ getOrderedMessages() {
100438
+ const messages = [];
100439
+ for (const child of Array.from(this.conversation.children)) {
100440
+ if (ChatMessageInternals.elementHasMessageInternals(child)) {
100441
+ messages.push(child);
100442
+ }
100443
+ }
100444
+ return messages;
100445
+ }
100446
+ }
100447
+ __decorate([
100448
+ observable
100449
+ ], AutoScrollManager.prototype, "autoScrollEngaged", void 0);
100450
+ __decorate([
100451
+ observable
100452
+ ], AutoScrollManager.prototype, "anchorActive", void 0);
100453
+
99386
100454
  /**
99387
100455
  * A Spright component for displaying a series of chat messages
99388
100456
  */
@@ -99390,6 +100458,15 @@ focus outline in that case.
99390
100458
  constructor() {
99391
100459
  super(...arguments);
99392
100460
  this.appearance = ChatConversationAppearance.default;
100461
+ this.autoScroll = false;
100462
+ /**
100463
+ * Manages auto-scroll behavior. Always present; its observers are registered
100464
+ * while the conversation is connected and `autoScroll` is enabled.
100465
+ * @internal
100466
+ */
100467
+ this.autoScrollManager = new AutoScrollManager(this);
100468
+ /** @internal */
100469
+ this.historyEmpty = true;
99393
100470
  /** @internal */
99394
100471
  this.inputEmpty = true;
99395
100472
  /** @internal */
@@ -99399,6 +100476,31 @@ focus outline in that case.
99399
100476
  /** @internal */
99400
100477
  this.endEmpty = true;
99401
100478
  }
100479
+ connectedCallback() {
100480
+ super.connectedCallback();
100481
+ if (this.autoScroll) {
100482
+ this.autoScrollManager.connect();
100483
+ }
100484
+ }
100485
+ disconnectedCallback() {
100486
+ super.disconnectedCallback();
100487
+ if (this.autoScroll) {
100488
+ this.autoScrollManager.disconnect();
100489
+ }
100490
+ }
100491
+ autoScrollChanged() {
100492
+ if (this.$fastController.isConnected) {
100493
+ if (this.autoScroll) {
100494
+ this.autoScrollManager.connect();
100495
+ }
100496
+ else {
100497
+ this.autoScrollManager.disconnect();
100498
+ }
100499
+ }
100500
+ }
100501
+ slottedHistoryMessagesChanged(_prev, next) {
100502
+ this.historyEmpty = next === undefined || next.length === 0;
100503
+ }
99402
100504
  slottedInputElementsChanged(_prev, next) {
99403
100505
  this.inputEmpty = next === undefined || next.length === 0;
99404
100506
  }
@@ -99415,6 +100517,18 @@ focus outline in that case.
99415
100517
  __decorate([
99416
100518
  attr
99417
100519
  ], ChatConversation.prototype, "appearance", void 0);
100520
+ __decorate([
100521
+ attr({ attribute: 'auto-scroll', mode: 'boolean' })
100522
+ ], ChatConversation.prototype, "autoScroll", void 0);
100523
+ __decorate([
100524
+ observable
100525
+ ], ChatConversation.prototype, "slottedMessages", void 0);
100526
+ __decorate([
100527
+ observable
100528
+ ], ChatConversation.prototype, "slottedHistoryMessages", void 0);
100529
+ __decorate([
100530
+ observable
100531
+ ], ChatConversation.prototype, "historyEmpty", void 0);
99418
100532
  __decorate([
99419
100533
  observable
99420
100534
  ], ChatConversation.prototype, "inputEmpty", void 0);
@@ -100074,6 +101188,8 @@ focus outline in that case.
100074
101188
  constructor() {
100075
101189
  super(...arguments);
100076
101190
  /** @internal */
101191
+ this.messageInternals = new ChatMessageInternals(this);
101192
+ /** @internal */
100077
101193
  this.footerActionsIsEmpty = true;
100078
101194
  }
100079
101195
  slottedFooterActionsElementsChanged(_prev, next) {
@@ -100140,6 +101256,13 @@ focus outline in that case.
100140
101256
  * A Spright component for displaying an outbound chat message
100141
101257
  */
100142
101258
  class ChatMessageOutbound extends FoundationElement {
101259
+ constructor() {
101260
+ super(...arguments);
101261
+ /** @internal */
101262
+ this.messageInternals = new ChatMessageInternals(this, {
101263
+ anchorOnInsert: true
101264
+ });
101265
+ }
100143
101266
  }
100144
101267
  const sprightChatMessageOutbound = ChatMessageOutbound.compose({
100145
101268
  baseName: 'chat-message-outbound',
@@ -100187,6 +101310,11 @@ focus outline in that case.
100187
101310
  * A Spright component for displaying an system chat message
100188
101311
  */
100189
101312
  class ChatMessageSystem extends FoundationElement {
101313
+ constructor() {
101314
+ super(...arguments);
101315
+ /** @internal */
101316
+ this.messageInternals = new ChatMessageInternals(this);
101317
+ }
100190
101318
  }
100191
101319
  const sprightChatMessageSystem = ChatMessageSystem.compose({
100192
101320
  baseName: 'chat-message-system',