termcast 1.3.9

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 (699) hide show
  1. package/dist/action-utils.d.ts +25 -0
  2. package/dist/action-utils.d.ts.map +1 -0
  3. package/dist/action-utils.js +209 -0
  4. package/dist/action-utils.js.map +1 -0
  5. package/dist/ai.d.ts +104 -0
  6. package/dist/ai.d.ts.map +1 -0
  7. package/dist/ai.js +135 -0
  8. package/dist/ai.js.map +1 -0
  9. package/dist/apis/ai.d.ts +104 -0
  10. package/dist/apis/ai.d.ts.map +1 -0
  11. package/dist/apis/ai.js +135 -0
  12. package/dist/apis/ai.js.map +1 -0
  13. package/dist/apis/cache.d.ts +84 -0
  14. package/dist/apis/cache.d.ts.map +1 -0
  15. package/dist/apis/cache.js +307 -0
  16. package/dist/apis/cache.js.map +1 -0
  17. package/dist/apis/cache.test.d.ts +2 -0
  18. package/dist/apis/cache.test.d.ts.map +1 -0
  19. package/dist/apis/cache.test.js +246 -0
  20. package/dist/apis/cache.test.js.map +1 -0
  21. package/dist/apis/clipboard.d.ts +36 -0
  22. package/dist/apis/clipboard.d.ts.map +1 -0
  23. package/dist/apis/clipboard.js +154 -0
  24. package/dist/apis/clipboard.js.map +1 -0
  25. package/dist/apis/environment.d.ts +63 -0
  26. package/dist/apis/environment.d.ts.map +1 -0
  27. package/dist/apis/environment.js +189 -0
  28. package/dist/apis/environment.js.map +1 -0
  29. package/dist/apis/hud.d.ts +7 -0
  30. package/dist/apis/hud.d.ts.map +1 -0
  31. package/dist/apis/hud.js +45 -0
  32. package/dist/apis/hud.js.map +1 -0
  33. package/dist/apis/localstorage.d.ts +13 -0
  34. package/dist/apis/localstorage.d.ts.map +1 -0
  35. package/dist/apis/localstorage.js +190 -0
  36. package/dist/apis/localstorage.js.map +1 -0
  37. package/dist/apis/localstorage.test.d.ts +2 -0
  38. package/dist/apis/localstorage.test.d.ts.map +1 -0
  39. package/dist/apis/localstorage.test.js +131 -0
  40. package/dist/apis/localstorage.test.js.map +1 -0
  41. package/dist/apis/oauth.d.ts +142 -0
  42. package/dist/apis/oauth.d.ts.map +1 -0
  43. package/dist/apis/oauth.js +551 -0
  44. package/dist/apis/oauth.js.map +1 -0
  45. package/dist/apis/preferences.d.ts +23 -0
  46. package/dist/apis/preferences.d.ts.map +1 -0
  47. package/dist/apis/preferences.js +105 -0
  48. package/dist/apis/preferences.js.map +1 -0
  49. package/dist/apis/toast.d.ts +81 -0
  50. package/dist/apis/toast.d.ts.map +1 -0
  51. package/dist/apis/toast.js +275 -0
  52. package/dist/apis/toast.js.map +1 -0
  53. package/dist/apis/toast.test.d.ts +2 -0
  54. package/dist/apis/toast.test.d.ts.map +1 -0
  55. package/dist/apis/toast.test.js +67 -0
  56. package/dist/apis/toast.test.js.map +1 -0
  57. package/dist/apis/window.d.ts +12 -0
  58. package/dist/apis/window.d.ts.map +1 -0
  59. package/dist/apis/window.js +47 -0
  60. package/dist/apis/window.js.map +1 -0
  61. package/dist/build.d.ts +15 -0
  62. package/dist/build.d.ts.map +1 -0
  63. package/dist/build.js +213 -0
  64. package/dist/build.js.map +1 -0
  65. package/dist/build.test.d.ts +2 -0
  66. package/dist/build.test.d.ts.map +1 -0
  67. package/dist/build.test.js +73 -0
  68. package/dist/build.test.js.map +1 -0
  69. package/dist/cache.d.ts +32 -0
  70. package/dist/cache.d.ts.map +1 -0
  71. package/dist/cache.js +205 -0
  72. package/dist/cache.js.map +1 -0
  73. package/dist/cache.test.d.ts +2 -0
  74. package/dist/cache.test.d.ts.map +1 -0
  75. package/dist/cache.test.js +246 -0
  76. package/dist/cache.test.js.map +1 -0
  77. package/dist/cli.d.ts +2 -0
  78. package/dist/cli.d.ts.map +1 -0
  79. package/dist/cli.js +278 -0
  80. package/dist/cli.js.map +1 -0
  81. package/dist/clipboard.d.ts +36 -0
  82. package/dist/clipboard.d.ts.map +1 -0
  83. package/dist/clipboard.js +154 -0
  84. package/dist/clipboard.js.map +1 -0
  85. package/dist/colors.d.ts +15 -0
  86. package/dist/colors.d.ts.map +1 -0
  87. package/dist/colors.js +13 -0
  88. package/dist/colors.js.map +1 -0
  89. package/dist/components/actions.d.ts +120 -0
  90. package/dist/components/actions.d.ts.map +1 -0
  91. package/dist/components/actions.js +371 -0
  92. package/dist/components/actions.js.map +1 -0
  93. package/dist/components/alert.d.ts +25 -0
  94. package/dist/components/alert.d.ts.map +1 -0
  95. package/dist/components/alert.js +99 -0
  96. package/dist/components/alert.js.map +1 -0
  97. package/dist/components/detail.d.ts +65 -0
  98. package/dist/components/detail.d.ts.map +1 -0
  99. package/dist/components/detail.js +147 -0
  100. package/dist/components/detail.js.map +1 -0
  101. package/dist/components/dropdown.d.ts +40 -0
  102. package/dist/components/dropdown.d.ts.map +1 -0
  103. package/dist/components/dropdown.js +202 -0
  104. package/dist/components/dropdown.js.map +1 -0
  105. package/dist/components/extension-preferences.d.ts +8 -0
  106. package/dist/components/extension-preferences.d.ts.map +1 -0
  107. package/dist/components/extension-preferences.js +139 -0
  108. package/dist/components/extension-preferences.js.map +1 -0
  109. package/dist/components/form/assign-components.d.ts +2 -0
  110. package/dist/components/form/assign-components.d.ts.map +1 -0
  111. package/dist/components/form/assign-components.js +22 -0
  112. package/dist/components/form/assign-components.js.map +1 -0
  113. package/dist/components/form/checkbox.d.ts +7 -0
  114. package/dist/components/form/checkbox.d.ts.map +1 -0
  115. package/dist/components/form/checkbox.js +46 -0
  116. package/dist/components/form/checkbox.js.map +1 -0
  117. package/dist/components/form/date-picker.d.ts +18 -0
  118. package/dist/components/form/date-picker.d.ts.map +1 -0
  119. package/dist/components/form/date-picker.js +69 -0
  120. package/dist/components/form/date-picker.js.map +1 -0
  121. package/dist/components/form/description.d.ts +7 -0
  122. package/dist/components/form/description.d.ts.map +1 -0
  123. package/dist/components/form/description.js +8 -0
  124. package/dist/components/form/description.js.map +1 -0
  125. package/dist/components/form/dropdown.d.ts +25 -0
  126. package/dist/components/form/dropdown.d.ts.map +1 -0
  127. package/dist/components/form/dropdown.js +286 -0
  128. package/dist/components/form/dropdown.js.map +1 -0
  129. package/dist/components/form/file-autocomplete.d.ts +12 -0
  130. package/dist/components/form/file-autocomplete.d.ts.map +1 -0
  131. package/dist/components/form/file-autocomplete.js +84 -0
  132. package/dist/components/form/file-autocomplete.js.map +1 -0
  133. package/dist/components/form/file-picker.d.ts +31 -0
  134. package/dist/components/form/file-picker.d.ts.map +1 -0
  135. package/dist/components/form/file-picker.js +113 -0
  136. package/dist/components/form/file-picker.js.map +1 -0
  137. package/dist/components/form/form-end.d.ts +2 -0
  138. package/dist/components/form/form-end.d.ts.map +1 -0
  139. package/dist/components/form/form-end.js +6 -0
  140. package/dist/components/form/form-end.js.map +1 -0
  141. package/dist/components/form/form-type-only.d.ts +174 -0
  142. package/dist/components/form/form-type-only.d.ts.map +1 -0
  143. package/dist/components/form/form-type-only.js +2 -0
  144. package/dist/components/form/form-type-only.js.map +1 -0
  145. package/dist/components/form/index.d.ts +46 -0
  146. package/dist/components/form/index.d.ts.map +1 -0
  147. package/dist/components/form/index.js +106 -0
  148. package/dist/components/form/index.js.map +1 -0
  149. package/dist/components/form/password-field.d.ts +7 -0
  150. package/dist/components/form/password-field.d.ts.map +1 -0
  151. package/dist/components/form/password-field.js +34 -0
  152. package/dist/components/form/password-field.js.map +1 -0
  153. package/dist/components/form/separator.d.ts +2 -0
  154. package/dist/components/form/separator.d.ts.map +1 -0
  155. package/dist/components/form/separator.js +8 -0
  156. package/dist/components/form/separator.js.map +1 -0
  157. package/dist/components/form/tagpicker.d.ts +134 -0
  158. package/dist/components/form/tagpicker.d.ts.map +1 -0
  159. package/dist/components/form/tagpicker.js +79 -0
  160. package/dist/components/form/tagpicker.js.map +1 -0
  161. package/dist/components/form/text-area.d.ts +8 -0
  162. package/dist/components/form/text-area.d.ts.map +1 -0
  163. package/dist/components/form/text-area.js +26 -0
  164. package/dist/components/form/text-area.js.map +1 -0
  165. package/dist/components/form/text-field.d.ts +7 -0
  166. package/dist/components/form/text-field.d.ts.map +1 -0
  167. package/dist/components/form/text-field.js +28 -0
  168. package/dist/components/form/text-field.js.map +1 -0
  169. package/dist/components/form/types.d.ts +43 -0
  170. package/dist/components/form/types.d.ts.map +1 -0
  171. package/dist/components/form/types.js +2 -0
  172. package/dist/components/form/types.js.map +1 -0
  173. package/dist/components/form/use-form-handling.d.ts +4 -0
  174. package/dist/components/form/use-form-handling.d.ts.map +1 -0
  175. package/dist/components/form/use-form-handling.js +37 -0
  176. package/dist/components/form/use-form-handling.js.map +1 -0
  177. package/dist/components/form/use-form-navigation.d.ts +8 -0
  178. package/dist/components/form/use-form-navigation.d.ts.map +1 -0
  179. package/dist/components/form/use-form-navigation.js +58 -0
  180. package/dist/components/form/use-form-navigation.js.map +1 -0
  181. package/dist/components/form/with-left-border.d.ts +17 -0
  182. package/dist/components/form/with-left-border.d.ts.map +1 -0
  183. package/dist/components/form/with-left-border.js +10 -0
  184. package/dist/components/form/with-left-border.js.map +1 -0
  185. package/dist/components/icon.d.ts +9 -0
  186. package/dist/components/icon.d.ts.map +1 -0
  187. package/dist/components/icon.js +485 -0
  188. package/dist/components/icon.js.map +1 -0
  189. package/dist/components/image.d.ts +19 -0
  190. package/dist/components/image.d.ts.map +1 -0
  191. package/dist/components/image.js +32 -0
  192. package/dist/components/image.js.map +1 -0
  193. package/dist/components/list.d.ts +234 -0
  194. package/dist/components/list.d.ts.map +1 -0
  195. package/dist/components/list.js +667 -0
  196. package/dist/components/list.js.map +1 -0
  197. package/dist/components/loading-bar.d.ts +8 -0
  198. package/dist/components/loading-bar.d.ts.map +1 -0
  199. package/dist/components/loading-bar.js +107 -0
  200. package/dist/components/loading-bar.js.map +1 -0
  201. package/dist/components/menubar-extra.d.ts +68 -0
  202. package/dist/components/menubar-extra.d.ts.map +1 -0
  203. package/dist/components/menubar-extra.js +39 -0
  204. package/dist/components/menubar-extra.js.map +1 -0
  205. package/dist/descendants.d.ts +25 -0
  206. package/dist/descendants.d.ts.map +1 -0
  207. package/dist/descendants.js +81 -0
  208. package/dist/descendants.js.map +1 -0
  209. package/dist/dev-ui.d.ts +7 -0
  210. package/dist/dev-ui.d.ts.map +1 -0
  211. package/dist/dev-ui.js +118 -0
  212. package/dist/dev-ui.js.map +1 -0
  213. package/dist/e2e-node.d.ts +63 -0
  214. package/dist/e2e-node.d.ts.map +1 -0
  215. package/dist/e2e-node.js +255 -0
  216. package/dist/e2e-node.js.map +1 -0
  217. package/dist/e2e.d.ts +39 -0
  218. package/dist/e2e.d.ts.map +1 -0
  219. package/dist/e2e.js +127 -0
  220. package/dist/e2e.js.map +1 -0
  221. package/dist/environment.d.ts +63 -0
  222. package/dist/environment.d.ts.map +1 -0
  223. package/dist/environment.js +189 -0
  224. package/dist/environment.js.map +1 -0
  225. package/dist/examples/action-show-in-finder.d.ts +2 -0
  226. package/dist/examples/action-show-in-finder.d.ts.map +1 -0
  227. package/dist/examples/action-show-in-finder.js +13 -0
  228. package/dist/examples/action-show-in-finder.js.map +1 -0
  229. package/dist/examples/datepicker.d.ts +2 -0
  230. package/dist/examples/datepicker.d.ts.map +1 -0
  231. package/dist/examples/datepicker.js +344 -0
  232. package/dist/examples/datepicker.js.map +1 -0
  233. package/dist/examples/environment-test.d.ts +2 -0
  234. package/dist/examples/environment-test.d.ts.map +1 -0
  235. package/dist/examples/environment-test.js +28 -0
  236. package/dist/examples/environment-test.js.map +1 -0
  237. package/dist/examples/error-boundary.d.ts +6 -0
  238. package/dist/examples/error-boundary.d.ts.map +1 -0
  239. package/dist/examples/error-boundary.js +67 -0
  240. package/dist/examples/error-boundary.js.map +1 -0
  241. package/dist/examples/form-basic-arrow-keys.vitest.d.ts +2 -0
  242. package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +1 -0
  243. package/dist/examples/form-basic-arrow-keys.vitest.js +46 -0
  244. package/dist/examples/form-basic-arrow-keys.vitest.js.map +1 -0
  245. package/dist/examples/form-basic.d.ts +2 -0
  246. package/dist/examples/form-basic.d.ts.map +1 -0
  247. package/dist/examples/form-basic.js +21 -0
  248. package/dist/examples/form-basic.js.map +1 -0
  249. package/dist/examples/form-basic.vitest.d.ts +2 -0
  250. package/dist/examples/form-basic.vitest.d.ts.map +1 -0
  251. package/dist/examples/form-basic.vitest.js +995 -0
  252. package/dist/examples/form-basic.vitest.js.map +1 -0
  253. package/dist/examples/form-dropdown-with-sections.d.ts +2 -0
  254. package/dist/examples/form-dropdown-with-sections.d.ts.map +1 -0
  255. package/dist/examples/form-dropdown-with-sections.js +13 -0
  256. package/dist/examples/form-dropdown-with-sections.js.map +1 -0
  257. package/dist/examples/form-dropdown-with-sections.vitest.d.ts +2 -0
  258. package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +1 -0
  259. package/dist/examples/form-dropdown-with-sections.vitest.js +75 -0
  260. package/dist/examples/form-dropdown-with-sections.vitest.js.map +1 -0
  261. package/dist/examples/form-dropdown.d.ts +2 -0
  262. package/dist/examples/form-dropdown.d.ts.map +1 -0
  263. package/dist/examples/form-dropdown.js +13 -0
  264. package/dist/examples/form-dropdown.js.map +1 -0
  265. package/dist/examples/form-dropdown.vitest.d.ts +2 -0
  266. package/dist/examples/form-dropdown.vitest.d.ts.map +1 -0
  267. package/dist/examples/form-dropdown.vitest.js +722 -0
  268. package/dist/examples/form-dropdown.vitest.js.map +1 -0
  269. package/dist/examples/form-multiselect-dropdown.d.ts +2 -0
  270. package/dist/examples/form-multiselect-dropdown.d.ts.map +1 -0
  271. package/dist/examples/form-multiselect-dropdown.js +13 -0
  272. package/dist/examples/form-multiselect-dropdown.js.map +1 -0
  273. package/dist/examples/form-tagpicker.d.ts +2 -0
  274. package/dist/examples/form-tagpicker.d.ts.map +1 -0
  275. package/dist/examples/form-tagpicker.js +13 -0
  276. package/dist/examples/form-tagpicker.js.map +1 -0
  277. package/dist/examples/form-tagpicker.vitest.d.ts +2 -0
  278. package/dist/examples/form-tagpicker.vitest.d.ts.map +1 -0
  279. package/dist/examples/form-tagpicker.vitest.js +491 -0
  280. package/dist/examples/form-tagpicker.vitest.js.map +1 -0
  281. package/dist/examples/internal/descendants-filtering.d.ts +2 -0
  282. package/dist/examples/internal/descendants-filtering.d.ts.map +1 -0
  283. package/dist/examples/internal/descendants-filtering.js +144 -0
  284. package/dist/examples/internal/descendants-filtering.js.map +1 -0
  285. package/dist/examples/internal/descendants.d.ts +2 -0
  286. package/dist/examples/internal/descendants.d.ts.map +1 -0
  287. package/dist/examples/internal/descendants.js +134 -0
  288. package/dist/examples/internal/descendants.js.map +1 -0
  289. package/dist/examples/internal/nested-boxes.d.ts +2 -0
  290. package/dist/examples/internal/nested-boxes.d.ts.map +1 -0
  291. package/dist/examples/internal/nested-boxes.js +7 -0
  292. package/dist/examples/internal/nested-boxes.js.map +1 -0
  293. package/dist/examples/internal/scrollbox-demo.d.ts +2 -0
  294. package/dist/examples/internal/scrollbox-demo.d.ts.map +1 -0
  295. package/dist/examples/internal/scrollbox-demo.js +104 -0
  296. package/dist/examples/internal/scrollbox-demo.js.map +1 -0
  297. package/dist/examples/internal/simple-dialog.d.ts +2 -0
  298. package/dist/examples/internal/simple-dialog.d.ts.map +1 -0
  299. package/dist/examples/internal/simple-dialog.js +43 -0
  300. package/dist/examples/internal/simple-dialog.js.map +1 -0
  301. package/dist/examples/internal/text-stacking.d.ts +2 -0
  302. package/dist/examples/internal/text-stacking.d.ts.map +1 -0
  303. package/dist/examples/internal/text-stacking.js +53 -0
  304. package/dist/examples/internal/text-stacking.js.map +1 -0
  305. package/dist/examples/internal/unicode-square-repro.d.ts +2 -0
  306. package/dist/examples/internal/unicode-square-repro.d.ts.map +1 -0
  307. package/dist/examples/internal/unicode-square-repro.js +7 -0
  308. package/dist/examples/internal/unicode-square-repro.js.map +1 -0
  309. package/dist/examples/list-dropdown-default.d.ts +2 -0
  310. package/dist/examples/list-dropdown-default.d.ts.map +1 -0
  311. package/dist/examples/list-dropdown-default.js +14 -0
  312. package/dist/examples/list-dropdown-default.js.map +1 -0
  313. package/dist/examples/list-dropdown-default.vitest.d.ts +2 -0
  314. package/dist/examples/list-dropdown-default.vitest.d.ts.map +1 -0
  315. package/dist/examples/list-dropdown-default.vitest.js +164 -0
  316. package/dist/examples/list-dropdown-default.vitest.js.map +1 -0
  317. package/dist/examples/list-fetch-data.d.ts +2 -0
  318. package/dist/examples/list-fetch-data.d.ts.map +1 -0
  319. package/dist/examples/list-fetch-data.js +87 -0
  320. package/dist/examples/list-fetch-data.js.map +1 -0
  321. package/dist/examples/list-fetch-data.vitest.d.ts +2 -0
  322. package/dist/examples/list-fetch-data.vitest.d.ts.map +1 -0
  323. package/dist/examples/list-fetch-data.vitest.js +103 -0
  324. package/dist/examples/list-fetch-data.vitest.js.map +1 -0
  325. package/dist/examples/list-filter-navigation.d.ts +2 -0
  326. package/dist/examples/list-filter-navigation.d.ts.map +1 -0
  327. package/dist/examples/list-filter-navigation.js +8 -0
  328. package/dist/examples/list-filter-navigation.js.map +1 -0
  329. package/dist/examples/list-with-detail.d.ts +2 -0
  330. package/dist/examples/list-with-detail.d.ts.map +1 -0
  331. package/dist/examples/list-with-detail.js +94 -0
  332. package/dist/examples/list-with-detail.js.map +1 -0
  333. package/dist/examples/list-with-detail.vitest.d.ts +2 -0
  334. package/dist/examples/list-with-detail.vitest.d.ts.map +1 -0
  335. package/dist/examples/list-with-detail.vitest.js +438 -0
  336. package/dist/examples/list-with-detail.vitest.js.map +1 -0
  337. package/dist/examples/list-with-dropdown.d.ts +2 -0
  338. package/dist/examples/list-with-dropdown.d.ts.map +1 -0
  339. package/dist/examples/list-with-dropdown.js +43 -0
  340. package/dist/examples/list-with-dropdown.js.map +1 -0
  341. package/dist/examples/list-with-dropdown.vitest.d.ts +2 -0
  342. package/dist/examples/list-with-dropdown.vitest.d.ts.map +1 -0
  343. package/dist/examples/list-with-dropdown.vitest.js +297 -0
  344. package/dist/examples/list-with-dropdown.vitest.js.map +1 -0
  345. package/dist/examples/list-with-sections.d.ts +2 -0
  346. package/dist/examples/list-with-sections.d.ts.map +1 -0
  347. package/dist/examples/list-with-sections.js +67 -0
  348. package/dist/examples/list-with-sections.js.map +1 -0
  349. package/dist/examples/list-with-sections.vitest.d.ts +2 -0
  350. package/dist/examples/list-with-sections.vitest.d.ts.map +1 -0
  351. package/dist/examples/list-with-sections.vitest.js +441 -0
  352. package/dist/examples/list-with-sections.vitest.js.map +1 -0
  353. package/dist/examples/miscellaneous.d.ts +2 -0
  354. package/dist/examples/miscellaneous.d.ts.map +1 -0
  355. package/dist/examples/miscellaneous.js +313 -0
  356. package/dist/examples/miscellaneous.js.map +1 -0
  357. package/dist/examples/nested-navigation.d.ts +2 -0
  358. package/dist/examples/nested-navigation.d.ts.map +1 -0
  359. package/dist/examples/nested-navigation.js +35 -0
  360. package/dist/examples/nested-navigation.js.map +1 -0
  361. package/dist/examples/preferences-test.d.ts +2 -0
  362. package/dist/examples/preferences-test.d.ts.map +1 -0
  363. package/dist/examples/preferences-test.js +43 -0
  364. package/dist/examples/preferences-test.js.map +1 -0
  365. package/dist/examples/simple-dropdown.d.ts +2 -0
  366. package/dist/examples/simple-dropdown.d.ts.map +1 -0
  367. package/dist/examples/simple-dropdown.js +15 -0
  368. package/dist/examples/simple-dropdown.js.map +1 -0
  369. package/dist/examples/simple-file-picker.d.ts +2 -0
  370. package/dist/examples/simple-file-picker.d.ts.map +1 -0
  371. package/dist/examples/simple-file-picker.js +21 -0
  372. package/dist/examples/simple-file-picker.js.map +1 -0
  373. package/dist/examples/simple-file-picker.vitest.d.ts +2 -0
  374. package/dist/examples/simple-file-picker.vitest.d.ts.map +1 -0
  375. package/dist/examples/simple-file-picker.vitest.js +277 -0
  376. package/dist/examples/simple-file-picker.vitest.js.map +1 -0
  377. package/dist/examples/simple-grid.d.ts +2 -0
  378. package/dist/examples/simple-grid.d.ts.map +1 -0
  379. package/dist/examples/simple-grid.js +51 -0
  380. package/dist/examples/simple-grid.js.map +1 -0
  381. package/dist/examples/simple-grid.vitest.d.ts +2 -0
  382. package/dist/examples/simple-grid.vitest.d.ts.map +1 -0
  383. package/dist/examples/simple-grid.vitest.js +498 -0
  384. package/dist/examples/simple-grid.vitest.js.map +1 -0
  385. package/dist/examples/simple-hud.d.ts +2 -0
  386. package/dist/examples/simple-hud.d.ts.map +1 -0
  387. package/dist/examples/simple-hud.js +18 -0
  388. package/dist/examples/simple-hud.js.map +1 -0
  389. package/dist/examples/simple-list-search.d.ts +2 -0
  390. package/dist/examples/simple-list-search.d.ts.map +1 -0
  391. package/dist/examples/simple-list-search.js +26 -0
  392. package/dist/examples/simple-list-search.js.map +1 -0
  393. package/dist/examples/simple-list.d.ts +2 -0
  394. package/dist/examples/simple-list.d.ts.map +1 -0
  395. package/dist/examples/simple-list.js +50 -0
  396. package/dist/examples/simple-list.js.map +1 -0
  397. package/dist/examples/simple-navigation.d.ts +2 -0
  398. package/dist/examples/simple-navigation.d.ts.map +1 -0
  399. package/dist/examples/simple-navigation.js +36 -0
  400. package/dist/examples/simple-navigation.js.map +1 -0
  401. package/dist/examples/simple-navigation.vitest.d.ts +2 -0
  402. package/dist/examples/simple-navigation.vitest.d.ts.map +1 -0
  403. package/dist/examples/simple-navigation.vitest.js +522 -0
  404. package/dist/examples/simple-navigation.vitest.js.map +1 -0
  405. package/dist/examples/store.d.ts +2 -0
  406. package/dist/examples/store.d.ts.map +1 -0
  407. package/dist/examples/store.js +5 -0
  408. package/dist/examples/store.js.map +1 -0
  409. package/dist/examples/store.vitest.d.ts +2 -0
  410. package/dist/examples/store.vitest.d.ts.map +1 -0
  411. package/dist/examples/store.vitest.js +52 -0
  412. package/dist/examples/store.vitest.js.map +1 -0
  413. package/dist/examples/tanstack-demo.d.ts +2 -0
  414. package/dist/examples/tanstack-demo.d.ts.map +1 -0
  415. package/dist/examples/tanstack-demo.js +51 -0
  416. package/dist/examples/tanstack-demo.js.map +1 -0
  417. package/dist/examples/use-promise-demo.d.ts +2 -0
  418. package/dist/examples/use-promise-demo.d.ts.map +1 -0
  419. package/dist/examples/use-promise-demo.js +45 -0
  420. package/dist/examples/use-promise-demo.js.map +1 -0
  421. package/dist/extensions/dev.d.ts +7 -0
  422. package/dist/extensions/dev.d.ts.map +1 -0
  423. package/dist/extensions/dev.js +124 -0
  424. package/dist/extensions/dev.js.map +1 -0
  425. package/dist/extensions/home.d.ts +8 -0
  426. package/dist/extensions/home.d.ts.map +1 -0
  427. package/dist/extensions/home.js +184 -0
  428. package/dist/extensions/home.js.map +1 -0
  429. package/dist/extensions/store.d.ts +6 -0
  430. package/dist/extensions/store.d.ts.map +1 -0
  431. package/dist/extensions/store.js +203 -0
  432. package/dist/extensions/store.js.map +1 -0
  433. package/dist/globals.d.ts +9 -0
  434. package/dist/globals.d.ts.map +1 -0
  435. package/dist/globals.js +21 -0
  436. package/dist/globals.js.map +1 -0
  437. package/dist/home-command.d.ts +8 -0
  438. package/dist/home-command.d.ts.map +1 -0
  439. package/dist/home-command.js +181 -0
  440. package/dist/home-command.js.map +1 -0
  441. package/dist/hooks/hooks.test.d.ts +2 -0
  442. package/dist/hooks/hooks.test.d.ts.map +1 -0
  443. package/dist/hooks/hooks.test.js +37 -0
  444. package/dist/hooks/hooks.test.js.map +1 -0
  445. package/dist/hooks/index.d.ts +6 -0
  446. package/dist/hooks/index.d.ts.map +1 -0
  447. package/dist/hooks/index.js +6 -0
  448. package/dist/hooks/index.js.map +1 -0
  449. package/dist/hooks/use-action-panel.d.ts +16 -0
  450. package/dist/hooks/use-action-panel.d.ts.map +1 -0
  451. package/dist/hooks/use-action-panel.js +19 -0
  452. package/dist/hooks/use-action-panel.js.map +1 -0
  453. package/dist/hooks/use-id.d.ts +9 -0
  454. package/dist/hooks/use-id.d.ts.map +1 -0
  455. package/dist/hooks/use-id.js +17 -0
  456. package/dist/hooks/use-id.js.map +1 -0
  457. package/dist/hooks/use-unstable-ai.d.ts +9 -0
  458. package/dist/hooks/use-unstable-ai.d.ts.map +1 -0
  459. package/dist/hooks/use-unstable-ai.js +13 -0
  460. package/dist/hooks/use-unstable-ai.js.map +1 -0
  461. package/dist/hooks.d.ts +10 -0
  462. package/dist/hooks.d.ts.map +1 -0
  463. package/dist/hooks.js +20 -0
  464. package/dist/hooks.js.map +1 -0
  465. package/dist/hover-repro.d.ts +2 -0
  466. package/dist/hover-repro.d.ts.map +1 -0
  467. package/dist/hover-repro.js +20 -0
  468. package/dist/hover-repro.js.map +1 -0
  469. package/dist/index.d.ts +58 -0
  470. package/dist/index.d.ts.map +1 -0
  471. package/dist/index.js +71 -0
  472. package/dist/index.js.map +1 -0
  473. package/dist/internal/date-picker-widget.d.ts +9 -0
  474. package/dist/internal/date-picker-widget.d.ts.map +1 -0
  475. package/dist/internal/date-picker-widget.js +380 -0
  476. package/dist/internal/date-picker-widget.js.map +1 -0
  477. package/dist/internal/dialog.d.ts +21 -0
  478. package/dist/internal/dialog.d.ts.map +1 -0
  479. package/dist/internal/dialog.js +122 -0
  480. package/dist/internal/dialog.js.map +1 -0
  481. package/dist/internal/error-handler.d.ts +2 -0
  482. package/dist/internal/error-handler.d.ts.map +1 -0
  483. package/dist/internal/error-handler.js +29 -0
  484. package/dist/internal/error-handler.js.map +1 -0
  485. package/dist/internal/focus-context.d.ts +10 -0
  486. package/dist/internal/focus-context.d.ts.map +1 -0
  487. package/dist/internal/focus-context.js +12 -0
  488. package/dist/internal/focus-context.js.map +1 -0
  489. package/dist/internal/navigation.d.ts +18 -0
  490. package/dist/internal/navigation.d.ts.map +1 -0
  491. package/dist/internal/navigation.js +83 -0
  492. package/dist/internal/navigation.js.map +1 -0
  493. package/dist/internal/providers.d.ts +8 -0
  494. package/dist/internal/providers.d.ts.map +1 -0
  495. package/dist/internal/providers.js +262 -0
  496. package/dist/internal/providers.js.map +1 -0
  497. package/dist/localstorage.d.ts +13 -0
  498. package/dist/localstorage.d.ts.map +1 -0
  499. package/dist/localstorage.js +190 -0
  500. package/dist/localstorage.js.map +1 -0
  501. package/dist/localstorage.test.d.ts +2 -0
  502. package/dist/localstorage.test.d.ts.map +1 -0
  503. package/dist/localstorage.test.js +131 -0
  504. package/dist/localstorage.test.js.map +1 -0
  505. package/dist/logger.d.ts +7 -0
  506. package/dist/logger.d.ts.map +1 -0
  507. package/dist/logger.js +70 -0
  508. package/dist/logger.js.map +1 -0
  509. package/dist/oauth.d.ts +142 -0
  510. package/dist/oauth.d.ts.map +1 -0
  511. package/dist/oauth.js +551 -0
  512. package/dist/oauth.js.map +1 -0
  513. package/dist/package-json.d.ts +84 -0
  514. package/dist/package-json.d.ts.map +1 -0
  515. package/dist/package-json.js +77 -0
  516. package/dist/package-json.js.map +1 -0
  517. package/dist/preferences.d.ts +23 -0
  518. package/dist/preferences.d.ts.map +1 -0
  519. package/dist/preferences.js +105 -0
  520. package/dist/preferences.js.map +1 -0
  521. package/dist/preload.d.ts +2 -0
  522. package/dist/preload.d.ts.map +1 -0
  523. package/dist/preload.js +28 -0
  524. package/dist/preload.js.map +1 -0
  525. package/dist/state.d.ts +26 -0
  526. package/dist/state.d.ts.map +1 -0
  527. package/dist/state.js +18 -0
  528. package/dist/state.js.map +1 -0
  529. package/dist/store-api/download.d.ts +8 -0
  530. package/dist/store-api/download.d.ts.map +1 -0
  531. package/dist/store-api/download.js +37 -0
  532. package/dist/store-api/download.js.map +1 -0
  533. package/dist/store-api/download.test.d.ts +2 -0
  534. package/dist/store-api/download.test.d.ts.map +1 -0
  535. package/dist/store-api/download.test.js +36 -0
  536. package/dist/store-api/download.test.js.map +1 -0
  537. package/dist/store-api/extension.d.ts +87 -0
  538. package/dist/store-api/extension.d.ts.map +1 -0
  539. package/dist/store-api/extension.js +23 -0
  540. package/dist/store-api/extension.js.map +1 -0
  541. package/dist/store-api/extension.test.d.ts +2 -0
  542. package/dist/store-api/extension.test.d.ts.map +1 -0
  543. package/dist/store-api/extension.test.js +22 -0
  544. package/dist/store-api/extension.test.js.map +1 -0
  545. package/dist/store-api/search.d.ts +101 -0
  546. package/dist/store-api/search.d.ts.map +1 -0
  547. package/dist/store-api/search.js +29 -0
  548. package/dist/store-api/search.js.map +1 -0
  549. package/dist/store-api/search.test.d.ts +2 -0
  550. package/dist/store-api/search.test.d.ts.map +1 -0
  551. package/dist/store-api/search.test.js +45 -0
  552. package/dist/store-api/search.test.js.map +1 -0
  553. package/dist/store.d.ts +21 -0
  554. package/dist/store.d.ts.map +1 -0
  555. package/dist/store.js +84 -0
  556. package/dist/store.js.map +1 -0
  557. package/dist/theme.d.ts +20 -0
  558. package/dist/theme.d.ts.map +1 -0
  559. package/dist/theme.js +26 -0
  560. package/dist/theme.js.map +1 -0
  561. package/dist/toast.d.ts +44 -0
  562. package/dist/toast.d.ts.map +1 -0
  563. package/dist/toast.js +221 -0
  564. package/dist/toast.js.map +1 -0
  565. package/dist/utils/file-system.d.ts +11 -0
  566. package/dist/utils/file-system.d.ts.map +1 -0
  567. package/dist/utils/file-system.js +66 -0
  568. package/dist/utils/file-system.js.map +1 -0
  569. package/dist/utils.d.ts +234 -0
  570. package/dist/utils.d.ts.map +1 -0
  571. package/dist/utils.js +473 -0
  572. package/dist/utils.js.map +1 -0
  573. package/dist/utils.test.d.ts +2 -0
  574. package/dist/utils.test.d.ts.map +1 -0
  575. package/dist/utils.test.js +152 -0
  576. package/dist/utils.test.js.map +1 -0
  577. package/dist/window.d.ts +12 -0
  578. package/dist/window.d.ts.map +1 -0
  579. package/dist/window.js +48 -0
  580. package/dist/window.js.map +1 -0
  581. package/package.json +56 -0
  582. package/src/action-utils.tsx +207 -0
  583. package/src/apis/ai.tsx +177 -0
  584. package/src/apis/cache.test.ts +311 -0
  585. package/src/apis/cache.tsx +394 -0
  586. package/src/apis/clipboard.tsx +200 -0
  587. package/src/apis/environment.tsx +239 -0
  588. package/src/apis/hud.tsx +86 -0
  589. package/src/apis/localstorage.test.ts +164 -0
  590. package/src/apis/localstorage.tsx +215 -0
  591. package/src/apis/oauth.tsx +744 -0
  592. package/src/apis/preferences.tsx +140 -0
  593. package/src/apis/toast.tsx +388 -0
  594. package/src/apis/window.tsx +61 -0
  595. package/src/build.test.tsx +78 -0
  596. package/src/build.tsx +273 -0
  597. package/src/cli.tsx +328 -0
  598. package/src/colors.tsx +15 -0
  599. package/src/components/actions.tsx +718 -0
  600. package/src/components/alert.tsx +205 -0
  601. package/src/components/detail.tsx +359 -0
  602. package/src/components/dropdown.tsx +438 -0
  603. package/src/components/extension-preferences.tsx +269 -0
  604. package/src/components/form/assign-components.tsx +22 -0
  605. package/src/components/form/checkbox.tsx +96 -0
  606. package/src/components/form/date-picker.tsx +125 -0
  607. package/src/components/form/description.tsx +30 -0
  608. package/src/components/form/dropdown.tsx +512 -0
  609. package/src/components/form/file-autocomplete.tsx +141 -0
  610. package/src/components/form/file-picker.tsx +233 -0
  611. package/src/components/form/form-end.tsx +6 -0
  612. package/src/components/form/index.tsx +242 -0
  613. package/src/components/form/password-field.tsx +87 -0
  614. package/src/components/form/separator.tsx +15 -0
  615. package/src/components/form/tagpicker.tsx +245 -0
  616. package/src/components/form/text-area.tsx +82 -0
  617. package/src/components/form/text-field.tsx +82 -0
  618. package/src/components/form/types.tsx +49 -0
  619. package/src/components/form/use-form-navigation.tsx +65 -0
  620. package/src/components/form/with-left-border.tsx +53 -0
  621. package/src/components/icon.tsx +496 -0
  622. package/src/components/image.tsx +54 -0
  623. package/src/components/list.tsx +1564 -0
  624. package/src/components/loading-bar.tsx +141 -0
  625. package/src/components/menubar-extra.tsx +181 -0
  626. package/src/descendants.tsx +134 -0
  627. package/src/e2e-node.tsx +303 -0
  628. package/src/e2e.tsx +147 -0
  629. package/src/examples/action-show-in-finder.tsx +80 -0
  630. package/src/examples/environment-test.tsx +50 -0
  631. package/src/examples/error-boundary.tsx +217 -0
  632. package/src/examples/form-basic.tsx +122 -0
  633. package/src/examples/form-basic.vitest.tsx +1035 -0
  634. package/src/examples/form-dropdown.tsx +102 -0
  635. package/src/examples/form-dropdown.vitest.tsx +758 -0
  636. package/src/examples/form-tagpicker.tsx +66 -0
  637. package/src/examples/form-tagpicker.vitest.tsx +523 -0
  638. package/src/examples/internal/descendants-filtering.tsx +223 -0
  639. package/src/examples/internal/descendants.tsx +208 -0
  640. package/src/examples/internal/scrollbox-demo.tsx +149 -0
  641. package/src/examples/internal/simple-dialog.tsx +124 -0
  642. package/src/examples/internal/text-stacking.tsx +90 -0
  643. package/src/examples/list-dropdown-default.tsx +69 -0
  644. package/src/examples/list-dropdown-default.vitest.tsx +187 -0
  645. package/src/examples/list-fetch-data.tsx +123 -0
  646. package/src/examples/list-fetch-data.vitest.tsx +110 -0
  647. package/src/examples/list-with-detail.tsx +161 -0
  648. package/src/examples/list-with-detail.vitest.tsx +468 -0
  649. package/src/examples/list-with-dropdown.tsx +97 -0
  650. package/src/examples/list-with-dropdown.vitest.tsx +324 -0
  651. package/src/examples/list-with-sections.tsx +196 -0
  652. package/src/examples/list-with-sections.vitest.tsx +479 -0
  653. package/src/examples/miscellaneous.tsx +780 -0
  654. package/src/examples/nested-navigation.tsx +118 -0
  655. package/src/examples/preferences-test.tsx +82 -0
  656. package/src/examples/simple-dropdown.tsx +95 -0
  657. package/src/examples/simple-file-picker.tsx +75 -0
  658. package/src/examples/simple-file-picker.vitest.tsx +306 -0
  659. package/src/examples/simple-grid.tsx +149 -0
  660. package/src/examples/simple-grid.vitest.tsx +535 -0
  661. package/src/examples/simple-hud.tsx +60 -0
  662. package/src/examples/simple-list-search.tsx +93 -0
  663. package/src/examples/simple-list.tsx +149 -0
  664. package/src/examples/simple-navigation.tsx +89 -0
  665. package/src/examples/simple-navigation.vitest.tsx +571 -0
  666. package/src/examples/store.tsx +4 -0
  667. package/src/examples/store.vitest.tsx +59 -0
  668. package/src/examples/tanstack-demo.tsx +104 -0
  669. package/src/examples/use-promise-demo.tsx +96 -0
  670. package/src/extensions/dev.tsx +215 -0
  671. package/src/extensions/home.tsx +332 -0
  672. package/src/extensions/store.tsx +375 -0
  673. package/src/globals.ts +34 -0
  674. package/src/hooks/index.tsx +8 -0
  675. package/src/hooks/use-action-panel.tsx +28 -0
  676. package/src/hooks/use-id.tsx +19 -0
  677. package/src/hooks/use-unstable-ai.tsx +15 -0
  678. package/src/hooks.tsx +22 -0
  679. package/src/index.tsx +240 -0
  680. package/src/internal/date-picker-widget.tsx +500 -0
  681. package/src/internal/dialog.tsx +202 -0
  682. package/src/internal/error-handler.tsx +32 -0
  683. package/src/internal/focus-context.tsx +23 -0
  684. package/src/internal/navigation.tsx +149 -0
  685. package/src/internal/providers.tsx +430 -0
  686. package/src/logger.tsx +84 -0
  687. package/src/package-json.tsx +197 -0
  688. package/src/preload.tsx +32 -0
  689. package/src/state.tsx +49 -0
  690. package/src/store-api/download.test.tsx +38 -0
  691. package/src/store-api/download.tsx +52 -0
  692. package/src/store-api/extension.test.tsx +24 -0
  693. package/src/store-api/extension.tsx +123 -0
  694. package/src/store-api/search.test.tsx +50 -0
  695. package/src/store-api/search.tsx +146 -0
  696. package/src/theme.tsx +31 -0
  697. package/src/utils/file-system.ts +87 -0
  698. package/src/utils.test.tsx +204 -0
  699. package/src/utils.tsx +657 -0
