@outfitter/tui 0.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.
Files changed (235) hide show
  1. package/README.md +250 -0
  2. package/dist/borders/index.d.ts +3 -0
  3. package/dist/borders/index.js +13 -0
  4. package/dist/box/index.d.ts +4 -0
  5. package/dist/box/index.js +10 -0
  6. package/dist/confirm.d.ts +37 -0
  7. package/dist/confirm.js +36 -0
  8. package/dist/demo/index.d.ts +77 -0
  9. package/dist/demo/index.js +142 -0
  10. package/dist/demo/registry.d.ts +6 -0
  11. package/dist/demo/registry.js +28 -0
  12. package/dist/demo/renderers/borders.d.ts +7 -0
  13. package/dist/demo/renderers/borders.js +14 -0
  14. package/dist/demo/renderers/box.d.ts +7 -0
  15. package/dist/demo/renderers/box.js +15 -0
  16. package/dist/demo/renderers/colors.d.ts +7 -0
  17. package/dist/demo/renderers/colors.js +15 -0
  18. package/dist/demo/renderers/indicators.d.ts +7 -0
  19. package/dist/demo/renderers/indicators.js +14 -0
  20. package/dist/demo/renderers/list.d.ts +7 -0
  21. package/dist/demo/renderers/list.js +16 -0
  22. package/dist/demo/renderers/markdown.d.ts +7 -0
  23. package/dist/demo/renderers/markdown.js +15 -0
  24. package/dist/demo/renderers/progress.d.ts +7 -0
  25. package/dist/demo/renderers/progress.js +14 -0
  26. package/dist/demo/renderers/spinner.d.ts +7 -0
  27. package/dist/demo/renderers/spinner.js +16 -0
  28. package/dist/demo/renderers/table.d.ts +7 -0
  29. package/dist/demo/renderers/table.js +16 -0
  30. package/dist/demo/renderers/text.d.ts +7 -0
  31. package/dist/demo/renderers/text.js +13 -0
  32. package/dist/demo/renderers/tree.d.ts +7 -0
  33. package/dist/demo/renderers/tree.js +15 -0
  34. package/dist/demo/section.d.ts +4 -0
  35. package/dist/demo/section.js +20 -0
  36. package/dist/demo/templates.d.ts +3 -0
  37. package/dist/demo/templates.js +10 -0
  38. package/dist/demo/types.d.ts +2 -0
  39. package/dist/demo/types.js +8 -0
  40. package/dist/index.d.ts +31 -0
  41. package/dist/index.js +77 -0
  42. package/dist/list/index.d.ts +3 -0
  43. package/dist/list/index.js +9 -0
  44. package/dist/preset/full.d.ts +12 -0
  45. package/dist/preset/full.js +37 -0
  46. package/dist/preset/standard.d.ts +9 -0
  47. package/dist/preset/standard.js +26 -0
  48. package/dist/prompt/confirm.d.ts +4 -0
  49. package/dist/prompt/confirm.js +9 -0
  50. package/dist/prompt/group.d.ts +4 -0
  51. package/dist/prompt/group.js +9 -0
  52. package/dist/prompt/index.d.ts +7 -0
  53. package/dist/prompt/index.js +32 -0
  54. package/dist/prompt/select.d.ts +4 -0
  55. package/dist/prompt/select.js +11 -0
  56. package/dist/prompt/text.d.ts +4 -0
  57. package/dist/prompt/text.js +11 -0
  58. package/dist/prompt/types.d.ts +3 -0
  59. package/dist/prompt/types.js +8 -0
  60. package/dist/prompt/validators.d.ts +2 -0
  61. package/dist/prompt/validators.js +8 -0
  62. package/dist/render/borders.d.ts +2 -0
  63. package/dist/render/borders.js +15 -0
  64. package/dist/render/box.d.ts +3 -0
  65. package/dist/render/box.js +20 -0
  66. package/dist/render/date.d.ts +2 -0
  67. package/dist/render/date.js +12 -0
  68. package/dist/render/format-relative.d.ts +2 -0
  69. package/dist/render/format-relative.js +8 -0
  70. package/dist/render/format.d.ts +2 -0
  71. package/dist/render/format.js +10 -0
  72. package/dist/render/heading.d.ts +3 -0
  73. package/dist/render/heading.js +11 -0
  74. package/dist/render/index.d.ts +31 -0
  75. package/dist/render/index.js +222 -0
  76. package/dist/render/indicators.d.ts +2 -0
  77. package/dist/render/indicators.js +16 -0
  78. package/dist/render/json.d.ts +2 -0
  79. package/dist/render/json.js +10 -0
  80. package/dist/render/layout.d.ts +5 -0
  81. package/dist/render/layout.js +22 -0
  82. package/dist/render/list.d.ts +2 -0
  83. package/dist/render/list.js +8 -0
  84. package/dist/render/markdown.d.ts +2 -0
  85. package/dist/render/markdown.js +8 -0
  86. package/dist/render/progress.d.ts +2 -0
  87. package/dist/render/progress.js +8 -0
  88. package/dist/render/separator.d.ts +3 -0
  89. package/dist/render/separator.js +11 -0
  90. package/dist/render/shapes.d.ts +2 -0
  91. package/dist/render/shapes.js +32 -0
  92. package/dist/render/spinner.d.ts +2 -0
  93. package/dist/render/spinner.js +12 -0
  94. package/dist/render/stack.d.ts +3 -0
  95. package/dist/render/stack.js +35 -0
  96. package/dist/render/table.d.ts +3 -0
  97. package/dist/render/table.js +9 -0
  98. package/dist/render/tree.d.ts +2 -0
  99. package/dist/render/tree.js +10 -0
  100. package/dist/render/types.d.ts +2 -0
  101. package/dist/render/types.js +1 -0
  102. package/dist/shared/@outfitter/tui-011579t8.d.ts +24 -0
  103. package/dist/shared/@outfitter/tui-06dntkse.js +146 -0
  104. package/dist/shared/@outfitter/tui-0awf316b.js +71 -0
  105. package/dist/shared/@outfitter/tui-0b85rht7.js +1 -0
  106. package/dist/shared/@outfitter/tui-0mpqnyc1.js +55 -0
  107. package/dist/shared/@outfitter/tui-1qh888th.d.ts +106 -0
  108. package/dist/shared/@outfitter/tui-1tk0kxa6.js +94 -0
  109. package/dist/shared/@outfitter/tui-1wggw2zj.d.ts +56 -0
  110. package/dist/shared/@outfitter/tui-2pwhzg55.js +123 -0
  111. package/dist/shared/@outfitter/tui-2tkva96b.d.ts +20 -0
  112. package/dist/shared/@outfitter/tui-2wfat6jb.js +22 -0
  113. package/dist/shared/@outfitter/tui-34q2aenf.d.ts +24 -0
  114. package/dist/shared/@outfitter/tui-37hjcqhb.d.ts +3 -0
  115. package/dist/shared/@outfitter/tui-3dyxg62j.d.ts +97 -0
  116. package/dist/shared/@outfitter/tui-3kza6p9k.d.ts +132 -0
  117. package/dist/shared/@outfitter/tui-43bnfxv9.js +30 -0
  118. package/dist/shared/@outfitter/tui-4yz7jcyq.js +214 -0
  119. package/dist/shared/@outfitter/tui-52ndmswq.js +23 -0
  120. package/dist/shared/@outfitter/tui-53ms1ba4.d.ts +41 -0
  121. package/dist/shared/@outfitter/tui-5dsn6d6d.js +86 -0
  122. package/dist/shared/@outfitter/tui-5pb72vf9.js +51 -0
  123. package/dist/shared/@outfitter/tui-6605wa2j.js +127 -0
  124. package/dist/shared/@outfitter/tui-6ptks7jj.js +19 -0
  125. package/dist/shared/@outfitter/tui-6svngg69.js +126 -0
  126. package/dist/shared/@outfitter/tui-733asbd8.js +37 -0
  127. package/dist/shared/@outfitter/tui-75bztyfp.d.ts +50 -0
  128. package/dist/shared/@outfitter/tui-83zaah9b.d.ts +17 -0
  129. package/dist/shared/@outfitter/tui-8ejx8gq5.d.ts +71 -0
  130. package/dist/shared/@outfitter/tui-8j1gbehy.d.ts +164 -0
  131. package/dist/shared/@outfitter/tui-8mypsnva.d.ts +74 -0
  132. package/dist/shared/@outfitter/tui-997aapz0.js +61 -0
  133. package/dist/shared/@outfitter/tui-9dbykt4g.d.ts +42 -0
  134. package/dist/shared/@outfitter/tui-9h1kdd98.d.ts +119 -0
  135. package/dist/shared/@outfitter/tui-9rj9yesd.js +118 -0
  136. package/dist/shared/@outfitter/tui-a65efhsk.d.ts +23 -0
  137. package/dist/shared/@outfitter/tui-a8nkrbds.js +1 -0
  138. package/dist/shared/@outfitter/tui-ajp1153q.d.ts +59 -0
  139. package/dist/shared/@outfitter/tui-ay1fv41j.d.ts +30 -0
  140. package/dist/shared/@outfitter/tui-azh1w4ak.js +67 -0
  141. package/dist/shared/@outfitter/tui-b14ry1j1.d.ts +53 -0
  142. package/dist/shared/@outfitter/tui-c56sxcm8.d.ts +87 -0
  143. package/dist/shared/@outfitter/tui-c6ft5w6q.d.ts +91 -0
  144. package/dist/shared/@outfitter/tui-cq7za0cz.js +62 -0
  145. package/dist/shared/@outfitter/tui-dh15zwg0.js +95 -0
  146. package/dist/shared/@outfitter/tui-esc46z2v.js +20 -0
  147. package/dist/shared/@outfitter/tui-f1mj6h6p.d.ts +2 -0
  148. package/dist/shared/@outfitter/tui-gcpz529w.js +122 -0
  149. package/dist/shared/@outfitter/tui-gqsdhmk9.d.ts +42 -0
  150. package/dist/shared/@outfitter/tui-hescagw2.js +32 -0
  151. package/dist/shared/@outfitter/tui-j2kd7eej.js +126 -0
  152. package/dist/shared/@outfitter/tui-j3bkjt2g.js +7 -0
  153. package/dist/shared/@outfitter/tui-jnn9d8cd.js +8 -0
  154. package/dist/shared/@outfitter/tui-jz5nws55.d.ts +51 -0
  155. package/dist/shared/@outfitter/tui-k3mby2kk.js +70 -0
  156. package/dist/shared/@outfitter/tui-kc4nxak0.js +20 -0
  157. package/dist/shared/@outfitter/tui-kcxv8txp.js +7 -0
  158. package/dist/shared/@outfitter/tui-kydbggmj.js +39 -0
  159. package/dist/shared/@outfitter/tui-mch672g9.js +30 -0
  160. package/dist/shared/@outfitter/tui-n9kxkdrh.js +82 -0
  161. package/dist/shared/@outfitter/tui-na4dnjpw.js +348 -0
  162. package/dist/shared/@outfitter/tui-ncaatp4j.js +25 -0
  163. package/dist/shared/@outfitter/tui-nce7fgtf.js +48 -0
  164. package/dist/shared/@outfitter/tui-ngz2fbdw.js +144 -0
  165. package/dist/shared/@outfitter/tui-nprd7g0d.js +52 -0
  166. package/dist/shared/@outfitter/tui-nr580mbv.js +272 -0
  167. package/dist/shared/@outfitter/tui-nr93tf31.d.ts +64 -0
  168. package/dist/shared/@outfitter/tui-pdwbbzwr.js +179 -0
  169. package/dist/shared/@outfitter/tui-qb07rtct.js +19 -0
  170. package/dist/shared/@outfitter/tui-qkyazctw.d.ts +36 -0
  171. package/dist/shared/@outfitter/tui-qn1rgz9v.d.ts +93 -0
  172. package/dist/shared/@outfitter/tui-qs3fhwp8.js +43 -0
  173. package/dist/shared/@outfitter/tui-r8hywf9m.d.ts +48 -0
  174. package/dist/shared/@outfitter/tui-rbbcc034.js +20 -0
  175. package/dist/shared/@outfitter/tui-rgkerz72.js +85 -0
  176. package/dist/shared/@outfitter/tui-rh52sycm.d.ts +45 -0
  177. package/dist/shared/@outfitter/tui-rr924x4z.d.ts +59 -0
  178. package/dist/shared/@outfitter/tui-rwpdjrt3.js +20 -0
  179. package/dist/shared/@outfitter/tui-rx9xq9s7.d.ts +26 -0
  180. package/dist/shared/@outfitter/tui-sk05ye6g.js +1 -0
  181. package/dist/shared/@outfitter/tui-sv2xmh3w.d.ts +26 -0
  182. package/dist/shared/@outfitter/tui-t1a9xgbd.js +111 -0
  183. package/dist/shared/@outfitter/tui-t9vd88jr.js +273 -0
  184. package/dist/shared/@outfitter/tui-tq1z78x0.js +11 -0
  185. package/dist/shared/@outfitter/tui-ts1f957s.d.ts +128 -0
  186. package/dist/shared/@outfitter/tui-ve0083wa.d.ts +61 -0
  187. package/dist/shared/@outfitter/tui-vt0wg6c4.js +54 -0
  188. package/dist/shared/@outfitter/tui-wfnnq0zq.d.ts +328 -0
  189. package/dist/shared/@outfitter/tui-x3yg0887.d.ts +223 -0
  190. package/dist/shared/@outfitter/tui-x9vvtfkk.js +20 -0
  191. package/dist/shared/@outfitter/tui-xbvz707j.js +20 -0
  192. package/dist/shared/@outfitter/tui-xbx6d4t7.js +1 -0
  193. package/dist/shared/@outfitter/tui-xph95b7h.js +67 -0
  194. package/dist/shared/@outfitter/tui-xqjx7d1f.js +135 -0
  195. package/dist/shared/@outfitter/tui-xrgrp99k.d.ts +112 -0
  196. package/dist/shared/@outfitter/tui-xzjv96ps.d.ts +300 -0
  197. package/dist/shared/@outfitter/tui-ykzs6v4v.d.ts +66 -0
  198. package/dist/shared/@outfitter/tui-yw9n5h6q.d.ts +54 -0
  199. package/dist/shared/@outfitter/tui-ywmakc6b.js +30 -0
  200. package/dist/shared/@outfitter/tui-z6nf9b9h.js +7 -0
  201. package/dist/shared/@outfitter/tui-zcspg6z6.d.ts +190 -0
  202. package/dist/shared/@outfitter/tui-zhbsnj7w.js +1 -0
  203. package/dist/streaming/ansi.d.ts +2 -0
  204. package/dist/streaming/ansi.js +8 -0
  205. package/dist/streaming/index.d.ts +4 -0
  206. package/dist/streaming/index.js +17 -0
  207. package/dist/streaming/spinner.d.ts +3 -0
  208. package/dist/streaming/spinner.js +10 -0
  209. package/dist/streaming/writer.d.ts +2 -0
  210. package/dist/streaming/writer.js +9 -0
  211. package/dist/table/index.d.ts +4 -0
  212. package/dist/table/index.js +10 -0
  213. package/dist/theme/context.d.ts +9 -0
  214. package/dist/theme/context.js +12 -0
  215. package/dist/theme/create.d.ts +8 -0
  216. package/dist/theme/create.js +10 -0
  217. package/dist/theme/index.d.ts +17 -0
  218. package/dist/theme/index.js +40 -0
  219. package/dist/theme/presets/bold.d.ts +8 -0
  220. package/dist/theme/presets/bold.js +10 -0
  221. package/dist/theme/presets/default.d.ts +8 -0
  222. package/dist/theme/presets/default.js +9 -0
  223. package/dist/theme/presets/index.d.ts +12 -0
  224. package/dist/theme/presets/index.js +22 -0
  225. package/dist/theme/presets/minimal.d.ts +8 -0
  226. package/dist/theme/presets/minimal.js +10 -0
  227. package/dist/theme/presets/rounded.d.ts +8 -0
  228. package/dist/theme/presets/rounded.js +10 -0
  229. package/dist/theme/resolve.d.ts +8 -0
  230. package/dist/theme/resolve.js +11 -0
  231. package/dist/theme/types.d.ts +7 -0
  232. package/dist/theme/types.js +1 -0
  233. package/dist/tree/index.d.ts +3 -0
  234. package/dist/tree/index.js +11 -0
  235. package/package.json +263 -0
