@nghyane/arcane-tui 0.1.9 → 0.1.10

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@nghyane/arcane-tui",
4
- "version": "0.1.9",
4
+ "version": "0.1.10",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://github.com/nghyane/arcane",
7
7
  "author": "Can Bölük",
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { matchesKey } from "../keys";
12
12
  import type { Component } from "../tui";
13
- import { wrapTextWithAnsi } from "../utils";
13
+ import { truncateToWidth, visibleWidth } from "../utils";
14
14
 
15
15
  /** Tab definition */
16
16
  export interface Tab {
@@ -112,31 +112,64 @@ export class TabBar implements Component {
112
112
 
113
113
  /** Render the tab bar, wrapping to multiple lines if needed */
114
114
  render(width: number): string[] {
115
- const parts: string[] = [];
115
+ const maxWidth = Math.max(1, width);
116
+ const chunks: string[] = [];
116
117
 
117
118
  // Label prefix
118
- parts.push(this.#theme.label(`${this.#label}:`));
119
- parts.push(" ");
119
+ chunks.push(this.#theme.label(`${this.#label}:`));
120
+ chunks.push(" ");
120
121
 
121
122
  // Tab buttons
122
123
  for (let i = 0; i < this.#tabs.length; i++) {
123
124
  const tab = this.#tabs[i];
124
125
  if (i === this.#activeIndex) {
125
- parts.push(this.#theme.activeTab(` ${tab.label} `));
126
+ chunks.push(this.#theme.activeTab(` ${tab.label} `));
126
127
  } else {
127
- parts.push(this.#theme.inactiveTab(` ${tab.label} `));
128
+ chunks.push(this.#theme.inactiveTab(` ${tab.label} `));
128
129
  }
129
130
  if (i < this.#tabs.length - 1) {
130
- parts.push(" ");
131
+ chunks.push(" ");
131
132
  }
132
133
  }
133
134
 
134
135
  // Navigation hint
135
- parts.push(" ");
136
- parts.push(this.#theme.hint("(tab to cycle)"));
136
+ chunks.push(" ");
137
+ chunks.push(this.#theme.hint("(tab to cycle)"));
137
138
 
138
- const line = parts.join("");
139
- const maxWidth = Math.max(1, width);
140
- return wrapTextWithAnsi(line, maxWidth);
139
+ const lines: string[] = [];
140
+ let currentLine = "";
141
+ let currentWidth = 0;
142
+
143
+ for (const chunk of chunks) {
144
+ const chunkWidth = visibleWidth(chunk);
145
+ if (chunkWidth <= 0) {
146
+ continue;
147
+ }
148
+
149
+ if (chunkWidth > maxWidth) {
150
+ if (currentLine) {
151
+ lines.push(currentLine);
152
+ currentLine = "";
153
+ currentWidth = 0;
154
+ }
155
+ lines.push(truncateToWidth(chunk, maxWidth));
156
+ continue;
157
+ }
158
+
159
+ if (currentWidth > 0 && currentWidth + chunkWidth > maxWidth) {
160
+ lines.push(currentLine);
161
+ currentLine = "";
162
+ currentWidth = 0;
163
+ }
164
+
165
+ currentLine += chunk;
166
+ currentWidth += chunkWidth;
167
+ }
168
+
169
+ if (currentLine) {
170
+ lines.push(currentLine);
171
+ }
172
+
173
+ return lines.length > 0 ? lines : [""];
141
174
  }
142
175
  }
package/src/tui.ts CHANGED
@@ -186,6 +186,7 @@ export class Container implements Component {
186
186
  }
187
187
 
188
188
  render(width: number): string[] {
189
+ width = Math.max(1, width);
189
190
  const lines: string[] = [];
190
191
  for (const child of this.children) {
191
192
  lines.push(...child.render(width));