@@ -0,0 +1,223 @@
1
+ // This example shows how to filter descendants by passing search query via context
2
+ // Items conditionally render null when they don't match the search
3
+ import { useKeyboard } from '@opentui/react'
4
+ import { createDescendants } from 'termcast/src/descendants'
5
+ import { createContext, useContext, useState } from 'react'
6
+ import { renderWithProviders } from '../../utils'
7
+ import { logger } from 'termcast/src/logger'
8
+
9
+ const { DescendantsProvider, useDescendants, useDescendant } =
10
+ createDescendants<{
11
+ title?: string
12
+ filtered?: boolean
13
+ }>()
14
+
15
+ const itemsPerPage = 6
16
+
17
+ const MenuContext = createContext<{
18
+ focusedIndex: number
19
+ offset: number
20
+ itemsPerPage: number
21
+ selectedIds: Set<string>
22
+ searchQuery: string
23
+ }>({
24
+ focusedIndex: 0,
25
+ offset: 0,
26
+ itemsPerPage,
27
+ selectedIds: new Set(),
28
+ searchQuery: '',
29
+ })
30
+
31
+ // Menu component with integrated search input
32
+ const Menu = ({ children }: { children: React.ReactNode }) => {
33
+ const descendantsContext = useDescendants()
34
+ const [focusedIndex, setFocusedIndex] = useState(0)
35
+ const [offset, setOffset] = useState(0)
36
+ const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
37
+ const [selectedTitles, setSelectedTitles] = useState<string[]>([])
38
+ const [searchQuery, setSearchQuery] = useState('')
39
+
40
+ useKeyboard((evt) => {
41
+ const items = Object.values(descendantsContext.map.current).filter(
42
+ (item) => item.index !== -1 && item.props?.filtered === true,
43
+ )
44
+ const itemCount = items.length
45
+
46
+ if (itemCount === 0) return
47
+
48
+ if (evt.name === 'down') {
49
+ setFocusedIndex((prev) => {
50
+ const nextIndex = (prev + 1) % itemCount
51
+
52
+ // Update offset only when the focused item is at the last position and there are more items
53
+ const visibleEnd = offset + itemsPerPage - 1
54
+ if (prev === visibleEnd && nextIndex < itemCount && nextIndex > prev) {
55
+ // Scroll down by one when at the last visible item
56
+ setOffset(offset + 1)
57
+ } else if (nextIndex < prev) {
58
+ // Wrapped to beginning
59
+ setOffset(0)
60
+ }
61
+
62
+ return nextIndex
63
+ })
64
+ } else if (evt.name === 'up') {
65
+ setFocusedIndex((prev) => {
66
+ const nextIndex = (prev - 1 + itemCount) % itemCount
67
+
68
+ // Update offset if we're going above the visible range
69
+ if (nextIndex < offset) {
70
+ setOffset(Math.max(0, nextIndex))
71
+ } else if (nextIndex >= offset + itemsPerPage) {
72
+ // Wrapped to end
73
+ setOffset(Math.max(0, itemCount - itemsPerPage))
74
+ }
75
+
76
+ return nextIndex
77
+ })
78
+ } else if (evt.name === 'return') {
79
+ // Toggle selection of current focused item
80
+ const entries = Object.entries(descendantsContext.map.current)
81
+ const sortedEntries = entries
82
+ .filter(
83
+ ([_, item]) => item.index !== -1 && item.props?.filtered === true,
84
+ )
85
+ .sort((a, b) => a[1].index - b[1].index)
86
+
87
+ const focusedId = sortedEntries[focusedIndex]?.[0]
88
+
89
+ if (focusedId) {
90
+ setSelectedIds((prev) => {
91
+ const newSet = new Set(prev)
92
+ if (newSet.has(focusedId)) {
93
+ newSet.delete(focusedId)
94
+ } else {
95
+ newSet.add(focusedId)
96
+ }
97
+
98
+ // Update selected titles state
99
+ const titles = Array.from(newSet)
100
+ .map((id) => descendantsContext.map.current[id]?.props?.title)
101
+ .filter(Boolean) as string[]
102
+
103
+ setSelectedTitles(titles)
104
+
105
+ return newSet
106
+ })
107
+ }
108
+ } else if (evt.ctrl && evt.name === 'return') {
109
+ // Log selected titles
110
+ logger.log('Selected filtered items:', selectedTitles)
111
+ }
112
+ })
113
+
114
+ return (
115
+ <MenuContext.Provider
116
+ value={{
117
+ focusedIndex,
118
+ offset,
119
+ itemsPerPage,
120
+ selectedIds,
121
+ searchQuery,
122
+ }}
123
+ >
124
+ <DescendantsProvider value={descendantsContext}>
125
+ <box flexDirection='column'>
126
+ <box flexDirection='column' borderStyle='single' padding={1}>
127
+ <text marginBottom={1}>Filter Menu</text>
128
+ <input
129
+ value={searchQuery}
130
+ onInput={(value) => {
131
+ setSearchQuery(value)
132
+ // Reset focus to first item when search changes
133
+ setFocusedIndex(0)
134
+ setOffset(0)
135
+ }}
136
+ focused
137
+ placeholder='Type to filter items...'
138
+ marginBottom={1}
139
+ />
140
+ <box flexDirection='column'>{children}</box>
141
+ </box>
142
+ {selectedTitles.length > 0 && (
143
+ <box
144
+ flexDirection='column'
145
+ marginTop={1}
146
+ borderStyle='single'
147
+ padding={1}
148
+ >
149
+ <text>Selected items ({selectedTitles.length}):</text>
150
+ {selectedTitles.map((title, index) => (
151
+ <text key={index} fg='green'>
152
+ • {title}
153
+ </text>
154
+ ))}
155
+ </box>
156
+ )}
157
+ </box>
158
+ </DescendantsProvider>
159
+ </MenuContext.Provider>
160
+ )
161
+ }
162
+
163
+ const Item = ({ title }: { title: string; key?: any }) => {
164
+ const { focusedIndex, offset, itemsPerPage, selectedIds, searchQuery } =
165
+ useContext(MenuContext)
166
+
167
+ // Determine if item matches filter
168
+ const isFiltered = title.toLowerCase().includes(searchQuery.toLowerCase())
169
+
170
+ // Register with descendants with the filtered state
171
+ const descendant = useDescendant({ title, filtered: isFiltered })
172
+
173
+ // Filter items based on search query from context
174
+ if (!isFiltered) {
175
+ return null
176
+ }
177
+
178
+ // Hide items that are outside the visible range
179
+ if (descendant.index < offset || descendant.index >= offset + itemsPerPage) {
180
+ return null
181
+ }
182
+
183
+ const isFocused = descendant.index === focusedIndex
184
+ const isSelected = selectedIds.has(descendant.descendantId)
185
+
186
+ return (
187
+ <text fg={isFocused ? 'blue' : 'white'}>
188
+ {isSelected ? '✓ ' : '▭ '}
189
+ {title}
190
+ </text>
191
+ )
192
+ }
193
+
194
+ const Example = () => {
195
+ const allItems = [
196
+ 'Apple Pie',
197
+ 'Banana Bread',
198
+ 'Chocolate Cake',
199
+ 'Apple Tart',
200
+ 'Blueberry Muffin',
201
+ 'Cherry Pie',
202
+ 'Apple Crumble',
203
+ 'Date Pudding',
204
+ 'Elderberry Jam',
205
+ 'Fig Newton',
206
+ 'Grape Jelly',
207
+ 'Honey Cake',
208
+ 'Ice Cream Sandwich',
209
+ 'Jelly Donut',
210
+ 'Key Lime Pie',
211
+ 'Lemon Tart',
212
+ ]
213
+
214
+ return (
215
+ <Menu>
216
+ {allItems.map((title) => (
217
+ <Item key={title} title={title} />
218
+ ))}
219
+ </Menu>
220
+ )
221
+ }
222
+
223
+ renderWithProviders(<Example />)
@@ -0,0 +1,208 @@
1
+ // read src/descendants.tsx to understand the core hooks that make this example possible
2
+ //
3
+ import { useKeyboard } from '@opentui/react'
4
+ import { createDescendants } from 'termcast/src/descendants'
5
+ import { useIsInFocus } from 'termcast/src/internal/focus-context'
6
+ import { createContext, useContext, useState } from 'react'
7
+ import { renderWithProviders } from '../../utils'
8
+ import { logger } from 'termcast/src/logger'
9
+
10
+ const { DescendantsProvider, useDescendants, useDescendant } =
11
+ createDescendants<{
12
+ title?: string
13
+ }>()
14
+
15
+ const itemsPerPage = 4
16
+
17
+ const FocusContext = createContext<{
18
+ focusedIndex: number
19
+ offset: number
20
+ itemsPerPage: number
21
+ selectedIds: Set<string>
22
+ }>({
23
+ focusedIndex: 0,
24
+ offset: 0,
25
+ itemsPerPage,
26
+ selectedIds: new Set(),
27
+ })
28
+
29
+ // IMPORTANT! Notice that we only use descendantsContext.map.current only inside hooks or event handlers. it MUST not be used in render scope
30
+ // instead each item renders its own content, descendantsContext must be used only for event handlers like useKeyboard or onMouseDown, or when user updates a search query to filter the filteredIndexes state
31
+ // to do conditional rendering instead add additional state, here we used offset to track the current page offset of displayed items, selectedIndexes, focusedIndex. Other examples could be searchQuery
32
+ const Menu = ({ children }: { children: React.ReactNode }) => {
33
+ const descendantsContext = useDescendants()
34
+ const [focusedIndex, setFocusedIndex] = useState(0)
35
+ const [offset, setOffset] = useState(0)
36
+ const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
37
+ const [selectedTitles, setSelectedTitles] = useState<string[]>([])
38
+ const inFocus = useIsInFocus()
39
+
40
+ useKeyboard((evt) => {
41
+ if (!inFocus) return
42
+
43
+ const items = Object.values(descendantsContext.map.current).filter(
44
+ (item) => item.index !== -1,
45
+ )
46
+ const itemCount = items.length
47
+
48
+ if (itemCount === 0) return
49
+
50
+ if (evt.name === 'down') {
51
+ setFocusedIndex((prev) => {
52
+ const nextIndex = (prev + 1) % itemCount
53
+
54
+ // Update offset only when the focused item is at the last position and there are more items
55
+ const visibleEnd = offset + itemsPerPage - 1
56
+ if (prev === visibleEnd && nextIndex < itemCount && nextIndex > prev) {
57
+ // Scroll down by one when at the last visible item
58
+ setOffset(offset + 1)
59
+ } else if (nextIndex < prev) {
60
+ // Wrapped to beginning
61
+ setOffset(0)
62
+ }
63
+
64
+ return nextIndex
65
+ })
66
+ } else if (evt.name === 'up') {
67
+ setFocusedIndex((prev) => {
68
+ const nextIndex = (prev - 1 + itemCount) % itemCount
69
+
70
+ // Update offset if we're going above the visible range
71
+ if (nextIndex < offset) {
72
+ setOffset(Math.max(0, nextIndex))
73
+ } else if (nextIndex >= offset + itemsPerPage) {
74
+ // Wrapped to end
75
+ setOffset(Math.max(0, itemCount - itemsPerPage))
76
+ }
77
+
78
+ return nextIndex
79
+ })
80
+ } else if (evt.name === 'return') {
81
+ // Toggle selection of current focused item
82
+ const entries = Object.entries(descendantsContext.map.current)
83
+ const sortedEntries = entries
84
+ .filter(([_, item]) => item.index !== -1)
85
+ .sort((a, b) => a[1].index - b[1].index)
86
+
87
+ const focusedId = sortedEntries[focusedIndex]?.[0]
88
+
89
+ if (focusedId) {
90
+ setSelectedIds((prev) => {
91
+ const newSet = new Set(prev)
92
+ if (newSet.has(focusedId)) {
93
+ newSet.delete(focusedId)
94
+ } else {
95
+ newSet.add(focusedId)
96
+ }
97
+
98
+ // Update selected titles state
99
+ const titles = Array.from(newSet)
100
+ .map((id) => descendantsContext.map.current[id]?.props?.title)
101
+ .filter(Boolean) as string[]
102
+
103
+ setSelectedTitles(titles)
104
+
105
+ return newSet
106
+ })
107
+ }
108
+ } else if (evt.ctrl && evt.name === 'return') {
109
+ // Log selected titles
110
+ logger.log('Selected items:', selectedTitles)
111
+ }
112
+ })
113
+
114
+ return (
115
+ <FocusContext.Provider
116
+ value={{
117
+ focusedIndex,
118
+ offset,
119
+ itemsPerPage: itemsPerPage,
120
+ selectedIds,
121
+ }}
122
+ >
123
+ <DescendantsProvider value={descendantsContext}>
124
+ <box flexDirection='column'>
125
+ <box>{children}</box>
126
+ {selectedTitles.length > 0 && (
127
+ <box
128
+ flexDirection='column'
129
+ marginTop={1}
130
+ borderStyle='single'
131
+ padding={1}
132
+ >
133
+ <text>Selected items ({selectedTitles.length}):</text>
134
+ {selectedTitles.map((title, index) => (
135
+ <text key={index} fg='green'>
136
+ • {title}
137
+ </text>
138
+ ))}
139
+ </box>
140
+ )}
141
+ </box>
142
+ </DescendantsProvider>
143
+ </FocusContext.Provider>
144
+ )
145
+ }
146
+
147
+ const Item = ({ title }: { title: string; key?: any }) => {
148
+ const descendant = useDescendant({ title })
149
+ const { focusedIndex, offset, itemsPerPage, selectedIds } =
150
+ useContext(FocusContext)
151
+
152
+ // Hide items that are outside the visible range
153
+ if (descendant.index < offset || descendant.index >= offset + itemsPerPage) {
154
+ return null
155
+ }
156
+
157
+ const isFocused = descendant.index === focusedIndex
158
+ const isSelected = selectedIds.has(descendant.descendantId)
159
+
160
+ return (
161
+ <text fg={isFocused ? 'blue' : 'white'}>
162
+ {isSelected ? '✓ ' : '▭ '}
163
+ {title}
164
+ </text>
165
+ )
166
+ }
167
+
168
+ const Example = () => {
169
+ const [searchQuery, setSearchQuery] = useState('')
170
+ const allItems = [
171
+ 'First Item',
172
+ 'Second Item',
173
+ 'Third Item',
174
+ 'Fourth Item',
175
+ 'Fifth Item',
176
+ 'Sixth Item',
177
+ 'Seventh Item',
178
+ 'Eighth Item',
179
+ 'Ninth Item',
180
+ 'Tenth Item',
181
+ 'Eleventh Item',
182
+ 'Twelfth Item',
183
+ ]
184
+
185
+ // Filter items based on search query
186
+ const filteredItems = allItems.filter((title) =>
187
+ title.toLowerCase().includes(searchQuery.toLowerCase()),
188
+ )
189
+
190
+ return (
191
+ <box flexDirection='column'>
192
+ <input
193
+ value={searchQuery}
194
+ onInput={setSearchQuery}
195
+ focused
196
+ placeholder='Search items...'
197
+ marginBottom={1}
198
+ />
199
+ <Menu>
200
+ {filteredItems.map((title) => (
201
+ <Item key={title} title={title} />
202
+ ))}
203
+ </Menu>
204
+ </box>
205
+ )
206
+ }
207
+
208
+ renderWithProviders(<Example />)
@@ -0,0 +1,149 @@
1
+ import React, { useState, useRef, useEffect } from 'react'
2
+ import { renderWithProviders } from 'termcast'
3
+ import { useKeyboard } from '@opentui/react'
4
+ import { fg, bold } from '@opentui/core'
5
+
6
+ function ScrollBoxListDemo(): any {
7
+ const [selectedIndex, setSelectedIndex] = useState(0)
8
+ const scrollBoxRef = useRef<any>(null)
9
+ const itemRefs = useRef<Map<number, any>>(new Map())
10
+
11
+ const items = Array.from({ length: 50 }, (_, i) => ({
12
+ id: i,
13
+ title: `Item ${i + 1}`,
14
+ description: `Description for item ${i + 1}`,
15
+ }))
16
+
17
+ useEffect(() => {
18
+ // Small delay to ensure layout is complete
19
+ const timeoutId = setTimeout(() => {
20
+ const scrollBox = scrollBoxRef.current
21
+ const selectedItem = itemRefs.current.get(selectedIndex)
22
+
23
+ if (scrollBox && selectedItem) {
24
+ // Get the actual item height including padding and margins
25
+ const itemHeight = selectedItem.height
26
+
27
+ // Calculate item position in the content
28
+ // We need the absolute position of the item within the scrollable content
29
+ const itemRelativeTop = selectedItem.y - scrollBox.content.y
30
+ const itemRelativeBottom = itemRelativeTop + itemHeight
31
+
32
+ // Get viewport info
33
+ const viewportHeight = scrollBox.viewport.height
34
+ const currentScrollTop = scrollBox.scrollTop || 0
35
+
36
+ // Define safe zone with padding
37
+ const safePadding = 2
38
+
39
+ // Calculate if item is fully visible
40
+ const itemVisibleTop = itemRelativeTop - currentScrollTop
41
+ const itemVisibleBottom = itemRelativeBottom - currentScrollTop
42
+
43
+ // Check if we need to scroll
44
+ if (itemVisibleTop < safePadding) {
45
+ // Item is too close to top or above viewport
46
+ const newScrollTop = Math.max(0, itemRelativeTop - safePadding)
47
+ scrollBox.scrollTo(newScrollTop)
48
+ } else if (itemVisibleBottom > viewportHeight - safePadding) {
49
+ // Item is too close to bottom or below viewport
50
+ // Calculate scroll position to show item at bottom with padding
51
+ const newScrollTop = Math.max(
52
+ 0,
53
+ itemRelativeBottom - viewportHeight + safePadding,
54
+ )
55
+ scrollBox.scrollTo(newScrollTop)
56
+ }
57
+ }
58
+ }, 20) // Give enough time for layout
59
+
60
+ return () => clearTimeout(timeoutId)
61
+ }, [selectedIndex])
62
+
63
+ useKeyboard((evt) => {
64
+ if (evt.name === 'up') {
65
+ setSelectedIndex((prev) => Math.max(0, prev - 1))
66
+ } else if (evt.name === 'down') {
67
+ setSelectedIndex((prev) => Math.min(items.length - 1, prev + 1))
68
+ } else if (evt.name === 'pageup') {
69
+ setSelectedIndex((prev) => Math.max(0, prev - 10))
70
+ } else if (evt.name === 'pagedown') {
71
+ setSelectedIndex((prev) => Math.min(items.length - 1, prev + 10))
72
+ } else if (evt.name === 'home') {
73
+ setSelectedIndex(0)
74
+ } else if (evt.name === 'end') {
75
+ setSelectedIndex(items.length - 1)
76
+ } else if (evt.name === 'q' || evt.name === 'escape') {
77
+ process.exit(0)
78
+ }
79
+ })
80
+
81
+ return (
82
+ <box flexDirection='column' width='100%' height='100%'>
83
+ <box padding={1} backgroundColor='#2e3440'>
84
+ <text>{bold(fg('#88c0d0')('ScrollBox Demo'))}</text>
85
+ <text fg='#d8dee9'>
86
+ ↑↓ Navigate | PgUp/PgDn Jump | Home/End First/Last
87
+ </text>
88
+ </box>
89
+
90
+ <scrollbox
91
+ ref={scrollBoxRef}
92
+ flexGrow={1}
93
+ flexShrink={1}
94
+ style={{
95
+ rootOptions: {
96
+ maxHeight: '100%',
97
+ overflow: 'hidden',
98
+ },
99
+ viewportOptions: {
100
+ flexGrow: 1,
101
+ flexShrink: 1,
102
+ },
103
+ contentOptions: {
104
+ padding: 1,
105
+ flexShrink: 0,
106
+ },
107
+ scrollbarOptions: {
108
+ visible: true,
109
+ showArrows: true,
110
+ },
111
+ }}
112
+ >
113
+ {items.map((item, index) => {
114
+ const isSelected = index === selectedIndex
115
+ return (
116
+ <box
117
+ key={item.id}
118
+ ref={(el) => {
119
+ if (el) itemRefs.current.set(index, el)
120
+ }}
121
+ padding={1}
122
+ backgroundColor={isSelected ? '#5e81ac' : '#3b4252'}
123
+ marginBottom={0.5}
124
+ >
125
+ <text>
126
+ {isSelected
127
+ ? bold(fg('#eceff4')(`▶ ${item.title}`))
128
+ : fg('#d8dee9')(` ${item.title}`)}
129
+ </text>
130
+ <text fg={isSelected ? '#e5e9f0' : '#81a1c1'}>
131
+ {item.description}
132
+ </text>
133
+ </box>
134
+ )
135
+ })}
136
+ </scrollbox>
137
+
138
+ <box padding={1} backgroundColor='#2e3440'>
139
+ <text fg='#81a1c1'>
140
+ Selected: {selectedIndex + 1}/{items.length} | Press [q] to quit
141
+ </text>
142
+ </box>
143
+ </box>
144
+ )
145
+ }
146
+
147
+ if (import.meta.main) {
148
+ renderWithProviders(<ScrollBoxListDemo />)
149
+ }
@@ -0,0 +1,124 @@
1
+ import React, { useState } from 'react'
2
+ import { useKeyboard } from '@opentui/react'
3
+ import { renderWithProviders } from 'termcast'
4
+ import {
5
+ useDialog,
6
+ type DialogPosition,
7
+ } from 'termcast/src/internal/dialog'
8
+ import { Theme } from 'termcast'
9
+ import { List } from 'termcast'
10
+ import { ActionPanel, Action } from 'termcast'
11
+ import { Dropdown } from 'termcast'
12
+ import { logger } from 'termcast'
13
+
14
+ function DialogContent({ position }: { position: DialogPosition }): any {
15
+ const [selectedDrink, setSelectedDrink] = useState<string>('coffee')
16
+
17
+ const handleDrinkChange = (newValue: string) => {
18
+ logger.log('Selected drink:', newValue)
19
+ setSelectedDrink(newValue)
20
+ }
21
+
22
+ return (
23
+ <Dropdown
24
+ tooltip='Select Drink'
25
+ onChange={handleDrinkChange}
26
+ value={selectedDrink}
27
+ placeholder='Search drinks...'
28
+ >
29
+ <Dropdown.Section title='Hot Drinks'>
30
+ <Dropdown.Item
31
+ value='coffee'
32
+ title='Coffee'
33
+ icon='☕'
34
+ keywords={['espresso', 'latte', 'cappuccino']}
35
+ />
36
+ <Dropdown.Item
37
+ value='tea'
38
+ title='Tea'
39
+ icon='🍵'
40
+ keywords={['green', 'black', 'herbal']}
41
+ />
42
+ </Dropdown.Section>
43
+
44
+ <Dropdown.Section title='Cold Drinks'>
45
+ <Dropdown.Item
46
+ value='juice'
47
+ title='Juice'
48
+ icon='🧃'
49
+ keywords={['orange', 'apple', 'grape']}
50
+ />
51
+ <Dropdown.Item
52
+ value='water'
53
+ title='Water'
54
+ icon='💧'
55
+ keywords={['sparkling', 'still', 'mineral']}
56
+ />
57
+ <Dropdown.Item
58
+ value='cola'
59
+ title='Cola'
60
+ icon='🥤'
61
+ keywords={['coke', 'pepsi', 'soda']}
62
+ />
63
+ </Dropdown.Section>
64
+ </Dropdown>
65
+ )
66
+ }
67
+
68
+ function App(): any {
69
+ const dialog = useDialog()
70
+
71
+ const positions: {
72
+ title: string
73
+ position: DialogPosition
74
+ description: string
75
+ }[] = [
76
+ {
77
+ title: 'Center',
78
+ position: 'center',
79
+ description: 'Shows dialog in the center of the screen',
80
+ },
81
+ {
82
+ title: 'Top Right',
83
+ position: 'top-right',
84
+ description: 'Shows dialog in the top-right corner',
85
+ },
86
+ {
87
+ title: 'Bottom Right',
88
+ position: 'bottom-right',
89
+ description: 'Shows dialog in the bottom-right corner',
90
+ },
91
+ ]
92
+
93
+ return (
94
+ <List navigationTitle='Dialog with Dropdown Example'>
95
+ {positions.map((item) => (
96
+ <List.Item
97
+ title={item.title}
98
+ subtitle={item.description}
99
+ actions={
100
+ <ActionPanel>
101
+ <Action
102
+ title={`Open ${item.title} Dialog`}
103
+ onAction={() => {
104
+ dialog.push(
105
+ <DialogContent position={item.position} />,
106
+ item.position,
107
+ )
108
+ }}
109
+ />
110
+ <Action
111
+ title='Clear All Dialogs'
112
+ onAction={() => {
113
+ dialog.clear()
114
+ }}
115
+ />
116
+ </ActionPanel>
117
+ }
118
+ />
119
+ ))}
120
+ </List>
121
+ )
122
+ }
123
+
124
+ renderWithProviders(<App />)