@@ -0,0 +1,51 @@
1
+ import { WidthMode } from "./tui-75bztyfp";
2
+ /**
3
+ * Separator style for headings.
4
+ */
5
+ type SeparatorStyle = "=" | "-" | "─" | "━" | "═";
6
+ /**
7
+ * Width mode for headings.
8
+ *
9
+ * Note: Headings only support "text", "full", and numeric widths.
10
+ * Use the shared WidthMode type for full container-relative support.
11
+ *
12
+ * @see WidthMode for the complete type definition
13
+ */
14
+ type HeadingWidthMode = Extract<WidthMode, "text" | "full" | number>;
15
+ /**
16
+ * Case transformation for heading text.
17
+ */
18
+ type CaseMode = "upper" | "lower" | "title" | "none";
19
+ /**
20
+ * Options for rendering a heading.
21
+ */
22
+ interface HeadingOptions {
23
+ /** Separator character/style (default: "=") */
24
+ separator?: SeparatorStyle;
25
+ /** Width mode (default: "text") */
26
+ width?: HeadingWidthMode;
27
+ /** Case transformation (default: "upper") */
28
+ case?: CaseMode;
29
+ }
30
+ /**
31
+ * Renders a section heading with a separator line below.
32
+ *
33
+ * @param text - The heading text
34
+ * @param options - Rendering options
35
+ * @returns Formatted heading string
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * import { renderHeading } from "@outfitter/tui/render";
40
+ *
41
+ * console.log(renderHeading("Theme Colors"));
42
+ * // THEME COLORS
43
+ * // ============
44
+ *
45
+ * console.log(renderHeading("Status", { separator: "─", case: "none" }));
46
+ * // Status
47
+ * // ──────
48
+ * ```
49
+ */
50
+ declare function renderHeading(text: string, options?: HeadingOptions): string;
51
+ export { SeparatorStyle, HeadingWidthMode, CaseMode, HeadingOptions, renderHeading };
@@ -0,0 +1,70 @@
1
+ // @bun
2
+ import {
3
+ getExample
4
+ } from "./tui-nprd7g0d.js";
5
+ import {
6
+ demoSection
7
+ } from "./tui-733asbd8.js";
8
+ import {
9
+ renderMarkdown
10
+ } from "./tui-vt0wg6c4.js";
11
+
12
+ // packages/tui/src/demo/renderers/markdown.ts
13
+ function renderMarkdownDemo(config, theme) {
14
+ const showCode = config.showCode ?? true;
15
+ const lines = [];
16
+ lines.push(demoSection("Markdown Rendering"));
17
+ lines.push("");
18
+ if (showCode) {
19
+ lines.push('import { renderMarkdown } from "@outfitter/tui/render";');
20
+ lines.push("");
21
+ }
22
+ const sample = getExample("markdownSample", config.examples);
23
+ lines.push("Input:");
24
+ lines.push(theme.muted("\u2500".repeat(40)));
25
+ for (const line of sample.split(`
26
+ `)) {
27
+ lines.push(theme.muted(line));
28
+ }
29
+ lines.push(theme.muted("\u2500".repeat(40)));
30
+ lines.push("");
31
+ lines.push("Output:");
32
+ lines.push("\u2500".repeat(40));
33
+ lines.push(renderMarkdown(sample));
34
+ lines.push("\u2500".repeat(40));
35
+ lines.push("");
36
+ lines.push(demoSection("Supported Elements"));
37
+ lines.push("");
38
+ const elements = [
39
+ {
40
+ name: "Headings",
41
+ markdown: `# Heading 1
42
+ ## Heading 2`,
43
+ desc: "Rendered bold"
44
+ },
45
+ { name: "Bold", markdown: "**bold text**", desc: "Rendered bold" },
46
+ { name: "Italic", markdown: "*italic text*", desc: "Rendered italic" },
47
+ { name: "Inline code", markdown: "`code`", desc: "Rendered cyan" },
48
+ {
49
+ name: "Code block",
50
+ markdown: "```\ncode block\n```",
51
+ desc: "Rendered dim"
52
+ }
53
+ ];
54
+ for (const el of elements) {
55
+ lines.push(`${el.name}:`);
56
+ lines.push(theme.muted(` ${el.desc}`));
57
+ lines.push(` Input: ${el.markdown.replace(/\n/g, "\\n")}`);
58
+ lines.push(` Output: ${renderMarkdown(el.markdown).replace(/\n/g, " ")}`);
59
+ lines.push("");
60
+ }
61
+ lines.push(demoSection("Color Support"));
62
+ lines.push("");
63
+ lines.push("\u2022 Colors applied when terminal supports ANSI");
64
+ lines.push("\u2022 Respects NO_COLOR environment variable");
65
+ lines.push("\u2022 Markdown syntax stripped when colors disabled");
66
+ return lines.join(`
67
+ `);
68
+ }
69
+
70
+ export { renderMarkdownDemo };
@@ -0,0 +1,20 @@
1
+ // @bun
2
+ import {
3
+ defaultTheme
4
+ } from "./tui-0mpqnyc1.js";
5
+
6
+ // packages/tui/src/theme/context.ts
7
+ function createThemedContext(options) {
8
+ const theme = options.theme ?? options.parent?.theme ?? defaultTheme;
9
+ const width = options.width ?? options.parent?.width ?? process.stdout.columns ?? 80;
10
+ return {
11
+ width,
12
+ theme,
13
+ ...options.parent && { parent: options.parent }
14
+ };
15
+ }
16
+ function getContextTheme(ctx) {
17
+ return ctx?.theme ?? defaultTheme;
18
+ }
19
+
20
+ export { createThemedContext, getContextTheme };
@@ -0,0 +1,7 @@
1
+ // @bun
2
+ // packages/tui/src/prompt/types.ts
3
+ function createCancelledError(message = "User cancelled") {
4
+ return { type: "cancelled", message };
5
+ }
6
+
7
+ export { createCancelledError };
@@ -0,0 +1,39 @@
1
+ // @bun
2
+ // packages/tui/src/render/tree.ts
3
+ var TREE_GUIDES = {
4
+ single: { vertical: "\u2502 ", fork: "\u251C\u2500\u2500 ", end: "\u2514\u2500\u2500 " },
5
+ heavy: { vertical: "\u2503 ", fork: "\u2523\u2501\u2501 ", end: "\u2517\u2501\u2501 " },
6
+ double: { vertical: "\u2551 ", fork: "\u2560\u2550\u2550 ", end: "\u255A\u2550\u2550 " },
7
+ rounded: { vertical: "\u2502 ", fork: "\u251C\u2500\u2500 ", end: "\u2570\u2500\u2500 " }
8
+ };
9
+ function renderTree(tree, options) {
10
+ const guide = TREE_GUIDES[options?.guide ?? "single"];
11
+ const maxDepth = options?.maxDepth;
12
+ const renderLabel = options?.renderLabel ?? ((key) => key);
13
+ const lines = [];
14
+ const renderNode = (key, value, prefix, isLast, depth) => {
15
+ if (maxDepth !== undefined && depth >= maxDepth) {
16
+ return;
17
+ }
18
+ const connector = isLast ? guide.end : guide.fork;
19
+ const label = renderLabel(key, value, depth);
20
+ lines.push(prefix + connector + label);
21
+ if (value !== null && typeof value === "object") {
22
+ const entries2 = Object.entries(value);
23
+ const childPrefix = prefix + (isLast ? " " : guide.vertical);
24
+ entries2.forEach(([childKey, childValue], index) => {
25
+ const childIsLast = index === entries2.length - 1;
26
+ renderNode(childKey, childValue, childPrefix, childIsLast, depth + 1);
27
+ });
28
+ }
29
+ };
30
+ const entries = Object.entries(tree);
31
+ entries.forEach(([key, value], index) => {
32
+ const isLast = index === entries.length - 1;
33
+ renderNode(key, value, "", isLast, 0);
34
+ });
35
+ return lines.join(`
36
+ `);
37
+ }
38
+
39
+ export { TREE_GUIDES, renderTree };
@@ -0,0 +1,30 @@
1
+ // @bun
2
+ import {
3
+ defaultTheme
4
+ } from "./tui-0mpqnyc1.js";
5
+ import {
6
+ BORDERS,
7
+ init_borders
8
+ } from "./tui-2pwhzg55.js";
9
+
10
+ // packages/tui/src/theme/presets/minimal.ts
11
+ init_borders();
12
+ var minimalTheme = {
13
+ ...defaultTheme,
14
+ name: "minimal",
15
+ border: "ascii",
16
+ borderChars: BORDERS.ascii,
17
+ treeGuide: "single",
18
+ delimiter: "bullet",
19
+ markers: {
20
+ ...defaultTheme.markers
21
+ },
22
+ listBullet: { unicode: "-", fallback: "-" },
23
+ checkbox: {
24
+ checked: { unicode: "[x]", fallback: "[x]" },
25
+ unchecked: { unicode: "[ ]", fallback: "[ ]" }
26
+ },
27
+ spinner: "line"
28
+ };
29
+
30
+ export { minimalTheme };
@@ -0,0 +1,82 @@
1
+ // @bun
2
+ import {
3
+ getTerminalWidth
4
+ } from "./tui-06dntkse.js";
5
+
6
+ // packages/tui/src/render/heading.ts
7
+ var ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
8
+ function toTitleCase(text) {
9
+ return text.replace(/\w\S*/g, (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
10
+ }
11
+ function applyCase(text, caseMode) {
12
+ if (caseMode === "none") {
13
+ return text;
14
+ }
15
+ const hasAnsi = ANSI_PATTERN.test(text);
16
+ ANSI_PATTERN.lastIndex = 0;
17
+ if (!hasAnsi) {
18
+ switch (caseMode) {
19
+ case "upper":
20
+ return text.toUpperCase();
21
+ case "lower":
22
+ return text.toLowerCase();
23
+ case "title":
24
+ return toTitleCase(text);
25
+ default: {
26
+ const _exhaustive = caseMode;
27
+ return _exhaustive;
28
+ }
29
+ }
30
+ }
31
+ const sequences = [];
32
+ for (const match of text.matchAll(ANSI_PATTERN)) {
33
+ sequences.push({ index: match.index, seq: match[0] });
34
+ }
35
+ const stripped = Bun.stripANSI(text);
36
+ let transformed;
37
+ switch (caseMode) {
38
+ case "upper":
39
+ transformed = stripped.toUpperCase();
40
+ break;
41
+ case "lower":
42
+ transformed = stripped.toLowerCase();
43
+ break;
44
+ case "title":
45
+ transformed = toTitleCase(stripped);
46
+ break;
47
+ default: {
48
+ const _exhaustive = caseMode;
49
+ return _exhaustive;
50
+ }
51
+ }
52
+ let result = transformed;
53
+ let offset = 0;
54
+ for (const { index, seq } of sequences) {
55
+ const insertPos = index + offset;
56
+ result = result.slice(0, insertPos) + seq + result.slice(insertPos);
57
+ offset += seq.length;
58
+ }
59
+ return result;
60
+ }
61
+ function getTextWidth(text) {
62
+ return Bun.stringWidth(text);
63
+ }
64
+ function renderHeading(text, options) {
65
+ const separator = options?.separator ?? "=";
66
+ const widthMode = options?.width ?? "text";
67
+ const caseMode = options?.case ?? "upper";
68
+ const transformedText = applyCase(text, caseMode);
69
+ let width;
70
+ if (widthMode === "text") {
71
+ width = getTextWidth(transformedText);
72
+ } else if (widthMode === "full") {
73
+ width = getTerminalWidth();
74
+ } else {
75
+ width = widthMode;
76
+ }
77
+ const separatorLine = separator.repeat(width);
78
+ return `${transformedText}
79
+ ${separatorLine}`;
80
+ }
81
+
82
+ export { renderHeading };
@@ -0,0 +1,348 @@
1
+ // @bun
2
+ import {
3
+ TREE_GUIDES
4
+ } from "./tui-kydbggmj.js";
5
+ import {
6
+ joinHorizontal,
7
+ joinVertical
8
+ } from "./tui-06dntkse.js";
9
+ import {
10
+ exports_box,
11
+ init_box,
12
+ renderBox
13
+ } from "./tui-t9vd88jr.js";
14
+ import {
15
+ getIndicator,
16
+ isUnicodeSupported
17
+ } from "./tui-pdwbbzwr.js";
18
+ import {
19
+ __toCommonJS
20
+ } from "./tui-hescagw2.js";
21
+
22
+ // packages/tui/src/render/stack.ts
23
+ init_box();
24
+ import { getStringWidth } from "@outfitter/cli/text";
25
+ var DELIMITERS = {
26
+ space: { unicode: " ", fallback: " " },
27
+ bullet: { unicode: "\u2022", fallback: "*" },
28
+ dot: { unicode: "\xB7", fallback: "." },
29
+ pipe: { unicode: "\u2502", fallback: "|" },
30
+ arrow: { unicode: "\u2192", fallback: "->" },
31
+ slash: { unicode: "/", fallback: "/" },
32
+ colon: { unicode: ":", fallback: ":" }
33
+ };
34
+ function getDelimiter(name, forceUnicode) {
35
+ const delimiter = DELIMITERS[name];
36
+ const useUnicode = forceUnicode ?? isUnicodeSupported();
37
+ return useUnicode ? delimiter.unicode : delimiter.fallback;
38
+ }
39
+ function getMarker(nameOrChar, forceUnicode) {
40
+ const knownMarkers = [
41
+ "circleDot",
42
+ "circleOutline",
43
+ "circle",
44
+ "checkbox",
45
+ "checkboxChecked",
46
+ "pointer",
47
+ "dash"
48
+ ];
49
+ if (knownMarkers.includes(nameOrChar)) {
50
+ return getIndicator("marker", nameOrChar, forceUnicode);
51
+ }
52
+ return nameOrChar;
53
+ }
54
+ var DEFAULT_STACK_THEME = {
55
+ markers: {
56
+ default: "circleOutline",
57
+ current: "circleDot",
58
+ focused: "pointer",
59
+ checked: "checkboxChecked",
60
+ disabled: "dash"
61
+ },
62
+ delimiter: "bullet",
63
+ guide: "single"
64
+ };
65
+ function isRenderable(value) {
66
+ return typeof value === "object" && value !== null && "output" in value && "width" in value && "height" in value && typeof value.output === "string" && typeof value.width === "number" && typeof value.height === "number";
67
+ }
68
+ function isDelimiterName(value) {
69
+ return value in DELIMITERS;
70
+ }
71
+ function resolveDelimiter(delimiter) {
72
+ if (delimiter === undefined) {
73
+ return getDelimiter("space");
74
+ }
75
+ if (isDelimiterName(delimiter)) {
76
+ return getDelimiter(delimiter);
77
+ }
78
+ return delimiter;
79
+ }
80
+ function normalizeItem(item) {
81
+ if (typeof item === "string") {
82
+ return { content: item };
83
+ }
84
+ if (isRenderable(item)) {
85
+ return { content: item.output };
86
+ }
87
+ return item;
88
+ }
89
+ function shouldShowMarker(item) {
90
+ return item.state !== undefined || item.marker !== undefined;
91
+ }
92
+ function resolveMarker(item, theme) {
93
+ if (!shouldShowMarker(item)) {
94
+ return { marker: "", show: false };
95
+ }
96
+ if (item.marker !== undefined) {
97
+ return { marker: getMarker(item.marker), show: true };
98
+ }
99
+ const state = item.state ?? "default";
100
+ const markerName = theme.markers[state];
101
+ return { marker: getMarker(markerName), show: true };
102
+ }
103
+ function getContentLines(content) {
104
+ if (typeof content === "string") {
105
+ return content.split(`
106
+ `);
107
+ }
108
+ return content;
109
+ }
110
+ function applyStyle(content, style) {
111
+ return style ? style(content) : content;
112
+ }
113
+ function hstack(items, options) {
114
+ if (items.length === 0)
115
+ return "";
116
+ const normalizedItems = items.map(normalizeItem);
117
+ const delimiter = resolveDelimiter(options?.delimiter);
118
+ const gap = options?.gap ?? 0;
119
+ const align = options?.align ?? "top";
120
+ const gapStr = " ".repeat(gap);
121
+ const fullDelimiter = `${gapStr}${delimiter}${gapStr}`;
122
+ const contentStrings = normalizedItems.map((item) => {
123
+ const lines = getContentLines(item.content);
124
+ const styledLines = lines.map((line) => applyStyle(line, item.style));
125
+ return styledLines.join(`
126
+ `);
127
+ });
128
+ const isMultiLine = contentStrings.some((s) => s.includes(`
129
+ `));
130
+ if (!isMultiLine) {
131
+ return contentStrings.join(fullDelimiter);
132
+ }
133
+ const blocks = contentStrings.map((content, idx) => {
134
+ if (idx === contentStrings.length - 1) {
135
+ return content;
136
+ }
137
+ const lines = content.split(`
138
+ `);
139
+ return lines.map((line) => line + fullDelimiter).join(`
140
+ `);
141
+ });
142
+ return joinHorizontal(blocks, { gap: 0, align });
143
+ }
144
+ function createHStack(items, options) {
145
+ const output = hstack(items, options);
146
+ const lines = output.split(`
147
+ `);
148
+ const width = Math.max(...lines.map(getStringWidth));
149
+ return {
150
+ output,
151
+ width,
152
+ height: lines.length
153
+ };
154
+ }
155
+ function vstackItem(header, body, options) {
156
+ const content = body && body.length > 0 ? [header, ...body] : [header];
157
+ const result = {
158
+ content,
159
+ state: options?.state ?? "default"
160
+ };
161
+ if (options?.marker !== undefined) {
162
+ result.marker = options.marker;
163
+ }
164
+ if (options?.compact !== undefined) {
165
+ result.compact = options.compact;
166
+ }
167
+ if (options?.style !== undefined) {
168
+ result.style = options.style;
169
+ }
170
+ return result;
171
+ }
172
+ var GUIDE_CHARS = {
173
+ single: "\u2502",
174
+ heavy: "\u2503",
175
+ double: "\u2551",
176
+ rounded: "\u2502"
177
+ };
178
+ function renderPlainMode(items, theme, gap) {
179
+ const lines = [];
180
+ for (const item of items) {
181
+ const { marker, show } = resolveMarker(item, theme);
182
+ const contentLines = getContentLines(item.content);
183
+ const prefix = show ? `${marker} ` : "";
184
+ const firstLine = contentLines[0];
185
+ if (firstLine !== undefined) {
186
+ const styled = applyStyle(firstLine, item.style);
187
+ lines.push(`${prefix}${styled}`);
188
+ }
189
+ const indent = show ? " " : "";
190
+ for (let i = 1;i < contentLines.length; i++) {
191
+ const line = contentLines[i];
192
+ if (line !== undefined) {
193
+ const styled = applyStyle(line, item.style);
194
+ lines.push(`${indent}${styled}`);
195
+ }
196
+ }
197
+ }
198
+ return joinVertical(lines, { gap });
199
+ }
200
+ function renderGuideMode(items, theme, guideStyle) {
201
+ const lines = [];
202
+ const guideChar = GUIDE_CHARS[guideStyle];
203
+ for (let itemIdx = 0;itemIdx < items.length; itemIdx++) {
204
+ const item = items[itemIdx];
205
+ if (!item)
206
+ continue;
207
+ const { marker, show } = resolveMarker(item, theme);
208
+ const contentLines = getContentLines(item.content);
209
+ const isLastItem = itemIdx === items.length - 1;
210
+ const displayMarker = show ? marker : getMarker(theme.markers.default);
211
+ const firstLine = contentLines[0];
212
+ if (firstLine !== undefined) {
213
+ const styled = applyStyle(firstLine, item.style);
214
+ lines.push(`${displayMarker} ${styled}`);
215
+ }
216
+ for (let i = 1;i < contentLines.length; i++) {
217
+ const line = contentLines[i];
218
+ if (line !== undefined) {
219
+ const styled = applyStyle(line, item.style);
220
+ lines.push(`${guideChar} ${styled}`);
221
+ }
222
+ }
223
+ if (!isLastItem) {
224
+ lines.push(guideChar);
225
+ }
226
+ }
227
+ return lines.join(`
228
+ `);
229
+ }
230
+ function renderTreeMode(items, guideStyle) {
231
+ const lines = [];
232
+ const guides = TREE_GUIDES[guideStyle];
233
+ for (let itemIdx = 0;itemIdx < items.length; itemIdx++) {
234
+ const item = items[itemIdx];
235
+ if (!item)
236
+ continue;
237
+ const contentLines = getContentLines(item.content);
238
+ const isLastItem = itemIdx === items.length - 1;
239
+ const connector = isLastItem ? guides.end : guides.fork;
240
+ const continuation = isLastItem ? " " : guides.vertical;
241
+ const firstLine = contentLines[0];
242
+ if (firstLine !== undefined) {
243
+ const styled = applyStyle(firstLine, item.style);
244
+ lines.push(`${connector}${styled}`);
245
+ }
246
+ for (let i = 1;i < contentLines.length; i++) {
247
+ const line = contentLines[i];
248
+ if (line !== undefined) {
249
+ const styled = applyStyle(line, item.style);
250
+ lines.push(`${continuation}${styled}`);
251
+ }
252
+ }
253
+ }
254
+ return lines.join(`
255
+ `);
256
+ }
257
+ function renderBoxedMode(items, gap) {
258
+ const boxes = [];
259
+ for (const item of items) {
260
+ const contentLines = getContentLines(item.content);
261
+ const styled = contentLines.map((line) => applyStyle(line, item.style));
262
+ boxes.push(renderBox(styled));
263
+ }
264
+ return joinVertical(boxes, { gap });
265
+ }
266
+ function renderCompactMode(items, theme) {
267
+ const lines = [];
268
+ for (const item of items) {
269
+ const { marker, show } = resolveMarker(item, theme);
270
+ const displayMarker = show ? marker : getMarker(theme.markers.default);
271
+ let displayText;
272
+ if (item.compact) {
273
+ displayText = item.compact;
274
+ } else {
275
+ const contentLines = getContentLines(item.content);
276
+ displayText = contentLines[0] ?? "";
277
+ }
278
+ const styled = applyStyle(displayText, item.style);
279
+ lines.push(`${displayMarker} ${styled}`);
280
+ }
281
+ return lines.join(`
282
+ `);
283
+ }
284
+ function vstack(items, options) {
285
+ if (items.length === 0)
286
+ return "";
287
+ const normalizedItems = items.map(normalizeItem);
288
+ const mode = options?.mode ?? "guide";
289
+ const gap = options?.gap ?? 0;
290
+ const theme = {
291
+ ...DEFAULT_STACK_THEME,
292
+ ...options?.theme,
293
+ markers: {
294
+ ...DEFAULT_STACK_THEME.markers,
295
+ ...options?.theme?.markers
296
+ }
297
+ };
298
+ const guideStyle = options?.guide ?? theme.guide ?? "single";
299
+ switch (mode) {
300
+ case "plain":
301
+ return renderPlainMode(normalizedItems, theme, gap);
302
+ case "guide":
303
+ return renderGuideMode(normalizedItems, theme, guideStyle);
304
+ case "tree":
305
+ return renderTreeMode(normalizedItems, guideStyle);
306
+ case "boxed":
307
+ return renderBoxedMode(normalizedItems, gap);
308
+ case "compact":
309
+ return renderCompactMode(normalizedItems, theme);
310
+ default: {
311
+ const _exhaustive = mode;
312
+ return _exhaustive;
313
+ }
314
+ }
315
+ }
316
+ function createVStack(items, options) {
317
+ const output = vstack(items, options);
318
+ const lines = output.split(`
319
+ `);
320
+ const width = Math.max(...lines.map(getStringWidth), 0);
321
+ return {
322
+ output,
323
+ width,
324
+ height: lines.length
325
+ };
326
+ }
327
+ function boxify(content, options) {
328
+ const { createBox: makeBox } = (init_box(), __toCommonJS(exports_box));
329
+ const boxContent = isRenderable(content) ? content.output : content;
330
+ const boxOptions = {
331
+ border: options?.border ?? "single"
332
+ };
333
+ if (options?.title !== undefined) {
334
+ boxOptions.title = options.title;
335
+ }
336
+ if (options?.padding !== undefined) {
337
+ boxOptions.padding = options.padding;
338
+ }
339
+ return makeBox(boxContent, boxOptions);
340
+ }
341
+ function unbox(content) {
342
+ if (isRenderable(content)) {
343
+ return content.output;
344
+ }
345
+ return content;
346
+ }
347
+
348
+ export { DELIMITERS, getDelimiter, getMarker, DEFAULT_STACK_THEME, isRenderable, hstack, createHStack, vstackItem, vstack, createVStack, boxify, unbox };
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import {
3
+ getTerminalWidth
4
+ } from "./tui-06dntkse.js";
5
+
6
+ // packages/tui/src/render/separator.ts
7
+ function renderSeparator(options) {
8
+ const style = options?.style ?? "\u2500";
9
+ const widthMode = options?.width ?? 40;
10
+ let width;
11
+ if (widthMode === "text") {
12
+ width = 40;
13
+ } else if (widthMode === "full") {
14
+ width = getTerminalWidth();
15
+ } else {
16
+ width = widthMode;
17
+ }
18
+ if (style.length === 2) {
19
+ const repetitions = Math.ceil(width / 2);
20
+ return style.repeat(repetitions).slice(0, width);
21
+ }
22
+ return style.repeat(width);
23
+ }
24
+
25
+ export { renderSeparator };