termcast 1.3.10 → 1.3.18

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 (500) hide show
  1. package/dist/apis/toast.d.ts +1 -5
  2. package/dist/apis/toast.d.ts.map +1 -1
  3. package/dist/apis/toast.js +23 -17
  4. package/dist/apis/toast.js.map +1 -1
  5. package/dist/build.d.ts +2 -0
  6. package/dist/build.d.ts.map +1 -1
  7. package/dist/build.js +4 -3
  8. package/dist/build.js.map +1 -1
  9. package/dist/cli.js +42 -0
  10. package/dist/cli.js.map +1 -1
  11. package/dist/colors.d.ts +8 -1
  12. package/dist/colors.d.ts.map +1 -1
  13. package/dist/colors.js +12 -0
  14. package/dist/colors.js.map +1 -1
  15. package/dist/compile.d.ts +30 -0
  16. package/dist/compile.d.ts.map +1 -0
  17. package/dist/compile.js +156 -0
  18. package/dist/compile.js.map +1 -0
  19. package/dist/components/actions.d.ts +1 -0
  20. package/dist/components/actions.d.ts.map +1 -1
  21. package/dist/components/actions.js +5 -2
  22. package/dist/components/actions.js.map +1 -1
  23. package/dist/components/command-arguments.d.ts +9 -0
  24. package/dist/components/command-arguments.d.ts.map +1 -0
  25. package/dist/components/command-arguments.js +21 -0
  26. package/dist/components/command-arguments.js.map +1 -0
  27. package/dist/components/detail.d.ts +1 -1
  28. package/dist/components/detail.d.ts.map +1 -1
  29. package/dist/components/detail.js +17 -39
  30. package/dist/components/detail.js.map +1 -1
  31. package/dist/components/dropdown.d.ts +1 -0
  32. package/dist/components/dropdown.d.ts.map +1 -1
  33. package/dist/components/dropdown.js +77 -21
  34. package/dist/components/dropdown.js.map +1 -1
  35. package/dist/components/extension-preferences.d.ts.map +1 -1
  36. package/dist/components/extension-preferences.js +19 -29
  37. package/dist/components/extension-preferences.js.map +1 -1
  38. package/dist/components/form/checkbox.d.ts.map +1 -1
  39. package/dist/components/form/checkbox.js +9 -2
  40. package/dist/components/form/checkbox.js.map +1 -1
  41. package/dist/components/form/date-picker.d.ts.map +1 -1
  42. package/dist/components/form/date-picker.js +15 -28
  43. package/dist/components/form/date-picker.js.map +1 -1
  44. package/dist/components/form/description.d.ts +2 -0
  45. package/dist/components/form/description.d.ts.map +1 -1
  46. package/dist/components/form/description.js +20 -2
  47. package/dist/components/form/description.js.map +1 -1
  48. package/dist/components/form/dropdown.d.ts.map +1 -1
  49. package/dist/components/form/dropdown.js +13 -28
  50. package/dist/components/form/dropdown.js.map +1 -1
  51. package/dist/components/form/file-autocomplete.d.ts +7 -4
  52. package/dist/components/form/file-autocomplete.d.ts.map +1 -1
  53. package/dist/components/form/file-autocomplete.js +54 -46
  54. package/dist/components/form/file-autocomplete.js.map +1 -1
  55. package/dist/components/form/file-picker.d.ts +5 -0
  56. package/dist/components/form/file-picker.d.ts.map +1 -1
  57. package/dist/components/form/file-picker.js +46 -49
  58. package/dist/components/form/file-picker.js.map +1 -1
  59. package/dist/components/form/form-ref.d.ts +43 -0
  60. package/dist/components/form/form-ref.d.ts.map +1 -0
  61. package/dist/components/form/form-ref.js +53 -0
  62. package/dist/components/form/form-ref.js.map +1 -0
  63. package/dist/components/form/index.d.ts +16 -0
  64. package/dist/components/form/index.d.ts.map +1 -1
  65. package/dist/components/form/index.js +86 -23
  66. package/dist/components/form/index.js.map +1 -1
  67. package/dist/components/form/password-field.d.ts.map +1 -1
  68. package/dist/components/form/password-field.js +32 -16
  69. package/dist/components/form/password-field.js.map +1 -1
  70. package/dist/components/form/text-area.d.ts.map +1 -1
  71. package/dist/components/form/text-area.js +32 -15
  72. package/dist/components/form/text-area.js.map +1 -1
  73. package/dist/components/form/text-field.d.ts.map +1 -1
  74. package/dist/components/form/text-field.js +37 -17
  75. package/dist/components/form/text-field.js.map +1 -1
  76. package/dist/components/form/use-form-navigation.d.ts +4 -0
  77. package/dist/components/form/use-form-navigation.d.ts.map +1 -1
  78. package/dist/components/form/use-form-navigation.js +35 -18
  79. package/dist/components/form/use-form-navigation.js.map +1 -1
  80. package/dist/components/form/with-left-border.d.ts.map +1 -1
  81. package/dist/components/form/with-left-border.js +2 -2
  82. package/dist/components/form/with-left-border.js.map +1 -1
  83. package/dist/components/icon.d.ts +3 -1
  84. package/dist/components/icon.d.ts.map +1 -1
  85. package/dist/components/icon.js +494 -469
  86. package/dist/components/icon.js.map +1 -1
  87. package/dist/components/list.d.ts +11 -7
  88. package/dist/components/list.d.ts.map +1 -1
  89. package/dist/components/list.js +170 -38
  90. package/dist/components/list.js.map +1 -1
  91. package/dist/components/loading-bar.js +1 -1
  92. package/dist/components/loading-bar.js.map +1 -1
  93. package/dist/descendants.d.ts.map +1 -1
  94. package/dist/descendants.js +8 -5
  95. package/dist/descendants.js.map +1 -1
  96. package/dist/examples/action-show-in-finder.js +1 -1
  97. package/dist/examples/action-show-in-finder.js.map +1 -1
  98. package/dist/examples/environment-test.js +1 -1
  99. package/dist/examples/environment-test.js.map +1 -1
  100. package/dist/examples/error-boundary.js +1 -1
  101. package/dist/examples/error-boundary.js.map +1 -1
  102. package/dist/examples/form-basic.d.ts.map +1 -1
  103. package/dist/examples/form-basic.js +2 -2
  104. package/dist/examples/form-basic.js.map +1 -1
  105. package/dist/examples/form-dropdown.js +1 -1
  106. package/dist/examples/form-dropdown.js.map +1 -1
  107. package/dist/examples/form-scroll.d.ts +2 -0
  108. package/dist/examples/form-scroll.d.ts.map +1 -0
  109. package/dist/examples/form-scroll.js +8 -0
  110. package/dist/examples/form-scroll.js.map +1 -0
  111. package/dist/examples/form-tagpicker.js +1 -1
  112. package/dist/examples/form-tagpicker.js.map +1 -1
  113. package/dist/examples/internal/descendants-filtering.js +8 -3
  114. package/dist/examples/internal/descendants-filtering.js.map +1 -1
  115. package/dist/examples/internal/descendants.js +10 -3
  116. package/dist/examples/internal/descendants.js.map +1 -1
  117. package/dist/examples/internal/rhf-custom-ref.d.ts +2 -0
  118. package/dist/examples/internal/rhf-custom-ref.d.ts.map +1 -0
  119. package/dist/examples/internal/rhf-custom-ref.js +67 -0
  120. package/dist/examples/internal/rhf-custom-ref.js.map +1 -0
  121. package/dist/examples/internal/scrollbox-demo.js +3 -7
  122. package/dist/examples/internal/scrollbox-demo.js.map +1 -1
  123. package/dist/examples/internal/scrollbox-with-descendants.d.ts +2 -0
  124. package/dist/examples/internal/scrollbox-with-descendants.d.ts.map +1 -0
  125. package/dist/examples/internal/scrollbox-with-descendants.js +63 -0
  126. package/dist/examples/internal/scrollbox-with-descendants.js.map +1 -0
  127. package/dist/examples/internal/simple-dialog.js +1 -1
  128. package/dist/examples/internal/simple-dialog.js.map +1 -1
  129. package/dist/examples/internal/simple-scrollbox.js +2 -3
  130. package/dist/examples/internal/simple-scrollbox.js.map +1 -1
  131. package/dist/examples/internal/text-stacking.js +4 -2
  132. package/dist/examples/internal/text-stacking.js.map +1 -1
  133. package/dist/examples/list-dropdown-default.js +1 -1
  134. package/dist/examples/list-dropdown-default.js.map +1 -1
  135. package/dist/examples/list-fetch-data.js +1 -1
  136. package/dist/examples/list-fetch-data.js.map +1 -1
  137. package/dist/examples/list-scrollbox.d.ts +2 -0
  138. package/dist/examples/list-scrollbox.d.ts.map +1 -0
  139. package/dist/examples/list-scrollbox.js +29 -0
  140. package/dist/examples/list-scrollbox.js.map +1 -0
  141. package/dist/examples/list-with-detail.js +1 -1
  142. package/dist/examples/list-with-detail.js.map +1 -1
  143. package/dist/examples/list-with-dropdown.js +1 -1
  144. package/dist/examples/list-with-dropdown.js.map +1 -1
  145. package/dist/examples/list-with-sections.js +3 -3
  146. package/dist/examples/list-with-sections.js.map +1 -1
  147. package/dist/examples/miscellaneous.js +1 -1
  148. package/dist/examples/miscellaneous.js.map +1 -1
  149. package/dist/examples/nested-navigation.js +4 -2
  150. package/dist/examples/nested-navigation.js.map +1 -1
  151. package/dist/examples/preferences-test.js +1 -1
  152. package/dist/examples/preferences-test.js.map +1 -1
  153. package/dist/examples/simple-dropdown.js +1 -1
  154. package/dist/examples/simple-dropdown.js.map +1 -1
  155. package/dist/examples/simple-file-picker.js +1 -1
  156. package/dist/examples/simple-file-picker.js.map +1 -1
  157. package/dist/examples/simple-grid.js +1 -1
  158. package/dist/examples/simple-grid.js.map +1 -1
  159. package/dist/examples/simple-hud.js +1 -1
  160. package/dist/examples/simple-hud.js.map +1 -1
  161. package/dist/examples/simple-list-search.js +1 -1
  162. package/dist/examples/simple-list-search.js.map +1 -1
  163. package/dist/examples/simple-list.js +1 -1
  164. package/dist/examples/simple-list.js.map +1 -1
  165. package/dist/examples/simple-navigation.js +4 -2
  166. package/dist/examples/simple-navigation.js.map +1 -1
  167. package/dist/examples/store.js +1 -1
  168. package/dist/examples/store.js.map +1 -1
  169. package/dist/examples/submodule-diff.d.ts +2 -0
  170. package/dist/examples/submodule-diff.d.ts.map +1 -0
  171. package/dist/examples/submodule-diff.js +99 -0
  172. package/dist/examples/submodule-diff.js.map +1 -0
  173. package/dist/examples/tanstack-demo.js +1 -1
  174. package/dist/examples/tanstack-demo.js.map +1 -1
  175. package/dist/examples/use-promise-demo.js +1 -1
  176. package/dist/examples/use-promise-demo.js.map +1 -1
  177. package/dist/extensions/dev.d.ts +8 -0
  178. package/dist/extensions/dev.d.ts.map +1 -1
  179. package/dist/extensions/dev.js +53 -28
  180. package/dist/extensions/dev.js.map +1 -1
  181. package/dist/extensions/home.d.ts.map +1 -1
  182. package/dist/extensions/home.js +16 -91
  183. package/dist/extensions/home.js.map +1 -1
  184. package/dist/globals.js +1 -1
  185. package/dist/globals.js.map +1 -1
  186. package/dist/index.d.ts +3 -1
  187. package/dist/index.d.ts.map +1 -1
  188. package/dist/index.js +5 -1
  189. package/dist/index.js.map +1 -1
  190. package/dist/internal/date-picker-widget.d.ts.map +1 -1
  191. package/dist/internal/date-picker-widget.js +56 -48
  192. package/dist/internal/date-picker-widget.js.map +1 -1
  193. package/dist/internal/dialog.d.ts.map +1 -1
  194. package/dist/internal/dialog.js +7 -7
  195. package/dist/internal/dialog.js.map +1 -1
  196. package/dist/internal/scrollbox.d.ts +2 -1
  197. package/dist/internal/scrollbox.d.ts.map +1 -1
  198. package/dist/internal/scrollbox.js +13 -7
  199. package/dist/internal/scrollbox.js.map +1 -1
  200. package/dist/release.d.ts +11 -0
  201. package/dist/release.d.ts.map +1 -0
  202. package/dist/release.js +113 -0
  203. package/dist/release.js.map +1 -0
  204. package/dist/state.d.ts +1 -0
  205. package/dist/state.d.ts.map +1 -1
  206. package/dist/state.js +1 -0
  207. package/dist/state.js.map +1 -1
  208. package/dist/theme.d.ts +11 -8
  209. package/dist/theme.d.ts.map +1 -1
  210. package/dist/theme.js +31 -8
  211. package/dist/theme.js.map +1 -1
  212. package/dist/utils/run-command.d.ts +22 -0
  213. package/dist/utils/run-command.d.ts.map +1 -0
  214. package/dist/utils/run-command.js +127 -0
  215. package/dist/utils/run-command.js.map +1 -0
  216. package/dist/utils.d.ts +1 -1
  217. package/dist/utils.d.ts.map +1 -1
  218. package/dist/utils.js +5 -3
  219. package/dist/utils.js.map +1 -1
  220. package/package.json +10 -7
  221. package/src/apis/toast.tsx +38 -17
  222. package/src/build.tsx +5 -3
  223. package/src/cli.tsx +46 -0
  224. package/src/colors.tsx +22 -1
  225. package/src/compile.tsx +219 -0
  226. package/src/components/actions.tsx +7 -1
  227. package/src/components/command-arguments.tsx +81 -0
  228. package/src/components/detail.tsx +26 -58
  229. package/src/components/dropdown.tsx +108 -23
  230. package/src/components/extension-preferences.tsx +55 -35
  231. package/src/components/form/checkbox.tsx +13 -5
  232. package/src/components/form/date-picker.tsx +24 -29
  233. package/src/components/form/description.tsx +35 -7
  234. package/src/components/form/dropdown.tsx +16 -30
  235. package/src/components/form/file-autocomplete.tsx +87 -77
  236. package/src/components/form/file-picker.tsx +69 -57
  237. package/src/components/form/form-ref.tsx +68 -0
  238. package/src/components/form/index.tsx +152 -41
  239. package/src/components/form/password-field.tsx +35 -22
  240. package/src/components/form/text-area.tsx +78 -58
  241. package/src/components/form/text-field.tsx +82 -61
  242. package/src/components/form/use-form-navigation.tsx +43 -23
  243. package/src/components/form/with-left-border.tsx +2 -1
  244. package/src/components/icon.tsx +497 -469
  245. package/src/components/list.tsx +279 -112
  246. package/src/components/loading-bar.tsx +1 -1
  247. package/src/descendants.tsx +15 -5
  248. package/src/examples/action-show-in-finder.tsx +1 -1
  249. package/src/examples/environment-test.tsx +1 -1
  250. package/src/examples/error-boundary.tsx +1 -1
  251. package/src/examples/file-autocomplete.vitest.tsx +245 -0
  252. package/src/examples/form-basic.tsx +12 -12
  253. package/src/examples/form-basic.vitest.tsx +297 -671
  254. package/src/examples/form-dropdown.tsx +1 -1
  255. package/src/examples/form-dropdown.vitest.tsx +353 -221
  256. package/src/examples/form-scroll.tsx +56 -0
  257. package/src/examples/form-scroll.vitest.tsx +228 -0
  258. package/src/examples/form-tagpicker.tsx +1 -1
  259. package/src/examples/form-tagpicker.vitest.tsx +438 -193
  260. package/src/examples/internal/descendants-filtering.tsx +13 -5
  261. package/src/examples/internal/descendants.tsx +17 -5
  262. package/src/examples/internal/rhf-custom-ref.tsx +152 -0
  263. package/src/examples/internal/scrollbox-demo.tsx +15 -7
  264. package/src/examples/internal/scrollbox-with-descendants.tsx +94 -0
  265. package/src/examples/internal/simple-dialog.tsx +1 -1
  266. package/src/examples/internal/simple-scrollbox.tsx +8 -5
  267. package/src/examples/internal/simple-scrollbox.vitest.tsx +47 -37
  268. package/src/examples/internal/text-stacking.tsx +4 -2
  269. package/src/examples/list-dropdown-default.tsx +1 -1
  270. package/src/examples/list-dropdown-default.vitest.tsx +136 -71
  271. package/src/examples/list-fetch-data.tsx +1 -1
  272. package/src/examples/list-fetch-data.vitest.tsx +42 -33
  273. package/src/examples/list-scrollbox.tsx +46 -0
  274. package/src/examples/list-scrollbox.vitest.tsx +103 -0
  275. package/src/examples/list-with-detail.tsx +1 -1
  276. package/src/examples/list-with-detail.vitest.tsx +290 -294
  277. package/src/examples/list-with-dropdown.tsx +1 -1
  278. package/src/examples/list-with-dropdown.vitest.tsx +190 -150
  279. package/src/examples/list-with-sections.tsx +12 -1
  280. package/src/examples/list-with-sections.vitest.tsx +390 -218
  281. package/src/examples/miscellaneous.tsx +1 -1
  282. package/src/examples/nested-navigation.tsx +4 -2
  283. package/src/examples/preferences-test.tsx +1 -1
  284. package/src/examples/simple-dropdown.tsx +1 -1
  285. package/src/examples/simple-file-picker.tsx +1 -1
  286. package/src/examples/simple-file-picker.vitest.tsx +538 -132
  287. package/src/examples/simple-grid.tsx +1 -1
  288. package/src/examples/simple-grid.vitest.tsx +258 -234
  289. package/src/examples/simple-hud.tsx +1 -1
  290. package/src/examples/simple-list-search.tsx +1 -1
  291. package/src/examples/simple-list.tsx +1 -1
  292. package/src/examples/simple-navigation.tsx +4 -2
  293. package/src/examples/simple-navigation.vitest.tsx +434 -238
  294. package/src/examples/store.tsx +1 -1
  295. package/src/examples/store.vitest.tsx +31 -10
  296. package/src/examples/submodule-diff.tsx +153 -0
  297. package/src/examples/tanstack-demo.tsx +1 -1
  298. package/src/examples/use-promise-demo.tsx +1 -1
  299. package/src/extensions/dev.tsx +74 -36
  300. package/src/extensions/dev.vitest.tsx +220 -0
  301. package/src/extensions/home.tsx +17 -118
  302. package/src/globals.ts +1 -1
  303. package/src/index.tsx +7 -1
  304. package/src/internal/date-picker-widget.tsx +56 -46
  305. package/src/internal/dialog.tsx +6 -6
  306. package/src/internal/scrollbox.tsx +15 -5
  307. package/src/release.tsx +159 -0
  308. package/src/state.tsx +2 -0
  309. package/src/store-api/search.test.tsx +4 -13
  310. package/src/theme.tsx +33 -8
  311. package/src/utils/run-command.tsx +204 -0
  312. package/src/utils.tsx +5 -3
  313. package/dist/ai.d.ts +0 -104
  314. package/dist/ai.d.ts.map +0 -1
  315. package/dist/ai.js +0 -135
  316. package/dist/ai.js.map +0 -1
  317. package/dist/apis/cache.test.d.ts +0 -2
  318. package/dist/apis/cache.test.d.ts.map +0 -1
  319. package/dist/apis/cache.test.js +0 -246
  320. package/dist/apis/cache.test.js.map +0 -1
  321. package/dist/apis/localstorage.test.d.ts +0 -2
  322. package/dist/apis/localstorage.test.d.ts.map +0 -1
  323. package/dist/apis/localstorage.test.js +0 -131
  324. package/dist/apis/localstorage.test.js.map +0 -1
  325. package/dist/apis/toast.test.d.ts +0 -2
  326. package/dist/apis/toast.test.d.ts.map +0 -1
  327. package/dist/apis/toast.test.js +0 -67
  328. package/dist/apis/toast.test.js.map +0 -1
  329. package/dist/build.test.d.ts +0 -2
  330. package/dist/build.test.d.ts.map +0 -1
  331. package/dist/build.test.js +0 -73
  332. package/dist/build.test.js.map +0 -1
  333. package/dist/cache.d.ts +0 -32
  334. package/dist/cache.d.ts.map +0 -1
  335. package/dist/cache.js +0 -205
  336. package/dist/cache.js.map +0 -1
  337. package/dist/cache.test.d.ts +0 -2
  338. package/dist/cache.test.d.ts.map +0 -1
  339. package/dist/cache.test.js +0 -246
  340. package/dist/cache.test.js.map +0 -1
  341. package/dist/clipboard.d.ts +0 -36
  342. package/dist/clipboard.d.ts.map +0 -1
  343. package/dist/clipboard.js +0 -154
  344. package/dist/clipboard.js.map +0 -1
  345. package/dist/components/form/form-type-only.d.ts +0 -174
  346. package/dist/components/form/form-type-only.d.ts.map +0 -1
  347. package/dist/components/form/form-type-only.js +0 -2
  348. package/dist/components/form/form-type-only.js.map +0 -1
  349. package/dist/components/form/use-form-handling.d.ts +0 -4
  350. package/dist/components/form/use-form-handling.d.ts.map +0 -1
  351. package/dist/components/form/use-form-handling.js +0 -37
  352. package/dist/components/form/use-form-handling.js.map +0 -1
  353. package/dist/dev-ui.d.ts +0 -7
  354. package/dist/dev-ui.d.ts.map +0 -1
  355. package/dist/dev-ui.js +0 -118
  356. package/dist/dev-ui.js.map +0 -1
  357. package/dist/environment.d.ts +0 -63
  358. package/dist/environment.d.ts.map +0 -1
  359. package/dist/environment.js +0 -189
  360. package/dist/environment.js.map +0 -1
  361. package/dist/examples/datepicker.d.ts +0 -2
  362. package/dist/examples/datepicker.d.ts.map +0 -1
  363. package/dist/examples/datepicker.js +0 -344
  364. package/dist/examples/datepicker.js.map +0 -1
  365. package/dist/examples/form-basic-arrow-keys.vitest.d.ts +0 -2
  366. package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +0 -1
  367. package/dist/examples/form-basic-arrow-keys.vitest.js +0 -46
  368. package/dist/examples/form-basic-arrow-keys.vitest.js.map +0 -1
  369. package/dist/examples/form-basic.vitest.d.ts +0 -2
  370. package/dist/examples/form-basic.vitest.d.ts.map +0 -1
  371. package/dist/examples/form-basic.vitest.js +0 -995
  372. package/dist/examples/form-basic.vitest.js.map +0 -1
  373. package/dist/examples/form-dropdown-with-sections.d.ts +0 -2
  374. package/dist/examples/form-dropdown-with-sections.d.ts.map +0 -1
  375. package/dist/examples/form-dropdown-with-sections.js +0 -13
  376. package/dist/examples/form-dropdown-with-sections.js.map +0 -1
  377. package/dist/examples/form-dropdown-with-sections.vitest.d.ts +0 -2
  378. package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +0 -1
  379. package/dist/examples/form-dropdown-with-sections.vitest.js +0 -75
  380. package/dist/examples/form-dropdown-with-sections.vitest.js.map +0 -1
  381. package/dist/examples/form-dropdown.vitest.d.ts +0 -2
  382. package/dist/examples/form-dropdown.vitest.d.ts.map +0 -1
  383. package/dist/examples/form-dropdown.vitest.js +0 -722
  384. package/dist/examples/form-dropdown.vitest.js.map +0 -1
  385. package/dist/examples/form-multiselect-dropdown.d.ts +0 -2
  386. package/dist/examples/form-multiselect-dropdown.d.ts.map +0 -1
  387. package/dist/examples/form-multiselect-dropdown.js +0 -13
  388. package/dist/examples/form-multiselect-dropdown.js.map +0 -1
  389. package/dist/examples/form-tagpicker.vitest.d.ts +0 -2
  390. package/dist/examples/form-tagpicker.vitest.d.ts.map +0 -1
  391. package/dist/examples/form-tagpicker.vitest.js +0 -491
  392. package/dist/examples/form-tagpicker.vitest.js.map +0 -1
  393. package/dist/examples/internal/nested-boxes.d.ts +0 -2
  394. package/dist/examples/internal/nested-boxes.d.ts.map +0 -1
  395. package/dist/examples/internal/nested-boxes.js +0 -7
  396. package/dist/examples/internal/nested-boxes.js.map +0 -1
  397. package/dist/examples/internal/simple-scrollbox.vitest.d.ts +0 -2
  398. package/dist/examples/internal/simple-scrollbox.vitest.d.ts.map +0 -1
  399. package/dist/examples/internal/simple-scrollbox.vitest.js +0 -88
  400. package/dist/examples/internal/simple-scrollbox.vitest.js.map +0 -1
  401. package/dist/examples/internal/unicode-square-repro.d.ts +0 -2
  402. package/dist/examples/internal/unicode-square-repro.d.ts.map +0 -1
  403. package/dist/examples/internal/unicode-square-repro.js +0 -7
  404. package/dist/examples/internal/unicode-square-repro.js.map +0 -1
  405. package/dist/examples/list-dropdown-default.vitest.d.ts +0 -2
  406. package/dist/examples/list-dropdown-default.vitest.d.ts.map +0 -1
  407. package/dist/examples/list-dropdown-default.vitest.js +0 -164
  408. package/dist/examples/list-dropdown-default.vitest.js.map +0 -1
  409. package/dist/examples/list-fetch-data.vitest.d.ts +0 -2
  410. package/dist/examples/list-fetch-data.vitest.d.ts.map +0 -1
  411. package/dist/examples/list-fetch-data.vitest.js +0 -103
  412. package/dist/examples/list-fetch-data.vitest.js.map +0 -1
  413. package/dist/examples/list-filter-navigation.d.ts +0 -2
  414. package/dist/examples/list-filter-navigation.d.ts.map +0 -1
  415. package/dist/examples/list-filter-navigation.js +0 -8
  416. package/dist/examples/list-filter-navigation.js.map +0 -1
  417. package/dist/examples/list-with-detail.vitest.d.ts +0 -2
  418. package/dist/examples/list-with-detail.vitest.d.ts.map +0 -1
  419. package/dist/examples/list-with-detail.vitest.js +0 -438
  420. package/dist/examples/list-with-detail.vitest.js.map +0 -1
  421. package/dist/examples/list-with-dropdown.vitest.d.ts +0 -2
  422. package/dist/examples/list-with-dropdown.vitest.d.ts.map +0 -1
  423. package/dist/examples/list-with-dropdown.vitest.js +0 -297
  424. package/dist/examples/list-with-dropdown.vitest.js.map +0 -1
  425. package/dist/examples/list-with-sections.vitest.d.ts +0 -2
  426. package/dist/examples/list-with-sections.vitest.d.ts.map +0 -1
  427. package/dist/examples/list-with-sections.vitest.js +0 -441
  428. package/dist/examples/list-with-sections.vitest.js.map +0 -1
  429. package/dist/examples/simple-file-picker.vitest.d.ts +0 -2
  430. package/dist/examples/simple-file-picker.vitest.d.ts.map +0 -1
  431. package/dist/examples/simple-file-picker.vitest.js +0 -277
  432. package/dist/examples/simple-file-picker.vitest.js.map +0 -1
  433. package/dist/examples/simple-grid.vitest.d.ts +0 -2
  434. package/dist/examples/simple-grid.vitest.d.ts.map +0 -1
  435. package/dist/examples/simple-grid.vitest.js +0 -498
  436. package/dist/examples/simple-grid.vitest.js.map +0 -1
  437. package/dist/examples/simple-navigation.vitest.d.ts +0 -2
  438. package/dist/examples/simple-navigation.vitest.d.ts.map +0 -1
  439. package/dist/examples/simple-navigation.vitest.js +0 -522
  440. package/dist/examples/simple-navigation.vitest.js.map +0 -1
  441. package/dist/examples/store.vitest.d.ts +0 -2
  442. package/dist/examples/store.vitest.d.ts.map +0 -1
  443. package/dist/examples/store.vitest.js +0 -48
  444. package/dist/examples/store.vitest.js.map +0 -1
  445. package/dist/home-command.d.ts +0 -8
  446. package/dist/home-command.d.ts.map +0 -1
  447. package/dist/home-command.js +0 -181
  448. package/dist/home-command.js.map +0 -1
  449. package/dist/hooks/hooks.test.d.ts +0 -2
  450. package/dist/hooks/hooks.test.d.ts.map +0 -1
  451. package/dist/hooks/hooks.test.js +0 -37
  452. package/dist/hooks/hooks.test.js.map +0 -1
  453. package/dist/hover-repro.d.ts +0 -2
  454. package/dist/hover-repro.d.ts.map +0 -1
  455. package/dist/hover-repro.js +0 -20
  456. package/dist/hover-repro.js.map +0 -1
  457. package/dist/localstorage.d.ts +0 -13
  458. package/dist/localstorage.d.ts.map +0 -1
  459. package/dist/localstorage.js +0 -190
  460. package/dist/localstorage.js.map +0 -1
  461. package/dist/localstorage.test.d.ts +0 -2
  462. package/dist/localstorage.test.d.ts.map +0 -1
  463. package/dist/localstorage.test.js +0 -131
  464. package/dist/localstorage.test.js.map +0 -1
  465. package/dist/oauth.d.ts +0 -142
  466. package/dist/oauth.d.ts.map +0 -1
  467. package/dist/oauth.js +0 -551
  468. package/dist/oauth.js.map +0 -1
  469. package/dist/preferences.d.ts +0 -23
  470. package/dist/preferences.d.ts.map +0 -1
  471. package/dist/preferences.js +0 -105
  472. package/dist/preferences.js.map +0 -1
  473. package/dist/store-api/download.test.d.ts +0 -2
  474. package/dist/store-api/download.test.d.ts.map +0 -1
  475. package/dist/store-api/download.test.js +0 -36
  476. package/dist/store-api/download.test.js.map +0 -1
  477. package/dist/store-api/extension.test.d.ts +0 -2
  478. package/dist/store-api/extension.test.d.ts.map +0 -1
  479. package/dist/store-api/extension.test.js +0 -22
  480. package/dist/store-api/extension.test.js.map +0 -1
  481. package/dist/store-api/search.test.d.ts +0 -2
  482. package/dist/store-api/search.test.d.ts.map +0 -1
  483. package/dist/store-api/search.test.js +0 -45
  484. package/dist/store-api/search.test.js.map +0 -1
  485. package/dist/store.d.ts +0 -21
  486. package/dist/store.d.ts.map +0 -1
  487. package/dist/store.js +0 -84
  488. package/dist/store.js.map +0 -1
  489. package/dist/toast.d.ts +0 -44
  490. package/dist/toast.d.ts.map +0 -1
  491. package/dist/toast.js +0 -221
  492. package/dist/toast.js.map +0 -1
  493. package/dist/utils.test.d.ts +0 -2
  494. package/dist/utils.test.d.ts.map +0 -1
  495. package/dist/utils.test.js +0 -152
  496. package/dist/utils.test.js.map +0 -1
  497. package/dist/window.d.ts +0 -12
  498. package/dist/window.d.ts.map +0 -1
  499. package/dist/window.js +0 -48
  500. package/dist/window.js.map +0 -1
