@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,230 @@
1
+ import type { BoxProps, ComponentNode, RenderOutput } from '@textui/core';
2
+ import {
3
+ defineComponent, h, useApp, useEffect, useFocus, useInput, useMeasure, useState, useTheme,
4
+ } from '@textui/core';
5
+
6
+ export interface SelectOption {
7
+ value: string;
8
+ label: string;
9
+ description?: string;
10
+ disabled?: boolean;
11
+ icon?: string;
12
+ }
13
+
14
+ export interface SelectProps extends BoxProps {
15
+ options: SelectOption[];
16
+ value?: string;
17
+ onChange?(value: string): void;
18
+ label?: string;
19
+ placeholder?: string;
20
+ /** Show the list inline instead of collapsing to one line. */
21
+ open?: boolean;
22
+ /** Rows shown at once when open. */
23
+ visibleRows?: number;
24
+ /**
25
+ * Where the list goes when it opens.
26
+ *
27
+ * `inline` grows the control: the options appear inside the same border, and
28
+ * everything under it moves down. Honest about the space it takes and the
29
+ * only one that cannot be clipped, which is why it is the default.
30
+ *
31
+ * `floating` puts the list on the floating layer, anchored under the
32
+ * control. Nothing below it moves, which is what you want in a form or a
33
+ * dense row of controls - the layout does not jump as you open and shut it.
34
+ *
35
+ * `modal` puts it in the middle of the screen over a scrim. For a list long
36
+ * enough or a choice consequential enough that the rest of the screen is a
37
+ * distraction.
38
+ *
39
+ * The keys are the same in all three, because the control keeps the keyboard
40
+ * in all three: the layer is somewhere to *draw* the list, not somewhere the
41
+ * focus goes. Arrow keys, enter and escape are answered by the same handler
42
+ * whichever mode it is in.
43
+ */
44
+ mode?: 'inline' | 'floating' | 'modal';
45
+ }
46
+
47
+ export const Select = defineComponent<SelectProps>('Select', (props) => {
48
+ const theme = useTheme();
49
+ const {
50
+ options, value, onChange, label, placeholder,
51
+ open: openProp, visibleRows = 6, disabled, mode = 'inline', ...rest
52
+ } = props;
53
+
54
+ const app = useApp();
55
+ const focus = useFocus({ disabled });
56
+ const measured = useMeasure();
57
+ const empty = placeholder ?? `Select${theme.glyphs.ellipsis}`;
58
+ const [open, setOpen] = useState(openProp ?? false);
59
+ const index = Math.max(0, options.findIndex((o) => o.value === value));
60
+ const [highlight, setHighlight] = useState(index);
61
+
62
+ useInput(
63
+ (event) => {
64
+ if (disabled) return false;
65
+ if (!open) {
66
+ if (event.name === 'enter' || event.name === 'space' || event.name === 'down') {
67
+ setOpen(true);
68
+ return true;
69
+ }
70
+ return false;
71
+ }
72
+ switch (event.name) {
73
+ case 'up': setHighlight((highlight - 1 + options.length) % options.length); return true;
74
+ case 'down': setHighlight((highlight + 1) % options.length); return true;
75
+ case 'enter': {
76
+ const chosen = options[highlight];
77
+ if (chosen && !chosen.disabled) onChange?.(chosen.value);
78
+ setOpen(false);
79
+ return true;
80
+ }
81
+ case 'escape': setOpen(false); return true;
82
+ default: return false;
83
+ }
84
+ },
85
+ { focusId: focus.id },
86
+ );
87
+
88
+ const selected = options.find((o) => o.value === value);
89
+ const start = Math.max(0, Math.min(highlight - Math.floor(visibleRows / 2), options.length - visibleRows));
90
+ const window = options.slice(start, start + visibleRows);
91
+
92
+ /**
93
+ * The options, wherever they are being drawn.
94
+ *
95
+ * One function rather than one per mode: three copies of a highlighted row
96
+ * is three chances for the modes to drift into looking like different
97
+ * controls, and the whole claim here is that they are one control shown in
98
+ * three places.
99
+ */
100
+ function list(): RenderOutput {
101
+ return h('box', { direction: 'column' },
102
+ ...window.map((option, i) => {
103
+ const active = start + i === highlight;
104
+ return h('box', {
105
+ key: option.value,
106
+ direction: 'row',
107
+ gap: 1,
108
+ // Ink, not a filled row.
109
+ //
110
+ // A background swatch is the heaviest mark available and it has
111
+ // to invert the text to stay readable, so the highlighted option
112
+ // is the one option whose colour tells you nothing about itself.
113
+ // Accent and an underline say "here" without repainting the row.
114
+ fg: option.disabled ? 'disabled' : active ? 'accent' : undefined,
115
+ onClick: () => {
116
+ if (option.disabled) return;
117
+ onChange?.(option.value);
118
+ setOpen(false);
119
+ },
120
+ },
121
+ h('text', { content: active ? theme.glyphs.chevronRight : ' ' }),
122
+ option.icon ? h('text', { content: option.icon }) : null,
123
+ h('text', { content: option.label, underline: active, bold: active }),
124
+ h('box', { flex: 1 }),
125
+ option.value === value ? h('text', { content: theme.glyphs.check }) : null,
126
+ );
127
+ }));
128
+ }
129
+
130
+ /*
131
+ * Opening a layer, and keeping it in step.
132
+ *
133
+ * Two effects rather than one, because they answer different questions. The
134
+ * first is "is there a layer" and runs when the mode or the open state
135
+ * changes; the second is "what is in it" and runs whenever the highlight
136
+ * moves. Reopening on every arrow key would work and would also mean a new
137
+ * layer entry per keystroke, with whatever a layer manager does on open -
138
+ * ordering, focus bookkeeping, the scrim - done four times to move a cursor
139
+ * four rows.
140
+ *
141
+ * The control keeps the keyboard either way, so `trapFocus` stays off: the
142
+ * layer is a surface to draw the list on, and moving focus into it would
143
+ * take the arrow keys away from the handler that answers them.
144
+ */
145
+ const layerId = `select:${focus.id}`;
146
+ const floating = mode !== 'inline';
147
+
148
+ useEffect(() => {
149
+ if (!floating || !open) return undefined;
150
+ const handle = app.layers.open({
151
+ id: layerId,
152
+ layer: mode === 'modal' ? 'modal' : 'floating',
153
+ scrim: mode === 'modal',
154
+ // Escape is the control's, and closing it there disposes this. Handled
155
+ // in both places, the layer would close and the control would still
156
+ // think it was open.
157
+ dismissOnEscape: false,
158
+ dismissOnOutsideClick: true,
159
+ position: mode === 'modal'
160
+ ? { kind: 'center' }
161
+ : { kind: 'anchor', targetId: focus.id, side: 'bottom', align: 'start' },
162
+ node: panel(),
163
+ onClose: () => setOpen(false),
164
+ });
165
+ return () => { handle.dispose(); };
166
+ }, [floating, open, mode]);
167
+
168
+ useEffect(() => {
169
+ if (!floating || !open) return;
170
+ app.layers.update(layerId, { node: panel() });
171
+ }, [highlight, value, options.length]);
172
+
173
+ /** The list with something to sit in, which inline gets from the control. */
174
+ function panel(): ComponentNode {
175
+ return h('box', {
176
+ direction: 'column',
177
+ // As wide as the control it came out of, so the two line up.
178
+ //
179
+ // `useMeasure` reports the *content* rect, and this panel has a frame
180
+ // and a gutter of its own to pay for - the same two the control is
181
+ // already paying - so it is four cells narrower than the box it is
182
+ // supposed to sit under unless they are added back.
183
+ width: Math.max(20, measured.width + 4),
184
+ border: theme.border,
185
+ bg: 'overlay',
186
+ padding: [0, 1],
187
+ }, list()) as ComponentNode;
188
+ }
189
+
190
+ /**
191
+ * One box, open or shut.
192
+ *
193
+ * The list used to be a second bordered box under the first, so opening the
194
+ * control drew two rules back to back and the options read as a separate
195
+ * thing that happened to be nearby. They are the control - the same border
196
+ * holds both, with a rule between them where the two borders used to be.
197
+ */
198
+ return h('box', {
199
+ id: focus.id,
200
+ role: 'combobox',
201
+ label,
202
+ direction: 'column',
203
+ border: { style: theme.border, color: focus.focused ? 'focus' : 'border' },
204
+ padding: [0, 1],
205
+ ...rest,
206
+ },
207
+ h('box', {
208
+ direction: 'row',
209
+ gap: 1,
210
+ onClick: () => { if (!disabled) setOpen(!open); },
211
+ },
212
+ label ? h('text', { content: label, fg: 'muted' }) : null,
213
+ h('text', {
214
+ content: selected?.label ?? empty,
215
+ fg: selected ? undefined : 'subtle',
216
+ flex: 1,
217
+ truncate: 'end',
218
+ }),
219
+ h('text', { content: open ? theme.glyphs.chevronUp : theme.glyphs.chevronDown, fg: 'muted' })),
220
+
221
+ // A borderless theme has no rule to draw, and a blank row there would be
222
+ // the gap this was meant to close.
223
+ mode === 'inline' && open && theme.border !== 'none'
224
+ ? h('box', { height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' })
225
+ : null,
226
+
227
+ mode === 'inline' && open ? list() : null,
228
+ );
229
+
230
+ });
@@ -0,0 +1,41 @@
1
+ import type { BoxProps } from '@textui/core';
2
+
3
+ export interface TextInputProps extends BoxProps {
4
+ value: string;
5
+ onChange?(value: string): void;
6
+ onSubmit?(value: string): void;
7
+ placeholder?: string;
8
+ label?: string;
9
+ /**
10
+ * Keep the label as the field's name but do not draw it inside the field -
11
+ * for a form or a dialog that already shows it beside or above the input.
12
+ */
13
+ hideLabel?: boolean;
14
+ /** Replace every character, for secrets. */
15
+ mask?: string;
16
+ /** Stop accepting input past this many characters. */
17
+ maxLength?: number;
18
+ autoFocus?: boolean;
19
+ /** Draw a search glyph before the field. */
20
+ search?: boolean;
21
+ /**
22
+ * A stable focus id, so a command can send the reader here by name.
23
+ *
24
+ * Without one a control's id is derived from its instance, which nothing
25
+ * outside the render can know - so "focus the filter" has nothing to name
26
+ * and the key that would do it cannot be written.
27
+ */
28
+ focusId?: string;
29
+ /**
30
+ * The caret tried to leave the field.
31
+ *
32
+ * A single-line input answers `left` and `right` itself right up to the
33
+ * ends, so a caller that wants those keys past the ends cannot have them
34
+ * from a key handler - the field takes the key and reports nothing. This is
35
+ * how it reports: the palette drills into a command's choices on `right`,
36
+ * and the path picker goes up a folder on `left`. `TextArea` has had this
37
+ * from the start; the two controls disagreeing is what left both of those
38
+ * keys silently doing nothing.
39
+ */
40
+ onEdge?(edge: 'start' | 'end'): void;
41
+ }
@@ -0,0 +1,63 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useFocus, useInput, useTheme } from '@textui/core';
3
+
4
+ export interface SliderProps extends BoxProps {
5
+ value: number;
6
+ min?: number;
7
+ max?: number;
8
+ step?: number;
9
+ label?: string;
10
+ onChange?(value: number): void;
11
+ /** Cells the track occupies. */
12
+ trackWidth?: number;
13
+ format?(value: number): string;
14
+ }
15
+
16
+ export const Slider = defineComponent<SliderProps>('Slider', (props) => {
17
+ const theme = useTheme();
18
+ const {
19
+ value, min = 0, max = 100, step = 1, label, onChange,
20
+ trackWidth = 20, format, disabled, ...rest
21
+ } = props;
22
+ const focus = useFocus({ disabled });
23
+
24
+ const clamp = (v: number): number => Math.max(min, Math.min(max, v));
25
+
26
+ useInput(
27
+ (event) => {
28
+ if (disabled) return false;
29
+ const big = Math.max(step, Math.round((max - min) / 10));
30
+ switch (event.name) {
31
+ case 'left': onChange?.(clamp(value - step)); return true;
32
+ case 'right': onChange?.(clamp(value + step)); return true;
33
+ case 'pagedown': onChange?.(clamp(value - big)); return true;
34
+ case 'pageup': onChange?.(clamp(value + big)); return true;
35
+ case 'home': onChange?.(min); return true;
36
+ case 'end': onChange?.(max); return true;
37
+ default: return false;
38
+ }
39
+ },
40
+ { focusId: focus.id },
41
+ );
42
+
43
+ const ratio = max === min ? 0 : (clamp(value) - min) / (max - min);
44
+ const filled = Math.round(ratio * (trackWidth - 1));
45
+
46
+ // Track, thumb and remainder all come from the theme, so an ascii terminal
47
+ // gets `--o--` rather than a row of question marks.
48
+ const thumb = theme.glyphs.bulletFilled;
49
+ const done = theme.glyphs.progressFull;
50
+ const todo = theme.glyphs.progressEmpty;
51
+ const track = Array.from({ length: trackWidth }, (_, i) =>
52
+ i === filled ? thumb : i < filled ? done : todo,
53
+ ).join('');
54
+
55
+ return h('box', { id: focus.id, role: 'slider', label, direction: 'row', gap: 1, ...rest },
56
+ label ? h('text', { content: label, fg: 'muted' }) : null,
57
+ h('text', {
58
+ content: track,
59
+ fg: disabled ? 'disabled' : focus.focused ? 'accent' : 'border',
60
+ }),
61
+ h('text', { content: format ? format(value) : String(value), fg: 'muted' }),
62
+ );
63
+ });
@@ -0,0 +1,39 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useFocus, useInput } from '@textui/core';
3
+
4
+ export interface SwitchProps extends BoxProps {
5
+ label?: string;
6
+ value?: boolean;
7
+ onChange?(value: boolean): void;
8
+ /** Words either side, so the state reads without colour. */
9
+ labels?: [off: string, on: string];
10
+ }
11
+
12
+ export const Switch = defineComponent<SwitchProps>('Switch', (props) => {
13
+ const { label, value = false, onChange, labels = ['off', 'on'], disabled, ...rest } = props;
14
+ const focus = useFocus({ disabled });
15
+
16
+ useInput(
17
+ (event) => {
18
+ if (disabled) return false;
19
+ if (event.name === 'space' || event.name === 'enter') { onChange?.(!value); return true; }
20
+ if (event.name === 'left') { onChange?.(false); return true; }
21
+ if (event.name === 'right') { onChange?.(true); return true; }
22
+ return false;
23
+ },
24
+ { focusId: focus.id },
25
+ );
26
+
27
+ return h('box', {
28
+ id: focus.id, role: 'switch', label, selected: value,
29
+ direction: 'row', gap: 1, bold: focus.focused,
30
+ onClick: () => { if (!disabled) onChange?.(!value); },
31
+ ...rest,
32
+ },
33
+ label ? h('text', { content: label }) : null,
34
+ h('text', {
35
+ content: value ? `[${labels[1]}]` : `[${labels[0]}]`,
36
+ fg: disabled ? 'disabled' : value ? 'accent' : 'muted',
37
+ }),
38
+ );
39
+ });