archymedes-cli 3.0.0 → 3.2.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.
@@ -1,322 +0,0 @@
1
- import {
2
- windowStart
3
- } from "./archymedes-v1ydhsp9.mjs";
4
- import {
5
- joinHorizontal,
6
- padToWidth,
7
- paginator
8
- } from "./archymedes-qsrxyhb3.mjs";
9
- import {
10
- NO_COLOR_PALETTE,
11
- UNICODE_GLYPHS,
12
- exitTopTermUIApp
13
- } from "./archymedes-y64yssbc.mjs";
14
- import {
15
- __require
16
- } from "./archymedes-x67v3n58.mjs";
17
-
18
- // packages/archymedes-cli/src/ui/file-screen.tsx
19
- import { useAsync, useInput, useState } from "@termuijs/jsx";
20
- import { Box, Text } from "@termuijs/widgets";
21
-
22
- // packages/core/src/cli/file-tree.ts
23
- function buildFileTree(paths) {
24
- const root = { name: "", path: "", kind: "dir", children: [] };
25
- for (const raw of paths) {
26
- const parts = raw.split("/").filter((part) => part.length > 0);
27
- let node = root;
28
- let built = "";
29
- for (const [index, part] of parts.entries()) {
30
- built = built ? `${built}/${part}` : part;
31
- const isFile = index === parts.length - 1;
32
- let child = node.children.find((candidate) => candidate.name === part);
33
- if (!child) {
34
- child = { name: part, path: built, kind: isFile ? "file" : "dir", children: [] };
35
- node.children.push(child);
36
- }
37
- node = child;
38
- }
39
- }
40
- sortTree(root);
41
- return root.children;
42
- }
43
- function sortTree(node) {
44
- node.children.sort((a, b) => a.kind === b.kind ? a.name.localeCompare(b.name) : a.kind === "dir" ? -1 : 1);
45
- for (const child of node.children)
46
- sortTree(child);
47
- }
48
- function directorySummary(node) {
49
- let files = 0;
50
- let dirs = 0;
51
- for (const child of node.children) {
52
- if (child.kind === "file")
53
- files += 1;
54
- else {
55
- dirs += 1;
56
- const nested = directorySummary(child);
57
- files += nested.files;
58
- dirs += nested.dirs;
59
- }
60
- }
61
- return { files, dirs };
62
- }
63
- // packages/archymedes-cli/src/ui/file-browser.ts
64
- function flattenTree(tree, expanded, depth = 0, trunks = []) {
65
- const rows = [];
66
- for (const [index, node] of tree.entries()) {
67
- const isLast = index === tree.length - 1;
68
- rows.push({ node, depth, isLast, trunks });
69
- if (node.kind === "dir" && expanded.has(node.path)) {
70
- rows.push(...flattenTree(node.children, expanded, depth + 1, [...trunks, !isLast]));
71
- }
72
- }
73
- return rows;
74
- }
75
- function filterTree(tree, query) {
76
- const needle = query.toLowerCase();
77
- const rows = [];
78
- const walk = (nodes) => {
79
- for (const node of nodes) {
80
- if (node.kind === "file") {
81
- if (node.path.toLowerCase().includes(needle))
82
- rows.push({ node, depth: 0, isLast: false, trunks: [] });
83
- } else
84
- walk(node.children);
85
- }
86
- };
87
- walk(tree);
88
- return rows;
89
- }
90
- function initialFileBrowserState(paths, columns, rows, palette = NO_COLOR_PALETTE) {
91
- return { tree: buildFileTree(paths), expanded: new Set, selected: 0, query: "", searching: false, columns, rows, palette };
92
- }
93
- function visibleRows(state) {
94
- return state.query ? filterTree(state.tree, state.query) : flattenTree(state.tree, state.expanded);
95
- }
96
- function currentRow(state) {
97
- const rows = visibleRows(state);
98
- if (rows.length === 0)
99
- return;
100
- return rows[Math.max(0, Math.min(state.selected, rows.length - 1))];
101
- }
102
- function keyToFileAction(key, character, searching) {
103
- const name = key.name ?? "";
104
- if (key.ctrl && name === "c")
105
- return { kind: "exit" };
106
- const isEnter = name === "return" || name === "enter" || name === "\r" || name === `
107
- `;
108
- const isEscape = name === "escape" || name === "\x1B";
109
- if (searching) {
110
- if (isEscape)
111
- return { kind: "commit" };
112
- if (isEnter)
113
- return { kind: "pick" };
114
- if (name === "backspace")
115
- return { kind: "backspace" };
116
- if (name === "up")
117
- return { kind: "move", step: -1 };
118
- if (name === "down")
119
- return { kind: "move", step: 1 };
120
- if (character && character.length === 1 && character >= " ")
121
- return { kind: "type", character };
122
- return { kind: "none" };
123
- }
124
- if (isEscape || name === "q")
125
- return { kind: "exit" };
126
- if (character === "/")
127
- return { kind: "search" };
128
- if (isEnter)
129
- return { kind: "pick" };
130
- if (character === "e")
131
- return { kind: "edit" };
132
- if (name === "up" || name === "k")
133
- return { kind: "move", step: -1 };
134
- if (name === "down" || name === "j")
135
- return { kind: "move", step: 1 };
136
- if (name === "right" || name === "l")
137
- return { kind: "expand" };
138
- if (name === "left" || name === "h")
139
- return { kind: "collapse" };
140
- return { kind: "none" };
141
- }
142
- function applyFileAction(state, action) {
143
- const rows = visibleRows(state);
144
- switch (action.kind) {
145
- case "move": {
146
- if (rows.length === 0)
147
- return state;
148
- const next = ((state.selected + action.step) % rows.length + rows.length) % rows.length;
149
- return { ...state, selected: next };
150
- }
151
- case "expand": {
152
- const row = currentRow(state);
153
- if (!row || row.node.kind !== "dir" || state.expanded.has(row.node.path))
154
- return state;
155
- return { ...state, expanded: new Set([...state.expanded, row.node.path]) };
156
- }
157
- case "collapse": {
158
- const row = currentRow(state);
159
- if (!row || row.node.kind !== "dir" || !state.expanded.has(row.node.path))
160
- return state;
161
- const expanded = new Set(state.expanded);
162
- expanded.delete(row.node.path);
163
- return { ...state, expanded };
164
- }
165
- case "search":
166
- return { ...state, searching: true };
167
- case "commit":
168
- return { ...state, searching: false };
169
- case "backspace":
170
- return { ...state, query: state.query.slice(0, -1), selected: 0 };
171
- case "type":
172
- return { ...state, query: state.query + action.character, selected: 0 };
173
- default:
174
- return state;
175
- }
176
- }
177
- function toggleDirectory(state) {
178
- const row = currentRow(state);
179
- if (!row || row.node.kind !== "dir")
180
- return state;
181
- return applyFileAction(state, state.expanded.has(row.node.path) ? { kind: "collapse" } : { kind: "expand" });
182
- }
183
- function treeWidth(columns) {
184
- const width = Math.max(1, Math.floor(columns));
185
- return width < 40 ? width : Math.max(20, Math.floor(width * 0.4));
186
- }
187
- function previewWidth(columns) {
188
- const width = Math.max(1, Math.floor(columns));
189
- return width < 40 ? 0 : Math.max(1, width - treeWidth(width) - 3);
190
- }
191
- function bodyHeight(rows) {
192
- return Math.max(0, Math.floor(rows) - 2);
193
- }
194
- function treeLabel(row, expanded, glyphs = UNICODE_GLYPHS) {
195
- const indent = row.trunks.map((carries) => carries ? glyphs.treeTrunk : " ").join("");
196
- const connector = row.isLast ? glyphs.treeLast : glyphs.treeBranch;
197
- if (row.node.kind === "file")
198
- return `${indent}${connector} ${row.node.name}`;
199
- const triangle = expanded.has(row.node.path) ? glyphs.expanded : glyphs.collapsed;
200
- return `${indent}${connector}${triangle} ${row.node.name}/`;
201
- }
202
- function composeFileFrame(state, preview, glyphs = UNICODE_GLYPHS) {
203
- const columns = Math.max(1, Math.floor(state.columns));
204
- const rowCount = Math.max(1, Math.floor(state.rows));
205
- const height = bodyHeight(rowCount);
206
- const rows = visibleRows(state);
207
- const selectedIndex = rows.length === 0 ? -1 : Math.max(0, Math.min(state.selected, rows.length - 1));
208
- const showPreview = previewWidth(columns) > 0;
209
- const tree = showPreview ? treeWidth(columns) : columns;
210
- const body = previewWidth(columns);
211
- const theme = state.palette.tokens;
212
- const out = [];
213
- const current = selectedIndex === -1 ? undefined : rows[selectedIndex];
214
- out.push({ text: padToWidth(` archymedes files · ${current ? current.node.path : "no matches"}`, columns), bold: true, color: theme.primary });
215
- if (rowCount === 1)
216
- return out;
217
- const start = windowStart(selectedIndex < 0 ? 0 : selectedIndex, rows.length, height);
218
- const previewLines = previewToLines(preview, body);
219
- for (let offset = 0;offset < height; offset += 1) {
220
- const row = rows[start + offset];
221
- const chosen = row !== undefined && start + offset === selectedIndex;
222
- const label = row ? treeLabel(row, state.expanded, glyphs) : "";
223
- const treeCell = padToWidth(chosen ? `${glyphs.prompt} ${label}` : ` ${label}`, tree);
224
- out.push({
225
- text: showPreview ? joinHorizontal(treeCell, previewLines[offset] ?? "", { leftWidth: tree, rightWidth: body, separator: ` ${glyphs.boxVertical} ` }) : treeCell,
226
- bold: chosen,
227
- dim: row?.node.kind === "dir" && !chosen,
228
- color: chosen ? theme.accent : undefined
229
- });
230
- }
231
- const overflow = rows.length > height ? ` ${paginator(selectedIndex < 0 ? 0 : selectedIndex, rows.length)}` : "";
232
- const footer = state.searching ? `search: ${state.query}▏ Enter open · Esc done` : `↑↓ move · →/l open · ←/h close · Enter pick a file · / search · Esc back${state.query ? ` filter: ${state.query}` : ""}${overflow}`;
233
- out.push({ text: padToWidth(` ${footer}`, columns), dim: true, color: theme.textMuted });
234
- return out;
235
- }
236
- function previewToLines(preview, width) {
237
- if (width <= 0)
238
- return [];
239
- switch (preview.kind) {
240
- case "empty":
241
- return ["", " (nothing to preview)"];
242
- case "error":
243
- return ["", ` ${preview.message}`];
244
- case "directory":
245
- return ["", ` ${preview.dirs} folder${preview.dirs === 1 ? "" : "s"}, ${preview.files} file${preview.files === 1 ? "" : "s"}`];
246
- case "file": {
247
- const lines = preview.lines.map((line) => ` ${line}`);
248
- if (preview.truncated)
249
- lines.push("", ` … ${preview.totalLines} lines total`);
250
- return lines;
251
- }
252
- }
253
- }
254
-
255
- // packages/archymedes-cli/src/ui/file-screen.tsx
256
- import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
257
- var Panel = Box;
258
- var Line = Text;
259
- function FileScreen({ columns, rows, paths, onExit, palette = NO_COLOR_PALETTE, readFile }) {
260
- const [state, setState] = useState(() => initialFileBrowserState(paths, columns, rows, palette));
261
- const selected = currentRow(state);
262
- const previewPath = selected?.node.kind === "file" ? selected.node.path : undefined;
263
- const { data, error } = useAsync(async () => previewPath ? readFile(previewPath) : null, [previewPath]);
264
- const preview = !selected ? { kind: "empty" } : selected.node.kind === "dir" ? { kind: "directory", ...directorySummary(selected.node) } : error ? { kind: "error", message: error.message } : data ? { kind: "file", lines: data.content.split(`
265
- `), totalLines: data.totalLines, truncated: data.truncated } : { kind: "empty" };
266
- useInput((input, key) => {
267
- const action = keyToFileAction({ name: key?.key, ctrl: key?.ctrl, shift: key?.shift }, input, state.searching);
268
- if (action.kind === "exit") {
269
- onExit(undefined);
270
- return;
271
- }
272
- if (action.kind === "pick" || action.kind === "edit") {
273
- const current = currentRow(state);
274
- if (current?.node.kind === "file") {
275
- onExit({ path: current.node.path, intent: action.kind === "edit" ? "edit" : "mention" });
276
- return;
277
- }
278
- setState((value) => toggleDirectory(value));
279
- return;
280
- }
281
- setState((current) => applyFileAction(current, action));
282
- });
283
- const frame = composeFileFrame(state, preview);
284
- return /* @__PURE__ */ jsxDEV(Panel, {
285
- flexDirection: "column",
286
- width: state.columns,
287
- height: state.rows,
288
- children: frame.map((line, index) => /* @__PURE__ */ jsxDEV(Line, {
289
- bold: line.bold,
290
- dimColor: line.dim,
291
- inverse: line.inverse,
292
- color: line.color,
293
- children: line.text
294
- }, `row-${index}`, false, undefined, this))
295
- }, undefined, false, undefined, this);
296
- }
297
- async function runFileScreen(options) {
298
- const { renderApp } = await import("@termuijs/jsx");
299
- return new Promise((resolve) => {
300
- let settled = false;
301
- const finish = (picked) => {
302
- if (settled)
303
- return;
304
- settled = true;
305
- exitTopTermUIApp();
306
- resolve(picked);
307
- };
308
- renderApp(FileScreen, {
309
- columns: options.columns,
310
- rows: options.rows,
311
- paths: options.paths,
312
- palette: options.palette,
313
- readFile: options.readFile,
314
- onExit: finish,
315
- fullscreen: true
316
- }).catch(() => finish(undefined));
317
- });
318
- }
319
- export {
320
- runFileScreen,
321
- FileScreen
322
- };
@@ -1,273 +0,0 @@
1
- import {
2
- GUIDE_TOPICS,
3
- applyViewport,
4
- newViewport,
5
- visibleLines,
6
- wrapText
7
- } from "./archymedes-ebm17h2q.mjs";
8
- import {
9
- joinHorizontal,
10
- padToWidth,
11
- scrollIndicator,
12
- scrollPercent,
13
- sliceToWidth
14
- } from "./archymedes-qsrxyhb3.mjs";
15
- import"./archymedes-2emwtckp.mjs";
16
- import {
17
- NO_COLOR_PALETTE,
18
- exitTopTermUIApp,
19
- visibleWidth
20
- } from "./archymedes-y64yssbc.mjs";
21
- import {
22
- __require
23
- } from "./archymedes-x67v3n58.mjs";
24
-
25
- // packages/archymedes-cli/src/ui/guide-screen.tsx
26
- import { useInput, useState } from "@termuijs/jsx";
27
- import { Box, Text } from "@termuijs/widgets";
28
-
29
- // packages/archymedes-cli/src/ui/guide-browser.ts
30
- function initialGuideState(columns, rows, palette = NO_COLOR_PALETTE) {
31
- return { topics: GUIDE_TOPICS, selected: 0, scroll: 0, query: "", searching: false, columns, rows, palette };
32
- }
33
- function visibleTopics(state) {
34
- const needle = state.query.trim().toLowerCase();
35
- if (!needle)
36
- return [...state.topics];
37
- return state.topics.filter((topic) => [topic.title, topic.summary, topic.id, ...topic.body, ...(topic.examples ?? []).flatMap((example) => [example.input, example.effect])].some((text) => text.toLowerCase().includes(needle)));
38
- }
39
- function currentTopic(state) {
40
- const topics = visibleTopics(state);
41
- if (topics.length === 0)
42
- return;
43
- return topics[Math.max(0, Math.min(state.selected, topics.length - 1))];
44
- }
45
- function sidebarWidth(columns) {
46
- const width = Math.max(1, Math.floor(columns));
47
- return Math.min(width, Math.max(14, Math.min(26, Math.floor(width * 0.28))));
48
- }
49
- function bodyHeight(rows) {
50
- return Math.max(0, Math.floor(rows) - 2);
51
- }
52
- function keyToGuideAction(key, character, searching) {
53
- const name = key.name ?? "";
54
- if (key.ctrl && name === "c")
55
- return { kind: "exit" };
56
- const isEnter = name === "return" || name === "enter" || name === "\r" || name === `
57
- `;
58
- const isEscape = name === "escape" || name === "\x1B";
59
- if (searching) {
60
- if (isEscape || isEnter)
61
- return { kind: "commit" };
62
- if (name === "backspace")
63
- return { kind: "backspace" };
64
- if (name === "up")
65
- return { kind: "move", step: -1 };
66
- if (name === "down")
67
- return { kind: "move", step: 1 };
68
- if (character && character.length === 1 && character >= " ")
69
- return { kind: "type", character };
70
- return { kind: "none" };
71
- }
72
- if (isEscape || name === "q")
73
- return { kind: "exit" };
74
- if (character === "/" || name === "f3")
75
- return { kind: "search" };
76
- if (name === "up" || name === "k")
77
- return { kind: "move", step: -1 };
78
- if (name === "down" || name === "j")
79
- return { kind: "move", step: 1 };
80
- if (name === "tab")
81
- return { kind: "move", step: key.shift ? -1 : 1 };
82
- if (name === "pagedown" || character === " ")
83
- return { kind: "page", step: 1 };
84
- if (name === "pageup")
85
- return { kind: "page", step: -1 };
86
- if (name === "right")
87
- return { kind: "scroll", rows: 1 };
88
- if (name === "left")
89
- return { kind: "scroll", rows: -1 };
90
- return { kind: "none" };
91
- }
92
- function applyGuideAction(state, action) {
93
- const topics = visibleTopics(state);
94
- switch (action.kind) {
95
- case "move": {
96
- if (topics.length === 0)
97
- return state;
98
- const next = ((state.selected + action.step) % topics.length + topics.length) % topics.length;
99
- return { ...state, selected: next, scroll: 0 };
100
- }
101
- case "scroll":
102
- case "page": {
103
- const topic = currentTopic(state);
104
- if (!topic)
105
- return state;
106
- const lines = topicLines(topic, bodyWidth(state.columns)).map((line) => line.text);
107
- const viewport = { ...newViewport(lines, bodyHeight(state.rows)), top: state.scroll };
108
- const moved = action.kind === "page" ? applyViewport(viewport, { kind: action.step === 1 ? "pageDown" : "pageUp" }) : applyViewport(viewport, action.rows > 0 ? { kind: "down", rows: action.rows } : { kind: "up", rows: -action.rows });
109
- return { ...state, scroll: moved.top };
110
- }
111
- case "search":
112
- return { ...state, searching: true };
113
- case "commit":
114
- return { ...state, searching: false };
115
- case "backspace":
116
- return { ...state, query: state.query.slice(0, -1), selected: 0, scroll: 0 };
117
- case "type":
118
- return { ...state, query: state.query + action.character, selected: 0, scroll: 0 };
119
- default:
120
- return state;
121
- }
122
- }
123
- function bodyWidth(columns) {
124
- const width = Math.max(1, Math.floor(columns));
125
- return width < 40 ? width : Math.max(1, width - sidebarWidth(width) - 3);
126
- }
127
- function topicLines(topic, width) {
128
- const measure = Math.max(1, Math.floor(width));
129
- const wrap = (text, available = measure) => wrapText(text, Math.max(1, available)).flatMap((line) => hardWrap(line, Math.max(1, available)));
130
- const rows = [
131
- ...wrap(topic.title).map((line) => ({ text: line, bold: true })),
132
- { text: "" }
133
- ];
134
- for (const paragraph of topic.body) {
135
- for (const line of wrap(paragraph))
136
- rows.push({ text: line });
137
- rows.push({ text: "" });
138
- }
139
- if (topic.examples && topic.examples.length > 0) {
140
- rows.push({ text: "try", bold: true });
141
- for (const example of topic.examples) {
142
- const commandIndent = " ".repeat(Math.min(2, Math.max(0, measure - 1)));
143
- const detailIndent = " ".repeat(Math.min(4, Math.max(0, measure - 1)));
144
- const [head, ...rest] = wrap(example.input, measure - visibleWidth(detailIndent));
145
- rows.push({ text: `${commandIndent}${head ?? ""}`, bold: true });
146
- for (const line of rest)
147
- rows.push({ text: `${detailIndent}${line}`, bold: true });
148
- for (const line of wrap(example.effect, measure - visibleWidth(detailIndent)))
149
- rows.push({ text: `${detailIndent}${line}`, dim: true });
150
- }
151
- }
152
- return rows;
153
- }
154
- function hardWrap(text, width) {
155
- if (visibleWidth(text) <= width)
156
- return [text];
157
- const lines = [];
158
- let line = "";
159
- const segments = typeof Intl.Segmenter === "function" ? [...new Intl.Segmenter(undefined, { granularity: "grapheme" }).segment(text)].map((entry) => entry.segment) : [...text];
160
- for (const segment of segments) {
161
- if (line && visibleWidth(line + segment) > width) {
162
- lines.push(line);
163
- line = "";
164
- }
165
- if (visibleWidth(segment) > width) {
166
- lines.push("…");
167
- continue;
168
- }
169
- line += segment;
170
- }
171
- if (line)
172
- lines.push(line);
173
- return lines;
174
- }
175
- function composeGuideFrame(state) {
176
- const columns = Math.max(1, Math.floor(state.columns));
177
- const rowCount = Math.max(1, Math.floor(state.rows));
178
- const compact = columns < 40;
179
- const sidebar = compact ? 0 : sidebarWidth(columns);
180
- const body = bodyWidth(columns);
181
- const height = bodyHeight(rowCount);
182
- const topics = visibleTopics(state);
183
- const selectedIndex = topics.length === 0 ? -1 : Math.max(0, Math.min(state.selected, topics.length - 1));
184
- const topic = selectedIndex === -1 ? undefined : topics[selectedIndex];
185
- const theme = state.palette.tokens;
186
- const rows = [];
187
- rows.push({
188
- text: padToWidth(compact ? ` archymedes guide · ${topic?.title ?? "no matches"}` : " archymedes guide", columns),
189
- bold: true,
190
- color: theme.primary
191
- });
192
- if (rowCount === 1)
193
- return rows;
194
- const lines = topic ? topicLines(topic, body) : [{ text: "Nothing matches that." }];
195
- const indices = visibleLines({ ...newViewport(lines.map((_, index) => `${index}`), height), top: state.scroll });
196
- const start = indices.length > 0 ? Number(indices[0]) : 0;
197
- const window = lines.slice(start, start + height);
198
- const listStart = Math.max(0, Math.min(selectedIndex - Math.floor(height / 2), Math.max(0, topics.length - height)));
199
- for (let offset = 0;offset < height; offset += 1) {
200
- const listed = topics[listStart + offset];
201
- const chosen = listed !== undefined && listStart + offset === selectedIndex;
202
- const cell = listed ? `${chosen ? "›" : " "} ${listed.title}` : "";
203
- const line = window[offset];
204
- rows.push({
205
- text: compact ? padToWidth(line?.text ?? "", columns) : joinHorizontal(sliceToWidth(cell, sidebar), line?.text ?? "", { leftWidth: sidebar, rightWidth: body, separator: " │ " }),
206
- bold: chosen || line?.bold,
207
- dim: line?.dim && !chosen,
208
- ...chosen ? { color: theme.accent } : line?.bold ? { color: theme.primary } : {}
209
- });
210
- }
211
- const position = lines.length > height ? ` ${scrollIndicator(scrollPercent(start, lines.length, height))}` : "";
212
- const footer = state.searching ? `search: ${state.query}▏ Enter done · Esc done` : `↑↓ topic · ←→ scroll · space page · / search · Esc back${state.query ? ` filter: ${state.query}` : ""}${position}`;
213
- rows.push({ text: padToWidth(` ${footer}`, columns), dim: true, color: theme.textMuted });
214
- return rows;
215
- }
216
-
217
- // packages/archymedes-cli/src/ui/guide-screen.tsx
218
- import { jsxDEV } from "@termuijs/jsx/jsx-dev-runtime";
219
- var Panel = Box;
220
- var Line = Text;
221
- function GuideScreen({ columns, rows, onExit, startAt, palette = NO_COLOR_PALETTE }) {
222
- const [state, setState] = useState(() => {
223
- const initial = initialGuideState(columns, rows, palette);
224
- const index = startAt ? initial.topics.findIndex((topic) => topic.id === startAt) : -1;
225
- return index >= 0 ? { ...initial, selected: index } : initial;
226
- });
227
- useInput((input, key) => {
228
- const action = keyToGuideAction({ name: key?.key, ctrl: key?.ctrl, shift: key?.shift }, input, state.searching);
229
- if (action.kind === "exit") {
230
- onExit();
231
- return;
232
- }
233
- setState((current) => applyGuideAction(current, action));
234
- });
235
- const frame = composeGuideFrame(state);
236
- return /* @__PURE__ */ jsxDEV(Panel, {
237
- flexDirection: "column",
238
- width: state.columns,
239
- height: state.rows,
240
- children: frame.map((row, index) => /* @__PURE__ */ jsxDEV(Line, {
241
- bold: row.bold,
242
- dimColor: row.dim,
243
- inverse: row.inverse,
244
- color: row.color,
245
- children: row.text
246
- }, `row-${index}`, false, undefined, this))
247
- }, undefined, false, undefined, this);
248
- }
249
- async function runGuideScreen(options) {
250
- const { renderApp } = await import("@termuijs/jsx");
251
- await new Promise((resolve) => {
252
- let settled = false;
253
- const finish = () => {
254
- if (settled)
255
- return;
256
- settled = true;
257
- exitTopTermUIApp();
258
- resolve();
259
- };
260
- renderApp(GuideScreen, {
261
- columns: options.columns,
262
- rows: options.rows,
263
- startAt: options.startAt,
264
- palette: options.palette,
265
- onExit: finish,
266
- fullscreen: true
267
- }).catch(finish);
268
- });
269
- }
270
- export {
271
- runGuideScreen,
272
- GuideScreen
273
- };