@@ -1,58 +1,78 @@
1
+ import {
2
+ BoxRenderable,
3
+ ScrollBoxRenderable,
4
+ TextAttributes,
5
+ TextareaRenderable,
6
+ } from '@opentui/core'
7
+ import { useKeyboard } from '@opentui/react'
1
8
  import React, {
2
- ReactNode,
3
- ReactElement,
4
- Children,
5
- isValidElement,
6
- useState,
7
- useEffect,
8
- useRef,
9
- Fragment,
10
- useMemo,
11
- useLayoutEffect,
12
- createContext,
13
- useContext,
9
+ ReactElement,
10
+ ReactNode,
11
+ createContext,
12
+ useContext,
13
+ useEffect,
14
+ useLayoutEffect,
15
+ useMemo,
16
+ useRef,
17
+ useState
14
18
  } from 'react'
15
- import { TextAttributes } from '@opentui/core'
16
- import { useKeyboard } from '@opentui/react'
17
- import { logger } from 'termcast/src/logger'
18
- import { Theme } from 'termcast/src/theme'
19
- import { Action, ActionPanel } from 'termcast/src/components/actions'
20
- import { InFocus, useIsInFocus } from 'termcast/src/internal/focus-context'
21
- import { CommonProps } from 'termcast/src/utils'
22
- import { useStore } from 'termcast/src/state'
23
- import { useDialog } from 'termcast/src/internal/dialog'
24
- import { createDescendants } from 'termcast/src/descendants'
25
19
  import { LoadingBar } from 'termcast/src/components/loading-bar'
