restty 0.1.15 → 0.1.16

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.
package/dist/app/index.js CHANGED
@@ -50359,6 +50359,9 @@ function createResttyApp(options) {
50359
50359
  const touchSelectionMode = normalizeTouchSelectionMode(options.touchSelectionMode);
50360
50360
  const touchSelectionLongPressMs = clampFiniteNumber(options.touchSelectionLongPressMs, 450, 120, 2000, true);
50361
50361
  const touchSelectionMoveThresholdPx = clampFiniteNumber(options.touchSelectionMoveThresholdPx, 10, 1, 64);
50362
+ const hasCoarsePointer = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(any-pointer: coarse)").matches;
50363
+ const hasTouchPoints = typeof navigator !== "undefined" && navigator.maxTouchPoints > 0;
50364
+ const showOverlayScrollbar = !(hasCoarsePointer || hasTouchPoints);
50362
50365
  const nerdIconScale = Number.isFinite(options.nerdIconScale) ? Number(options.nerdIconScale) : 1;
50363
50366
  const alphaBlending = options.alphaBlending ?? "linear-corrected";
50364
50367
  const srgbChannelToLinear = (c3) => c3 <= 0.04045 ? c3 / 12.92 : Math.pow((c3 + 0.055) / 1.055, 2.4);
@@ -50563,9 +50566,12 @@ function createResttyApp(options) {
50563
50566
  const touchSelectionState = {
50564
50567
  pendingPointerId: null,
50565
50568
  activePointerId: null,
50569
+ panPointerId: null,
50566
50570
  pendingCell: null,
50571
+ pendingStartedAt: 0,
50567
50572
  pendingStartX: 0,
50568
50573
  pendingStartY: 0,
50574
+ panLastY: 0,
50569
50575
  pendingTimer: 0
50570
50576
  };
50571
50577
  const linkState = {
@@ -50579,6 +50585,10 @@ function createResttyApp(options) {
50579
50585
  lastOffset: 0,
50580
50586
  lastLen: 0
50581
50587
  };
50588
+ const scrollbarDragState = {
50589
+ pointerId: null,
50590
+ thumbGrabRatio: 0.5
50591
+ };
50582
50592
  const KITTY_FLAG_REPORT_EVENTS2 = 1 << 1;
50583
50593
  function updateCanvasCursor() {
50584
50594
  if (!canvas)
@@ -50599,6 +50609,21 @@ function createResttyApp(options) {
50599
50609
  }
50600
50610
  touchSelectionState.pendingPointerId = null;
50601
50611
  touchSelectionState.pendingCell = null;
50612
+ touchSelectionState.pendingStartedAt = 0;
50613
+ }
50614
+ function tryActivatePendingTouchSelection(pointerId) {
50615
+ if (touchSelectionMode !== "long-press")
50616
+ return false;
50617
+ if (touchSelectionState.pendingPointerId !== pointerId || !touchSelectionState.pendingCell) {
50618
+ return false;
50619
+ }
50620
+ if (performance.now() - touchSelectionState.pendingStartedAt < touchSelectionLongPressMs) {
50621
+ return false;
50622
+ }
50623
+ const pendingCell = touchSelectionState.pendingCell;
50624
+ clearPendingTouchSelection();
50625
+ beginSelectionDrag(pendingCell, pointerId);
50626
+ return true;
50602
50627
  }
50603
50628
  function beginSelectionDrag(cell, pointerId) {
50604
50629
  selectionState.active = true;
@@ -50606,6 +50631,7 @@ function createResttyApp(options) {
50606
50631
  selectionState.anchor = cell;
50607
50632
  selectionState.focus = cell;
50608
50633
  touchSelectionState.activePointerId = pointerId;
50634
+ touchSelectionState.panPointerId = null;
50609
50635
  canvas.setPointerCapture?.(pointerId);
50610
50636
  updateCanvasCursor();
50611
50637
  needsRender = true;
@@ -50613,6 +50639,160 @@ function createResttyApp(options) {
50613
50639
  function noteScrollActivity() {
50614
50640
  scrollbarState.lastInputAt = performance.now();
50615
50641
  }
50642
+ function getViewportScrollOffset() {
50643
+ if (!wasmHandle || !wasmExports?.restty_scrollbar_offset)
50644
+ return 0;
50645
+ return wasmExports.restty_scrollbar_offset(wasmHandle) || 0;
50646
+ }
50647
+ function shiftSelectionByRows(deltaRows) {
50648
+ if (!deltaRows)
50649
+ return;
50650
+ if (!selectionState.active && !selectionState.dragging)
50651
+ return;
50652
+ if (!selectionState.anchor || !selectionState.focus)
50653
+ return;
50654
+ const maxAbs = Math.max(1024, (gridState.rows || 24) * 128);
50655
+ selectionState.anchor = {
50656
+ row: clamp(selectionState.anchor.row + deltaRows, -maxAbs, maxAbs),
50657
+ col: selectionState.anchor.col
50658
+ };
50659
+ selectionState.focus = {
50660
+ row: clamp(selectionState.focus.row + deltaRows, -maxAbs, maxAbs),
50661
+ col: selectionState.focus.col
50662
+ };
50663
+ needsRender = true;
50664
+ }
50665
+ function scrollViewportByLines(lines) {
50666
+ if (!wasmReady || !wasmHandle || !gridState.cellH)
50667
+ return;
50668
+ scrollRemainder += lines;
50669
+ const delta = Math.trunc(scrollRemainder);
50670
+ scrollRemainder -= delta;
50671
+ if (!delta)
50672
+ return;
50673
+ const beforeOffset = getViewportScrollOffset();
50674
+ wasm.scrollViewport(wasmHandle, delta);
50675
+ const afterOffset = getViewportScrollOffset();
50676
+ shiftSelectionByRows(beforeOffset - afterOffset);
50677
+ if (linkState.hoverId)
50678
+ updateLinkHover(null);
50679
+ wasm.renderUpdate(wasmHandle);
50680
+ needsRender = true;
50681
+ noteScrollActivity();
50682
+ }
50683
+ function setViewportScrollOffset(nextOffset) {
50684
+ if (!wasmReady || !wasmHandle || !wasmExports?.restty_scrollbar_total)
50685
+ return;
50686
+ const total = wasmExports.restty_scrollbar_total(wasmHandle) || 0;
50687
+ const len = wasmExports.restty_scrollbar_len ? wasmExports.restty_scrollbar_len(wasmHandle) : 0;
50688
+ const current = wasmExports.restty_scrollbar_offset ? wasmExports.restty_scrollbar_offset(wasmHandle) : 0;
50689
+ const maxOffset = Math.max(0, total - len);
50690
+ const clamped = clamp(Math.round(nextOffset), 0, maxOffset);
50691
+ const delta = clamped - current;
50692
+ if (!delta)
50693
+ return;
50694
+ const beforeOffset = getViewportScrollOffset();
50695
+ wasm.scrollViewport(wasmHandle, delta);
50696
+ const afterOffset = getViewportScrollOffset();
50697
+ shiftSelectionByRows(beforeOffset - afterOffset);
50698
+ if (linkState.hoverId)
50699
+ updateLinkHover(null);
50700
+ wasm.renderUpdate(wasmHandle);
50701
+ needsRender = true;
50702
+ noteScrollActivity();
50703
+ }
50704
+ function pointerToCanvasPx(event) {
50705
+ const rect = canvas.getBoundingClientRect();
50706
+ const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
50707
+ const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
50708
+ return {
50709
+ x: (event.clientX - rect.left) * scaleX,
50710
+ y: (event.clientY - rect.top) * scaleY
50711
+ };
50712
+ }
50713
+ function computeOverlayScrollbarLayout(rows, cellW, cellH, total, offset, len) {
50714
+ if (!(total > len && len > 0))
50715
+ return null;
50716
+ const trackHeight = rows * cellH;
50717
+ const width = Math.max(10, Math.round(cellW * 0.9));
50718
+ const margin = Math.max(6, Math.round(width * 0.5));
50719
+ const insetY = Math.max(2, Math.round(cellH * 0.2));
50720
+ const trackX = canvas.width - margin - width;
50721
+ const trackY = insetY;
50722
+ const trackH = Math.max(width, trackHeight - insetY * 2);
50723
+ const denom = Math.max(1, total - len);
50724
+ const thumbH = Math.max(width, Math.round(trackH * (len / total)));
50725
+ const thumbY = trackY + Math.round(offset / denom * (trackH - thumbH));
50726
+ return { total, offset, len, denom, width, trackX, trackY, trackH, thumbY, thumbH };
50727
+ }
50728
+ function getOverlayScrollbarLayout() {
50729
+ if (!showOverlayScrollbar || !wasmExports?.restty_scrollbar_total || !wasmHandle)
50730
+ return null;
50731
+ if (!gridState.rows || !gridState.cellW || !gridState.cellH)
50732
+ return null;
50733
+ const total = wasmExports.restty_scrollbar_total(wasmHandle) || 0;
50734
+ const offset = wasmExports.restty_scrollbar_offset ? wasmExports.restty_scrollbar_offset(wasmHandle) : 0;
50735
+ const len = wasmExports.restty_scrollbar_len ? wasmExports.restty_scrollbar_len(wasmHandle) : gridState.rows;
50736
+ return computeOverlayScrollbarLayout(gridState.rows, gridState.cellW, gridState.cellH, total, offset, len);
50737
+ }
50738
+ function isPointInScrollbarHitArea(layout, x3, y) {
50739
+ const hitPadX = Math.max(3, Math.round(layout.width * 0.35));
50740
+ return x3 >= layout.trackX - hitPadX && x3 <= layout.trackX + layout.width + hitPadX && y >= layout.trackY && y <= layout.trackY + layout.trackH;
50741
+ }
50742
+ function isPointInScrollbarThumb(layout, x3, y) {
50743
+ return x3 >= layout.trackX && x3 <= layout.trackX + layout.width && y >= layout.thumbY && y <= layout.thumbY + layout.thumbH;
50744
+ }
50745
+ function scrollbarOffsetForPointerY(layout, pointerY, thumbGrabRatio) {
50746
+ const thumbTop = pointerY - layout.thumbH * thumbGrabRatio;
50747
+ const trackSpan = Math.max(1, layout.trackH - layout.thumbH);
50748
+ const ratio = clamp((thumbTop - layout.trackY) / trackSpan, 0, 1);
50749
+ return Math.round(ratio * layout.denom);
50750
+ }
50751
+ function pushRoundedVerticalBar(out, x3, y, w, h, color) {
50752
+ const x02 = Math.round(x3);
50753
+ const y02 = Math.round(y);
50754
+ const width = Math.max(1, Math.round(w));
50755
+ const height = Math.max(1, Math.round(h));
50756
+ const radius = Math.min(Math.floor(width * 0.5), Math.floor(height * 0.5));
50757
+ if (radius <= 0) {
50758
+ pushRectBox(out, x02, y02, width, height, color);
50759
+ return;
50760
+ }
50761
+ const middleH = height - radius * 2;
50762
+ if (middleH > 0) {
50763
+ pushRectBox(out, x02, y02 + radius, width, middleH, color);
50764
+ }
50765
+ const radiusSq = radius * radius;
50766
+ for (let row = 0;row < radius; row += 1) {
50767
+ const dy = radius - row - 0.5;
50768
+ const inset = Math.max(0, Math.floor(radius - Math.sqrt(Math.max(0, radiusSq - dy * dy))));
50769
+ const rowW = width - inset * 2;
50770
+ if (rowW <= 0)
50771
+ continue;
50772
+ pushRectBox(out, x02 + inset, y02 + row, rowW, 1, color);
50773
+ pushRectBox(out, x02 + inset, y02 + height - 1 - row, rowW, 1, color);
50774
+ }
50775
+ }
50776
+ function appendOverlayScrollbar(overlayData, rows, cellW, cellH, total, offset, len) {
50777
+ if (!showOverlayScrollbar)
50778
+ return;
50779
+ const layout = computeOverlayScrollbarLayout(rows, cellW, cellH, total, offset, len);
50780
+ if (!layout)
50781
+ return;
50782
+ const since = performance.now() - scrollbarState.lastInputAt;
50783
+ const fadeDelay = 160;
50784
+ const fadeDuration = 520;
50785
+ let alpha = 0;
50786
+ if (since < fadeDelay) {
50787
+ alpha = 0.68;
50788
+ } else if (since < fadeDelay + fadeDuration) {
50789
+ alpha = 0.68 * (1 - (since - fadeDelay) / fadeDuration);
50790
+ }
50791
+ if (alpha <= 0.01)
50792
+ return;
50793
+ const thumbColor = [0.96, 0.96, 0.96, alpha * 0.75];
50794
+ pushRoundedVerticalBar(overlayData, layout.trackX, layout.thumbY, layout.width, layout.thumbH, thumbColor);
50795
+ }
50616
50796
  function releaseKittyImage(entry) {
50617
50797
  const source = entry?.source;
50618
50798
  if (source && typeof source.close === "function") {
@@ -51424,8 +51604,25 @@ function createResttyApp(options) {
51424
51604
  function bindCanvasEvents() {
51425
51605
  if (!attachCanvasEvents)
51426
51606
  return;
51427
- canvas.style.touchAction = touchSelectionMode === "drag" ? "none" : "pan-y pinch-zoom";
51607
+ canvas.style.touchAction = touchSelectionMode === "long-press" || touchSelectionMode === "drag" ? "none" : "pan-y pinch-zoom";
51428
51608
  const onPointerDown = (event) => {
51609
+ if (!isTouchPointer(event) && event.button === 0) {
51610
+ const layout = getOverlayScrollbarLayout();
51611
+ if (layout) {
51612
+ const point = pointerToCanvasPx(event);
51613
+ if (isPointInScrollbarHitArea(layout, point.x, point.y)) {
51614
+ event.preventDefault();
51615
+ noteScrollActivity();
51616
+ const hitThumb = isPointInScrollbarThumb(layout, point.x, point.y);
51617
+ scrollbarDragState.pointerId = event.pointerId;
51618
+ scrollbarDragState.thumbGrabRatio = hitThumb ? clamp((point.y - layout.thumbY) / Math.max(1, layout.thumbH), 0, 1) : 0.5;
51619
+ const targetOffset = scrollbarOffsetForPointerY(layout, point.y, scrollbarDragState.thumbGrabRatio);
51620
+ setViewportScrollOffset(targetOffset);
51621
+ canvas.setPointerCapture?.(event.pointerId);
51622
+ return;
51623
+ }
51624
+ }
51625
+ }
51429
51626
  if (inputHandler.sendMouseEvent("down", event)) {
51430
51627
  event.preventDefault();
51431
51628
  canvas.setPointerCapture?.(event.pointerId);
@@ -51436,6 +51633,7 @@ function createResttyApp(options) {
51436
51633
  return;
51437
51634
  const cell2 = normalizeSelectionCell(positionToCell(event));
51438
51635
  touchSelectionState.activePointerId = null;
51636
+ touchSelectionState.panPointerId = null;
51439
51637
  if (touchSelectionMode === "off")
51440
51638
  return;
51441
51639
  if (touchSelectionMode === "drag") {
@@ -51446,15 +51644,13 @@ function createResttyApp(options) {
51446
51644
  clearPendingTouchSelection();
51447
51645
  touchSelectionState.pendingPointerId = event.pointerId;
51448
51646
  touchSelectionState.pendingCell = cell2;
51647
+ touchSelectionState.pendingStartedAt = performance.now();
51449
51648
  touchSelectionState.pendingStartX = event.clientX;
51450
51649
  touchSelectionState.pendingStartY = event.clientY;
51650
+ touchSelectionState.panPointerId = event.pointerId;
51651
+ touchSelectionState.panLastY = event.clientY;
51451
51652
  touchSelectionState.pendingTimer = setTimeout(() => {
51452
- if (touchSelectionState.pendingPointerId !== event.pointerId || !touchSelectionState.pendingCell) {
51453
- return;
51454
- }
51455
- const pendingCell = touchSelectionState.pendingCell;
51456
- clearPendingTouchSelection();
51457
- beginSelectionDrag(pendingCell, event.pointerId);
51653
+ tryActivatePendingTouchSelection(event.pointerId);
51458
51654
  }, touchSelectionLongPressMs);
51459
51655
  return;
51460
51656
  }
@@ -51466,6 +51662,18 @@ function createResttyApp(options) {
51466
51662
  beginSelectionDrag(cell, event.pointerId);
51467
51663
  };
51468
51664
  const onPointerMove = (event) => {
51665
+ if (scrollbarDragState.pointerId === event.pointerId) {
51666
+ const layout = getOverlayScrollbarLayout();
51667
+ if (!layout) {
51668
+ scrollbarDragState.pointerId = null;
51669
+ return;
51670
+ }
51671
+ const point = pointerToCanvasPx(event);
51672
+ const targetOffset = scrollbarOffsetForPointerY(layout, point.y, scrollbarDragState.thumbGrabRatio);
51673
+ setViewportScrollOffset(targetOffset);
51674
+ event.preventDefault();
51675
+ return;
51676
+ }
51469
51677
  if (inputHandler.sendMouseEvent("move", event)) {
51470
51678
  event.preventDefault();
51471
51679
  return;
@@ -51476,8 +51684,18 @@ function createResttyApp(options) {
51476
51684
  const dy = event.clientY - touchSelectionState.pendingStartY;
51477
51685
  if (dx * dx + dy * dy >= touchSelectionMoveThresholdPx * touchSelectionMoveThresholdPx) {
51478
51686
  clearPendingTouchSelection();
51687
+ } else {
51688
+ tryActivatePendingTouchSelection(event.pointerId);
51689
+ }
51690
+ if (touchSelectionState.pendingPointerId === event.pointerId) {
51691
+ if (touchSelectionMode === "long-press" && touchSelectionState.panPointerId === event.pointerId) {
51692
+ const deltaPx = touchSelectionState.panLastY - event.clientY;
51693
+ touchSelectionState.panLastY = event.clientY;
51694
+ scrollViewportByLines(deltaPx / Math.max(1, gridState.cellH) * 1.5);
51695
+ event.preventDefault();
51696
+ }
51697
+ return;
51479
51698
  }
51480
- return;
51481
51699
  }
51482
51700
  if (selectionState.dragging && touchSelectionState.activePointerId === event.pointerId) {
51483
51701
  const cell2 = normalizeSelectionCell(positionToCell(event));
@@ -51486,6 +51704,13 @@ function createResttyApp(options) {
51486
51704
  updateLinkHover(null);
51487
51705
  updateCanvasCursor();
51488
51706
  needsRender = true;
51707
+ return;
51708
+ }
51709
+ if (touchSelectionMode === "long-press" && touchSelectionState.panPointerId === event.pointerId) {
51710
+ const deltaPx = touchSelectionState.panLastY - event.clientY;
51711
+ touchSelectionState.panLastY = event.clientY;
51712
+ scrollViewportByLines(deltaPx / Math.max(1, gridState.cellH) * 1.5);
51713
+ event.preventDefault();
51489
51714
  }
51490
51715
  return;
51491
51716
  }
@@ -51501,6 +51726,11 @@ function createResttyApp(options) {
51501
51726
  needsRender = true;
51502
51727
  };
51503
51728
  const onPointerUp = (event) => {
51729
+ if (scrollbarDragState.pointerId === event.pointerId) {
51730
+ scrollbarDragState.pointerId = null;
51731
+ event.preventDefault();
51732
+ return;
51733
+ }
51504
51734
  if (inputHandler.sendMouseEvent("up", event)) {
51505
51735
  event.preventDefault();
51506
51736
  return;
@@ -51509,6 +51739,7 @@ function createResttyApp(options) {
51509
51739
  if (touchSelectionState.pendingPointerId === event.pointerId) {
51510
51740
  clearPendingTouchSelection();
51511
51741
  touchSelectionState.activePointerId = null;
51742
+ touchSelectionState.panPointerId = null;
51512
51743
  return;
51513
51744
  }
51514
51745
  if (selectionState.dragging && touchSelectionState.activePointerId === event.pointerId) {
@@ -51523,6 +51754,10 @@ function createResttyApp(options) {
51523
51754
  updateCanvasCursor();
51524
51755
  needsRender = true;
51525
51756
  }
51757
+ return;
51758
+ }
51759
+ if (touchSelectionState.panPointerId === event.pointerId) {
51760
+ touchSelectionState.panPointerId = null;
51526
51761
  }
51527
51762
  return;
51528
51763
  }
@@ -51540,15 +51775,21 @@ function createResttyApp(options) {
51540
51775
  } else {
51541
51776
  updateLinkHover(cell);
51542
51777
  }
51543
- if (!selectionState.active && event.button === 0 && (event.metaKey || event.ctrlKey) && linkState.hoverUri) {
51778
+ if (!selectionState.active && event.button === 0 && linkState.hoverUri) {
51544
51779
  openLink(linkState.hoverUri);
51545
51780
  }
51546
51781
  };
51547
51782
  const onPointerCancel = (event) => {
51783
+ if (scrollbarDragState.pointerId === event.pointerId) {
51784
+ scrollbarDragState.pointerId = null;
51785
+ }
51548
51786
  if (isTouchPointer(event)) {
51549
51787
  if (touchSelectionState.pendingPointerId === event.pointerId) {
51550
51788
  clearPendingTouchSelection();
51551
51789
  }
51790
+ if (touchSelectionState.panPointerId === event.pointerId) {
51791
+ touchSelectionState.panPointerId = null;
51792
+ }
51552
51793
  if (touchSelectionState.activePointerId === event.pointerId) {
51553
51794
  touchSelectionState.activePointerId = null;
51554
51795
  if (selectionState.dragging) {
@@ -51579,16 +51820,7 @@ function createResttyApp(options) {
51579
51820
  } else {
51580
51821
  lines = event.deltaY / gridState.cellH;
51581
51822
  }
51582
- lines *= speed;
51583
- scrollRemainder += lines;
51584
- const delta = Math.trunc(scrollRemainder);
51585
- scrollRemainder -= delta;
51586
- if (!delta)
51587
- return;
51588
- wasm.scrollViewport(wasmHandle, delta);
51589
- wasm.renderUpdate(wasmHandle);
51590
- needsRender = true;
51591
- noteScrollActivity();
51823
+ scrollViewportByLines(lines * speed);
51592
51824
  event.preventDefault();
51593
51825
  };
51594
51826
  const onContextMenu = (event) => {
@@ -51614,6 +51846,7 @@ function createResttyApp(options) {
51614
51846
  canvas.removeEventListener("wheel", onWheel);
51615
51847
  canvas.removeEventListener("contextmenu", onContextMenu);
51616
51848
  clearPendingTouchSelection();
51849
+ scrollbarDragState.pointerId = null;
51617
51850
  });
51618
51851
  if (imeInput) {
51619
51852
  let suppressNextInput = false;
@@ -53756,7 +53989,9 @@ function createResttyApp(options) {
53756
53989
  const startRow = forward ? a3.row : f.row;
53757
53990
  const endRow = forward ? f.row : a3.row;
53758
53991
  const lines = [];
53759
- for (let row = startRow;row <= endRow; row += 1) {
53992
+ const clampedStartRow = clamp(startRow, 0, rows - 1);
53993
+ const clampedEndRow = clamp(endRow, 0, rows - 1);
53994
+ for (let row = clampedStartRow;row <= clampedEndRow; row += 1) {
53760
53995
  const range = selectionForRow(row, cols);
53761
53996
  if (!range)
53762
53997
  continue;
@@ -53883,8 +54118,6 @@ function createResttyApp(options) {
53883
54118
  graphemeOffset,
53884
54119
  graphemeLen,
53885
54120
  graphemeBuffer,
53886
- selectionStart,
53887
- selectionEnd,
53888
54121
  cursor
53889
54122
  } = render;
53890
54123
  if (!codepoints || !fgBytes)
@@ -54075,13 +54308,9 @@ function createResttyApp(options) {
54075
54308
  for (let row = 0;row < rows; row += 1) {
54076
54309
  const rowY = row * cellH;
54077
54310
  const baseY = rowY + yPad + baselineOffset;
54078
- let selStart = selectionStart ? selectionStart[row] : -1;
54079
- let selEnd = selectionEnd ? selectionEnd[row] : -1;
54080
54311
  const localSel = selectionState.active ? selectionForRow(row, cols) : null;
54081
- if (localSel) {
54082
- selStart = localSel.start;
54083
- selEnd = localSel.end;
54084
- }
54312
+ const selStart = localSel?.start ?? -1;
54313
+ const selEnd = localSel?.end ?? -1;
54085
54314
  if (selStart >= 0 && selEnd > selStart) {
54086
54315
  const start = Math.max(0, selStart);
54087
54316
  const end = Math.min(cols, selEnd);
@@ -54589,36 +54818,8 @@ function createResttyApp(options) {
54589
54818
  scrollbarState.lastTotal = total;
54590
54819
  scrollbarState.lastOffset = offset;
54591
54820
  scrollbarState.lastLen = len;
54592
- noteScrollActivity();
54593
- }
54594
- if (total > len && len > 0) {
54595
- const now = performance.now();
54596
- const since = now - scrollbarState.lastInputAt;
54597
- const fadeDelay = 600;
54598
- const fadeDuration = 700;
54599
- let alpha = 0;
54600
- if (offset > 0) {
54601
- alpha = 0.65;
54602
- } else if (since < fadeDelay) {
54603
- alpha = 0.5;
54604
- } else if (since < fadeDelay + fadeDuration) {
54605
- alpha = 0.5 * (1 - (since - fadeDelay) / fadeDuration);
54606
- }
54607
- if (alpha > 0.01) {
54608
- const trackH = rows * cellH;
54609
- const scrollbarWidth = Math.max(2, Math.round(cellW * 0.12));
54610
- const margin = Math.max(2, Math.round(cellW * 0.2));
54611
- const trackX = canvas.width - margin - scrollbarWidth;
54612
- const trackY = 0;
54613
- const denom = Math.max(1, total - len);
54614
- const thumbH = Math.max(cellH * 1.5, Math.round(trackH * (len / total)));
54615
- const thumbY = Math.round(offset / denom * (trackH - thumbH));
54616
- const thumbColor = [1, 1, 1, alpha * 0.35];
54617
- const trackColor = [1, 1, 1, alpha * 0.08];
54618
- pushRectBox(overlayData, trackX, trackY, scrollbarWidth, trackH, trackColor);
54619
- pushRectBox(overlayData, trackX, thumbY, scrollbarWidth, thumbH, thumbColor);
54620
- }
54621
54821
  }
54822
+ appendOverlayScrollbar(overlayData, rows, cellW, cellH, total, offset, len);
54622
54823
  }
54623
54824
  webgpuUniforms[0] = canvas.width;
54624
54825
  webgpuUniforms[1] = canvas.height;
@@ -54794,8 +54995,6 @@ function createResttyApp(options) {
54794
54995
  graphemeOffset,
54795
54996
  graphemeLen,
54796
54997
  graphemeBuffer,
54797
- selectionStart,
54798
- selectionEnd,
54799
54998
  cursor
54800
54999
  } = render;
54801
55000
  if (!codepoints || !fgBytes) {
@@ -54973,13 +55172,9 @@ function createResttyApp(options) {
54973
55172
  for (let row = 0;row < rows; row += 1) {
54974
55173
  const rowY = row * cellH;
54975
55174
  const baseY = rowY + yPad + baselineOffset;
54976
- let selStart = selectionStart ? selectionStart[row] : -1;
54977
- let selEnd = selectionEnd ? selectionEnd[row] : -1;
54978
55175
  const localSel = selectionState.active ? selectionForRow(row, cols) : null;
54979
- if (localSel) {
54980
- selStart = localSel.start;
54981
- selEnd = localSel.end;
54982
- }
55176
+ const selStart = localSel?.start ?? -1;
55177
+ const selEnd = localSel?.end ?? -1;
54983
55178
  if (selStart >= 0 && selEnd > selStart) {
54984
55179
  const start = Math.max(0, selStart);
54985
55180
  const end = Math.min(cols, selEnd);
@@ -55313,36 +55508,8 @@ function createResttyApp(options) {
55313
55508
  scrollbarState.lastTotal = total;
55314
55509
  scrollbarState.lastOffset = offset;
55315
55510
  scrollbarState.lastLen = len;
55316
- noteScrollActivity();
55317
- }
55318
- if (total > len && len > 0) {
55319
- const now = performance.now();
55320
- const since = now - scrollbarState.lastInputAt;
55321
- const fadeDelay = 600;
55322
- const fadeDuration = 700;
55323
- let alpha = 0;
55324
- if (offset > 0) {
55325
- alpha = 0.65;
55326
- } else if (since < fadeDelay) {
55327
- alpha = 0.5;
55328
- } else if (since < fadeDelay + fadeDuration) {
55329
- alpha = 0.5 * (1 - (since - fadeDelay) / fadeDuration);
55330
- }
55331
- if (alpha > 0.01) {
55332
- const trackH = rows * cellH;
55333
- const scrollbarWidth = Math.max(2, Math.round(cellW * 0.12));
55334
- const margin = Math.max(2, Math.round(cellW * 0.2));
55335
- const trackX = canvas.width - margin - scrollbarWidth;
55336
- const trackY = 0;
55337
- const denom = Math.max(1, total - len);
55338
- const thumbH = Math.max(cellH * 1.5, Math.round(trackH * (len / total)));
55339
- const thumbY = Math.round(offset / denom * (trackH - thumbH));
55340
- const thumbColor = [1, 1, 1, alpha * 0.35];
55341
- const trackColor = [1, 1, 1, alpha * 0.08];
55342
- pushRectBox(overlayData, trackX, trackY, scrollbarWidth, trackH, trackColor);
55343
- pushRectBox(overlayData, trackX, thumbY, scrollbarWidth, thumbH, thumbColor);
55344
- }
55345
55511
  }
55512
+ appendOverlayScrollbar(overlayData, rows, cellW, cellH, total, offset, len);
55346
55513
  }
55347
55514
  for (const [fontIndex, neededIds] of neededGlyphIdsByFont.entries()) {
55348
55515
  const fontEntry = fontState.fonts[fontIndex];
@@ -55718,9 +55885,11 @@ function createResttyApp(options) {
55718
55885
  }
55719
55886
  appendLog(`[key] ${JSON.stringify(normalized)}${before}`);
55720
55887
  }
55721
- if (source === "key" && selectionState.active) {
55888
+ if (source !== "program" && (selectionState.active || selectionState.dragging)) {
55722
55889
  clearSelection();
55723
55890
  }
55891
+ if (source === "pty" && linkState.hoverId)
55892
+ updateLinkHover(null);
55724
55893
  writeToWasm(wasmHandle, normalized);
55725
55894
  flushWasmOutputToPty();
55726
55895
  if (source === "pty" && inputHandler?.isSynchronizedOutput?.()) {