@ni/ok-components 0.3.2 → 0.3.4

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.
@@ -13466,6 +13466,12 @@
13466
13466
  * @internal
13467
13467
  */
13468
13468
  this.direction = Direction.ltr;
13469
+ /**
13470
+ * The collection of focusable toolbar controls.
13471
+ *
13472
+ * @internal
13473
+ */
13474
+ this.focusableElements = [];
13469
13475
  /**
13470
13476
  * The orientation of the toolbar.
13471
13477
  *
@@ -13486,7 +13492,7 @@
13486
13492
  }
13487
13493
  set activeIndex(value) {
13488
13494
  if (this.$fastController.isConnected) {
13489
- this._activeIndex = limit(0, this.focusableElements.length - 1, value);
13495
+ this._activeIndex = limit(0, this.focusableElements.length > 0 ? this.focusableElements.length - 1 : 0, value);
13490
13496
  Observable.notify(this, "activeIndex");
13491
13497
  }
13492
13498
  }
@@ -13501,7 +13507,7 @@
13501
13507
  * @internal
13502
13508
  */
13503
13509
  mouseDownHandler(e) {
13504
- const activeIndex = this.focusableElements?.findIndex(x => x.contains(e.target));
13510
+ const activeIndex = this.focusableElements.findIndex(x => x.contains(e.target));
13505
13511
  if (activeIndex > -1 && this.activeIndex !== activeIndex) {
13506
13512
  this.setFocusedElement(activeIndex);
13507
13513
  }
@@ -13558,7 +13564,7 @@
13558
13564
  return !e.target.closest("[role=radiogroup]");
13559
13565
  }
13560
13566
  const nextIndex = this.activeIndex + incrementer;
