termcast 1.3.21 → 1.3.24

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 (412) hide show
  1. package/dist/ai.d.ts +104 -0
  2. package/dist/ai.d.ts.map +1 -0
  3. package/dist/ai.js +135 -0
  4. package/dist/ai.js.map +1 -0
  5. package/dist/apis/browser-extension.d.ts +18 -0
  6. package/dist/apis/browser-extension.d.ts.map +1 -0
  7. package/dist/apis/browser-extension.js +14 -0
  8. package/dist/apis/browser-extension.js.map +1 -0
  9. package/dist/apis/localstorage.d.ts.map +1 -1
  10. package/dist/apis/localstorage.js +4 -7
  11. package/dist/apis/localstorage.js.map +1 -1
  12. package/dist/apis/oauth.d.ts.map +1 -1
  13. package/dist/apis/oauth.js +5 -1
  14. package/dist/apis/oauth.js.map +1 -1
  15. package/dist/apis/preferences.d.ts.map +1 -1
  16. package/dist/apis/preferences.js +38 -19
  17. package/dist/apis/preferences.js.map +1 -1
  18. package/dist/build.d.ts.map +1 -1
  19. package/dist/build.js +2 -1
  20. package/dist/build.js.map +1 -1
  21. package/dist/cache.d.ts +32 -0
  22. package/dist/cache.d.ts.map +1 -0
  23. package/dist/cache.js +205 -0
  24. package/dist/cache.js.map +1 -0
  25. package/dist/cli.d.ts.map +1 -1
  26. package/dist/cli.js +67 -31
  27. package/dist/cli.js.map +1 -1
  28. package/dist/clipboard.d.ts +36 -0
  29. package/dist/clipboard.d.ts.map +1 -0
  30. package/dist/clipboard.js +154 -0
  31. package/dist/clipboard.js.map +1 -0
  32. package/dist/compile.d.ts.map +1 -1
  33. package/dist/compile.js +22 -5
  34. package/dist/compile.js.map +1 -1
  35. package/dist/components/actions.d.ts.map +1 -1
  36. package/dist/components/actions.js +56 -30
  37. package/dist/components/actions.js.map +1 -1
  38. package/dist/components/detail.d.ts.map +1 -1
  39. package/dist/components/detail.js +4 -0
  40. package/dist/components/detail.js.map +1 -1
  41. package/dist/components/dropdown.d.ts.map +1 -1
  42. package/dist/components/dropdown.js +38 -15
  43. package/dist/components/dropdown.js.map +1 -1
  44. package/dist/components/extension-preferences.d.ts.map +1 -1
  45. package/dist/components/extension-preferences.js +40 -13
  46. package/dist/components/extension-preferences.js.map +1 -1
  47. package/dist/components/form/checkbox.d.ts.map +1 -1
  48. package/dist/components/form/checkbox.js +5 -3
  49. package/dist/components/form/checkbox.js.map +1 -1
  50. package/dist/components/form/date-picker.d.ts.map +1 -1
  51. package/dist/components/form/date-picker.js +5 -3
  52. package/dist/components/form/date-picker.js.map +1 -1
  53. package/dist/components/form/description.d.ts.map +1 -1
  54. package/dist/components/form/description.js +2 -2
  55. package/dist/components/form/description.js.map +1 -1
  56. package/dist/components/form/dropdown.d.ts.map +1 -1
  57. package/dist/components/form/dropdown.js +84 -80
  58. package/dist/components/form/dropdown.js.map +1 -1
  59. package/dist/components/form/file-autocomplete.d.ts +3 -6
  60. package/dist/components/form/file-autocomplete.d.ts.map +1 -1
  61. package/dist/components/form/file-autocomplete.js +61 -66
  62. package/dist/components/form/file-autocomplete.js.map +1 -1
  63. package/dist/components/form/file-picker.d.ts.map +1 -1
  64. package/dist/components/form/file-picker.js +33 -30
  65. package/dist/components/form/file-picker.js.map +1 -1
  66. package/dist/components/form/form-end.d.ts.map +1 -1
  67. package/dist/components/form/form-end.js +21 -1
  68. package/dist/components/form/form-end.js.map +1 -1
  69. package/dist/components/form/form-type-only.d.ts +174 -0
  70. package/dist/components/form/form-type-only.d.ts.map +1 -0
  71. package/dist/components/form/form-type-only.js +2 -0
  72. package/dist/components/form/form-type-only.js.map +1 -0
  73. package/dist/components/form/index.d.ts +3 -1
  74. package/dist/components/form/index.d.ts.map +1 -1
  75. package/dist/components/form/index.js +100 -28
  76. package/dist/components/form/index.js.map +1 -1
  77. package/dist/components/form/password-field.d.ts.map +1 -1
  78. package/dist/components/form/password-field.js +5 -3
  79. package/dist/components/form/password-field.js.map +1 -1
  80. package/dist/components/form/text-area.d.ts.map +1 -1
  81. package/dist/components/form/text-area.js +5 -3
  82. package/dist/components/form/text-area.js.map +1 -1
  83. package/dist/components/form/text-field.d.ts.map +1 -1
  84. package/dist/components/form/text-field.js +6 -4
  85. package/dist/components/form/text-field.js.map +1 -1
  86. package/dist/components/form/types.d.ts +5 -0
  87. package/dist/components/form/types.d.ts.map +1 -1
  88. package/dist/components/form/use-form-handling.d.ts +4 -0
  89. package/dist/components/form/use-form-handling.d.ts.map +1 -0
  90. package/dist/components/form/use-form-handling.js +37 -0
  91. package/dist/components/form/use-form-handling.js.map +1 -0
  92. package/dist/components/form/with-left-border.d.ts +2 -1
  93. package/dist/components/form/with-left-border.d.ts.map +1 -1
  94. package/dist/components/form/with-left-border.js +27 -3
  95. package/dist/components/form/with-left-border.js.map +1 -1
  96. package/dist/components/icon.d.ts +1 -0
  97. package/dist/components/icon.d.ts.map +1 -1
  98. package/dist/components/icon.js +24 -8
  99. package/dist/components/icon.js.map +1 -1
  100. package/dist/components/list.d.ts +2 -2
  101. package/dist/components/list.d.ts.map +1 -1
  102. package/dist/components/list.js +140 -62
  103. package/dist/components/list.js.map +1 -1
  104. package/dist/components/loading-bar.d.ts.map +1 -1
  105. package/dist/components/loading-bar.js +2 -2
  106. package/dist/components/loading-bar.js.map +1 -1
  107. package/dist/components/loading-text.d.ts +8 -0
  108. package/dist/components/loading-text.d.ts.map +1 -0
  109. package/dist/components/loading-text.js +58 -0
  110. package/dist/components/loading-text.js.map +1 -0
  111. package/dist/descendants.js +1 -1
  112. package/dist/descendants.js.map +1 -1
  113. package/dist/dev-ui.d.ts +7 -0
  114. package/dist/dev-ui.d.ts.map +1 -0
  115. package/dist/dev-ui.js +118 -0
  116. package/dist/dev-ui.js.map +1 -0
  117. package/dist/environment.d.ts +63 -0
  118. package/dist/environment.d.ts.map +1 -0
  119. package/dist/environment.js +189 -0
  120. package/dist/environment.js.map +1 -0
  121. package/dist/examples/datepicker.d.ts +2 -0
  122. package/dist/examples/datepicker.d.ts.map +1 -0
  123. package/dist/examples/datepicker.js +344 -0
  124. package/dist/examples/datepicker.js.map +1 -0
  125. package/dist/examples/file-autocomplete.vitest.d.ts +2 -0
  126. package/dist/examples/file-autocomplete.vitest.d.ts.map +1 -0
  127. package/dist/examples/file-autocomplete.vitest.js +223 -0
  128. package/dist/examples/file-autocomplete.vitest.js.map +1 -0
  129. package/dist/examples/form-basic-arrow-keys.vitest.d.ts +2 -0
  130. package/dist/examples/form-basic-arrow-keys.vitest.d.ts.map +1 -0
  131. package/dist/examples/form-basic-arrow-keys.vitest.js +46 -0
  132. package/dist/examples/form-basic-arrow-keys.vitest.js.map +1 -0
  133. package/dist/examples/form-basic.vitest.d.ts +2 -0
  134. package/dist/examples/form-basic.vitest.d.ts.map +1 -0
  135. package/dist/examples/form-basic.vitest.js +630 -0
  136. package/dist/examples/form-basic.vitest.js.map +1 -0
  137. package/dist/examples/form-dropdown-with-sections.d.ts +2 -0
  138. package/dist/examples/form-dropdown-with-sections.d.ts.map +1 -0
  139. package/dist/examples/form-dropdown-with-sections.js +13 -0
  140. package/dist/examples/form-dropdown-with-sections.js.map +1 -0
  141. package/dist/examples/form-dropdown-with-sections.vitest.d.ts +2 -0
  142. package/dist/examples/form-dropdown-with-sections.vitest.d.ts.map +1 -0
  143. package/dist/examples/form-dropdown-with-sections.vitest.js +75 -0
  144. package/dist/examples/form-dropdown-with-sections.vitest.js.map +1 -0
  145. package/dist/examples/form-dropdown.vitest.d.ts +2 -0
  146. package/dist/examples/form-dropdown.vitest.d.ts.map +1 -0
  147. package/dist/examples/form-dropdown.vitest.js +854 -0
  148. package/dist/examples/form-dropdown.vitest.js.map +1 -0
  149. package/dist/examples/form-multiselect-dropdown.d.ts +2 -0
  150. package/dist/examples/form-multiselect-dropdown.d.ts.map +1 -0
  151. package/dist/examples/form-multiselect-dropdown.js +13 -0
  152. package/dist/examples/form-multiselect-dropdown.js.map +1 -0
  153. package/dist/examples/form-scroll.d.ts.map +1 -1
  154. package/dist/examples/form-scroll.js +7 -1
  155. package/dist/examples/form-scroll.js.map +1 -1
  156. package/dist/examples/form-scroll.vitest.d.ts +2 -0
  157. package/dist/examples/form-scroll.vitest.d.ts.map +1 -0
  158. package/dist/examples/form-scroll.vitest.js +211 -0
  159. package/dist/examples/form-scroll.vitest.js.map +1 -0
  160. package/dist/examples/form-tagpicker.vitest.d.ts +2 -0
  161. package/dist/examples/form-tagpicker.vitest.d.ts.map +1 -0
  162. package/dist/examples/form-tagpicker.vitest.js +736 -0
  163. package/dist/examples/form-tagpicker.vitest.js.map +1 -0
  164. package/dist/examples/internal/descendants-filtering.js +1 -1
  165. package/dist/examples/internal/descendants-filtering.js.map +1 -1
  166. package/dist/examples/internal/descendants.js +1 -1
  167. package/dist/examples/internal/descendants.js.map +1 -1
  168. package/dist/examples/internal/nested-boxes.d.ts +2 -0
  169. package/dist/examples/internal/nested-boxes.d.ts.map +1 -0
  170. package/dist/examples/internal/nested-boxes.js +7 -0
  171. package/dist/examples/internal/nested-boxes.js.map +1 -0
  172. package/dist/examples/internal/rhf-custom-ref.js +2 -2
  173. package/dist/examples/internal/rhf-custom-ref.js.map +1 -1
  174. package/dist/examples/internal/scrollbox-demo.js +3 -22
  175. package/dist/examples/internal/scrollbox-demo.js.map +1 -1
  176. package/dist/examples/internal/scrollbox-descendants.d.ts +2 -0
  177. package/dist/examples/internal/scrollbox-descendants.d.ts.map +1 -0
  178. package/dist/examples/internal/scrollbox-descendants.js +83 -0
  179. package/dist/examples/internal/scrollbox-descendants.js.map +1 -0
  180. package/dist/examples/internal/scrollbox-with-descendants.js +4 -8
  181. package/dist/examples/internal/scrollbox-with-descendants.js.map +1 -1
  182. package/dist/examples/internal/simple-scrollbox.vitest.d.ts +2 -0
  183. package/dist/examples/internal/simple-scrollbox.vitest.d.ts.map +1 -0
  184. package/dist/examples/internal/simple-scrollbox.vitest.js +96 -0
  185. package/dist/examples/internal/simple-scrollbox.vitest.js.map +1 -0
  186. package/dist/examples/internal/unicode-square-repro.d.ts +2 -0
  187. package/dist/examples/internal/unicode-square-repro.d.ts.map +1 -0
  188. package/dist/examples/internal/unicode-square-repro.js +7 -0
  189. package/dist/examples/internal/unicode-square-repro.js.map +1 -0
  190. package/dist/examples/list-detail-metadata.d.ts +2 -0
  191. package/dist/examples/list-detail-metadata.d.ts.map +1 -0
  192. package/dist/examples/list-detail-metadata.js +8 -0
  193. package/dist/examples/list-detail-metadata.js.map +1 -0
  194. package/dist/examples/list-dropdown-default.vitest.d.ts +2 -0
  195. package/dist/examples/list-dropdown-default.vitest.d.ts.map +1 -0
  196. package/dist/examples/list-dropdown-default.vitest.js +234 -0
  197. package/dist/examples/list-dropdown-default.vitest.js.map +1 -0
  198. package/dist/examples/list-fetch-data.vitest.d.ts +2 -0
  199. package/dist/examples/list-fetch-data.vitest.d.ts.map +1 -0
  200. package/dist/examples/list-fetch-data.vitest.js +111 -0
  201. package/dist/examples/list-fetch-data.vitest.js.map +1 -0
  202. package/dist/examples/list-filter-navigation.d.ts +2 -0
  203. package/dist/examples/list-filter-navigation.d.ts.map +1 -0
  204. package/dist/examples/list-filter-navigation.js +8 -0
  205. package/dist/examples/list-filter-navigation.js.map +1 -0
  206. package/dist/examples/list-scrollbox.vitest.d.ts +2 -0
  207. package/dist/examples/list-scrollbox.vitest.d.ts.map +1 -0
  208. package/dist/examples/list-scrollbox.vitest.js +93 -0
  209. package/dist/examples/list-scrollbox.vitest.js.map +1 -0
  210. package/dist/examples/list-with-detail-long.d.ts +2 -0
  211. package/dist/examples/list-with-detail-long.d.ts.map +1 -0
  212. package/dist/examples/list-with-detail-long.js +53 -0
  213. package/dist/examples/list-with-detail-long.js.map +1 -0
  214. package/dist/examples/list-with-detail.vitest.d.ts +2 -0
  215. package/dist/examples/list-with-detail.vitest.d.ts.map +1 -0
  216. package/dist/examples/list-with-detail.vitest.js +434 -0
  217. package/dist/examples/list-with-detail.vitest.js.map +1 -0
  218. package/dist/examples/list-with-dropdown.vitest.d.ts +2 -0
  219. package/dist/examples/list-with-dropdown.vitest.d.ts.map +1 -0
  220. package/dist/examples/list-with-dropdown.vitest.js +337 -0
  221. package/dist/examples/list-with-dropdown.vitest.js.map +1 -0
  222. package/dist/examples/list-with-sections.js +5 -1
  223. package/dist/examples/list-with-sections.js.map +1 -1
  224. package/dist/examples/list-with-sections.vitest.d.ts +2 -0
  225. package/dist/examples/list-with-sections.vitest.d.ts.map +1 -0
  226. package/dist/examples/list-with-sections.vitest.js +601 -0
  227. package/dist/examples/list-with-sections.vitest.js.map +1 -0
  228. package/dist/examples/scrollbox-vertical-centering.d.ts +6 -0
  229. package/dist/examples/scrollbox-vertical-centering.d.ts.map +1 -0
  230. package/dist/examples/scrollbox-vertical-centering.js +17 -0
  231. package/dist/examples/scrollbox-vertical-centering.js.map +1 -0
  232. package/dist/examples/simple-file-picker.vitest.d.ts +2 -0
  233. package/dist/examples/simple-file-picker.vitest.d.ts.map +1 -0
  234. package/dist/examples/simple-file-picker.vitest.js +678 -0
  235. package/dist/examples/simple-file-picker.vitest.js.map +1 -0
  236. package/dist/examples/simple-grid.vitest.d.ts +2 -0
  237. package/dist/examples/simple-grid.vitest.d.ts.map +1 -0
  238. package/dist/examples/simple-grid.vitest.js +521 -0
  239. package/dist/examples/simple-grid.vitest.js.map +1 -0
  240. package/dist/examples/simple-navigation.js +10 -4
  241. package/dist/examples/simple-navigation.js.map +1 -1
  242. package/dist/examples/simple-navigation.vitest.d.ts +2 -0
  243. package/dist/examples/simple-navigation.vitest.d.ts.map +1 -0
  244. package/dist/examples/simple-navigation.vitest.js +718 -0
  245. package/dist/examples/simple-navigation.vitest.js.map +1 -0
  246. package/dist/examples/store.vitest.d.ts +2 -0
  247. package/dist/examples/store.vitest.d.ts.map +1 -0
  248. package/dist/examples/store.vitest.js +69 -0
  249. package/dist/examples/store.vitest.js.map +1 -0
  250. package/dist/extensions/dev.d.ts +4 -2
  251. package/dist/extensions/dev.d.ts.map +1 -1
  252. package/dist/extensions/dev.js +61 -10
  253. package/dist/extensions/dev.js.map +1 -1
  254. package/dist/extensions/dev.vitest.d.ts +2 -0
  255. package/dist/extensions/dev.vitest.d.ts.map +1 -0
  256. package/dist/extensions/dev.vitest.js +197 -0
  257. package/dist/extensions/dev.vitest.js.map +1 -0
  258. package/dist/extensions/home.d.ts.map +1 -1
  259. package/dist/extensions/home.js +3 -0
  260. package/dist/extensions/home.js.map +1 -1
  261. package/dist/home-command.d.ts +8 -0
  262. package/dist/home-command.d.ts.map +1 -0
  263. package/dist/home-command.js +181 -0
  264. package/dist/home-command.js.map +1 -0
  265. package/dist/hover-repro.d.ts +2 -0
  266. package/dist/hover-repro.d.ts.map +1 -0
  267. package/dist/hover-repro.js +20 -0
  268. package/dist/hover-repro.js.map +1 -0
  269. package/dist/index.d.ts +1 -0
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +2 -0
  272. package/dist/index.js.map +1 -1
  273. package/dist/internal/dialog.d.ts +1 -0
  274. package/dist/internal/dialog.d.ts.map +1 -1
  275. package/dist/internal/dialog.js +27 -18
  276. package/dist/internal/dialog.js.map +1 -1
  277. package/dist/internal/navigation.d.ts +9 -1
  278. package/dist/internal/navigation.d.ts.map +1 -1
  279. package/dist/internal/navigation.js +5 -5
  280. package/dist/internal/navigation.js.map +1 -1
  281. package/dist/internal/offscreen.d.ts +6 -0
  282. package/dist/internal/offscreen.d.ts.map +1 -0
  283. package/dist/internal/offscreen.js +10 -0
  284. package/dist/internal/offscreen.js.map +1 -0
  285. package/dist/internal/providers.d.ts.map +1 -1
  286. package/dist/internal/providers.js +2 -2
  287. package/dist/internal/providers.js.map +1 -1
  288. package/dist/internal/scrollbox.d.ts +1 -10
  289. package/dist/internal/scrollbox.d.ts.map +1 -1
  290. package/dist/internal/scrollbox.js +2 -1
  291. package/dist/internal/scrollbox.js.map +1 -1
  292. package/dist/localstorage.d.ts +13 -0
  293. package/dist/localstorage.d.ts.map +1 -0
  294. package/dist/localstorage.js +190 -0
  295. package/dist/localstorage.js.map +1 -0
  296. package/dist/oauth.d.ts +142 -0
  297. package/dist/oauth.d.ts.map +1 -0
  298. package/dist/oauth.js +551 -0
  299. package/dist/oauth.js.map +1 -0
  300. package/dist/preferences.d.ts +23 -0
  301. package/dist/preferences.d.ts.map +1 -0
  302. package/dist/preferences.js +105 -0
  303. package/dist/preferences.js.map +1 -0
  304. package/dist/state.d.ts +2 -0
  305. package/dist/state.d.ts.map +1 -1
  306. package/dist/state.js +3 -0
  307. package/dist/state.js.map +1 -1
  308. package/dist/store.d.ts +21 -0
  309. package/dist/store.d.ts.map +1 -0
  310. package/dist/store.js +84 -0
  311. package/dist/store.js.map +1 -0
  312. package/dist/swift-loader.d.ts +3 -0
  313. package/dist/swift-loader.d.ts.map +1 -0
  314. package/dist/swift-loader.js +193 -0
  315. package/dist/swift-loader.js.map +1 -0
  316. package/dist/swift-runtime.d.ts +2 -0
  317. package/dist/swift-runtime.d.ts.map +1 -0
  318. package/dist/swift-runtime.js +27 -0
  319. package/dist/swift-runtime.js.map +1 -0
  320. package/dist/toast.d.ts +44 -0
  321. package/dist/toast.d.ts.map +1 -0
  322. package/dist/toast.js +221 -0
  323. package/dist/toast.js.map +1 -0
  324. package/dist/utils/file-system.d.ts +9 -0
  325. package/dist/utils/file-system.d.ts.map +1 -1
  326. package/dist/utils/file-system.js +49 -0
  327. package/dist/utils/file-system.js.map +1 -1
  328. package/dist/utils/run-command.d.ts +25 -1
  329. package/dist/utils/run-command.d.ts.map +1 -1
  330. package/dist/utils/run-command.js +47 -4
  331. package/dist/utils/run-command.js.map +1 -1
  332. package/dist/window.d.ts +12 -0
  333. package/dist/window.d.ts.map +1 -0
  334. package/dist/window.js +48 -0
  335. package/dist/window.js.map +1 -0
  336. package/package.json +12 -10
  337. package/src/apis/browser-extension.tsx +29 -0
  338. package/src/apis/localstorage.test.ts +14 -6
  339. package/src/apis/localstorage.tsx +8 -5
  340. package/src/apis/oauth.tsx +5 -1
  341. package/src/apis/preferences.tsx +48 -22
  342. package/src/build.test.tsx +52 -0
  343. package/src/build.tsx +2 -1
  344. package/src/cli.tsx +78 -37
  345. package/src/compile.tsx +22 -5
  346. package/src/components/actions.tsx +94 -32
  347. package/src/components/detail.tsx +4 -0
  348. package/src/components/dropdown.tsx +47 -14
  349. package/src/components/extension-preferences.tsx +44 -16
  350. package/src/components/form/checkbox.tsx +12 -6
  351. package/src/components/form/date-picker.tsx +12 -6
  352. package/src/components/form/description.tsx +7 -2
  353. package/src/components/form/dropdown.tsx +131 -119
  354. package/src/components/form/file-autocomplete.tsx +90 -108
  355. package/src/components/form/file-picker.tsx +54 -43
  356. package/src/components/form/form-end.tsx +23 -2
  357. package/src/components/form/index.tsx +152 -34
  358. package/src/components/form/password-field.tsx +12 -6
  359. package/src/components/form/text-area.tsx +13 -6
  360. package/src/components/form/text-field.tsx +13 -6
  361. package/src/components/form/types.tsx +6 -0
  362. package/src/components/form/with-left-border.tsx +41 -8
  363. package/src/components/icon.tsx +27 -8
  364. package/src/components/list.tsx +193 -74
  365. package/src/components/loading-bar.tsx +3 -2
  366. package/src/components/loading-text.tsx +79 -0
  367. package/src/descendants.tsx +1 -0
  368. package/src/examples/file-autocomplete.vitest.tsx +130 -125
  369. package/src/examples/form-basic.vitest.tsx +376 -176
  370. package/src/examples/form-dropdown.vitest.tsx +126 -126
  371. package/src/examples/form-scroll.tsx +2 -0
  372. package/src/examples/form-scroll.vitest.tsx +58 -58
  373. package/src/examples/form-tagpicker.vitest.tsx +99 -99
  374. package/src/examples/internal/descendants-filtering.tsx +1 -0
  375. package/src/examples/internal/descendants.tsx +1 -0
  376. package/src/examples/internal/rhf-custom-ref.tsx +2 -0
  377. package/src/examples/internal/scrollbox-demo.tsx +3 -27
  378. package/src/examples/internal/scrollbox-with-descendants.tsx +4 -7
  379. package/src/examples/internal/simple-scrollbox.vitest.tsx +7 -5
  380. package/src/examples/list-detail-metadata.tsx +49 -0
  381. package/src/examples/list-detail-metadata.vitest.tsx +88 -0
  382. package/src/examples/list-dropdown-default.vitest.tsx +51 -51
  383. package/src/examples/list-fetch-data.vitest.tsx +4 -4
  384. package/src/examples/list-scrollbox.vitest.tsx +73 -14
  385. package/src/examples/list-with-detail-long.tsx +70 -0
  386. package/src/examples/list-with-detail.vitest.tsx +198 -92
  387. package/src/examples/list-with-dropdown.vitest.tsx +53 -53
  388. package/src/examples/list-with-sections.tsx +1 -0
  389. package/src/examples/list-with-sections.vitest.tsx +213 -89
  390. package/src/examples/list-with-toast.vitest.tsx +4 -4
  391. package/src/examples/simple-file-picker.vitest.tsx +61 -471
  392. package/src/examples/simple-grid.vitest.tsx +238 -233
  393. package/src/examples/simple-navigation.tsx +15 -7
  394. package/src/examples/simple-navigation.vitest.tsx +121 -210
  395. package/src/examples/store.vitest.tsx +1 -1
  396. package/src/examples/swift-extension.vitest.tsx +148 -0
  397. package/src/examples/synonyms.vitest.tsx +159 -0
  398. package/src/extensions/dev.tsx +74 -7
  399. package/src/extensions/dev.vitest.tsx +97 -31
  400. package/src/extensions/home.tsx +6 -0
  401. package/src/index.tsx +3 -0
  402. package/src/internal/dialog.tsx +43 -30
  403. package/src/internal/navigation.tsx +3 -1
  404. package/src/internal/offscreen.tsx +15 -0
  405. package/src/internal/providers.tsx +4 -2
  406. package/src/internal/scrollbox.tsx +4 -8
  407. package/src/keyboard.test.tsx +69 -0
  408. package/src/state.tsx +7 -0
  409. package/src/swift-loader.tsx +239 -0
  410. package/src/swift-runtime.tsx +36 -0
  411. package/src/utils/file-system.ts +61 -0
  412. package/src/utils/run-command.tsx +75 -6
