@nmakarov/cli-toolkit 0.81.0 → 0.82.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.
package/dist/screen.js CHANGED
@@ -984,8 +984,45 @@ function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {
984
984
  return { scrollTop: next, following: isScrolledToBottom(next, max) };
985
985
  }
986
986
 
987
- // src/screen/scrollable-text.js
988
- var h5 = createElement2;
987
+ // src/screen/visible-text.js
988
+ var ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
989
+ function stripAnsi(text) {
990
+ return String(text ?? "").replace(ANSI_RE, "");
991
+ }
992
+ function visibleWidth(text) {
993
+ return [...stripAnsi(text)].length;
994
+ }
995
+ function sliceVisible(text, cols) {
996
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
997
+ const s = String(text ?? "");
998
+ if (w === 0) return "";
999
+ let vis = 0;
1000
+ let out = "";
1001
+ let i = 0;
1002
+ while (i < s.length && vis < w) {
1003
+ ANSI_RE.lastIndex = i;
1004
+ const m = ANSI_RE.exec(s);
1005
+ if (m && m.index === i) {
1006
+ out += m[0];
1007
+ i += m[0].length;
1008
+ continue;
1009
+ }
1010
+ const cp = s.codePointAt(i);
1011
+ const ch = String.fromCodePoint(cp);
1012
+ out += ch;
1013
+ i += ch.length;
1014
+ vis += 1;
1015
+ }
1016
+ return out;
1017
+ }
1018
+ function padEndVisible(text, cols) {
1019
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1020
+ const s = String(text ?? "");
1021
+ const vis = visibleWidth(s);
1022
+ if (vis === w) return s;
1023
+ if (vis > w) return sliceVisible(s, w);
1024
+ return s + " ".repeat(w - vis);
1025
+ }
989
1026
  function wrapTextLines(text, cols) {
990
1027
  const w = Math.max(1, Math.floor(Number(cols) || 1));
991
1028
  const out = [];
@@ -994,20 +1031,23 @@ function wrapTextLines(text, cols) {
994
1031
  out.push("");
995
1032
  continue;
996
1033
  }
1034
+ if (visibleWidth(raw) <= w) {
1035
+ out.push(raw);
1036
+ continue;
1037
+ }
997
1038
  let rest = raw;
998
- while (rest.length > w) {
999
- out.push(rest.slice(0, w));
1000
- rest = rest.slice(w);
1039
+ while (visibleWidth(rest) > w) {
1040
+ const head = sliceVisible(rest, w);
1041
+ out.push(head);
1042
+ rest = rest.slice(head.length);
1001
1043
  }
1002
1044
  if (rest.length > 0) out.push(rest);
1003
1045
  }
1004
1046
  return out;
1005
1047
  }
1006
- function padEndVisible(s, w) {
1007
- const t = String(s ?? "");
1008
- if (t.length >= w) return t.slice(0, w);
1009
- return t + " ".repeat(w - t.length);
1010
- }
1048
+
1049
+ // src/screen/scrollable-text.js
1050
+ var h5 = createElement2;
1011
1051
  var SCROLL_KEYS = [
1012
1052
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
1013
1053
  { key: "downArrow", caption: "scroll", action: "scrollDown", order: 0 },
@@ -1080,14 +1120,17 @@ function ScrollableText({
1080
1120
  }, [ctx, bindKeys, followBottom]);
1081
1121
  const status = allLines.length === 0 ? "empty" : `lines ${clamped + 1}-${Math.min(clamped + visible.length, allLines.length)} of ${allLines.length}` + (needsBar ? " \xB7 \u2325\u2191/\u2193 or PgUp/Dn page" : "") + (followBottom && following ? " \xB7 follow" : followBottom ? " \xB7 follow off" : "");
1082
1122
  const rowNodes = visible.map((line, i) => {
1083
- const body = padEndVisible(line, textWidth);
1084
1123
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1085
1124
  const isThumb = glyph === BAR_THUMB;
1086
1125
  return h5(
1087
- Text5,
1088
- { key: `L${clamped + i}` },
1089
- body,
1090
- glyph ? h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph) : null
1126
+ Box4,
1127
+ { key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1128
+ h5(
1129
+ Box4,
1130
+ { width: textWidth, flexShrink: 0 },
1131
+ h5(Text5, { wrap: "truncate" }, padEndVisible(line, textWidth))
1132
+ ),
1133
+ showScrollbar ? h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
1091
1134
  );
1092
1135
  });
1093
1136
  if (bar && visible.length < viewportRows) {
@@ -1095,10 +1138,10 @@ function ScrollableText({
1095
1138
  const glyph = bar[i] ?? BAR_TRACK;
1096
1139
  rowNodes.push(
1097
1140
  h5(
1098
- Text5,
1099
- { key: `pad${i}` },
1100
- padEndVisible("", textWidth),
1101
- h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
1141
+ Box4,
1142
+ { key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1143
+ h5(Box4, { width: textWidth, flexShrink: 0 }, h5(Text5, {}, padEndVisible("", textWidth))),
1144
+ h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
1102
1145
  )
1103
1146
  );
1104
1147
  }
@@ -1283,6 +1326,7 @@ export {
1283
1326
  nextScrollAfterContentChange,
1284
1327
  nextScrollAfterUserMove,
1285
1328
  organizeFooterMessages,
1329
+ padEndVisible,
1286
1330
  scrollbarGlyphs,
1287
1331
  showListScreen,
1288
1332
  showMenuScreen,
@@ -1290,6 +1334,8 @@ export {
1290
1334
  showMultiColumnListWithPreviewScreen,
1291
1335
  showScreen,
1292
1336
  showWordGridScreen,
1337
+ sliceVisible,
1338
+ stripAnsi,
1293
1339
  useCallback,
1294
1340
  useEffect3 as useEffect,
1295
1341
  useInput2 as useInput,
@@ -1297,6 +1343,7 @@ export {
1297
1343
  useMemo2 as useMemo,
1298
1344
  useRef3 as useRef,
1299
1345
  useState4 as useState,
1346
+ visibleWidth,
1300
1347
  wrapTextLines
1301
1348
  };
1302
1349
  //# sourceMappingURL=screen.js.map