20
+ import { createDescendants } from 'termcast/src/descendants'
21
+ import { useDialog } from 'termcast/src/internal/dialog'
22
+ import { useIsInFocus } from 'termcast/src/internal/focus-context'
26
23
  import { useNavigationPending } from 'termcast/src/internal/navigation'
24
+ import { ScrollBox } from 'termcast/src/internal/scrollbox'
25
+
26
+ import { Color, resolveColor } from 'termcast/src/colors'
27
+ import { getIconEmoji } from 'termcast/src/components/icon'
28
+ import { Theme, markdownSyntaxStyle } from 'termcast/src/theme'
29
+ import { CommonProps } from 'termcast/src/utils'
30
+
31
+ export { Color }
32
+
33
+ function formatRelativeDate(date: Date): string {
34
+ const now = new Date()
35
+ const diffMs = now.getTime() - date.getTime()
36
+ const diffSec = Math.floor(diffMs / 1000)
37
+ const diffMin = Math.floor(diffSec / 60)
38
+ const diffHour = Math.floor(diffMin / 60)
39
+ const diffDay = Math.floor(diffHour / 24)
40
+ const diffWeek = Math.floor(diffDay / 7)
41
+ const diffMonth = Math.floor(diffDay / 30)
42
+ const diffYear = Math.floor(diffDay / 365)
43
+
44
+ if (diffSec < 60) {
45
+ return 'now'
46
+ }
47
+ if (diffMin < 60) {
48
+ return `${diffMin}m`
49
+ }
50
+ if (diffHour < 24) {
51
+ return `${diffHour}h`
52
+ }
53
+ if (diffDay < 7) {
54
+ return `${diffDay}d`
55
+ }
56
+ if (diffWeek < 4) {
57
+ return `${diffWeek}w`
58
+ }
59
+ if (diffMonth < 12) {
60
+ return `${diffMonth}mo`
61
+ }
62
+ return `${diffYear}y`
63
+ }
27
64
 
