ink-native 0.1.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.
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createStreams
4
+ } from "./chunk-3NCUBVFY.js";
5
+
6
+ // src/cli.tsx
7
+ import { parseArgs } from "util";
8
+ import { render } from "ink";
9
+
10
+ // src/Demo/index.tsx
11
+ import { Box, Newline, Spacer, Text, useInput } from "ink";
12
+ import { useEffect, useState } from "react";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
14
+ var TIMER_INTERVAL_MS = 1e3;
15
+ var PERCENT_MAX = 100;
16
+ var DEFAULT_PROGRESS_WIDTH = 20;
17
+ var SCALE_DECIMAL_PLACES = 2;
18
+ var PROGRESS_MEM_MULTIPLIER = 0.7;
19
+ var PROGRESS_MEM_OFFSET = 30;
20
+ var PROGRESS_DSK_MULTIPLIER = 0.4;
21
+ var PROGRESS_DSK_OFFSET = 60;
22
+ var ANIMATION_WIDTH = 10;
23
+ var ANSI_256_SAMPLE_COLORS = [196, 208, 226, 46, 51, 21, 129, 201];
24
+ var TextStylesTab = () => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
25
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Text Styles" }),
26
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
27
+ /* @__PURE__ */ jsx(Text, { children: "Normal text" }),
28
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Bold text" }),
29
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Dim text" }),
30
+ /* @__PURE__ */ jsx(Text, { italic: true, children: "Italic text" }),
31
+ /* @__PURE__ */ jsx(Text, { underline: true, children: "Underlined text" }),
32
+ /* @__PURE__ */ jsx(Text, { strikethrough: true, children: "Strikethrough text" }),
33
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: "Inverse text" }),
34
+ /* @__PURE__ */ jsx(Text, { bold: true, italic: true, underline: true, children: "Combined: bold + italic + underline" })
35
+ ] }),
36
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Emoji" }),
37
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
38
+ /* @__PURE__ */ jsx(Text, { children: "Smileys: \u{1F600} \u{1F60E} \u{1F973} \u{1F60D} \u{1F914} \u{1F634}" }),
39
+ /* @__PURE__ */ jsx(Text, { children: "Hands: \u{1F44B} \u{1F44D} \u{1F44E} \u{1F44F} \u{1F64C} \u270C\uFE0F" }),
40
+ /* @__PURE__ */ jsx(Text, { children: "Animals: \u{1F431} \u{1F436} \u{1F98A} \u{1F43B} \u{1F43C} \u{1F981}" }),
41
+ /* @__PURE__ */ jsx(Text, { children: "Food: \u{1F34E} \u{1F355} \u{1F354} \u{1F32E} \u{1F363} \u{1F369}" }),
42
+ /* @__PURE__ */ jsx(Text, { children: "Objects: \u2B50 \u{1F525} \u{1F4A1} \u{1F389} \u{1F680} \u{1F4BB}" })
43
+ ] })
44
+ ] });
45
+ var BasicColorsTab = () => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
46
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "ANSI 16 Colors" }),
47
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
48
+ /* @__PURE__ */ jsx(Text, { children: "Foreground:" }),
49
+ /* @__PURE__ */ jsxs(Box, { gap: 1, flexWrap: "wrap", children: [
50
+ /* @__PURE__ */ jsx(Text, { color: "black", backgroundColor: "white", children: "black" }),
51
+ /* @__PURE__ */ jsx(Text, { color: "red", children: "red" }),
52
+ /* @__PURE__ */ jsx(Text, { color: "green", children: "green" }),
53
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "yellow" }),
54
+ /* @__PURE__ */ jsx(Text, { color: "blue", children: "blue" }),
55
+ /* @__PURE__ */ jsx(Text, { color: "magenta", children: "magenta" }),
56
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "cyan" }),
57
+ /* @__PURE__ */ jsx(Text, { color: "white", children: "white" })
58
+ ] }),
59
+ /* @__PURE__ */ jsxs(Box, { gap: 1, flexWrap: "wrap", marginTop: 1, children: [
60
+ /* @__PURE__ */ jsx(Text, { color: "blackBright", children: "gray" }),
61
+ /* @__PURE__ */ jsx(Text, { color: "redBright", children: "redBright" }),
62
+ /* @__PURE__ */ jsx(Text, { color: "greenBright", children: "greenBright" }),
63
+ /* @__PURE__ */ jsx(Text, { color: "yellowBright", children: "yellowBright" }),
64
+ /* @__PURE__ */ jsx(Text, { color: "blueBright", children: "blueBright" }),
65
+ /* @__PURE__ */ jsx(Text, { color: "magentaBright", children: "magentaBright" }),
66
+ /* @__PURE__ */ jsx(Text, { color: "cyanBright", children: "cyanBright" }),
67
+ /* @__PURE__ */ jsx(Text, { color: "whiteBright", children: "whiteBright" })
68
+ ] }),
69
+ /* @__PURE__ */ jsx(Newline, {}),
70
+ /* @__PURE__ */ jsx(Text, { children: "Background:" }),
71
+ /* @__PURE__ */ jsxs(Box, { gap: 1, flexWrap: "wrap", children: [
72
+ /* @__PURE__ */ jsx(Text, { backgroundColor: "red", children: " red " }),
73
+ /* @__PURE__ */ jsx(Text, { backgroundColor: "green", children: " green " }),
74
+ /* @__PURE__ */ jsxs(Text, { backgroundColor: "yellow", color: "black", children: [
75
+ " ",
76
+ "yellow",
77
+ " "
78
+ ] }),
79
+ /* @__PURE__ */ jsx(Text, { backgroundColor: "blue", children: " blue " }),
80
+ /* @__PURE__ */ jsx(Text, { backgroundColor: "magenta", children: " magenta " }),
81
+ /* @__PURE__ */ jsxs(Text, { backgroundColor: "cyan", color: "black", children: [
82
+ " ",
83
+ "cyan",
84
+ " "
85
+ ] })
86
+ ] })
87
+ ] })
88
+ ] });
89
+ var ExtendedColorsTab = () => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
90
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Extended Colors" }),
91
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
92
+ /* @__PURE__ */ jsx(Text, { children: "ANSI 256 (color codes):" }),
93
+ /* @__PURE__ */ jsx(Box, { gap: 1, children: ANSI_256_SAMPLE_COLORS.map((code) => /* @__PURE__ */ jsxs(Text, { color: `ansi256-${code}`, children: [
94
+ "#",
95
+ code
96
+ ] }, code)) }),
97
+ /* @__PURE__ */ jsx(Newline, {}),
98
+ /* @__PURE__ */ jsx(Text, { children: "RGB True Color (hex):" }),
99
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
100
+ /* @__PURE__ */ jsx(Text, { color: "#ff6b6b", children: "#ff6b6b" }),
101
+ /* @__PURE__ */ jsx(Text, { color: "#ffd93d", children: "#ffd93d" }),
102
+ /* @__PURE__ */ jsx(Text, { color: "#6bcb77", children: "#6bcb77" }),
103
+ /* @__PURE__ */ jsx(Text, { color: "#4d96ff", children: "#4d96ff" }),
104
+ /* @__PURE__ */ jsx(Text, { color: "#9b5de5", children: "#9b5de5" }),
105
+ /* @__PURE__ */ jsx(Text, { color: "#f15bb5", children: "#f15bb5" })
106
+ ] }),
107
+ /* @__PURE__ */ jsx(Newline, {}),
108
+ /* @__PURE__ */ jsx(Text, { children: "Gradient effect:" }),
109
+ /* @__PURE__ */ jsx(Box, { children: [
110
+ { char: "R", color: "#ff0000" },
111
+ { char: "A", color: "#ff7f00" },
112
+ { char: "I", color: "#ffff00" },
113
+ { char: "N", color: "#00ff00" },
114
+ { char: "B", color: "#0000ff" },
115
+ { char: "O", color: "#4b0082" },
116
+ { char: "W", color: "#9400d3" }
117
+ ].map(({ char, color }) => /* @__PURE__ */ jsx(Text, { color, children: char }, char)) })
118
+ ] })
119
+ ] });
120
+ var LayoutTab = () => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
121
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Box Layouts & Borders" }),
122
+ /* @__PURE__ */ jsxs(Box, { gap: 2, paddingLeft: 1, children: [
123
+ /* @__PURE__ */ jsxs(
124
+ Box,
125
+ {
126
+ flexDirection: "column",
127
+ borderStyle: "single",
128
+ borderColor: "cyan",
129
+ paddingX: 1,
130
+ children: [
131
+ /* @__PURE__ */ jsx(Text, { children: "Single" }),
132
+ /* @__PURE__ */ jsx(Text, { children: "Border" })
133
+ ]
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsxs(
137
+ Box,
138
+ {
139
+ flexDirection: "column",
140
+ borderStyle: "double",
141
+ borderColor: "yellow",
142
+ paddingX: 1,
143
+ children: [
144
+ /* @__PURE__ */ jsx(Text, { children: "Double" }),
145
+ /* @__PURE__ */ jsx(Text, { children: "Border" })
146
+ ]
147
+ }
148
+ ),
149
+ /* @__PURE__ */ jsxs(
150
+ Box,
151
+ {
152
+ flexDirection: "column",
153
+ borderStyle: "round",
154
+ borderColor: "green",
155
+ paddingX: 1,
156
+ children: [
157
+ /* @__PURE__ */ jsx(Text, { children: "Round" }),
158
+ /* @__PURE__ */ jsx(Text, { children: "Border" })
159
+ ]
160
+ }
161
+ ),
162
+ /* @__PURE__ */ jsxs(
163
+ Box,
164
+ {
165
+ flexDirection: "column",
166
+ borderStyle: "bold",
167
+ borderColor: "magenta",
168
+ paddingX: 1,
169
+ children: [
170
+ /* @__PURE__ */ jsx(Text, { children: "Bold" }),
171
+ /* @__PURE__ */ jsx(Text, { children: "Border" })
172
+ ]
173
+ }
174
+ )
175
+ ] }),
176
+ /* @__PURE__ */ jsx(Box, { paddingLeft: 1, marginTop: 1, children: /* @__PURE__ */ jsxs(
177
+ Box,
178
+ {
179
+ borderStyle: "single",
180
+ borderColor: "blue",
181
+ padding: 1,
182
+ flexDirection: "column",
183
+ width: 40,
184
+ children: [
185
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
186
+ /* @__PURE__ */ jsx(Text, { children: "Left" }),
187
+ /* @__PURE__ */ jsx(Text, { children: "Right" })
188
+ ] }),
189
+ /* @__PURE__ */ jsx(Box, { justifyContent: "center", marginY: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", children: "Centered content" }) }),
190
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Nested box with padding" }) })
191
+ ]
192
+ }
193
+ ) })
194
+ ] });
195
+ var ProgressBar = ({
196
+ value,
197
+ width = DEFAULT_PROGRESS_WIDTH,
198
+ color = "green"
199
+ }) => {
200
+ const filled = Math.round(value / PERCENT_MAX * width);
201
+ const empty = width - filled;
202
+ return /* @__PURE__ */ jsxs(Text, { children: [
203
+ /* @__PURE__ */ jsx(Text, { color, children: "\u2588".repeat(filled) }),
204
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2591".repeat(empty) }),
205
+ /* @__PURE__ */ jsxs(Text, { children: [
206
+ " ",
207
+ value.toFixed(0),
208
+ "%"
209
+ ] })
210
+ ] });
211
+ };
212
+ var DynamicTab = ({
213
+ elapsed,
214
+ progress
215
+ }) => {
216
+ const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
217
+ const spinnerFrame = spinnerFrames[elapsed % spinnerFrames.length];
218
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
219
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Dynamic Updates" }),
220
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
221
+ /* @__PURE__ */ jsxs(Text, { children: [
222
+ "Elapsed: ",
223
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
224
+ elapsed,
225
+ "s"
226
+ ] })
227
+ ] }),
228
+ /* @__PURE__ */ jsxs(Text, { children: [
229
+ "Spinner: ",
230
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: spinnerFrame }),
231
+ " Loading..."
232
+ ] }),
233
+ /* @__PURE__ */ jsx(Newline, {}),
234
+ /* @__PURE__ */ jsx(Text, { children: "Progress bars:" }),
235
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [
236
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
237
+ /* @__PURE__ */ jsx(Text, { children: "CPU:" }),
238
+ /* @__PURE__ */ jsx(ProgressBar, { value: progress, color: "green" })
239
+ ] }),
240
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
241
+ /* @__PURE__ */ jsx(Text, { children: "MEM:" }),
242
+ /* @__PURE__ */ jsx(
243
+ ProgressBar,
244
+ {
245
+ value: (progress * PROGRESS_MEM_MULTIPLIER + PROGRESS_MEM_OFFSET) % PERCENT_MAX,
246
+ color: "blue"
247
+ }
248
+ )
249
+ ] }),
250
+ /* @__PURE__ */ jsxs(Box, { gap: 1, children: [
251
+ /* @__PURE__ */ jsx(Text, { children: "DSK:" }),
252
+ /* @__PURE__ */ jsx(
253
+ ProgressBar,
254
+ {
255
+ value: (progress * PROGRESS_DSK_MULTIPLIER + PROGRESS_DSK_OFFSET) % PERCENT_MAX,
256
+ color: "yellow"
257
+ }
258
+ )
259
+ ] })
260
+ ] }),
261
+ /* @__PURE__ */ jsx(Newline, {}),
262
+ /* @__PURE__ */ jsx(Text, { children: "Animation:" }),
263
+ /* @__PURE__ */ jsx(Box, { paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u25CF".padStart(elapsed % ANIMATION_WIDTH + 1, " ").padEnd(ANIMATION_WIDTH, " ") }) })
264
+ ] })
265
+ ] });
266
+ };
267
+ var TAB_STYLES = 0;
268
+ var TAB_COLORS = 1;
269
+ var TAB_EXTENDED = 2;
270
+ var TAB_LAYOUT = 3;
271
+ var TAB_DYNAMIC = 4;
272
+ var MENU_ITEMS = [
273
+ { id: "styles", label: "Text Styles" },
274
+ { id: "colors", label: "Basic Colors" },
275
+ { id: "extended", label: "Extended Colors" },
276
+ { id: "layout", label: "Layouts" },
277
+ { id: "dynamic", label: "Dynamic" }
278
+ ];
279
+ var DemoApp = ({
280
+ scaleFactor,
281
+ initialFrameRate: initialFrameRate2,
282
+ onFrameRateChange
283
+ }) => {
284
+ const [selectedTab, setSelectedTab] = useState(0);
285
+ const [elapsed, setElapsed] = useState(0);
286
+ const [progress, setProgress] = useState(0);
287
+ const [frameRate, setFrameRate] = useState(initialFrameRate2);
288
+ useEffect(() => {
289
+ const timer = setInterval(() => {
290
+ setElapsed((e) => e + 1);
291
+ setProgress((p) => (p + 2) % PERCENT_MAX);
292
+ }, TIMER_INTERVAL_MS);
293
+ return () => clearInterval(timer);
294
+ }, []);
295
+ useEffect(() => {
296
+ if (!onFrameRateChange) {
297
+ return;
298
+ }
299
+ return onFrameRateChange(setFrameRate);
300
+ }, [onFrameRateChange]);
301
+ useInput((input, key) => {
302
+ if (key.leftArrow || input === "h") {
303
+ setSelectedTab((t) => t > 0 ? t - 1 : MENU_ITEMS.length - 1);
304
+ } else if (key.rightArrow || input === "l") {
305
+ setSelectedTab((t) => t < MENU_ITEMS.length - 1 ? t + 1 : 0);
306
+ } else if (key.tab) {
307
+ setSelectedTab((t) => (t + 1) % MENU_ITEMS.length);
308
+ }
309
+ });
310
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [
311
+ /* @__PURE__ */ jsxs(Box, { borderStyle: "double", borderColor: "cyan", paddingX: 2, children: [
312
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "ink-native Demo" }),
313
+ /* @__PURE__ */ jsx(Spacer, {}),
314
+ /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
315
+ "Scale: ",
316
+ scaleFactor.toFixed(SCALE_DECIMAL_PLACES),
317
+ "x | ",
318
+ frameRate,
319
+ " fps"
320
+ ] })
321
+ ] }),
322
+ /* @__PURE__ */ jsx(Box, { marginY: 1, gap: 1, children: MENU_ITEMS.map(
323
+ (item, i) => i === selectedTab ? /* @__PURE__ */ jsx(
324
+ Box,
325
+ {
326
+ borderStyle: "round",
327
+ borderColor: "cyan",
328
+ paddingX: 1,
329
+ children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: item.label })
330
+ },
331
+ item.id
332
+ ) : /* @__PURE__ */ jsx(
333
+ Box,
334
+ {
335
+ borderStyle: "single",
336
+ borderColor: "gray",
337
+ paddingX: 1,
338
+ children: /* @__PURE__ */ jsx(Text, { children: item.label })
339
+ },
340
+ item.id
341
+ )
342
+ ) }),
343
+ /* @__PURE__ */ jsxs(
344
+ Box,
345
+ {
346
+ flexDirection: "column",
347
+ borderStyle: "single",
348
+ borderColor: "gray",
349
+ padding: 1,
350
+ minHeight: 15,
351
+ children: [
352
+ selectedTab === TAB_STYLES && /* @__PURE__ */ jsx(TextStylesTab, {}),
353
+ selectedTab === TAB_COLORS && /* @__PURE__ */ jsx(BasicColorsTab, {}),
354
+ selectedTab === TAB_EXTENDED && /* @__PURE__ */ jsx(ExtendedColorsTab, {}),
355
+ selectedTab === TAB_LAYOUT && /* @__PURE__ */ jsx(LayoutTab, {}),
356
+ selectedTab === TAB_DYNAMIC && /* @__PURE__ */ jsx(DynamicTab, { elapsed, progress })
357
+ ]
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2190 \u2192 or h/l to switch tabs | Tab to cycle | Ctrl+C to exit" }) })
361
+ ] });
362
+ };
363
+
364
+ // src/cli.tsx
365
+ import { jsx as jsx2 } from "react/jsx-runtime";
366
+ var DEFAULT_WIDTH = 800;
367
+ var DEFAULT_HEIGHT = 600;
368
+ var { values: args } = parseArgs({
369
+ options: {
370
+ title: { type: "string" },
371
+ width: { type: "string" },
372
+ height: { type: "string" },
373
+ background: { type: "string" },
374
+ "frame-rate": { type: "string" },
375
+ help: { type: "boolean", short: "h", default: false }
376
+ }
377
+ });
378
+ if (args.help) {
379
+ console.log(`
380
+ ink-native - Render Ink apps in native windows
381
+
382
+ Usage: pnpm dlx ink-native [options]
383
+
384
+ Options:
385
+ --title <string> Window title
386
+ --width <number> Window width in pixels (default: 800)
387
+ --height <number> Window height in pixels (default: 600)
388
+ --background <hex> Background color (e.g., "#1a1a2e")
389
+ --frame-rate <number> Force frame rate instead of default 60fps
390
+ -h, --help Show this help message
391
+
392
+ For library usage, see: https://github.com/tuxracer/ink-native
393
+ `);
394
+ process.exit(0);
395
+ }
396
+ var { stdin, stdout, window } = createStreams({
397
+ title: args.title ?? "ink-native Demo",
398
+ width: args.width ? parseInt(args.width, 10) : DEFAULT_WIDTH,
399
+ height: args.height ? parseInt(args.height, 10) : DEFAULT_HEIGHT,
400
+ ...args.background && { backgroundColor: args.background },
401
+ ...args["frame-rate"] && { frameRate: parseInt(args["frame-rate"], 10) }
402
+ });
403
+ var initialFrameRate = window.getFrameRate();
404
+ render(/* @__PURE__ */ jsx2(DemoApp, { scaleFactor: 1, initialFrameRate }), {
405
+ stdin,
406
+ stdout
407
+ });
408
+ window.on("close", () => process.exit(0));
409
+ process.on("SIGINT", () => {
410
+ window.close();
411
+ process.exit(0);
412
+ });