@promptctl/rich-js 0.18.0 → 0.18.1

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 (221) hide show
  1. package/dist/core/anchor.d.ts +45 -0
  2. package/dist/core/anchor.js +39 -0
  3. package/dist/core/ansi.d.ts +65 -0
  4. package/dist/core/ansi.js +231 -0
  5. package/dist/core/box.d.ts +143 -0
  6. package/dist/core/box.js +379 -0
  7. package/dist/core/cells.d.ts +159 -0
  8. package/dist/core/cells.js +287 -0
  9. package/dist/core/color.d.ts +246 -0
  10. package/dist/core/color.js +1038 -0
  11. package/dist/core/console.d.ts +165 -0
  12. package/dist/core/console.js +527 -0
  13. package/dist/core/emoji.d.ts +24 -0
  14. package/dist/core/emoji.js +391 -0
  15. package/dist/core/export-html.d.ts +59 -0
  16. package/dist/core/export-html.js +200 -0
  17. package/dist/core/export-lines.d.ts +121 -0
  18. package/dist/core/export-lines.js +141 -0
  19. package/dist/core/highlighter.d.ts +33 -0
  20. package/dist/core/highlighter.js +124 -0
  21. package/dist/core/json.d.ts +27 -0
  22. package/dist/core/json.js +53 -0
  23. package/dist/core/markup.d.ts +119 -0
  24. package/dist/core/markup.js +731 -0
  25. package/dist/core/measure.d.ts +27 -0
  26. package/dist/core/measure.js +62 -0
  27. package/dist/core/oklch.d.ts +161 -0
  28. package/dist/core/oklch.js +312 -0
  29. package/dist/core/osc8.d.ts +68 -0
  30. package/dist/core/osc8.js +90 -0
  31. package/dist/core/place.d.ts +30 -0
  32. package/dist/core/place.js +51 -0
  33. package/dist/core/pretty.d.ts +144 -0
  34. package/dist/core/pretty.js +476 -0
  35. package/dist/core/protocol.d.ts +267 -0
  36. package/dist/core/protocol.js +163 -0
  37. package/dist/core/render.d.ts +84 -0
  38. package/dist/core/render.js +145 -0
  39. package/dist/core/segment.d.ts +161 -0
  40. package/dist/core/segment.js +492 -0
  41. package/dist/core/spinnerData.d.ts +12 -0
  42. package/dist/core/spinnerData.js +117 -0
  43. package/dist/core/strip.d.ts +141 -0
  44. package/dist/core/strip.js +305 -0
  45. package/dist/core/style.d.ts +169 -0
  46. package/dist/core/style.js +695 -0
  47. package/dist/core/subscription.d.ts +12 -0
  48. package/dist/core/subscription.js +12 -0
  49. package/dist/core/text.d.ts +256 -0
  50. package/dist/core/text.js +976 -0
  51. package/dist/core/wrap.d.ts +41 -0
  52. package/dist/core/wrap.js +127 -0
  53. package/dist/host/app.d.ts +121 -0
  54. package/dist/host/app.js +255 -0
  55. package/dist/host/host-environment.d.ts +26 -0
  56. package/dist/host/host-environment.js +44 -0
  57. package/dist/host/index.d.ts +5 -0
  58. package/dist/host/index.js +3 -0
  59. package/dist/host/terminal-host.d.ts +179 -0
  60. package/dist/host/terminal-host.js +186 -0
  61. package/dist/index.d.ts +91 -0
  62. package/dist/index.js +107 -0
  63. package/dist/node/prompt.d.ts +21 -0
  64. package/dist/node/prompt.js +30 -0
  65. package/dist/node/save.d.ts +17 -0
  66. package/dist/node/save.js +21 -0
  67. package/dist/node/terminal-host.d.ts +113 -0
  68. package/dist/node/terminal-host.js +227 -0
  69. package/dist/node/traceback.d.ts +37 -0
  70. package/dist/node/traceback.js +134 -0
  71. package/dist/renderables/align.d.ts +16 -0
  72. package/dist/renderables/align.js +33 -0
  73. package/dist/renderables/columns.d.ts +61 -0
  74. package/dist/renderables/columns.js +152 -0
  75. package/dist/renderables/constrain.d.ts +15 -0
  76. package/dist/renderables/constrain.js +37 -0
  77. package/dist/renderables/embed.d.ts +50 -0
  78. package/dist/renderables/embed.js +71 -0
  79. package/dist/renderables/flexStrip.d.ts +41 -0
  80. package/dist/renderables/flexStrip.js +200 -0
  81. package/dist/renderables/group.d.ts +11 -0
  82. package/dist/renderables/group.js +17 -0
  83. package/dist/renderables/layout.d.ts +92 -0
  84. package/dist/renderables/layout.js +312 -0
  85. package/dist/renderables/live.d.ts +50 -0
  86. package/dist/renderables/live.js +175 -0
  87. package/dist/renderables/markdown.d.ts +24 -0
  88. package/dist/renderables/markdown.js +184 -0
  89. package/dist/renderables/padding.d.ts +38 -0
  90. package/dist/renderables/padding.js +141 -0
  91. package/dist/renderables/panel.d.ts +116 -0
  92. package/dist/renderables/panel.js +307 -0
  93. package/dist/renderables/progress.d.ts +90 -0
  94. package/dist/renderables/progress.js +238 -0
  95. package/dist/renderables/progressBar.d.ts +31 -0
  96. package/dist/renderables/progressBar.js +53 -0
  97. package/dist/renderables/prompt.d.ts +49 -0
  98. package/dist/renderables/prompt.js +125 -0
  99. package/dist/renderables/rule.d.ts +25 -0
  100. package/dist/renderables/rule.js +90 -0
  101. package/dist/renderables/spinner.d.ts +31 -0
  102. package/dist/renderables/spinner.js +70 -0
  103. package/dist/renderables/status.d.ts +23 -0
  104. package/dist/renderables/status.js +60 -0
  105. package/dist/renderables/syntax.d.ts +35 -0
  106. package/dist/renderables/syntax.js +115 -0
  107. package/dist/renderables/table.d.ts +194 -0
  108. package/dist/renderables/table.js +795 -0
  109. package/dist/renderables/traceback.d.ts +31 -0
  110. package/dist/renderables/traceback.js +108 -0
  111. package/dist/renderables/tree.d.ts +68 -0
  112. package/dist/renderables/tree.js +150 -0
  113. package/dist/renderables/viewport.d.ts +114 -0
  114. package/dist/renderables/viewport.js +198 -0
  115. package/dist/template-bindings/color-funcs.d.ts +87 -0
  116. package/dist/template-bindings/color-funcs.js +217 -0
  117. package/dist/template-bindings/helpers.d.ts +24 -0
  118. package/dist/template-bindings/helpers.js +48 -0
  119. package/dist/template-bindings/index.d.ts +107 -0
  120. package/dist/template-bindings/index.js +146 -0
  121. package/dist/template-bindings/palette-funcs.d.ts +94 -0
  122. package/dist/template-bindings/palette-funcs.js +141 -0
  123. package/dist/template-bindings/style-funcs.d.ts +28 -0
  124. package/dist/template-bindings/style-funcs.js +155 -0
  125. package/dist/themes/buildPalette.d.ts +36 -0
  126. package/dist/themes/buildPalette.js +56 -0
  127. package/dist/themes/colorMath.d.ts +82 -0
  128. package/dist/themes/colorMath.js +254 -0
  129. package/dist/themes/colorRef.d.ts +51 -0
  130. package/dist/themes/colorRef.js +96 -0
  131. package/dist/themes/data/ansi-tables.d.ts +14 -0
  132. package/dist/themes/data/ansi-tables.js +49 -0
  133. package/dist/themes/data/atom-one-dark.d.ts +3 -0
  134. package/dist/themes/data/atom-one-dark.js +177 -0
  135. package/dist/themes/data/atom-one-light.d.ts +3 -0
  136. package/dist/themes/data/atom-one-light.js +177 -0
  137. package/dist/themes/data/catppuccin-frappe.d.ts +3 -0
  138. package/dist/themes/data/catppuccin-frappe.js +177 -0
  139. package/dist/themes/data/catppuccin-latte.d.ts +3 -0
  140. package/dist/themes/data/catppuccin-latte.js +177 -0
  141. package/dist/themes/data/catppuccin-macchiato.d.ts +3 -0
  142. package/dist/themes/data/catppuccin-macchiato.js +177 -0
  143. package/dist/themes/data/catppuccin-mocha.d.ts +3 -0
  144. package/dist/themes/data/catppuccin-mocha.js +177 -0
  145. package/dist/themes/data/cyberpunk.d.ts +17 -0
  146. package/dist/themes/data/cyberpunk.js +193 -0
  147. package/dist/themes/data/default.d.ts +3 -0
  148. package/dist/themes/data/default.js +160 -0
  149. package/dist/themes/data/dracula.d.ts +3 -0
  150. package/dist/themes/data/dracula.js +177 -0
  151. package/dist/themes/data/flexoki.d.ts +3 -0
  152. package/dist/themes/data/flexoki.js +177 -0
  153. package/dist/themes/data/gruvbox.d.ts +3 -0
  154. package/dist/themes/data/gruvbox.js +177 -0
  155. package/dist/themes/data/index.d.ts +35 -0
  156. package/dist/themes/data/index.js +64 -0
  157. package/dist/themes/data/monokai.d.ts +3 -0
  158. package/dist/themes/data/monokai.js +177 -0
  159. package/dist/themes/data/nord.d.ts +3 -0
  160. package/dist/themes/data/nord.js +177 -0
  161. package/dist/themes/data/rose-pine-dawn.d.ts +3 -0
  162. package/dist/themes/data/rose-pine-dawn.js +177 -0
  163. package/dist/themes/data/rose-pine-moon.d.ts +3 -0
  164. package/dist/themes/data/rose-pine-moon.js +177 -0
  165. package/dist/themes/data/rose-pine.d.ts +3 -0
  166. package/dist/themes/data/rose-pine.js +177 -0
  167. package/dist/themes/data/solarized-dark.d.ts +3 -0
  168. package/dist/themes/data/solarized-dark.js +177 -0
  169. package/dist/themes/data/solarized-light.d.ts +3 -0
  170. package/dist/themes/data/solarized-light.js +177 -0
  171. package/dist/themes/data/svg-export.d.ts +3 -0
  172. package/dist/themes/data/svg-export.js +177 -0
  173. package/dist/themes/data/textual-ansi.d.ts +3 -0
  174. package/dist/themes/data/textual-ansi.js +160 -0
  175. package/dist/themes/data/textual-dark.d.ts +3 -0
  176. package/dist/themes/data/textual-dark.js +160 -0
  177. package/dist/themes/data/textual-light.d.ts +3 -0
  178. package/dist/themes/data/textual-light.js +160 -0
  179. package/dist/themes/data/tokyo-night.d.ts +3 -0
  180. package/dist/themes/data/tokyo-night.js +177 -0
  181. package/dist/themes/data/types.d.ts +31 -0
  182. package/dist/themes/data/types.js +10 -0
  183. package/dist/themes/palette.d.ts +21 -0
  184. package/dist/themes/palette.js +28 -0
  185. package/dist/themes/ramp.d.ts +83 -0
  186. package/dist/themes/ramp.js +122 -0
  187. package/dist/themes/registry.d.ts +44 -0
  188. package/dist/themes/registry.js +94 -0
  189. package/dist/themes/terminalThemes.d.ts +49 -0
  190. package/dist/themes/terminalThemes.js +63 -0
  191. package/dist/themes/transpose.d.ts +87 -0
  192. package/dist/themes/transpose.js +138 -0
  193. package/dist/widgets/button.d.ts +49 -0
  194. package/dist/widgets/button.js +208 -0
  195. package/dist/widgets/checkbox.d.ts +41 -0
  196. package/dist/widgets/checkbox.js +157 -0
  197. package/dist/widgets/dropdown.d.ts +67 -0
  198. package/dist/widgets/dropdown.js +450 -0
  199. package/dist/widgets/event-router.d.ts +71 -0
  200. package/dist/widgets/event-router.js +629 -0
  201. package/dist/widgets/focus-manager.d.ts +45 -0
  202. package/dist/widgets/focus-manager.js +191 -0
  203. package/dist/widgets/hit.d.ts +64 -0
  204. package/dist/widgets/hit.js +113 -0
  205. package/dist/widgets/index.d.ts +20 -0
  206. package/dist/widgets/index.js +14 -0
  207. package/dist/widgets/slider.d.ts +57 -0
  208. package/dist/widgets/slider.js +270 -0
  209. package/dist/widgets/static-item.d.ts +34 -0
  210. package/dist/widgets/static-item.js +54 -0
  211. package/dist/widgets/text-input.d.ts +274 -0
  212. package/dist/widgets/text-input.js +1165 -0
  213. package/dist/widgets/toggle.d.ts +44 -0
  214. package/dist/widgets/toggle.js +180 -0
  215. package/dist/widgets/types.d.ts +87 -0
  216. package/dist/widgets/types.js +30 -0
  217. package/dist/widgets/widget-app.d.ts +63 -0
  218. package/dist/widgets/widget-app.js +199 -0
  219. package/dist/widgets/widget-base.d.ts +40 -0
  220. package/dist/widgets/widget-base.js +165 -0
  221. package/package.json +6 -2
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Built-in spinner frame data.
3
+ * [LAW:one-type-per-behavior] All spinners are instances of SpinnerData — differ only by frame data.
4
+ */
5
+ /** The spinner an ASCII-only output draws in place of any other. */
6
+ export const LINE_SPINNER = { frames: ["-", "\\", "|", "/"], interval: 130 };
7
+ // [LAW:one-source-of-truth] Single authoritative collection of spinner definitions
8
+ export const SPINNERS = {
9
+ dots: { frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], interval: 80 },
10
+ dots2: { frames: ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"], interval: 80 },
11
+ dots3: { frames: ["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"], interval: 80 },
12
+ line: LINE_SPINNER,
13
+ line2: { frames: ["⠂", "-", "–", "—", "–", "-"], interval: 100 },
14
+ pipe: { frames: ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"], interval: 100 },
15
+ simpleDots: { frames: [". ", ".. ", "...", " "], interval: 400 },
16
+ simpleDotsScrolling: { frames: [". ", ".. ", "...", " ..", " .", " "], interval: 200 },
17
+ star: { frames: ["✶", "✸", "✹", "✺", "✹", "✷"], interval: 70 },
18
+ star2: { frames: ["+", "x", "*"], interval: 80 },
19
+ flip: { frames: ["_", "_", "_", "-", "`", "`", "'", "´", "-", "_", "_", "_"], interval: 70 },
20
+ hamburger: { frames: ["☱", "☲", "☴"], interval: 100 },
21
+ growVertical: { frames: ["▁", "▃", "▄", "▅", "▆", "▇", "▆", "▅", "▄", "▃"], interval: 120 },
22
+ growHorizontal: { frames: ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"], interval: 120 },
23
+ balloon: { frames: [" ", ".", "o", "O", "@", "*", " "], interval: 140 },
24
+ balloon2: { frames: [".", "o", "O", "°", "O", "o", "."], interval: 120 },
25
+ noise: { frames: ["▓", "▒", "░"], interval: 100 },
26
+ bounce: { frames: ["⠁", "⠂", "⠄", "⠂"], interval: 120 },
27
+ boxBounce: { frames: ["▖", "▘", "▝", "▗"], interval: 120 },
28
+ boxBounce2: { frames: ["▌", "▀", "▐", "▄"], interval: 100 },
29
+ triangle: { frames: ["◢", "◣", "◤", "◥"], interval: 50 },
30
+ arc: { frames: ["◜", "◠", "◝", "◞", "◡", "◟"], interval: 100 },
31
+ circle: { frames: ["◡", "⊙", "◠"], interval: 120 },
32
+ squareCorners: { frames: ["◰", "◳", "◲", "◱"], interval: 180 },
33
+ circleQuarters: { frames: ["◴", "◷", "◶", "◵"], interval: 120 },
34
+ circleHalves: { frames: ["◐", "◓", "◑", "◒"], interval: 50 },
35
+ squish: { frames: ["╫", "╪"], interval: 100 },
36
+ toggle: { frames: ["⊶", "⊷"], interval: 250 },
37
+ toggle2: { frames: ["▫", "▪"], interval: 80 },
38
+ toggle3: { frames: ["□", "■"], interval: 120 },
39
+ toggle4: { frames: ["■", "□", "▪", "▫"], interval: 100 },
40
+ toggle5: { frames: ["▮", "▯"], interval: 100 },
41
+ toggle6: { frames: ["ဝ", "၀"], interval: 300 },
42
+ toggle7: { frames: ["⦾", "⦿"], interval: 80 },
43
+ toggle8: { frames: ["◍", "◌"], interval: 100 },
44
+ toggle9: { frames: ["◉", "◎"], interval: 100 },
45
+ toggle10: { frames: ["㊂", "㊀", "㊁"], interval: 100 },
46
+ toggle11: { frames: ["⧇", "⧆"], interval: 50 },
47
+ toggle12: { frames: ["☗", "☖"], interval: 120 },
48
+ toggle13: { frames: ["=", "*", "-"], interval: 80 },
49
+ arrow: { frames: ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"], interval: 100 },
50
+ arrow2: { frames: ["⬆️ ", "↗️ ", "➡️ ", "↘️ ", "⬇️ ", "↙️ ", "⬅️ ", "↖️ "], interval: 80 },
51
+ arrow3: { frames: ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"], interval: 120 },
52
+ bouncingBar: { frames: [
53
+ "[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", "[ ]",
54
+ "[ =]", "[ ==]", "[ ===]", "[====]", "[=== ]", "[== ]", "[= ]",
55
+ ], interval: 80 },
56
+ bouncingBall: { frames: [
57
+ "( ● )", "( ● )", "( ● )", "( ● )", "( ●)", "( ● )",
58
+ "( ● )", "( ● )", "( ● )", "(● )",
59
+ ], interval: 80 },
60
+ smiley: { frames: ["😄 ", "😝 "], interval: 200 },
61
+ monkey: { frames: ["🙈 ", "🙈 ", "🙉 ", "🙊 "], interval: 300 },
62
+ hearts: { frames: ["💛 ", "💙 ", "💜 ", "💚 ", "❤️ "], interval: 100 },
63
+ clock: { frames: ["🕛 ", "🕐 ", "🕑 ", "🕒 ", "🕓 ", "🕔 ", "🕕 ", "🕖 ", "🕗 ", "🕘 ", "🕙 ", "🕚 "], interval: 100 },
64
+ earth: { frames: ["🌍 ", "🌎 ", "🌏 "], interval: 180 },
65
+ moon: { frames: ["🌑 ", "🌒 ", "🌓 ", "🌔 ", "🌕 ", "🌖 ", "🌗 ", "🌘 "], interval: 80 },
66
+ runner: { frames: ["🚶 ", "🏃 "], interval: 140 },
67
+ pong: { frames: [
68
+ "▐⠂ ▌", "▐⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌",
69
+ "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
70
+ "▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂▌",
71
+ "▐ ⠠▌", "▐ ⡀▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
72
+ "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌",
73
+ "▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐⠠ ▌",
74
+ ], interval: 80 },
75
+ material: { frames: [
76
+ "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
77
+ "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
78
+ "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁", "██████▁▁▁▁▁▁▁▁▁▁▁▁▁▁",
79
+ "███████▁▁▁▁▁▁▁▁▁▁▁▁▁", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
80
+ "█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
81
+ "██████████▁▁▁▁▁▁▁▁▁▁", "███████████▁▁▁▁▁▁▁▁▁",
82
+ "█████████████▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
83
+ "██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
84
+ "▁██████████████▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
85
+ "▁▁██████████████▁▁▁▁", "▁▁▁██████████████▁▁▁",
86
+ "▁▁▁▁█████████████▁▁▁", "▁▁▁▁██████████████▁▁",
87
+ "▁▁▁▁██████████████▁▁", "▁▁▁▁▁██████████████▁",
88
+ "▁▁▁▁▁██████████████▁", "▁▁▁▁▁██████████████▁",
89
+ "▁▁▁▁▁▁██████████████", "▁▁▁▁▁▁██████████████",
90
+ "▁▁▁▁▁▁▁█████████████", "▁▁▁▁▁▁▁█████████████",
91
+ "▁▁▁▁▁▁▁▁████████████", "▁▁▁▁▁▁▁▁████████████",
92
+ "▁▁▁▁▁▁▁▁▁███████████", "▁▁▁▁▁▁▁▁▁███████████",
93
+ "▁▁▁▁▁▁▁▁▁▁██████████", "▁▁▁▁▁▁▁▁▁▁██████████",
94
+ "▁▁▁▁▁▁▁▁▁▁▁▁████████", "▁▁▁▁▁▁▁▁▁▁▁▁▁███████",
95
+ "▁▁▁▁▁▁▁▁▁▁▁▁▁▁██████", "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████",
96
+ "▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█████", "█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁████",
97
+ "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁███",
98
+ "███▁▁▁▁▁▁▁▁▁▁▁▁▁▁███", "████▁▁▁▁▁▁▁▁▁▁▁▁▁▁██",
99
+ "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█", "█████▁▁▁▁▁▁▁▁▁▁▁▁▁▁█",
100
+ "██████▁▁▁▁▁▁▁▁▁▁▁▁▁█", "████████▁▁▁▁▁▁▁▁▁▁▁▁",
101
+ "█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
102
+ "█████████▁▁▁▁▁▁▁▁▁▁▁", "█████████▁▁▁▁▁▁▁▁▁▁▁",
103
+ "███████████▁▁▁▁▁▁▁▁▁", "████████████▁▁▁▁▁▁▁▁",
104
+ "████████████▁▁▁▁▁▁▁▁", "██████████████▁▁▁▁▁▁",
105
+ "██████████████▁▁▁▁▁▁", "▁██████████████▁▁▁▁▁",
106
+ "▁██████████████▁▁▁▁▁", "▁▁▁██████████████▁▁▁",
107
+ "▁▁▁▁▁████████████▁▁▁", "▁▁▁▁▁████████████▁▁▁",
108
+ "▁▁▁▁▁▁███████████▁▁▁", "▁▁▁▁▁▁▁▁█████████▁▁▁",
109
+ "▁▁▁▁▁▁▁▁█████████▁▁▁", "▁▁▁▁▁▁▁▁▁█████████▁▁",
110
+ "▁▁▁▁▁▁▁▁▁█████████▁▁", "▁▁▁▁▁▁▁▁▁▁█████████▁",
111
+ ], interval: 17 },
112
+ aesthetic: { frames: [
113
+ "▰▱▱▱▱▱▱", "▰▰▱▱▱▱▱", "▰▰▰▱▱▱▱", "▰▰▰▰▱▱▱",
114
+ "▰▰▰▰▰▱▱", "▰▰▰▰▰▰▱", "▰▰▰▰▰▰▰", "▰▱▱▱▱▱▱",
115
+ ], interval: 80 },
116
+ };
117
+ export const DEFAULT_SPINNER = "dots";
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Strip + Joiner — edge-aware horizontal layout primitive.
3
+ *
4
+ * A `Strip` renders a horizontal sequence of styled items with a `Joiner`
5
+ * deciding how each transition between adjacent items looks. The joiner is
6
+ * a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
7
+ * so endpoint joins (the start and end of the strip) are explicit positions
8
+ * in the protocol — the joiner names what an endpoint looks like rather than
9
+ * the strip guessing.
10
+ *
11
+ * [LAW:one-source-of-truth] The render walk
12
+ * joiner(null, items[0]), items[0],
13
+ * joiner(items[0], items[1]), items[1], ...,
14
+ * joiner(items[N-1], null)
15
+ * is the single authority for how strips lay out. Every joiner participates
16
+ * in the same protocol; "look up the previous segment's bg" is no longer a
17
+ * powerline-specific hack but the contract every joiner shares.
18
+ *
19
+ * [LAW:locality-or-seam] The joiner protocol asks each item only for its
20
+ * *edge* style — the column adjacent to the joiner — not for a single
21
+ * whole-item style. This pushes the bg-uniformity requirement out of the
22
+ * cell type and into the narrowest place that actually needs it: the column
23
+ * boundary. Items with uniform styling report the same style at both edges;
24
+ * items with varying styling report the actual boundary column. There is no
25
+ * single-style invariant on the cell type — the terminal supports per-column
26
+ * styling, so the cell type does too.
27
+ */
28
+ import { Segment } from "./segment.js";
29
+ import { Style } from "./style.js";
30
+ import { type Renderable, type RenderOptions } from "./protocol.js";
31
+ /**
32
+ * Items in a `Strip` expose their per-edge style so joiners can paint the
33
+ * transition glyph at each boundary.
34
+ *
35
+ * `edgeStyle("left", options)` reports the style of the item's leftmost cell
36
+ * column; `edgeStyle("right", options)` reports the rightmost. Joiners read
37
+ * only these — the item's interior may carry any per-column variation without
38
+ * breaking the join.
39
+ *
40
+ * The edge is asked in a render, with that render's options, because a style
41
+ * name only becomes a colour against the render's theme. A joiner therefore
42
+ * reads edges inside the `render` of what it returns, never in `join`.
43
+ */
44
+ export interface StyledRenderable extends Renderable {
45
+ edgeStyle(side: "left" | "right", options: RenderOptions): Style;
46
+ }
47
+ export interface Joiner<T extends StyledRenderable = StyledRenderable> {
48
+ /**
49
+ * `left === null` marks the start endpoint; `right === null` marks the end
50
+ * endpoint. The joiner decides what an endpoint looks like — typically
51
+ * fg-only with no bg so the strip blends into the terminal background.
52
+ */
53
+ join(left: T | null, right: T | null): Renderable;
54
+ }
55
+ export declare class Strip<T extends StyledRenderable = StyledRenderable> implements Renderable {
56
+ readonly items: readonly T[];
57
+ readonly joiner: Joiner<T>;
58
+ constructor(items: readonly T[], joiner: Joiner<T>);
59
+ render(options: RenderOptions): Iterable<Segment>;
60
+ }
61
+ /**
62
+ * The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
63
+ * arrow between them to be seen. Below it the arrow is drawn in a colour the
64
+ * eye cannot tell from its own background, so the joiner draws the divider
65
+ * instead. Twice the ~.02 threshold of a visible difference, because a seam is
66
+ * one cell wide.
67
+ */
68
+ export declare const SEAM_MIN_DELTA_E = 0.04;
69
+ export interface PowerlineJoinerOptions {
70
+ /** Glyph for every join between two coloured items. */
71
+ glyph: string;
72
+ /**
73
+ * Glyph drawn between neighbours whose backgrounds the eye cannot tell apart,
74
+ * in the left item's text colour — the arrow itself would vanish into the
75
+ * shared background.
76
+ */
77
+ divider: string;
78
+ /**
79
+ * Glyph for every join a coloured item is entered from nothing — the strip's
80
+ * start, or a colourless left neighbour — painted in the right item's
81
+ * background. `""` begins a coloured run flat.
82
+ */
83
+ lead: string;
84
+ /**
85
+ * Glyph for every join a coloured item leaves into nothing — the strip's end,
86
+ * or a colourless right neighbour — painted in the left item's background.
87
+ * `""` ends a coloured run flat.
88
+ */
89
+ tail: string;
90
+ }
91
+ /**
92
+ * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
93
+ * led by U+E0D7 (Nerd Fonts ple-left_hard_divider_inverse, the right-arrow's
94
+ * inverse) and tailed by the arrow itself. The lead leaves empty a triangle
95
+ * whose base is its cell's left edge and whose point touches the first item, so
96
+ * the run opens notched — as if an arrow before it pointed in — rather than
97
+ * with a shape pointing out. The notch is the terminal's own background showing
98
+ * through, never a colour painted to imitate it, so it matches under a
99
+ * translucent terminal background too. The lead is a Powerline Extra glyph: a
100
+ * classic powerline font lacks it.
101
+ */
102
+ export declare const POWERLINE_JOINER_GLYPHS: Readonly<PowerlineJoinerOptions>;
103
+ export declare class PowerlineJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
104
+ private readonly _glyphs;
105
+ constructor(options?: PowerlineJoinerOptions);
106
+ join(left: T | null, right: T | null): Renderable;
107
+ }
108
+ export interface CapsuleJoinerOptions {
109
+ /** Left-cap glyph (default: U+E0B6, powerline rounded left). */
110
+ left?: string;
111
+ /** Right-cap glyph (default: U+E0B4, powerline rounded right). */
112
+ right?: string;
113
+ /** Separator inserted between adjacent capsules in the middle position. */
114
+ separator?: string;
115
+ }
116
+ export declare class CapsuleJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
117
+ private readonly _caps;
118
+ private readonly _separator;
119
+ constructor(options?: CapsuleJoinerOptions);
120
+ _emit(left: T | null, right: T | null, options: RenderOptions): Iterable<Segment>;
121
+ join(left: T | null, right: T | null): Renderable;
122
+ }
123
+ export interface PlainJoinerOptions {
124
+ separator?: string;
125
+ style?: Style;
126
+ }
127
+ export declare class PlainJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
128
+ private readonly _separator;
129
+ private readonly _style;
130
+ constructor(options?: PlainJoinerOptions);
131
+ join(left: T | null, right: T | null): Renderable;
132
+ }
133
+ export interface GradientJoinerOptions {
134
+ /** Number of cells between adjacent items (default: 4). */
135
+ steps?: number;
136
+ }
137
+ export declare class GradientJoiner<T extends StyledRenderable = StyledRenderable> implements Joiner<T> {
138
+ private readonly _steps;
139
+ constructor(options?: GradientJoinerOptions);
140
+ join(left: T | null, right: T | null): Renderable;
141
+ }
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Strip + Joiner — edge-aware horizontal layout primitive.
3
+ *
4
+ * A `Strip` renders a horizontal sequence of styled items with a `Joiner`
5
+ * deciding how each transition between adjacent items looks. The joiner is
6
+ * a pure function of `(leftItem | null, rightItem | null) -> Renderable`,
7
+ * so endpoint joins (the start and end of the strip) are explicit positions
8
+ * in the protocol — the joiner names what an endpoint looks like rather than
9
+ * the strip guessing.
10
+ *
11
+ * [LAW:one-source-of-truth] The render walk
12
+ * joiner(null, items[0]), items[0],
13
+ * joiner(items[0], items[1]), items[1], ...,
14
+ * joiner(items[N-1], null)
15
+ * is the single authority for how strips lay out. Every joiner participates
16
+ * in the same protocol; "look up the previous segment's bg" is no longer a
17
+ * powerline-specific hack but the contract every joiner shares.
18
+ *
19
+ * [LAW:locality-or-seam] The joiner protocol asks each item only for its
20
+ * *edge* style — the column adjacent to the joiner — not for a single
21
+ * whole-item style. This pushes the bg-uniformity requirement out of the
22
+ * cell type and into the narrowest place that actually needs it: the column
23
+ * boundary. Items with uniform styling report the same style at both edges;
24
+ * items with varying styling report the actual boundary column. There is no
25
+ * single-style invariant on the cell type — the terminal supports per-column
26
+ * styling, so the cell type does too.
27
+ */
28
+ import { Segment } from "./segment.js";
29
+ import { Style } from "./style.js";
30
+ import { ColorDepth, ColorSpec, blendRgb } from "./color.js";
31
+ import { Oklch } from "./oklch.js";
32
+ import { drawable } from "./protocol.js";
33
+ // --- Strip ---
34
+ export class Strip {
35
+ items;
36
+ joiner;
37
+ constructor(items, joiner) {
38
+ this.items = items;
39
+ this.joiner = joiner;
40
+ }
41
+ *render(options) {
42
+ const items = this.items;
43
+ if (items.length === 0)
44
+ return;
45
+ // [LAW:dataflow-not-control-flow] The walk is the same shape every render:
46
+ // start-cap, item, mid-join, item, ..., item, end-cap. Variability lives
47
+ // in `items` and in what the joiner emits at each position — never in
48
+ // whether a join runs.
49
+ yield* this.joiner.join(null, items[0]).render(options);
50
+ for (let i = 0; i < items.length; i++) {
51
+ const item = items[i];
52
+ yield* item.render(options);
53
+ const next = i + 1 < items.length ? items[i + 1] : null;
54
+ yield* this.joiner.join(item, next).render(options);
55
+ }
56
+ // [LAW:one-source-of-truth] `Strip`'s sibling `FlexStrip` ends every line
57
+ // it emits, including the last, and the other block-level renderables
58
+ // (`Panel`/`Rule`/`Table` structurally, `RichText` via `end`) do too — so
59
+ // `Group` can emit children back to back with nothing in between
60
+ // (docs/group.md). A `Strip` that left its last line open broke only
61
+ // under composition: printed alone, Console's own "close whatever the
62
+ // renderable left open" step (console.ts) papered over it, and a `Group`
63
+ // of a Strip and a RichText ran the RichText onto the Strip's line
64
+ // instead of below it. (Not every renderable follows this — a `Spinner`
65
+ // or `ProgressBar` is a line *fragment*, not a block; see
66
+ // rich-flexstrip-5kf.4cq for the open question of formalizing that split.)
67
+ yield Segment.line();
68
+ }
69
+ }
70
+ // --- Helpers ---
71
+ const EMPTY = {
72
+ *render(_options) {
73
+ // intentionally empty
74
+ },
75
+ };
76
+ /** A renderable whose segments are computed from the options it is rendered with. */
77
+ function deferred(emit) {
78
+ return { render: emit };
79
+ }
80
+ // Endpoint and powerline join glyphs paint the adjacent item's edge bg
81
+ // *as* their fg. If the edge has no bgcolor, the glyph degrades to the
82
+ // default fg — which renders as nothing visible against the terminal
83
+ // background, the right outcome for an unstyled edge.
84
+ function bgAsFg(edge) {
85
+ return new Style({ color: edge.bgcolor });
86
+ }
87
+ // A bg with a real colour to paint. `undefined` (no bg) and the terminal
88
+ // DEFAULT colour (transparent — identical to the terminal background) are the
89
+ // two representations of "nothing to paint"; the powerline separator treats
90
+ // them the same, so the gate cannot be fooled by an explicit `… on default`.
91
+ function paintableBg(bg) {
92
+ return bg !== undefined && !bg.isDefault ? bg : undefined;
93
+ }
94
+ // A cap or arrow is its cell continuing: that cell's ground as the writer draws
95
+ // it, so a translucent ground is not composited a second time over whatever it
96
+ // enters.
97
+ function drawnGround(bg) {
98
+ return new Style({ bgcolor: bg }).drawnColors().bgcolor;
99
+ }
100
+ // A cap is its glyph in its cell's ground, and "" is a flat end: no glyph, so
101
+ // no segment — the same output as a join with nothing to paint.
102
+ function* cap(glyph, bg) {
103
+ if (glyph !== "")
104
+ yield new Segment(glyph, new Style({ color: drawnGround(bg) }));
105
+ }
106
+ // --- PowerlineJoiner ---
107
+ /**
108
+ * The least ΔE_OK two neighbouring backgrounds must differ by for the powerline
109
+ * arrow between them to be seen. Below it the arrow is drawn in a colour the
110
+ * eye cannot tell from its own background, so the joiner draws the divider
111
+ * instead. Twice the ~.02 threshold of a visible difference, because a seam is
112
+ * one cell wide.
113
+ */
114
+ export const SEAM_MIN_DELTA_E = 0.04;
115
+ // An arrow the eye cannot tell from the ground it is drawn on. What is
116
+ // measured is what is drawn — `Style.drawnColors`, the colours the writer
117
+ // encodes: the arrow's colour flattened onto its ground and the ground onto
118
+ // the terminal's black, both downgraded to the depth the render encodes at,
119
+ // so two grounds 256 colours round to one cube entry are the one entry they
120
+ // render as. A colour whose RGB is the terminal theme's own (ANSI 0–15) has no
121
+ // value here, so two of them are the same only when they are the same palette
122
+ // slot — its `number`, never the name or the depth that spells it ("red",
123
+ // "color(1)", an EIGHT_BIT spec on 0–15 are one slot).
124
+ function vanishes(arrow, colorSystem) {
125
+ // No colour emitted draws nothing to tell apart; measure what was handed.
126
+ const { color, bgcolor } = arrow.drawnColors(colorSystem ?? ColorDepth.TRUECOLOR);
127
+ if (color === undefined || bgcolor === undefined)
128
+ return false;
129
+ const av = color.fixedValue;
130
+ const bv = bgcolor.fixedValue;
131
+ return av !== undefined && bv !== undefined
132
+ ? Oklch.fromRgba(av).deltaE(Oklch.fromRgba(bv)) < SEAM_MIN_DELTA_E
133
+ : color.number === bgcolor.number;
134
+ }
135
+ /**
136
+ * The powerline set: U+E0B0 (right-arrow) divided by U+E0B1 (thin right-arrow),
137
+ * led by U+E0D7 (Nerd Fonts ple-left_hard_divider_inverse, the right-arrow's
138
+ * inverse) and tailed by the arrow itself. The lead leaves empty a triangle
139
+ * whose base is its cell's left edge and whose point touches the first item, so
140
+ * the run opens notched — as if an arrow before it pointed in — rather than
141
+ * with a shape pointing out. The notch is the terminal's own background showing
142
+ * through, never a colour painted to imitate it, so it matches under a
143
+ * translucent terminal background too. The lead is a Powerline Extra glyph: a
144
+ * classic powerline font lacks it.
145
+ */
146
+ export const POWERLINE_JOINER_GLYPHS = Object.freeze({
147
+ glyph: "\ue0b0",
148
+ divider: "\ue0b1",
149
+ lead: "\ue0d7",
150
+ tail: "\ue0b0",
151
+ });
152
+ /** The powerline set in ASCII: an arrow for every join, runs begun flat. */
153
+ const ASCII_POWERLINE_GLYPHS = Object.freeze({
154
+ glyph: ">",
155
+ divider: ">",
156
+ lead: "",
157
+ tail: ">",
158
+ });
159
+ const powerlineGlyphs = ({ glyph, divider, lead, tail }) => glyph + divider + lead + tail;
160
+ export class PowerlineJoiner {
161
+ _glyphs;
162
+ constructor(options = POWERLINE_JOINER_GLYPHS) {
163
+ this._glyphs = options;
164
+ }
165
+ join(left, right) {
166
+ // [LAW:dataflow-not-control-flow] One table for all three positions (start
167
+ // cap, mid-join, end cap), read off which side has a colour to paint. The
168
+ // endpoints are not control-flow special cases; they are the DATA cases
169
+ // where a neighbour (hence its bg) is absent:
170
+ // • both bgs — the arrow in the LEFT bg (the colour bleeding rightward)
171
+ // over the RIGHT bg.
172
+ // • left bg only — the end cap, OR a coloured item before a colourless
173
+ // one — the tail bleeds the left colour out over the terminal
174
+ // background (fg = left bg, no bg).
175
+ // • right bg only — the start cap, OR a colourless item before a coloured
176
+ // one — the lead: the right colour painted over the terminal
177
+ // background in the lead's shape (fg = right bg, no bg).
178
+ // • neither — nothing to paint, so the join yields nothing.
179
+ // Equal REAL bgs still emit: a same-bg seam between two distinct items is a
180
+ // structural boundary, never suppressed. The arrow would be drawn in its own
181
+ // background colour there and vanish, so the seam is the DIVIDER instead, in
182
+ // the left item's text colour — the vim-airline convention for neighbours
183
+ // that share a background. "Equal" is perceptual (SEAM_MIN_DELTA_E) and
184
+ // measured on the colours the terminal draws at `options.colorSystem`: an
185
+ // arrow a hair off its background is as invisible as one exactly on it,
186
+ // and two backgrounds 256 colours round to one entry are one background.
187
+ // Background colour is paint, not structure; its ABSENCE (nothing to paint)
188
+ // is the only thing that elides the separator, and that is paint logic.
189
+ // "Absent" = no bg OR the terminal default (transparent) — paintableBg folds
190
+ // both to undefined so an explicit `… on default` cannot smuggle a separator.
191
+ const glyphs = this._glyphs;
192
+ return deferred(function* (options) {
193
+ const { glyph, divider, lead, tail } = drawable(options, glyphs, ASCII_POWERLINE_GLYPHS, powerlineGlyphs);
194
+ const leftEdge = left?.edgeStyle("right", options);
195
+ const leftBg = paintableBg(leftEdge?.bgcolor);
196
+ const rightBg = paintableBg(right?.edgeStyle("left", options).bgcolor);
197
+ if (leftBg === undefined) {
198
+ if (rightBg !== undefined)
199
+ yield* cap(lead, rightBg);
200
+ return;
201
+ }
202
+ if (rightBg === undefined) {
203
+ yield* cap(tail, leftBg);
204
+ return;
205
+ }
206
+ const arrow = new Style({ color: drawnGround(leftBg), bgcolor: rightBg });
207
+ // The divider is the left item's text on the left item's own ground,
208
+ // so it reads exactly as well as that item's text does, at any depth.
209
+ yield vanishes(arrow, options.colorSystem)
210
+ ? new Segment(divider, new Style({ color: leftEdge?.color, bgcolor: leftBg }))
211
+ : new Segment(glyph, arrow);
212
+ });
213
+ }
214
+ }
215
+ const ASCII_CAPS = { left: "(", right: ")" };
216
+ const capGlyphs = ({ left, right }) => left + right;
217
+ export class CapsuleJoiner {
218
+ _caps;
219
+ _separator;
220
+ constructor(options) {
221
+ this._caps = { left: options?.left ?? "", right: options?.right ?? "" };
222
+ this._separator = options?.separator ?? " ";
223
+ }
224
+ *_emit(left, right, options) {
225
+ const caps = drawable(options, this._caps, ASCII_CAPS, capGlyphs);
226
+ const separator = drawable(options, this._separator, " ");
227
+ if (left === null && right === null)
228
+ return;
229
+ if (left === null) {
230
+ yield new Segment(caps.left, bgAsFg(right.edgeStyle("left", options)));
231
+ return;
232
+ }
233
+ if (right === null) {
234
+ yield new Segment(caps.right, bgAsFg(left.edgeStyle("right", options)));
235
+ return;
236
+ }
237
+ // Middle: close the left capsule, separator (unstyled), open the right.
238
+ yield new Segment(caps.right, bgAsFg(left.edgeStyle("right", options)));
239
+ if (separator.length > 0)
240
+ yield new Segment(separator);
241
+ yield new Segment(caps.left, bgAsFg(right.edgeStyle("left", options)));
242
+ }
243
+ join(left, right) {
244
+ return deferred((options) => this._emit(left, right, options));
245
+ }
246
+ }
247
+ export class PlainJoiner {
248
+ _separator;
249
+ _style;
250
+ constructor(options) {
251
+ this._separator = options?.separator ?? " | ";
252
+ this._style = options?.style ?? Style.parse("dim");
253
+ }
254
+ join(left, right) {
255
+ // Endpoints are empty — a fixed separator has no natural cap.
256
+ if (left === null || right === null)
257
+ return EMPTY;
258
+ const separator = this._separator;
259
+ const style = this._style;
260
+ return deferred((options) => [new Segment(drawable(options, separator, " | "), style)]);
261
+ }
262
+ }
263
+ /**
264
+ * Half-block dithering glyph: paints the cell's left half with the foreground
265
+ * colour and the right half with the background colour. Lets each cell carry
266
+ * two colour samples — `2 * steps` samples in `steps` cells — so the gradient
267
+ * looks twice as smooth as one-colour-per-cell at the same width.
268
+ */
269
+ const HALF_BLOCK = "▌"; // ▌
270
+ export class GradientJoiner {
271
+ _steps;
272
+ constructor(options) {
273
+ this._steps = options?.steps ?? 4;
274
+ }
275
+ join(left, right) {
276
+ // [LAW:dataflow-not-control-flow] Endpoints have no opposite anchor to
277
+ // interpolate toward — the data (a missing neighbor) makes the gradient
278
+ // empty. Same for edges lacking a bgcolor: nothing to blend between.
279
+ if (left === null || right === null)
280
+ return EMPTY;
281
+ const steps = this._steps;
282
+ return deferred(function* (options) {
283
+ const lbg = left.edgeStyle("right", options).bgcolor;
284
+ const rbg = right.edgeStyle("left", options).bgcolor;
285
+ if (!lbg || !rbg)
286
+ return;
287
+ const lTrip = lbg.getTruecolor();
288
+ const rTrip = rbg.getTruecolor();
289
+ // An ASCII cell carries one sample, the background: the gradient keeps
290
+ // its colours at half the resolution.
291
+ const half = drawable(options, HALF_BLOCK, " ");
292
+ const samples = 2 * steps;
293
+ // Midpoint sampling across `2 * steps` half-cell positions: sample j has
294
+ // t = (j + 0.5) / samples. Cell i takes samples 2i (left half) and 2i+1
295
+ // (right half). No sample ever equals either anchor.
296
+ for (let i = 0; i < steps; i++) {
297
+ const tLeft = (2 * i + 0.5) / samples;
298
+ const tRight = (2 * i + 1.5) / samples;
299
+ const fg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tLeft));
300
+ const bg = ColorSpec.fromRgba(blendRgb(lTrip, rTrip, tRight));
301
+ yield new Segment(half, new Style({ color: fg, bgcolor: bg }));
302
+ }
303
+ });
304
+ }
305
+ }