@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.cjs CHANGED
@@ -65,6 +65,7 @@ __export(screen_exports, {
65
65
  nextScrollAfterContentChange: () => nextScrollAfterContentChange,
66
66
  nextScrollAfterUserMove: () => nextScrollAfterUserMove,
67
67
  organizeFooterMessages: () => organizeFooterMessages,
68
+ padEndVisible: () => padEndVisible,
68
69
  scrollbarGlyphs: () => scrollbarGlyphs,
69
70
  showListScreen: () => showListScreen,
70
71
  showMenuScreen: () => showMenuScreen,
@@ -72,6 +73,8 @@ __export(screen_exports, {
72
73
  showMultiColumnListWithPreviewScreen: () => showMultiColumnListWithPreviewScreen,
73
74
  showScreen: () => showScreen,
74
75
  showWordGridScreen: () => showWordGridScreen,
76
+ sliceVisible: () => sliceVisible,
77
+ stripAnsi: () => stripAnsi,
75
78
  useCallback: () => import_react6.useCallback,
76
79
  useEffect: () => import_react6.useEffect,
77
80
  useInput: () => import_ink6.useInput,
@@ -79,6 +82,7 @@ __export(screen_exports, {
79
82
  useMemo: () => import_react6.useMemo,
80
83
  useRef: () => import_react6.useRef,
81
84
  useState: () => import_react6.useState,
85
+ visibleWidth: () => visibleWidth,
82
86
  wrapTextLines: () => wrapTextLines
83
87
  });
84
88
  module.exports = __toCommonJS(screen_exports);
@@ -1067,8 +1071,45 @@ function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {
1067
1071
  return { scrollTop: next, following: isScrolledToBottom(next, max) };
1068
1072
  }
1069
1073
 
1070
- // src/screen/scrollable-text.js
1071
- // Removed: intermediate assignment - code will access import variable directly
1074
+ // src/screen/visible-text.js
1075
+ var ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
1076
+ function stripAnsi(text) {
1077
+ return String(text ?? "").replace(ANSI_RE, "");
1078
+ }
1079
+ function visibleWidth(text) {
1080
+ return [...stripAnsi(text)].length;
1081
+ }
1082
+ function sliceVisible(text, cols) {
1083
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1084
+ const s = String(text ?? "");
1085
+ if (w === 0) return "";
1086
+ let vis = 0;
1087
+ let out = "";
1088
+ let i = 0;
1089
+ while (i < s.length && vis < w) {
1090
+ ANSI_RE.lastIndex = i;
1091
+ const m = ANSI_RE.exec(s);
1092
+ if (m && m.index === i) {
1093
+ out += m[0];
1094
+ i += m[0].length;
1095
+ continue;
1096
+ }
1097
+ const cp = s.codePointAt(i);
1098
+ const ch = String.fromCodePoint(cp);
1099
+ out += ch;
1100
+ i += ch.length;
1101
+ vis += 1;
1102
+ }
1103
+ return out;
1104
+ }
1105
+ function padEndVisible(text, cols) {
1106
+ const w = Math.max(0, Math.floor(Number(cols) || 0));
1107
+ const s = String(text ?? "");
1108
+ const vis = visibleWidth(s);
1109
+ if (vis === w) return s;
1110
+ if (vis > w) return sliceVisible(s, w);
1111
+ return s + " ".repeat(w - vis);
1112
+ }
1072
1113
  function wrapTextLines(text, cols) {
1073
1114
  const w = Math.max(1, Math.floor(Number(cols) || 1));
1074
1115
  const out = [];
@@ -1077,20 +1118,23 @@ function wrapTextLines(text, cols) {
1077
1118
  out.push("");
1078
1119
  continue;
1079
1120
  }
1121
+ if (visibleWidth(raw) <= w) {
1122
+ out.push(raw);
1123
+ continue;
1124
+ }
1080
1125
  let rest = raw;
1081
- while (rest.length > w) {
1082
- out.push(rest.slice(0, w));
1083
- rest = rest.slice(w);
1126
+ while (visibleWidth(rest) > w) {
1127
+ const head = sliceVisible(rest, w);
1128
+ out.push(head);
1129
+ rest = rest.slice(head.length);
1084
1130
  }
1085
1131
  if (rest.length > 0) out.push(rest);
1086
1132
  }
1087
1133
  return out;
1088
1134
  }
1089
- function padEndVisible(s, w) {
1090
- const t = String(s ?? "");
1091
- if (t.length >= w) return t.slice(0, w);
1092
- return t + " ".repeat(w - t.length);
1093
- }
1135
+
1136
+ // src/screen/scrollable-text.js
1137
+ // Removed: intermediate assignment - code will access import variable directly
1094
1138
  var SCROLL_KEYS = [
1095
1139
  { key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
1096
1140
  { key: "downArrow", caption: "scroll", action: "scrollDown", order: 0 },
@@ -1163,14 +1207,17 @@ function ScrollableText({
1163
1207
  }, [ctx, bindKeys, followBottom]);
1164
1208
  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" : "");
1165
1209
  const rowNodes = visible.map((line, i) => {
1166
- const body = padEndVisible(line, textWidth);
1167
1210
  const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
1168
1211
  const isThumb = glyph === BAR_THUMB;
1169
1212
  return h5(
1170
- import_ink5.Text,
1171
- { key: `L${clamped + i}` },
1172
- body,
1173
- glyph ? h5(import_ink5.Text, { color: isThumb ? "cyan" : "gray" }, glyph) : null
1213
+ import_ink5.Box,
1214
+ { key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1215
+ h5(
1216
+ import_ink5.Box,
1217
+ { width: textWidth, flexShrink: 0 },
1218
+ h5(import_ink5.Text, { wrap: "truncate" }, padEndVisible(line, textWidth))
1219
+ ),
1220
+ showScrollbar ? h5(import_ink5.Box, { width: 1, flexShrink: 0 }, h5(import_ink5.Text, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
1174
1221
  );
1175
1222
  });
1176
1223
  if (bar && visible.length < viewportRows) {
@@ -1178,10 +1225,10 @@ function ScrollableText({
1178
1225
  const glyph = bar[i] ?? BAR_TRACK;
1179
1226
  rowNodes.push(
1180
1227
  h5(
1181
- import_ink5.Text,
1182
- { key: `pad${i}` },
1183
- padEndVisible("", textWidth),
1184
- h5(import_ink5.Text, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
1228
+ import_ink5.Box,
1229
+ { key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
1230
+ h5(import_ink5.Box, { width: textWidth, flexShrink: 0 }, h5(import_ink5.Text, {}, padEndVisible("", textWidth))),
1231
+ h5(import_ink5.Box, { width: 1, flexShrink: 0 }, h5(import_ink5.Text, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
1185
1232
  )
1186
1233
  );
1187
1234
  }
@@ -1379,6 +1426,7 @@ if (typeof window === "undefined") {
1379
1426
  nextScrollAfterContentChange,
1380
1427
  nextScrollAfterUserMove,
1381
1428
  organizeFooterMessages,
1429
+ padEndVisible,
1382
1430
  scrollbarGlyphs,
1383
1431
  showListScreen,
1384
1432
  showMenuScreen,
@@ -1386,6 +1434,8 @@ if (typeof window === "undefined") {
1386
1434
  showMultiColumnListWithPreviewScreen,
1387
1435
  showScreen,
1388
1436
  showWordGridScreen,
1437
+ sliceVisible,
1438
+ stripAnsi,
1389
1439
  useCallback,
1390
1440
  useEffect,
1391
1441
  useInput,
@@ -1393,6 +1443,7 @@ if (typeof window === "undefined") {
1393
1443
  useMemo,
1394
1444
  useRef,
1395
1445
  useState,
1446
+ visibleWidth,
1396
1447
  wrapTextLines
1397
1448
  });
1398
1449
  //# sourceMappingURL=screen.cjs.map