@@ -1,20 +1,28 @@
1
- import { describe, test, expect, beforeEach, afterAll } from 'bun:test'
1
+ import { describe, test, expect, beforeEach, beforeAll, afterAll } from 'bun:test'
2
2
  import { LocalStorage } from './localstorage'
3
+ import { useStore } from '../state'
3
4
  import * as os from 'os'
4
5
  import * as path from 'path'
5
6
  import * as fs from 'fs'
6
7
 
7
8
  describe('LocalStorage', () => {
9
+ const testExtensionPath = path.join(os.tmpdir(), 'termcast-localstorage-test')
10
+
11
+ beforeAll(() => {
12
+ // Set up extensionPath required by LocalStorage
13
+ useStore.setState({ extensionPath: testExtensionPath })
14
+ })
15
+
8
16
  beforeEach(async () => {
9
17
  await LocalStorage.clear()
10
18
  })
11
19
 
12
20
  afterAll(() => {
13
- // Optional: Clean up test database after all tests
14
- // const dbPath = path.join(os.homedir(), '.termcast.db')
15
- // if (fs.existsSync(dbPath)) {
16
- // fs.unlinkSync(dbPath)
17
- // }
21
+ // Clean up test database after all tests
22
+ const dbDir = path.join(testExtensionPath, '.termcast-bundle')
23
+ if (fs.existsSync(dbDir)) {
24
+ fs.rmSync(dbDir, { recursive: true })
25
+ }
18
26
  })
19
27
 
20
28
  describe('setItem and getItem', () => {
@@ -11,12 +11,13 @@ let currentDbPath: string | null = null
11
11
  function getCurrentDatabasePath(): string {
12
12
  const extensionPath = useStore.getState().extensionPath
13
13
 
14
- if (extensionPath) {
15
- // Use .termcast-bundle directory inside extension path
16
- return path.join(extensionPath, '.termcast-bundle', 'data.db')
17
- } else {
18
- return path.join(os.homedir(), '.termcast', '.termcast-bundle', 'data.db')
14
+ if (!extensionPath) {
15
+ throw new Error(
16
+ 'extensionPath not set - cannot access LocalStorage before extension is initialized',
17
+ )
19
18
  }
19
+ // Use .termcast-bundle directory inside extension path
20
+ return path.join(extensionPath, '.termcast-bundle', 'data.db')
20
21
  }
21
22
 
22
23
  function getDatabase(): Database {
@@ -59,6 +60,8 @@ function getDatabase(): Database {
59
60
  return db
60
61
  }
61
62
 
63
+
64
+
62
65
  export namespace LocalStorage {
63
66
  export type Value = string | number | boolean
64
67
 
@@ -405,6 +405,7 @@ export namespace OAuth {
405
405
 
406
406
  return new Promise((resolve, reject) => {
407
407
  const port = 8989
408
+ let authTimeout: ReturnType<typeof setTimeout>
408
409
 
409
410
  // Create a local server to handle the OAuth callback
410
411
  const server = http.createServer((req, res) => {
@@ -534,6 +535,7 @@ export namespace OAuth {
534
535
  res.end(JSON.stringify({ success: true }))
535
536
 
536
537
  server.close()
538
+ clearTimeout(authTimeout)
537
539
  this.isAuthorizing = false
538
540
 
539
541
  // For implicit flow, save tokens immediately since we won't do token exchange
@@ -570,6 +572,7 @@ export namespace OAuth {
570
572
  })
571
573
  res.end(JSON.stringify({ error: 'parse_error' }))
572
574
  server.close()
575
+ clearTimeout(authTimeout)
573
576
  reject(error)
574
577
  }
575
578
  })
@@ -608,11 +611,12 @@ export namespace OAuth {
608
611
 
609
612
  server.on('error', (error) => {
610
613
  logger.error('OAuth implicit flow server error:', error)
614
+ clearTimeout(authTimeout)
611
615
  reject(error)
612
616
  })
613
617
 
614
618
  // Set a timeout for the authorization
615
- setTimeout(
619
+ authTimeout = setTimeout(
616
620
  () => {
617
621
  server.close()
618
622
  reject(new Error('OAuth authorization timeout'))
@@ -35,47 +35,73 @@ export function getPreferenceValues<
35
35
  return {} as Values
36
36
  }
37
37
 
38
+ // Build defaults from preference definitions
39
+ const defaults: PreferenceValues = {}
40
+
41
+ // Extension-level preference defaults
42
+ const extensionPrefs = extensionPackageJson?.preferences || []
43
+ for (const pref of extensionPrefs) {
44
+ if (pref.default !== undefined) {
45
+ defaults[pref.name] = pref.default
46
+ }
47
+ }
48
+
49
+ // Command-specific preference defaults (override extension defaults)
50
+ if (currentCommandName && extensionPackageJson?.commands) {
51
+ const commandDef = extensionPackageJson.commands.find(
52
+ (cmd) => cmd.name === currentCommandName,
53
+ )
54
+ const commandPrefs = commandDef?.preferences || []
55
+ for (const pref of commandPrefs) {
56
+ if (pref.default !== undefined) {
57
+ defaults[pref.name] = pref.default
58
+ }
59
+ }
60
+ }
61
+
62
+ let extensionSavedValues: PreferenceValues = {}
63
+ let commandSavedValues: PreferenceValues = {}
64
+
38
65
  try {
39
- // First try to load command-specific preferences, then fall back to extension preferences
66
+ // Load extension-level preferences
67
+ const extensionPreferencesKey = `preferences.${extensionName}`
68
+ const extensionPreferences = LocalStorage.getItemSync(extensionPreferencesKey)
69
+
70
+ if (extensionPreferences && typeof extensionPreferences === 'string') {
71
+ try {
72
+ extensionSavedValues = JSON.parse(extensionPreferences)
73
+ logger.log(
74
+ `Loaded extension preferences for ${extensionName}:`,
75
+ extensionSavedValues,
76
+ )
77
+ } catch (parseError) {
78
+ logger.error(`Failed to parse extension preferences:`, parseError)
79
+ }
80
+ }
81
+
82
+ // Load command-specific preferences
40
83
  if (currentCommandName) {
41
84
  const commandPreferencesKey = `preferences.${extensionName}.${currentCommandName}`
42
85
  const commandPreferences = LocalStorage.getItemSync(commandPreferencesKey)
43
86
 
44
87
  if (commandPreferences && typeof commandPreferences === 'string') {
45
88
  try {
46
- const parsed = JSON.parse(commandPreferences)
89
+ commandSavedValues = JSON.parse(commandPreferences)
47
90
  logger.log(
48
91
  `Loaded command preferences for ${extensionName}/${currentCommandName}:`,
49
- parsed,
92
+ commandSavedValues,
50
93
  )
51
- return parsed as Values
52
94
  } catch (parseError) {
53
95
  logger.error(`Failed to parse command preferences:`, parseError)
54
96
  }
55
97
  }
56
98
  }
57
-
58
- // Fall back to extension-level preferences
59
- const extensionPreferencesKey = `preferences.${extensionName}`
60
- const extensionPreferences = LocalStorage.getItemSync(
61
- extensionPreferencesKey,
62
- )
63
-
64
- if (extensionPreferences && typeof extensionPreferences === 'string') {
65
- try {
66
- const parsed = JSON.parse(extensionPreferences)
67
- logger.log(`Loaded extension preferences for ${extensionName}:`, parsed)
68
- return parsed as Values
69
- } catch (parseError) {
70
- logger.error(`Failed to parse extension preferences:`, parseError)
71
- }
72
- }
73
99
  } catch (error) {
74
100
  logger.error(`Failed to load preferences for ${extensionName}:`, error)
75
101
  }
76
102
 
77
- // Return empty preferences if none saved
78
- return {} as Values
103
+ // Merge: defaults < extension saved < command saved
104
+ return { ...defaults, ...extensionSavedValues, ...commandSavedValues } as Values
79
105
  }
80
106
 
81
107
  /**
@@ -69,6 +69,58 @@ describe('buildExtensionCommands', () => {
69
69
  "filePath": "/BASE_PATH/fixtures/simple-extension/src/show-state.tsx",
70
70
  "exists": true,
71
71
  "bundledPath": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle/show-state.js"
72
+ },
73
+ {
74
+ "name": "with-arguments",
75
+ "title": "With Arguments",
76
+ "subtitle": "Command with arguments",
77
+ "description": "Demonstrates command arguments (text, password, dropdown)",
78
+ "mode": "view",
79
+ "arguments": [
80
+ {
81
+ "name": "query",
82
+ "type": "text",
83
+ "placeholder": "Search query",
84
+ "required": true
85
+ },
86
+ {
87
+ "name": "secretKey",
88
+ "type": "password",
89
+ "placeholder": "Secret key"
90
+ },
91
+ {
92
+ "name": "category",
93
+ "type": "dropdown",
94
+ "placeholder": "Category",
95
+ "data": [
96
+ {
97
+ "title": "Work",
98
+ "value": "work"
99
+ },
100
+ {
101
+ "title": "Personal",
102
+ "value": "personal"
103
+ },
104
+ {
105
+ "title": "Other",
106
+ "value": "other"
107
+ }
108
+ ]
109
+ }
110
+ ],
111
+ "filePath": "/BASE_PATH/fixtures/simple-extension/src/with-arguments.tsx",
112
+ "exists": true,
113
+ "bundledPath": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle/with-arguments.js"
114
+ },
115
+ {
116
+ "name": "quick-action",
117
+ "title": "Quick Action",
118
+ "subtitle": "No-view command",
119
+ "description": "Copies current timestamp to clipboard without showing a view",
120
+ "mode": "no-view",
121
+ "filePath": "/BASE_PATH/fixtures/simple-extension/src/quick-action.tsx",
122
+ "exists": true,
123
+ "bundledPath": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle/quick-action.js"
72
124
  }
73
125
  ],
74
126
  "bundleDir": "/BASE_PATH/fixtures/simple-extension/.termcast-bundle"
package/src/build.tsx CHANGED
@@ -8,6 +8,7 @@ import * as termcastApi from './index'
8
8
  import * as opentuiReact from '@opentui/react'
9
9
  import * as opentuiCore from '@opentui/core'
10
10
  import * as react from 'react'
11
+ import { swiftLoaderPlugin } from './swift-loader'
11
12
 
12
13
  const GLOBALS_NAMESPACE = 'globals'
13
14
  const VIRTUAL_ENTRY_NAMESPACE = 'virtual-entry'
@@ -225,7 +226,7 @@ export async function buildExtensionCommands({
225
226
  target: target || (format === 'cjs' ? 'node' : 'bun'),
226
227
  format,
227
228
  // external: [],
228
- plugins: [aliasPlugin],
229
+ plugins: [aliasPlugin, swiftLoaderPlugin],
229
230
  naming: '[name].js',
230
231
  throw: false,
231
232
  })
package/src/cli.tsx CHANGED
@@ -2,10 +2,11 @@ import fs from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { execSync, spawn } from 'node:child_process'
4
4
  import { cac } from 'cac'
5
- import chokidar from 'chokidar'
5
+ import * as watcher from '@parcel/watcher'
6
6
  import { buildExtensionCommands } from './build'
7
7
  import { logger } from './logger'
8
8
  import { installExtension } from './utils'
9
+ import { searchStoreListings } from './store-api/search'
9
10
  import './globals'
10
11
  import { startDevMode, triggerRebuild } from './extensions/dev'
11
12
  import { compileExtension } from './compile'
@@ -66,13 +67,22 @@ checkForUpdates()
66
67
 
67
68
  cli
68
69
  .command('dev [path]', 'Run the extension in the current working directory')
69
- .action(async (extensionPath, options) => {
70
+ .action(async (rawExtensionPath, options) => {
70
71
  try {
71
- extensionPath = path.resolve(extensionPath || process.cwd())
72
+ // Check if the provided arg looks like a path (contains / or . or is existing dir)
73
+ const looksLikePath = rawExtensionPath && (
74
+ rawExtensionPath.includes('/') ||
75
+ rawExtensionPath.startsWith('.') ||
76
+ fs.existsSync(rawExtensionPath)
77
+ )
78
+ const extensionPath = path.resolve(looksLikePath ? rawExtensionPath : process.cwd())
72
79
  let isBuilding = false
73
80
 
74
81
  // Start dev mode with initial render
75
- await startDevMode({ extensionPath })
82
+ // Skip args up to and including "dev" subcommand, plus path if it looks like one
83
+ const devIndex = process.argv.findIndex((arg) => arg === 'dev')
84
+ const skipArgv = devIndex - 1 + (looksLikePath ? 1 : 0)
85
+ await startDevMode({ extensionPath, skipArgv })
76
86
 
77
87
  logger.log(`dev mode started`)
78
88
  // Only watch if running in a TTY (interactive terminal)
@@ -83,38 +93,18 @@ cli
83
93
 
84
94
  console.log('\nWatching for file changes...')
85
95
 
86
- // Watch entire extension directory
87
- const watcher = chokidar.watch(extensionPath, {
88
- persistent: true,
89
- ignoreInitial: true,
90
- awaitWriteFinish: {
91
- stabilityThreshold: 300,
92
- pollInterval: 100,
93
- },
94
- })
95
-
96
+ // Watch entire extension directory using @parcel/watcher
96
97
  const ignoredPatterns = [
97
- 'node_modules',
98
- '.termcast-bundle',
99
- '.git',
100
- 'app.log',
101
- 'dist',
102
- 'build',
98
+ '**/node_modules/**',
99
+ '**/.termcast-bundle/**',
100
+ '**/.git/**',
101
+ '**/.build/**', // Swift build output
102
+ '**/*.log',
103
+ '**/dist/**',
104
+ '**/build/**',
103
105
  ]
104
106
 
105
- const shouldIgnore = (filePath: string) => {
106
- const relativePath = path.relative(extensionPath, filePath)
107
- return ignoredPatterns.some(
108
- (pattern) =>
109
- relativePath.includes(pattern) || filePath.endsWith('.log'),
110
- )
111
- }
112
-
113
107
  const rebuild = async (filePath: string) => {
114
- if (shouldIgnore(filePath)) {
115
- return
116
- }
117
-
118
108
  if (isBuilding) {
119
109
  logger.log('Build already in progress, skipping...')
120
110
  return
@@ -133,11 +123,28 @@ cli
133
123
  }
134
124
  }
135
125
 
136
- watcher
137
- .on('change', rebuild)
138
- .on('add', rebuild)
139
- .on('unlink', rebuild)
140
- .on('error', (error) => logger.error('Watcher error:', error))
126
+ const subscription = await watcher.subscribe(
127
+ extensionPath,
128
+ (err, events) => {
129
+ if (err) {
130
+ logger.error('Watcher error:', err)
131
+ return
132
+ }
133
+ // Trigger rebuild for any event (create, update, delete)
134
+ if (events.length > 0) {
135
+ rebuild(events[0].path)
136
+ }
137
+ },
138
+ { ignore: ignoredPatterns }
139
+ )
140
+
141
+ // Clean up watcher on exit signals
142
+ const cleanup = async () => {
143
+ await subscription.unsubscribe()
144
+ process.exit(0)
145
+ }
146
+ process.on('SIGINT', cleanup)
147
+ process.on('SIGTERM', cleanup)
141
148
  } catch (e: any) {
142
149
  console.error('Failed to start dev mode:', e?.message || e)
143
150
  logger.error(e)
@@ -365,6 +372,40 @@ cli
365
372
  }
366
373
  })
367
374
 
375
+ cli
376
+ .command('raycast-search <query>', 'Search for extensions in the Raycast store')
377
+ .option('-n, --limit <number>', 'Number of results to show', { default: '10' })
378
+ .action(async (query: string, options: { limit: string }) => {
379
+ try {
380
+ const limit = parseInt(options.limit, 10)
381
+ const result = await searchStoreListings({ query, perPage: limit })
382
+
383
+ if (result.data.length === 0) {
384
+ console.log(`No extensions found for "${query}"`)
385
+ process.exit(0)
386
+ }
387
+
388
+ console.log(`Found ${result.data.length} extensions for "${query}":\n`)
389
+
390
+ for (const ext of result.data) {
391
+ const downloads = ext.download_count.toLocaleString()
392
+ const commands = ext.commands.map((c) => c.name).join(', ')
393
+ console.log(` ${ext.name}`)
394
+ console.log(` Path: extensions/${ext.relative_path.replace('extensions/', '')}`)
395
+ console.log(` Downloads: ${downloads}`)
396
+ console.log(` Commands: ${commands || 'none'}`)
397
+ console.log(` Description: ${ext.description.slice(0, 100)}${ext.description.length > 100 ? '...' : ''}`)
398
+ console.log()
399
+ }
400
+
401
+ console.log(`Download with: termcast download <extension-name>`)
402
+ process.exit(0)
403
+ } catch (error: any) {
404
+ console.error('Search failed:', error.message)
405
+ process.exit(1)
406
+ }
407
+ })
408
+
368
409
  cli
369
410
  .command('download <extensionName>', 'Download extension from Raycast extensions repo')
370
411
  .option('-o, --output <path>', 'Output directory', { default: '.' })
package/src/compile.tsx CHANGED
@@ -3,6 +3,7 @@ import path from 'node:path'
3
3
  import type { BunPlugin } from 'bun'
4
4
  import { logger } from './logger'
5
5
  import { getCommandsWithFiles } from './package-json'
6
+ import { swiftLoaderPlugin } from './swift-loader'
6
7
 
7
8
  const raycastAliasPlugin: BunPlugin = {
8
9
  name: 'raycast-to-termcast',
@@ -53,6 +54,7 @@ ${commandsArray}
53
54
  await startCompiledExtension({
54
55
  extensionPath: ${JSON.stringify(extensionPath)},
55
56
  compiledCommands,
57
+ skipArgv: 0,
56
58
  });
57
59
  }
58
60
 
@@ -184,18 +186,33 @@ export async function compileExtension({
184
186
  entrypoints: [tempEntryPath],
185
187
  target: bunTarget as 'bun',
186
188
  minify,
189
+ // bytecode: true, // TODO need to wait for opentui to support this removing top level await
190
+ sourcemap: 'external',
187
191
  compile: {
188
192
  outfile: defaultOutfile,
189
193
  },
190
- plugins: [raycastAliasPlugin],
194
+ plugins: [raycastAliasPlugin, swiftLoaderPlugin],
191
195
  throw: false,
192
196
  } as Parameters<typeof Bun.build>[0])
193
197
 
194
198
  if (!result.success) {
195
- const errorMessage = result.logs
196
- .map((log: any) => log.message || String(log))
197
- .join('\n')
198
- throw new Error(`Compile failed: ${errorMessage || 'Unknown error'}`)
199
+ const errorDetails = result.logs.map((log: any) => {
200
+ const parts = [log.message || String(log)]
201
+ if (log.position) {
202
+ parts.push(` at ${log.position.file}:${log.position.line}:${log.position.column}`)
203
+ }
204
+ if (log.notes) {
205
+ for (const note of log.notes) {
206
+ parts.push(` note: ${note.text}`)
207
+ if (note.location) {
208
+ parts.push(` at ${note.location.file}:${note.location.line}`)
209
+ }
210
+ }
211
+ }
212
+ return parts.join('\n')
213
+ })
214
+ logger.log('Compile errors:', JSON.stringify(result.logs, null, 2))
215
+ throw new Error(`Compile failed: ${errorDetails.join('\n\n') || 'Unknown error'}`)
199
216
  }
200
217
 
201
218
  logger.log('Build outputs:', result.outputs?.map((o) => o.path))