silvery 0.17.0 → 0.17.2

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 (171) hide show
  1. package/dist/UPNG-AVSMjiFE.mjs +5076 -0
  2. package/dist/UPNG-AVSMjiFE.mjs.map +1 -0
  3. package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs +6 -0
  4. package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs.map +1 -0
  5. package/dist/animation-C_PTO0uH.mjs +304 -0
  6. package/dist/animation-C_PTO0uH.mjs.map +1 -0
  7. package/dist/ansi-CXLE_pt1.mjs +71 -0
  8. package/dist/ansi-CXLE_pt1.mjs.map +1 -0
  9. package/dist/ansi-zmNzgkPB.d.mts +49 -0
  10. package/dist/ansi-zmNzgkPB.d.mts.map +1 -0
  11. package/dist/apng-DCWY913R.mjs +3 -0
  12. package/dist/apng-ENBAJk-H.mjs +70 -0
  13. package/dist/apng-ENBAJk-H.mjs.map +1 -0
  14. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  15. package/dist/backend-CkIkIHR-.mjs +13396 -0
  16. package/dist/backend-CkIkIHR-.mjs.map +1 -0
  17. package/dist/backends-CkvbG3js.mjs +1181 -0
  18. package/dist/backends-CkvbG3js.mjs.map +1 -0
  19. package/dist/backends-CyJqNLeK.mjs +3 -0
  20. package/dist/chunk-BSw8zbkd.mjs +37 -0
  21. package/dist/cli-B-k7Bm56.mjs +4 -0
  22. package/dist/context-QreF3UHr.mjs +64 -0
  23. package/dist/context-QreF3UHr.mjs.map +1 -0
  24. package/dist/derive-D7bFJdfU.d.mts +28 -0
  25. package/dist/derive-D7bFJdfU.d.mts.map +1 -0
  26. package/dist/devtools-CscuKaDK.mjs +89 -0
  27. package/dist/devtools-CscuKaDK.mjs.map +1 -0
  28. package/dist/devtools-D4oGc6LY.mjs +2 -0
  29. package/dist/eta-DLiVPaSD.mjs +110 -0
  30. package/dist/eta-DLiVPaSD.mjs.map +1 -0
  31. package/dist/flexily-zero-adapter-DmG4Ge8t.mjs +3376 -0
  32. package/dist/flexily-zero-adapter-DmG4Ge8t.mjs.map +1 -0
  33. package/dist/flexily-zero-adapter-GHwEW11s.mjs +2 -0
  34. package/dist/gif-BaJNREpP.mjs +3 -0
  35. package/dist/gif-Bp6fIyN3.mjs +73 -0
  36. package/dist/gif-Bp6fIyN3.mjs.map +1 -0
  37. package/dist/gifenc-GiVCZ9-3.mjs +730 -0
  38. package/dist/gifenc-GiVCZ9-3.mjs.map +1 -0
  39. package/dist/image-Dx7gYjkq.mjs +346 -0
  40. package/dist/image-Dx7gYjkq.mjs.map +1 -0
  41. package/dist/index-CBcSpGSM.d.mts +3416 -0
  42. package/dist/index-CBcSpGSM.d.mts.map +1 -0
  43. package/dist/index-DCVL3jHo.d.mts +634 -0
  44. package/dist/index-DCVL3jHo.d.mts.map +1 -0
  45. package/dist/index-p-wBs_wH.d.mts +175 -0
  46. package/dist/index-p-wBs_wH.d.mts.map +1 -0
  47. package/dist/index.d.mts +7296 -0
  48. package/dist/index.d.mts.map +1 -0
  49. package/dist/index.mjs +9399 -0
  50. package/dist/index.mjs.map +1 -0
  51. package/dist/key-mapping-BsUHe_nk.mjs +3 -0
  52. package/dist/key-mapping-DsyfLEdC.mjs +132 -0
  53. package/dist/key-mapping-DsyfLEdC.mjs.map +1 -0
  54. package/dist/layout-engine-B3dsnVLU.mjs +50 -0
  55. package/dist/layout-engine-B3dsnVLU.mjs.map +1 -0
  56. package/dist/layout-engine-D_lSR4i9.mjs +2 -0
  57. package/dist/multi-progress-C0-rkn86.d.mts +180 -0
  58. package/dist/multi-progress-C0-rkn86.d.mts.map +1 -0
  59. package/dist/multi-progress-CQVB9lES.mjs +219 -0
  60. package/dist/multi-progress-CQVB9lES.mjs.map +1 -0
  61. package/dist/node-Dedx-6xF.mjs +1085 -0
  62. package/dist/node-Dedx-6xF.mjs.map +1 -0
  63. package/dist/pipeline-DDOPrjuY.mjs +4387 -0
  64. package/dist/pipeline-DDOPrjuY.mjs.map +1 -0
  65. package/dist/progress-bar-COPSBlT9.mjs +155 -0
  66. package/dist/progress-bar-COPSBlT9.mjs.map +1 -0
  67. package/dist/reconciler-2lp5VXK7.mjs +16506 -0
  68. package/dist/reconciler-2lp5VXK7.mjs.map +1 -0
  69. package/dist/render-string-BXvxTg5P.mjs +201 -0
  70. package/dist/render-string-BXvxTg5P.mjs.map +1 -0
  71. package/dist/render-string-hvfpVtoP.mjs +2 -0
  72. package/dist/resvg-js-V6oMi8CY.mjs +203 -0
  73. package/dist/resvg-js-V6oMi8CY.mjs.map +1 -0
  74. package/dist/runtime-BjDHNTxJ.mjs +8723 -0
  75. package/dist/runtime-BjDHNTxJ.mjs.map +1 -0
  76. package/dist/runtime.d.mts +2 -0
  77. package/dist/runtime.mjs +3 -0
  78. package/dist/spinner-Cgej6Vnb.d.mts +127 -0
  79. package/dist/spinner-Cgej6Vnb.d.mts.map +1 -0
  80. package/dist/spinner-DSByknyx.mjs +298 -0
  81. package/dist/spinner-DSByknyx.mjs.map +1 -0
  82. package/dist/src-9B5k0JmY.mjs +1629 -0
  83. package/dist/src-9B5k0JmY.mjs.map +1 -0
  84. package/dist/src-C9f3hiVG.mjs +3620 -0
  85. package/dist/src-C9f3hiVG.mjs.map +1 -0
  86. package/dist/src-fJVbhdn-.mjs +816 -0
  87. package/dist/src-fJVbhdn-.mjs.map +1 -0
  88. package/dist/theme.d.mts +115 -0
  89. package/dist/theme.d.mts.map +1 -0
  90. package/dist/theme.mjs +8 -0
  91. package/dist/theme.mjs.map +1 -0
  92. package/dist/types-Bhj5QkIQ.mjs +13 -0
  93. package/dist/types-Bhj5QkIQ.mjs.map +1 -0
  94. package/dist/types-CDgkE-Rw.d.mts +241 -0
  95. package/dist/types-CDgkE-Rw.d.mts.map +1 -0
  96. package/dist/ui/animation.d.mts +2 -0
  97. package/dist/ui/animation.mjs +2 -0
  98. package/dist/ui/ansi.d.mts +2 -0
  99. package/dist/ui/ansi.mjs +2 -0
  100. package/dist/ui/cli.d.mts +5 -0
  101. package/dist/ui/cli.mjs +7 -0
  102. package/dist/ui/display.d.mts +35 -0
  103. package/dist/ui/display.d.mts.map +1 -0
  104. package/dist/ui/display.mjs +123 -0
  105. package/dist/ui/display.mjs.map +1 -0
  106. package/dist/ui/image.d.mts +2 -0
  107. package/dist/ui/image.mjs +2 -0
  108. package/dist/ui/input.d.mts +184 -0
  109. package/dist/ui/input.d.mts.map +1 -0
  110. package/dist/ui/input.mjs +285 -0
  111. package/dist/ui/input.mjs.map +1 -0
  112. package/dist/ui/progress.d.mts +249 -0
  113. package/dist/ui/progress.d.mts.map +1 -0
  114. package/dist/ui/progress.mjs +858 -0
  115. package/dist/ui/progress.mjs.map +1 -0
  116. package/dist/ui/react.d.mts +280 -0
  117. package/dist/ui/react.d.mts.map +1 -0
  118. package/dist/ui/react.mjs +413 -0
  119. package/dist/ui/react.mjs.map +1 -0
  120. package/dist/ui/utils.d.mts +86 -0
  121. package/dist/ui/utils.d.mts.map +1 -0
  122. package/dist/ui/utils.mjs +2 -0
  123. package/dist/ui/wrappers.d.mts +3 -0
  124. package/dist/ui/wrappers.mjs +2 -0
  125. package/dist/ui.d.mts +6 -0
  126. package/dist/ui.mjs +7 -0
  127. package/dist/useLatest-BMIYXd6e.d.mts +154 -0
  128. package/dist/useLatest-BMIYXd6e.d.mts.map +1 -0
  129. package/dist/useLayout-BG2cGl15.mjs +139 -0
  130. package/dist/useLayout-BG2cGl15.mjs.map +1 -0
  131. package/dist/with-text-input-CmHf_9d6.d.mts +284 -0
  132. package/dist/with-text-input-CmHf_9d6.d.mts.map +1 -0
  133. package/dist/wrapper-Dqh0zi2W.mjs +3527 -0
  134. package/dist/wrapper-Dqh0zi2W.mjs.map +1 -0
  135. package/dist/wrappers-hhL8EQ_n.mjs +810 -0
  136. package/dist/wrappers-hhL8EQ_n.mjs.map +1 -0
  137. package/dist/yoga-adapter-BJ9SOhTY.mjs +245 -0
  138. package/dist/yoga-adapter-BJ9SOhTY.mjs.map +1 -0
  139. package/dist/yoga-adapter-Daq6-dw1.mjs +2 -0
  140. package/package.json +48 -75
  141. package/CHANGELOG.md +0 -319
  142. package/dist/chalk.js +0 -4
  143. package/dist/index.js +0 -270
  144. package/dist/ink.js +0 -142
  145. package/dist/runtime.js +0 -135
  146. package/dist/theme.js +0 -7
  147. package/dist/ui/animation.js +0 -3
  148. package/dist/ui/ansi.js +0 -3
  149. package/dist/ui/cli.js +0 -9
  150. package/dist/ui/display.js +0 -4
  151. package/dist/ui/image.js +0 -4
  152. package/dist/ui/input.js +0 -3
  153. package/dist/ui/progress.js +0 -9
  154. package/dist/ui/react.js +0 -4
  155. package/dist/ui/utils.js +0 -3
  156. package/dist/ui/wrappers.js +0 -15
  157. package/dist/ui.js +0 -18
  158. package/src/index.ts +0 -73
  159. package/src/runtime.ts +0 -4
  160. package/src/theme.ts +0 -4
  161. package/src/ui/animation.ts +0 -2
  162. package/src/ui/ansi.ts +0 -2
  163. package/src/ui/cli.ts +0 -3
  164. package/src/ui/display.ts +0 -2
  165. package/src/ui/image.ts +0 -2
  166. package/src/ui/input.ts +0 -2
  167. package/src/ui/progress.ts +0 -2
  168. package/src/ui/react.ts +0 -2
  169. package/src/ui/utils.ts +0 -2
  170. package/src/ui/wrappers.ts +0 -2
  171. package/src/ui.ts +0 -4
