@zaly/tui 0.0.11 → 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.
Files changed (260) hide show
  1. package/assets/schemas/shiki-language.schema.json +352 -0
  2. package/assets/schemas/shiki-theme.schema.json +71 -0
  3. package/assets/schemas/theme.schema.json +227 -732
  4. package/assets/themes/andromeeda.json +97 -0
  5. package/assets/themes/ayu-dark.json +31 -44
  6. package/assets/themes/ayu-light.json +106 -0
  7. package/assets/themes/ayu-mirage.json +106 -0
  8. package/assets/themes/catppuccin-frappe.json +44 -60
  9. package/assets/themes/catppuccin-latte.json +44 -60
  10. package/assets/themes/catppuccin-macchiato.json +44 -60
  11. package/assets/themes/catppuccin-mocha.json +44 -60
  12. package/assets/themes/dark-plus.json +99 -0
  13. package/assets/themes/dracula.json +47 -66
  14. package/assets/themes/everforest-dark.json +28 -45
  15. package/assets/themes/everforest-light.json +28 -45
  16. package/assets/themes/github-dark-default.json +107 -0
  17. package/assets/themes/github-dark-dimmed.json +107 -0
  18. package/assets/themes/github-light-default.json +107 -0
  19. package/assets/themes/gruvbox-dark-hard.json +98 -0
  20. package/assets/themes/gruvbox-dark-medium.json +34 -48
  21. package/assets/themes/gruvbox-light-medium.json +98 -0
  22. package/assets/themes/horizon-bright.json +101 -0
  23. package/assets/themes/horizon.json +101 -0
  24. package/assets/themes/iterm2/LICENSE +25 -0
  25. package/assets/themes/iterm2/README.md +28 -0
  26. package/assets/themes/iterm2/catppuccin-latte.json +140 -0
  27. package/assets/themes/iterm2/catppuccin-mocha.json +140 -0
  28. package/assets/themes/iterm2/github-dark.json +140 -0
  29. package/assets/themes/iterm2/github.json +140 -0
  30. package/assets/themes/iterm2/gruvbox-dark.json +140 -0
  31. package/assets/themes/iterm2/gruvbox-light.json +140 -0
  32. package/assets/themes/iterm2/nord.json +140 -0
  33. package/assets/themes/iterm2/tokyonight-day.json +140 -0
  34. package/assets/themes/iterm2/tokyonight-moon.json +140 -0
  35. package/assets/themes/kanagawa-dragon.json +55 -68
  36. package/assets/themes/kanagawa-lotus.json +105 -0
  37. package/assets/themes/kanagawa-wave.json +55 -68
  38. package/assets/themes/light-plus.json +99 -0
  39. package/assets/themes/material-theme-lighter.json +102 -0
  40. package/assets/themes/material-theme-palenight.json +52 -64
  41. package/assets/themes/material-theme.json +102 -0
  42. package/assets/themes/min-dark.json +67 -28
  43. package/assets/themes/min-light.json +67 -32
  44. package/assets/themes/monokai.json +55 -67
  45. package/assets/themes/night-owl-light.json +105 -0
  46. package/assets/themes/night-owl.json +57 -68
  47. package/assets/themes/nord.json +53 -55
  48. package/assets/themes/one-dark-pro.json +46 -57
  49. package/assets/themes/one-light.json +52 -59
  50. package/assets/themes/poimandres.json +51 -68
  51. package/assets/themes/rose-pine-dawn.json +99 -0
  52. package/assets/themes/rose-pine-moon.json +99 -0
  53. package/assets/themes/rose-pine.json +51 -50
  54. package/assets/themes/solarized-dark.json +39 -51
  55. package/assets/themes/solarized-light.json +40 -52
  56. package/assets/themes/synthwave-84.json +48 -50
  57. package/assets/themes/tokyonight-day.json +6 -7
  58. package/assets/themes/tokyonight-moon.json +6 -6
  59. package/assets/themes/tokyonight-night.json +6 -6
  60. package/assets/themes/tokyonight-storm.json +6 -6
  61. package/assets/themes/vesper.json +51 -58
  62. package/assets/themes/vitesse-black.json +103 -0
  63. package/assets/themes/vitesse-dark.json +26 -49
  64. package/assets/themes/vitesse-light.json +26 -49
  65. package/dist/{actions-DFboj3g5.d.mts → actions--ODlgCQ5.d.mts} +4 -4
  66. package/dist/{actions-DFboj3g5.d.mts.map → actions--ODlgCQ5.d.mts.map} +1 -1
  67. package/dist/{ansi-Clq0ozyA.mjs → ansi-CMv71xVr.mjs} +38 -31
  68. package/dist/ansi-CMv71xVr.mjs.map +1 -0
  69. package/dist/ansi.d.mts +3 -1
  70. package/dist/ansi.d.mts.map +1 -1
  71. package/dist/ansi.mjs +1 -1
  72. package/dist/{autocomplete-CxzetPOo.d.mts → autocomplete-CD30kSe_.d.mts} +4 -4
  73. package/dist/{autocomplete-CxzetPOo.d.mts.map → autocomplete-CD30kSe_.d.mts.map} +1 -1
  74. package/dist/{box-DLEcEvDH.mjs → box-C_N_7ChP.mjs} +2 -2
  75. package/dist/box-C_N_7ChP.mjs.map +1 -0
  76. package/dist/builder-Chwtk0nQ.mjs +196 -0
  77. package/dist/builder-Chwtk0nQ.mjs.map +1 -0
  78. package/dist/{callbacks-D132G8dy.mjs → callbacks-DLecWn7G.mjs} +4 -4
  79. package/dist/{callbacks-D132G8dy.mjs.map → callbacks-DLecWn7G.mjs.map} +1 -1
  80. package/dist/client-CNGt-dOt.mjs +1 -0
  81. package/dist/{client-C2GXKfJ1.mjs → client-D7qz4TZt.mjs} +7 -3
  82. package/dist/client-D7qz4TZt.mjs.map +1 -0
  83. package/dist/color-DBMQLv4Y.mjs +37 -0
  84. package/dist/color-DBMQLv4Y.mjs.map +1 -0
  85. package/dist/{ctx-8Nuf5BrN.mjs → ctx-BaQ2hP5u.mjs} +3 -3
  86. package/dist/{ctx-8Nuf5BrN.mjs.map → ctx-BaQ2hP5u.mjs.map} +1 -1
  87. package/dist/ctx-CndlTp1T.mjs +1 -0
  88. package/dist/{divider-l0-JPEIm.mjs → divider-BlNNN2OS.mjs} +2 -2
  89. package/dist/divider-BlNNN2OS.mjs.map +1 -0
  90. package/dist/{files-BUsa-RVl.d.mts → files-B_5HDBPp.d.mts} +3 -3
  91. package/dist/{files-BUsa-RVl.d.mts.map → files-B_5HDBPp.d.mts.map} +1 -1
  92. package/dist/github-Cy2hfWJ7.mjs.map +1 -1
  93. package/dist/{github-D89A3F9U.d.mts → github-CyRwUQ3y.d.mts} +3 -3
  94. package/dist/{github-D89A3F9U.d.mts.map → github-CyRwUQ3y.d.mts.map} +1 -1
  95. package/dist/{image-34bU73bW.d.mts → image-BLls2F4t.d.mts} +2 -2
  96. package/dist/{image-34bU73bW.d.mts.map → image-BLls2F4t.d.mts.map} +1 -1
  97. package/dist/image-Cqtj3yRA.mjs +178 -0
  98. package/dist/image-Cqtj3yRA.mjs.map +1 -0
  99. package/dist/image.d.mts +1 -1
  100. package/dist/index.d.mts +13 -4
  101. package/dist/index.d.mts.map +1 -1
  102. package/dist/index.mjs +8 -7
  103. package/dist/index.mjs.map +1 -1
  104. package/dist/{input-D7fQEUdt.mjs → input-ET2YEMcl.mjs} +16 -11
  105. package/dist/input-ET2YEMcl.mjs.map +1 -0
  106. package/dist/{input-Dylds_sI.d.mts → input-NuD8TH8N.d.mts} +3 -3
  107. package/dist/{input-Dylds_sI.d.mts.map → input-NuD8TH8N.d.mts.map} +1 -1
  108. package/dist/{inspect-DPLRum7L.d.mts → inspect-B1uXxdKC.d.mts} +11 -15
  109. package/dist/inspect-B1uXxdKC.d.mts.map +1 -0
  110. package/dist/{inspect-CcgiZ_F9.mjs → inspect-Cxzs-W0g.mjs} +2 -2
  111. package/dist/{inspect-CcgiZ_F9.mjs.map → inspect-Cxzs-W0g.mjs.map} +1 -1
  112. package/dist/kitty-DKQYsQfH.mjs +1 -0
  113. package/dist/{log-Dy_QnPZF.mjs → log-B4djzy2m.mjs} +5 -5
  114. package/dist/log-B4djzy2m.mjs.map +1 -0
  115. package/dist/{logger-DvuX9DPS.mjs → logger-CvJCITzP.mjs} +3 -3
  116. package/dist/{logger-DvuX9DPS.mjs.map → logger-CvJCITzP.mjs.map} +1 -1
  117. package/dist/{markdown-BGPa7UzD.mjs → markdown-D3ZtRn6C.mjs} +9 -8
  118. package/dist/markdown-D3ZtRn6C.mjs.map +1 -0
  119. package/dist/markdown.d.mts +1 -1
  120. package/dist/markdown.d.mts.map +1 -1
  121. package/dist/markdown.mjs +1 -1
  122. package/dist/math-CU0wmC9N.mjs +1 -0
  123. package/dist/math-Dd7a1irv.mjs +206 -0
  124. package/dist/math-Dd7a1irv.mjs.map +1 -0
  125. package/dist/oklch-Bsh5swbC.mjs +99 -0
  126. package/dist/oklch-Bsh5swbC.mjs.map +1 -0
  127. package/dist/{overlay-9WXYiGgW.mjs → overlay-LvOjG7kn.mjs} +2 -2
  128. package/dist/{overlay-9WXYiGgW.mjs.map → overlay-LvOjG7kn.mjs.map} +1 -1
  129. package/dist/{picker-JL8lZfRH.d.mts → picker-B-OxKKnD.d.mts} +5 -5
  130. package/dist/{picker-JL8lZfRH.d.mts.map → picker-B-OxKKnD.d.mts.map} +1 -1
  131. package/dist/{picker-BqHINl_a.mjs → picker-f6xjgACX.mjs} +2 -2
  132. package/dist/{picker-BqHINl_a.mjs.map → picker-f6xjgACX.mjs.map} +1 -1
  133. package/dist/{queries-B_lOwEiE.mjs → queries-BUkBxkuM.mjs} +66 -3
  134. package/dist/queries-BUkBxkuM.mjs.map +1 -0
  135. package/dist/{queries-Cvalgu6P.d.mts → queries-C75-wG1B.d.mts} +42 -11
  136. package/dist/queries-C75-wG1B.d.mts.map +1 -0
  137. package/dist/{registry-3hLzS4ks.mjs → registry-DUWpSPoo.mjs} +208 -68
  138. package/dist/registry-DUWpSPoo.mjs.map +1 -0
  139. package/dist/{render-f7M2856V.mjs → render-B7LfNM5K.mjs} +2 -2
  140. package/dist/{render-f7M2856V.mjs.map → render-B7LfNM5K.mjs.map} +1 -1
  141. package/dist/{renderer-V6AGjbyf.mjs → renderer-BLsd-wrG.mjs} +167 -20
  142. package/dist/renderer-BLsd-wrG.mjs.map +1 -0
  143. package/dist/renderer-YHbR7JZ4.mjs +1 -0
  144. package/dist/{renderer-DesbRwjQ.mjs → renderer-aAtkFgll.mjs} +8 -7
  145. package/dist/renderer-aAtkFgll.mjs.map +1 -0
  146. package/dist/{select-zGd5pbiB.d.mts → select-BKE5LzdN.d.mts} +3 -3
  147. package/dist/{select-zGd5pbiB.d.mts.map → select-BKE5LzdN.d.mts.map} +1 -1
  148. package/dist/services/logger.d.mts +1 -1
  149. package/dist/services/logger.mjs +1 -1
  150. package/dist/services/notifier.d.mts +1 -1
  151. package/dist/services/notifier.mjs +2 -2
  152. package/dist/services/picker.d.mts +5 -5
  153. package/dist/services/picker.mjs +6 -6
  154. package/dist/services/prompt.d.mts +4 -4
  155. package/dist/services/prompt.mjs +5 -5
  156. package/dist/shiki/server.mjs +37 -14
  157. package/dist/shiki/server.mjs.map +1 -1
  158. package/dist/shiki-B4U0s8jT.mjs +635 -0
  159. package/dist/shiki-B4U0s8jT.mjs.map +1 -0
  160. package/dist/shiki-CJauRusM.mjs +20 -0
  161. package/dist/shiki-CJauRusM.mjs.map +1 -0
  162. package/dist/style-DslRHzI4.mjs +109 -0
  163. package/dist/style-DslRHzI4.mjs.map +1 -0
  164. package/dist/style.d.mts +4 -3
  165. package/dist/style.d.mts.map +1 -1
  166. package/dist/style.mjs +4 -4
  167. package/dist/{text-CRZD9KTN.mjs → text-BoJdKXLU.mjs} +2 -2
  168. package/dist/{text-CRZD9KTN.mjs.map → text-BoJdKXLU.mjs.map} +1 -1
  169. package/dist/{text-BefiXAFW.d.mts → text-CmxbA8lk.d.mts} +3 -3
  170. package/dist/{text-BefiXAFW.d.mts.map → text-CmxbA8lk.d.mts.map} +1 -1
  171. package/dist/{text-BLz1tRoC.mjs → text-DPrhma4x.mjs} +2 -2
  172. package/dist/text-DPrhma4x.mjs.map +1 -0
  173. package/dist/text.d.mts +1 -1
  174. package/dist/text.mjs +1 -1
  175. package/dist/theme-C8LkcoaK.mjs +61 -0
  176. package/dist/theme-C8LkcoaK.mjs.map +1 -0
  177. package/dist/theme-DVX8dvGG.mjs +1794 -0
  178. package/dist/theme-DVX8dvGG.mjs.map +1 -0
  179. package/dist/themes.d.mts +213 -73
  180. package/dist/themes.d.mts.map +1 -1
  181. package/dist/themes.mjs +1 -1
  182. package/dist/{tree-CArtDRec.d.mts → tree-CTvSpF9b.d.mts} +3 -3
  183. package/dist/{tree-CArtDRec.d.mts.map → tree-CTvSpF9b.d.mts.map} +1 -1
  184. package/dist/{types-C0EOLZDc.d.mts → types-C9ceMsbJ.d.mts} +137 -137
  185. package/dist/types-C9ceMsbJ.d.mts.map +1 -0
  186. package/dist/{widget-DtJU2-BJ.d.mts → widget-DlF32PRp.d.mts} +2 -2
  187. package/dist/{widget-DtJU2-BJ.d.mts.map → widget-DlF32PRp.d.mts.map} +1 -1
  188. package/dist/widgets/autocomplete.d.mts +1 -1
  189. package/dist/widgets/autocomplete.mjs +2 -2
  190. package/dist/widgets/box.d.mts +1 -1
  191. package/dist/widgets/box.mjs +1 -1
  192. package/dist/widgets/code.d.mts +4 -2
  193. package/dist/widgets/code.d.mts.map +1 -1
  194. package/dist/widgets/code.mjs +8 -7
  195. package/dist/widgets/code.mjs.map +1 -1
  196. package/dist/widgets/completions/actions.d.mts +1 -1
  197. package/dist/widgets/completions/files.d.mts +1 -1
  198. package/dist/widgets/completions/github.d.mts +1 -1
  199. package/dist/widgets/completions/index.d.mts +3 -3
  200. package/dist/widgets/diff.d.mts +2 -2
  201. package/dist/widgets/diff.d.mts.map +1 -1
  202. package/dist/widgets/diff.mjs +35 -12
  203. package/dist/widgets/diff.mjs.map +1 -1
  204. package/dist/widgets/divider.d.mts +3 -3
  205. package/dist/widgets/divider.mjs +1 -1
  206. package/dist/widgets/image.d.mts +1 -1
  207. package/dist/widgets/image.mjs +4 -4
  208. package/dist/widgets/image.mjs.map +1 -1
  209. package/dist/widgets/input.d.mts +1 -1
  210. package/dist/widgets/input.mjs +1 -1
  211. package/dist/widgets/log.d.mts +1 -1
  212. package/dist/widgets/log.mjs +1 -1
  213. package/dist/widgets/markdown.d.mts +4 -4
  214. package/dist/widgets/markdown.d.mts.map +1 -1
  215. package/dist/widgets/markdown.mjs +1 -1
  216. package/dist/widgets/overlay.d.mts +1 -1
  217. package/dist/widgets/overlay.mjs +1 -1
  218. package/dist/widgets/picker.d.mts +1 -1
  219. package/dist/widgets/picker.mjs +1 -1
  220. package/dist/widgets/progress.d.mts +4 -4
  221. package/dist/widgets/progress.mjs.map +1 -1
  222. package/dist/widgets/select.d.mts +1 -1
  223. package/dist/widgets/show.d.mts +1 -1
  224. package/dist/widgets/spinner.d.mts +2 -2
  225. package/dist/widgets/text.d.mts +1 -1
  226. package/dist/widgets/text.mjs +1 -1
  227. package/dist/widgets/tree.d.mts +1 -1
  228. package/dist/widgets/widget.d.mts +1 -1
  229. package/package.json +5 -7
  230. package/assets/themes/dracula-soft.json +0 -119
  231. package/assets/themes/github-dark.json +0 -123
  232. package/assets/themes/github-light.json +0 -123
  233. package/dist/ansi-Clq0ozyA.mjs.map +0 -1
  234. package/dist/box-DLEcEvDH.mjs.map +0 -1
  235. package/dist/builder-DC9byAmK.mjs +0 -386
  236. package/dist/builder-DC9byAmK.mjs.map +0 -1
  237. package/dist/client-C2GXKfJ1.mjs.map +0 -1
  238. package/dist/client-bzdHIDL2.mjs +0 -1
  239. package/dist/ctx-k0wTqeql.mjs +0 -1
  240. package/dist/divider-l0-JPEIm.mjs.map +0 -1
  241. package/dist/image-Cm5T-uw-.mjs +0 -108
  242. package/dist/image-Cm5T-uw-.mjs.map +0 -1
  243. package/dist/input-D7fQEUdt.mjs.map +0 -1
  244. package/dist/inspect-DPLRum7L.d.mts.map +0 -1
  245. package/dist/log-Dy_QnPZF.mjs.map +0 -1
  246. package/dist/markdown-BGPa7UzD.mjs.map +0 -1
  247. package/dist/queries-B_lOwEiE.mjs.map +0 -1
  248. package/dist/queries-Cvalgu6P.d.mts.map +0 -1
  249. package/dist/registry-3hLzS4ks.mjs.map +0 -1
  250. package/dist/renderer-BSMOuiLM.mjs +0 -1
  251. package/dist/renderer-DesbRwjQ.mjs.map +0 -1
  252. package/dist/renderer-V6AGjbyf.mjs.map +0 -1
  253. package/dist/shiki--ASSYv4_.mjs +0 -12
  254. package/dist/shiki--ASSYv4_.mjs.map +0 -1
  255. package/dist/shiki-D7l5--zz.mjs +0 -432
  256. package/dist/shiki-D7l5--zz.mjs.map +0 -1
  257. package/dist/text-BLz1tRoC.mjs.map +0 -1
  258. package/dist/theme.config-BKXX_noZ.mjs +0 -863
  259. package/dist/theme.config-BKXX_noZ.mjs.map +0 -1
  260. package/dist/types-C0EOLZDc.d.mts.map +0 -1
