@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,232 @@
1
+ import type {
2
+ ComponentDefinition,
3
+ Disposable,
4
+ LayerEntry,
5
+ LayerPosition,
6
+ SemanticVariant,
7
+ TextUIApp,
8
+ } from '@textui/core';
9
+ import { CommandPalette } from './command-palette.js';
10
+ import { Dialog } from './dialog.js';
11
+ import { LayerScope } from './layer-scope.js';
12
+ import { PathPicker } from './path-picker.js';
13
+ import { PromptDialog } from './prompt-dialog.js';
14
+ import type { ToastHostProps } from './toast-host.js';
15
+ import { ToastHost } from './toast-host.js';
16
+ import { Toast } from './toast.js';
17
+ import { Tooltip } from './tooltip.js';
18
+
19
+ /**
20
+ * Overlays.
21
+ *
22
+ * Every one of these is a layer entry, not a component that draws itself over
23
+ * its neighbours - so focus trapping, dismissal and paint order are decided
24
+ * once by the layer manager rather than five times, slightly differently.
25
+ */
26
+ export * from './command-palette.js';
27
+ export * from './dialog.js';
28
+ export * from './layer-scope.js';
29
+ export * from './path-picker.js';
30
+ export * from './prompt-dialog.js';
31
+ export * from './toast.js';
32
+ export * from './toast-host.js';
33
+ export * from './tooltip.js';
34
+
35
+ export interface ConfirmOptions {
36
+ title?: string;
37
+ message: string;
38
+ confirmLabel?: string;
39
+ cancelLabel?: string;
40
+ tone?: SemanticVariant;
41
+ }
42
+
43
+ /**
44
+ * The composition rule the brief asks for: a dialog can be assembled by hand
45
+ * out of public components, and the common case gets a one-liner that returns
46
+ * a promise. Both go through the same layer manager.
47
+ */
48
+ export function confirm(
49
+ layers: { open(entry: LayerEntry): { dispose(): void } },
50
+ options: ConfirmOptions,
51
+ ): Promise<boolean> {
52
+ return new Promise((resolve) => {
53
+ const id = `confirm:${options.message}`;
54
+ let settled = false;
55
+
56
+ const finish = (value: boolean): void => {
57
+ if (settled) return;
58
+ settled = true;
59
+ handle.dispose();
60
+ resolve(value);
61
+ };
62
+
63
+ const handle = layers.open({
64
+ id,
65
+ layer: 'modal',
66
+ scrim: true,
67
+ trapFocus: true,
68
+ dismissOnEscape: true,
69
+ onClose: () => finish(false),
70
+ node: {
71
+ component: 'Dialog',
72
+ title: options.title ?? 'Confirm',
73
+ width: 50,
74
+ children: { component: 'text', content: options.message, wrap: 'word' },
75
+ actions: [
76
+ {
77
+ id: 'confirm',
78
+ label: options.confirmLabel ?? 'Confirm',
79
+ tone: options.tone ?? 'primary',
80
+ onPress: () => finish(true),
81
+ },
82
+ {
83
+ id: 'cancel',
84
+ label: options.cancelLabel ?? 'Cancel',
85
+ onPress: () => finish(false),
86
+ },
87
+ ],
88
+ },
89
+ });
90
+ });
91
+ }
92
+
93
+ export interface PromptOptions {
94
+ title?: string;
95
+ message?: string;
96
+ placeholder?: string;
97
+ initialValue?: string;
98
+ mask?: string;
99
+ }
100
+
101
+ export function prompt(
102
+ layers: { open(entry: LayerEntry): { dispose(): void } },
103
+ options: PromptOptions,
104
+ ): Promise<string | null> {
105
+ return new Promise((resolve) => {
106
+ let settled = false;
107
+ const finish = (value: string | null): void => {
108
+ if (settled) return;
109
+ settled = true;
110
+ handle.dispose();
111
+ resolve(value);
112
+ };
113
+
114
+ const handle = layers.open({
115
+ id: `prompt:${options.title ?? options.message ?? 'input'}`,
116
+ layer: 'modal',
117
+ scrim: true,
118
+ trapFocus: true,
119
+ dismissOnEscape: true,
120
+ onClose: () => finish(null),
121
+ node: {
122
+ component: 'PromptDialog',
123
+ title: options.title ?? 'Input',
124
+ message: options.message,
125
+ placeholder: options.placeholder,
126
+ initialValue: options.initialValue,
127
+ mask: options.mask,
128
+ onSubmit: { handler: (value: string) => finish(value) },
129
+ onCancel: { handler: () => finish(null) },
130
+ },
131
+ });
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Picking a path by looking at it.
137
+ *
138
+ * The third question, beside `confirm` and `prompt`, and it exists because the
139
+ * other two cannot ask it. A path typed blind into a text field is the worst
140
+ * way to give one: you have to already know the answer, which is the opposite
141
+ * of what picking is for.
142
+ *
143
+ * It reads the **resource registry**, never the filesystem. `search` made that
144
+ * choice already and it is why search works on whatever is mounted; a picker
145
+ * that reached for `node:fs` would work on `file:` and nothing else, and the
146
+ * first thing anyone wants to pick off a remote is a file.
147
+ */
148
+ export interface PickOptions {
149
+ /** Where to start looking. A directory URI. */
150
+ start: string;
151
+ /** What counts as an answer. Directories are walked through either way. */
152
+ wants?: 'file' | 'directory';
153
+ title?: string;
154
+ placeholder?: string;
155
+ visibleRows?: number;
156
+ width?: number;
157
+ }
158
+
159
+ export function pick(app: TextUIApp, options: PickOptions): Promise<string | null> {
160
+ return new Promise((resolve) => {
161
+ let settled = false;
162
+ const finish = (value: string | null): void => {
163
+ if (settled) return;
164
+ settled = true;
165
+ handle.dispose();
166
+ resolve(value);
167
+ };
168
+
169
+ const handle = app.layers.open({
170
+ id: `pick:${options.start}`,
171
+ layer: 'modal',
172
+ scrim: true,
173
+ trapFocus: true,
174
+ dismissOnEscape: true,
175
+ onClose: () => finish(null),
176
+ node: {
177
+ component: 'PathPicker',
178
+ start: options.start,
179
+ wants: options.wants ?? 'file',
180
+ title: options.title,
181
+ placeholder: options.placeholder,
182
+ visibleRows: options.visibleRows,
183
+ width: options.width,
184
+ onPick: { handler: (uri: string) => finish(uri) },
185
+ onCancel: { handler: () => finish(null) },
186
+ },
187
+ });
188
+ });
189
+ }
190
+
191
+ export interface NotifyOptions {
192
+ message: string;
193
+ tone?: SemanticVariant;
194
+ title?: string;
195
+ icon?: string;
196
+ /** Milliseconds on screen. 0 keeps it until it is closed. */
197
+ timeoutMs?: number;
198
+ /** Reuse an id to replace a standing toast rather than stack another. */
199
+ id?: string;
200
+ }
201
+
202
+ let notifyCounter = 0;
203
+
204
+ export function notify(app: TextUIApp, options: NotifyOptions): Disposable {
205
+ const { message, tone = 'info', title, icon, timeoutMs = 2500, id } = options;
206
+ return app.layers.open({
207
+ id: id ?? `toast-${++notifyCounter}`,
208
+ layer: 'notification',
209
+ timeoutMs: timeoutMs > 0 ? timeoutMs : undefined,
210
+ node: { component: 'Toast', message, tone, title, icon },
211
+ });
212
+ }
213
+
214
+ export function toastPosition(anchor: ToastHostProps['anchor']): LayerPosition {
215
+ switch (anchor) {
216
+ case 'top': return { kind: 'screen', rect: { y: 1 } };
217
+ case 'top-right': return { kind: 'screen', rect: { y: 1 } };
218
+ case 'bottom': return { kind: 'screen', rect: { y: 0 } };
219
+ default: return { kind: 'screen', rect: {} };
220
+ }
221
+ }
222
+
223
+ export const OVERLAY_COMPONENTS: ComponentDefinition[] = [
224
+ { component: 'Dialog', category: 'overlay', renderer: { kind: 'function', render: Dialog }, role: 'dialog', description: 'Modal box with actions; traps focus and restores it.' },
225
+ { component: 'PromptDialog', category: 'overlay', renderer: { kind: 'function', render: PromptDialog }, role: 'dialog', description: 'One-field dialog behind the `prompt` helper.' },
226
+ { component: 'PathPicker', category: 'overlay', renderer: { kind: 'function', render: PathPicker }, role: 'dialog', description: 'Walk the resource tree and pick a file or a folder.' },
227
+ { component: 'Tooltip', category: 'overlay', renderer: { kind: 'function', render: Tooltip }, role: 'tooltip', description: 'Small anchored hint.' },
228
+ { component: 'Toast', category: 'overlay', renderer: { kind: 'function', render: Toast }, role: 'status', description: 'Transient notification.' },
229
+ { component: 'ToastHost', category: 'overlay', renderer: { kind: 'function', render: ToastHost }, description: 'Where toasts stack.' },
230
+ { component: 'LayerScope', category: 'overlay', renderer: { kind: 'function', render: LayerScope }, description: 'The focus scope a layer lives in; makes `trapFocus` real.' },
231
+ { component: 'CommandPalette', category: 'overlay', renderer: { kind: 'function', render: CommandPalette }, role: 'dialog', description: 'Fuzzy search over the command registry.' },
232
+ ];
@@ -0,0 +1,26 @@
1
+ import type { ComponentNode, RenderOutput } from '@textui/core';
2
+ import { defineComponent, useFocusScope } from '@textui/core';
3
+
4
+ /**
5
+ * The focus scope a layer lives in.
6
+ *
7
+ * `trapFocus` on a layer used to be a flag nothing read: `Dialog` and
8
+ * `CommandPalette` trapped because they each called `useFocusScope`
9
+ * themselves, and any layer built out of plain nodes - a menu dropdown, say -
10
+ * silently did not. Tab then walked straight out of the open thing and into
11
+ * whatever was behind it, and the next key went with it.
12
+ *
13
+ * Wrapping every layer in this makes the flag mean what it says, once, for all
14
+ * of them. It renders its child rather than a box of its own, so a layer's
15
+ * measurements are unchanged by being scoped.
16
+ */
17
+ export interface LayerScopeProps {
18
+ scopeId: string;
19
+ trap?: boolean;
20
+ children?: ComponentNode | ComponentNode[];
21
+ }
22
+
23
+ export const LayerScope = defineComponent<LayerScopeProps>('LayerScope', (props) => {
24
+ useFocusScope({ id: `layer:${props.scopeId}`, trap: props.trap === true, restore: true });
25
+ return (props.children ?? null) as RenderOutput;
26
+ });
@@ -0,0 +1,215 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import {
3
+ defineComponent,
4
+ h,
5
+ nameOf,
6
+ useEffect,
7
+ useInput,
8
+ useRuntime,
9
+ useState,
10
+ useTheme,
11
+ } from '@textui/core';
12
+ import { TextInput } from '../control/index.js';
13
+ import type { MenuItem } from '../navigation/index.js';
14
+ import { Menu } from '../navigation/index.js';
15
+ import { hint } from './shared.js';
16
+
17
+ export interface PathPickerProps extends BoxProps {
18
+ start: string;
19
+ wants?: 'file' | 'directory';
20
+ title?: string;
21
+ placeholder?: string;
22
+ visibleRows?: number;
23
+ onPick?(uri: string): void;
24
+ onCancel?(): void;
25
+ }
26
+
27
+ /** The parent of a directory URI, or null at the top of its scheme. */
28
+ export function parentOf(uri: string): string | null {
29
+ const at = uri.lastIndexOf('/');
30
+ if (at < 0) return null;
31
+ const head = uri.slice(0, at);
32
+ // `scheme://` is a root, not a parent: trimming again would produce
33
+ // `scheme:/` and then `scheme:`, which are two URIs nothing can list.
34
+ if (head.endsWith('/') || head.endsWith(':')) return null;
35
+ return head;
36
+ }
37
+
38
+ export const PathPicker = defineComponent<PathPickerProps>('PathPicker', (props) => {
39
+ const {
40
+ start, wants = 'file', title, placeholder, visibleRows = 10,
41
+ width = 60, onPick, onCancel, ...rest
42
+ } = props;
43
+ const theme = useTheme();
44
+ const runtime = useRuntime();
45
+ const app = runtime.app();
46
+
47
+ const [at, setAt] = useState(start);
48
+ const [query, setQuery] = useState('');
49
+ const [highlight, setHighlight] = useState(0);
50
+ const [entries, setEntries] = useState<{ uri: string; name: string; directory: boolean }[]>([]);
51
+ /*
52
+ * An empty folder and a folder still being read are different answers.
53
+ *
54
+ * "Nothing here" under a list that has not arrived is a lie the reader acts
55
+ * on - they press escape and go somewhere else. So the list says which.
56
+ */
57
+ const [loading, setLoading] = useState(true);
58
+
59
+ useEffect(() => {
60
+ let live = true;
61
+ setLoading(true);
62
+ void (async () => {
63
+ const found = await app?.resources.list(at).catch(() => []) ?? [];
64
+ if (!live) return;
65
+ setEntries(found.map((r) => ({
66
+ uri: r.uri,
67
+ name: r.metadata.name || nameOf(r.uri),
68
+ directory: r.capabilities.includes('list'),
69
+ })));
70
+ setLoading(false);
71
+ })();
72
+ return () => { live = false; };
73
+ }, [at]);
74
+
75
+ const parent = parentOf(at);
76
+ const q = query.trim().toLowerCase();
77
+ const shown = entries
78
+ // A folder cannot be *chosen* when a file is wanted, but it still has to
79
+ // be walked through - so both kinds are listed either way, and only what
80
+ // enter does about them differs.
81
+ .filter((e) => q === '' || e.name.toLowerCase().includes(q))
82
+ // Folders first, then by name: a list sorted only by name buries the way
83
+ // onward among the things at the end of the journey.
84
+ .sort((a, b) => (a.directory === b.directory
85
+ ? a.name.localeCompare(b.name)
86
+ : (a.directory ? -1 : 1)));
87
+
88
+ const rows: MenuItem[] = [
89
+ // Picking the folder you are standing in needs a row, because there is no
90
+ // child to press enter on and a hidden chord for it is a chord nobody
91
+ // finds. It is first, since it is the answer most often wanted.
92
+ ...(wants === 'directory'
93
+ ? [{ id: '.', label: 'Use this folder', icon: theme.glyphs.check }]
94
+ : []),
95
+ ...(parent !== null ? [{ id: '..', label: '..', icon: theme.glyphs.chevronUp }] : []),
96
+ ...shown.map((e) => ({
97
+ id: e.uri,
98
+ label: e.name,
99
+ icon: e.directory ? theme.glyphs.chevronRight : ' ',
100
+ ...(e.directory ? {} : { description: '' }),
101
+ })),
102
+ ];
103
+
104
+ const index = Math.max(0, Math.min(highlight, rows.length - 1));
105
+
106
+ const up = (): void => {
107
+ if (parent === null) return;
108
+ setAt(parent);
109
+ setQuery('');
110
+ setHighlight(0);
111
+ };
112
+
113
+ const choose = (id?: string): void => {
114
+ const chosen = id ?? rows[index]?.id;
115
+ if (chosen === undefined) return;
116
+ if (chosen === '.') { onPick?.(at); return; }
117
+ if (chosen === '..') { up(); return; }
118
+ const entry = entries.find((e) => e.uri === chosen);
119
+ if (!entry) return;
120
+ // A directory is a place to go when a file is wanted, and both a place to
121
+ // go and an answer when one is not - which is why enter descends and the
122
+ // row above is what picks.
123
+ if (entry.directory) { setAt(entry.uri); setQuery(''); setHighlight(0); return; }
124
+ if (wants === 'file') onPick?.(entry.uri);
125
+ };
126
+
127
+ useInput((event) => {
128
+ const wrap = (n: number): number => (rows.length === 0
129
+ ? 0
130
+ : ((n % rows.length) + rows.length) % rows.length);
131
+ if (event.name === 'up') { setHighlight(wrap(index - 1)); return true; }
132
+ if (event.name === 'down') { setHighlight(wrap(index + 1)); return true; }
133
+ // Only when a caller gave one. `pick` mounts this on a dismissible layer
134
+ // and the layer closes itself on escape, so taking the key unconditionally
135
+ // would swallow escape for a caller that mounted the picker plainly and
136
+ // wired nothing to it.
137
+ if (event.name === 'escape' && onCancel) { onCancel(); return true; }
138
+ return false;
139
+ }, { global: true });
140
+
141
+
142
+ const move = `${theme.glyphs.arrowUp}${theme.glyphs.arrowDown} move`;
143
+
144
+ return h('box', {
145
+ role: 'dialog',
146
+ label: title ?? 'Choose',
147
+ border: theme.border,
148
+ bg: 'overlay',
149
+ width,
150
+ direction: 'column',
151
+ ...(theme.border === 'none' ? { padding: { left: 1, right: 1 } } : {}),
152
+ title: ` ${title ?? (wants === 'directory' ? 'choose a folder' : 'choose a file')} `,
153
+ ...rest,
154
+ },
155
+ // Where you are. A column of bare names with no header is a list you can
156
+ // get lost in - and the tail is the part that changes, so it is the part
157
+ // kept when the path is too long for the dialog.
158
+ h('text', { content: at, fg: 'muted', truncate: 'start' }),
159
+ h(TextInput, {
160
+ value: query,
161
+ onChange: (next: string) => { setQuery(next); setHighlight(0); },
162
+ onSubmit: () => choose(),
163
+ /*
164
+ * Leftwards is upwards, the way it is in every tree.
165
+ *
166
+ * Through `onEdge` rather than a key handler beside the others: the
167
+ * field has the keyboard, and it answers `left` itself until the caret
168
+ * runs out of text. A global handler for it never fires - the field
169
+ * reports the edge instead, which is the hook that exists for exactly
170
+ * this. It also means a typed filter keeps its own arrows, which is
171
+ * what you want while editing one.
172
+ */
173
+ onEdge: (edge: 'start' | 'end') => { if (edge === 'start') up(); },
174
+ placeholder: placeholder ?? `Filter${theme.glyphs.ellipsis}`,
175
+ search: true,
176
+ autoFocus: true,
177
+ border: 'none',
178
+ }),
179
+ h('box', { height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' }),
180
+ h(Menu, {
181
+ items: rows,
182
+ visibleRows,
183
+ interactive: false,
184
+ activeId: rows[index]?.id,
185
+ onSelect: (id: string) => { choose(id); },
186
+ }),
187
+ /*
188
+ * An empty folder and a folder still being read are different answers.
189
+ *
190
+ * "Nothing here" under a list that has not arrived is a lie the reader
191
+ * acts on - they press escape and go somewhere else. It is a line of its
192
+ * own rather than the menu's empty state because the menu is never empty:
193
+ * `..` and "Use this folder" are rows, and neither is a child.
194
+ */
195
+ shown.length === 0
196
+ ? h('text', {
197
+ content: loading
198
+ ? `Reading${theme.glyphs.ellipsis}`
199
+ : (q === '' ? 'Nothing here.' : 'Nothing matches.'),
200
+ fg: 'muted',
201
+ })
202
+ : null,
203
+ h('box', { height: 1, fill: theme.borderChars().top, fg: 'borderSubtle' }),
204
+ h('text', {
205
+ content: hint(theme, [
206
+ move,
207
+ wants === 'directory' ? 'enter open' : 'enter choose',
208
+ `${theme.glyphs.chevronLeft} up`,
209
+ 'esc cancel',
210
+ ]),
211
+ fg: 'subtle',
212
+ truncate: 'end',
213
+ }),
214
+ );
215
+ });
@@ -0,0 +1,45 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useState } from '@textui/core';
3
+ import { TextInput } from '../control/index.js';
4
+ import { Dialog } from './dialog.js';
5
+
6
+ export interface PromptDialogProps extends BoxProps {
7
+ title?: string;
8
+ message?: string;
9
+ placeholder?: string;
10
+ initialValue?: string;
11
+ mask?: string;
12
+ onSubmit?(value: string): void;
13
+ onCancel?(): void;
14
+ }
15
+
16
+ export const PromptDialog = defineComponent<PromptDialogProps>('PromptDialog', (props) => {
17
+ const { title, message, placeholder, initialValue = '', mask, onSubmit, onCancel, ...rest } = props;
18
+ const [value, setValue] = useState(initialValue);
19
+
20
+ return h(Dialog, {
21
+ title,
22
+ width: 50,
23
+ onClose: onCancel,
24
+ actions: [
25
+ { id: 'ok', label: 'OK', tone: 'primary', onPress: () => onSubmit?.(value) },
26
+ { id: 'cancel', label: 'Cancel', onPress: onCancel },
27
+ ],
28
+ ...rest,
29
+ },
30
+ message ? h('text', { content: message, wrap: 'word' }) : null,
31
+ h(TextInput, {
32
+ value,
33
+ onChange: setValue,
34
+ placeholder,
35
+ mask,
36
+ // The message names the field: an unlabelled input is a focus stop
37
+ // nothing can describe, in the dialog whose whole job is one question.
38
+ // It is already on screen above, so it is not drawn twice.
39
+ label: message,
40
+ hideLabel: true,
41
+ autoFocus: true,
42
+ onSubmit: () => onSubmit?.(value),
43
+ }),
44
+ );
45
+ });
@@ -0,0 +1,19 @@
1
+ import type { ResolvedTheme } from '@textui/core';
2
+
3
+ /**
4
+ * Raise a toast.
5
+ *
6
+ * Exists because the alternative - every caller assembling a layer entry - is
7
+ * how two of them end up with different timeouts and one of them forgets the
8
+ * `notification` layer and lands under the dialog it is reporting on.
9
+ */
10
+ /**
11
+ * The footer of an overlay: what the keys do.
12
+ *
13
+ * Joined with the theme's separator rather than a `·` written here, because a
14
+ * terminal that cannot draw a middle dot draws a `?` instead - and the row it
15
+ * ruins is the one telling you how to get out.
16
+ */
17
+ export function hint(theme: ResolvedTheme, parts: string[]): string {
18
+ return parts.join(` ${theme.glyphs.separator} `);
19
+ }
@@ -0,0 +1,30 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useEffect, useRuntime } from '@textui/core';
3
+
4
+ export interface ToastHostProps extends BoxProps {
5
+ /** Where the stack sits. Named `anchor` so it does not shadow `position`. */
6
+ anchor?: 'top-right' | 'bottom-right' | 'top' | 'bottom';
7
+ }
8
+
9
+ /** Renders whatever is on the notification layer. */
10
+ export const ToastHost = defineComponent<ToastHostProps>('ToastHost', (props) => {
11
+ const runtime = useRuntime();
12
+ const { anchor = 'bottom-right', ...rest } = props;
13
+ const entries = runtime.layers.entries('notification');
14
+
15
+ useEffect(() => {
16
+ // Re-render when the layer set changes; the manager already asks for a
17
+ // frame, this only keeps the subscription honest.
18
+ }, [entries.length]);
19
+
20
+ if (entries.length === 0) return null;
21
+
22
+ return h('box', {
23
+ direction: 'column',
24
+ gap: 1,
25
+ align: anchor.endsWith('right') ? 'end' : 'stretch',
26
+ ...rest,
27
+ },
28
+ ...entries.map((entry) => h('box', { key: entry.id }, entry.node)),
29
+ );
30
+ });
@@ -0,0 +1,35 @@
1
+ import type { BoxProps, SemanticVariant } from '@textui/core';
2
+ import { defineComponent, h, useTheme } from '@textui/core';
3
+
4
+ export interface ToastProps extends BoxProps {
5
+ message: string;
6
+ tone?: SemanticVariant;
7
+ title?: string;
8
+ icon?: string;
9
+ }
10
+
11
+ export const Toast = defineComponent<ToastProps>('Toast', (props) => {
12
+ const theme = useTheme();
13
+ const { message, tone = 'info', title, icon, ...rest } = props;
14
+ const glyph = icon ?? {
15
+ success: theme.glyphs.check,
16
+ warning: theme.glyphs.warning,
17
+ danger: theme.glyphs.cross,
18
+ info: theme.glyphs.info,
19
+ }[tone as 'success' | 'warning' | 'danger' | 'info'] ?? theme.glyphs.info;
20
+
21
+ return h('box', {
22
+ role: 'status',
23
+ border: theme.border,
24
+ bg: 'overlay',
25
+ padding: [0, 1],
26
+ direction: 'row',
27
+ gap: 1,
28
+ ...rest,
29
+ },
30
+ h('text', { content: glyph, fg: tone }),
31
+ h('box', { direction: 'column' },
32
+ title ? h('text', { content: title, bold: true }) : null,
33
+ h('text', { content: message, wrap: 'word' })),
34
+ );
35
+ });
@@ -0,0 +1,17 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import { defineComponent, h, useTheme } from '@textui/core';
3
+
4
+ export interface TooltipProps extends BoxProps {
5
+ text: string;
6
+ }
7
+
8
+ export const Tooltip = defineComponent<TooltipProps>('Tooltip', ({ text, ...rest }) => {
9
+ const theme = useTheme();
10
+ return h('box', {
11
+ role: 'tooltip',
12
+ border: theme.border,
13
+ bg: 'overlay',
14
+ padding: [0, 1],
15
+ ...rest,
16
+ }, h('text', { content: text }));
17
+ });