@@ -0,0 +1,413 @@
1
+ import { n as SPINNER_INTERVALS, t as SPINNER_FRAMES } from "../spinner-DSByknyx.mjs";
2
+ import { a as getETA } from "../eta-DLiVPaSD.mjs";
3
+ import React, { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region packages/ag-react/src/ui/react/Spinner.tsx
6
+ /**
7
+ * React Spinner component for silvery/Ink TUI apps
8
+ */
9
+ /**
10
+ * Animated spinner component for React TUI apps
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * import { Spinner } from "@silvery/ag-react/ui/react";
15
+ *
16
+ * function LoadingView() {
17
+ * return <Spinner label="Loading..." />;
18
+ * }
19
+ *
20
+ * // With style
21
+ * <Spinner label="Processing..." style="arc" color="yellow" />
22
+ * ```
23
+ */
24
+ function Spinner({ label, style = "dots", color = "cyan" }) {
25
+ const [frameIndex, setFrameIndex] = useState(0);
26
+ const frames = SPINNER_FRAMES[style];
27
+ const interval = SPINNER_INTERVALS[style];
28
+ useEffect(() => {
29
+ const timer = setInterval(() => {
30
+ setFrameIndex((i) => (i + 1) % frames.length);
31
+ }, interval);
32
+ return () => clearInterval(timer);
33
+ }, [frames.length, interval]);
34
+ const frame = frames[frameIndex];
35
+ return /* @__PURE__ */ jsxs("span", {
36
+ "data-progressx-spinner": true,
37
+ "data-color": color,
38
+ children: [frame, label && /* @__PURE__ */ jsxs("span", { children: [" ", label] })]
39
+ });
40
+ }
41
+ /**
42
+ * Hook for using spinner state in custom components
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * function CustomSpinner() {
47
+ * const frame = useSpinnerFrame("dots");
48
+ * return <Text color="cyan">{frame}</Text>;
49
+ * }
50
+ * ```
51
+ */
52
+ function useSpinnerFrame(style = "dots") {
53
+ const [frameIndex, setFrameIndex] = useState(0);
54
+ const frames = SPINNER_FRAMES[style];
55
+ const interval = SPINNER_INTERVALS[style];
56
+ useEffect(() => {
57
+ const timer = setInterval(() => {
58
+ setFrameIndex((i) => (i + 1) % frames.length);
59
+ }, interval);
60
+ return () => clearInterval(timer);
61
+ }, [frames.length, interval]);
62
+ return frames[frameIndex];
63
+ }
64
+ //#endregion
65
+ //#region packages/ag-react/src/ui/react/ProgressBar.tsx
66
+ /**
67
+ * React ProgressBar component for silvery/Ink TUI apps
68
+ */
69
+ /**
70
+ * Progress bar component for React TUI apps
71
+ *
72
+ * @example
73
+ * ```tsx
74
+ * import { ProgressBar } from "@silvery/ag-react/ui/react";
75
+ *
76
+ * function DownloadProgress({ current, total }) {
77
+ * return (
78
+ * <ProgressBar
79
+ * value={current}
80
+ * total={total}
81
+ * showPercentage
82
+ * showETA
83
+ * />
84
+ * );
85
+ * }
86
+ * ```
87
+ */
88
+ function ProgressBar({ value, total, width = 40, showPercentage = true, showETA = false, label, color = "cyan" }) {
89
+ const [eta, setEta] = useState("--:--");
90
+ const etaBuffer = useRef([]);
91
+ useEffect(() => {
92
+ const now = Date.now();
93
+ etaBuffer.current.push({
94
+ time: now,
95
+ value
96
+ });
97
+ if (etaBuffer.current.length > 10) etaBuffer.current.shift();
98
+ setEta(getETA(etaBuffer.current, value, total).formatted);
99
+ }, [value, total]);
100
+ const percent = total > 0 ? value / total : 0;
101
+ const percentDisplay = `${Math.round(percent * 100)}%`;
102
+ const filledWidth = Math.round(width * percent);
103
+ const emptyWidth = width - filledWidth;
104
+ const bar = "█".repeat(filledWidth) + "░".repeat(emptyWidth);
105
+ const parts = [];
106
+ if (label) parts.push(label);
107
+ parts.push(`[${bar}]`);
108
+ if (showPercentage) parts.push(percentDisplay.padStart(4));
109
+ if (showETA) parts.push(`ETA: ${eta}`);
110
+ return /* @__PURE__ */ jsx("span", {
111
+ "data-progressx-bar": true,
112
+ "data-color": color,
113
+ "data-percent": percent,
114
+ children: parts.join(" ")
115
+ });
116
+ }
117
+ /**
118
+ * Hook for progress bar state management
119
+ *
120
+ * @example
121
+ * ```tsx
122
+ * function MyProgress() {
123
+ * const { value, total, update, increment, eta, percent } = useProgressBar(100);
124
+ *
125
+ * useEffect(() => {
126
+ * const timer = setInterval(() => increment(), 100);
127
+ * return () => clearInterval(timer);
128
+ * }, []);
129
+ *
130
+ * return <Text>{percent}% - ETA: {eta}</Text>;
131
+ * }
132
+ * ```
133
+ */
134
+ function useProgressBar(initialTotal) {
135
+ const [value, setValue] = useState(0);
136
+ const [total, setTotal] = useState(initialTotal);
137
+ const etaBuffer = useRef([]);
138
+ const [eta, setEta] = useState("--:--");
139
+ const update = (newValue) => {
140
+ setValue(newValue);
141
+ const now = Date.now();
142
+ etaBuffer.current.push({
143
+ time: now,
144
+ value: newValue
145
+ });
146
+ if (etaBuffer.current.length > 10) etaBuffer.current.shift();
147
+ setEta(getETA(etaBuffer.current, newValue, total).formatted);
148
+ };
149
+ const increment = (amount = 1) => update(value + amount);
150
+ const reset = (newTotal) => {
151
+ setValue(0);
152
+ if (newTotal !== void 0) setTotal(newTotal);
153
+ etaBuffer.current = [];
154
+ setEta("--:--");
155
+ };
156
+ return {
157
+ value,
158
+ total,
159
+ percent: total > 0 ? Math.round(value / total * 100) : 0,
160
+ eta,
161
+ update,
162
+ increment,
163
+ reset,
164
+ setTotal
165
+ };
166
+ }
167
+ //#endregion
168
+ //#region packages/ag-react/src/ui/react/Tasks.tsx
169
+ /**
170
+ * React Tasks component - listr2-style task list for TUI apps
171
+ */
172
+ /** Status icons for tasks */
173
+ const STATUS_ICONS = {
174
+ pending: "○",
175
+ running: "",
176
+ completed: "✔",
177
+ failed: "✖",
178
+ skipped: "⊘"
179
+ };
180
+ /** Status colors */
181
+ const STATUS_COLORS = {
182
+ pending: "gray",
183
+ running: "cyan",
184
+ completed: "green",
185
+ failed: "red",
186
+ skipped: "yellow"
187
+ };
188
+ /**
189
+ * Single task component
190
+ *
191
+ * @example
192
+ * ```tsx
193
+ * <Task title="Downloading files" status="running">
194
+ * <ProgressBar value={50} total={100} />
195
+ * </Task>
196
+ * ```
197
+ */
198
+ function Task({ title, status, children }) {
199
+ const spinnerFrame = useSpinnerFrame("dots");
200
+ const icon = status === "running" ? spinnerFrame : STATUS_ICONS[status];
201
+ const color = STATUS_COLORS[status];
202
+ return /* @__PURE__ */ jsxs("div", {
203
+ "data-progressx-task": true,
204
+ "data-status": status,
205
+ "data-color": color,
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", {
208
+ "data-icon": true,
209
+ children: icon
210
+ }),
211
+ /* @__PURE__ */ jsxs("span", {
212
+ "data-title": true,
213
+ children: [" ", title]
214
+ }),
215
+ children != null ? /* @__PURE__ */ jsx("div", {
216
+ "data-children": true,
217
+ children
218
+ }) : null
219
+ ]
220
+ });
221
+ }
222
+ /**
223
+ * Container for multiple tasks
224
+ *
225
+ * @example
226
+ * ```tsx
227
+ * <Tasks>
228
+ * <Task title="Scanning files" status="completed" />
229
+ * <Task title="Processing" status="running">
230
+ * <ProgressBar value={current} total={total} />
231
+ * </Task>
232
+ * <Task title="Cleanup" status="pending" />
233
+ * </Tasks>
234
+ * ```
235
+ */
236
+ function Tasks({ children }) {
237
+ return /* @__PURE__ */ jsx("div", {
238
+ "data-progressx-tasks": true,
239
+ children
240
+ });
241
+ }
242
+ /**
243
+ * Hook for managing task state
244
+ *
245
+ * @example
246
+ * ```tsx
247
+ * function MyTasks() {
248
+ * const { tasks, start, complete, fail, updateProgress } = useTasks([
249
+ * { id: 'scan', title: 'Scanning' },
250
+ * { id: 'process', title: 'Processing' },
251
+ * ]);
252
+ *
253
+ * useEffect(() => {
254
+ * start('scan');
255
+ * doScan().then(() => {
256
+ * complete('scan');
257
+ * start('process');
258
+ * });
259
+ * }, []);
260
+ *
261
+ * return (
262
+ * <Tasks>
263
+ * {tasks.map(t => <Task key={t.id} title={t.title} status={t.status} />)}
264
+ * </Tasks>
265
+ * );
266
+ * }
267
+ * ```
268
+ */
269
+ function useTasks(initialTasks) {
270
+ const [tasks, setTasks] = React.useState(initialTasks.map((t) => ({
271
+ ...t,
272
+ status: "pending"
273
+ })));
274
+ const updateTask = (id, updates) => {
275
+ setTasks((prev) => prev.map((t) => t.id === id ? {
276
+ ...t,
277
+ ...updates
278
+ } : t));
279
+ };
280
+ const start = (id) => updateTask(id, { status: "running" });
281
+ const complete = (id, title) => updateTask(id, {
282
+ status: "completed",
283
+ ...title && { title }
284
+ });
285
+ const fail = (id, title) => updateTask(id, {
286
+ status: "failed",
287
+ ...title && { title }
288
+ });
289
+ const skip = (id, title) => updateTask(id, {
290
+ status: "skipped",
291
+ ...title && { title }
292
+ });
293
+ const updateProgress = (id, progress) => updateTask(id, { progress });
294
+ const getTask = (id) => tasks.find((t) => t.id === id);
295
+ return {
296
+ tasks,
297
+ start,
298
+ complete,
299
+ fail,
300
+ skip,
301
+ updateProgress,
302
+ updateTask,
303
+ getTask,
304
+ allCompleted: tasks.every((t) => t.status === "completed" || t.status === "skipped"),
305
+ hasFailed: tasks.some((t) => t.status === "failed")
306
+ };
307
+ }
308
+ //#endregion
309
+ //#region packages/ag-react/src/ui/react/context.tsx
310
+ /**
311
+ * React context for progress state management
312
+ */
313
+ const ProgressContext = createContext(null);
314
+ /**
315
+ * Progress context provider
316
+ *
317
+ * @example
318
+ * ```tsx
319
+ * function App() {
320
+ * return (
321
+ * <ProgressProvider>
322
+ * <MyApp />
323
+ * </ProgressProvider>
324
+ * );
325
+ * }
326
+ *
327
+ * function DeepComponent() {
328
+ * const { showSpinner, hideSpinner } = useProgress();
329
+ *
330
+ * const handleLoad = async () => {
331
+ * showSpinner("Loading...");
332
+ * await loadData();
333
+ * hideSpinner();
334
+ * };
335
+ * }
336
+ * ```
337
+ */
338
+ function ProgressProvider({ children }) {
339
+ const [isLoading, setIsLoading] = useState(false);
340
+ const [loadingText, setLoadingText] = useState("");
341
+ const [spinnerStyle, setSpinnerStyle] = useState("dots");
342
+ const [progress, setProgress] = useState(null);
343
+ const value = {
344
+ isLoading,
345
+ loadingText,
346
+ spinnerStyle,
347
+ showSpinner: useCallback((text, style = "dots") => {
348
+ setLoadingText(text);
349
+ setSpinnerStyle(style);
350
+ setIsLoading(true);
351
+ }, []),
352
+ hideSpinner: useCallback(() => {
353
+ setIsLoading(false);
354
+ setLoadingText("");
355
+ }, []),
356
+ progress,
357
+ updateProgress: useCallback((current, total) => {
358
+ setProgress((prev) => ({
359
+ current,
360
+ total: total ?? prev?.total ?? 100
361
+ }));
362
+ }, []),
363
+ clearProgress: useCallback(() => {
364
+ setProgress(null);
365
+ }, [])
366
+ };
367
+ return /* @__PURE__ */ jsx(ProgressContext.Provider, {
368
+ value,
369
+ children
370
+ });
371
+ }
372
+ /**
373
+ * Hook to access progress context
374
+ *
375
+ * @example
376
+ * ```tsx
377
+ * function LoadingOverlay() {
378
+ * const { isLoading, loadingText, spinnerStyle } = useProgress();
379
+ *
380
+ * if (!isLoading) return null;
381
+ *
382
+ * return <Spinner label={loadingText} style={spinnerStyle} />;
383
+ * }
384
+ * ```
385
+ */
386
+ function useProgress() {
387
+ const context = useContext(ProgressContext);
388
+ if (!context) throw new Error("useProgress must be used within a ProgressProvider");
389
+ return context;
390
+ }
391
+ /**
392
+ * Component that renders spinner when loading
393
+ *
394
+ * @example
395
+ * ```tsx
396
+ * <ProgressProvider>
397
+ * <ProgressIndicator />
398
+ * <MainContent />
399
+ * </ProgressProvider>
400
+ * ```
401
+ */
402
+ function ProgressIndicator() {
403
+ const { isLoading, loadingText, spinnerStyle } = useProgress();
404
+ if (!isLoading) return null;
405
+ return /* @__PURE__ */ jsx(Spinner, {
406
+ label: loadingText,
407
+ style: spinnerStyle
408
+ });
409
+ }
410
+ //#endregion
411
+ export { ProgressBar, ProgressIndicator, ProgressProvider, Spinner, Task, Tasks, useProgress, useProgressBar, useSpinnerFrame, useTasks };
412
+
413
+ //# sourceMappingURL=react.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.mjs","names":[],"sources":["../../packages/ag-react/src/ui/react/Spinner.tsx","../../packages/ag-react/src/ui/react/ProgressBar.tsx","../../packages/ag-react/src/ui/react/Tasks.tsx","../../packages/ag-react/src/ui/react/context.tsx"],"sourcesContent":["/**\n * React Spinner component for silvery/Ink TUI apps\n */\n\nimport React, { useState, useEffect } from \"react\"\nimport type { SpinnerProps, SpinnerStyle } from \"../types.js\"\nimport { SPINNER_FRAMES, SPINNER_INTERVALS } from \"../cli/spinner\"\n\n/**\n * Animated spinner component for React TUI apps\n *\n * @example\n * ```tsx\n * import { Spinner } from \"@silvery/ag-react/ui/react\";\n *\n * function LoadingView() {\n * return <Spinner label=\"Loading...\" />;\n * }\n *\n * // With style\n * <Spinner label=\"Processing...\" style=\"arc\" color=\"yellow\" />\n * ```\n */\nexport function Spinner({ label, style = \"dots\", color = \"cyan\" }: SpinnerProps): React.ReactElement {\n const [frameIndex, setFrameIndex] = useState(0)\n const frames = SPINNER_FRAMES[style]\n const interval = SPINNER_INTERVALS[style]\n\n useEffect(() => {\n const timer = setInterval(() => {\n setFrameIndex((i) => (i + 1) % frames.length)\n }, interval)\n\n return () => clearInterval(timer)\n }, [frames.length, interval])\n\n const frame = frames[frameIndex]\n\n // Note: In a real silvery app, you'd use <Text color={color}> etc.\n // This is a generic React component that can be styled by the consumer\n return (\n <span data-progressx-spinner data-color={color}>\n {frame}\n {label && <span> {label}</span>}\n </span>\n )\n}\n\n/**\n * Hook for using spinner state in custom components\n *\n * @example\n * ```tsx\n * function CustomSpinner() {\n * const frame = useSpinnerFrame(\"dots\");\n * return <Text color=\"cyan\">{frame}</Text>;\n * }\n * ```\n */\nexport function useSpinnerFrame(style: SpinnerStyle = \"dots\"): string {\n const [frameIndex, setFrameIndex] = useState(0)\n const frames = SPINNER_FRAMES[style]\n const interval = SPINNER_INTERVALS[style]\n\n useEffect(() => {\n const timer = setInterval(() => {\n setFrameIndex((i) => (i + 1) % frames.length)\n }, interval)\n\n return () => clearInterval(timer)\n }, [frames.length, interval])\n\n return frames[frameIndex]!\n}\n","/**\n * React ProgressBar component for silvery/Ink TUI apps\n */\n\nimport React, { useState, useEffect, useRef } from \"react\"\nimport type { ProgressBarProps } from \"../types.js\"\nimport { getETA, DEFAULT_ETA_BUFFER_SIZE, type ETASample } from \"../utils/eta\"\n\n/**\n * Progress bar component for React TUI apps\n *\n * @example\n * ```tsx\n * import { ProgressBar } from \"@silvery/ag-react/ui/react\";\n *\n * function DownloadProgress({ current, total }) {\n * return (\n * <ProgressBar\n * value={current}\n * total={total}\n * showPercentage\n * showETA\n * />\n * );\n * }\n * ```\n */\nexport function ProgressBar({\n value,\n total,\n width = 40,\n showPercentage = true,\n showETA = false,\n label,\n color = \"cyan\",\n}: ProgressBarProps): React.ReactElement {\n // ETA calculation state\n const [eta, setEta] = useState<string>(\"--:--\")\n const etaBuffer = useRef<ETASample[]>([])\n\n // Update ETA buffer when value changes\n useEffect(() => {\n const now = Date.now()\n etaBuffer.current.push({ time: now, value })\n\n if (etaBuffer.current.length > DEFAULT_ETA_BUFFER_SIZE) {\n etaBuffer.current.shift()\n }\n\n // Calculate ETA using shared utility\n const result = getETA(etaBuffer.current, value, total)\n setEta(result.formatted)\n }, [value, total])\n\n const percent = total > 0 ? value / total : 0\n const percentDisplay = `${Math.round(percent * 100)}%`\n\n const filledWidth = Math.round(width * percent)\n const emptyWidth = width - filledWidth\n\n const bar = \"█\".repeat(filledWidth) + \"░\".repeat(emptyWidth)\n\n // Build the display parts\n const parts: string[] = []\n\n if (label) {\n parts.push(label)\n }\n\n parts.push(`[${bar}]`)\n\n if (showPercentage) {\n parts.push(percentDisplay.padStart(4))\n }\n\n if (showETA) {\n parts.push(`ETA: ${eta}`)\n }\n\n return (\n <span data-progressx-bar data-color={color} data-percent={percent}>\n {parts.join(\" \")}\n </span>\n )\n}\n\n/**\n * Hook for progress bar state management\n *\n * @example\n * ```tsx\n * function MyProgress() {\n * const { value, total, update, increment, eta, percent } = useProgressBar(100);\n *\n * useEffect(() => {\n * const timer = setInterval(() => increment(), 100);\n * return () => clearInterval(timer);\n * }, []);\n *\n * return <Text>{percent}% - ETA: {eta}</Text>;\n * }\n * ```\n */\nexport function useProgressBar(initialTotal: number) {\n const [value, setValue] = useState(0)\n const [total, setTotal] = useState(initialTotal)\n const etaBuffer = useRef<ETASample[]>([])\n const [eta, setEta] = useState<string>(\"--:--\")\n\n const update = (newValue: number) => {\n setValue(newValue)\n\n // Update ETA buffer\n const now = Date.now()\n etaBuffer.current.push({ time: now, value: newValue })\n if (etaBuffer.current.length > DEFAULT_ETA_BUFFER_SIZE) {\n etaBuffer.current.shift()\n }\n\n // Calculate ETA using shared utility\n const result = getETA(etaBuffer.current, newValue, total)\n setEta(result.formatted)\n }\n\n const increment = (amount = 1) => update(value + amount)\n\n const reset = (newTotal?: number) => {\n setValue(0)\n if (newTotal !== undefined) setTotal(newTotal)\n etaBuffer.current = []\n setEta(\"--:--\")\n }\n\n const percent = total > 0 ? Math.round((value / total) * 100) : 0\n\n return {\n value,\n total,\n percent,\n eta,\n update,\n increment,\n reset,\n setTotal,\n }\n}\n","/**\n * React Tasks component - listr2-style task list for TUI apps\n */\n\nimport React from \"react\"\nimport type { TaskProps, TaskStatus } from \"../types.js\"\nimport { useSpinnerFrame } from \"./Spinner\"\n\n/** Status icons for tasks */\nconst STATUS_ICONS: Record<TaskStatus, string> = {\n pending: \"○\",\n running: \"\", // Will use spinner\n completed: \"✔\",\n failed: \"✖\",\n skipped: \"⊘\",\n}\n\n/** Status colors */\nconst STATUS_COLORS: Record<TaskStatus, string> = {\n pending: \"gray\",\n running: \"cyan\",\n completed: \"green\",\n failed: \"red\",\n skipped: \"yellow\",\n}\n\n/**\n * Single task component\n *\n * @example\n * ```tsx\n * <Task title=\"Downloading files\" status=\"running\">\n * <ProgressBar value={50} total={100} />\n * </Task>\n * ```\n */\nexport function Task({ title, status, children }: TaskProps): React.ReactElement {\n const spinnerFrame = useSpinnerFrame(\"dots\")\n const icon = status === \"running\" ? spinnerFrame : STATUS_ICONS[status]\n const color = STATUS_COLORS[status]\n\n return (\n <div data-progressx-task data-status={status} data-color={color}>\n <span data-icon>{icon}</span>\n <span data-title> {title}</span>\n {children != null ? <div data-children>{children as React.ReactNode}</div> : null}\n </div>\n )\n}\n\n/**\n * Container for multiple tasks\n *\n * @example\n * ```tsx\n * <Tasks>\n * <Task title=\"Scanning files\" status=\"completed\" />\n * <Task title=\"Processing\" status=\"running\">\n * <ProgressBar value={current} total={total} />\n * </Task>\n * <Task title=\"Cleanup\" status=\"pending\" />\n * </Tasks>\n * ```\n */\nexport function Tasks({ children }: { children: React.ReactNode }): React.ReactElement {\n return <div data-progressx-tasks>{children}</div>\n}\n\n/**\n * Hook for managing task state\n *\n * @example\n * ```tsx\n * function MyTasks() {\n * const { tasks, start, complete, fail, updateProgress } = useTasks([\n * { id: 'scan', title: 'Scanning' },\n * { id: 'process', title: 'Processing' },\n * ]);\n *\n * useEffect(() => {\n * start('scan');\n * doScan().then(() => {\n * complete('scan');\n * start('process');\n * });\n * }, []);\n *\n * return (\n * <Tasks>\n * {tasks.map(t => <Task key={t.id} title={t.title} status={t.status} />)}\n * </Tasks>\n * );\n * }\n * ```\n */\nexport function useTasks(initialTasks: Array<{ id: string; title: string }>) {\n const [tasks, setTasks] = React.useState<\n Array<{\n id: string\n title: string\n status: TaskStatus\n progress?: { current: number; total: number }\n }>\n >(\n initialTasks.map((t) => ({\n ...t,\n status: \"pending\" as TaskStatus,\n })),\n )\n\n const updateTask = (\n id: string,\n updates: Partial<{\n status: TaskStatus\n title: string\n progress: { current: number; total: number }\n }>,\n ) => {\n setTasks((prev) => prev.map((t) => (t.id === id ? { ...t, ...updates } : t)))\n }\n\n const start = (id: string) => updateTask(id, { status: \"running\" })\n const complete = (id: string, title?: string) => updateTask(id, { status: \"completed\", ...(title && { title }) })\n const fail = (id: string, title?: string) => updateTask(id, { status: \"failed\", ...(title && { title }) })\n const skip = (id: string, title?: string) => updateTask(id, { status: \"skipped\", ...(title && { title }) })\n const updateProgress = (id: string, progress: { current: number; total: number }) => updateTask(id, { progress })\n\n const getTask = (id: string) => tasks.find((t) => t.id === id)\n const allCompleted = tasks.every((t) => t.status === \"completed\" || t.status === \"skipped\")\n const hasFailed = tasks.some((t) => t.status === \"failed\")\n\n return {\n tasks,\n start,\n complete,\n fail,\n skip,\n updateProgress,\n updateTask,\n getTask,\n allCompleted,\n hasFailed,\n }\n}\n","/**\n * React context for progress state management\n */\n\nimport React, { createContext, useContext, useState, useCallback } from \"react\"\nimport type { SpinnerStyle } from \"../types.js\"\nimport { Spinner } from \"./Spinner\"\n\n/** Progress context state */\ninterface ProgressContextState {\n /** Currently showing a spinner */\n isLoading: boolean\n /** Loading message */\n loadingText: string\n /** Spinner style */\n spinnerStyle: SpinnerStyle\n\n /** Show a spinner with message */\n showSpinner: (text: string, style?: SpinnerStyle) => void\n /** Hide the spinner */\n hideSpinner: () => void\n\n /** Progress bar state */\n progress: { current: number; total: number } | null\n /** Update progress */\n updateProgress: (current: number, total?: number) => void\n /** Clear progress */\n clearProgress: () => void\n}\n\nconst ProgressContext = createContext<ProgressContextState | null>(null)\n\n/**\n * Progress context provider\n *\n * @example\n * ```tsx\n * function App() {\n * return (\n * <ProgressProvider>\n * <MyApp />\n * </ProgressProvider>\n * );\n * }\n *\n * function DeepComponent() {\n * const { showSpinner, hideSpinner } = useProgress();\n *\n * const handleLoad = async () => {\n * showSpinner(\"Loading...\");\n * await loadData();\n * hideSpinner();\n * };\n * }\n * ```\n */\nexport function ProgressProvider({ children }: { children: React.ReactNode }): React.ReactElement {\n const [isLoading, setIsLoading] = useState(false)\n const [loadingText, setLoadingText] = useState(\"\")\n const [spinnerStyle, setSpinnerStyle] = useState<SpinnerStyle>(\"dots\")\n const [progress, setProgress] = useState<{\n current: number\n total: number\n } | null>(null)\n\n const showSpinner = useCallback((text: string, style: SpinnerStyle = \"dots\") => {\n setLoadingText(text)\n setSpinnerStyle(style)\n setIsLoading(true)\n }, [])\n\n const hideSpinner = useCallback(() => {\n setIsLoading(false)\n setLoadingText(\"\")\n }, [])\n\n const updateProgress = useCallback((current: number, total?: number) => {\n setProgress((prev) => ({\n current,\n total: total ?? prev?.total ?? 100,\n }))\n }, [])\n\n const clearProgress = useCallback(() => {\n setProgress(null)\n }, [])\n\n const value: ProgressContextState = {\n isLoading,\n loadingText,\n spinnerStyle,\n showSpinner,\n hideSpinner,\n progress,\n updateProgress,\n clearProgress,\n }\n\n return <ProgressContext.Provider value={value}>{children}</ProgressContext.Provider>\n}\n\n/**\n * Hook to access progress context\n *\n * @example\n * ```tsx\n * function LoadingOverlay() {\n * const { isLoading, loadingText, spinnerStyle } = useProgress();\n *\n * if (!isLoading) return null;\n *\n * return <Spinner label={loadingText} style={spinnerStyle} />;\n * }\n * ```\n */\nexport function useProgress(): ProgressContextState {\n const context = useContext(ProgressContext)\n\n if (!context) {\n throw new Error(\"useProgress must be used within a ProgressProvider\")\n }\n\n return context\n}\n\n/**\n * Component that renders spinner when loading\n *\n * @example\n * ```tsx\n * <ProgressProvider>\n * <ProgressIndicator />\n * <MainContent />\n * </ProgressProvider>\n * ```\n */\nexport function ProgressIndicator(): React.ReactElement | null {\n const { isLoading, loadingText, spinnerStyle } = useProgress()\n\n if (!isLoading) {\n return null\n }\n\n return <Spinner label={loadingText} style={spinnerStyle} />\n}\n"],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ //#region packages/ag-react/src/ui/utils/eta.d.ts
2
+ /**
3
+ * Shared ETA calculation utilities
4
+ */
5
+ /** Sample point for ETA calculation */
6
+ interface ETASample {
7
+ time: number;
8
+ value: number;
9
+ }
10
+ /** ETA calculation result */
11
+ interface ETAResult {
12
+ /** Estimated seconds remaining, or null if insufficient data */
13
+ seconds: number | null;
14
+ /** Formatted ETA string (e.g., "1:30", "2:15:30", "--:--") */
15
+ formatted: string;
16
+ }
17
+ /**
18
+ * Calculate ETA from a buffer of samples
19
+ *
20
+ * @param buffer - Array of {time, value} samples
21
+ * @param current - Current progress value
22
+ * @param total - Total target value
23
+ * @returns ETA in seconds (null if insufficient data)
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const buffer = [
28
+ * { time: 1000, value: 0 },
29
+ * { time: 2000, value: 10 },
30
+ * ];
31
+ * const eta = calculateETA(buffer, 10, 100);
32
+ * // eta = 9 (9 seconds remaining at 10 items/sec)
33
+ * ```
34
+ */
35
+ declare function calculateETA(buffer: ETASample[], current: number, total: number): number | null;
36
+ /**
37
+ * Format ETA seconds as human-readable string
38
+ *
39
+ * @param eta - ETA in seconds (null for unknown)
40
+ * @returns Formatted string (e.g., "1:30", "2:15:30", "--:--", ">1d")
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * formatETA(90) // "1:30"
45
+ * formatETA(3665) // "1:01:05"
46
+ * formatETA(null) // "--:--"
47
+ * formatETA(100000) // ">1d"
48
+ * ```
49
+ */
50
+ declare function formatETA(eta: number | null): string;
51
+ /**
52
+ * Calculate and format ETA in one call
53
+ *
54
+ * @param buffer - Array of {time, value} samples
55
+ * @param current - Current progress value
56
+ * @param total - Total target value
57
+ * @returns Object with seconds (number|null) and formatted string
58
+ */
59
+ declare function getETA(buffer: ETASample[], current: number, total: number): ETAResult;
60
+ /** Default buffer size for ETA smoothing */
61
+ declare const DEFAULT_ETA_BUFFER_SIZE = 10;
62
+ /**
63
+ * Create an ETA tracker with automatic buffer management
64
+ *
65
+ * @param bufferSize - Number of samples to keep (default: 10)
66
+ * @returns ETA tracker object
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const tracker = createETATracker();
71
+ * tracker.record(0);
72
+ * // ... later ...
73
+ * tracker.record(50);
74
+ * const eta = tracker.getETA(50, 100);
75
+ * console.log(eta.formatted); // "0:30"
76
+ * ```
77
+ */
78
+ declare function createETATracker(bufferSize?: number): {
79
+ /** Record a new sample */record(value: number): void; /** Get current ETA */
80
+ getETA(current: number, total: number): ETAResult; /** Reset the buffer */
81
+ reset(): void; /** Get buffer for external use */
82
+ getBuffer(): readonly ETASample[];
83
+ };
84
+ //#endregion
85
+ export { DEFAULT_ETA_BUFFER_SIZE, ETAResult, ETASample, calculateETA, createETATracker, formatETA, getETA };
86
+ //# sourceMappingURL=utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.mts","names":[],"sources":["../../packages/ag-react/src/ui/utils/eta.ts"],"mappings":";;AAKA;;;UAAiB,SAAA;EACf,IAAA;EACA,KAAA;AAAA;;UAIe,SAAA;EAIN;EAFT,OAAA;EAuB0B;EArB1B,SAAA;AAAA;;;;;;;AAwDF;;;;;AA6BA;;;;;;;iBAhEgB,YAAA,CAAa,MAAA,EAAQ,SAAA,IAAa,OAAA,UAAiB,KAAA;;;;AAyEnE;;;;;AAkBA;;;;;;iBAxDgB,SAAA,CAAU,GAAA;;;;;;;;;iBA6BV,MAAA,CAAO,MAAA,EAAQ,SAAA,IAAa,OAAA,UAAiB,KAAA,WAAgB,SAAA;;cAShE,uBAAA;;;;;;;;;;;;;;;;;iBAkBG,gBAAA,CAAiB,UAAA;;0BAaP,KAAA,WAAkB,SAAA;;wBAUlB,SAAA;AAAA"}
@@ -0,0 +1,2 @@
1
+ import { a as getETA, i as formatETA, n as calculateETA, r as createETATracker, t as DEFAULT_ETA_BUFFER_SIZE } from "../eta-DLiVPaSD.mjs";
2
+ export { DEFAULT_ETA_BUFFER_SIZE, calculateETA, createETATracker, formatETA, getETA };
@@ -0,0 +1,3 @@
1
+ import { _ as TextInputOptions, a as ProgressInfo, r as ProgressCallback } from "../types-CDgkE-Rw.mjs";
2
+ import { a as waitForEvent, c as wrapGenerator, d as attachSpinner, f as withSpinner, i as withSelect, l as createProgressCallback, n as withTextInput, o as wrapEmitter, r as createSelect, s as withIterableProgress, t as createTextInput, u as withProgress } from "../with-text-input-CmHf_9d6.mjs";
3
+ export { ProgressCallback, ProgressInfo, TextInputOptions, attachSpinner, createProgressCallback, createSelect, createTextInput, waitForEvent, withIterableProgress, withProgress, withSelect, withSpinner, withTextInput, wrapEmitter, wrapGenerator };
@@ -0,0 +1,2 @@
1
+ import { a as waitForEvent, c as wrapGenerator, d as attachSpinner, f as withSpinner, i as withSelect, l as createProgressCallback, n as withTextInput, o as wrapEmitter, r as createSelect, s as withIterableProgress, t as createTextInput, u as withProgress } from "../wrappers-hhL8EQ_n.mjs";
2
+ export { attachSpinner, createProgressCallback, createSelect, createTextInput, waitForEvent, withIterableProgress, withProgress, withSelect, withSpinner, withTextInput, wrapEmitter, wrapGenerator };
package/dist/ui.d.mts ADDED
@@ -0,0 +1,6 @@
1
+ import { _ as TextInputOptions, a as ProgressInfo, b as WithSelectOptions, c as SpinnerOptions, d as StepProgress, f as TableColumn, g as TaskStatus, h as TaskState, i as ProgressGenerator, l as SpinnerProps, m as TaskProps, n as ProgressBarProps, o as SelectOption, p as TableProps, r as ProgressCallback, s as SelectProps, t as ProgressBarOptions, u as SpinnerStyle, v as TextInputProps, x as WithSpinnerOptions, y as WithProgressOptions } from "./types-CDgkE-Rw.mjs";
2
+ import { i as createSpinner, n as SPINNER_FRAMES, r as Spinner, t as CallableSpinner } from "./spinner-Cgej6Vnb.mjs";
3
+ import { n as TaskHandle, r as ProgressBar, t as MultiProgress } from "./multi-progress-C0-rkn86.mjs";
4
+ import { a as CURSOR_RESTORE, c as CURSOR_TO_START, d as getTerminalWidth, f as isTTY, h as writeLine, i as CURSOR_HIDE, l as cursorDown, m as write, n as CLEAR_LINE_END, o as CURSOR_SAVE, p as withCursor, r as CLEAR_SCREEN, s as CURSOR_SHOW, t as CLEAR_LINE, u as cursorUp } from "./ansi-zmNzgkPB.mjs";
5
+ import { a as waitForEvent, c as wrapGenerator, d as attachSpinner, f as withSpinner, i as withSelect, l as createProgressCallback, n as withTextInput, o as wrapEmitter, r as createSelect, s as withIterableProgress, t as createTextInput, u as withProgress } from "./with-text-input-CmHf_9d6.mjs";
6
+ export { CLEAR_LINE, CLEAR_LINE_END, CLEAR_SCREEN, CURSOR_HIDE, CURSOR_RESTORE, CURSOR_SAVE, CURSOR_SHOW, CURSOR_TO_START, CallableSpinner, MultiProgress, ProgressBar, ProgressBarOptions, ProgressBarProps, ProgressCallback, ProgressGenerator, ProgressInfo, SPINNER_FRAMES, SelectOption, SelectProps, Spinner, SpinnerOptions, SpinnerProps, SpinnerStyle, StepProgress, TableColumn, TableProps, TaskHandle, TaskProps, TaskState, TaskStatus, TextInputOptions, TextInputProps, WithProgressOptions, WithSelectOptions, WithSpinnerOptions, attachSpinner, createProgressCallback, createSelect, createSpinner, createTextInput, cursorDown, cursorUp, getTerminalWidth, isTTY, waitForEvent, withCursor, withIterableProgress, withProgress, withSelect, withSpinner, withTextInput, wrapEmitter, wrapGenerator, write, writeLine };
package/dist/ui.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import { i as createSpinner, r as Spinner, t as SPINNER_FRAMES } from "./spinner-DSByknyx.mjs";
2
+ import { a as CURSOR_RESTORE, c as CURSOR_TO_START, d as getTerminalWidth, f as isTTY, h as writeLine, i as CURSOR_HIDE, l as cursorDown, m as write, n as CLEAR_LINE_END, o as CURSOR_SAVE, p as withCursor, r as CLEAR_SCREEN, s as CURSOR_SHOW, t as CLEAR_LINE, u as cursorUp } from "./ansi-CXLE_pt1.mjs";
3
+ import { t as ProgressBar } from "./progress-bar-COPSBlT9.mjs";
4
+ import { t as MultiProgress } from "./multi-progress-CQVB9lES.mjs";
5
+ import "./cli-B-k7Bm56.mjs";
6
+ import { a as waitForEvent, c as wrapGenerator, d as attachSpinner, f as withSpinner, i as withSelect, l as createProgressCallback, n as withTextInput, o as wrapEmitter, r as createSelect, s as withIterableProgress, t as createTextInput, u as withProgress } from "./wrappers-hhL8EQ_n.mjs";
7
+ export { CLEAR_LINE, CLEAR_LINE_END, CLEAR_SCREEN, CURSOR_HIDE, CURSOR_RESTORE, CURSOR_SAVE, CURSOR_SHOW, CURSOR_TO_START, MultiProgress, ProgressBar, SPINNER_FRAMES, Spinner, attachSpinner, createProgressCallback, createSelect, createSpinner, createTextInput, cursorDown, cursorUp, getTerminalWidth, isTTY, waitForEvent, withCursor, withIterableProgress, withProgress, withSelect, withSpinner, withTextInput, wrapEmitter, wrapGenerator, write, writeLine };