@zaly/tui 0.0.4 → 0.0.6

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.
Files changed (156) hide show
  1. package/dist/actions-CnVzKVID.d.mts +41 -0
  2. package/dist/actions-CnVzKVID.d.mts.map +1 -0
  3. package/dist/actions-DEIKF2ts.mjs +48 -0
  4. package/dist/actions-DEIKF2ts.mjs.map +1 -0
  5. package/dist/{box-DyaByEiG.mjs → box-DepqUtuo.mjs} +2 -2
  6. package/dist/{box-DyaByEiG.mjs.map → box-DepqUtuo.mjs.map} +1 -1
  7. package/dist/{builder-D49ECBEf.mjs → builder-DTz5mppV.mjs} +2 -2
  8. package/dist/{builder-D49ECBEf.mjs.map → builder-DTz5mppV.mjs.map} +1 -1
  9. package/dist/{callbacks-CNjGNxVw.mjs → callbacks-DcMBGQEO.mjs} +2 -2
  10. package/dist/{callbacks-CNjGNxVw.mjs.map → callbacks-DcMBGQEO.mjs.map} +1 -1
  11. package/dist/{client-D6C_uczF.mjs → client-BBdtbLp4.mjs} +5 -10
  12. package/dist/client-BBdtbLp4.mjs.map +1 -0
  13. package/dist/client-cIckDgAj.mjs +2 -0
  14. package/dist/clipboard-l_TWxxTf.mjs +404 -0
  15. package/dist/clipboard-l_TWxxTf.mjs.map +1 -0
  16. package/dist/clipboard.mjs +1 -403
  17. package/dist/ctx-Bt4VlRPg.mjs +2 -0
  18. package/dist/ctx-DjJ1zSbs.mjs +43 -0
  19. package/dist/ctx-DjJ1zSbs.mjs.map +1 -0
  20. package/dist/divider-cclEAdPx.mjs +9 -0
  21. package/dist/divider-cclEAdPx.mjs.map +1 -0
  22. package/dist/files-Aw3iWpXD.d.mts +29 -0
  23. package/dist/files-Aw3iWpXD.d.mts.map +1 -0
  24. package/dist/files-BvThQpOf.mjs +42 -0
  25. package/dist/files-BvThQpOf.mjs.map +1 -0
  26. package/dist/github-Cy2hfWJ7.mjs +137 -0
  27. package/dist/github-Cy2hfWJ7.mjs.map +1 -0
  28. package/dist/github-DS00VoOj.d.mts +64 -0
  29. package/dist/github-DS00VoOj.d.mts.map +1 -0
  30. package/dist/image-BTxDPPiT.d.mts +37 -0
  31. package/dist/image-BTxDPPiT.d.mts.map +1 -0
  32. package/dist/index.mjs +6 -202
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/input-CRBuTrsL.mjs +497 -0
  35. package/dist/input-CRBuTrsL.mjs.map +1 -0
  36. package/dist/{inspect-D1d9t-ni.mjs → inspect-DE5goDzB.mjs} +2 -2
  37. package/dist/{inspect-D1d9t-ni.mjs.map → inspect-DE5goDzB.mjs.map} +1 -1
  38. package/dist/log-Djvrxqk0.mjs +130 -0
  39. package/dist/log-Djvrxqk0.mjs.map +1 -0
  40. package/dist/logger-DDrt03So.mjs +71 -0
  41. package/dist/logger-DDrt03So.mjs.map +1 -0
  42. package/dist/markdown-CTlPe5ks.mjs +124 -0
  43. package/dist/markdown-CTlPe5ks.mjs.map +1 -0
  44. package/dist/markdown.mjs +1 -1
  45. package/dist/overlay-9xNgsuuy.mjs +18 -0
  46. package/dist/overlay-9xNgsuuy.mjs.map +1 -0
  47. package/dist/{picker-ndVVt6qF.mjs → picker-cH-rc7-X.mjs} +5 -5
  48. package/dist/{picker-ndVVt6qF.mjs.map → picker-cH-rc7-X.mjs.map} +1 -1
  49. package/dist/queries-B_lOwEiE.mjs +200 -0
  50. package/dist/queries-B_lOwEiE.mjs.map +1 -0
  51. package/dist/{registry-U654j61Y.mjs → registry-w_w7gZr_.mjs} +3 -5
  52. package/dist/registry-w_w7gZr_.mjs.map +1 -0
  53. package/dist/render-F8pVXN7h.mjs +33 -0
  54. package/dist/render-F8pVXN7h.mjs.map +1 -0
  55. package/dist/renderer-Dgj_qEOA.mjs +2 -0
  56. package/dist/{renderer-CdLCkJB-.mjs → renderer-qSMVeNSV.mjs} +3 -5
  57. package/dist/{renderer-CdLCkJB-.mjs.map → renderer-qSMVeNSV.mjs.map} +1 -1
  58. package/dist/{renderer-CxL4xbkl.mjs → renderer-uMeDzF9B.mjs} +8 -7
  59. package/dist/{renderer-CxL4xbkl.mjs.map → renderer-uMeDzF9B.mjs.map} +1 -1
  60. package/dist/select-m7NE6Rwa.mjs +195 -0
  61. package/dist/select-m7NE6Rwa.mjs.map +1 -0
  62. package/dist/services/logger.mjs +1 -70
  63. package/dist/services/notifier.mjs +2 -2
  64. package/dist/services/picker.d.mts +1 -1
  65. package/dist/services/picker.mjs +6 -6
  66. package/dist/services/prompt.d.mts +1 -1
  67. package/dist/services/prompt.mjs +5 -5
  68. package/dist/shiki/server.d.mts +1 -0
  69. package/dist/shiki/server.mjs +129 -0
  70. package/dist/shiki/server.mjs.map +1 -0
  71. package/dist/{shiki-BrjVUkeh.mjs → shiki-B5NwIiot.mjs} +5 -10
  72. package/dist/shiki-B5NwIiot.mjs.map +1 -0
  73. package/dist/shiki-BK-v9CtF.mjs +12 -0
  74. package/dist/shiki-BK-v9CtF.mjs.map +1 -0
  75. package/dist/show-DR2x1YFc.mjs +85 -0
  76. package/dist/show-DR2x1YFc.mjs.map +1 -0
  77. package/dist/style.mjs +2 -2
  78. package/dist/text-9lwQeqYr.d.mts +33 -0
  79. package/dist/text-9lwQeqYr.d.mts.map +1 -0
  80. package/dist/text-DILrol9j.mjs +32 -0
  81. package/dist/text-DILrol9j.mjs.map +1 -0
  82. package/dist/text-q26V6_Sc.mjs +111 -0
  83. package/dist/text-q26V6_Sc.mjs.map +1 -0
  84. package/dist/text.d.mts +2 -33
  85. package/dist/text.mjs +1 -110
  86. package/dist/{theme.config-CU3B50HN.mjs → theme.config-BptYUq4K.mjs} +4 -4
  87. package/dist/{theme.config-CU3B50HN.mjs.map → theme.config-BptYUq4K.mjs.map} +1 -1
  88. package/dist/themes.mjs +1 -1
  89. package/dist/tree-Bo1afYhe.mjs +73 -0
  90. package/dist/tree-Bo1afYhe.mjs.map +1 -0
  91. package/dist/widget-BkMwhY2p.mjs +40 -0
  92. package/dist/widget-BkMwhY2p.mjs.map +1 -0
  93. package/dist/widget-M7jD8Rgg.d.mts +49 -0
  94. package/dist/widget-M7jD8Rgg.d.mts.map +1 -0
  95. package/dist/widgets/autocomplete.mjs +2 -2
  96. package/dist/widgets/box.mjs +1 -1
  97. package/dist/widgets/code.mjs +7 -7
  98. package/dist/widgets/completions/actions.d.mts +2 -41
  99. package/dist/widgets/completions/actions.mjs +1 -47
  100. package/dist/widgets/completions/files.d.mts +2 -29
  101. package/dist/widgets/completions/files.mjs +1 -41
  102. package/dist/widgets/completions/github.d.mts +2 -64
  103. package/dist/widgets/completions/github.mjs +1 -136
  104. package/dist/widgets/completions/index.d.mts +3 -3
  105. package/dist/widgets/completions/index.mjs +3 -3
  106. package/dist/widgets/diff.d.mts +1 -1
  107. package/dist/widgets/diff.mjs +3 -3
  108. package/dist/widgets/divider.mjs +1 -8
  109. package/dist/widgets/image.d.mts +2 -37
  110. package/dist/widgets/image.mjs +1 -1
  111. package/dist/widgets/input.mjs +1 -496
  112. package/dist/widgets/log.mjs +1 -129
  113. package/dist/widgets/markdown.d.mts +2 -2
  114. package/dist/widgets/markdown.mjs +1 -123
  115. package/dist/widgets/overlay.mjs +1 -17
  116. package/dist/widgets/picker.mjs +1 -1
  117. package/dist/widgets/select.mjs +1 -194
  118. package/dist/widgets/show.mjs +1 -84
  119. package/dist/widgets/text.mjs +1 -31
  120. package/dist/widgets/tree.mjs +1 -72
  121. package/dist/widgets/widget.d.mts +2 -49
  122. package/dist/widgets/widget.mjs +1 -39
  123. package/dist/worker-BvRm4OsW.mjs +2 -0
  124. package/dist/worker-T6SdPzUH.mjs +52 -0
  125. package/dist/worker-T6SdPzUH.mjs.map +1 -0
  126. package/package.json +7 -3
  127. package/dist/client-D6C_uczF.mjs.map +0 -1
  128. package/dist/clipboard.mjs.map +0 -1
  129. package/dist/registry-U654j61Y.mjs.map +0 -1
  130. package/dist/render-DxVLqqB9.mjs +0 -74
  131. package/dist/render-DxVLqqB9.mjs.map +0 -1
  132. package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
  133. package/dist/services/logger.mjs.map +0 -1
  134. package/dist/shiki-BrjVUkeh.mjs.map +0 -1
  135. package/dist/text.d.mts.map +0 -1
  136. package/dist/text.mjs.map +0 -1
  137. package/dist/widgets/completions/actions.d.mts.map +0 -1
  138. package/dist/widgets/completions/actions.mjs.map +0 -1
  139. package/dist/widgets/completions/files.d.mts.map +0 -1
  140. package/dist/widgets/completions/files.mjs.map +0 -1
  141. package/dist/widgets/completions/github.d.mts.map +0 -1
  142. package/dist/widgets/completions/github.mjs.map +0 -1
  143. package/dist/widgets/divider.mjs.map +0 -1
  144. package/dist/widgets/image.d.mts.map +0 -1
  145. package/dist/widgets/input.mjs.map +0 -1
  146. package/dist/widgets/log.mjs.map +0 -1
  147. package/dist/widgets/markdown.mjs.map +0 -1
  148. package/dist/widgets/overlay.mjs.map +0 -1
  149. package/dist/widgets/select.mjs.map +0 -1
  150. package/dist/widgets/show.mjs.map +0 -1
  151. package/dist/widgets/text.mjs.map +0 -1
  152. package/dist/widgets/tree.mjs.map +0 -1
  153. package/dist/widgets/widget.d.mts.map +0 -1
  154. package/dist/widgets/widget.mjs.map +0 -1
  155. package/dist/worker-DjHuQSbY.mjs +0 -27
  156. package/dist/worker-DjHuQSbY.mjs.map +0 -1
