@textui/widgets 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (423) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/chart/area-chart.d.ts +4 -0
  4. package/dist/chart/area-chart.d.ts.map +1 -0
  5. package/dist/chart/area-chart.js +3 -0
  6. package/dist/chart/bar-chart.d.ts +32 -0
  7. package/dist/chart/bar-chart.d.ts.map +1 -0
  8. package/dist/chart/bar-chart.js +32 -0
  9. package/dist/chart/gauge.d.ts +26 -0
  10. package/dist/chart/gauge.d.ts.map +1 -0
  11. package/dist/chart/gauge.js +26 -0
  12. package/dist/chart/heatmap.d.ts +13 -0
  13. package/dist/chart/heatmap.d.ts.map +1 -0
  14. package/dist/chart/heatmap.js +27 -0
  15. package/dist/chart/histogram.d.ts +12 -0
  16. package/dist/chart/histogram.d.ts.map +1 -0
  17. package/dist/chart/histogram.js +22 -0
  18. package/dist/chart/index.d.ts +20 -0
  19. package/dist/chart/index.d.ts.map +1 -0
  20. package/dist/chart/index.js +32 -0
  21. package/dist/chart/line-chart.d.ts +7 -0
  22. package/dist/chart/line-chart.d.ts.map +1 -0
  23. package/dist/chart/line-chart.js +75 -0
  24. package/dist/chart/shared.d.ts +34 -0
  25. package/dist/chart/shared.d.ts.map +1 -0
  26. package/dist/chart/shared.js +78 -0
  27. package/dist/chart/sparkline.d.ts +15 -0
  28. package/dist/chart/sparkline.d.ts.map +1 -0
  29. package/dist/chart/sparkline.js +22 -0
  30. package/dist/control/button.d.ts +27 -0
  31. package/dist/control/button.d.ts.map +1 -0
  32. package/dist/control/button.js +130 -0
  33. package/dist/control/checkbox.d.ts +10 -0
  34. package/dist/control/checkbox.d.ts.map +1 -0
  35. package/dist/control/checkbox.js +31 -0
  36. package/dist/control/index.d.ts +20 -0
  37. package/dist/control/index.d.ts.map +1 -0
  38. package/dist/control/index.js +36 -0
  39. package/dist/control/radio-group.d.ts +17 -0
  40. package/dist/control/radio-group.d.ts.map +1 -0
  41. package/dist/control/radio-group.js +32 -0
  42. package/dist/control/search-box.d.ts +7 -0
  43. package/dist/control/search-box.d.ts.map +1 -0
  44. package/dist/control/search-box.js +3 -0
  45. package/dist/control/select.d.ts +42 -0
  46. package/dist/control/select.d.ts.map +1 -0
  47. package/dist/control/select.js +166 -0
  48. package/dist/control/shared.d.ts +41 -0
  49. package/dist/control/shared.d.ts.map +1 -0
  50. package/dist/control/shared.js +1 -0
  51. package/dist/control/slider.d.ts +14 -0
  52. package/dist/control/slider.d.ts.map +1 -0
  53. package/dist/control/slider.js +45 -0
  54. package/dist/control/switch.d.ts +10 -0
  55. package/dist/control/switch.d.ts.map +1 -0
  56. package/dist/control/switch.js +32 -0
  57. package/dist/control/text-area.d.ts +87 -0
  58. package/dist/control/text-area.d.ts.map +1 -0
  59. package/dist/control/text-area.js +299 -0
  60. package/dist/control/text-input.d.ts +10 -0
  61. package/dist/control/text-input.d.ts.map +1 -0
  62. package/dist/control/text-input.js +129 -0
  63. package/dist/data/code-viewer.d.ts +71 -0
  64. package/dist/data/code-viewer.d.ts.map +1 -0
  65. package/dist/data/code-viewer.js +232 -0
  66. package/dist/data/feed.d.ts +43 -0
  67. package/dist/data/feed.d.ts.map +1 -0
  68. package/dist/data/feed.js +178 -0
  69. package/dist/data/index.d.ts +54 -0
  70. package/dist/data/index.d.ts.map +1 -0
  71. package/dist/data/index.js +187 -0
  72. package/dist/data/list.d.ts +31 -0
  73. package/dist/data/list.d.ts.map +1 -0
  74. package/dist/data/list.js +104 -0
  75. package/dist/data/log-viewer.d.ts +26 -0
  76. package/dist/data/log-viewer.d.ts.map +1 -0
  77. package/dist/data/log-viewer.js +69 -0
  78. package/dist/data/markdown-view.d.ts +31 -0
  79. package/dist/data/markdown-view.d.ts.map +1 -0
  80. package/dist/data/markdown-view.js +139 -0
  81. package/dist/data/pagination.d.ts +9 -0
  82. package/dist/data/pagination.d.ts.map +1 -0
  83. package/dist/data/pagination.js +18 -0
  84. package/dist/data/scroll-thumb.d.ts +15 -0
  85. package/dist/data/scroll-thumb.d.ts.map +1 -0
  86. package/dist/data/scroll-thumb.js +32 -0
  87. package/dist/data/shared.d.ts +12 -0
  88. package/dist/data/shared.d.ts.map +1 -0
  89. package/dist/data/shared.js +17 -0
  90. package/dist/data/tree.d.ts +35 -0
  91. package/dist/data/tree.d.ts.map +1 -0
  92. package/dist/data/tree.js +158 -0
  93. package/dist/decorations.d.ts +88 -0
  94. package/dist/decorations.d.ts.map +1 -0
  95. package/dist/decorations.js +135 -0
  96. package/dist/display/alert.d.ts +8 -0
  97. package/dist/display/alert.d.ts.map +1 -0
  98. package/dist/display/alert.js +12 -0
  99. package/dist/display/badge.d.ts +10 -0
  100. package/dist/display/badge.d.ts.map +1 -0
  101. package/dist/display/badge.js +21 -0
  102. package/dist/display/card.d.ts +8 -0
  103. package/dist/display/card.d.ts.map +1 -0
  104. package/dist/display/card.js +12 -0
  105. package/dist/display/empty-state.d.ts +10 -0
  106. package/dist/display/empty-state.d.ts.map +1 -0
  107. package/dist/display/empty-state.js +5 -0
  108. package/dist/display/error-state.d.ts +9 -0
  109. package/dist/display/error-state.d.ts.map +1 -0
  110. package/dist/display/error-state.js +7 -0
  111. package/dist/display/heading.d.ts +6 -0
  112. package/dist/display/heading.d.ts.map +1 -0
  113. package/dist/display/heading.js +8 -0
  114. package/dist/display/index.d.ts +25 -0
  115. package/dist/display/index.d.ts.map +1 -0
  116. package/dist/display/index.js +52 -0
  117. package/dist/display/key-value.d.ts +14 -0
  118. package/dist/display/key-value.d.ts.map +1 -0
  119. package/dist/display/key-value.js +11 -0
  120. package/dist/display/label.d.ts +6 -0
  121. package/dist/display/label.d.ts.map +1 -0
  122. package/dist/display/label.js +3 -0
  123. package/dist/display/marquee.d.ts +36 -0
  124. package/dist/display/marquee.d.ts.map +1 -0
  125. package/dist/display/marquee.js +55 -0
  126. package/dist/display/progress.d.ts +39 -0
  127. package/dist/display/progress.d.ts.map +1 -0
  128. package/dist/display/progress.js +46 -0
  129. package/dist/display/skeleton.d.ts +20 -0
  130. package/dist/display/skeleton.d.ts.map +1 -0
  131. package/dist/display/skeleton.js +20 -0
  132. package/dist/display/spinner.d.ts +7 -0
  133. package/dist/display/spinner.d.ts.map +1 -0
  134. package/dist/display/spinner.js +9 -0
  135. package/dist/display/status-dot.d.ts +8 -0
  136. package/dist/display/status-dot.d.ts.map +1 -0
  137. package/dist/display/status-dot.js +13 -0
  138. package/dist/display/timeline.d.ts +12 -0
  139. package/dist/display/timeline.d.ts.map +1 -0
  140. package/dist/display/timeline.js +22 -0
  141. package/dist/find.d.ts +74 -0
  142. package/dist/find.d.ts.map +1 -0
  143. package/dist/find.js +102 -0
  144. package/dist/form/danger-zone.d.ts +11 -0
  145. package/dist/form/danger-zone.d.ts.map +1 -0
  146. package/dist/form/danger-zone.js +15 -0
  147. package/dist/form/field.d.ts +19 -0
  148. package/dist/form/field.d.ts.map +1 -0
  149. package/dist/form/field.js +35 -0
  150. package/dist/form/form-actions.d.ts +11 -0
  151. package/dist/form/form-actions.d.ts.map +1 -0
  152. package/dist/form/form-actions.js +16 -0
  153. package/dist/form/form-section.d.ts +7 -0
  154. package/dist/form/form-section.d.ts.map +1 -0
  155. package/dist/form/form-section.js +5 -0
  156. package/dist/form/form.d.ts +7 -0
  157. package/dist/form/form.d.ts.map +1 -0
  158. package/dist/form/form.js +3 -0
  159. package/dist/form/index.d.ts +42 -0
  160. package/dist/form/index.d.ts.map +1 -0
  161. package/dist/form/index.js +140 -0
  162. package/dist/form/shared.d.ts +25 -0
  163. package/dist/form/shared.d.ts.map +1 -0
  164. package/dist/form/shared.js +9 -0
  165. package/dist/index.d.ts +26 -0
  166. package/dist/index.d.ts.map +1 -0
  167. package/dist/index.js +62 -0
  168. package/dist/layout/center.d.ts +7 -0
  169. package/dist/layout/center.d.ts.map +1 -0
  170. package/dist/layout/center.js +8 -0
  171. package/dist/layout/column.d.ts +3 -0
  172. package/dist/layout/column.d.ts.map +1 -0
  173. package/dist/layout/column.js +2 -0
  174. package/dist/layout/divider.d.ts +11 -0
  175. package/dist/layout/divider.d.ts.map +1 -0
  176. package/dist/layout/divider.js +13 -0
  177. package/dist/layout/grid.d.ts +10 -0
  178. package/dist/layout/grid.d.ts.map +1 -0
  179. package/dist/layout/grid.js +22 -0
  180. package/dist/layout/index.d.ts +19 -0
  181. package/dist/layout/index.d.ts.map +1 -0
  182. package/dist/layout/index.js +36 -0
  183. package/dist/layout/panel.d.ts +37 -0
  184. package/dist/layout/panel.d.ts.map +1 -0
  185. package/dist/layout/panel.js +71 -0
  186. package/dist/layout/row.d.ts +7 -0
  187. package/dist/layout/row.d.ts.map +1 -0
  188. package/dist/layout/row.js +2 -0
  189. package/dist/layout/scroll-view.d.ts +27 -0
  190. package/dist/layout/scroll-view.d.ts.map +1 -0
  191. package/dist/layout/scroll-view.js +93 -0
  192. package/dist/layout/splitter.d.ts +10 -0
  193. package/dist/layout/splitter.d.ts.map +1 -0
  194. package/dist/layout/splitter.js +9 -0
  195. package/dist/layout/stack.d.ts +7 -0
  196. package/dist/layout/stack.d.ts.map +1 -0
  197. package/dist/layout/stack.js +5 -0
  198. package/dist/navigation/breadcrumb.d.ts +14 -0
  199. package/dist/navigation/breadcrumb.d.ts.map +1 -0
  200. package/dist/navigation/breadcrumb.js +24 -0
  201. package/dist/navigation/index.d.ts +17 -0
  202. package/dist/navigation/index.d.ts.map +1 -0
  203. package/dist/navigation/index.js +30 -0
  204. package/dist/navigation/key-hints.d.ts +11 -0
  205. package/dist/navigation/key-hints.d.ts.map +1 -0
  206. package/dist/navigation/key-hints.js +13 -0
  207. package/dist/navigation/menu.d.ts +35 -0
  208. package/dist/navigation/menu.d.ts.map +1 -0
  209. package/dist/navigation/menu.js +88 -0
  210. package/dist/navigation/status-bar.d.ts +18 -0
  211. package/dist/navigation/status-bar.d.ts.map +1 -0
  212. package/dist/navigation/status-bar.js +12 -0
  213. package/dist/navigation/tabs.d.ts +20 -0
  214. package/dist/navigation/tabs.d.ts.map +1 -0
  215. package/dist/navigation/tabs.js +41 -0
  216. package/dist/navigation/toolbar.d.ts +14 -0
  217. package/dist/navigation/toolbar.d.ts.map +1 -0
  218. package/dist/navigation/toolbar.js +10 -0
  219. package/dist/navigation/wizard.d.ts +15 -0
  220. package/dist/navigation/wizard.d.ts.map +1 -0
  221. package/dist/navigation/wizard.js +17 -0
  222. package/dist/overlay/command-palette.d.ts +63 -0
  223. package/dist/overlay/command-palette.d.ts.map +1 -0
  224. package/dist/overlay/command-palette.js +415 -0
  225. package/dist/overlay/dialog.d.ts +16 -0
  226. package/dist/overlay/dialog.d.ts.map +1 -0
  227. package/dist/overlay/dialog.js +44 -0
  228. package/dist/overlay/index.d.ts +84 -0
  229. package/dist/overlay/index.d.ts.map +1 -0
  230. package/dist/overlay/index.js +157 -0
  231. package/dist/overlay/layer-scope.d.ts +21 -0
  232. package/dist/overlay/layer-scope.d.ts.map +1 -0
  233. package/dist/overlay/layer-scope.js +5 -0
  234. package/dist/overlay/path-picker.d.ts +14 -0
  235. package/dist/overlay/path-picker.d.ts.map +1 -0
  236. package/dist/overlay/path-picker.js +200 -0
  237. package/dist/overlay/prompt-dialog.d.ts +12 -0
  238. package/dist/overlay/prompt-dialog.d.ts.map +1 -0
  239. package/dist/overlay/prompt-dialog.js +29 -0
  240. package/dist/overlay/shared.d.ts +17 -0
  241. package/dist/overlay/shared.d.ts.map +1 -0
  242. package/dist/overlay/shared.js +17 -0
  243. package/dist/overlay/toast-host.d.ts +8 -0
  244. package/dist/overlay/toast-host.d.ts.map +1 -0
  245. package/dist/overlay/toast-host.js +19 -0
  246. package/dist/overlay/toast.d.ts +9 -0
  247. package/dist/overlay/toast.d.ts.map +1 -0
  248. package/dist/overlay/toast.js +20 -0
  249. package/dist/overlay/tooltip.d.ts +6 -0
  250. package/dist/overlay/tooltip.d.ts.map +1 -0
  251. package/dist/overlay/tooltip.js +11 -0
  252. package/dist/panel/index.d.ts +79 -0
  253. package/dist/panel/index.d.ts.map +1 -0
  254. package/dist/panel/index.js +256 -0
  255. package/dist/panel/resource-panel.d.ts +93 -0
  256. package/dist/panel/resource-panel.d.ts.map +1 -0
  257. package/dist/panel/resource-panel.js +213 -0
  258. package/dist/panel/shared.d.ts +6 -0
  259. package/dist/panel/shared.d.ts.map +1 -0
  260. package/dist/panel/shared.js +4 -0
  261. package/dist/shells/console-shell.d.ts +8 -0
  262. package/dist/shells/console-shell.d.ts.map +1 -0
  263. package/dist/shells/console-shell.js +30 -0
  264. package/dist/shells/index.d.ts +20 -0
  265. package/dist/shells/index.d.ts.map +1 -0
  266. package/dist/shells/index.js +61 -0
  267. package/dist/shells/paper-shell.d.ts +9 -0
  268. package/dist/shells/paper-shell.d.ts.map +1 -0
  269. package/dist/shells/paper-shell.js +23 -0
  270. package/dist/shells/plain-shell.d.ts +3 -0
  271. package/dist/shells/plain-shell.d.ts.map +1 -0
  272. package/dist/shells/plain-shell.js +11 -0
  273. package/dist/shells/shared.d.ts +12 -0
  274. package/dist/shells/shared.d.ts.map +1 -0
  275. package/dist/shells/shared.js +21 -0
  276. package/dist/shells/workbench-shell.d.ts +9 -0
  277. package/dist/shells/workbench-shell.d.ts.map +1 -0
  278. package/dist/shells/workbench-shell.js +43 -0
  279. package/dist/surface/bar-layout.d.ts +4 -0
  280. package/dist/surface/bar-layout.d.ts.map +1 -0
  281. package/dist/surface/bar-layout.js +7 -0
  282. package/dist/surface/index.d.ts +58 -0
  283. package/dist/surface/index.d.ts.map +1 -0
  284. package/dist/surface/index.js +48 -0
  285. package/dist/surface/inline-layout.d.ts +4 -0
  286. package/dist/surface/inline-layout.d.ts.map +1 -0
  287. package/dist/surface/inline-layout.js +7 -0
  288. package/dist/surface/mount-view.d.ts +7 -0
  289. package/dist/surface/mount-view.d.ts.map +1 -0
  290. package/dist/surface/mount-view.js +19 -0
  291. package/dist/surface/rail-layout.d.ts +4 -0
  292. package/dist/surface/rail-layout.d.ts.map +1 -0
  293. package/dist/surface/rail-layout.js +19 -0
  294. package/dist/surface/shared.d.ts +7 -0
  295. package/dist/surface/shared.d.ts.map +1 -0
  296. package/dist/surface/shared.js +1 -0
  297. package/dist/surface/single-layout.d.ts +4 -0
  298. package/dist/surface/single-layout.d.ts.map +1 -0
  299. package/dist/surface/single-layout.js +18 -0
  300. package/dist/surface/split-layout.d.ts +4 -0
  301. package/dist/surface/split-layout.d.ts.map +1 -0
  302. package/dist/surface/split-layout.js +7 -0
  303. package/dist/surface/stack-layout.d.ts +4 -0
  304. package/dist/surface/stack-layout.d.ts.map +1 -0
  305. package/dist/surface/stack-layout.js +22 -0
  306. package/dist/surface/surface-area.d.ts +16 -0
  307. package/dist/surface/surface-area.d.ts.map +1 -0
  308. package/dist/surface/surface-area.js +32 -0
  309. package/dist/surface/tabs-layout.d.ts +4 -0
  310. package/dist/surface/tabs-layout.d.ts.map +1 -0
  311. package/dist/surface/tabs-layout.js +24 -0
  312. package/dist/tone.d.ts +16 -0
  313. package/dist/tone.d.ts.map +1 -0
  314. package/dist/tone.js +45 -0
  315. package/dist/viewport.d.ts +30 -0
  316. package/dist/viewport.d.ts.map +1 -0
  317. package/dist/viewport.js +17 -0
  318. package/package.json +54 -0
  319. package/src/chart/area-chart.ts +9 -0
  320. package/src/chart/bar-chart.ts +74 -0
  321. package/src/chart/gauge.ts +60 -0
  322. package/src/chart/heatmap.ts +49 -0
  323. package/src/chart/histogram.ts +36 -0
  324. package/src/chart/index.ts +36 -0
  325. package/src/chart/line-chart.ts +100 -0
  326. package/src/chart/shared.ts +112 -0
  327. package/src/chart/sparkline.ts +46 -0
  328. package/src/control/button.ts +184 -0
  329. package/src/control/checkbox.ts +48 -0
  330. package/src/control/index.ts +40 -0
  331. package/src/control/radio-group.ts +60 -0
  332. package/src/control/search-box.ts +15 -0
  333. package/src/control/select.ts +230 -0
  334. package/src/control/shared.ts +41 -0
  335. package/src/control/slider.ts +63 -0
  336. package/src/control/switch.ts +39 -0
  337. package/src/control/text-area.ts +390 -0
  338. package/src/control/text-input.ts +150 -0
  339. package/src/data/code-viewer.ts +337 -0
  340. package/src/data/feed.ts +204 -0
  341. package/src/data/index.ts +243 -0
  342. package/src/data/list.ts +149 -0
  343. package/src/data/log-viewer.ts +105 -0
  344. package/src/data/markdown-view.ts +182 -0
  345. package/src/data/pagination.ts +31 -0
  346. package/src/data/scroll-thumb.ts +40 -0
  347. package/src/data/shared.ts +23 -0
  348. package/src/data/tree.ts +215 -0
  349. package/src/decorations.ts +176 -0
  350. package/src/display/alert.ts +28 -0
  351. package/src/display/badge.ts +40 -0
  352. package/src/display/card.ts +23 -0
  353. package/src/display/empty-state.ts +21 -0
  354. package/src/display/error-state.ts +23 -0
  355. package/src/display/heading.ts +17 -0
  356. package/src/display/index.ts +55 -0
  357. package/src/display/key-value.ts +32 -0
  358. package/src/display/label.ts +11 -0
  359. package/src/display/marquee.ts +88 -0
  360. package/src/display/progress.ts +92 -0
  361. package/src/display/skeleton.ts +34 -0
  362. package/src/display/spinner.ts +20 -0
  363. package/src/display/status-dot.ts +24 -0
  364. package/src/display/timeline.ts +47 -0
  365. package/src/find.ts +138 -0
  366. package/src/form/danger-zone.ts +34 -0
  367. package/src/form/field.ts +61 -0
  368. package/src/form/form-actions.ts +35 -0
  369. package/src/form/form-section.ts +16 -0
  370. package/src/form/form.ts +13 -0
  371. package/src/form/index.ts +191 -0
  372. package/src/form/shared.ts +36 -0
  373. package/src/index.ts +63 -0
  374. package/src/layout/center.ts +17 -0
  375. package/src/layout/column.ts +6 -0
  376. package/src/layout/divider.ts +31 -0
  377. package/src/layout/grid.ts +34 -0
  378. package/src/layout/index.ts +39 -0
  379. package/src/layout/panel.ts +114 -0
  380. package/src/layout/row.ts +11 -0
  381. package/src/layout/scroll-view.ts +115 -0
  382. package/src/layout/splitter.ts +24 -0
  383. package/src/layout/stack.ts +12 -0
  384. package/src/navigation/breadcrumb.ts +43 -0
  385. package/src/navigation/index.ts +33 -0
  386. package/src/navigation/key-hints.ts +25 -0
  387. package/src/navigation/menu.ts +134 -0
  388. package/src/navigation/status-bar.ts +43 -0
  389. package/src/navigation/tabs.ts +73 -0
  390. package/src/navigation/toolbar.ts +25 -0
  391. package/src/navigation/wizard.ts +43 -0
  392. package/src/overlay/command-palette.ts +485 -0
  393. package/src/overlay/dialog.ts +65 -0
  394. package/src/overlay/index.ts +232 -0
  395. package/src/overlay/layer-scope.ts +26 -0
  396. package/src/overlay/path-picker.ts +215 -0
  397. package/src/overlay/prompt-dialog.ts +45 -0
  398. package/src/overlay/shared.ts +19 -0
  399. package/src/overlay/toast-host.ts +30 -0
  400. package/src/overlay/toast.ts +35 -0
  401. package/src/overlay/tooltip.ts +17 -0
  402. package/src/panel/index.ts +317 -0
  403. package/src/panel/resource-panel.ts +304 -0
  404. package/src/panel/shared.ts +8 -0
  405. package/src/shells/console-shell.ts +47 -0
  406. package/src/shells/index.ts +66 -0
  407. package/src/shells/paper-shell.ts +31 -0
  408. package/src/shells/plain-shell.ts +19 -0
  409. package/src/shells/shared.ts +24 -0
  410. package/src/shells/workbench-shell.ts +62 -0
  411. package/src/surface/bar-layout.ts +11 -0
  412. package/src/surface/index.ts +53 -0
  413. package/src/surface/inline-layout.ts +11 -0
  414. package/src/surface/mount-view.ts +30 -0
  415. package/src/surface/rail-layout.ts +27 -0
  416. package/src/surface/shared.ts +7 -0
  417. package/src/surface/single-layout.ts +25 -0
  418. package/src/surface/split-layout.ts +11 -0
  419. package/src/surface/stack-layout.ts +32 -0
  420. package/src/surface/surface-area.ts +46 -0
  421. package/src/surface/tabs-layout.ts +30 -0
  422. package/src/tone.ts +48 -0
  423. package/src/viewport.ts +45 -0