@@ -1,12 +1,20 @@
1
+ import { Simplify } from "@zaly/shared";
1
2
  import { BundledLanguage, BundledTheme } from "shiki/types";
2
3
  //#region src/shiki/types.d.ts
3
4
  type ShikiTheme = BundledTheme;
4
5
  type ShikiLanguage = BundledLanguage;
6
+ type ShikiSelection = "auto" | ShikiTheme;
7
+ type GeneratedShikiTheme = {
8
+ name: string;
9
+ appearance: "dark" | "light";
10
+ styles: AnsiStyle[];
11
+ };
12
+ type ShikiThemeInput = ShikiTheme | GeneratedShikiTheme;
5
13
  type ShikiRequest = {
6
14
  key?: string;
7
15
  code: string;
8
16
  lang: string;
9
- theme?: ShikiTheme;
17
+ theme?: ShikiThemeInput;
10
18
  signal?: AbortSignal;
11
19
  };
12
20
  type ShikiWorkerRequest = Omit<ShikiRequest, "lang" | "key"> & {
@@ -29,68 +37,16 @@ type ShikiWorkerMessage = {
29
37
  type: "result";
30
38
  });
31
39
  type ShikiOpts = {
32
- theme?: ShikiTheme;
40
+ theme?: ShikiThemeInput;
33
41
  signal?: AbortSignal;
34
42
  };