@@ -1,497 +1,2 @@
1
- import { S as unwrap, x as untrack } from "../reactive-f7NpAi69.mjs";
2
- import { t as Node } from "../node-BZ7f6HzU.mjs";
3
- import { formatText } from "../text.mjs";
4
- import { clipboard } from "../clipboard.mjs";
5
- import { hash, isPromiseLike } from "@zaly/shared";
6
- import { sliceAnsi, splitAnsi, stringWidth } from "@zaly/shared/ansi";
7
- import { basename } from "pathe";
8
- import { fileDetect } from "@zaly/shared/detect";
9
- //#region src/widgets/input.ts
10
- const PASTE_MAX_LINES = 5;
11
- const PASTE_MAX_CHARS = 1e3;
12
- /**
13
- * Multi-line text input with auto-grow.
14
- *
15
- * Editing commands (`cursorLeft`, `deleteWordBack`, `submit`, …) live on
16
- * `this.actions` as zero-arg methods. The input router maps keymap
17
- * bindings like `"input.cursorLeft"` onto those methods — users bind
18
- * different keys by configuring the keymap, not by patching the class.
19
- * The methods are also callable directly (`input.actions.submit()`),
20
- * which is handy in tests or for higher-level macros.
21
- *
22
- * What this class *still* handles via its `key` event listener:
23
- * - **Printable character insertion.** An unbound keystroke whose
24
- * `text` is set and has no ctrl/alt/meta modifier becomes a literal
25
- * insert at the cursor. There's no action for every printable char
26
- * in the keymap; the raw-key fallback handles them.
27
- * - **Paste events.** Whole payload inserted at cursor; always.
28
- *
29
- * Everything else (navigation, editing, submit/newline) goes through
30
- * the router → actions pipeline. Unbound non-printable keys fall back
31
- * to `emit("key", …)` and bubble to the parent chain.
32
- *
33
- * Rendering word-wraps each logical line to `ctx.width`, so long
34
- * messages naturally grow vertically. The UI surface resizes its
35
- * reserved footer when the Input's row count changes, so the stream
36
- * above shifts accordingly.
37
- */
38
- var Input = class Input extends Node {
39
- /** Class-level scope tag used by the input router to bind keymaps. */
40
- static type = "input";
41
- type = Input.type;
42
- #focused = false;
43
- #history = [];
44
- #historyDraft = "";
45
- #historyIndex;
46
- #preferredCol;
47
- #staged = [];
48
- #formatCache = /* @__PURE__ */ new Map();
49
- #formatGen = 0;
50
- /**
51
- * Editing actions. Parameterless — they close over `this` — so both
52
- * the router (via keymap dispatch) and application code can invoke
53
- * them. Add to the keymap in `src/input/actions.ts` to give them
54
- * default key bindings.
55
- */
56
- actions = {
57
- "input.cursorDown": () => {
58
- const v = this.state.value ?? "";
59
- const { col, line } = posToLineCol(v, this.#cursor());
60
- if (line >= countLines(v) - 1) {
61
- this.#historyNext();
62
- return;
63
- }
64
- this.#preferredCol ??= col;
65
- this.state.cursor = lineColToPos(v, line + 1, this.#preferredCol);
66
- },
67
- "input.cursorLeft": () => {
68
- const c = this.#cursor();
69
- this.#preferredCol = void 0;
70
- this.state.cursor = c > 0 ? c - 1 : c;
71
- },
72
- "input.cursorLineEnd": () => {
73
- const v = this.state.value ?? "";
74
- this.#preferredCol = void 0;
75
- this.state.cursor = lineEndPos(v, this.#cursor());
76
- },
77
- "input.cursorLineStart": () => {
78
- const v = this.state.value ?? "";
79
- const { line } = posToLineCol(v, this.#cursor());
80
- this.#preferredCol = void 0;
81
- this.state.cursor = lineColToPos(v, line, 0);
82
- },
83
- "input.cursorRight": () => {
84
- const v = this.state.value ?? "";
85
- const c = this.#cursor();
86
- this.#preferredCol = void 0;
87
- this.state.cursor = c < v.length ? c + 1 : c;
88
- },
89
- "input.cursorUp": () => {
90
- const v = this.state.value ?? "";
91
- const { col, line } = posToLineCol(v, this.#cursor());
92
- if (line === 0) {
93
- this.#historyPrev();
94
- return;
95
- }
96
- this.#preferredCol ??= col;
97
- this.state.cursor = lineColToPos(v, line - 1, this.#preferredCol);
98
- },
99
- "input.deleteCharBack": () => {
100
- const v = this.state.value ?? "";
101
- const c = this.#cursor();
102
- this.#preferredCol = void 0;
103
- if (c === 0) return;
104
- this.#historyEdit();
105
- const marker = this.#markerRange(c, "back");
106
- if (marker) return this.#deleteRange(marker.start, marker.end);
107
- this.state.set({
108
- cursor: c - 1,
109
- value: v.slice(0, c - 1) + v.slice(c)
110
- });
111
- },
112
- "input.deleteCharForward": () => {
113
- const v = this.state.value ?? "";
114
- const c = this.#cursor();
115
- this.#preferredCol = void 0;
116
- if (c >= v.length) return;
117
- this.#historyEdit();
118
- const marker = this.#markerRange(c, "forward");
119
- if (marker) return this.#deleteRange(marker.start, marker.end);
120
- this.state.value = v.slice(0, c) + v.slice(c + 1);
121
- },
122
- "input.deleteWordBack": () => {
123
- const v = this.state.value ?? "";
124
- const c = this.#cursor();
125
- this.#preferredCol = void 0;
126
- let i = c;
127
- while (i > 0 && isWhitespace(v[i - 1])) i--;
128
- while (i > 0 && !isWhitespace(v[i - 1])) i--;
129
- if (i === c) return;
130
- this.#historyEdit();
131
- this.state.set({
132
- cursor: i,
133
- value: v.slice(0, i) + v.slice(c)
134
- });
135
- },
136
- "input.insertNewline": () => {
137
- const v = this.state.value ?? "";
138
- const c = this.#cursor();
139
- this.#preferredCol = void 0;
140
- let lineStart = c;
141
- while (lineStart > 0 && v[lineStart - 1] !== "\n") lineStart--;
142
- let indent = "";
143
- for (let i = lineStart; i < c; i++) {
144
- const ch = v[i];
145
- if (ch === " " || ch === " ") indent += ch;
146
- else break;
147
- }
148
- const insert = `\n${indent}`;
149
- this.#historyEdit();
150
- this.state.set({
151
- cursor: c + insert.length,
152
- value: v.slice(0, c) + insert + v.slice(c)
153
- });
154
- },
155
- "input.insertTab": () => {
156
- const v = this.state.value ?? "";
157
- const c = this.#cursor();
158
- this.#preferredCol = void 0;
159
- const tab = " ";
160
- this.#historyEdit();
161
- this.state.set({
162
- cursor: c + 2,
163
- value: v.slice(0, c) + tab + v.slice(c)
164
- });
165
- },
166
- "input.paste": () => {
167
- (async () => {
168
- const content = await clipboard.read();
169
- if (!content) return;
170
- if (content.kind === "text") {
171
- this.emit("paste", { paste: {
172
- stop: () => void 0,
173
- stopped: false,
174
- text: content.text
175
- } });
176
- return;
177
- }
178
- const paths = content.kind === "image" ? [content.path] : content.paths;
179
- const files = await Promise.all(paths.map((path) => fileDetect({ path })));
180
- for (let i = 0; i < paths.length; i++) {
181
- const path = paths[i];
182
- const file = files[i];
183
- if (!file) continue;
184
- this.attach({
185
- ...file,
186
- path
187
- });
188
- }
189
- })();
190
- },
191
- "input.submit": () => {
192
- const value = this.state.value ?? "";
193
- if (this.state.validate?.(value) === false) return;
194
- const ret = this.consume();
195
- this.#historyAdd(ret.value);
196
- this.emit("submit", ret);
197
- }
198
- };
199
- constructor(initial = {}) {
200
- const value = initial.value ?? "";
201
- super({
202
- cursor: value.length,
203
- value,
204
- ...initial
205
- });
206
- this.#history = [...initial.history ?? []];
207
- this.on("key", ({ key }) => {
208
- this.#handleKey(key);
209
- });
210
- this.on("paste", ({ paste }) => {
211
- this.paste(paste.text);
212
- paste.stop();
213
- });
214
- this.on("focus", () => {
215
- this.#focused = true;
216
- this.invalidate();
217
- });
218
- this.on("blur", () => {
219
- this.#focused = false;
220
- this.invalidate();
221
- });
222
- this.on("mount", () => {
223
- this.ctx?.input.events.on("terminal-focus", () => this.invalidate(), { signal: this.mountSignal });
224
- });
225
- }
226
- get history() {
227
- return this.#history;
228
- }
229
- set history(v) {
230
- this.#history = [...v];
231
- this.#historyIndex = void 0;
232
- }
233
- attach(att) {
234
- if (att.type !== "paste" && this.state.canAttach?.(att) === false) return this.insert(att.path);
235
- const id = this.#staged.length + 1;
236
- let prefix = att.type[0].toUpperCase() + att.type.slice(1);
237
- let suffix = "";
238
- if (att.type === "paste") {
239
- prefix = "Pasted text";
240
- suffix = ` +${countLines(att.text)} lines`;
241
- } else if (!["image", "pdf"].includes(att.type)) suffix = ` ${basename(att.path)}`;
242
- const marker = `[${prefix} #${id}${suffix}]`;
243
- this.#staged.push({
244
- ...att,
245
- id,
246
- marker
247
- });
248
- this.insert(marker);
249
- if (att.type !== "paste") this.emit("attach", { attachment: att });
250
- }
251
- paste(text) {
252
- if (countLines(text) > (this.state.pasteMaxLines ?? PASTE_MAX_LINES) || stringWidth(text) > (this.state.pasteMaxChars ?? PASTE_MAX_CHARS)) return this.attach({
253
- text,
254
- type: "paste"
255
- });
256
- this.insert(text);
257
- }
258
- insert(text) {
259
- const v = this.state.value ?? "";
260
- const c = this.#cursor();
261
- this.#historyEdit();
262
- this.#preferredCol = void 0;
263
- this.state.set({
264
- cursor: c + text.length,
265
- value: v.slice(0, c) + text + v.slice(c)
266
- });
267
- }
268
- replace(text) {
269
- this.state.value = "";
270
- this.insert(text);
271
- }
272
- /** Consume the input's current value and attachments.
273
- * Pastes are replaced inline with their text; file/image
274
- * attachments are returned in the `attachments` array and removed from the value. */
275
- consume() {
276
- let value = this.state.value ?? "";
277
- const atts = [];
278
- for (const att of this.#staged) {
279
- if (!value.includes(att.marker)) continue;
280
- if (att.type === "paste") value = value.replace(att.marker, att.text);
281
- else atts.push(att);
282
- }
283
- this.#staged = [];
284
- this.#preferredCol = void 0;
285
- this.state.set({
286
- cursor: 0,
287
- value: ""
288
- });
289
- return {
290
- attachments: atts,
291
- value
292
- };
293
- }
294
- #cursor() {
295
- const v = this.state.value ?? "";
296
- return Math.max(0, Math.min(v.length, this.state.cursor ?? 0));
297
- }
298
- #deleteRange(start, end) {
299
- const v = this.state.value ?? "";
300
- this.#historyEdit();
301
- this.#preferredCol = void 0;
302
- this.state.set({
303
- cursor: start,
304
- value: v.slice(0, start) + v.slice(end)
305
- });
306
- }
307
- historyAdd(value) {
308
- this.#historyAdd(value);
309
- }
310
- #historyAdd(value) {
311
- if (value.trim() === "") return;
312
- if (this.#history.at(-1) !== value) {
313
- this.#history.push(value);
314
- this.emit("history", {
315
- added: value,
316
- history: [...this.#history]
317
- });
318
- }
319
- this.#historyDraft = "";
320
- this.#historyIndex = void 0;
321
- }
322
- #historyEdit() {
323
- this.#historyDraft = "";
324
- this.#historyIndex = void 0;
325
- }
326
- #historyNext() {
327
- if (this.#historyIndex === void 0) return;
328
- const next = this.#historyIndex + 1;
329
- if (next >= this.#history.length) {
330
- this.#historySet(this.#historyDraft);
331
- this.#historyDraft = "";
332
- this.#historyIndex = void 0;
333
- return;
334
- }
335
- this.#historyIndex = next;
336
- this.#historySet(this.#history[next]);
337
- }
338
- #historyPrev() {
339
- if (this.#history.length === 0) return;
340
- if (this.#historyIndex === void 0) {
341
- this.#historyDraft = this.state.value ?? "";
342
- this.#historyIndex = this.#history.length - 1;
343
- } else if (this.#historyIndex > 0) this.#historyIndex--;
344
- this.#historySet(this.#history[this.#historyIndex]);
345
- }
346
- #historySet(value) {
347
- this.#preferredCol = void 0;
348
- this.state.set({
349
- cursor: value.length,
350
- value
351
- });
352
- }
353
- #markerRange(pos, dir) {
354
- const value = this.state.value ?? "";
355
- for (const att of this.#staged) {
356
- const start = value.indexOf(att.marker);
357
- if (start === -1) continue;
358
- const end = start + att.marker.length;
359
- if (dir === "back" && pos > start && pos <= end) return {
360
- end,
361
- start
362
- };
363
- if (dir === "forward" && pos >= start && pos < end) return {
364
- end,
365
- start
366
- };
367
- }
368
- }
369
- #handleKey(ev) {
370
- if (ev.text === void 0 || ev.ctrl || ev.alt || ev.meta) return;
371
- this.insert(ev.text);
372
- ev.stop();
373
- }
374
- #format(value, ctx) {
375
- const format = this.state.format;
376
- if (!format) return value;
377
- if (ctx.version !== this.#formatCache.version) {
378
- this.#formatCache.clear();
379
- this.#formatCache.version = ctx.version;
380
- }
381
- const key = hash(value);
382
- const cached = this.#formatCache.get(key);
383
- if (cached?.result !== void 0) return cached.result;
384
- const streaming = this.#streamingFormat(value);
385
- if (cached?.promise) return streaming ?? value;
386
- const ret = format(value, { style: ctx.style });
387
- if (!isPromiseLike(ret)) return ret;
388
- const gen = ++this.#formatGen;
389
- const entry = { input: value };
390
- entry.promise = ret.then((result) => {
391
- if (this.#formatCache.get(key) !== entry) return;
392
- entry.result = result;
393
- entry.promise = void 0;
394
- if (this.#formatGen === gen && result !== value) untrack(() => this.invalidate());
395
- }, () => {
396
- if (this.#formatCache.get(key) === entry) this.#formatCache.delete(key);
397
- });
398
- this.#formatCache.set(key, entry);
399
- while (this.#formatCache.size > 100) this.#formatCache.delete(this.#formatCache.keys().next().value);
400
- return streaming ?? value;
401
- }
402
- /** Reuse a highlighted prefix while async formatting catches up. */
403
- #streamingFormat(value) {
404
- let ret;
405
- for (const [key, cached] of this.#formatCache) {
406
- if (cached.result === void 0) continue;
407
- if (value.startsWith(cached.input) && cached.input.length > (ret?.[1].input.length ?? 0)) ret = [key, cached];
408
- }
409
- if (ret === void 0) return;
410
- this.#formatCache.delete(ret[0]);
411
- this.#formatCache.set(ret[0], ret[1]);
412
- return ret[1].result + value.slice(ret[1].input.length);
413
- }
414
- async _render(ctx) {
415
- const value = this.state.value ?? "";
416
- const placeholder = this.state.placeholder ?? "";
417
- const cursor = this.#cursor();
418
- const focused = this.#focused;
419
- let content;
420
- if (value === "") {
421
- const ph = unwrap(placeholder);
422
- content = ph ? ` ${ctx.style.quiet(ph)}` : "";
423
- } else {
424
- content = value;
425
- for (const att of this.#staged) {
426
- if (!content.includes(att.marker)) continue;
427
- content = content.replace(att.marker, ctx.style.accent(att.marker));
428
- }
429
- content = this.#format(content, ctx);
430
- }
431
- if (focused && this.ctx?.input.terminalFocus) {
432
- const { col, line } = posToLineCol(value, cursor);
433
- const lines = splitAnsi(content);
434
- const target = Math.max(0, Math.min(line, lines.length - 1));
435
- const row = lines[target] ?? "";
436
- const head = sliceAnsi(row, 0, col);
437
- const at = sliceAnsi(row, col, col + 1) || " ";
438
- const tail = sliceAnsi(row, col + 1);
439
- lines[target] = head + ctx.style.inverse(at) + tail;
440
- content = lines.join("\n");
441
- }
442
- return formatText(content, {
443
- style: ctx.style.add(this.state),
444
- width: ctx.width,
445
- wrap: "word"
446
- });
447
- }
448
- };
449
- /**
450
- * Factory for `Input`. All fields optional; default is an empty,
451
- * focusable input that fills `ctx.width` and has no placeholder.
452
- *
453
- * ```ts
454
- * input({ placeholder: "type a message…" })
455
- * const i = input({ value: "draft" })
456
- * i.on("submit", (text) => console.log("user typed", text))
457
- * ```
458
- */
459
- function input(state = {}) {
460
- return new Input(state);
461
- }
462
- function isWhitespace(ch) {
463
- return ch !== void 0 && (ch === " " || ch === " " || ch === "\n");
464
- }
465
- function posToLineCol(value, cursor) {
466
- let line = 0;
467
- let col = 0;
468
- for (let i = 0; i < cursor; i++) if (value[i] === "\n") {
469
- line++;
470
- col = 0;
471
- } else col++;
472
- return {
473
- col,
474
- line
475
- };
476
- }
477
- function lineColToPos(value, line, col) {
478
- const lines = value.split("\n");
479
- const clampLine = Math.max(0, Math.min(line, lines.length - 1));
480
- let abs = 0;
481
- for (let i = 0; i < clampLine; i++) abs += lines[i].length + 1;
482
- return abs + Math.min(col, lines[clampLine].length);
483
- }
484
- function lineEndPos(value, cursor) {
485
- let i = cursor;
486
- while (i < value.length && value[i] !== "\n") i++;
487
- return i;
488
- }
489
- function countLines(value) {
490
- let n = 1;
491
- for (const ch of value) if (ch === "\n") n++;
492
- return n;
493
- }
494
- //#endregion
1
+ import { n as input, t as Input } from "../input-CRBuTrsL.mjs";
495
2
  export { Input, input };
496
-
497
- //# sourceMappingURL=input.mjs.map
@@ -1,130 +1,2 @@
1
- import { n as box } from "../box-DyaByEiG.mjs";
2
- import { text } from "./text.mjs";
3
- import { markdown } from "./markdown.mjs";
4
- import { widget } from "./widget.mjs";
5
- import { stringWidth } from "@zaly/shared/ansi";
6
- import { hasColors } from "@zaly/shared/env";
7
- //#region src/widgets/log.ts
8
- /** Per-level default prefix style + icon + color. Matches rekal's
9
- * `defaultStyles` table, adapted to zaly's theme slots. */
10
- const defaultLogStyles = {
11
- cancel: {
12
- color: "warn",
13
- icon: "✖ ",
14
- style: "icon"
15
- },
16
- debug: {
17
- color: "info",
18
- icon: "⚙ ",
19
- style: "prompt"
20
- },
21
- error: {
22
- color: "error",
23
- icon: "✖ ",
24
- style: "badge",
25
- textColor: "error"
26
- },
27
- fatal: {
28
- color: "error",
29
- icon: "☢ ",
30
- style: "badge"
31
- },
32
- info: {
33
- color: "info",
34
- icon: "ℹ ",
35
- style: "icon"
36
- },
37
- log: {
38
- color: "muted",
39
- icon: "●",
40
- style: "icon"
41
- },
42
- success: {
43
- color: "success",
44
- icon: "✔ ",
45
- style: "icon"
46
- },
47
- trace: {
48
- color: "muted",
49
- icon: "⠿",
50
- style: "icon",
51
- textColor: "muted"
52
- },
53
- warn: {
54
- color: "warn",
55
- icon: "⚠",
56
- style: "badge",
57
- textColor: "warn"
58
- }
59
- };
60
- const noColorStyles = {
61
- badge: "title",
62
- icon: "text",
63
- notif: "text",
64
- prompt: "text",
65
- text: "text",
66
- title: "text"
67
- };
68
- function renderPrefix(s, ctx) {
69
- const style = ctx.style;
70
- const base = defaultLogStyles[s.level];
71
- let ls = s.style ?? base.style;
72
- if (!hasColors) ls = noColorStyles[ls];
73
- let icon = s.icon ?? base.icon ?? "";
74
- icon = icon === "" ? "" : `${icon}${" ".repeat(2 - stringWidth(icon))}`;
75
- const color = s.color ?? base.color ?? "inherit";
76
- let styledPrefix = "";
77
- if (ls === "badge") styledPrefix = style.bg(color).fg("black").bold(` ${s.level} `);
78
- else if (ls === "icon") styledPrefix = style.fg(color)(icon);
79
- else if (ls === "prompt") styledPrefix = style.fg(color).bold(`${icon} ${s.level}`);
80
- else if (ls === "title") styledPrefix = style.fg(color).bold(`${s.level}:`);
81
- else if (ls === "notif") styledPrefix = style.fg(color).bold(`${icon} ${s.title ?? s.level}`);
82
- if (s.prefix) styledPrefix = s.prefix + styledPrefix;
83
- if (s.title && ls !== "notif") styledPrefix += style.bold(` ${s.title}`);
84
- return styledPrefix;
85
- }
86
- /**
87
- * A single log entry — level-styled prefix (icon / badge / prompt / title /
88
- * plain text) followed by the body content. The body can be any Node, so
89
- * callers can stack markdown, code, images, etc. inside a log line.
90
- *
91
- * ```ts
92
- * log({ level: "info", content: "hello" })
93
- * log({ level: "error", content: markdown("**boom**") })
94
- * ```
95
- */
96
- const log = widget((state, ...children) => {
97
- const base = defaultLogStyles[state.level];
98
- const color = state.color ?? base.color ?? "inherit";
99
- const s = state;
100
- const textColor = state.textColor ?? (s.style === "notif" ? "inherit" : base.textColor);
101
- const style = {
102
- style: textColor ? { fg: textColor } : void 0,
103
- width: "fill"
104
- };
105
- if (state.content !== "") children = [state.markdown ?? true ? markdown(state.content, style) : text(state.content, style), ...children];
106
- return box({
107
- ...s.style === "notif" ? {
108
- border: "single",
109
- borderStyle: { fg: color },
110
- borderTitle: (ctx) => renderPrefix(state, ctx),
111
- borderTitleAlign: "center",
112
- padding: [0, 1],
113
- width: "fill"
114
- } : void 0,
115
- flexDirection: "row",
116
- gap: 1,
117
- visible: state.visible
118
- }, s.style === "notif" ? void 0 : text((ctx) => renderPrefix(state, ctx), {
119
- flexShrink: 0,
120
- wrap: "none"
121
- }), box({
122
- flexDirection: "column",
123
- flexGrow: 1,
124
- gap: 1
125
- }, ...children));
126
- });
127
- //#endregion
1
+ import { t as log } from "../log-Djvrxqk0.mjs";
128
2
  export { log };
129
-
130
- //# sourceMappingURL=log.mjs.map
@@ -1,8 +1,8 @@
1
1
  import { J as Layout, P as RenderCtx, U as TextContent, X as State, p as Node } from "../queries-DH3bj74K.mjs";
2
2
  import { o as AnyStyle } from "../types-B9Eh7k2v.mjs";
3
- import { WrapMode } from "../text.mjs";
3
+ import { t as WrapMode } from "../text-9lwQeqYr.mjs";
4
4
  import { n as MdOptions } from "../types-D3jk1rtk.mjs";
5
- import { Image } from "./image.mjs";
5
+ import { t as Image } from "../image-BTxDPPiT.mjs";
6
6
  //#region src/widgets/markdown.d.ts
7
7
  interface MarkdownState {
8
8
  /** Markdown source. Accepts a plain string or a reactive accessor —