@@ -0,0 +1,32 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ /**
3
+ * A one-cell scrollbar.
4
+ *
5
+ * Exported because anything with a viewport wants the same one: two components
6
+ * drawing their own would drift, and the thumb is the only thing on screen
7
+ * that says how much of a file you are looking at.
8
+ */
9
+ export const ScrollThumb = defineComponent('ScrollThumb', ({ total, rows, offset, focused }) => {
10
+ const theme = useTheme();
11
+ // Not border glyphs: `left` and `right` are the same character in every
12
+ // border style, so a thumb drawn with one would be invisible against a
13
+ // track drawn with the other.
14
+ const thumbChar = theme.glyphs.progressFull;
15
+ const trackChar = theme.glyphs.progressEmpty;
16
+ const track = Math.max(1, rows);
17
+ const size = Math.max(1, Math.round((rows / Math.max(1, total)) * track));
18
+ const span = Math.max(0, track - size);
19
+ const position = total <= rows
20
+ ? 0
21
+ : Math.round((offset / Math.max(1, total - rows)) * span);
22
+ const cells = [];
23
+ for (let i = 0; i < track; i++) {
24
+ const onThumb = i >= position && i < position + size;
25
+ cells.push(h('text', {
26
+ key: i,
27
+ content: onThumb ? thumbChar : trackChar,
28
+ fg: onThumb ? (focused ? 'focus' : 'border') : 'borderSubtle',
29
+ }));
30
+ }
31
+ return h('box', { width: 1, direction: 'column' }, ...cells);
32
+ });
@@ -0,0 +1,12 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ /**
3
+ * An entry that reports how tall it turned out to be.
4
+ *
5
+ * Through a ref rather than state, deliberately: a height arriving must not
6
+ * schedule a render, or every measurement would cause the next measurement.
7
+ */
8
+ export declare const FeedEntry: (props: BoxProps & {
9
+ onHeight(height: number): void;
10
+ }) => import("@textui/core").RenderOutput;
11
+ export declare const FeedScrollbar: (props: Record<string, never>) => import("@textui/core").RenderOutput;
12
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/data/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C;;;;;GAKG;AACH,eAAO,MAAM,SAAS;qBAAiD,MAAM,GAAG,IAAI;yCAQnF,CAAC;AAEF,eAAO,MAAM,aAAa,uEAGxB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { defineComponent, h, useEffect, useMeasure, useTheme } from '@textui/core';
2
+ /**
3
+ * An entry that reports how tall it turned out to be.
4
+ *
5
+ * Through a ref rather than state, deliberately: a height arriving must not
6
+ * schedule a render, or every measurement would cause the next measurement.
7
+ */
8
+ export const FeedEntry = defineComponent('FeedEntry', (props) => {
9
+ const { onHeight, children, ...rest } = props;
10
+ const measured = useMeasure();
11
+ useEffect(() => { onHeight(measured.height); }, [measured.height]);
12
+ return h('box', { direction: 'column', ...rest }, children);
13
+ });
14
+ export const FeedScrollbar = defineComponent('FeedScrollbar', () => {
15
+ const theme = useTheme();
16
+ return h('box', { width: 1, fill: theme.borderChars().left, fg: 'borderSubtle' });
17
+ });
@@ -0,0 +1,35 @@
1
+ import type { BoxProps, SemanticVariant } from '@textui/core';
2
+ export interface TreeNode {
3
+ id: string;
4
+ label: string;
5
+ icon?: string;
6
+ children?: TreeNode[];
7
+ /** Children exist but are not loaded yet. */
8
+ hasChildren?: boolean;
9
+ tone?: SemanticVariant;
10
+ meta?: string;
11
+ }
12
+ export interface TreeProps extends BoxProps {
13
+ nodes: TreeNode[];
14
+ selectedId?: string;
15
+ expandedIds?: string[];
16
+ onSelect?(id: string, node: TreeNode): void;
17
+ onActivate?(id: string, node: TreeNode): void;
18
+ onToggle?(id: string, expanded: boolean): void;
19
+ visibleRows?: number;
20
+ indent?: number;
21
+ /**
22
+ * What the expand mark looks like, when a chevron is not what it means.
23
+ *
24
+ * A file tree's twisty is not only "there is more here" - it is also the one
25
+ * thing on the row that says this is a folder, because a folder has no size
26
+ * beside it and nothing else distinguishes it. A caller that knows its rows
27
+ * are folders can say so; everything else gets the theme's chevrons.
28
+ */
29
+ twistyOpen?: string;
30
+ twistyClosed?: string;
31
+ /** Claim focus on mount, if nothing in this scope already has it. */
32
+ autoFocus?: boolean;
33
+ }
34
+ export declare const Tree: (props: TreeProps) => import("@textui/core").RenderOutput;
35
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/data/tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAc9D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC;IACtB,6CAA6C;IAC7C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAU,SAAQ,QAAQ;IACzC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC5C,UAAU,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAmBD,eAAO,MAAM,IAAI,2DAqJf,CAAC"}
@@ -0,0 +1,158 @@
1
+ import { chorded, defineComponent, h, useFocus, useInput, useMeasure, useTheme, } from '@textui/core';
2
+ import { usePanelState } from '../panel/index.js';
3
+ import { TONE } from '../tone.js';
4
+ import { viewportRows } from '../viewport.js';
5
+ function flatten(nodes, expanded, depth = 0, out = []) {
6
+ for (const node of nodes) {
7
+ const expandable = Boolean(node.hasChildren || (node.children && node.children.length > 0));
8
+ const isExpanded = expanded.has(node.id);
9
+ out.push({ node, depth, expanded: isExpanded, expandable });
10
+ if (isExpanded && node.children)
11
+ flatten(node.children, expanded, depth + 1, out);
12
+ }
13
+ return out;
14
+ }
15
+ export const Tree = defineComponent('Tree', (props) => {
16
+ const theme = useTheme();
17
+ const { nodes, selectedId, expandedIds, onSelect, onActivate, onToggle, visibleRows, indent = 2, twistyOpen, twistyClosed, autoFocus, ...rest } = props;
18
+ const focus = useFocus({ autoFocus });
19
+ const measured = useMeasure();
20
+ const treePage = viewportRows(props, measured, 10, { requested: visibleRows });
21
+ /*
22
+ * Uncontrolled expansion belongs to the panel when there is one: a JSON file
23
+ * opened as a structure, switched away from and switched back to, comes back
24
+ * open where it was rather than collapsed to the root. A tree in a sidebar
25
+ * is in no panel and keeps ordinary component state, which is what it had.
26
+ */
27
+ const [treeView, setTreeView] = usePanelState({ expanded: [], selected: null });
28
+ const internalExpanded = treeView.expanded;
29
+ const setInternalExpanded = (next) => setTreeView({ expanded: next });
30
+ const internalSelected = treeView.selected;
31
+ const setInternalSelected = (next) => setTreeView({ selected: next });
32
+ const expanded = new Set(expandedIds ?? internalExpanded);
33
+ const rows = flatten(nodes, expanded);
34
+ const currentId = selectedId ?? internalSelected ?? rows[0]?.node.id ?? null;
35
+ const index = Math.max(0, rows.findIndex((r) => r.node.id === currentId));
36
+ const select = (next) => {
37
+ const row = rows[Math.max(0, Math.min(rows.length - 1, next))];
38
+ if (!row)
39
+ return;
40
+ if (selectedId === undefined)
41
+ setInternalSelected(row.node.id);
42
+ onSelect?.(row.node.id, row.node);
43
+ };
44
+ const toggle = (id, next) => {
45
+ if (expandedIds === undefined) {
46
+ setInternalExpanded(next
47
+ ? [...internalExpanded, id]
48
+ : internalExpanded.filter((e) => e !== id));
49
+ }
50
+ onToggle?.(id, next);
51
+ };
52
+ useInput((event) => {
53
+ const row = rows[index];
54
+ if (!row || chorded(event))
55
+ return false;
56
+ switch (event.name) {
57
+ case 'up':
58
+ select(index - 1);
59
+ return true;
60
+ case 'down':
61
+ select(index + 1);
62
+ return true;
63
+ case 'pageup':
64
+ select(index - treePage);
65
+ return true;
66
+ case 'pagedown':
67
+ select(index + treePage);
68
+ return true;
69
+ case 'home':
70
+ select(0);
71
+ return true;
72
+ case 'end':
73
+ select(rows.length - 1);
74
+ return true;
75
+ case 'right':
76
+ // Right expands, and only moves inward once already expanded.
77
+ if (row.expandable && !row.expanded)
78
+ toggle(row.node.id, true);
79
+ else
80
+ select(index + 1);
81
+ return true;
82
+ case 'left':
83
+ if (row.expandable && row.expanded)
84
+ toggle(row.node.id, false);
85
+ else {
86
+ const parent = rows.slice(0, index).reverse().find((r) => r.depth < row.depth);
87
+ if (parent)
88
+ select(rows.indexOf(parent));
89
+ }
90
+ return true;
91
+ case 'enter':
92
+ if (row.expandable)
93
+ toggle(row.node.id, !row.expanded);
94
+ onActivate?.(row.node.id, row.node);
95
+ return true;
96
+ default: return false;
97
+ }
98
+ }, { focusId: focus.id });
99
+ // As with the list: how many rows fit is a question for the layout, not for
100
+ // the data. A deep tree scrolls inside its pane instead of stretching it.
101
+ const shown = viewportRows(props, measured, rows.length, { requested: visibleRows });
102
+ const window = rows.length <= shown
103
+ ? rows
104
+ : rows.slice(Math.max(0, Math.min(index - Math.floor(shown / 2), rows.length - shown)), Math.max(0, Math.min(index - Math.floor(shown / 2), rows.length - shown)) + shown);
105
+ /*
106
+ * One glyph column, and a second only when something needs both.
107
+ *
108
+ * A row that cannot expand has no twisty, so its icon goes in the twisty's
109
+ * place - otherwise a file sits one column right of a folder at the same
110
+ * depth and reads as being inside it. That was exactly the bug: an explorer
111
+ * that puts the folder glyph *in* the twisty (which is what `twistyClosed`
112
+ * is for) had its files pushed two columns clear of their siblings the
113
+ * moment they grew icons of their own.
114
+ *
115
+ * A second column appears only for a tree where something expandable also
116
+ * has an icon - a chevron *and* a folder mark - and then it is reserved on
117
+ * every row, including the ones that leave it blank, because a column that
118
+ * comes and go by row is the same misalignment wearing a different hat.
119
+ * Measured over every row rather than the visible ones, so scrolling cannot
120
+ * shift the layout under you.
121
+ */
122
+ const iconColumn = rows.some((r) => r.expandable && r.node.icon !== undefined);
123
+ return h('box', { id: focus.id, role: 'tree', direction: 'column', ...rest }, ...window.map((row) => {
124
+ const active = row.node.id === currentId;
125
+ const twisty = row.expandable
126
+ ? (row.expanded ? (twistyOpen ?? theme.glyphs.chevronDown)
127
+ : (twistyClosed ?? theme.glyphs.chevronRight))
128
+ : (iconColumn ? ' ' : row.node.icon ?? ' ');
129
+ // The marker carries the node's colour only when it *is* the node's
130
+ // icon; a twisty is structure and takes the row's own colour.
131
+ const markerTone = !row.expandable && !iconColumn && row.node.tone !== undefined
132
+ ? TONE[row.node.tone]
133
+ : undefined;
134
+ return h('box', {
135
+ key: row.node.id,
136
+ role: 'treeitem',
137
+ label: row.node.label,
138
+ selected: active,
139
+ direction: 'row',
140
+ gap: 1,
141
+ bg: active && focus.focused ? 'selected' : active ? 'active' : undefined,
142
+ fg: active && focus.focused ? 'inverted' : undefined,
143
+ onClick: () => {
144
+ if (selectedId === undefined)
145
+ setInternalSelected(row.node.id);
146
+ onSelect?.(row.node.id, row.node);
147
+ },
148
+ }, h('text', {
149
+ content: ' '.repeat(row.depth * indent) + twisty,
150
+ ...(markerTone !== undefined && !(active && focus.focused) ? { fg: markerTone } : {}),
151
+ }), iconColumn
152
+ ? h('text', {
153
+ content: row.node.icon ?? ' ',
154
+ ...(row.node.tone !== undefined ? { fg: TONE[row.node.tone] } : {}),
155
+ })
156
+ : null, h('text', { content: row.node.label, flex: 1, truncate: 'end' }), row.node.meta ? h('text', { content: row.node.meta, fg: active ? undefined : 'muted' }) : null);
157
+ }));
158
+ });
@@ -0,0 +1,88 @@
1
+ import type { BindingPath, ReactiveStore, SemanticVariant, StyleColor } from '@textui/core';
2
+ /**
3
+ * Marks on resources.
4
+ *
5
+ * A tree of files is the same tree whether or not anything has an opinion
6
+ * about the files in it - so "this one is modified", "this one has an error",
7
+ * "this one matched your search" cannot be properties of the explorer. They
8
+ * are contributions, and the explorer's job is to draw whatever arrived.
9
+ *
10
+ * They live in the store rather than behind a registry because a decoration is
11
+ * a *value that changes*, not a capability that is registered once: git
12
+ * refreshes, a build finishes, a search runs again. The explorer subscribes to
13
+ * one subtree and redraws; nothing has to be told about anything.
14
+ *
15
+ * Each contributor owns a source name and writes under it, which is what makes
16
+ * two contributors possible and what makes unloading one of them a single
17
+ * delete rather than a diff.
18
+ */
19
+ export declare const DECORATIONS_ROOT = "$/ui/decorations";
20
+ export interface ResourceDecoration {
21
+ /** A short mark at the end of the row. Wins over whatever the row had. */
22
+ badge?: string;
23
+ /** Colours the row, so a glance is enough. */
24
+ tone?: SemanticVariant;
25
+ /** Replaces the row's icon. */
26
+ icon?: string;
27
+ }
28
+ /** Where one contributor's marks live. */
29
+ export declare function decorationsPath(source: string): BindingPath;
30
+ /**
31
+ * Publish one contributor's marks, as a whole.
32
+ *
33
+ * The whole set at once, deliberately: a decoration that is *gone* - the file
34
+ * was committed, the error was fixed - has to disappear, and a merge of
35
+ * updates leaves the old ones behind forever.
36
+ */
37
+ export declare function setDecorations(store: ReactiveStore, source: string, byUri: Record<string, ResourceDecoration>): void;
38
+ export declare function clearDecorations(store: ReactiveStore, source: string): void;
39
+ /** Every contributor's mark for one resource, merged. */
40
+ export declare function decorationFor(store: ReactiveStore, uri: string): ResourceDecoration | null;
41
+ /**
42
+ * A reader that redraws when anything changes.
43
+ *
44
+ * One subscription for the whole tree rather than one per row: a component
45
+ * cannot call a hook per item without its hook count moving as the list does,
46
+ * and the marks arrive as one refresh anyway.
47
+ */
48
+ export declare function useDecorations(): (uri: string) => ResourceDecoration | null;
49
+ /**
50
+ * Marks on lines, which is the same idea one level down.
51
+ *
52
+ * A gutter belongs to whatever is drawing the file, and what a line *means* -
53
+ * added since the last commit, covered by a test, carrying an error - belongs
54
+ * to whatever knows that. Same bargain as the tree: the editor draws a column
55
+ * of marks and has never heard of git.
56
+ *
57
+ * Kept per resource rather than per panel, because "this line is new" is true
58
+ * of the file and not of where you happen to be looking at it.
59
+ */
60
+ export declare const LINE_MARKS_ROOT = "$/ui/line-marks";
61
+ export type LineMark = 'added' | 'changed' | 'removed';
62
+ /** Line numbers count from zero, like an index, because a caret does. */
63
+ export type LineMarks = Record<number, LineMark>;
64
+ /**
65
+ * What a marked line looks like, in one cell.
66
+ *
67
+ * ASCII, so every terminal draws one - and here rather than in whichever
68
+ * component happened to need it first, because two renderers drawing the same
69
+ * mark differently is the same file looking like two files. It lived in the
70
+ * editor, which is why the *viewer* drew no marks at all: you turned the
71
+ * setting on, stayed in view mode, and nothing happened.
72
+ */
73
+ export declare const MARK_GLYPH: Record<LineMark, string>;
74
+ export declare const MARK_TONE: Record<LineMark, StyleColor>;
75
+ export declare function lineMarksPath(source: string, uri: string): BindingPath;
76
+ export declare function setLineMarks(store: ReactiveStore, source: string, uri: string, marks: LineMarks | null): void;
77
+ /** Drop everything one contributor said, wherever it said it. */
78
+ export declare function clearLineMarks(store: ReactiveStore, source: string): void;
79
+ export declare function lineMarksFor(store: ReactiveStore, uri: string | null): LineMarks;
80
+ /**
81
+ * The marks on one file, redrawn when they change.
82
+ *
83
+ * One subscription, and an empty object when nobody has said anything - so a
84
+ * renderer can ask unconditionally and draw no column at all when the answer
85
+ * is empty.
86
+ */
87
+ export declare function useLineMarks(uri: string | null): LineMarks;
88
+ //# sourceMappingURL=decorations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorations.d.ts","sourceRoot":"","sources":["../src/decorations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG5F;;;;;;;;;;;;;;;;GAgBG;AAEH,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,GACxC,IAAI,CAMN;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED,yDAAyD;AACzD,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAa1F;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,IAAI,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,CAI3E;AAID;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvD,yEAAyE;AACzE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAI/C,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,CAIlD,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAEtE;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,SAAS,GAAG,IAAI,GACtB,IAAI,CAEN;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAchF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAI1D"}
@@ -0,0 +1,135 @@
1
+ import { useStoreSubtree, useRuntime, escapeSegment } from '@textui/core';
2
+ /**
3
+ * Marks on resources.
4
+ *
5
+ * A tree of files is the same tree whether or not anything has an opinion
6
+ * about the files in it - so "this one is modified", "this one has an error",
7
+ * "this one matched your search" cannot be properties of the explorer. They
8
+ * are contributions, and the explorer's job is to draw whatever arrived.
9
+ *
10
+ * They live in the store rather than behind a registry because a decoration is
11
+ * a *value that changes*, not a capability that is registered once: git
12
+ * refreshes, a build finishes, a search runs again. The explorer subscribes to
13
+ * one subtree and redraws; nothing has to be told about anything.
14
+ *
15
+ * Each contributor owns a source name and writes under it, which is what makes
16
+ * two contributors possible and what makes unloading one of them a single
17
+ * delete rather than a diff.
18
+ */
19
+ export const DECORATIONS_ROOT = '$/ui/decorations';
20
+ /** Where one contributor's marks live. */
21
+ export function decorationsPath(source) {
22
+ return `${DECORATIONS_ROOT}/${escapeSegment(source)}`;
23
+ }
24
+ /**
25
+ * Publish one contributor's marks, as a whole.
26
+ *
27
+ * The whole set at once, deliberately: a decoration that is *gone* - the file
28
+ * was committed, the error was fixed - has to disappear, and a merge of
29
+ * updates leaves the old ones behind forever.
30
+ */
31
+ export function setDecorations(store, source, byUri) {
32
+ const escaped = {};
33
+ for (const [uri, decoration] of Object.entries(byUri)) {
34
+ escaped[escapeSegment(uri)] = decoration;
35
+ }
36
+ store.set(decorationsPath(source), escaped);
37
+ }
38
+ export function clearDecorations(store, source) {
39
+ store.set(decorationsPath(source), null);
40
+ }
41
+ /** Every contributor's mark for one resource, merged. */
42
+ export function decorationFor(store, uri) {
43
+ const all = store.get(DECORATIONS_ROOT);
44
+ if (!all)
45
+ return null;
46
+ const key = escapeSegment(uri);
47
+ let merged = null;
48
+ for (const bySource of Object.values(all)) {
49
+ const found = bySource?.[key];
50
+ if (found)
51
+ merged = { ...(merged ?? {}), ...found };
52
+ }
53
+ return merged;
54
+ }
55
+ /**
56
+ * A reader that redraws when anything changes.
57
+ *
58
+ * One subscription for the whole tree rather than one per row: a component
59
+ * cannot call a hook per item without its hook count moving as the list does,
60
+ * and the marks arrive as one refresh anyway.
61
+ */
62
+ export function useDecorations() {
63
+ const runtime = useRuntime();
64
+ useStoreSubtree(DECORATIONS_ROOT);
65
+ return (uri) => decorationFor(runtime.store, uri);
66
+ }
67
+ // ------------------------------------------------------------------ lines
68
+ /**
69
+ * Marks on lines, which is the same idea one level down.
70
+ *
71
+ * A gutter belongs to whatever is drawing the file, and what a line *means* -
72
+ * added since the last commit, covered by a test, carrying an error - belongs
73
+ * to whatever knows that. Same bargain as the tree: the editor draws a column
74
+ * of marks and has never heard of git.
75
+ *
76
+ * Kept per resource rather than per panel, because "this line is new" is true
77
+ * of the file and not of where you happen to be looking at it.
78
+ */
79
+ export const LINE_MARKS_ROOT = '$/ui/line-marks';
80
+ /**
81
+ * What a marked line looks like, in one cell.
82
+ *
83
+ * ASCII, so every terminal draws one - and here rather than in whichever
84
+ * component happened to need it first, because two renderers drawing the same
85
+ * mark differently is the same file looking like two files. It lived in the
86
+ * editor, which is why the *viewer* drew no marks at all: you turned the
87
+ * setting on, stayed in view mode, and nothing happened.
88
+ */
89
+ export const MARK_GLYPH = {
90
+ added: '+',
91
+ changed: '~',
92
+ removed: '_',
93
+ };
94
+ export const MARK_TONE = {
95
+ added: 'success',
96
+ changed: 'warning',
97
+ removed: 'danger',
98
+ };
99
+ export function lineMarksPath(source, uri) {
100
+ return `${LINE_MARKS_ROOT}/${escapeSegment(source)}/${escapeSegment(uri)}`;
101
+ }
102
+ export function setLineMarks(store, source, uri, marks) {
103
+ store.set(lineMarksPath(source, uri), marks);
104
+ }
105
+ /** Drop everything one contributor said, wherever it said it. */
106
+ export function clearLineMarks(store, source) {
107
+ store.set(`${LINE_MARKS_ROOT}/${escapeSegment(source)}`, null);
108
+ }
109
+ export function lineMarksFor(store, uri) {
110
+ if (uri === null)
111
+ return {};
112
+ const all = store.get(LINE_MARKS_ROOT);
113
+ if (!all)
114
+ return {};
115
+ const key = escapeSegment(uri);
116
+ let merged = {};
117
+ for (const bySource of Object.values(all)) {
118
+ const found = bySource?.[key];
119
+ if (found)
120
+ merged = { ...merged, ...found };
121
+ }
122
+ return merged;
123
+ }
124
+ /**
125
+ * The marks on one file, redrawn when they change.
126
+ *
127
+ * One subscription, and an empty object when nobody has said anything - so a
128
+ * renderer can ask unconditionally and draw no column at all when the answer
129
+ * is empty.
130
+ */
131
+ export function useLineMarks(uri) {
132
+ const runtime = useRuntime();
133
+ useStoreSubtree(LINE_MARKS_ROOT);
134
+ return lineMarksFor(runtime.store, uri);
135
+ }
@@ -0,0 +1,8 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface AlertProps extends BoxProps {
3
+ tone?: 'info' | 'success' | 'warning' | 'danger';
4
+ title?: string;
5
+ message?: string;
6
+ }
7
+ export declare const Alert: (props: AlertProps) => import("@textui/core").RenderOutput;
8
+ //# sourceMappingURL=alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert.d.ts","sourceRoot":"","sources":["../../src/display/alert.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,UAAW,SAAQ,QAAQ;IAC1C,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,KAAK,4DAkBhB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ export const Alert = defineComponent('Alert', (props) => {
3
+ const theme = useTheme();
4
+ const { tone = 'info', title, message, children, ...rest } = props;
5
+ const icon = {
6
+ info: theme.glyphs.info,
7
+ success: theme.glyphs.check,
8
+ warning: theme.glyphs.warning,
9
+ danger: theme.glyphs.cross,
10
+ }[tone];
11
+ return h('box', { role: 'alert', direction: 'row', gap: 1, ...rest }, h('text', { content: icon, fg: tone }), h('box', { direction: 'column', flex: 1 }, title ? h('text', { content: title, bold: true, fg: tone }) : null, message ? h('text', { content: message, wrap: 'word' }) : null, children));
12
+ });
@@ -0,0 +1,10 @@
1
+ import type { BoxProps, SemanticVariant, SurfaceVariant } from '@textui/core';
2
+ export interface BadgeProps extends BoxProps {
3
+ label: string;
4
+ tone?: SemanticVariant;
5
+ variant?: SurfaceVariant;
6
+ /** Glyph before the label, so the badge reads without colour. */
7
+ icon?: string;
8
+ }
9
+ export declare const Badge: (props: BadgeProps) => import("@textui/core").RenderOutput;
10
+ //# sourceMappingURL=badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/display/badge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9E,MAAM,WAAW,UAAW,SAAQ,QAAQ;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,KAAK,4DA2BhB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ import { ON_TONE, TONE as TONE_COLOR } from '../tone.js';
3
+ export const Badge = defineComponent('Badge', (props) => {
4
+ const { label, tone = 'default', variant = 'ghost', icon, ...rest } = props;
5
+ const color = TONE_COLOR[tone];
6
+ // `ghost` is chrome-less: the tone, and nothing around it. That is the
7
+ // default because it is the badge that fits in a sentence, and it is what
8
+ // `ghost` already means on Button - one word, one meaning, both components.
9
+ const style = variant === 'solid' ? { bg: color, fg: ON_TONE[tone] } : { fg: color };
10
+ // A badge is inline: it sits in a row of text and must stay one line tall.
11
+ // The outline variant is therefore brackets rather than a box border - a
12
+ // three-row chip in a sentence is not an outline, it is a panel.
13
+ const brackets = variant === 'outline';
14
+ return h('box', {
15
+ direction: 'row',
16
+ gap: icon ? 1 : 0,
17
+ padding: variant === 'solid' ? [0, 1] : 0,
18
+ ...style,
19
+ ...rest,
20
+ }, brackets ? h('text', { content: '[' }) : null, icon ? h('text', { content: icon }) : null, h('text', { content: label }), brackets ? h('text', { content: ']' }) : null);
21
+ });
@@ -0,0 +1,8 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface CardProps extends BoxProps {
3
+ title?: string;
4
+ subtitle?: string;
5
+ footer?: string;
6
+ }
7
+ export declare const Card: (props: CardProps) => import("@textui/core").RenderOutput;
8
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../src/display/card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,SAAU,SAAQ,QAAQ;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,IAAI,2DAaf,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ export const Card = defineComponent('Card', (props) => {
3
+ const theme = useTheme();
4
+ const { title, subtitle, children, ...rest } = props;
5
+ return h('box', {
6
+ border: theme.border,
7
+ padding: theme.density === 'compact' ? 0 : [0, 1],
8
+ direction: 'column',
9
+ title,
10
+ ...rest,
11
+ }, subtitle ? h('text', { content: subtitle, fg: 'muted' }) : null, children);
12
+ });
@@ -0,0 +1,10 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface EmptyStateProps extends BoxProps {
3
+ title: string;
4
+ message?: string;
5
+ icon?: string;
6
+ /** Hint text: what the reader can do about it. */
7
+ hint?: string;
8
+ }
9
+ export declare const EmptyState: (props: EmptyStateProps) => import("@textui/core").RenderOutput;
10
+ //# sourceMappingURL=empty-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../src/display/empty-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,UAAU,iEASrB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ export const EmptyState = defineComponent('EmptyState', (props) => {
3
+ const { title, message, icon, hint, children, ...rest } = props;
4
+ return h('box', { direction: 'column', align: 'center', justify: 'center', flex: 1, gap: 0, ...rest }, icon ? h('text', { content: icon, fg: 'subtle' }) : null, h('text', { content: title, bold: true, fg: 'muted' }), message ? h('text', { content: message, fg: 'subtle', wrap: 'word', textAlign: 'center' }) : null, hint ? h('text', { content: hint, fg: 'subtle', dim: true }) : null, children);
5
+ });
@@ -0,0 +1,9 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface ErrorStateProps extends BoxProps {
3
+ title?: string;
4
+ error: unknown;
5
+ /** Command id offered as a retry. */
6
+ onRetry?: () => void;
7
+ }
8
+ export declare const ErrorState: (props: ErrorStateProps) => import("@textui/core").RenderOutput;
9
+ //# sourceMappingURL=error-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-state.d.ts","sourceRoot":"","sources":["../../src/display/error-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,iEAYrB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ export const ErrorState = defineComponent('ErrorState', (props) => {
3
+ const theme = useTheme();
4
+ const { title = 'Something went wrong', error, onRetry, ...rest } = props;
5
+ const message = error instanceof Error ? error.message : String(error);
6
+ return h('box', { role: 'alert', direction: 'column', gap: 1, padding: 1, ...rest }, h('box', { direction: 'row', gap: 1 }, h('text', { content: theme.glyphs.cross, fg: 'danger' }), h('text', { content: title, bold: true, fg: 'danger' })), h('text', { content: message, fg: 'muted', wrap: 'word' }), onRetry ? h('text', { content: 'r retry', fg: 'subtle' }) : null);
7
+ });
@@ -0,0 +1,6 @@
1
+ import type { TextProps } from '@textui/core';
2
+ export interface HeadingProps extends TextProps {
3
+ level?: 1 | 2 | 3;
4
+ }
5
+ export declare const Heading: (props: HeadingProps) => import("@textui/core").RenderOutput;
6
+ //# sourceMappingURL=heading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../src/display/heading.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACnB;AAED,eAAO,MAAM,OAAO,8DAQnB,CAAC"}