28
65
  interface ActionsInterface {
29
66
  actions?: ReactNode
30
67
  }
31
68
 
32
69
  function ListFooter(): any {
33
- const toast = useStore((state) => state.toast)
34
-
35
- if (toast) {
36
- return (
37
- <box
38
- border={false}
39
- style={{
40
- paddingLeft: 1,
41
- paddingRight: 1,
42
- paddingTop: 1,
43
- marginTop: 1,
44
- }}
45
- >
46
- {toast}
47
- </box>
48
- )
49
- }
50
-
51
70
  return (
52
71
  <box
53
72
  border={false}
54
73
  style={{
55
74
  paddingLeft: 1,
75
+ flexShrink: 0,
56
76
  paddingRight: 1,
57
77
  paddingTop: 1,
58
78
  marginTop: 1,
@@ -64,11 +84,11 @@ function ListFooter(): any {
64
84
  </text>
65
85
  <text fg={Theme.textMuted}> select</text>
66
86
  <text fg={Theme.text} attributes={TextAttributes.BOLD}>
67
- {' '}↑↓
87
+ {' '}↑↓
68
88
  </text>
69
89
  <text fg={Theme.textMuted}> navigate</text>
70
90
  <text fg={Theme.text} attributes={TextAttributes.BOLD}>
71
- {' '}^k
91
+ {' '}^k
72
92
  </text>
73
93
  <text fg={Theme.textMuted}> actions</text>
74
94
  </box>
@@ -96,10 +116,8 @@ interface PaginationInterface {
96
116
  }
97
117
  }
98
118
 
99
- export type Color = string
100
-
101
119
  export namespace Image {
102
- export type ImageLike = string
120
+ export type ImageLike = string | { source: string; tintColor?: string }
103
121
  }
104
122
 
105
123
  export type ItemAccessory =
@@ -109,7 +127,7 @@ export type ItemAccessory =
109
127
  | null
110
128
  | {
111
129
  value: string | null
112
- color?: Color
130
+ color?: Color.ColorLike
113
131
  }
114
132
  }
115
133
  | {
@@ -118,7 +136,7 @@ export type ItemAccessory =
118
136
  | null
119
137
  | {
120
138
  value: Date | null
121
- color?: Color
139
+ color?: Color.ColorLike
122
140
  }
123
141
  }
124
142
  | {
@@ -126,7 +144,7 @@ export type ItemAccessory =
126
144
  | string
127
145
  | {
128
146
  value: string
129
- color?: Color
147
+ color?: Color.ColorLike
130
148
  }
131
149
  }
132
150
  | {
@@ -245,7 +263,7 @@ interface ListItemDetailMetadataType {
245
263
 
246
264
  interface ListItemDetailMetadataTagListType {
247
265
  (props: { title: string; children: ReactNode }): any
248
- Item: (props: { text?: string; color?: Color; icon?: Image.ImageLike; onAction?: () => void }) => any
266
+ Item: (props: { text?: string; color?: Color.ColorLike; icon?: Image.ImageLike; onAction?: () => void }) => any
249
267
  }
250
268
 
251
269
  interface ListDropdownType {
@@ -309,6 +327,7 @@ interface ListItemDescendant {
309
327
  actions?: ReactNode
310
328
  visible?: boolean
311
329
  detail?: ReactNode
330
+ elementRef?: { y: number; height: number } | null
312
331
  }
313
332
 
314
333
  const {
@@ -355,7 +374,7 @@ interface ListDropdownDialogProps extends DropdownProps {
355
374
  function ListDropdownDialog(props: ListDropdownDialogProps): any {
356
375
  const [searchText, setSearchTextRaw] = useState('')
357
376
  const [selectedIndex, setSelectedIndex] = useState(0)
358
- const inputRef = useRef<any>(null)
377
+ const inputRef = useRef<TextareaRenderable>(null)
359
378
  const descendantsContext = useDropdownDescendants()
360
379
 
361
380
  // Wrapper function that updates search text
@@ -364,6 +383,7 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
364
383
  setSelectedIndex(0) // Reset selection when search changes
365
384
  }
366
385
 
386
+
367
387
  const move = (direction: -1 | 1) => {
368
388
  // Get all visible items
369
389
  const items = Object.values(descendantsContext.map.current)
@@ -433,12 +453,20 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
433
453
  <text fg={Theme.textMuted}>esc</text>
434
454
  </box>
435
455
  <box style={{ paddingTop: 1, paddingBottom: 1 }}>
436
- <input
456
+ <textarea
437
457
  ref={inputRef}
438
- onInput={setSearchText}
458
+ height={1}
459
+ keyBindings={[
460
+ { name: 'return', action: 'submit' },
461
+ { name: 'linefeed', action: 'submit' },
462
+ ]}
463
+ onContentChange={() => {
464
+ const value = inputRef.current?.plainText || ''
465
+ setSearchText(value)
466
+ }}
439
467
  placeholder={props.placeholder || 'Search...'}
440
468
  focused={inFocus}
441
- value={searchText}
469
+ initialValue={searchText}
442
470
  focusedBackgroundColor={Theme.backgroundPanel}
443
471
  cursorColor={Theme.primary}
444
472
  focusedTextColor={Theme.textMuted}
@@ -499,16 +527,18 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
499
527
  function ListItemRow(props: {
500
528
  title: string
501
529
  subtitle?: string
530
+ icon?: string
531
+ iconColor?: string
502
532
  accessories?: ItemAccessory[]
503
533
  active?: boolean
504
534
  isShowingDetail?: boolean
505
535
  onMouseDown?: () => void
506
536
  index?: number
537
+ ref?: React.Ref<BoxRenderable>
507
538
  }) {
508
- const { title, subtitle, accessories, active } = props
539
+ const { title, subtitle, icon, iconColor, accessories, active, ref } = props
509
540
  const [isHovered, setIsHovered] = useState(false)
510
541
 
511
- // Format accessories for display
512
542
  const accessoryElements: ReactNode[] = []
513
543
  if (accessories) {
514
544
  accessories.forEach((accessory) => {
@@ -517,11 +547,14 @@ function ListItemRow(props: {
517
547
  typeof accessory.text === 'string'
518
548
  ? accessory.text
519
549
  : accessory.text?.value
550
+ const textColor =
551
+ typeof accessory.text === 'object' ? accessory.text?.color : undefined
520
552
  if (textValue) {
521
553
  accessoryElements.push(
522
554
  <text
523
555
  key={`text-${textValue}`}
524
- fg={active ? Theme.background : Theme.info}
556
+ fg={active ? Theme.background : resolveColor(textColor) || Theme.info}
557
+ wrapMode="none"
525
558
  >
526
559
  {textValue}
527
560
  </text>,
@@ -533,22 +566,48 @@ function ListItemRow(props: {
533
566
  typeof accessory.tag === 'string'
534
567
  ? accessory.tag
535
568
  : accessory.tag?.value
569
+ const tagColor =
570
+ typeof accessory.tag === 'object' ? accessory.tag?.color : undefined
536
571
  if (tagValue) {
537
572
  accessoryElements.push(
538
573
  <text
539
574
  key={`tag-${tagValue}`}
540
- fg={active ? Theme.background : Theme.warning}
575
+ fg={active ? Theme.background : resolveColor(tagColor) || Theme.warning}
576
+ wrapMode="none"
541
577
  >
542
578
  [{tagValue}]
543
579
  </text>,
544
580
  )
545
581
  }
546
582
  }
583
+ if ('date' in accessory && accessory.date) {
584
+ const dateValue =
585
+ accessory.date instanceof Date
586
+ ? accessory.date
587
+ : accessory.date?.value
588
+ const dateColor =
589
+ typeof accessory.date === 'object' && !(accessory.date instanceof Date)
590
+ ? accessory.date?.color
591
+ : undefined
592
+ if (dateValue) {
593
+ const formatted = formatRelativeDate(dateValue)
594
+ accessoryElements.push(
595
+ <text
596
+ key={`date-${dateValue.getTime()}`}
597
+ fg={active ? Theme.background : resolveColor(dateColor) || Theme.success}
598
+ wrapMode="none"
599
+ >
600
+ {formatted}
601
+ </text>,
602
+ )
603
+ }
604
+ }
547
605
  })
548
606
  }
549
607
 
550
608
  return (
551
609
  <box
610
+ ref={ref}
552
611
  style={{
553
612
  flexDirection: 'row',
554
613
  justifyContent: 'space-between',
@@ -557,39 +616,44 @@ function ListItemRow(props: {
557
616
  : isHovered
558
617
  ? Theme.backgroundPanel
559
618
  : undefined,
560
- paddingLeft: active ? 0 : 1,
619
+ paddingLeft: 0,
561
620
  paddingRight: 1,
621
+ gap: 1,
562
622
  }}
563
623
  border={false}
564
- onMouseMove={() => setIsHovered(true)}
565
- onMouseOut={() => setIsHovered(false)}
624
+ onMouseMove={() => {
625
+ setIsHovered(true)
626
+ }}
627
+ onMouseOut={() => {
628
+ setIsHovered(false)
629
+ }}
566
630
  onMouseDown={props.onMouseDown}
567
631
  >
568
- <box style={{ flexDirection: 'row', flexGrow: 1, flexShrink: 1 }}>
569
- {active && (
570
- <text fg={Theme.textMuted} selectable={false}>
571
-
632
+ <box style={{ flexDirection: 'row', flexGrow: 1, flexShrink: 1, overflow: 'hidden', gap: 1 }}>
633
+ <box style={{ flexDirection: 'row', flexShrink: 0 }}>
634
+ <text fg={active ? Theme.background : Theme.text} attributes={active ? TextAttributes.BOLD : undefined} selectable={false} wrapMode="none">{active ? '›' : ' '}</text>
635
+ {icon && <text fg={active ? Theme.background : iconColor || Theme.text} selectable={false} wrapMode="none">{getIconEmoji(icon)} </text>}
636
+ <text
637
+ fg={active ? Theme.background : Theme.text}
638
+ attributes={active ? TextAttributes.BOLD : undefined}
639
+ selectable={false}
640
+ wrapMode="none"
641
+ >
642
+ {title}
572
643
  </text>
573
- )}
574
- <text
575
- fg={active ? Theme.background : Theme.text}
576
- attributes={active ? TextAttributes.BOLD : undefined}
577
- selectable={false}
578
- >
579
- {title}
580
- </text>
644
+ </box>
581
645
  {subtitle && (
582
646
  <text
583
647
  fg={active ? Theme.background : Theme.textMuted}
584
648
  selectable={false}
649
+ wrapMode="none"
585
650
  >
586
- {' '}
587
651
  {subtitle}
588
652
  </text>
589
653
  )}
590
654
  </box>
591
655
  {accessoryElements.length > 0 && (
592
- <box style={{ flexDirection: 'row' }}>
656
+ <box style={{ flexDirection: 'row', flexShrink: 0 }}>
593
657
  {accessoryElements.map((elem, i) => (
594
658
  <box key={i} style={{ flexDirection: 'row' }}>
595
659
  {i > 0 && <text> </text>}
@@ -598,7 +662,6 @@ function ListItemRow(props: {
598
662
  ))}
599
663
  </box>
600
664
  )}
601
- {/*{active && <text fg={Theme.textMuted}>‹</text>}*/}
602
665
  </box>
603
666
  )
604
667
  }
@@ -623,7 +686,8 @@ export const List: ListType = (props) => {
623
686
  const [selectedIndex, setSelectedIndex] = useState(0)
624
687
  const [isDropdownOpen, setIsDropdownOpen] = useState(false)
625
688
  const [currentDetail, setCurrentDetail] = useState<ReactNode>(null)
626
- const inputRef = useRef<any>(null)
689
+ const inputRef = useRef<TextareaRenderable>(null)
690
+ const scrollBoxRef = useRef<ScrollBoxRenderable>(null)
627
691
  const descendantsContext = useListDescendants()
628
692
  const navigationPending = useNavigationPending()
629
693
 
@@ -632,6 +696,15 @@ export const List: ListType = (props) => {
632
696
  ? controlledSearchText
633
697
  : internalSearchText
634
698
 
699
+ // Sync controlled searchText → textarea (only when externally controlled)
700
+ useLayoutEffect(() => {
701
+ if (controlledSearchText === undefined) return
702
+ const textarea = inputRef.current
703
+ if (textarea && textarea.plainText !== controlledSearchText) {
704
+ textarea.setText(controlledSearchText)
705
+ }
706
+ }, [controlledSearchText])
707
+
635
708
  // Determine if filtering is enabled
636
709
  // List filters automatically when:
637
710
  // - filtering is not specified (defaults to true) OR filtering is explicitly true
@@ -694,15 +767,36 @@ export const List: ListType = (props) => {
694
767
  }
695
768
  }, [selectedItemId])
696
769
 
770
+ const scrollToItem = (item: { props?: ListItemDescendant }) => {
771
+ const scrollBox = scrollBoxRef.current
772
+ const elementRef = item.props?.elementRef
773
+ if (!scrollBox || !elementRef) return
774
+
775
+ const contentY = scrollBox.content?.y || 0
776
+ const viewportHeight = scrollBox.viewport?.height || 10
777
+ const currentScrollTop = scrollBox.scrollTop || 0
778
+
779
+ const itemTop = elementRef.y - contentY
780
+ const itemBottom = itemTop + elementRef.height
781
+
782
+ const visibleTop = currentScrollTop
783
+ const visibleBottom = currentScrollTop + viewportHeight
784
+
785
+ if (itemTop < visibleTop) {
786
+ scrollBox.scrollTo(itemTop)
787
+ } else if (itemBottom > visibleBottom) {
788
+ scrollBox.scrollTo(itemBottom - viewportHeight)
789
+ }
790
+ }
791
+
697
792
  const move = (direction: -1 | 1) => {
698
- // Get all visible items
699
793
  const items = Object.values(descendantsContext.map.current)
700
794
  .filter((item) => item.index !== -1 && item.props?.visible !== false)
701
795
  .sort((a, b) => a.index - b.index)
702
796
 
703
797
  if (items.length === 0) return
704
798
 
705
- // Find currently selected item's position in visible items
799
+
706
800
  let currentVisibleIndex = items.findIndex(
707
801
  (item) => item.index === selectedIndex,
708
802
  )
@@ -710,11 +804,11 @@ export const List: ListType = (props) => {
710
804
  // If current selection is not visible, select first visible item
711
805
  if (items[0]) {
712
806
  setSelectedIndex(items[0].index)
807
+ scrollToItem(items[0])
713
808
  }
714
809
  return
715
810
  }
716
811
 
717
- // Calculate next visible index
718
812
  let nextVisibleIndex = currentVisibleIndex + direction
719
813
  if (nextVisibleIndex < 0) nextVisibleIndex = items.length - 1
720
814
  if (nextVisibleIndex >= items.length) nextVisibleIndex = 0
@@ -722,10 +816,10 @@ export const List: ListType = (props) => {
722
816
  const nextItem = items[nextVisibleIndex]
723
817
  if (nextItem) {
724
818
  setSelectedIndex(nextItem.index)
819
+ scrollToItem(nextItem)
725
820
  }
726
821
  }
727
822
 
728
- // Handle keyboard navigation
729
823
  const inFocus = useIsInFocus()
730
824
  const dialog = useDialog()
731
825
 
@@ -808,7 +902,7 @@ export const List: ListType = (props) => {
808
902
  )}
809
903
 
810
904
  {/* Search bar with optional dropdown accessory */}
811
- <box>
905
+ <box style={{ flexShrink: 0 }}>
812
906
  <box
813
907
  border={false}
814
908
  style={{
@@ -818,7 +912,6 @@ export const List: ListType = (props) => {
818
912
  marginBottom: 1,
819
913
  flexDirection: 'row',
820
914
  justifyContent: 'space-between',
821
-
822
915
  alignItems: 'center',
823
916
  }}
824
917
  >
@@ -829,12 +922,20 @@ export const List: ListType = (props) => {
829
922
  flexShrink: 1,
830
923
  }}
831
924
  >
832
- <input
925
+ <textarea
833
926
  ref={inputRef}
927
+ height={1}
928
+ keyBindings={[
929
+ { name: 'return', action: 'submit' },
930
+ { name: 'linefeed', action: 'submit' },
931
+ ]}
834
932
  placeholder={searchBarPlaceholder}
835
933
  focused={inFocus && !isDropdownOpen}
836
- value={searchText}
837
- onInput={handleSearchChange}
934
+ initialValue={searchText}
935
+ onContentChange={() => {
936
+ const value = inputRef.current?.plainText || ''
937
+ handleSearchChange(value)
938
+ }}
838
939
  focusedBackgroundColor={Theme.backgroundPanel}
839
940
  cursorColor={Theme.primary}
840
941
  focusedTextColor={Theme.text}
@@ -845,16 +946,32 @@ export const List: ListType = (props) => {
845
946
  </box>
846
947
 
847
948
  {/* Main content area with optional detail view */}
848
- <box style={{ flexDirection: 'row', flexGrow: 1 }}>
949
+ <box style={{ flexDirection: 'row', flexGrow: 1, flexShrink: 1 }}>
849
950
  {/* List content - render children which will register themselves */}
850
- <box style={{ marginTop: 1, width: isShowingDetail ? '50%' : '100%', flexGrow: isShowingDetail ? 0 : 1 }}>
851
- <>
951
+ <box style={{ width: isShowingDetail ? '50%' : '100%', flexGrow: isShowingDetail ? 0 : 1, flexShrink: 1, flexDirection: 'column' }}>
952
+ {/* Scrollable list items */}
953
+ <ScrollBox
954
+ ref={scrollBoxRef}
955
+ focused={false}
956
+ flexGrow={1}
957
+ flexShrink={1}
958
+ style={{
959
+ rootOptions: {
960
+ backgroundColor: undefined,
961
+ },
962
+ scrollbarOptions: {
963
+
964
+ showArrows: true,
965
+
966
+ },
967
+ }}
968
+ >
852
969
  {/* Render children - they will register as descendants */}
853
970
  <ListItemsRenderer>{children}</ListItemsRenderer>
971
+ </ScrollBox>
854
972
 
855
- {/* Footer with keyboard shortcuts or toast */}
856
- <ListFooter />
857
- </>
973
+ {/* Footer with keyboard shortcuts or toast */}
974
+ <ListFooter />
858
975
  </box>
859
976
 
860
977
  {/* Detail panel on the right */}
@@ -907,6 +1024,7 @@ const ListItem: ListItemType = (props) => {
907
1024
  const { sectionTitle } = listSectionContext
908
1025
  const listContext = useContext(ListContext)
909
1026
  const dialog = useDialog()
1027
+ const elementRef = useRef<BoxRenderable>(null)
910
1028
 
911
1029
  // Extract text values for descendant registration
912
1030
  const titleText =
@@ -942,6 +1060,7 @@ const ListItem: ListItemType = (props) => {
942
1060
  actions: props.actions,
943
1061
  visible: isVisible,
944
1062
  detail: props.detail,
1063
+ elementRef: elementRef.current,
945
1064
  })
946
1065
 
947
1066
  // Get selected index from parent List context
@@ -974,16 +1093,40 @@ const ListItem: ListItemType = (props) => {
974
1093
  // Don't show accessories if we're showing detail
975
1094
  const showAccessories = !props.detail && props.accessories
976
1095
 
1096
+ // Get icon string and color from props.icon (can be string or object with value/tintColor)
1097
+ const { iconValue, iconColor } = (() => {
1098
+ if (!props.icon) return { iconValue: undefined, iconColor: undefined }
1099
+ if (typeof props.icon === 'string') return { iconValue: props.icon, iconColor: undefined }
1100
+ const iconObj = props.icon as Record<string, unknown>
1101
+ if ('source' in iconObj && typeof iconObj.source === 'string') {
1102
+ return { iconValue: iconObj.source, iconColor: iconObj.tintColor as string | undefined }
1103
+ }
1104
+ if ('value' in iconObj && iconObj.value) {
1105
+ const val = iconObj.value
1106
+ if (typeof val === 'string') return { iconValue: val, iconColor: undefined }
1107
+ if (typeof val === 'object' && val !== null) {
1108
+ const valObj = val as Record<string, unknown>
1109
+ if ('source' in valObj && typeof valObj.source === 'string') {
1110
+ return { iconValue: valObj.source, iconColor: valObj.tintColor as string | undefined }
1111
+ }
1112
+ }
1113
+ }
1114
+ return { iconValue: undefined, iconColor: undefined }
1115
+ })()
1116
+
977
1117
  // Render the item row directly
978
1118
  return (
979
1119
  <ListItemRow
980
1120
  title={titleText}
981
1121
  subtitle={subtitleText}
1122
+ icon={iconValue}
1123
+ iconColor={iconColor}
982
1124
  accessories={showAccessories ? props.accessories : undefined}
983
1125
  active={isActive}
984
1126
  isShowingDetail={props.detail !== undefined}
985
1127
  onMouseDown={handleMouseDown}
986
1128
  index={index}
1129
+ ref={elementRef}
987
1130
  />
988
1131
  )
989
1132
  }
@@ -999,22 +1142,37 @@ const ListItemDetail: ListItemDetailType = (props) => {
999
1142
  </box>
1000
1143
  )}
1001
1144
 
1002
- {markdown && (
1003
- <box style={{ flexGrow: 1, flexShrink: 1, overflow: 'scroll' }}>
1004
- <text>{markdown}</text>
1005
- </box>
1006
- )}
1145
+ <ScrollBox
1146
+ focused={true}
1147
+ flexGrow={1}
1148
+ flexShrink={1}
1149
+ style={{
1150
+ rootOptions: {
1151
+ backgroundColor: undefined,
1152
+ },
1153
+ scrollbarOptions: {
1007
1154
 
1008
- {metadata && (
1009
- <box
1010
- style={{ paddingTop: 1 }}
1011
- border={['top']}
1012
- borderStyle='single'
1013
- borderColor={Theme.border}
1014
- >
1015
- {metadata}
1155
+ showArrows: true,
1156
+
1157
+ },
1158
+ }}
1159
+ >
1160
+ <box style={{ flexDirection: 'column' }}>
1161
+ {markdown && (
1162
+ <code content={markdown} filetype="markdown" syntaxStyle={markdownSyntaxStyle} drawUnstyledText={false} />
1163
+ )}
1164
+ {metadata && (
1165
+ <box
1166
+ style={{ paddingTop: 1 }}
1167
+ border={['top']}
1168
+ borderStyle='single'
1169
+ borderColor={Theme.border}
1170
+ >
1171
+ {metadata}
1172
+ </box>
1173
+ )}
1016
1174
  </box>
1017
- )}
1175
+ </ScrollBox>
1018
1176
  </box>
1019
1177
  )
1020
1178
  }
@@ -1064,10 +1222,10 @@ const ListItemDetailMetadataTagList = (props: { title: string; children: ReactNo
1064
1222
  )
1065
1223
  }
1066
1224
 
1067
- const ListItemDetailMetadataTagListItem = (props: { text?: string; color?: Color; icon?: Image.ImageLike; onAction?: () => void }) => {
1225
+ const ListItemDetailMetadataTagListItem = (props: { text?: string; color?: Color.ColorLike; icon?: Image.ImageLike; onAction?: () => void }) => {
1068
1226
  return (
1069
1227
  <box style={{ paddingRight: 1 }}>
1070
- <text fg={props.color || Theme.accent}>[{props.text}]</text>
1228
+ <text fg={resolveColor(props.color) || Theme.accent}>[{props.text}]</text>
1071
1229
  </box>
1072
1230
  )
1073
1231
  }
@@ -1382,6 +1540,11 @@ const ListSection = (props: SectionProps) => {
1382
1540
  const listContext = useContext(ListContext)
1383
1541
  const searchText = listContext?.searchText || ''
1384
1542
 
1543
+ // Don't render empty sections
1544
+ if (React.Children.count(props.children) === 0) {
1545
+ return null
1546
+ }
1547
+
1385
1548
  // Create new context with section title and search text
1386
1549
  const sectionContextValue = useMemo(
1387
1550
  () => ({
@@ -1396,14 +1559,13 @@ const ListSection = (props: SectionProps) => {
1396
1559
  const showTitle = props.title && !searchText.trim()
1397
1560
 
1398
1561
  return (
1399
- <>
1562
+ <box style={{ marginBottom: 1 }}>
1400
1563
  {/* Render section title if provided and not searching */}
1401
1564
  {showTitle && (
1402
1565
  <box
1403
1566
  border={false}
1404
1567
  style={{
1405
1568
  paddingLeft: 1,
1406
- paddingTop: 1,
1407
1569
  }}
1408
1570
  >
1409
1571
  <text fg={Theme.accent} attributes={TextAttributes.BOLD}>
@@ -1415,7 +1577,7 @@ const ListSection = (props: SectionProps) => {
1415
1577
  <ListSectionContext.Provider value={sectionContextValue}>
1416
1578
  {props.children}
1417
1579
  </ListSectionContext.Provider>
1418
- </>
1580
+ </box>
1419
1581
  )
1420
1582
  }
1421
1583
 
@@ -1526,9 +1688,14 @@ Grid.Item = (props: GridItemProps) => {
1526
1688
  const { content, getDetailMarkdown, ...itemProps } = props
1527
1689
 
1528
1690
  // Extract image value and tooltip
1529
- const imageValue = typeof content === 'string' ? content : content?.value
1691
+ const imageValue = (() => {
1692
+ if (typeof content === 'string') return content
1693
+ if (content && 'source' in content) return content
1694
+ if (content && 'value' in content) return content.value
1695
+ return undefined
1696
+ })()
1530
1697
  const imageTooltip =
1531
- typeof content === 'object' ? content?.tooltip : undefined
1698
+ typeof content === 'object' && content && 'tooltip' in content ? content.tooltip : undefined
1532
1699
 
1533
1700
  // Convert Grid.Item props to List.Item props
1534
1701
  const listItemProps: ItemProps = {