@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,112 @@
1
+ import type { BoxProps, SemanticVariant, StyleColor } from '@textui/core';
2
+ import { defineComponent, h, useTheme } from '@textui/core';
3
+
4
+ export const TONE: Record<SemanticVariant, StyleColor> = {
5
+ default: 'text', primary: 'primary', secondary: 'secondary', accent: 'accent',
6
+ success: 'success', warning: 'warning', danger: 'danger', info: 'info', muted: 'muted',
7
+ };
8
+
9
+ export interface Series {
10
+ values: number[];
11
+ label?: string;
12
+ tone?: SemanticVariant;
13
+ }
14
+
15
+ export function bounds(values: number[], min?: number, max?: number): [number, number] {
16
+ if (values.length === 0) return [min ?? 0, max ?? 1];
17
+ const lo = min ?? Math.min(...values);
18
+ const hi = max ?? Math.max(...values);
19
+ return lo === hi ? [lo, lo + 1] : [lo, hi];
20
+ }
21
+
22
+ /** Take `width` samples, averaging when there is more data than cells. */
23
+ export function resample(values: number[], width: number): number[] {
24
+ if (width <= 0) return [];
25
+ if (values.length === 0) return new Array<number>(width).fill(0);
26
+ if (values.length === width) return values;
27
+
28
+ if (values.length < width) {
29
+ // Fewer points than cells: stretch across the width. Padding with the
30
+ // first value would invent a flat stretch of history that never happened,
31
+ // which on a chart reads as "nothing was going on" rather than "no data".
32
+ return Array.from({ length: width }, (_, i) => {
33
+ const position = (i * (values.length - 1)) / (width - 1 || 1);
34
+ const low = Math.floor(position);
35
+ const high = Math.min(values.length - 1, low + 1);
36
+ const t = position - low;
37
+ return (values[low] as number) * (1 - t) + (values[high] as number) * t;
38
+ });
39
+ }
40
+
41
+ const out: number[] = [];
42
+ const bucket = values.length / width;
43
+ for (let i = 0; i < width; i++) {
44
+ const start = Math.floor(i * bucket);
45
+ const end = Math.max(start + 1, Math.floor((i + 1) * bucket));
46
+ const slice = values.slice(start, end);
47
+ out.push(slice.reduce((a, b) => a + b, 0) / slice.length);
48
+ }
49
+ return out;
50
+ }
51
+
52
+ export const VerticalBars = defineComponent<{
53
+ data: { label: string; value: number; tone?: SemanticVariant }[];
54
+ max: number;
55
+ height: number;
56
+ /** Cells across, per bar. One is a hairline; two or three read as bars. */
57
+ columnWidth?: number;
58
+ }>('VerticalBars', ({ data, max, height, columnWidth = 1, ...rest }) => {
59
+ const theme = useTheme();
60
+ const blocks = theme.glyphs.blocks;
61
+
62
+ // Each cell holds eight levels, so a column is a run of full blocks plus one
63
+ // partial - the same trick as the progress bar, turned on its side.
64
+ const columns = data.map((item) => {
65
+ const units = Math.round((item.value / max) * height * blocks.length);
66
+ const full = Math.floor(units / blocks.length);
67
+ const partialIndex = units % blocks.length;
68
+ const cells: string[] = [];
69
+ for (let row = height - 1; row >= 0; row--) {
70
+ if (row < full) cells.push(blocks[blocks.length - 1] as string);
71
+ else if (row === full && partialIndex > 0) cells.push(blocks[partialIndex - 1] as string);
72
+ else cells.push(' ');
73
+ }
74
+ return { cells: cells.reverse(), item };
75
+ });
76
+
77
+ return h('box', { direction: 'column', ...rest },
78
+ ...Array.from({ length: height }, (_, row) =>
79
+ h('box', { key: row, direction: 'row', gap: 1 },
80
+ ...columns.map((col, i) =>
81
+ h('text', {
82
+ key: i,
83
+ // The glyph repeated, not a wider glyph: a column is one cell of
84
+ // vertical resolution and `columnWidth` of horizontal, so widening
85
+ // it must not change how the value is drawn.
86
+ content: (col.cells[height - 1 - row] as string).repeat(columnWidth),
87
+ fg: TONE[col.item.tone ?? 'accent'],
88
+ })))),
89
+ h('box', { direction: 'row', gap: 1 },
90
+ ...data.map((item, i) =>
91
+ // As much of the label as the bar is wide, padded so the next one
92
+ // starts over its own bar rather than sliding left under a short name.
93
+ h('text', {
94
+ key: i,
95
+ content: item.label.slice(0, columnWidth).padEnd(columnWidth),
96
+ fg: 'subtle',
97
+ }))),
98
+ );
99
+ });
100
+
101
+ export interface LineChartProps extends BoxProps {
102
+ series: Series[];
103
+ min?: number;
104
+ max?: number;
105
+ chartWidth?: number;
106
+ chartHeight?: number;
107
+ /** Draw a y-axis with the bounds labelled. */
108
+ axis?: boolean;
109
+ /** Fill under the line. */
110
+ area?: boolean;
111
+ format?(value: number): string;
112
+ }
@@ -0,0 +1,46 @@
1
+ import type { BoxProps, SemanticVariant } from '@textui/core';
2
+ import { defineComponent, h, useTheme } from '@textui/core';
3
+ import { TONE, bounds, resample } from './shared.js';
4
+
5
+ export interface SparklineProps extends BoxProps {
6
+ values: number[];
7
+ min?: number;
8
+ max?: number;
9
+ tone?: SemanticVariant;
10
+ /** Cells wide. Values are sampled to fit. */
11
+ chartWidth?: number;
12
+ /** Print the latest value after the line. */
13
+ showValue?: boolean;
14
+ format?(value: number): string;
15
+ }
16
+
17
+ /** One row of block glyphs: eight levels per cell. */
18
+ export const Sparkline = defineComponent<SparklineProps>('Sparkline', (props) => {
19
+ const theme = useTheme();
20
+ const {
21
+ values, min, max, tone = 'accent', chartWidth,
22
+ showValue = false, format, ...rest
23
+ } = props;
24
+
25
+ const blocks = theme.glyphs.blocks;
26
+ const width = chartWidth ?? values.length;
27
+ const sampled = resample(values, width);
28
+ const [lo, hi] = bounds(sampled, min, max);
29
+
30
+ const line = sampled
31
+ .map((v) => {
32
+ const ratio = (v - lo) / (hi - lo);
33
+ const index = Math.max(0, Math.min(blocks.length - 1, Math.round(ratio * (blocks.length - 1))));
34
+ return blocks[index] as string;
35
+ })
36
+ .join('');
37
+
38
+ const latest = values[values.length - 1];
39
+
40
+ return h('box', { direction: 'row', gap: 1, ...rest },
41
+ h('text', { content: line, fg: TONE[tone] }),
42
+ showValue && latest !== undefined
43
+ ? h('text', { content: format ? format(latest) : String(latest), fg: 'muted' })
44
+ : null,
45
+ );
46
+ });
@@ -0,0 +1,184 @@
1
+ import type {
2
+ BorderStyle,
3
+ BoxProps,
4
+ SemanticVariant,
5
+ StyleColor,
6
+ SurfaceVariant,
7
+ } from '@textui/core';
8
+ import { defineComponent, h, useFocus, useInput, useTheme } from '@textui/core';
9
+ import { ON_TONE, TONE } from '../tone.js';
10
+
11
+ /** A border that takes up space without drawing anything. */
12
+ const BLANK_BORDER = {
13
+ topLeft: ' ', top: ' ', topRight: ' ', right: ' ',
14
+ bottomRight: ' ', bottom: ' ', bottomLeft: ' ', left: ' ',
15
+ cross: ' ', teeTop: ' ', teeBottom: ' ', teeLeft: ' ', teeRight: ' ',
16
+ };
17
+
18
+ export interface ButtonProps extends BoxProps {
19
+ label: string;
20
+ tone?: SemanticVariant;
21
+ variant?: SurfaceVariant;
22
+ icon?: string;
23
+ /** Shortcut hint rendered after the label. */
24
+ hint?: string;
25
+ onPress?(): void;
26
+ autoFocus?: boolean;
27
+ /**
28
+ * How much of the screen the button takes, and how heavy its edge is.
29
+ *
30
+ * `md` is a button: three rows, the theme's edge. `sm` is one row with no
31
+ * edge at all, for a toolbar or a row of buttons that must not out-weigh
32
+ * the fields beside them. `lg` is three rows with a heavy one.
33
+ *
34
+ * It matters most when filled. A solid `md` draws its edge in half-blocks,
35
+ * so it stands the same height as the outline button next to it without
36
+ * reading as a heavier object; `lg` fills the edge cells too and becomes
37
+ * the whole rectangle, which is what solid used to do at every size - and
38
+ * why one row of buttons looked bigger than the row above it.
39
+ */
40
+ size?: 'sm' | 'md' | 'lg';
41
+ }
42
+
43
+ export const Button = defineComponent<ButtonProps>('Button', (props) => {
44
+ const theme = useTheme();
45
+ const {
46
+ label, tone = 'default', variant = 'outline', icon, hint,
47
+ onPress, disabled, autoFocus, size = 'md', ...rest
48
+ } = props;
49
+
50
+ const focus = useFocus({ disabled, autoFocus });
51
+ useInput(
52
+ (event) => {
53
+ if (disabled) return false;
54
+ if (event.name === 'enter' || event.name === 'space') {
55
+ onPress?.();
56
+ return true;
57
+ }
58
+ return false;
59
+ },
60
+ { focusId: focus.id },
61
+ );
62
+
63
+ // Selection inverts.
64
+ //
65
+ // At rest a button is a line and a label in its tone; selected, the tone
66
+ // becomes the background and the label flips to the colour written for it.
67
+ // Recolouring only the border was too quiet to find - and next to a filled
68
+ // button it read backwards, because the filled one looked like the selected
69
+ // one however hard the border tried.
70
+ const filled = (focus.focused || props.selected === true) && !disabled;
71
+ const resolvedTone = filled && tone === 'default' ? 'primary' : tone;
72
+
73
+ const color = disabled ? 'disabled' : TONE[resolvedTone];
74
+ const onColor = disabled ? 'text' : ON_TONE[resolvedTone];
75
+
76
+ // `sm` has no ring, so nothing here reserves one.
77
+ const ringed = size !== 'sm' && theme.border !== 'none';
78
+
79
+ // A solid button reserves the same ring an outline one draws, filled with
80
+ // its own background rather than left out. Without it the two are one row
81
+ // and three rows tall, and a dialog's OK sits a line above its Cancel.
82
+ const solidBorder = {
83
+ style: theme.border,
84
+ color: focus.focused ? ('focus' as StyleColor) : undefined,
85
+ ...(focus.focused ? {} : { chars: BLANK_BORDER }),
86
+ };
87
+
88
+ // The tone fills the inside of the frame, not the frame itself. A cell
89
+ // carries one background, so a background on the button's own box lands on
90
+ // the border glyphs too - rounded corners included - and the button reads as
91
+ // a coloured block rather than a filled button. Hanging the fill on an inner
92
+ // box leaves the ring on whatever is behind it. The wrapper is there whether
93
+ // or not the button is filled, so focusing one does not reshape its tree.
94
+ //
95
+ // A solid button is inset too at `md`, which is the whole of the size fix:
96
+ // hanging the fill on an inner box leaves the ring to be drawn in
97
+ // half-blocks rather than filled through, so it weighs what the outline
98
+ // button beside it weighs. `lg` keeps the fill on the outer box - the ring
99
+ // cells take the tone as well and the button becomes a solid rectangle.
100
+ const inset = variant === 'ghost' || variant === 'link'
101
+ ? false
102
+ : variant !== 'solid' || (ringed && size === 'md');
103
+
104
+ // Filled, the frame becomes the fill's own edge.
105
+ //
106
+ // A cell holds one background, so filling the box the ordinary way colours
107
+ // its border glyphs too and the button reads as a block; filling only the
108
+ // inside leaves the border cell on the backdrop, and a gap runs between the
109
+ // frame and the fill. `half` is drawn from block elements whose coloured
110
+ // half faces inward, so the ring meets the inside with nothing between. It
111
+ // measures the same as the line border it replaces - one cell a side - so
112
+ // focus changes how a button looks without changing its size.
113
+ //
114
+ // A theme that asked for no border, or for ascii, is left alone: both are
115
+ // deliberate looks, and `half` degrades to ascii anyway on a terminal that
116
+ // cannot draw block elements.
117
+ const filledBorder: BorderStyle =
118
+ theme.border === 'none' || theme.border === 'ascii' ? theme.border : 'half';
119
+
120
+ // The edge, by size. `lg` asks for the heaviest line the theme can draw and
121
+ // falls back to the theme's own where there is none to ask for.
122
+ const edge: BorderStyle = size === 'lg' && theme.border !== 'ascii' ? 'bold' : theme.border;
123
+
124
+ const style =
125
+ variant === 'solid'
126
+ ? size === 'sm' || !ringed
127
+ // One row, filled. No ring to reserve and nothing to align to.
128
+ ? { bg: color, fg: onColor }
129
+ : size === 'lg'
130
+ // The fill runs under the ring, so the whole rectangle is the button.
131
+ ? { bg: color, fg: onColor, border: solidBorder }
132
+ // The ring is drawn from block elements whose coloured half faces
133
+ // inward: it meets the fill with no gap and stands half as heavy.
134
+ : { border: { style: filledBorder, color }, fg: color }
135
+ : variant === 'ghost' || variant === 'link'
136
+ ? (filled ? { bg: color, fg: onColor } : { fg: color })
137
+ : size === 'sm' || !ringed
138
+ ? (filled ? { bg: color, fg: onColor } : { fg: color })
139
+ : { border: { style: filled ? filledBorder : edge, color }, fg: color };
140
+
141
+ const padding = variant === 'ghost' || variant === 'link' ? 0 : ([0, 1] as [number, number]);
142
+
143
+ const content = [
144
+ icon ? h('text', { content: icon }) : null,
145
+ h('text', { content: label }),
146
+ // On a filled button the hint has to sit on the tone too; `muted` against
147
+ // a solid colour is the one combination that is never readable.
148
+ hint ? h('text', { content: hint, fg: filled ? onColor : 'muted', dim: !filled }) : null,
149
+ ];
150
+
151
+ return h('box', {
152
+ id: focus.id,
153
+ role: 'button',
154
+ label,
155
+ direction: 'row',
156
+ // The inner box owns the run of the label - gap, padding and centring -
157
+ // whenever there is one, so the two paths measure the same.
158
+ gap: inset ? 0 : 1,
159
+ // Centred, so a button stretched by the row it sits in keeps its label on
160
+ // the same line as its neighbours' labels.
161
+ align: 'center',
162
+ padding: inset ? 0 : padding,
163
+ bold: inset ? undefined : focus.focused,
164
+ underline: focus.focused && (variant === 'ghost' || variant === 'link'),
165
+ onClick: () => { if (!disabled) onPress?.(); },
166
+ ...style,
167
+ ...rest,
168
+ },
169
+ inset
170
+ ? h('box', {
171
+ // Grow, so the fill reaches the frame on a button the row stretched.
172
+ flex: 1,
173
+ direction: 'row',
174
+ gap: 1,
175
+ align: 'center',
176
+ padding,
177
+ bold: focus.focused,
178
+ // A solid button is filled whether or not it has focus - that is
179
+ // what solid means. An outline one fills only when it takes focus.
180
+ ...(variant === 'solid' || filled ? { bg: color, fg: onColor } : {}),
181
+ }, ...content)
182
+ : content,
183
+ );
184
+ });
@@ -0,0 +1,48 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useFocus, useInput, useTheme } from '@textui/core';
3
+
4
+ export interface CheckboxProps extends BoxProps {
5
+ label?: string;
6
+ checked?: boolean;
7
+ /** Neither checked nor unchecked - a parent of mixed children. */
8
+ indeterminate?: boolean;
9
+ onChange?(checked: boolean): void;
10
+ }
11
+
12
+ export const Checkbox = defineComponent<CheckboxProps>('Checkbox', (props) => {
13
+ const theme = useTheme();
14
+ const { label, checked = false, indeterminate, onChange, disabled, ...rest } = props;
15
+ const focus = useFocus({ disabled });
16
+
17
+ useInput(
18
+ (event) => {
19
+ if (disabled) return false;
20
+ if (event.name === 'space' || event.name === 'enter') {
21
+ onChange?.(!checked);
22
+ return true;
23
+ }
24
+ return false;
25
+ },
26
+ { focusId: focus.id },
27
+ );
28
+
29
+ const glyph = indeterminate
30
+ ? theme.glyphs.checkboxMixed
31
+ : checked ? theme.glyphs.checkboxOn : theme.glyphs.checkboxOff;
32
+
33
+ return h('box', {
34
+ id: focus.id,
35
+ role: 'checkbox',
36
+ label,
37
+ selected: checked,
38
+ direction: 'row',
39
+ gap: 1,
40
+ fg: disabled ? 'disabled' : focus.focused ? 'accent' : undefined,
41
+ bold: focus.focused,
42
+ onClick: () => { if (!disabled) onChange?.(!checked); },
43
+ ...rest,
44
+ },
45
+ h('text', { content: glyph }),
46
+ label ? h('text', { content: label }) : null,
47
+ );
48
+ });
@@ -0,0 +1,40 @@
1
+ import type { ComponentDefinition } from '@textui/core';
2
+ import { Button } from './button.js';
3
+ import { Checkbox } from './checkbox.js';
4
+ import { RadioGroup } from './radio-group.js';
5
+ import { SearchBox } from './search-box.js';
6
+ import { Select } from './select.js';
7
+ import { Slider } from './slider.js';
8
+ import { Switch } from './switch.js';
9
+ import { TextArea } from './text-area.js';
10
+ import { TextInput } from './text-input.js';
11
+
12
+ /**
13
+ * Controls.
14
+ *
15
+ * Every control here is focusable, keyboard-first and states its own focus
16
+ * ring, because a terminal has no hover to fall back on: if the focused
17
+ * control is not obvious without moving a mouse, the interface is unusable.
18
+ */
19
+ export * from './button.js';
20
+ export * from './checkbox.js';
21
+ export * from './radio-group.js';
22
+ export * from './search-box.js';
23
+ export * from './select.js';
24
+ export * from './slider.js';
25
+ export * from './switch.js';
26
+ export * from './text-area.js';
27
+ export * from './text-input.js';
28
+ export type { TextInputProps } from './shared.js';
29
+
30
+ export const CONTROL_COMPONENTS: ComponentDefinition[] = [
31
+ { component: 'Button', category: 'control', renderer: { kind: 'function', render: Button }, role: 'button', variants: ['solid', 'outline', 'ghost', 'link'], description: 'Focusable action.' },
32
+ { component: 'Checkbox', category: 'control', renderer: { kind: 'function', render: Checkbox }, role: 'checkbox', description: 'On, off, or mixed.' },
33
+ { component: 'Switch', category: 'control', renderer: { kind: 'function', render: Switch }, role: 'switch', description: 'Two-state toggle with words, not only colour.' },
34
+ { component: 'RadioGroup', category: 'control', renderer: { kind: 'function', render: RadioGroup }, role: 'radio', description: 'One of several.' },
35
+ { component: 'Slider', category: 'control', renderer: { kind: 'function', render: Slider }, role: 'slider', description: 'A value along a track.' },
36
+ { component: 'TextArea', category: 'control', renderer: { kind: 'function', render: TextArea }, role: 'textbox', description: 'A field that is a paragraph: grows, scrolls, and gives back the keys it does not want.' },
37
+ { component: 'TextInput', category: 'control', renderer: { kind: 'function', render: TextInput }, role: 'textbox', description: 'Single-line text with a real caret.' },
38
+ { component: 'Select', category: 'control', renderer: { kind: 'function', render: Select }, role: 'combobox', description: 'Pick from a list, collapsed or open.' },
39
+ { component: 'SearchBox', category: 'control', renderer: { kind: 'function', render: SearchBox }, role: 'searchbox', description: 'A text field that looks like search.' },
40
+ ];
@@ -0,0 +1,60 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useFocus, useInput, useTheme } from '@textui/core';
3
+
4
+ export interface RadioOption {
5
+ value: string;
6
+ label: string;
7
+ description?: string;
8
+ disabled?: boolean;
9
+ }
10
+
11
+ export interface RadioGroupProps extends BoxProps {
12
+ options: RadioOption[];
13
+ value?: string;
14
+ onChange?(value: string): void;
15
+ label?: string;
16
+ /** Lay the options out in a row instead of a column. */
17
+ inline?: boolean;
18
+ }
19
+
20
+ export const RadioGroup = defineComponent<RadioGroupProps>('RadioGroup', (props) => {
21
+ const theme = useTheme();
22
+ const { options, value, onChange, label, inline, disabled, ...rest } = props;
23
+ const focus = useFocus({ disabled });
24
+ const index = Math.max(0, options.findIndex((o) => o.value === value));
25
+
26
+ useInput(
27
+ (event) => {
28
+ if (disabled) return false;
29
+ const step = inline
30
+ ? (event.name === 'right' ? 1 : event.name === 'left' ? -1 : 0)
31
+ : (event.name === 'down' ? 1 : event.name === 'up' ? -1 : 0);
32
+ if (step === 0) return false;
33
+ const next = options[(index + step + options.length) % options.length];
34
+ if (next && !next.disabled) onChange?.(next.value);
35
+ return true;
36
+ },
37
+ { focusId: focus.id },
38
+ );
39
+
40
+ return h('box', { id: focus.id, role: 'group', label, direction: 'column', gap: 0, ...rest },
41
+ label ? h('text', { content: label, fg: 'muted' }) : null,
42
+ h('box', { direction: inline ? 'row' : 'column', gap: inline ? 2 : 0 },
43
+ ...options.map((option) => {
44
+ const selected = option.value === value;
45
+ return h('box', {
46
+ key: option.value,
47
+ direction: 'row',
48
+ gap: 1,
49
+ fg: option.disabled ? 'disabled' : selected && focus.focused ? 'accent' : undefined,
50
+ bold: selected && focus.focused,
51
+ onClick: () => { if (!option.disabled) onChange?.(option.value); },
52
+ },
53
+ h('text', { content: selected ? theme.glyphs.radioOn : theme.glyphs.radioOff }),
54
+ h('text', { content: option.label }),
55
+ option.description ? h('text', { content: option.description, fg: 'subtle' }) : null,
56
+ );
57
+ }),
58
+ ),
59
+ );
60
+ });
@@ -0,0 +1,15 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ import type { TextInputProps } from './shared.js';
3
+ import { TextInput } from './text-input.js';
4
+
5
+ export interface SearchBoxProps extends Omit<TextInputProps, 'search'> {
6
+ /** Result count, shown after the field. */
7
+ count?: number;
8
+ }
9
+
10
+ export const SearchBox = defineComponent<SearchBoxProps>('SearchBox', ({ count, ...props }) =>
11
+ h('box', { direction: 'row', gap: 1 },
12
+ h(TextInput, { search: true, flex: 1, ...props }),
13
+ count !== undefined ? h('text', { content: `${count}`, fg: 'muted' }) : null,
14
+ ),
15
+ );