@oh-my-pi/pi-tui 15.2.1 → 15.2.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [15.2.3] - 2026-05-22
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Added `SettingsList#setItems` to replace the entire settings list with a new items array while automatically clamping selection to a valid index
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Updated `Loader` to drive renders at ~60fps (16ms tick) while keeping spinner-frame advancement at 80ms so shimmer/animated message colorizers update smoothly without altering spinner cadence
|
|
13
|
+
|
|
5
14
|
## [15.1.9] - 2026-05-21
|
|
6
15
|
|
|
7
16
|
### Fixed
|
|
@@ -25,6 +25,14 @@ export declare class SettingsList implements Component {
|
|
|
25
25
|
constructor(items: SettingItem[], maxVisible: number, theme: SettingsListTheme, onChange: (id: string, newValue: string) => void, onCancel: () => void);
|
|
26
26
|
/** Update an item's currentValue */
|
|
27
27
|
updateValue(id: string, newValue: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Replace the entire items array. Selection is preserved when the prior
|
|
30
|
+
* index is still valid, otherwise clamped to the last item (or 0 if the
|
|
31
|
+
* list is now empty). An open submenu is left untouched — its lifetime
|
|
32
|
+
* is bounded by its own done callback, and `#closeSubmenu` re-clamps the
|
|
33
|
+
* restored index against the new list on the way out.
|
|
34
|
+
*/
|
|
35
|
+
setItems(items: SettingItem[]): void;
|
|
28
36
|
invalidate(): void;
|
|
29
37
|
render(width: number): string[];
|
|
30
38
|
handleInput(data: string): void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-tui",
|
|
4
|
-
"version": "15.2.
|
|
4
|
+
"version": "15.2.3",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"fmt": "biome format --write ."
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@oh-my-pi/pi-natives": "15.2.
|
|
41
|
-
"@oh-my-pi/pi-utils": "15.2.
|
|
40
|
+
"@oh-my-pi/pi-natives": "15.2.3",
|
|
41
|
+
"@oh-my-pi/pi-utils": "15.2.3",
|
|
42
42
|
"lru-cache": "11.3.6",
|
|
43
43
|
"marked": "^18.0.3"
|
|
44
44
|
},
|
package/src/components/loader.ts
CHANGED
|
@@ -3,13 +3,27 @@ import { sliceByColumn, visibleWidth } from "../utils";
|
|
|
3
3
|
import { Text } from "./text";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Loader component that
|
|
6
|
+
* Loader component that drives display refresh at ~60fps so callers whose
|
|
7
|
+
* message colorizer is time-dependent (e.g. shimmer/KITT) animate smoothly.
|
|
8
|
+
*
|
|
9
|
+
* Two cadences are interleaved on a single timer:
|
|
10
|
+
* - **Render tick** (every `RENDER_INTERVAL_MS`) → asks the TUI to redraw.
|
|
11
|
+
* The TUI already throttles at 16ms (`MIN_RENDER_INTERVAL_MS`), so this
|
|
12
|
+
* is the natural upper bound; static messageColorFns produce identical
|
|
13
|
+
* output and the differ drops the no-op redraw at ~zero cost.
|
|
14
|
+
* - **Spinner advance** (every `SPINNER_ADVANCE_MS`) → bumps the spinner
|
|
15
|
+
* frame index. Decoupled from the render cadence so the spinner keeps
|
|
16
|
+
* its classic ~12.5fps step pace regardless of shimmer state.
|
|
7
17
|
*/
|
|
18
|
+
const RENDER_INTERVAL_MS = 16;
|
|
19
|
+
const SPINNER_ADVANCE_MS = 80;
|
|
20
|
+
|
|
8
21
|
export class Loader extends Text {
|
|
9
22
|
#frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
10
23
|
#currentFrame = 0;
|
|
11
24
|
#intervalId?: NodeJS.Timeout;
|
|
12
25
|
#ui: TUI | null = null;
|
|
26
|
+
#lastSpinnerTick = 0;
|
|
13
27
|
|
|
14
28
|
constructor(
|
|
15
29
|
ui: TUI,
|
|
@@ -38,11 +52,16 @@ export class Loader extends Text {
|
|
|
38
52
|
}
|
|
39
53
|
|
|
40
54
|
start() {
|
|
55
|
+
this.#lastSpinnerTick = performance.now();
|
|
41
56
|
this.#updateDisplay();
|
|
42
57
|
this.#intervalId = setInterval(() => {
|
|
43
|
-
|
|
58
|
+
const now = performance.now();
|
|
59
|
+
if (now - this.#lastSpinnerTick >= SPINNER_ADVANCE_MS) {
|
|
60
|
+
this.#currentFrame = (this.#currentFrame + 1) % this.#frames.length;
|
|
61
|
+
this.#lastSpinnerTick = now;
|
|
62
|
+
}
|
|
44
63
|
this.#updateDisplay();
|
|
45
|
-
},
|
|
64
|
+
}, RENDER_INTERVAL_MS);
|
|
46
65
|
}
|
|
47
66
|
|
|
48
67
|
stop() {
|
|
@@ -59,6 +59,22 @@ export class SettingsList implements Component {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Replace the entire items array. Selection is preserved when the prior
|
|
64
|
+
* index is still valid, otherwise clamped to the last item (or 0 if the
|
|
65
|
+
* list is now empty). An open submenu is left untouched — its lifetime
|
|
66
|
+
* is bounded by its own done callback, and `#closeSubmenu` re-clamps the
|
|
67
|
+
* restored index against the new list on the way out.
|
|
68
|
+
*/
|
|
69
|
+
setItems(items: SettingItem[]): void {
|
|
70
|
+
this.#items = items;
|
|
71
|
+
if (this.#items.length === 0) {
|
|
72
|
+
this.#selectedIndex = 0;
|
|
73
|
+
} else if (this.#selectedIndex >= this.#items.length) {
|
|
74
|
+
this.#selectedIndex = this.#items.length - 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
62
78
|
invalidate(): void {
|
|
63
79
|
this.#submenuComponent?.invalidate?.();
|
|
64
80
|
}
|