13561
- if (this.focusableElements[nextIndex]) {
13567
+ if (this.focusableElements.length > 0 && this.focusableElements[nextIndex]) {
13562
13568
  e.preventDefault();
13563
13569
  }
13564
13570
  this.setFocusedElement(nextIndex);
@@ -13581,7 +13587,7 @@
13581
13587
  * @internal
13582
13588
  */
13583
13589
  reduceFocusableElements() {
13584
- const previousFocusedElement = this.focusableElements?.[this.activeIndex];
13590
+ const previousFocusedElement = this.focusableElements[this.activeIndex];
13585
13591
  this.focusableElements = this.allSlottedItems.reduce(Toolbar.reduceFocusableItems, []);
13586
13592
  // If the previously active item is still focusable, adjust the active index to the
13587
13593
  // index of that item.
@@ -13598,7 +13604,8 @@
13598
13604
  setFocusedElement(activeIndex = this.activeIndex) {
13599
13605
  this.activeIndex = activeIndex;
13600
13606
  this.setFocusableElements();
13601
- if (this.focusableElements[this.activeIndex] &&
13607
+ if (this.focusableElements.length > 0 &&
13608
+ this.focusableElements[this.activeIndex] &&
13602
13609
  // Don't focus the toolbar element if some event handlers moved
13603
13610
  // the focus on another element in the page.
13604
13611
  this.contains(getRootActiveElement(this))) {
@@ -40786,8 +40793,13 @@ so this becomes the fallback color for the slot */ ''}
40786
40793
  for (let node of added)
40787
40794
  if (node.nodeName == "BR" && node.parentNode) {
40788
40795
  let after = node.nextSibling;
40789
- if (after && after.nodeType == 1 && after.contentEditable == "false")
40790
- node.parentNode.removeChild(node);
40796
+ while (after && after.nodeType == 1) {
40797
+ if (after.contentEditable == "false") {
40798
+ node.parentNode.removeChild(node);
40799
+ break;
40800
+ }
40801
+ after = after.firstChild;
40802
+ }
40791
40803
  }
40792
40804
  }
40793
40805
  else if (gecko && added.length) {
@@ -41625,12 +41637,12 @@ so this becomes the fallback color for the slot */ ''}
41625
41637
  }
41626
41638
  updateDraggedNode(dragging, prev) {
41627
41639
  let sel = dragging.node, found = -1;
41628
- if (this.state.doc.nodeAt(sel.from) == sel.node) {
41640
+ if (sel.from < this.state.doc.content.size && this.state.doc.nodeAt(sel.from) == sel.node) {
41629
41641
  found = sel.from;
41630
41642
  }
41631
41643
  else {
41632
41644
  let movedPos = sel.from + (this.state.doc.content.size - prev.doc.content.size);
41633
- let moved = movedPos > 0 && this.state.doc.nodeAt(movedPos);
41645
+ let moved = movedPos > 0 && movedPos < this.state.doc.content.size && this.state.doc.nodeAt(movedPos);
41634
41646
  if (moved == sel.node)
41635
41647
  found = movedPos;
41636
41648
  }
@@ -43502,6 +43514,67 @@ so this becomes the fallback color for the slot */ ''}
43502
43514
  }
43503
43515
 
43504
43516
  // src/utilities/mergeAttributes.ts
43517
+ function splitStyleDeclarations(styles) {
43518
+ const result = [];
43519
+ let current = "";
43520
+ let inSingleQuote = false;
43521
+ let inDoubleQuote = false;
43522
+ let parenDepth = 0;
43523
+ const length = styles.length;
43524
+ for (let i = 0; i < length; i += 1) {
43525
+ const char = styles[i];
43526
+ if (char === "'" && !inDoubleQuote) {
43527
+ inSingleQuote = !inSingleQuote;
43528
+ current += char;
43529
+ continue;
43530
+ }
43531
+ if (char === '"' && !inSingleQuote) {
43532
+ inDoubleQuote = !inDoubleQuote;
43533
+ current += char;
43534
+ continue;
43535
+ }
43536
+ if (!inSingleQuote && !inDoubleQuote) {
43537
+ if (char === "(") {
43538
+ parenDepth += 1;
43539
+ current += char;
43540
+ continue;
43541
+ }
43542
+ if (char === ")" && parenDepth > 0) {
43543
+ parenDepth -= 1;
43544
+ current += char;
43545
+ continue;
43546
+ }
43547
+ if (char === ";" && parenDepth === 0) {
43548
+ result.push(current);
43549
+ current = "";
43550
+ continue;
43551
+ }
43552
+ }
43553
+ current += char;
43554
+ }
43555
+ if (current) {
43556
+ result.push(current);
43557
+ }
43558
+ return result;
43559
+ }
43560
+ function parseStyleEntries(styles) {
43561
+ const pairs = [];
43562
+ const declarations = splitStyleDeclarations(styles || "");
43563
+ const numDeclarations = declarations.length;
43564
+ for (let i = 0; i < numDeclarations; i += 1) {
43565
+ const declaration = declarations[i];
43566
+ const firstColonIndex = declaration.indexOf(":");
43567
+ if (firstColonIndex === -1) {
43568
+ continue;
43569
+ }
43570
+ const property = declaration.slice(0, firstColonIndex).trim();
43571
+ const value = declaration.slice(firstColonIndex + 1).trim();
43572
+ if (property && value) {
43573
+ pairs.push([property, value]);
43574
+ }
43575
+ }
43576
+ return pairs;
43577
+ }
43505
43578
  function mergeAttributes(...objects) {
43506
43579
  return objects.filter((item) => !!item).reduce((items, item) => {
43507
43580
  const mergedAttributes = { ...items };
@@ -43517,17 +43590,7 @@ so this becomes the fallback color for the slot */ ''}
43517
43590
  const insertClasses = valueClasses.filter((valueClass) => !existingClasses.includes(valueClass));
43518
43591
  mergedAttributes[key] = [...existingClasses, ...insertClasses].join(" ");
43519
43592
  } else if (key === "style") {
43520
- const newStyles = value ? value.split(";").map((style2) => style2.trim()).filter(Boolean) : [];
43521
- const existingStyles = mergedAttributes[key] ? mergedAttributes[key].split(";").map((style2) => style2.trim()).filter(Boolean) : [];
43522
- const styleMap = /* @__PURE__ */ new Map();
43523
- existingStyles.forEach((style2) => {
43524
- const [property, val] = style2.split(":").map((part) => part.trim());
43525
- styleMap.set(property, val);
43526
- });
43527
- newStyles.forEach((style2) => {
43528
- const [property, val] = style2.split(":").map((part) => part.trim());
43529
- styleMap.set(property, val);
43530
- });
43593
+ const styleMap = new Map([...parseStyleEntries(mergedAttributes[key]), ...parseStyleEntries(value)]);
43531
43594
  mergedAttributes[key] = Array.from(styleMap.entries()).map(([property, val]) => `${property}: ${val}`).join("; ");
43532
43595
  } else {
43533
43596
  mergedAttributes[key] = value;
@@ -44114,7 +44177,7 @@ so this becomes the fallback color for the slot */ ''}
44114
44177
  return true;
44115
44178
  }
44116
44179
  if (node.isText) {
44117
- return /^\s*$/m.test((_a = node.text) != null ? _a : "");
44180
+ return !/\S/.test((_a = node.text) != null ? _a : "");
44118
44181
  }
44119
44182
  }
44120
44183
  if (node.isText) {
@@ -47499,17 +47562,21 @@ ${renderedContent}
47499
47562
  const prefix = typeof prefixOrGenerator === "function" ? prefixOrGenerator(ctx) : prefixOrGenerator;
47500
47563
  const [content, ...children] = node.content;
47501
47564
  const mainContent = h2.renderChildren([content]);
47502
- const output = [`${prefix}${mainContent}`];
47565
+ let output = `${prefix}${mainContent}`;
47503
47566
  if (children && children.length > 0) {
47504
- children.forEach((child) => {
47505
- const childContent = h2.renderChildren([child]);
47506
- if (childContent) {
47507
- const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : "").join("\n");
47508
- output.push(indentedChild);
47567
+ children.forEach((child, index) => {
47568
+ var _a, _b;
47569
+ const childContent = (_b = (_a = h2.renderChild) == null ? void 0 : _a.call(h2, child, index + 1)) != null ? _b : h2.renderChildren([child]);
47570
+ if (childContent !== void 0 && childContent !== null) {
47571
+ const indentedChild = childContent.split("\n").map((line) => line ? h2.indent(line) : h2.indent("")).join("\n");
47572
+ output += child.type === "paragraph" ? `
47573
+
47574
+ ${indentedChild}` : `
47575
+ ${indentedChild}`;
47509
47576
  }
47510
47577
  });
47511
47578
  }
47512
- return output.join("\n");
47579
+ return output;
47513
47580
  }
47514
47581
 
47515
47582
  // src/MarkView.ts
@@ -58366,6 +58433,12 @@ ${renderedContent}
58366
58433
  parseMarkdown: (token, helpers) => {
58367
58434
  return helpers.applyMark("bold", helpers.parseInline(token.tokens || []));
58368
58435
  },
58436
+ markdownOptions: {
58437
+ htmlReopen: {
58438
+ open: "<strong>",
58439
+ close: "</strong>"
58440
+ }
58441
+ },
58369
58442
  renderMarkdown: (node, h) => {
58370
58443
  return `**${h.renderChildren(node)}**`;
58371
58444
  },
@@ -58483,6 +58556,12 @@ ${renderedContent}
58483
58556
  parseMarkdown: (token, helpers) => {
58484
58557
  return helpers.applyMark("italic", helpers.parseInline(token.tokens || []));
58485
58558
  },
58559
+ markdownOptions: {
58560
+ htmlReopen: {
58561
+ open: "<em>",
58562
+ close: "</em>"
58563
+ }
58564
+ },
58486
58565
  renderMarkdown: (node, h) => {
58487
58566
  return `*${h.renderChildren(node)}*`;
58488
58567
  },
@@ -60789,14 +60868,16 @@ ${renderedContent}
60789
60868
  },
60790
60869
  markdownTokenName: "list_item",
60791
60870
  parseMarkdown: (token, helpers) => {
60871
+ var _a;
60792
60872
  if (token.type !== "list_item") {
60793
60873
  return [];
60794
60874
  }
60875
+ const parseBlockChildren = (_a = helpers.parseBlockChildren) != null ? _a : helpers.parseChildren;
60795
60876
  let content = [];
60796
60877
  if (token.tokens && token.tokens.length > 0) {
60797
60878
  const hasParagraphTokens = token.tokens.some((t) => t.type === "paragraph");
60798
60879
  if (hasParagraphTokens) {
60799
- content = helpers.parseChildren(token.tokens);
60880
+ content = parseBlockChildren(token.tokens);
60800
60881
  } else {
60801
60882
  const firstToken = token.tokens[0];
60802
60883
  if (firstToken && firstToken.type === "text" && firstToken.tokens && firstToken.tokens.length > 0) {
@@ -60809,11 +60890,11 @@ ${renderedContent}
60809
60890
  ];
60810
60891
  if (token.tokens.length > 1) {
60811
60892
  const remainingTokens = token.tokens.slice(1);
60812
- const additionalContent = helpers.parseChildren(remainingTokens);
60893
+ const additionalContent = parseBlockChildren(remainingTokens);
60813
60894
  content.push(...additionalContent);
60814
60895
  }
60815
60896
  } else {
60816
- content = helpers.parseChildren(token.tokens);
60897
+ content = parseBlockChildren(token.tokens);
60817
60898
  }
60818
60899
  }
60819
60900
  }
@@ -62322,13 +62403,16 @@ ${nextLine.slice(indentLevel + 2)}`;
62322
62403
  }
62323
62404
  return helpers.createNode("paragraph", void 0, content);
62324
62405
  },
62325
- renderMarkdown: (node, h) => {
62406
+ renderMarkdown: (node, h, ctx) => {
62407
+ var _a, _b;
62326
62408
  if (!node) {
62327
62409
  return "";
62328
62410
  }
62329
62411
  const content = Array.isArray(node.content) ? node.content : [];
62330
62412
  if (content.length === 0) {
62331
- return EMPTY_PARAGRAPH_MARKDOWN;
62413
+ const previousContent = Array.isArray((_a = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _a.content) ? ctx.previousNode.content : [];
62414
+ const previousNodeIsEmptyParagraph = ((_b = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _b.type) === "paragraph" && previousContent.length === 0;
62415
+ return previousNodeIsEmptyParagraph ? EMPTY_PARAGRAPH_MARKDOWN : "";
62332
62416
  }
62333
62417
  return h.renderChildren(content);
62334
62418
  },
@@ -62546,7 +62630,7 @@ ${nextLine.slice(indentLevel + 2)}`;
62546
62630
  */
62547
62631
  static valid($pos) {
62548
62632
  let parent = $pos.parent;
62549
- if (parent.isTextblock || !closedBefore($pos) || !closedAfter($pos))
62633
+ if (parent.inlineContent || !closedBefore($pos) || !closedAfter($pos))
62550
62634
  return false;
62551
62635
  let override = parent.type.spec.allowGapCursor;
62552
62636
  if (override != null)
@@ -63575,6 +63659,9 @@ ${nextLine.slice(indentLevel + 2)}`;
63575
63659
  doc.descendants((node, pos) => {
63576
63660
  const hasAnchor = anchor >= pos && anchor <= pos + node.nodeSize;
63577
63661
  const isEmpty = !node.isLeaf && isNodeEmpty(node);
63662
+ if (!node.type.isTextblock) {
63663
+ return this.options.includeChildren;
63664
+ }
63578
63665
  if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) {
63579
63666
  const classes = [this.options.emptyNodeClass];
63580
63667
  if (isEmptyDoc) {
@@ -72375,7 +72462,7 @@ focus outline in that case.
72375
72462
  this.scrollElement = null;
72376
72463
  this.targetWindow = null;
72377
72464
  this.isScrolling = false;
72378
- this.currentScrollToIndex = null;
72465
+ this.scrollState = null;
72379
72466
  this.measurementsCache = [];
72380
72467
  this.itemSizeCache = /* @__PURE__ */ new Map();
72381
72468
  this.laneAssignments = /* @__PURE__ */ new Map();
@@ -72388,6 +72475,10 @@ focus outline in that case.
72388
72475
  this.scrollDirection = null;
72389
72476
  this.scrollAdjustments = 0;
72390
72477
  this.elementsCache = /* @__PURE__ */ new Map();
72478
+ this.now = () => {
72479
+ var _a, _b, _c;
72480
+ return ((_c = (_b = (_a = this.targetWindow) == null ? void 0 : _a.performance) == null ? void 0 : _b.now) == null ? void 0 : _c.call(_b)) ?? Date.now();
72481
+ };
72391
72482
  this.observer = /* @__PURE__ */ (() => {
72392
72483
  let _ro = null;
72393
72484
  const get = () => {
@@ -72400,7 +72491,18 @@ focus outline in that case.
72400
72491
  return _ro = new this.targetWindow.ResizeObserver((entries) => {
72401
72492
  entries.forEach((entry) => {
72402
72493
  const run = () => {
72403
- this._measureElement(entry.target, entry);
72494
+ const node = entry.target;
72495
+ const index = this.indexFromElement(node);
72496
+ if (!node.isConnected) {
72497
+ this.observer.unobserve(node);
72498
+ return;
72499
+ }
72500
+ if (this.shouldMeasureDuringScroll(index)) {
72501
+ this.resizeItem(
72502
+ index,
72503
+ this.options.measureElement(node, entry, this)
72504
+ );
72505
+ }
72404
72506
  };
72405
72507
  this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
72406
72508
  });
@@ -72485,6 +72587,11 @@ focus outline in that case.
72485
72587
  this.unsubs.filter(Boolean).forEach((d) => d());
72486
72588
  this.unsubs = [];
72487
72589
  this.observer.disconnect();
72590
+ if (this.rafId != null && this.targetWindow) {
72591
+ this.targetWindow.cancelAnimationFrame(this.rafId);
72592
+ this.rafId = null;
72593
+ }
72594
+ this.scrollState = null;
72488
72595
  this.scrollElement = null;
72489
72596
  this.targetWindow = null;
72490
72597
  };
@@ -72523,6 +72630,9 @@ focus outline in that case.
72523
72630
  this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null;
72524
72631
  this.scrollOffset = offset;
72525
72632
  this.isScrolling = isScrolling;
72633
+ if (this.scrollState) {
72634
+ this.scheduleScrollReconcile();
72635
+ }
72526
72636
  this.maybeNotify();
72527
72637
  })
72528
72638
  );
@@ -72532,6 +72642,7 @@ focus outline in that case.
72532
72642
  });
72533
72643
  }
72534
72644
  };
72645
+ this.rafId = null;
72535
72646
  this.getSize = () => {
72536
72647
  if (!this.options.enabled) {
72537
72648
  this.scrollRect = null;
@@ -72750,13 +72861,38 @@ focus outline in that case.
72750
72861
  }
72751
72862
  return parseInt(indexStr, 10);
72752
72863
  };
72753
- this._measureElement = (node, entry) => {
72754
- const index = this.indexFromElement(node);
72755
- const item = this.measurementsCache[index];
72756
- if (!item) {
72864
+ this.shouldMeasureDuringScroll = (index) => {
72865
+ var _a;
72866
+ if (!this.scrollState || this.scrollState.behavior !== "smooth") {
72867
+ return true;
72868
+ }
72869
+ const scrollIndex = this.scrollState.index ?? ((_a = this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)) == null ? void 0 : _a.index);
72870
+ if (scrollIndex !== void 0 && this.range) {
72871
+ const bufferSize = Math.max(
72872
+ this.options.overscan,
72873
+ Math.ceil((this.range.endIndex - this.range.startIndex) / 2)
72874
+ );
72875
+ const minIndex = Math.max(0, scrollIndex - bufferSize);
72876
+ const maxIndex = Math.min(
72877
+ this.options.count - 1,
72878
+ scrollIndex + bufferSize
72879
+ );
72880
+ return index >= minIndex && index <= maxIndex;
72881
+ }
72882
+ return true;
72883
+ };
72884
+ this.measureElement = (node) => {
72885
+ if (!node) {
72886
+ this.elementsCache.forEach((cached, key2) => {
72887
+ if (!cached.isConnected) {
72888
+ this.observer.unobserve(cached);
72889
+ this.elementsCache.delete(key2);
72890
+ }
72891
+ });
72757
72892
  return;
72758
72893
  }
72759
- const key = item.key;
72894
+ const index = this.indexFromElement(node);
72895
+ const key = this.options.getItemKey(index);
72760
72896
  const prevNode = this.elementsCache.get(key);
72761
72897
  if (prevNode !== node) {
72762
72898
  if (prevNode) {
@@ -72765,19 +72901,18 @@ focus outline in that case.
72765
72901
  this.observer.observe(node);
72766
72902
  this.elementsCache.set(key, node);
72767
72903
  }
72768
- if (node.isConnected) {
72769
- this.resizeItem(index, this.options.measureElement(node, entry, this));
72904
+ if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) {
72905
+ this.resizeItem(index, this.options.measureElement(node, void 0, this));
72770
72906
  }
72771
72907
  };
72772
72908
  this.resizeItem = (index, size) => {
72909
+ var _a;
72773
72910
  const item = this.measurementsCache[index];
72774
- if (!item) {
72775
- return;
72776
- }
72911
+ if (!item) return;
72777
72912
  const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
72778
72913
  const delta = size - itemSize;
72779
72914
  if (delta !== 0) {
72780
- if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {
72915
+ if (((_a = this.scrollState) == null ? void 0 : _a.behavior) !== "smooth" && (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments)) {
72781
72916
  if (this.options.debug) {
72782
72917
  console.info("correction", delta);
72783
72918
  }
@@ -72791,18 +72926,6 @@ focus outline in that case.
72791
72926
  this.notify(false);
72792
72927
  }
72793
72928
  };
72794
- this.measureElement = (node) => {
72795
- if (!node) {
72796
- this.elementsCache.forEach((cached, key) => {
72797
- if (!cached.isConnected) {
72798
- this.observer.unobserve(cached);
72799
- this.elementsCache.delete(key);
72800
- }
72801
- });
72802
- return;
72803
- }
72804
- this._measureElement(node, void 0);
72805
- };
72806
72929
  this.getVirtualItems = memo(
72807
72930
  () => [this.getVirtualIndexes(), this.getMeasurements()],
72808
72931
  (indexes, measurements) => {
@@ -72859,12 +72982,10 @@ focus outline in that case.
72859
72982
  };
72860
72983
  this.getOffsetForIndex = (index, align = "auto") => {
72861
72984
  index = Math.max(0, Math.min(index, this.options.count - 1));
72862
- const item = this.measurementsCache[index];
72863
- if (!item) {
72864
- return void 0;
72865
- }
72866
72985
  const size = this.getSize();
72867
72986
  const scrollOffset = this.getScrollOffset();
72987
+ const item = this.measurementsCache[index];
72988
+ if (!item) return;
72868
72989
  if (align === "auto") {
72869
72990
  if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
72870
72991
  align = "end";
@@ -72883,85 +73004,55 @@ focus outline in that case.
72883
73004
  align
72884
73005
  ];
72885
73006
  };
72886
- this.isDynamicMode = () => this.elementsCache.size > 0;
72887
- this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
72888
- if (behavior === "smooth" && this.isDynamicMode()) {
72889
- console.warn(
72890
- "The `smooth` scroll behavior is not fully supported with dynamic size."
72891
- );
72892
- }
72893
- this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
72894
- adjustments: void 0,
72895
- behavior
72896
- });
73007
+ this.scrollToOffset = (toOffset, { align = "start", behavior = "auto" } = {}) => {
73008
+ const offset = this.getOffsetForAlignment(toOffset, align);
73009
+ const now = this.now();
73010
+ this.scrollState = {
73011
+ index: null,
73012
+ align,
73013
+ behavior,
73014
+ startedAt: now,
73015
+ lastTargetOffset: offset,
73016
+ stableFrames: 0
73017
+ };
73018
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
73019
+ this.scheduleScrollReconcile();
72897
73020
  };
72898
- this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
72899
- if (behavior === "smooth" && this.isDynamicMode()) {
72900
- console.warn(
72901
- "The `smooth` scroll behavior is not fully supported with dynamic size."
72902
- );
72903
- }
73021
+ this.scrollToIndex = (index, {
73022
+ align: initialAlign = "auto",
73023
+ behavior = "auto"
73024
+ } = {}) => {
72904
73025
  index = Math.max(0, Math.min(index, this.options.count - 1));
72905
- this.currentScrollToIndex = index;
72906
- let attempts = 0;
72907
- const maxAttempts = 10;
72908
- const tryScroll = (currentAlign) => {
72909
- if (!this.targetWindow) return;
72910
- const offsetInfo = this.getOffsetForIndex(index, currentAlign);
72911
- if (!offsetInfo) {
72912
- console.warn("Failed to get offset for index:", index);
72913
- return;
72914
- }
72915
- const [offset, align] = offsetInfo;
72916
- this._scrollToOffset(offset, { adjustments: void 0, behavior });
72917
- this.targetWindow.requestAnimationFrame(() => {
72918
- if (!this.targetWindow) return;
72919
- const verify = () => {
72920
- if (this.currentScrollToIndex !== index) return;
72921
- const currentOffset = this.getScrollOffset();
72922
- const afterInfo = this.getOffsetForIndex(index, align);
72923
- if (!afterInfo) {
72924
- console.warn("Failed to get offset for index:", index);
72925
- return;
72926
- }
72927
- if (!approxEqual(afterInfo[0], currentOffset)) {
72928
- scheduleRetry(align);
72929
- }
72930
- };
72931
- if (this.isDynamicMode()) {
72932
- this.targetWindow.requestAnimationFrame(verify);
72933
- } else {
72934
- verify();
72935
- }
72936
- });
72937
- };
72938
- const scheduleRetry = (align) => {
72939
- if (!this.targetWindow) return;
72940
- if (this.currentScrollToIndex !== index) return;
72941
- attempts++;
72942
- if (attempts < maxAttempts) {
72943
- if (this.options.debug) {
72944
- console.info("Schedule retry", attempts, maxAttempts);
72945
- }
72946
- this.targetWindow.requestAnimationFrame(() => tryScroll(align));
72947
- } else {
72948
- console.warn(
72949
- `Failed to scroll to index ${index} after ${maxAttempts} attempts.`
72950
- );
72951
- }
73026
+ const offsetInfo = this.getOffsetForIndex(index, initialAlign);
73027
+ if (!offsetInfo) {
73028
+ return;
73029
+ }
73030
+ const [offset, align] = offsetInfo;
73031
+ const now = this.now();
73032
+ this.scrollState = {
73033
+ index,
73034
+ align,
73035
+ behavior,
73036
+ startedAt: now,
73037
+ lastTargetOffset: offset,
73038
+ stableFrames: 0
72952
73039
  };
72953
- tryScroll(initialAlign);
73040
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
73041
+ this.scheduleScrollReconcile();
72954
73042
  };
72955
- this.scrollBy = (delta, { behavior } = {}) => {
72956
- if (behavior === "smooth" && this.isDynamicMode()) {
72957
- console.warn(
72958
- "The `smooth` scroll behavior is not fully supported with dynamic size."
72959
- );
72960
- }
72961
- this._scrollToOffset(this.getScrollOffset() + delta, {
72962
- adjustments: void 0,
72963
- behavior
72964
- });
73043
+ this.scrollBy = (delta, { behavior = "auto" } = {}) => {
73044
+ const offset = this.getScrollOffset() + delta;
73045
+ const now = this.now();
73046
+ this.scrollState = {
73047
+ index: null,
73048
+ align: "start",
73049
+ behavior,
73050
+ startedAt: now,
73051
+ lastTargetOffset: offset,
73052
+ stableFrames: 0
73053
+ };
73054
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
73055
+ this.scheduleScrollReconcile();
72965
73056
  };
72966
73057
  this.getTotalSize = () => {
72967
73058
  var _a;
@@ -73001,6 +73092,49 @@ focus outline in that case.
73001
73092
  };
73002
73093
  this.setOptions(opts);
73003
73094
  }
73095
+ scheduleScrollReconcile() {
73096
+ if (!this.targetWindow) {
73097
+ this.scrollState = null;
73098
+ return;
73099
+ }
73100
+ if (this.rafId != null) return;
73101
+ this.rafId = this.targetWindow.requestAnimationFrame(() => {
73102
+ this.rafId = null;
73103
+ this.reconcileScroll();
73104
+ });
73105
+ }
73106
+ reconcileScroll() {
73107
+ if (!this.scrollState) return;
73108
+ const el = this.scrollElement;
73109
+ if (!el) return;
73110
+ const MAX_RECONCILE_MS = 5e3;
73111
+ if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {
73112
+ this.scrollState = null;
73113
+ return;
73114
+ }
73115
+ const offsetInfo = this.scrollState.index != null ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align) : void 0;
73116
+ const targetOffset = offsetInfo ? offsetInfo[0] : this.scrollState.lastTargetOffset;
73117
+ const STABLE_FRAMES = 1;
73118
+ const targetChanged = targetOffset !== this.scrollState.lastTargetOffset;
73119
+ if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {
73120
+ this.scrollState.stableFrames++;
73121
+ if (this.scrollState.stableFrames >= STABLE_FRAMES) {
73122
+ this.scrollState = null;
73123
+ return;
73124
+ }
73125
+ } else {
73126
+ this.scrollState.stableFrames = 0;
73127
+ if (targetChanged) {
73128
+ this.scrollState.lastTargetOffset = targetOffset;
73129
+ this.scrollState.behavior = "auto";
73130
+ this._scrollToOffset(targetOffset, {
73131
+ adjustments: void 0,
73132
+ behavior: "auto"
73133
+ });
73134
+ }
73135
+ }
73136
+ this.scheduleScrollReconcile();
73137
+ }
73004
73138
  };
73005
73139
  const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
73006
73140
  while (low <= high) {
@@ -98215,6 +98349,7 @@ focus outline in that case.
98215
98349
  textAreaInputHandler() {
98216
98350
  this.value = this.textArea.value;
98217
98351
  this.isInputEmpty = this.shouldDisableSendButton();
98352
+ this.adjustTextAreaHeight();
98218
98353
  this.queueUpdateScrollbarWidth();
98219
98354
  }
98220
98355
  // If a property can affect whether a scrollbar is visible, we need to
@@ -98236,6 +98371,7 @@ focus outline in that case.
98236
98371
  if (this.textArea) {
98237
98372
  this.textArea.value = this.value;
98238
98373
  this.isInputEmpty = this.shouldDisableSendButton();
98374
+ this.adjustTextAreaHeight();
98239
98375
  this.queueUpdateScrollbarWidth();
98240
98376
  }
98241
98377
  }
@@ -98246,6 +98382,7 @@ focus outline in that case.
98246
98382
  super.connectedCallback();
98247
98383
  this.textArea.value = this.value;
98248
98384
  this.isInputEmpty = this.shouldDisableSendButton();
98385
+ this.adjustTextAreaHeight();
98249
98386
  this.resizeObserver = new ResizeObserver(() => this.onResize());
98250
98387
  this.resizeObserver.observe(this);
98251
98388
  }
@@ -98287,10 +98424,12 @@ focus outline in that case.
98287
98424
  this.isInputEmpty = true;
98288
98425
  if (this.textArea) {
98289
98426
  this.textArea.value = '';
98427
+ this.adjustTextAreaHeight();
98290
98428
  this.textArea.focus();
98291
98429
  }
98292
98430
  }
98293
98431
  onResize() {
98432
+ this.adjustTextAreaHeight();
98294
98433
  this.scrollbarWidth = this.textArea.offsetWidth - this.textArea.clientWidth;
98295
98434
  }
98296
98435
  queueUpdateScrollbarWidth() {
@@ -98302,11 +98441,22 @@ focus outline in that case.
98302
98441
  DOM.queueUpdate(() => this.updateScrollbarWidth());
98303
98442
  }
98304
98443
  }
98444
+ // Workaround for browsers that do not support the CSS property `field-sizing: content`
98445
+ // See https://github.com/ni/nimble/issues/2902
98446
+ adjustTextAreaHeight() {
98447
+ if (ChatInput.fieldSizingSupported || !this.textArea) {
98448
+ return;
98449
+ }
98450
+ const textArea = this.textArea;
98451
+ textArea.style.height = 'auto';
98452
+ textArea.style.height = `${textArea.scrollHeight}px`;
98453
+ }
98305
98454
  updateScrollbarWidth() {
98306
98455
  this.updateScrollbarWidthQueued = false;
98307
98456
  this.scrollbarWidth = this.textArea.offsetWidth - this.textArea.clientWidth;
98308
98457
  }
98309
98458
  }
98459
+ ChatInput.fieldSizingSupported = CSS.supports('field-sizing', 'content');
98310
98460
  __decorate([
98311
98461
  attr
98312
98462
  ], ChatInput.prototype, "placeholder", void 0);