@dui-toolkit/plugin-tui 0.1.1-next.1 → 0.1.1-next.3
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/index.mjs +41 -20
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -307,28 +307,30 @@ var SelectList = class extends BaseWidget {
|
|
|
307
307
|
}
|
|
308
308
|
switch (key) {
|
|
309
309
|
case "ArrowUp":
|
|
310
|
-
if (this.data.selectedIndex > 0) {
|
|
310
|
+
if (items.length > 0 && this.data.selectedIndex > 0) {
|
|
311
311
|
this.data.selectedIndex--;
|
|
312
312
|
if (this.data.selectedIndex < this.data.scrollOffset) this.data.scrollOffset = this.data.selectedIndex;
|
|
313
313
|
}
|
|
314
|
-
this.data.onSelect?.(items[this.data.selectedIndex], this.data.selectedIndex);
|
|
314
|
+
if (items[this.data.selectedIndex]) this.data.onSelect?.(items[this.data.selectedIndex], this.data.selectedIndex);
|
|
315
315
|
return true;
|
|
316
316
|
case "ArrowDown":
|
|
317
|
-
if (this.data.selectedIndex < items.length - 1) {
|
|
317
|
+
if (items.length > 0 && this.data.selectedIndex < items.length - 1) {
|
|
318
318
|
this.data.selectedIndex++;
|
|
319
319
|
if (this.data.selectedIndex >= this.data.scrollOffset + maxVisible) this.data.scrollOffset = this.data.selectedIndex - maxVisible + 1;
|
|
320
320
|
}
|
|
321
|
-
this.data.onSelect?.(items[this.data.selectedIndex], this.data.selectedIndex);
|
|
321
|
+
if (items[this.data.selectedIndex]) this.data.onSelect?.(items[this.data.selectedIndex], this.data.selectedIndex);
|
|
322
322
|
return true;
|
|
323
323
|
case "Home":
|
|
324
324
|
this.data.selectedIndex = 0;
|
|
325
325
|
this.data.scrollOffset = 0;
|
|
326
|
-
this.data.onSelect?.(items[0], 0);
|
|
326
|
+
if (items[0]) this.data.onSelect?.(items[0], 0);
|
|
327
327
|
return true;
|
|
328
328
|
case "End":
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
329
|
+
if (items.length > 0) {
|
|
330
|
+
this.data.selectedIndex = items.length - 1;
|
|
331
|
+
if (items.length > maxVisible) this.data.scrollOffset = items.length - maxVisible;
|
|
332
|
+
this.data.onSelect?.(items[this.data.selectedIndex], this.data.selectedIndex);
|
|
333
|
+
}
|
|
332
334
|
return true;
|
|
333
335
|
case "Enter": {
|
|
334
336
|
const sel = items[this.data.selectedIndex];
|
|
@@ -368,7 +370,28 @@ var SelectList = class extends BaseWidget {
|
|
|
368
370
|
* corrupts terminal state) or wide glyphs (CJK / emoji). These helpers stay
|
|
369
371
|
* cell-aware and never split an escape sequence.
|
|
370
372
|
*/
|
|
371
|
-
const CSI_RE = /\x1b\[[0-9;:<=>?]*[
|
|
373
|
+
const CSI_RE = /\x1b\[[0-9;:<=>?]*[ -\/]*[@-~]/;
|
|
374
|
+
/**
|
|
375
|
+
* Skip past a single escape sequence starting at `rest[0]`.
|
|
376
|
+
* Returns the length of the escape sequence, or 0 if `rest` does not start
|
|
377
|
+
* with a recognised escape.
|
|
378
|
+
*/
|
|
379
|
+
function escapeLength(rest) {
|
|
380
|
+
if (!rest.startsWith("\x1B")) return 0;
|
|
381
|
+
const csi = CSI_RE.exec(rest);
|
|
382
|
+
if (csi && csi[0].length > 0) return csi[0].length;
|
|
383
|
+
if (rest.length >= 2) {
|
|
384
|
+
if (rest[1] === "]") {
|
|
385
|
+
for (let i = 2; i < rest.length; i++) {
|
|
386
|
+
if (rest[i] === "\x07") return i + 1;
|
|
387
|
+
if (rest[i] === "\x1B" && rest[i + 1] === "\\") return i + 2;
|
|
388
|
+
}
|
|
389
|
+
return rest.length;
|
|
390
|
+
}
|
|
391
|
+
return 2;
|
|
392
|
+
}
|
|
393
|
+
return 1;
|
|
394
|
+
}
|
|
372
395
|
/**
|
|
373
396
|
* Truncate an ANSI-wrapped string to `maxCells` terminal cells.
|
|
374
397
|
*
|
|
@@ -384,22 +407,20 @@ function truncateAnsi(text, maxCells) {
|
|
|
384
407
|
const target = Math.max(0, maxCells - 1);
|
|
385
408
|
let out = "";
|
|
386
409
|
let used = 0;
|
|
387
|
-
let
|
|
388
|
-
while (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
410
|
+
let pos = 0;
|
|
411
|
+
while (pos < text.length && used < target) {
|
|
412
|
+
const escLen = escapeLength(text.slice(pos));
|
|
413
|
+
if (escLen > 0) {
|
|
414
|
+
out += text.slice(pos, pos + escLen);
|
|
415
|
+
pos += escLen;
|
|
416
|
+
continue;
|
|
396
417
|
}
|
|
397
|
-
const ch =
|
|
418
|
+
const ch = text.charAt(pos);
|
|
398
419
|
const w = visibleLength(ch);
|
|
399
420
|
if (used + w > target) break;
|
|
400
421
|
out += ch;
|
|
401
422
|
used += w;
|
|
402
|
-
|
|
423
|
+
pos++;
|
|
403
424
|
}
|
|
404
425
|
return out + "…";
|
|
405
426
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dui-toolkit/plugin-tui",
|
|
3
|
-
"version": "0.1.1-next.
|
|
3
|
+
"version": "0.1.1-next.3",
|
|
4
4
|
"description": "TUI widget toolkit plugin for @bdocs/dui — text inputs, select lists, modals, status bars, and more.",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"type": "module",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@bdocs/dui": "0.7.0-next.
|
|
31
|
+
"@bdocs/dui": "0.7.0-next.5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^22.0.0",
|