35
43
  //#endregion
36
- //#region src/style/types.d.ts
37
- type RGB = [r: number, g: number, b: number];
38
- /** Alpha percentage for `/<alpha>` suffix on Color values. Any integer
39
- * 0..100 is accepted at runtime; the template literal uses `${number}`
40
- * so odd values like `/98` typecheck without a cast. */
41
- type ColorLightness = `${number}`;
42
- /** Standard ANSI color names. */
43
- type AnsiColorName = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey";
44
- /** Bright ANSI variants — `brightRed`, `brightBlue`, etc. */
45
- type BrightAnsiColorName = `bright${Capitalize<AnsiColorName>}`;
46
- type AnsiColor = AnsiColorName | BrightAnsiColorName | HexColor | "inherit";
47
- /** Hex color string. Matches `#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa`
48
- * (any case; runtime validates). Alpha is native to the hex form, so
49
- * there is no separate `/<alpha>` suffix for hex. */
50
- type HexColor = `#${string}`;
51
- type ThemeKey = keyof Theme;
52
- /**
53
- * A color value. Accepted forms:
54
- * - `#rgb` / `#rrggbb` hex
55
- * - ANSI color names (`red`, `cyan`, `gray`, …)
56
- * - Bright ANSI variants (`brightRed`, `brightBlue`, …)
57
- * - Theme slot keys from `keyof Theme` (`primary`, `muted`, …)
58
- * - `'inherit'` — use the parent's color (renders as no escape).
59
- * - Variant suffix `-<step>` on hex or theme slots — e.g. `primary-300`,
60
- * `#82aaff-900`. The base color gets resolved through the theme
61
- * (extracting the channel when needed), then `variant(base, step)`
62
- * shifts it along the OKLCH tonal scale.
63
- */
64
- type Color = HexColor | AnsiColorName | BrightAnsiColorName | ThemeKey | "inherit" | `${HexColor | ThemeKey}-${ColorLightness}` | `${HexColor | ThemeKey}+${ColorLightness}`;
65
- interface AnsiStyle {
66
- fg?: AnsiColor;
67
- bg?: AnsiColor;
68
- bold?: boolean;
69
- dim?: boolean;
70
- italic?: boolean;
71
- underline?: boolean;
72
- inverse?: boolean;
73
- strikethrough?: boolean;
74
- }
75
- /** Base style shared by every node type. Box/Text/etc. extend this.
76
- * Pure styling — no layout or lifecycle fields. Widget state interfaces
77
- * extend `StyleState` to pick up the `visible` base-state bits alongside
78
- * these style fields. */
79
- type Style = Omit<AnsiStyle, "fg" | "bg"> & {
80
- fg?: Color;
81
- bg?: Color;
82
- style?: AnyStyle;
83
- };
84
- type AnyStyle = Style | Color;
85
- //#endregion
86
44
  //#region src/themes/types.d.ts
87
- /**
88
- * A theme slot value. Color shortcuts expand to `{ fg: <color> }` at resolve
89
- * time; Style objects are used as-is and may carry attrs (`bold`, `underline`,
90
- * etc.) and a `bg`. Use Color for simple fg-only slots; escalate to Style when
91
- * the part needs more than just a foreground color.
92
- */
93
- type ThemeValue = Color | Style;
45
+ type ThemeStyle<Ansi extends boolean = true> = Simplify<Omit<AnsiStyle, "fg" | "bg"> & {
46
+ fg?: Color<Ansi>;
47
+ bg?: Color<Ansi>;
48
+ }>;
49
+ type ThemeValue<Ansi extends boolean = true> = ThemeStyle<Ansi> | Color<Ansi>;
94
50
  /**
95
51
  * A theme is a flat record mapping semantic slots to `ThemeValue`s. Callers
96
52
  * reference slots by key (`fg: "primary"` for colors, `borderStyle: "border"`
@@ -107,111 +63,155 @@ type ThemeValue = Color | Style;
107
63
  * **Surface tiers**: `ui` → `subtle` → `overlay` (bottom → top).
108
64
  * `highlight` is orthogonal — a tinted accent surface, not a tier.
109
65
  */
