@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
package/dist/find.js ADDED
@@ -0,0 +1,102 @@
1
+ import { useStoreValue } from '@textui/core';
2
+ /**
3
+ * Finding things in text.
4
+ *
5
+ * The query lives in the store rather than in whatever component is showing
6
+ * the text, for the usual reason: a search box, a status bar counting matches
7
+ * and the viewer painting them are three things that have to agree, and the
8
+ * only way three things agree is by reading one answer.
9
+ *
10
+ * The matching itself is here and not in the editor because a viewer wants it
11
+ * too, and so will a results panel: given a string and a query, which spans
12
+ * matched. Nothing here knows what a caret is.
13
+ */
14
+ export const FIND_ROOT = '$/ui/find';
15
+ export const FIND_QUERY = `${FIND_ROOT}/query`;
16
+ export const FIND_CASE = `${FIND_ROOT}/matchCase`;
17
+ /** Bumped to ask whoever is showing the text to move to the next match. */
18
+ export const FIND_STEP = `${FIND_ROOT}/step`;
19
+ /**
20
+ * Every match in a document, in reading order.
21
+ *
22
+ * Overlapping matches are not a thing: a search steps past what it found, so
23
+ * `aa` in `aaaa` is two matches and not three. That is what every editor does
24
+ * and what "next" means when you press it twice.
25
+ */
26
+ export function findMatches(text, query) {
27
+ const needle = query.matchCase === true ? query.text : query.text.toLowerCase();
28
+ if (needle === '')
29
+ return [];
30
+ const out = [];
31
+ const lines = text.split('\n');
32
+ for (let line = 0; line < lines.length; line++) {
33
+ const raw = lines[line];
34
+ const haystack = query.matchCase === true ? raw : raw.toLowerCase();
35
+ let at = haystack.indexOf(needle);
36
+ while (at !== -1) {
37
+ out.push({ line, start: at, end: at + needle.length });
38
+ at = haystack.indexOf(needle, at + needle.length);
39
+ }
40
+ }
41
+ return out;
42
+ }
43
+ /**
44
+ * The match a caret should go to next, wrapping at the end.
45
+ *
46
+ * From *after* the caret, not from the caret: pressing next while sitting on a
47
+ * match has to move, or "next" is a key that does nothing. Backwards is the
48
+ * mirror, and both wrap, because a search that stops at the end of the file is
49
+ * a search you have to restart by hand.
50
+ */
51
+ export function stepMatch(matches, from, direction) {
52
+ if (matches.length === 0)
53
+ return -1;
54
+ if (direction === 1) {
55
+ const found = matches.findIndex((m) => m.line > from.line || (m.line === from.line && m.start > from.column));
56
+ return found === -1 ? 0 : found;
57
+ }
58
+ /*
59
+ * Backwards, from *before* the caret - and the caret is usually sitting at
60
+ * the end of the match it just stepped to, so "before" has to mean the match
61
+ * *ends* before it. Comparing starts instead finds the match the caret is
62
+ * standing in and calls that the previous one, which is a key that does
63
+ * nothing every other press.
64
+ */
65
+ for (let i = matches.length - 1; i >= 0; i--) {
66
+ const m = matches[i];
67
+ if (m.line < from.line || (m.line === from.line && m.end < from.column))
68
+ return i;
69
+ }
70
+ return matches.length - 1;
71
+ }
72
+ /** Which match the caret is sitting inside, or -1. */
73
+ export function matchAt(matches, at) {
74
+ return matches.findIndex((m) => m.line === at.line && at.column >= m.start && at.column <= m.end);
75
+ }
76
+ export function readQuery(store) {
77
+ return {
78
+ text: store.get(FIND_QUERY) ?? '',
79
+ matchCase: store.get(FIND_CASE) === true,
80
+ };
81
+ }
82
+ export function setQuery(store, text) {
83
+ store.set(FIND_QUERY, text);
84
+ }
85
+ /**
86
+ * Ask whoever is showing the text to move.
87
+ *
88
+ * A counter rather than a command, so the thing that moves is the thing that
89
+ * knows where the caret is - and so two panels showing the same file each move
90
+ * their own.
91
+ */
92
+ export function stepFind(store, direction) {
93
+ const at = store.get(FIND_STEP);
94
+ store.set(FIND_STEP, { n: (at?.n ?? 0) + 1, direction });
95
+ }
96
+ /** The current query, and the ask to move, for a component showing text. */
97
+ export function useFind() {
98
+ const text = useStoreValue(FIND_QUERY, '') ?? '';
99
+ const matchCase = useStoreValue(FIND_CASE, false) === true;
100
+ const step = useStoreValue(FIND_STEP);
101
+ return { query: { text, matchCase }, step };
102
+ }
@@ -0,0 +1,11 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface DangerZoneProps extends BoxProps {
3
+ title?: string;
4
+ description?: string;
5
+ actionLabel: string;
6
+ onAction?(): void;
7
+ /** Require typing this exact text before the action is enabled. */
8
+ confirmText?: string;
9
+ }
10
+ export declare const DangerZone: (props: DangerZoneProps) => import("@textui/core").RenderOutput;
11
+ //# sourceMappingURL=danger-zone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"danger-zone.d.ts","sourceRoot":"","sources":["../../src/form/danger-zone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,WAAW,eAAgB,SAAQ,QAAQ;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,iEAoBrB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ import { Button } from '../control/index.js';
3
+ export const DangerZone = defineComponent('DangerZone', (props) => {
4
+ const theme = useTheme();
5
+ const { title = 'Danger zone', description, actionLabel, onAction, confirmText, ...rest } = props;
6
+ return h('box', {
7
+ border: { style: theme.border, color: 'danger' },
8
+ padding: [0, 1],
9
+ direction: 'column',
10
+ title: ` ${title} `,
11
+ ...rest,
12
+ }, description ? h('text', { content: description, fg: 'muted', wrap: 'word' }) : null, confirmText
13
+ ? h('text', { content: `Type "${confirmText}" to confirm.`, fg: 'subtle' })
14
+ : null, h('box', { direction: 'row', justify: 'end' }, h(Button, { label: actionLabel, tone: 'danger', variant: 'outline', onPress: onAction })));
15
+ });
@@ -0,0 +1,19 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface FieldProps extends BoxProps {
3
+ name: string;
4
+ label?: string;
5
+ hint?: string;
6
+ required?: boolean;
7
+ /** Cells reserved for the label, so a column of fields lines up. */
8
+ labelWidth?: number;
9
+ /** Label above the control rather than beside it. */
10
+ stacked?: boolean;
11
+ }
12
+ /**
13
+ * A labelled control with its error.
14
+ *
15
+ * The error line is always reserved when one could appear, so a form does not
16
+ * jump a row every time validation fires.
17
+ */
18
+ export declare const Field: (props: FieldProps) => import("@textui/core").RenderOutput;
19
+ //# sourceMappingURL=field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/form/field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,WAAW,UAAW,SAAQ,QAAQ;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,eAAO,MAAM,KAAK,4DAuChB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ import { useFormContext } from './shared.js';
3
+ /**
4
+ * A labelled control with its error.
5
+ *
6
+ * The error line is always reserved when one could appear, so a form does not
7
+ * jump a row every time validation fires.
8
+ */
9
+ export const Field = defineComponent('Field', (props) => {
10
+ const theme = useTheme();
11
+ const form = useFormContext();
12
+ const { name, label, hint, required, labelWidth, stacked, children, ...rest } = props;
13
+ const error = form.errorFor(name);
14
+ const labelNode = label
15
+ ? h('box', { direction: 'row', gap: 0, width: stacked ? undefined : labelWidth }, h('text', { content: label, fg: error ? 'danger' : 'muted' }), required ? h('text', { content: '*', fg: 'danger' }) : null)
16
+ : null;
17
+ return h('box', { direction: 'column', ...rest },
18
+ // Centred, so the label sits on the control's line of text rather than on
19
+ // the top edge of its frame.
20
+ //
21
+ // A row stretches its children, so a one-row label beside a three-row
22
+ // bordered input was drawn at the top of three rows - level with the
23
+ // border, one above the text it names. Borderless controls are one row
24
+ // and were fine, which is why a form mixing the two had half its labels
25
+ // aligned and half of them a row high.
26
+ h('box', {
27
+ direction: stacked ? 'column' : 'row',
28
+ gap: stacked ? 0 : 1,
29
+ ...(stacked ? {} : { align: 'center' }),
30
+ }, labelNode, h('box', { flex: 1 }, children)), error
31
+ ? h('box', { direction: 'row', gap: 1 }, stacked ? null : h('box', { width: labelWidth }), h('text', { content: theme.glyphs.warning, fg: 'danger' }), h('text', { content: error, fg: 'danger', wrap: 'word' }))
32
+ : hint
33
+ ? h('box', { direction: 'row', gap: 1 }, stacked ? null : h('box', { width: labelWidth }), h('text', { content: hint, fg: 'subtle' }))
34
+ : null);
35
+ });
@@ -0,0 +1,11 @@
1
+ import type { BoxProps, SemanticVariant } from '@textui/core';
2
+ export interface FormActionsProps extends BoxProps {
3
+ submitLabel?: string;
4
+ cancelLabel?: string;
5
+ onCancel?(): void;
6
+ tone?: SemanticVariant;
7
+ /** Disable submit until something changed. */
8
+ requireDirty?: boolean;
9
+ }
10
+ export declare const FormActions: (props: FormActionsProps) => import("@textui/core").RenderOutput;
11
+ //# sourceMappingURL=form-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-actions.d.ts","sourceRoot":"","sources":["../../src/form/form-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAK9D,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,IAAI,CAAC;IAClB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,WAAW,kEAoBtB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { defineComponent, h, useTheme } from '@textui/core';
2
+ import { Button } from '../control/index.js';
3
+ import { useFormContext } from './shared.js';
4
+ export const FormActions = defineComponent('FormActions', (props) => {
5
+ const theme = useTheme();
6
+ const form = useFormContext();
7
+ const { submitLabel = 'Submit', cancelLabel = 'Cancel', onCancel, tone = 'primary', requireDirty = false, ...rest } = props;
8
+ const blocked = form.submitting || (requireDirty && !form.dirty);
9
+ return h('box', { direction: 'row', gap: 1, justify: 'end', ...rest }, onCancel ? h(Button, { label: cancelLabel, onPress: onCancel }) : null, h(Button, {
10
+ label: form.submitting ? `${submitLabel}${theme.glyphs.ellipsis}` : submitLabel,
11
+ tone,
12
+ variant: 'solid',
13
+ disabled: blocked,
14
+ onPress: () => void form.submit(),
15
+ }));
16
+ });
@@ -0,0 +1,7 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface FormSectionProps extends BoxProps {
3
+ title: string;
4
+ description?: string;
5
+ }
6
+ export declare const FormSection: (props: FormSectionProps) => import("@textui/core").RenderOutput;
7
+ //# sourceMappingURL=form-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form-section.d.ts","sourceRoot":"","sources":["../../src/form/form-section.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,kEAOtB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ export const FormSection = defineComponent('FormSection', (props) => {
3
+ const { title, description, children, ...rest } = props;
4
+ return h('box', { direction: 'column', ...rest }, h('text', { content: title, bold: true }), description ? h('text', { content: description, fg: 'muted', wrap: 'word' }) : null, h('box', { direction: 'column' }, children));
5
+ });
@@ -0,0 +1,7 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ import type { FormApi } from './shared.js';
3
+ export interface FormProps extends BoxProps {
4
+ form: FormApi<Record<string, unknown>>;
5
+ }
6
+ export declare const Form: (props: FormProps) => import("@textui/core").RenderOutput;
7
+ //# sourceMappingURL=form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/form/form.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,SAAU,SAAQ,QAAQ;IACzC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,IAAI,2DAGhB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ import { FormContext } from './shared.js';
3
+ export const Form = defineComponent('Form', ({ form, children, ...rest }) => h(FormContext.Provider, { value: form }, h('box', { role: 'form', direction: 'column', ...rest }, children)));
@@ -0,0 +1,42 @@
1
+ import type { ComponentDefinition } from '@textui/core';
2
+ import type { FormApi, FormErrors } from './shared.js';
3
+ /**
4
+ * Forms and validation.
5
+ *
6
+ * Validation runs on a whole values object rather than per field, because the
7
+ * rules people actually need are cross-field - "confirm must match password",
8
+ * "end must be after start" - and a per-field validator cannot see its
9
+ * siblings. Fields subscribe to the errors that name them.
10
+ */
11
+ export * from './danger-zone.js';
12
+ export * from './field.js';
13
+ export * from './form.js';
14
+ export * from './form-actions.js';
15
+ export * from './form-section.js';
16
+ export type { FormApi, FormErrors, FormState } from './shared.js';
17
+ export { useFormContext } from './shared.js';
18
+ export type Validator<T> = (values: T) => FormErrors<T> | null;
19
+ export interface UseFormOptions<T extends Record<string, unknown>> {
20
+ initialValues: T;
21
+ validate?: Validator<T>;
22
+ onSubmit?(values: T): void | Promise<void>;
23
+ }
24
+ export declare function useForm<T extends Record<string, unknown>>(options: UseFormOptions<T>): FormApi<T>;
25
+ /** Small composable validators, because every form needs the same four. */
26
+ export declare const validators: {
27
+ required: (message?: string) => (value: unknown) => string | undefined;
28
+ minLength: (n: number, message?: string) => (value: unknown) => string | undefined;
29
+ maxLength: (n: number, message?: string) => (value: unknown) => string | undefined;
30
+ pattern: (re: RegExp, message?: string) => (value: unknown) => string | undefined;
31
+ range: (min: number, max: number, message?: string) => (value: unknown) => string | undefined;
32
+ };
33
+ /**
34
+ * Build a whole-form validator from per-field rules.
35
+ *
36
+ * Returns the error map rather than `FormErrors | null`, so it composes: a
37
+ * caller can take the result, add a cross-field rule, and hand the whole thing
38
+ * to `useForm` without a null check in between.
39
+ */
40
+ export declare function fieldValidators<T extends Record<string, unknown>>(rules: Partial<Record<keyof T & string, ((value: unknown) => string | undefined)[]>>): (values: T) => FormErrors<T>;
41
+ export declare const FORM_COMPONENTS: ComponentDefinition[];
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/form/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAOxD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEvD;;;;;;;GAOG;AACH,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AAE/D,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,aAAa,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvD,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,CAAC,CAAC,CAyFZ;AAID,2EAA2E;AAC3E,eAAO,MAAM,UAAU;qCAElB,OAAO,OAAO,KAAG,MAAM,GAAG,SAAS;mBAGvB,MAAM,YAAY,MAAM,MACpC,OAAO,OAAO,KAAG,MAAM,GAAG,SAAS;mBAKvB,MAAM,YAAY,MAAM,MACpC,OAAO,OAAO,KAAG,MAAM,GAAG,SAAS;kBAKxB,MAAM,wBACjB,OAAO,OAAO,KAAG,MAAM,GAAG,SAAS;iBAGzB,MAAM,OAAO,MAAM,YAAY,MAAM,MAC/C,OAAO,OAAO,KAAG,MAAM,GAAG,SAAS;CAMvC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/D,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,GACnF,CAAC,MAAM,EAAE,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,CAc9B;AAED,eAAO,MAAM,eAAe,EAAE,mBAAmB,EAMhD,CAAC"}
@@ -0,0 +1,140 @@
1
+ import { useCallback, useMemo, useState } from '@textui/core';
2
+ import { DangerZone } from './danger-zone.js';
3
+ import { Field } from './field.js';
4
+ import { FormActions } from './form-actions.js';
5
+ import { FormSection } from './form-section.js';
6
+ import { Form } from './form.js';
7
+ /**
8
+ * Forms and validation.
9
+ *
10
+ * Validation runs on a whole values object rather than per field, because the
11
+ * rules people actually need are cross-field - "confirm must match password",
12
+ * "end must be after start" - and a per-field validator cannot see its
13
+ * siblings. Fields subscribe to the errors that name them.
14
+ */
15
+ export * from './danger-zone.js';
16
+ export * from './field.js';
17
+ export * from './form.js';
18
+ export * from './form-actions.js';
19
+ export * from './form-section.js';
20
+ export { useFormContext } from './shared.js';
21
+ export function useForm(options) {
22
+ const [values, setValuesState] = useState(options.initialValues);
23
+ // Validate the initial values immediately: a form whose required fields are
24
+ // empty is not valid, and reporting it as valid until the first keystroke
25
+ // makes `form.valid` useless for enabling a submit button.
26
+ const [errors, setErrors] = useState(() => options.validate?.(options.initialValues) ?? {});
27
+ const [touched, setTouched] = useState({});
28
+ const [submitting, setSubmitting] = useState(false);
29
+ const [submitted, setSubmitted] = useState(false);
30
+ const [initial] = useState(options.initialValues);
31
+ const runValidation = useCallback((next) => options.validate?.(next) ?? {}, [options.validate]);
32
+ const setValue = (field, value) => {
33
+ const next = { ...values, [field]: value };
34
+ setValuesState(next);
35
+ // Re-validate as they type, but only surface what they have touched.
36
+ setErrors(runValidation(next));
37
+ };
38
+ const dirty = useMemo(() => JSON.stringify(values) !== JSON.stringify(initial), [values, initial]);
39
+ const api = {
40
+ values,
41
+ errors,
42
+ touched,
43
+ submitting,
44
+ submitted,
45
+ valid: Object.keys(errors).length === 0,
46
+ dirty,
47
+ setValue,
48
+ setValues(patch) {
49
+ const next = { ...values, ...patch };
50
+ setValuesState(next);
51
+ setErrors(runValidation(next));
52
+ },
53
+ setError(field, message) {
54
+ setErrors({ ...errors, [field]: message });
55
+ },
56
+ touch(field) {
57
+ if (touched[field])
58
+ return;
59
+ setTouched({ ...touched, [field]: true });
60
+ },
61
+ reset(next) {
62
+ setValuesState(next ?? initial);
63
+ setErrors({});
64
+ setTouched({});
65
+ setSubmitted(false);
66
+ },
67
+ validate() {
68
+ const found = runValidation(values);
69
+ setErrors(found);
70
+ return Object.keys(found).length === 0;
71
+ },
72
+ async submit() {
73
+ const found = runValidation(values);
74
+ setErrors(found);
75
+ // Submitting reveals every error, touched or not.
76
+ setTouched(Object.keys(values).reduce((acc, key) => ({ ...acc, [key]: true }), {}));
77
+ if (Object.keys(found).length > 0)
78
+ return;
79
+ setSubmitting(true);
80
+ try {
81
+ await options.onSubmit?.(values);
82
+ setSubmitted(true);
83
+ }
84
+ finally {
85
+ setSubmitting(false);
86
+ }
87
+ },
88
+ errorFor(field) {
89
+ return touched[field] || submitted ? errors[field] : undefined;
90
+ },
91
+ };
92
+ return api;
93
+ }
94
+ // ------------------------------------------------------------- validators
95
+ /** Small composable validators, because every form needs the same four. */
96
+ export const validators = {
97
+ required: (message = 'Required') => (value) => value === undefined || value === null || value === '' ? message : undefined,
98
+ minLength: (n, message) => (value) => typeof value === 'string' && value.length < n
99
+ ? message ?? `Must be at least ${n} characters`
100
+ : undefined,
101
+ maxLength: (n, message) => (value) => typeof value === 'string' && value.length > n
102
+ ? message ?? `Must be at most ${n} characters`
103
+ : undefined,
104
+ pattern: (re, message = 'Invalid format') => (value) => typeof value === 'string' && value !== '' && !re.test(value) ? message : undefined,
105
+ range: (min, max, message) => (value) => {
106
+ const n = Number(value);
107
+ return Number.isNaN(n) || n < min || n > max
108
+ ? message ?? `Must be between ${min} and ${max}`
109
+ : undefined;
110
+ },
111
+ };
112
+ /**
113
+ * Build a whole-form validator from per-field rules.
114
+ *
115
+ * Returns the error map rather than `FormErrors | null`, so it composes: a
116
+ * caller can take the result, add a cross-field rule, and hand the whole thing
117
+ * to `useForm` without a null check in between.
118
+ */
119
+ export function fieldValidators(rules) {
120
+ return (values) => {
121
+ const errors = {};
122
+ for (const [field, checks] of Object.entries(rules)) {
123
+ for (const check of checks ?? []) {
124
+ const message = check(values[field]);
125
+ if (message) {
126
+ errors[field] = message;
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ return errors;
132
+ };
133
+ }
134
+ export const FORM_COMPONENTS = [
135
+ { component: 'Form', category: 'form', renderer: { kind: 'function', render: Form }, role: 'form', description: 'Provides form state to its fields.' },
136
+ { component: 'Field', category: 'form', renderer: { kind: 'function', render: Field }, description: 'Label, control and error, aligned.' },
137
+ { component: 'FormSection', category: 'form', renderer: { kind: 'function', render: FormSection }, description: 'A titled group of fields.' },
138
+ { component: 'FormActions', category: 'form', renderer: { kind: 'function', render: FormActions }, description: 'Submit and cancel.' },
139
+ { component: 'DangerZone', category: 'form', renderer: { kind: 'function', render: DangerZone }, description: 'Destructive action, fenced off.' },
140
+ ];
@@ -0,0 +1,25 @@
1
+ export type FormErrors<T> = Partial<Record<keyof T & string, string>>;
2
+ export interface FormState<T extends Record<string, unknown>> {
3
+ values: T;
4
+ errors: FormErrors<T>;
5
+ /** Fields the user has interacted with. Errors show only for these. */
6
+ touched: Partial<Record<keyof T & string, boolean>>;
7
+ submitting: boolean;
8
+ submitted: boolean;
9
+ valid: boolean;
10
+ dirty: boolean;
11
+ }
12
+ export interface FormApi<T extends Record<string, unknown>> extends FormState<T> {
13
+ setValue<K extends keyof T & string>(field: K, value: T[K]): void;
14
+ setValues(values: Partial<T>): void;
15
+ setError(field: keyof T & string, message: string | undefined): void;
16
+ touch(field: keyof T & string): void;
17
+ reset(values?: T): void;
18
+ validate(): boolean;
19
+ submit(): Promise<void>;
20
+ /** The error to show for a field: only after it has been touched. */
21
+ errorFor(field: keyof T & string): string | undefined;
22
+ }
23
+ export declare const FormContext: import("@textui/core").Context<FormApi<Record<string, unknown>> | null>;
24
+ export declare function useFormContext<T extends Record<string, unknown>>(): FormApi<T>;
25
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/form/shared.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtE,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,MAAM,EAAE,CAAC,CAAC;IACV,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACtB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IAC9E,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAClE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC;IACrE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,QAAQ,IAAI,OAAO,CAAC;IACpB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAED,eAAO,MAAM,WAAW,yEAAuE,CAAC;AAEhG,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAM9E"}
@@ -0,0 +1,9 @@
1
+ import { createContext, useContext } from '@textui/core';
2
+ export const FormContext = createContext('Form', null);
3
+ export function useFormContext() {
4
+ const form = useContext(FormContext);
5
+ if (!form) {
6
+ throw new Error('[textui] a Field must be rendered inside a Form');
7
+ }
8
+ return form;
9
+ }
@@ -0,0 +1,26 @@
1
+ import type { ComponentDefinition, TextUIApp, Disposable } from '@textui/core';
2
+ export * from './layout/index.js';
3
+ export * from './display/index.js';
4
+ export * from './control/index.js';
5
+ export * from './form/index.js';
6
+ export * from './data/index.js';
7
+ export * from './navigation/index.js';
8
+ export * from './overlay/index.js';
9
+ export * from './chart/index.js';
10
+ export * from './surface/index.js';
11
+ export * from './shells/index.js';
12
+ export * from './panel/index.js';
13
+ export * from './decorations.js';
14
+ export * from './find.js';
15
+ export * from './viewport.js';
16
+ export * from './tone.js';
17
+ /** Every component the library ships, in one list. */
18
+ export declare const CATALOG: ComponentDefinition[];
19
+ /**
20
+ * Register the catalog, the surface layouts and the built-in shells.
21
+ *
22
+ * One call, because a half-registered catalog fails at mount time rather than
23
+ * at boot - and a runtime miss is much harder to read than a boot error.
24
+ */
25
+ export declare function registerBuiltins(app: TextUIApp): Disposable;
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAc/E,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAE1B,sDAAsD;AACtD,eAAO,MAAM,OAAO,EAAE,mBAAmB,EAaxC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,UAAU,CAU3D"}
package/dist/index.js ADDED
@@ -0,0 +1,62 @@
1
+ import { createBag, PRIMITIVES } from '@textui/core';
2
+ import { LAYOUT_COMPONENTS } from './layout/index.js';
3
+ import { DISPLAY_COMPONENTS } from './display/index.js';
4
+ import { CONTROL_COMPONENTS } from './control/index.js';
5
+ import { FORM_COMPONENTS } from './form/index.js';
6
+ import { DATA_COMPONENTS } from './data/index.js';
7
+ import { NAVIGATION_COMPONENTS } from './navigation/index.js';
8
+ import { OVERLAY_COMPONENTS } from './overlay/index.js';
9
+ import { CHART_COMPONENTS } from './chart/index.js';
10
+ import { SURFACE_COMPONENTS, BUILTIN_LAYOUTS } from './surface/index.js';
11
+ import { SHELL_COMPONENTS, BUILTIN_SHELLS } from './shells/index.js';
12
+ import { PANEL_COMPONENTS, panelCommands } from './panel/index.js';
13
+ export * from './layout/index.js';
14
+ export * from './display/index.js';
15
+ export * from './control/index.js';
16
+ export * from './form/index.js';
17
+ export * from './data/index.js';
18
+ export * from './navigation/index.js';
19
+ export * from './overlay/index.js';
20
+ export * from './chart/index.js';
21
+ export * from './surface/index.js';
22
+ export * from './shells/index.js';
23
+ export * from './panel/index.js';
24
+ export * from './decorations.js';
25
+ export * from './find.js';
26
+ export * from './viewport.js';
27
+ export * from './tone.js';
28
+ /** Every component the library ships, in one list. */
29
+ export const CATALOG = [
30
+ ...PRIMITIVES,
31
+ ...LAYOUT_COMPONENTS,
32
+ ...DISPLAY_COMPONENTS,
33
+ ...CONTROL_COMPONENTS,
34
+ ...FORM_COMPONENTS,
35
+ ...DATA_COMPONENTS,
36
+ ...NAVIGATION_COMPONENTS,
37
+ ...OVERLAY_COMPONENTS,
38
+ ...CHART_COMPONENTS,
39
+ ...SURFACE_COMPONENTS,
40
+ ...SHELL_COMPONENTS,
41
+ ...PANEL_COMPONENTS,
42
+ ];
43
+ /**
44
+ * Register the catalog, the surface layouts and the built-in shells.
45
+ *
46
+ * One call, because a half-registered catalog fails at mount time rather than
47
+ * at boot - and a runtime miss is much harder to read than a boot error.
48
+ */
49
+ export function registerBuiltins(app) {
50
+ const bag = createBag();
51
+ bag.add(app.components.registerMany(CATALOG));
52
+ for (const layout of BUILTIN_LAYOUTS)
53
+ bag.add(app.layouts.register(layout));
54
+ for (const shell of BUILTIN_SHELLS)
55
+ bag.add(app.shells.register(shell));
56
+ // The panel commands come with the panel: what they offer is read off the
57
+ // resource registry, so a host that mounts a panel has already said
58
+ // everything "open with" needs. Keys stay the host's choice.
59
+ for (const command of panelCommands(app))
60
+ bag.add(app.commands.register(command));
61
+ return bag;
62
+ }
@@ -0,0 +1,7 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface CenterProps extends BoxProps {
3
+ /** Centre horizontally, vertically, or both. */
4
+ axis?: 'both' | 'horizontal' | 'vertical';
5
+ }
6
+ export declare const Center: (props: CenterProps) => import("@textui/core").RenderOutput;
7
+ //# sourceMappingURL=center.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"center.d.ts","sourceRoot":"","sources":["../../src/layout/center.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC;CAC3C;AAED,eAAO,MAAM,MAAM,6DAQlB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ export const Center = defineComponent('Center', ({ axis = 'both', ...props }) => h('box', {
3
+ flex: props.flex ?? 1,
4
+ direction: 'column',
5
+ justify: axis === 'horizontal' ? 'start' : 'center',
6
+ align: axis === 'vertical' ? 'stretch' : 'center',
7
+ ...props,
8
+ }));
@@ -0,0 +1,3 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export declare const Column: (props: BoxProps) => import("@textui/core").RenderOutput;
3
+ //# sourceMappingURL=column.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column.d.ts","sourceRoot":"","sources":["../../src/layout/column.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,eAAO,MAAM,MAAM,0DAElB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { defineComponent, h } from '@textui/core';
2
+ export const Column = defineComponent('Column', (props) => h('box', { direction: 'column', ...props }));
@@ -0,0 +1,11 @@
1
+ import type { BoxProps } from '@textui/core';
2
+ export interface DividerProps extends Omit<BoxProps, 'direction'> {
3
+ /** A divider runs across the flow, so it names its own axis. */
4
+ direction?: 'horizontal' | 'vertical';
5
+ /** Text set into the rule. */
6
+ label?: string;
7
+ labelAlign?: 'left' | 'center' | 'right';
8
+ char?: string;
9
+ }
10
+ export declare const Divider: (props: DividerProps) => import("@textui/core").RenderOutput;
11
+ //# sourceMappingURL=divider.d.ts.map