110
- type Theme = {
66
+ type Theme<Ansi extends boolean = true, T = ThemeValue<Ansi>> = {
111
67
  id: string;
68
+ /** Dark/light appearance, inferred from bg when omitted in a theme file. */
69
+ appearance: "dark" | "light";
112
70
  name?: string;
113
- /** Optional name of a matching Shiki syntax-highlighting theme. Code
114
- * blocks and fenced markdown snippets look this up so highlighting
115
- * aligns with the TUI palette. Leave unset for themes without a
116
- * Shiki counterpart. */
117
- shiki?: ShikiTheme;
71
+ /** Matching bundled Shiki theme. Unset or "auto" generates highlighting
72
+ * from the syntax slots. */
73
+ shiki?: ShikiSelection;
74
+ fg: Color<Ansi, Ansi>;
75
+ bg: Color<Ansi, Ansi>;
118
76
  /** Brand / primary accent. */
119
- primary: Color;
77
+ primary: Color<Ansi>;
120
78
  /** Secondary accent — distinct hue from `primary`. */
121
- accent: Color;
122
- /** Default text color used by themed blocks (markdown content, code,
123
- * quotes) that compose `fg: "text"` into their style. Defaults to
124
- * `"inherit"` (terminal fg). Set explicitly when a theme wants
125
- * themed text inside its tinted regions. */
126
- text: Color;
79
+ accent: Color<Ansi>;
127
80
  /** Secondary text — first tier of the quietness ladder
128
81
  * (`muted` → `quiet` → `comment`). Slightly faded but readable;
129
82
  * good for timestamps, captions, less-prominent labels. */
130
- muted: ThemeValue;
83
+ muted: T;
131
84
  /** De-emphasized but still readable. Reasoning / thinking text,
132
85
  * secondary annotations, hints. */
133
- quiet: ThemeValue;
86
+ quiet: T;
134
87
  /** Editor-comment tier — soft, often tinted. Used for code
135
88
  * annotations, line-number labels, italic quotes. */
136
- comment: ThemeValue;
89
+ comment: T;
137
90
  /** Section / panel titles. Typically `bold` + a fg color. */
138
- title: ThemeValue;
91
+ title: T;
139
92
  /** Structural separators — borders, dividers, gutter lines. */
140
- delim: ThemeValue;
141
- /** Structural neutral — applied as fg for borders, dividers, and the
142
- * gutter; as bg for subtly-tinted surfaces. Never used for
143
- * de-emphasized text; that's the `muted` / `quiet` / `comment`
144
- * tier. */
145
- subtle: ThemeValue;
93
+ delim: T;
146
94
  /** Default UI surface. Bottom of the stack. */
147
- ui: ThemeValue;
95
+ ui: T;
148
96
  /** Popup / modal surface. One tier above `ui`. */
149
- overlay: ThemeValue;
97
+ overlay: T;
150
98
  /** Tinted region for emphasized content within the stream — user
151
99
  * bubble bg, focused row, callout. Distinct from `code`, which is
152
100
  * reserved for code-block bg. */
153
- highlight: ThemeValue;
101
+ highlight: T;
154
102
  /** Separators between messages or sections. */
155
- divider: ThemeValue;
103
+ divider: T;
156
104
  /** Highlighted text in inputs, lists, autocomplete. */
157
- selection: ThemeValue;
105
+ selection: T;
158
106
  /** Line-number column, diff markers. */
159
- gutter: ThemeValue;
107
+ gutter: T;
160
108
  /** Main input-prompt styling. */
161
- prompt: ThemeValue;
109
+ prompt: T;
162
110
  /** Structural border around panels, boxes, tables. */
163
- border: ThemeValue;
111
+ border: T;
164
112
  /** Title text inside a bordered region (slightly stronger than
165
113
  * `border`). */
166
- borderTitle: ThemeValue;
114
+ borderTitle: T;
167
115
  /** Code-block surface (bg + optional fg). Default for `mdCodeBlock`. */
168
- code: ThemeValue;
116
+ code: T;
169
117
  /** Title above a code block (e.g. file path). */
170
- codeTitle: ThemeValue;
171
- success: Color;
172
- info: Color;
173
- warn: Color;
174
- error: Color;
175
- syntaxBoolean: ThemeValue;
176
- syntaxBracket: ThemeValue;
177
- syntaxConstant: ThemeValue;
178
- syntaxDelimiter: ThemeValue;
179
- syntaxField: ThemeValue;
180
- syntaxFunction: ThemeValue;
181
- syntaxNumber: ThemeValue;
182
- syntaxSpecial: ThemeValue;
183
- syntaxString: ThemeValue;
184
- mdBold: ThemeValue;
185
- mdCode: ThemeValue;
186
- mdCodeBlock: ThemeValue;
187
- mdCodeBlockTitle: ThemeValue;
188
- mdHeading1: ThemeValue;
189
- mdHeading2: ThemeValue;
190
- mdHeading3: ThemeValue;
191
- mdHeading4: ThemeValue;
192
- mdHeading5: ThemeValue;
193
- mdHeading6: ThemeValue;
194
- mdHeading: ThemeValue;
195
- mdHr: ThemeValue;
196
- mdItalic: ThemeValue;
197
- mdLink: ThemeValue;
198
- mdListBullet: ThemeValue;
199
- mdListChecked: ThemeValue;
200
- mdListUnchecked: ThemeValue;
201
- mdQuote: ThemeValue;
202
- mdStrikethrough: ThemeValue;
203
- mdTable: ThemeValue;
204
- mdTableHeader: ThemeValue;
205
- optionName: ThemeValue;
206
- optionDesc: ThemeValue;
118
+ codeTitle: T;
119
+ success: Color<Ansi>;
120
+ info: Color<Ansi>;
121
+ warn: Color<Ansi>;
122
+ error: Color<Ansi>;
123
+ syntaxBoolean: T;
124
+ syntaxBracket: T;
125
+ syntaxConstant: T;
126
+ syntaxDelimiter: T;
127
+ syntaxField: T;
128
+ syntaxFunction: T;
129
+ syntaxNumber: T;
130
+ syntaxSpecial: T;
131
+ syntaxString: T;
132
+ mdBold: T;
133
+ mdCode: T;
134
+ mdCodeBlock: T;
135
+ mdCodeBlockTitle: T;
136
+ mdHeading1: T;
137
+ mdHeading2: T;
138
+ mdHeading3: T;
139
+ mdHeading4: T;
140
+ mdHeading5: T;
141
+ mdHeading6: T;
142
+ mdHeading: T;
143
+ mdHr: T;
144
+ mdItalic: T;
145
+ mdLink: T;
146
+ mdListBullet: T;
147
+ mdListChecked: T;
148
+ mdListUnchecked: T;
149
+ mdMath: T;
150
+ mdQuote: T;
151
+ mdStrikethrough: T;
152
+ mdTable: T;
153
+ mdTableHeader: T;
154
+ optionName: T;
155
+ optionDesc: T;
207
156
  /** Currently-highlighted entry. */
208
- optionActive: ThemeValue;
209
- diffAdd: ThemeValue;
210
- diffContext: ThemeValue;
211
- diffDel: ThemeValue;
212
- diffLine: ThemeValue;
213
- diffTitle: ThemeValue;
157
+ optionActive: T;
158
+ diffAdd: T;
159
+ diffDel: T;
160
+ diffContext: T;
161
+ diffAddNum: T;
162
+ diffDelNum: T;
163
+ diffContextNum: T;
214
164
  };
215
165
  //#endregion
216
- export { ShikiRequest as _, AnsiStyle as a, ShikiWorkerMessage as b, Color as c, RGB as d, Style as f, ShikiOpts as g, ShikiLanguage as h, AnsiColorName as i, ColorLightness as l, ShikiJob as m, ThemeValue as n, AnyStyle as o, ThemeKey as p, AnsiColor as r, BrightAnsiColorName as s, Theme as t, HexColor as u, ShikiResult as v, ShikiWorkerRequest as x, ShikiTheme as y };
217
- //# sourceMappingURL=types-C0EOLZDc.d.mts.map
166
+ //#region src/style/types.d.ts
167
+ type RGB = [r: number, g: number, b: number];
168
+ /** Alpha percentage for `/<alpha>` suffix on Color values. Any integer
169
+ * 0..100 is accepted at runtime; the template literal uses `${number}`
170
+ * so odd values like `/98` typecheck without a cast. */
171
+ type ColorLightness = `${number}`;
172
+ /** Standard ANSI color names. */
173
+ type AnsiColorName = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "grey";
174
+ /** Bright ANSI variants — `brightRed`, `brightBlue`, etc. */
175
+ type BrightAnsiColorName = `bright${Capitalize<AnsiColorName>}`;
176
+ type AnsiColor = AnsiColorName | BrightAnsiColorName | HexColor | "inherit";
177
+ /** Hex color string. Matches `#rgb` / `#rgba` / `#rrggbb` / `#rrggbbaa`
178
+ * (any case; runtime validates). Alpha is native to the hex form, so
179
+ * there is no separate `/<alpha>` suffix for hex. */
180
+ type HexColor = `#${string}`;
181
+ type ThemeKey = Exclude<keyof Theme<false, unknown>, "shiki" | "$schema" | "id" | "name" | "appearance">;
182
+ /**
183
+ * A color value. Accepted forms:
184
+ * - `#rgb` / `#rrggbb` hex
185
+ * - ANSI color names (`red`, `cyan`, `gray`, …)
186
+ * - Bright ANSI variants (`brightRed`, `brightBlue`, …)
187
+ * - Theme slot keys from `keyof Theme` (`primary`, `muted`, …)
188
+ * - `'inherit'` — use the parent's color (renders as no escape).
189
+ * - Variant suffix `-<step>` on hex or theme slots — e.g. `primary-300`,
190
+ * `#82aaff-900`. The base color gets resolved through the theme
191
+ * (extracting the channel when needed), then `variant(base, step)`
192
+ * shifts it along the OKLCH tonal scale.
193
+ */
194
+ type Color<Ansi extends boolean = true, I = true> = HexColor | (Ansi extends true ? AnsiColorName : never) | (Ansi extends true ? BrightAnsiColorName : never) | ThemeKey | (I extends true ? "inherit" : never) | `${HexColor | ThemeKey}-${ColorLightness}` | `${HexColor | ThemeKey}+${ColorLightness}`;
195
+ interface AnsiStyle {
196
+ fg?: AnsiColor;
197
+ bg?: AnsiColor;
198
+ bold?: boolean;
199
+ dim?: boolean;
200
+ italic?: boolean;
201
+ underline?: boolean;
202
+ inverse?: boolean;
203
+ strikethrough?: boolean;
204
+ }
205
+ /** Base style shared by every node type. Box/Text/etc. extend this.
206
+ * Pure styling — no layout or lifecycle fields. Widget state interfaces
207
+ * extend `StyleState` to pick up the `visible` base-state bits alongside
208
+ * these style fields. */
209
+ type Style<Ansi extends boolean = true> = Simplify<Omit<AnsiStyle, "fg" | "bg"> & {
210
+ fg?: Color<Ansi>;
211
+ bg?: Color<Ansi>;
212
+ style?: AnyStyle<Ansi>;
213
+ }>;
214
+ type AnyStyle<Ansi extends boolean = false> = Style<Ansi> | Color<Ansi>;
215
+ //#endregion
216
+ export { ShikiThemeInput as C, ShikiTheme as S, ShikiWorkerRequest as T, ShikiLanguage as _, BrightAnsiColorName as a, ShikiResult as b, HexColor as c, ThemeKey as d, Theme as f, ShikiJob as g, GeneratedShikiTheme as h, AnyStyle as i, RGB as l, ThemeValue as m, AnsiColorName as n, Color as o, ThemeStyle as p, AnsiStyle as r, ColorLightness as s, AnsiColor as t, Style as u, ShikiOpts as v, ShikiWorkerMessage as w, ShikiSelection as x, ShikiRequest as y };
217
+ //# sourceMappingURL=types-C9ceMsbJ.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-C9ceMsbJ.d.mts","names":[],"sources":["../src/shiki/types.ts","../src/themes/types.ts","../src/style/types.ts"],"mappings":";;;KAGY,aAAa;KACb,gBAAgB;KAChB,0BAA0B;KAC1B;EACV;EACA;EACA,QAAQ;;KAEE,kBAAkB,aAAa;KAE/B;EACV;EACA;EACA;EACA,QAAQ;EACR,SAAS;;KAGC,qBAAqB,KAAK;EACpC;EACA,MAAM;EACN;;KAGU,WAAW,qBACrB,kBAAkB,QAAQ,cAAc;EACtC;;KAGQ;EACV;EACA;EACA;EACA;;KAGU;EAAuB;KAAmB;EAAgB;;KAE1D;EACV,QAAQ;EACR,SAAS;;;;KCvCC,WAAW,+BAA+B,SACpD,KAAK;EACH,KAAK,MAAM;EACX,KAAK,MAAM;;KAGH,WAAW,+BAA+B,WAAW,QAAQ,MAAM;;;;;;;;;;;;;;;;;KAkBnE,MAAM,6BAA6B,IAAI,WAAW;EAC5D;;EAEA;EACA;;;EAGA,QAAQ;EAIR,IAAI,MAAM,MAAM;EAChB,IAAI,MAAM,MAAM;;EAEhB,SAAS,MAAM;;EAEf,QAAQ,MAAM;;;;EAOd,OAAO;;;EAGP,OAAO;;;EAGP,SAAS;;EAET,OAAO;;EAEP,OAAO;;EAKP,IAAI;;EAEJ,SAAS;;;;EAIT,WAAW;;EAKX,SAAS;;EAET,WAAW;;EAEX,QAAQ;;EAER,QAAQ;;EAER,QAAQ;;;EAGR,aAAa;;EAKb,MAAM;;EAEN,WAAW;EAIX,SAAS,MAAM;EACf,MAAM,MAAM;EACZ,MAAM,MAAM;EACZ,OAAO,MAAM;EAGb,eAAe;EACf,eAAe;EACf,gBAAgB;EAChB,iBAAiB;EACjB,aAAa;EACb,gBAAgB;EAChB,cAAc;EACd,eAAe;EACf,cAAc;EAId,QAAQ;EACR,QAAQ;EACR,aAAa;EACb,kBAAkB;EAClB,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,WAAW;EACX,MAAM;EACN,UAAU;EACV,QAAQ;EACR,cAAc;EACd,eAAe;EACf,iBAAiB;EACjB,QAAQ;EACR,SAAS;EACT,iBAAiB;EACjB,SAAS;EACT,eAAe;EAIf,YAAY;EACZ,YAAY;;EAEZ,cAAc;EAGd,SAAS;EACT,SAAS;EACT,aAAa;EACb,YAAY;EACZ,YAAY;EACZ,gBAAgB;;;;KCtJN,OAAO,WAAW,WAAW;;;;KAK7B;;KAGA;;KAaA,+BAA+B,WAAW;KAE1C,YAAY,gBAAgB,sBAAsB;;;;KAKlD;KACA,WAAW,cACf;;;;;;;;;;;;;KAgBI,MAAM,6BAA6B,YAC3C,YACC,oBAAoB,0BACpB,oBAAoB,+BACrB,YACC,yCACE,WAAW,YAAY,sBACvB,WAAW,YAAY;UAEb;EACf,KAAK;EACL,KAAK;EACL;EACA;EACA;EACA;EACA;EACA;;;;;;KAOU,MAAM,+BAA+B,SAC/C,KAAK;EACH,KAAK,MAAM;EACX,KAAK,MAAM;EACX,QAAQ,SAAS;;KAIT,SAAS,gCAAgC,MAAM,QAAQ,MAAM"}
@@ -1,4 +1,4 @@
1
- import { p as Node } from "./queries-Cvalgu6P.mjs";
1
+ import { h as Node } from "./queries-C75-wG1B.mjs";
2
2
  //#region src/widgets/widget.d.ts
3
3
  type Props = Record<string, unknown>;
4
4
  /**
@@ -46,4 +46,4 @@ type Widget<A extends unknown[] = never[], N extends Node = Node> = (...args: A)
46
46
  declare function widget<T extends Widget>(fn: T): T;
47
47
  //#endregion
48
48
  export { Widget as n, widget as r, Props as t };
49
- //# sourceMappingURL=widget-DtJU2-BJ.d.mts.map
49
+ //# sourceMappingURL=widget-DlF32PRp.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"widget-DtJU2-BJ.d.mts","names":[],"sources":["../src/widgets/widget.ts"],"mappings":";;KAIY,QAAQ;;;;;;;;;;;KAYR,OAAO,+BAA+B,UAAU,OAAO,YAAY,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkC3E,OAAO,UAAU,QAAQ,IAAI,IAAI"}
1
+ {"version":3,"file":"widget-DlF32PRp.d.mts","names":[],"sources":["../src/widgets/widget.ts"],"mappings":";;KAIY,QAAQ;;;;;;;;;;;KAYR,OAAO,+BAA+B,UAAU,OAAO,YAAY,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkC3E,OAAO,UAAU,QAAQ,IAAI,IAAI"}
@@ -1,2 +1,2 @@
1
- import { a as AutocompleteState, i as AutocompleteOptions, n as Autocomplete, o as CompletionSource, r as AutocompleteEvents, s as autocomplete, t as AcceptFn } from "../autocomplete-CxzetPOo.mjs";
1
+ import { a as AutocompleteState, i as AutocompleteOptions, n as Autocomplete, o as CompletionSource, r as AutocompleteEvents, s as autocomplete, t as AcceptFn } from "../autocomplete-CD30kSe_.mjs";
2
2
  export { AcceptFn, Autocomplete, AutocompleteEvents, AutocompleteOptions, AutocompleteState, CompletionSource, autocomplete };
@@ -1,7 +1,7 @@
1
1
  import { S as unwrap, f as effect, h as memo, y as signal } from "../reactive-f7NpAi69.mjs";
2
2
  import { t as Node } from "../node-BZ7f6HzU.mjs";
3
- import { t as picker } from "../picker-BqHINl_a.mjs";
4
- import { t as Input } from "../input-D7fQEUdt.mjs";
3
+ import { t as picker } from "../picker-f6xjgACX.mjs";
4
+ import { t as Input } from "../input-ET2YEMcl.mjs";
5
5
  //#region src/widgets/autocomplete.ts
6
6
  /**
7
7
  * Autocomplete popup bound to an `Input`. Watches the input's value and
@@ -1,2 +1,2 @@
1
- import { B as Padding, R as Box, V as box, z as BoxStyle } from "../queries-Cvalgu6P.mjs";
1
+ import { B as Box, H as Padding, U as box, V as BoxStyle } from "../queries-C75-wG1B.mjs";
2
2
  export { Box, BoxStyle, Padding, box };
@@ -1 +1 @@
1
- export { t as Box, n as box } from "../box-DLEcEvDH.mjs";
1
+ export { t as Box, n as box } from "../box-C_N_7ChP.mjs";
@@ -1,5 +1,6 @@
1
- import { R as Box, X as State, nt as Reactive } from "../queries-Cvalgu6P.mjs";
2
- import { o as AnyStyle } from "../types-C0EOLZDc.mjs";
1
+ import { i as AnyStyle } from "../types-C9ceMsbJ.mjs";
2
+ import { B as Box, Q as State, it as Reactive } from "../queries-C75-wG1B.mjs";
3
+ import { t as WrapMode } from "../text-CmxbA8lk.mjs";
3
4
  //#region src/widgets/code.d.ts
4
5
  export interface CodeState {
5
6
  /** Source to render. Plain string or reactive accessor — pass a
@@ -23,6 +24,7 @@ export interface CodeState {
23
24
  offset?: Reactive<number | undefined>;
24
25
  limit?: Reactive<number | undefined>;
25
26
  more?: (more: number, msg: string) => string;
27
+ wrap?: WrapMode;
26
28
  }
27
29
  /**
28
30
  * Standalone code block: shiki-highlighted body inside a `code`-styled
@@ -1 +1 @@
1
- {"version":3,"file":"code.d.mts","names":["_$__box_ts0.Box"],"sources":["../../src/widgets/code.ts"],"mappings":";;;iBAciB;;;EAGf,MAAM;;;EAGN,OAAO;;;;EAIP;;;EAGA,QAAQ;;EAER;EACA,QAAQ;EACR;EACA,eAAe;EACf,SAAS;EACT,QAAQ;EACR,QAAQ,cAAc;;;;;;;;;;;;;;;;;;;;qBAqBX,OAAI,OAAkB,MAAM,eAANA"}
1
+ {"version":3,"file":"code.d.mts","names":["_$__box_ts0.Box"],"sources":["../../src/widgets/code.ts"],"mappings":";;;;iBAgBiB;;;EAGf,MAAM;;;EAGN,OAAO;;;;EAIP;;;EAGA,QAAQ;;EAER;EACA,QAAQ;EACR;EACA,eAAe;EACf,SAAS;EACT,QAAQ;EACR,QAAQ,cAAc;EACtB,OAAO;;;;;;;;;;;;;;;;;;;;qBAqBI,OAAI,OAAkB,MAAM,eAANA"}
@@ -1,9 +1,10 @@
1
1
  import { S as unwrap, h as memo, r as createAsync, w as useContext } from "../reactive-f7NpAi69.mjs";
2
- import { n as box } from "../box-DLEcEvDH.mjs";
3
- import { a as formatLines } from "../text-CRZD9KTN.mjs";
4
- import { n as text } from "../text-BLz1tRoC.mjs";
5
- import { t as RenderContext } from "../render-f7M2856V.mjs";
6
- import { t as codeToAnsi } from "../shiki--ASSYv4_.mjs";
2
+ import { n as box } from "../box-C_N_7ChP.mjs";
3
+ import { a as formatLines } from "../text-BoJdKXLU.mjs";
4
+ import { n as text } from "../text-DPrhma4x.mjs";
5
+ import { t as RenderContext } from "../render-B7LfNM5K.mjs";
6
+ import { t as codeToAnsi } from "../shiki-CJauRusM.mjs";
7
+ import { t as shikiTheme } from "../theme-C8LkcoaK.mjs";
7
8
  import { t as widget } from "../widget-BkMwhY2p.mjs";
8
9
  import { t as show } from "../show-DR2x1YFc.mjs";
9
10
  import { extname } from "pathe";
@@ -36,7 +37,7 @@ const code = widget((props) => {
36
37
  const body = createAsync(async () => {
37
38
  const source = plain();
38
39
  if (!lang || !syntax) return source;
39
- return await codeToAnsi(source, lang, { theme: context?.style().theme.shiki });
40
+ return await codeToAnsi(source, lang, { theme: context ? shikiTheme(context.style().theme) : void 0 });
40
41
  }, { initialValue: plain() });
41
42
  const formatted = memo(() => formatLines(body().split("\n"), {
42
43
  limit: unwrap(props.limit),
@@ -51,7 +52,7 @@ const code = widget((props) => {
51
52
  padding: props.style === false ? void 0 : [0, 1],
52
53
  style: props.style === false ? void 0 : props.style ?? "code",
53
54
  width: "fit"
54
- }, show({ when: title }, () => text((ctx) => ctx.style.codeTitle(title() ?? ""), { wrap: "none" })), text(formatted, { wrap: "none" }));
55
+ }, show({ when: title }, () => text((ctx) => ctx.style.codeTitle(title() ?? ""), { wrap: "none" })), text(formatted, { wrap: props.wrap ?? "none" }));
55
56
  });
56
57
  //#endregion
57
58
  export { code };
@@ -1 +1 @@
1
- {"version":3,"file":"code.mjs","names":[],"sources":["../../src/widgets/code.ts"],"sourcesContent":["import type { Reactive } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { AnyStyle } from \"../style/types.ts\"\n\nimport { extname } from \"pathe\"\nimport { createAsync, memo, unwrap, useContext } from \"../core/reactive.ts\"\nimport { RenderContext } from \"../core/render.ts\"\nimport { formatLines } from \"../layout/text.ts\"\nimport { codeToAnsi } from \"../shiki/shiki.ts\"\nimport { box } from \"./box.ts\"\nimport { show } from \"./show.ts\"\nimport { text } from \"./text.ts\"\nimport { widget } from \"./widget.ts\"\n\nexport interface CodeState {\n /** Source to render. Plain string or reactive accessor — pass a\n * signal for streaming bash output / tool results. */\n code: Reactive<string>\n /** Optional file path. Drives the default `lang` (extension) and\n * `title` (path) when those aren't set explicitly. */\n path?: Reactive<string>\n /** Language for syntax highlighting (any shiki-bundled name or\n * alias). Defaults to `extname(path).slice(1)` when `path` is set.\n * Unknown langs fall through to plain rendering. */\n lang?: string\n /** Title line shown above the block. May contain ANSI. Defaults to\n * `path` when set. */\n title?: Reactive<string>\n /** Disable syntax highlighting even if `lang` is set. Default: `true`. */\n syntax?: boolean\n style?: AnyStyle | false\n numbered?: boolean\n numberOffset?: Reactive<number | undefined>\n offset?: Reactive<number | undefined>\n limit?: Reactive<number | undefined>\n more?: (more: number, msg: string) => string\n}\n\n/**\n * Standalone code block: shiki-highlighted body inside a `code`-styled\n * shrink-to-content backdrop, optionally titled.\n *\n * Composition over custom layout — the backdrop is `box({ bg: \"code\",\n * width: \"fit\" })`, the body is plain `text(...)`. Ambient theme/style\n * arrive via `useContext(RenderContext)`; the async closure reads\n * `style()?.theme` so it stays correct across theme swaps.\n *\n * Async highlighting flows through `createAsync`: signal reads inside\n * the async closure auto-track, so `props.code` (or any other reactive\n * source) drives a re-fire. The accessor returns `initialValue` (the\n * plain source) until shiki resolves, then swaps to the highlighted\n * version. When called inside a Stream surface's `append`, the surface\n * installs a `SuspenseContext` boundary; Stream awaits it before\n * painting, so rows committed to scrollback always reflect the\n * resolved highlight rather than the initial plain source.\n */\nexport const code = widget((props: State<CodeState>) => {\n const path = unwrap(props.path)\n const lang = props.lang ?? (path !== undefined ? extname(path).slice(1).toLowerCase() : undefined)\n const syntax = props.syntax ?? true\n\n // Theme is sourced from a render-time hook since the async closure\n // runs outside the render phase.\n\n const context = useContext(RenderContext)\n\n const title = memo(() => unwrap(props.title) ?? path)\n\n const plain = () => unwrap(props.code).replace(/\\n+$/, \"\")\n\n const body = createAsync(\n async () => {\n const source = plain()\n if (!lang || !syntax) return source\n return await codeToAnsi(source, lang, { theme: context?.style().theme.shiki })\n },\n { initialValue: plain() }\n )\n\n const formatted = memo(() =>\n formatLines(body().split(\"\\n\"), {\n limit: unwrap(props.limit),\n more: props.more,\n numberOffset: unwrap(props.numberOffset),\n numbered: props.numbered,\n offset: unwrap(props.offset),\n style: context?.style().gutter,\n }).join(\"\\n\")\n )\n\n return box(\n {\n flexDirection: \"column\",\n padding: props.style === false ? undefined : [0, 1],\n style: props.style === false ? undefined : (props.style ?? \"code\"),\n width: \"fit\",\n },\n show({ when: title }, () =>\n text((ctx) => ctx.style.codeTitle(title() ?? \"\"), { wrap: \"none\" })\n ),\n text(formatted, { wrap: \"none\" })\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAa,OAAO,QAAQ,UAA4B;CACtD,MAAM,OAAO,OAAO,MAAM,IAAI;CAC9B,MAAM,OAAO,MAAM,SAAS,SAAS,KAAA,IAAY,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,KAAA;CACxF,MAAM,SAAS,MAAM,UAAU;CAK/B,MAAM,UAAU,WAAW,aAAa;CAExC,MAAM,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,IAAI;CAEpD,MAAM,cAAc,OAAO,MAAM,IAAI,CAAC,CAAC,QAAQ,QAAQ,EAAE;CAEzD,MAAM,OAAO,YACX,YAAY;EACV,MAAM,SAAS,MAAM;EACrB,IAAI,CAAC,QAAQ,CAAC,QAAQ,OAAO;EAC7B,OAAO,MAAM,WAAW,QAAQ,MAAM,EAAE,OAAO,SAAS,MAAM,CAAC,CAAC,MAAM,MAAM,CAAC;CAC/E,GACA,EAAE,cAAc,MAAM,EAAE,CAC1B;CAEA,MAAM,YAAY,WAChB,YAAY,KAAK,CAAC,CAAC,MAAM,IAAI,GAAG;EAC9B,OAAO,OAAO,MAAM,KAAK;EACzB,MAAM,MAAM;EACZ,cAAc,OAAO,MAAM,YAAY;EACvC,UAAU,MAAM;EAChB,QAAQ,OAAO,MAAM,MAAM;EAC3B,OAAO,SAAS,MAAM,CAAC,CAAC;CAC1B,CAAC,CAAC,CAAC,KAAK,IAAI,CACd;CAEA,OAAO,IACL;EACE,eAAe;EACf,SAAS,MAAM,UAAU,QAAQ,KAAA,IAAY,CAAC,GAAG,CAAC;EAClD,OAAO,MAAM,UAAU,QAAQ,KAAA,IAAa,MAAM,SAAS;EAC3D,OAAO;CACT,GACA,KAAK,EAAE,MAAM,MAAM,SACjB,MAAM,QAAQ,IAAI,MAAM,UAAU,MAAM,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CACpE,GACA,KAAK,WAAW,EAAE,MAAM,OAAO,CAAC,CAClC;AACF,CAAC"}
1
+ {"version":3,"file":"code.mjs","names":[],"sources":["../../src/widgets/code.ts"],"sourcesContent":["import type { Reactive } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { WrapMode } from \"../layout/text.ts\"\nimport type { AnyStyle } from \"../style/types.ts\"\n\nimport { extname } from \"pathe\"\nimport { createAsync, memo, unwrap, useContext } from \"../core/reactive.ts\"\nimport { RenderContext } from \"../core/render.ts\"\nimport { formatLines } from \"../layout/text.ts\"\nimport { codeToAnsi } from \"../shiki/shiki.ts\"\nimport { shikiTheme } from \"../shiki/theme.ts\"\nimport { box } from \"./box.ts\"\nimport { show } from \"./show.ts\"\nimport { text } from \"./text.ts\"\nimport { widget } from \"./widget.ts\"\n\nexport interface CodeState {\n /** Source to render. Plain string or reactive accessor — pass a\n * signal for streaming bash output / tool results. */\n code: Reactive<string>\n /** Optional file path. Drives the default `lang` (extension) and\n * `title` (path) when those aren't set explicitly. */\n path?: Reactive<string>\n /** Language for syntax highlighting (any shiki-bundled name or\n * alias). Defaults to `extname(path).slice(1)` when `path` is set.\n * Unknown langs fall through to plain rendering. */\n lang?: string\n /** Title line shown above the block. May contain ANSI. Defaults to\n * `path` when set. */\n title?: Reactive<string>\n /** Disable syntax highlighting even if `lang` is set. Default: `true`. */\n syntax?: boolean\n style?: AnyStyle | false\n numbered?: boolean\n numberOffset?: Reactive<number | undefined>\n offset?: Reactive<number | undefined>\n limit?: Reactive<number | undefined>\n more?: (more: number, msg: string) => string\n wrap?: WrapMode\n}\n\n/**\n * Standalone code block: shiki-highlighted body inside a `code`-styled\n * shrink-to-content backdrop, optionally titled.\n *\n * Composition over custom layout — the backdrop is `box({ bg: \"code\",\n * width: \"fit\" })`, the body is plain `text(...)`. Ambient theme/style\n * arrive via `useContext(RenderContext)`; the async closure reads\n * `style()?.theme` so it stays correct across theme swaps.\n *\n * Async highlighting flows through `createAsync`: signal reads inside\n * the async closure auto-track, so `props.code` (or any other reactive\n * source) drives a re-fire. The accessor returns `initialValue` (the\n * plain source) until shiki resolves, then swaps to the highlighted\n * version. When called inside a Stream surface's `append`, the surface\n * installs a `SuspenseContext` boundary; Stream awaits it before\n * painting, so rows committed to scrollback always reflect the\n * resolved highlight rather than the initial plain source.\n */\nexport const code = widget((props: State<CodeState>) => {\n const path = unwrap(props.path)\n const lang = props.lang ?? (path !== undefined ? extname(path).slice(1).toLowerCase() : undefined)\n const syntax = props.syntax ?? true\n\n // Theme is sourced from a render-time hook since the async closure\n // runs outside the render phase.\n\n const context = useContext(RenderContext)\n\n const title = memo(() => unwrap(props.title) ?? path)\n\n const plain = () => unwrap(props.code).replace(/\\n+$/, \"\")\n\n const body = createAsync(\n async () => {\n const source = plain()\n if (!lang || !syntax) return source\n return await codeToAnsi(source, lang, {\n theme: context ? shikiTheme(context.style().theme) : undefined,\n })\n },\n { initialValue: plain() }\n )\n\n const formatted = memo(() =>\n formatLines(body().split(\"\\n\"), {\n limit: unwrap(props.limit),\n more: props.more,\n numberOffset: unwrap(props.numberOffset),\n numbered: props.numbered,\n offset: unwrap(props.offset),\n style: context?.style().gutter,\n }).join(\"\\n\")\n )\n\n return box(\n {\n flexDirection: \"column\",\n padding: props.style === false ? undefined : [0, 1],\n style: props.style === false ? undefined : (props.style ?? \"code\"),\n width: \"fit\",\n },\n show({ when: title }, () =>\n text((ctx) => ctx.style.codeTitle(title() ?? \"\"), { wrap: \"none\" })\n ),\n text(formatted, { wrap: props.wrap ?? \"none\" })\n )\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,MAAa,OAAO,QAAQ,UAA4B;CACtD,MAAM,OAAO,OAAO,MAAM,IAAI;CAC9B,MAAM,OAAO,MAAM,SAAS,SAAS,KAAA,IAAY,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,KAAA;CACxF,MAAM,SAAS,MAAM,UAAU;CAK/B,MAAM,UAAU,WAAW,aAAa;CAExC,MAAM,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,IAAI;CAEpD,MAAM,cAAc,OAAO,MAAM,IAAI,CAAC,CAAC,QAAQ,QAAQ,EAAE;CAEzD,MAAM,OAAO,YACX,YAAY;EACV,MAAM,SAAS,MAAM;EACrB,IAAI,CAAC,QAAQ,CAAC,QAAQ,OAAO;EAC7B,OAAO,MAAM,WAAW,QAAQ,MAAM,EACpC,OAAO,UAAU,WAAW,QAAQ,MAAM,CAAC,CAAC,KAAK,IAAI,KAAA,EACvD,CAAC;CACH,GACA,EAAE,cAAc,MAAM,EAAE,CAC1B;CAEA,MAAM,YAAY,WAChB,YAAY,KAAK,CAAC,CAAC,MAAM,IAAI,GAAG;EAC9B,OAAO,OAAO,MAAM,KAAK;EACzB,MAAM,MAAM;EACZ,cAAc,OAAO,MAAM,YAAY;EACvC,UAAU,MAAM;EAChB,QAAQ,OAAO,MAAM,MAAM;EAC3B,OAAO,SAAS,MAAM,CAAC,CAAC;CAC1B,CAAC,CAAC,CAAC,KAAK,IAAI,CACd;CAEA,OAAO,IACL;EACE,eAAe;EACf,SAAS,MAAM,UAAU,QAAQ,KAAA,IAAY,CAAC,GAAG,CAAC;EAClD,OAAO,MAAM,UAAU,QAAQ,KAAA,IAAa,MAAM,SAAS;EAC3D,OAAO;CACT,GACA,KAAK,EAAE,MAAM,MAAM,SACjB,MAAM,QAAQ,IAAI,MAAM,UAAU,MAAM,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CACpE,GACA,KAAK,WAAW,EAAE,MAAM,MAAM,QAAQ,OAAO,CAAC,CAChD;AACF,CAAC"}
@@ -1,2 +1,2 @@
1
- import { n as ActionsSourceOptions, r as actionsSource, t as ActionCompletionItem } from "../../actions-DFboj3g5.mjs";
1
+ import { n as ActionsSourceOptions, r as actionsSource, t as ActionCompletionItem } from "../../actions--ODlgCQ5.mjs";
2
2
  export { ActionCompletionItem, ActionsSourceOptions, actionsSource };
@@ -1,2 +1,2 @@
1
- import { n as filesSource, t as FilesSourceOptions } from "../../files-BUsa-RVl.mjs";
1
+ import { n as filesSource, t as FilesSourceOptions } from "../../files-B_5HDBPp.mjs";
2
2
  export { FilesSourceOptions, filesSource };
@@ -1,2 +1,2 @@
1
- import { a as githubSource, i as GithubState, n as GithubItem, r as GithubSourceOptions, t as GithubFetcher } from "../../github-D89A3F9U.mjs";
1
+ import { a as githubSource, i as GithubState, n as GithubItem, r as GithubSourceOptions, t as GithubFetcher } from "../../github-CyRwUQ3y.mjs";
2
2
  export { GithubFetcher, GithubItem, GithubSourceOptions, GithubState, githubSource };
@@ -1,4 +1,4 @@
1
- import { n as ActionsSourceOptions, r as actionsSource, t as ActionCompletionItem } from "../../actions-DFboj3g5.mjs";
2
- import { n as filesSource, t as FilesSourceOptions } from "../../files-BUsa-RVl.mjs";
3
- import { a as githubSource, i as GithubState, n as GithubItem, r as GithubSourceOptions, t as GithubFetcher } from "../../github-D89A3F9U.mjs";
1
+ import { n as ActionsSourceOptions, r as actionsSource, t as ActionCompletionItem } from "../../actions--ODlgCQ5.mjs";
2
+ import { n as filesSource, t as FilesSourceOptions } from "../../files-B_5HDBPp.mjs";
3
+ import { a as githubSource, i as GithubState, n as GithubItem, r as GithubSourceOptions, t as GithubFetcher } from "../../github-CyRwUQ3y.mjs";
4
4
  export { ActionCompletionItem, ActionsSourceOptions, FilesSourceOptions, GithubFetcher, GithubItem, GithubSourceOptions, GithubState, actionsSource, filesSource, githubSource };
@@ -1,5 +1,5 @@
1
- import { J as Layout, P as RenderCtx, X as State, nt as Reactive, p as Node } from "../queries-Cvalgu6P.mjs";
2
- import { t as WrapMode } from "../text-BefiXAFW.mjs";
1
+ import { I as RenderCtx, Q as State, X as Layout, h as Node, it as Reactive } from "../queries-C75-wG1B.mjs";
2
+ import { t as WrapMode } from "../text-CmxbA8lk.mjs";
3
3
  //#region src/widgets/diff.d.ts
4
4
  export interface DiffState {
5
5
  /** Pre-state file content. Plain string or reactive accessor —
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.mts","names":[],"sources":["../../src/widgets/diff.ts"],"mappings":";;;iBAeiB;;;EAGf,UAAU;;;EAGV,UAAU;;;;EAIV,OAAO;;;EAGP;;EAEA;EACA,OAAO;;;;;;;;;;;;;qBAuBI,aAAa,KAAK;;EAI7B,YAAY,OAAO;MA+Bf;IAAW;IAAkB;;YAOjB,QAAQ,KAAK,YAAY;EAmBhC,UAAU;;;;;;;;;;;;;wBA4BL,KAAK,OAAO,MAAM,aAAa"}
1
+ {"version":3,"file":"diff.d.mts","names":[],"sources":["../../src/widgets/diff.ts"],"mappings":";;;iBAgBiB;;;EAGf,UAAU;;;EAGV,UAAU;;;;EAIV,OAAO;;;EAGP;;EAEA;EACA,OAAO;;;;;;;;;;;;;qBA2BI,aAAa,KAAK;;EAI7B,YAAY,OAAO;MA+Bf;IAAW;IAAkB;;YAOjB,QAAQ,KAAK,YAAY;EAqBhC,UAAU;;;;;;;;;;;;;wBA+BL,KAAK,OAAO,MAAM,aAAa"}
@@ -1,11 +1,13 @@
1
1
  import { S as unwrap, h as memo, r as createAsync, w as useContext } from "../reactive-f7NpAi69.mjs";
2
2
  import { t as Node } from "../node-BZ7f6HzU.mjs";
3
- import { r as countLines, t as calcLayout } from "../text-CRZD9KTN.mjs";
4
- import { t as RenderContext } from "../render-f7M2856V.mjs";
5
- import { t as codeToAnsi } from "../shiki--ASSYv4_.mjs";
3
+ import { t as calcLayout } from "../text-BoJdKXLU.mjs";
4
+ import { t as RenderContext } from "../render-B7LfNM5K.mjs";
5
+ import { t as codeToAnsi } from "../shiki-CJauRusM.mjs";
6
+ import { t as shikiTheme } from "../theme-C8LkcoaK.mjs";
6
7
  import { splitAnsi, stringWidth, wrapAnsi } from "@zaly/shared/ansi";
7
8
  import { basename, extname } from "pathe";
8
9
  //#region src/widgets/diff.ts
10
+ const NO_NEWLINE = String.raw``;
9
11
  /**
10
12
  * Show a unified diff between two file contents with syntax-highlighted
11
13
  * rows. Added rows carry a green backdrop and `+` prefix; removed rows
@@ -34,7 +36,7 @@ var Diff = class extends Node {
34
36
  const lang = this.#lang();
35
37
  const input = this.input;
36
38
  if (!lang) return input;
37
- const theme = context?.style().theme.shiki;
39
+ const theme = context ? shikiTheme(context.style().theme) : void 0;
38
40
  const [original, modified] = await Promise.all([codeToAnsi(input.original, lang, { theme }), codeToAnsi(input.modified, lang, { theme })]);
39
41
  return {
40
42
  modified,
@@ -56,16 +58,18 @@ var Diff = class extends Node {
56
58
  const input = this.input;
57
59
  const layout = this.layout();
58
60
  const width = Math.min(ctx.width, layout.width);
61
+ const original = splitLines(input.original);
62
+ const modified = splitLines(input.modified);
59
63
  const opts = {
60
64
  context: this.state.context ?? 3,
61
65
  ctx: {
62
66
  ...ctx,
63
67
  width
64
68
  },
65
- modified: input.modified.split("\n"),
66
- modifiedHi: highlighted.modified.split("\n"),
67
- original: input.original.split("\n"),
68
- originalHi: highlighted.original.split("\n")
69
+ modified,
70
+ modifiedHi: splitAnsi(highlighted.modified).slice(0, modified.length),
71
+ original,
72
+ originalHi: splitAnsi(highlighted.original).slice(0, original.length)
69
73
  };
70
74
  this.state.wrap ??= "word";
71
75
  return await buildDiffRows(opts);
@@ -74,10 +78,12 @@ var Diff = class extends Node {
74
78
  const input = this.input;
75
79
  const original = calcLayout(input.original, { wrap: this.state.wrap });
76
80
  const modified = calcLayout(input.modified, { wrap: this.state.wrap });
77
- const padding = Math.max(1, countLines(unwrap(this.state.original)), countLines(unwrap(this.state.modified))).toString().length * 2 + 4 + 4;
81
+ const numWidth = Math.max(1, splitLines(input.original).length, splitLines(input.modified).length).toString().length;
82
+ const markerWidth = [input.original, input.modified].some((s) => s !== "" && !s.endsWith("\n")) ? stringWidth(NO_NEWLINE) : 0;
83
+ const padding = numWidth * 2 + 4 + 4;
78
84
  return {
79
85
  minWidth: Math.max(original.minWidth, modified.minWidth) + padding,
80
- width: Math.max(original.width, modified.width) + padding
86
+ width: Math.max(original.width, modified.width, markerWidth) + padding
81
87
  };
82
88
  }
83
89
  };
@@ -95,10 +101,20 @@ var Diff = class extends Node {
95
101
  function diff(state) {
96
102
  return new Diff(state);
97
103
  }
104
+ function splitLines(text) {
105
+ if (text === "") return [];
106
+ const terminated = text.endsWith("\n");
107
+ const lines = text.split("\n");
108
+ if (terminated) lines.pop();
109
+ return lines.map((line, i) => ({
110
+ terminated: i < lines.length - 1 || terminated,
111
+ text: line
112
+ }));
113
+ }
98
114
  async function buildDiffRows(opts) {
99
115
  const context = opts.context;
100
116
  const { diffArrays } = await import("diff");
101
- const segments = diffArrays(opts.original, opts.modified);
117
+ const segments = diffArrays(opts.original, opts.modified, { comparator: (a, b) => a.text === b.text && a.terminated === b.terminated });
102
118
  const { original: origLines, modified: modLines, originalHi: origHi, modifiedHi: modHi, ctx } = opts;
103
119
  const ann = [];
104
120
  let oI = 0;
@@ -136,16 +152,19 @@ async function buildDiffRows(opts) {
136
152
  content: modHi[a.modIdx] ?? origHi[a.origIdx] ?? "",
137
153
  newNum: a.modIdx + 1,
138
154
  origNum: a.origIdx + 1,
155
+ terminated: modLines[a.modIdx].terminated,
139
156
  type: "context"
140
157
  });
141
158
  else if (a.kind === "remove") rows.push({
142
159
  content: origHi[a.origIdx] ?? "",
143
160
  origNum: a.origIdx + 1,
161
+ terminated: origLines[a.origIdx].terminated,
144
162
  type: "remove"
145
163
  });
146
164
  else rows.push({
147
165
  content: modHi[a.modIdx] ?? "",
148
166
  newNum: a.modIdx + 1,
167
+ terminated: modLines[a.modIdx].terminated,
149
168
  type: "add"
150
169
  });
151
170
  }
@@ -166,7 +185,7 @@ function renderRows(ctx, rows, origTotal, modTotal) {
166
185
  for (const r of rows) {
167
186
  const origStr = r.type === "add" ? "" : String(r.origNum);
168
187
  const newStr = r.type === "remove" ? "" : String(r.newNum);
169
- const gutterStyle = s.bg(`${styles[r.type]}+10`);
188
+ const gutterStyle = s[`${styles[r.type]}Num`] ?? ((x) => x);
170
189
  const gutter = gutterStyle(` ${pad(origStr, numWidth)} ${pad(newStr, numWidth)} `);
171
190
  const prefix = r.type === "add" ? " + " : r.type === "remove" ? " - " : " ";
172
191
  const innerWidth = Math.max(0, contentWidth - stringWidth(prefix) - 1);
@@ -179,6 +198,10 @@ function renderRows(ctx, rows, origTotal, modTotal) {
179
198
  const styledBody = rowStyle?.(bodyLine) ?? bodyLine;
180
199
  out.push((i === 0 ? gutter : gutterStyle(blankGutter)) + styledBody);
181
200
  }
201
+ if (!r.terminated) {
202
+ const marker = wrapAnsi(NO_NEWLINE, Math.max(1, contentWidth), { mode: "word" });
203
+ for (const line of splitAnsi(marker)) out.push(" ".repeat(gutterWidth) + s.dim(line));
204
+ }
182
205
  }
183
206
  return out;
184
207
  }