@ui-sdk/web 0.0.0-stage → 0.1.0-beta.1

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 (467) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +10 -2
  3. package/browser/web/accordion.js +1 -0
  4. package/browser/web/alert-dialog.js +1 -0
  5. package/browser/web/autocomplete.js +1 -0
  6. package/browser/web/avatar.js +1 -0
  7. package/browser/web/button.js +1 -0
  8. package/browser/web/calendar.js +1 -0
  9. package/browser/web/carousel.js +1 -0
  10. package/browser/web/checkbox.js +1 -0
  11. package/browser/web/chunks/0eRGibL6.js +1 -0
  12. package/browser/web/chunks/2bIEUO6_.js +1 -0
  13. package/browser/web/chunks/5A9w2ULz.js +1 -0
  14. package/browser/web/chunks/5RSyydjV.js +1 -0
  15. package/browser/web/chunks/9pWTy2wl.js +1 -0
  16. package/browser/web/chunks/B0f2j6zz.js +1 -0
  17. package/browser/web/chunks/B1rux6br.js +1 -0
  18. package/browser/web/chunks/B3-APaNf.js +1 -0
  19. package/browser/web/chunks/B7EgSgjQ.js +1 -0
  20. package/browser/web/chunks/B8QcOzJU.js +1 -0
  21. package/browser/web/chunks/BFueEkwm.js +3 -0
  22. package/browser/web/chunks/BJj3oS29.js +1 -0
  23. package/browser/web/chunks/BNSvTCpr.js +1 -0
  24. package/browser/web/chunks/BPD0kAZB.js +1 -0
  25. package/browser/web/chunks/BQeduZqT.js +1 -0
  26. package/browser/web/chunks/B_CVFyiz.js +1 -0
  27. package/browser/web/chunks/B_ns1YHO.js +1 -0
  28. package/browser/web/chunks/BcwkVTsR.js +1 -0
  29. package/browser/web/chunks/BeaQ6TYM.js +1 -0
  30. package/browser/web/chunks/BgBB013u.js +1 -0
  31. package/browser/web/chunks/BgsKhHDm.js +1 -0
  32. package/browser/web/chunks/BjMcbuhi.js +9 -0
  33. package/browser/web/chunks/Bjiy_F2N.js +1 -0
  34. package/browser/web/chunks/BqScCLwv.js +1 -0
  35. package/browser/web/chunks/BqX3Utqx.js +1 -0
  36. package/browser/web/chunks/BtVkQf3z.js +1 -0
  37. package/browser/web/chunks/By30h-7B.js +1 -0
  38. package/browser/web/chunks/C1zqYpy2.js +1 -0
  39. package/browser/web/chunks/C436juFf.js +1 -0
  40. package/browser/web/chunks/C4_bULs1.js +1 -0
  41. package/browser/web/chunks/C4omqJEz.js +1 -0
  42. package/browser/web/chunks/C7tt0T3n.js +1 -0
  43. package/browser/web/chunks/C8w7s5dg.js +1 -0
  44. package/browser/web/chunks/CElY4erO.js +1 -0
  45. package/browser/web/chunks/CFODo-m2.js +1 -0
  46. package/browser/web/chunks/CL4wjam9.js +1 -0
  47. package/browser/web/chunks/CMg-8UVf.js +1 -0
  48. package/browser/web/chunks/COWKfakj.js +1 -0
  49. package/browser/web/chunks/CQBU0qZ4.js +1 -0
  50. package/browser/web/chunks/CV6uABgc.js +1 -0
  51. package/browser/web/chunks/C_SWFpWQ.js +1 -0
  52. package/browser/web/chunks/C_Uanbrl.js +1 -0
  53. package/browser/web/chunks/Ce_CSanC.js +1 -0
  54. package/browser/web/chunks/Cg-ZmRhS.js +1 -0
  55. package/browser/web/chunks/Cgf2wPI_.js +1 -0
  56. package/browser/web/chunks/Cuep_3Vf.js +1 -0
  57. package/browser/web/chunks/D02PaHn6.js +1 -0
  58. package/browser/web/chunks/D5LiaI5R.js +1 -0
  59. package/browser/web/chunks/D9UgVYvF.js +1 -0
  60. package/browser/web/chunks/DC08tnkE.js +2 -0
  61. package/browser/web/chunks/DG8YGSvu.js +1 -0
  62. package/browser/web/chunks/DIQd0FYD.js +1 -0
  63. package/browser/web/chunks/DMLqacE8.js +1 -0
  64. package/browser/web/chunks/DSUI3yI-.js +1 -0
  65. package/browser/web/chunks/DT3Hb76X.js +1 -0
  66. package/browser/web/chunks/DY75g3-W.js +1 -0
  67. package/browser/web/chunks/DZpNQKZ9.js +1 -0
  68. package/browser/web/chunks/Db-W1wrC.js +1 -0
  69. package/browser/web/chunks/Dc1xK3Ii.js +1 -0
  70. package/browser/web/chunks/DdF6awFs.js +1 -0
  71. package/browser/web/chunks/DdaCLml8.js +1 -0
  72. package/browser/web/chunks/Dh8MLjQO.js +1 -0
  73. package/browser/web/chunks/DiuslJRy.js +1 -0
  74. package/browser/web/chunks/DjRcw3Y0.js +1 -0
  75. package/browser/web/chunks/Djdv-16J.js +1 -0
  76. package/browser/web/chunks/DnFXe_lF.js +1 -0
  77. package/browser/web/chunks/DneGv1oC.js +1 -0
  78. package/browser/web/chunks/DsVxP-p-.js +1 -0
  79. package/browser/web/chunks/DwDilCo2.js +1 -0
  80. package/browser/web/chunks/DwV48AXv.js +1 -0
  81. package/browser/web/chunks/F37aF4-L.js +1 -0
  82. package/browser/web/chunks/LyB6XIbN.js +1 -0
  83. package/browser/web/chunks/NKnbYGjC.js +1 -0
  84. package/browser/web/chunks/Vk-rVi16.js +1 -0
  85. package/browser/web/chunks/XsM0J1Ex.js +1 -0
  86. package/browser/web/chunks/asSN9iEp.js +1 -0
  87. package/browser/web/chunks/c-AjHfdF.js +1 -0
  88. package/browser/web/chunks/dR-12TPY.js +1 -0
  89. package/browser/web/chunks/hR4xM0EC.js +1 -0
  90. package/browser/web/chunks/hqOaBxAg.js +1 -0
  91. package/browser/web/chunks/kMKqqeG4.js +1 -0
  92. package/browser/web/chunks/kXboBcfi.js +1 -0
  93. package/browser/web/chunks/l4aQIg22.js +1 -0
  94. package/browser/web/chunks/tJC0JSU4.js +1 -0
  95. package/browser/web/chunks/wHdS_QYM.js +1 -0
  96. package/browser/web/chunks/yv8dTvNI.js +1 -0
  97. package/browser/web/chunks/yw9M3nfi.js +1 -0
  98. package/browser/web/collapsible.js +1 -0
  99. package/browser/web/color-picker.js +1 -0
  100. package/browser/web/combobox.js +2 -0
  101. package/browser/web/command.js +1 -0
  102. package/browser/web/core.js +5 -0
  103. package/browser/web/date-input.js +1 -0
  104. package/browser/web/date-picker.js +1 -0
  105. package/browser/web/dialog.js +1 -0
  106. package/browser/web/drawer.js +1 -0
  107. package/browser/web/field.js +1 -0
  108. package/browser/web/file-input.js +1 -0
  109. package/browser/web/hover-card.js +1 -0
  110. package/browser/web/image-cropper.js +1 -0
  111. package/browser/web/input.js +1 -0
  112. package/browser/web/label.js +1 -0
  113. package/browser/web/listbox.js +1 -0
  114. package/browser/web/menu.js +1 -0
  115. package/browser/web/menubar.js +1 -0
  116. package/browser/web/meter.js +1 -0
  117. package/browser/web/navigation-menu.js +1 -0
  118. package/browser/web/number-input.js +1 -0
  119. package/browser/web/otp-input.js +2 -0
  120. package/browser/web/overlays.js +1 -0
  121. package/browser/web/pagination.js +1 -0
  122. package/browser/web/password-input.js +1 -0
  123. package/browser/web/popover.js +1 -0
  124. package/browser/web/preferences.js +1 -0
  125. package/browser/web/progress.js +1 -0
  126. package/browser/web/radio.js +1 -0
  127. package/browser/web/rating.js +1 -0
  128. package/browser/web/resizable.js +1 -0
  129. package/browser/web/scroll-area.js +1 -0
  130. package/browser/web/segmented-control.js +1 -0
  131. package/browser/web/select.js +1 -0
  132. package/browser/web/separator.js +1 -0
  133. package/browser/web/slider.js +1 -0
  134. package/browser/web/switch.js +1 -0
  135. package/browser/web/tabs.js +1 -0
  136. package/browser/web/textarea.js +1 -0
  137. package/browser/web/time-input.js +1 -0
  138. package/browser/web/timeline.js +1 -0
  139. package/browser/web/toast.js +1 -0
  140. package/browser/web/toggle.js +1 -0
  141. package/browser/web/token-input.js +8 -0
  142. package/browser/web/toolbar.js +1 -0
  143. package/browser/web/tooltip.js +1 -0
  144. package/browser/web/tree.js +1 -0
  145. package/browser/web/trigger-menu.js +4 -0
  146. package/browser/web/waterfall.js +1 -0
  147. package/browser/web.css +3378 -0
  148. package/browser/web.js +3 -0
  149. package/custom-elements.json +32315 -0
  150. package/dist/accordion.d.ts +2 -0
  151. package/dist/accordion.js +57 -0
  152. package/dist/action.d.ts +16 -0
  153. package/dist/action.js +39 -0
  154. package/dist/agent.d.ts +2 -0
  155. package/dist/agent.js +7 -0
  156. package/dist/autocomplete.d.ts +2 -0
  157. package/dist/autocomplete.js +120 -0
  158. package/dist/autoload.d.ts +18 -0
  159. package/dist/autoload.js +63 -0
  160. package/dist/avatar.d.ts +2 -0
  161. package/dist/avatar.js +27 -0
  162. package/dist/browser-core.d.ts +2 -0
  163. package/dist/browser-core.js +8 -0
  164. package/dist/button.d.ts +2 -0
  165. package/dist/button.js +35 -0
  166. package/dist/calendar.d.ts +23 -0
  167. package/dist/calendar.js +429 -0
  168. package/dist/carousel.d.ts +2 -0
  169. package/dist/carousel.js +54 -0
  170. package/dist/checkbox.d.ts +4 -0
  171. package/dist/checkbox.js +75 -0
  172. package/dist/collapsible.d.ts +2 -0
  173. package/dist/collapsible.js +28 -0
  174. package/dist/color-picker.d.ts +2 -0
  175. package/dist/color-picker.js +64 -0
  176. package/dist/combobox.d.ts +2 -0
  177. package/dist/combobox.js +334 -0
  178. package/dist/command.d.ts +2 -0
  179. package/dist/command.js +122 -0
  180. package/dist/date-input.d.ts +3 -0
  181. package/dist/date-input.js +87 -0
  182. package/dist/date-picker.d.ts +2 -0
  183. package/dist/date-picker.js +174 -0
  184. package/dist/default-text.d.ts +3 -0
  185. package/dist/default-text.js +24 -0
  186. package/dist/define-element.d.ts +404 -0
  187. package/dist/define-element.js +1489 -0
  188. package/dist/dialog.d.ts +3 -0
  189. package/dist/dialog.js +94 -0
  190. package/dist/drawer.d.ts +2 -0
  191. package/dist/drawer.js +96 -0
  192. package/dist/entries/accordion.d.ts +3 -0
  193. package/dist/entries/accordion.js +7 -0
  194. package/dist/entries/alert-dialog.d.ts +3 -0
  195. package/dist/entries/alert-dialog.js +13 -0
  196. package/dist/entries/autocomplete.d.ts +3 -0
  197. package/dist/entries/autocomplete.js +7 -0
  198. package/dist/entries/avatar.d.ts +2 -0
  199. package/dist/entries/avatar.js +3 -0
  200. package/dist/entries/button.d.ts +2 -0
  201. package/dist/entries/button.js +3 -0
  202. package/dist/entries/calendar.d.ts +3 -0
  203. package/dist/entries/calendar.js +7 -0
  204. package/dist/entries/carousel.d.ts +3 -0
  205. package/dist/entries/carousel.js +7 -0
  206. package/dist/entries/checkbox.d.ts +3 -0
  207. package/dist/entries/checkbox.js +15 -0
  208. package/dist/entries/collapsible.d.ts +3 -0
  209. package/dist/entries/collapsible.js +7 -0
  210. package/dist/entries/color-picker.d.ts +3 -0
  211. package/dist/entries/color-picker.js +7 -0
  212. package/dist/entries/combobox.d.ts +3 -0
  213. package/dist/entries/combobox.js +7 -0
  214. package/dist/entries/command.d.ts +3 -0
  215. package/dist/entries/command.js +7 -0
  216. package/dist/entries/date-input.d.ts +3 -0
  217. package/dist/entries/date-input.js +7 -0
  218. package/dist/entries/date-picker.d.ts +3 -0
  219. package/dist/entries/date-picker.js +7 -0
  220. package/dist/entries/dialog.d.ts +3 -0
  221. package/dist/entries/dialog.js +7 -0
  222. package/dist/entries/drawer.d.ts +3 -0
  223. package/dist/entries/drawer.js +8 -0
  224. package/dist/entries/field.d.ts +2 -0
  225. package/dist/entries/field.js +3 -0
  226. package/dist/entries/file-input.d.ts +3 -0
  227. package/dist/entries/file-input.js +13 -0
  228. package/dist/entries/hover-card.d.ts +3 -0
  229. package/dist/entries/hover-card.js +7 -0
  230. package/dist/entries/image-cropper.d.ts +3 -0
  231. package/dist/entries/image-cropper.js +7 -0
  232. package/dist/entries/input.d.ts +3 -0
  233. package/dist/entries/input.js +8 -0
  234. package/dist/entries/label.d.ts +2 -0
  235. package/dist/entries/label.js +3 -0
  236. package/dist/entries/listbox.d.ts +3 -0
  237. package/dist/entries/listbox.js +7 -0
  238. package/dist/entries/menu.d.ts +3 -0
  239. package/dist/entries/menu.js +7 -0
  240. package/dist/entries/menubar.d.ts +3 -0
  241. package/dist/entries/menubar.js +7 -0
  242. package/dist/entries/meter.d.ts +2 -0
  243. package/dist/entries/meter.js +3 -0
  244. package/dist/entries/navigation-menu.d.ts +3 -0
  245. package/dist/entries/navigation-menu.js +7 -0
  246. package/dist/entries/number-input.d.ts +3 -0
  247. package/dist/entries/number-input.js +7 -0
  248. package/dist/entries/otp-input.d.ts +3 -0
  249. package/dist/entries/otp-input.js +7 -0
  250. package/dist/entries/overlays.d.ts +2 -0
  251. package/dist/entries/overlays.js +3 -0
  252. package/dist/entries/pagination.d.ts +3 -0
  253. package/dist/entries/pagination.js +11 -0
  254. package/dist/entries/password-input.d.ts +3 -0
  255. package/dist/entries/password-input.js +7 -0
  256. package/dist/entries/popover.d.ts +3 -0
  257. package/dist/entries/popover.js +7 -0
  258. package/dist/entries/preferences.d.ts +3 -0
  259. package/dist/entries/preferences.js +13 -0
  260. package/dist/entries/progress.d.ts +2 -0
  261. package/dist/entries/progress.js +3 -0
  262. package/dist/entries/radio.d.ts +3 -0
  263. package/dist/entries/radio.js +7 -0
  264. package/dist/entries/rating.d.ts +3 -0
  265. package/dist/entries/rating.js +8 -0
  266. package/dist/entries/resizable.d.ts +3 -0
  267. package/dist/entries/resizable.js +11 -0
  268. package/dist/entries/scroll-area.d.ts +3 -0
  269. package/dist/entries/scroll-area.js +7 -0
  270. package/dist/entries/segmented-control.d.ts +3 -0
  271. package/dist/entries/segmented-control.js +7 -0
  272. package/dist/entries/select.d.ts +3 -0
  273. package/dist/entries/select.js +7 -0
  274. package/dist/entries/separator.d.ts +2 -0
  275. package/dist/entries/separator.js +3 -0
  276. package/dist/entries/slider.d.ts +3 -0
  277. package/dist/entries/slider.js +7 -0
  278. package/dist/entries/switch.d.ts +3 -0
  279. package/dist/entries/switch.js +7 -0
  280. package/dist/entries/tabs.d.ts +3 -0
  281. package/dist/entries/tabs.js +7 -0
  282. package/dist/entries/textarea.d.ts +3 -0
  283. package/dist/entries/textarea.js +7 -0
  284. package/dist/entries/time-input.d.ts +3 -0
  285. package/dist/entries/time-input.js +7 -0
  286. package/dist/entries/timeline.d.ts +3 -0
  287. package/dist/entries/timeline.js +7 -0
  288. package/dist/entries/toast.d.ts +2 -0
  289. package/dist/entries/toast.js +3 -0
  290. package/dist/entries/toggle.d.ts +3 -0
  291. package/dist/entries/toggle.js +12 -0
  292. package/dist/entries/token-input.d.ts +3 -0
  293. package/dist/entries/token-input.js +17 -0
  294. package/dist/entries/toolbar.d.ts +3 -0
  295. package/dist/entries/toolbar.js +7 -0
  296. package/dist/entries/tooltip.d.ts +3 -0
  297. package/dist/entries/tooltip.js +7 -0
  298. package/dist/entries/tree.d.ts +3 -0
  299. package/dist/entries/tree.js +17 -0
  300. package/dist/entries/trigger-menu.d.ts +3 -0
  301. package/dist/entries/trigger-menu.js +11 -0
  302. package/dist/entries/waterfall.d.ts +3 -0
  303. package/dist/entries/waterfall.js +11 -0
  304. package/dist/events.d.ts +1658 -0
  305. package/dist/events.js +0 -0
  306. package/dist/field.d.ts +2 -0
  307. package/dist/field.js +101 -0
  308. package/dist/file-input.d.ts +2 -0
  309. package/dist/file-input.js +140 -0
  310. package/dist/forward-attributes.d.ts +2 -0
  311. package/dist/forward-attributes.js +22 -0
  312. package/dist/history.d.ts +2 -0
  313. package/dist/history.js +11 -0
  314. package/dist/hover-card.d.ts +2 -0
  315. package/dist/hover-card.js +31 -0
  316. package/dist/image-cropper.d.ts +2 -0
  317. package/dist/image-cropper.js +66 -0
  318. package/dist/index.d.ts +66 -0
  319. package/dist/index.js +269 -0
  320. package/dist/input.d.ts +3 -0
  321. package/dist/input.js +69 -0
  322. package/dist/label.d.ts +2 -0
  323. package/dist/label.js +11 -0
  324. package/dist/list.d.ts +40 -0
  325. package/dist/list.js +192 -0
  326. package/dist/listbox.d.ts +2 -0
  327. package/dist/listbox.js +84 -0
  328. package/dist/menu.d.ts +4 -0
  329. package/dist/menu.js +295 -0
  330. package/dist/menubar.d.ts +4 -0
  331. package/dist/menubar.js +30 -0
  332. package/dist/meter.d.ts +2 -0
  333. package/dist/meter.js +22 -0
  334. package/dist/navigation-menu.d.ts +2 -0
  335. package/dist/navigation-menu.js +114 -0
  336. package/dist/number-input.d.ts +2 -0
  337. package/dist/number-input.js +73 -0
  338. package/dist/observe.d.ts +2 -0
  339. package/dist/observe.js +7 -0
  340. package/dist/otp-input.d.ts +2 -0
  341. package/dist/otp-input.js +72 -0
  342. package/dist/overlays.d.ts +13 -0
  343. package/dist/overlays.js +156 -0
  344. package/dist/pagination.d.ts +2 -0
  345. package/dist/pagination.js +127 -0
  346. package/dist/password-input.d.ts +2 -0
  347. package/dist/password-input.js +57 -0
  348. package/dist/popover.d.ts +2 -0
  349. package/dist/popover.js +64 -0
  350. package/dist/popup.d.ts +40 -0
  351. package/dist/popup.js +112 -0
  352. package/dist/preferences.d.ts +2 -0
  353. package/dist/preferences.js +56 -0
  354. package/dist/progress.d.ts +2 -0
  355. package/dist/progress.js +22 -0
  356. package/dist/radio.d.ts +2 -0
  357. package/dist/radio.js +33 -0
  358. package/dist/rating.d.ts +2 -0
  359. package/dist/rating.js +64 -0
  360. package/dist/resizable.d.ts +2 -0
  361. package/dist/resizable.js +42 -0
  362. package/dist/scroll-area.d.ts +2 -0
  363. package/dist/scroll-area.js +45 -0
  364. package/dist/segmented-control.d.ts +2 -0
  365. package/dist/segmented-control.js +28 -0
  366. package/dist/select.d.ts +2 -0
  367. package/dist/select.js +239 -0
  368. package/dist/separator.d.ts +2 -0
  369. package/dist/separator.js +11 -0
  370. package/dist/slider.d.ts +2 -0
  371. package/dist/slider.js +77 -0
  372. package/dist/tabs.d.ts +2 -0
  373. package/dist/tabs.js +37 -0
  374. package/dist/timeline.d.ts +2 -0
  375. package/dist/timeline.js +27 -0
  376. package/dist/toast.d.ts +20 -0
  377. package/dist/toast.js +177 -0
  378. package/dist/toggle.d.ts +3 -0
  379. package/dist/toggle.js +64 -0
  380. package/dist/token-input.d.ts +2 -0
  381. package/dist/token-input.js +103 -0
  382. package/dist/toolbar.d.ts +2 -0
  383. package/dist/toolbar.js +36 -0
  384. package/dist/tooltip.d.ts +2 -0
  385. package/dist/tooltip.js +35 -0
  386. package/dist/tree.d.ts +2 -0
  387. package/dist/tree.js +147 -0
  388. package/dist/trigger-menu.d.ts +2 -0
  389. package/dist/trigger-menu.js +133 -0
  390. package/dist/waterfall.d.ts +2 -0
  391. package/dist/waterfall.js +140 -0
  392. package/docs/README.md +89 -0
  393. package/docs/agents.md +1523 -0
  394. package/docs/components/accordion.md +1401 -0
  395. package/docs/components/alert-dialog.md +788 -0
  396. package/docs/components/autocomplete.md +1692 -0
  397. package/docs/components/avatar.md +261 -0
  398. package/docs/components/button.md +441 -0
  399. package/docs/components/calendar.md +1536 -0
  400. package/docs/components/carousel.md +1055 -0
  401. package/docs/components/checkbox.md +1045 -0
  402. package/docs/components/collapsible.md +535 -0
  403. package/docs/components/color-picker.md +651 -0
  404. package/docs/components/combobox.md +3274 -0
  405. package/docs/components/command.md +1431 -0
  406. package/docs/components/date-input.md +563 -0
  407. package/docs/components/date-picker.md +1136 -0
  408. package/docs/components/dialog.md +1360 -0
  409. package/docs/components/drawer.md +1201 -0
  410. package/docs/components/field.md +519 -0
  411. package/docs/components/file-input.md +617 -0
  412. package/docs/components/hover-card.md +486 -0
  413. package/docs/components/image-cropper.md +489 -0
  414. package/docs/components/input.md +327 -0
  415. package/docs/components/label.md +208 -0
  416. package/docs/components/listbox.md +1015 -0
  417. package/docs/components/menu.md +1212 -0
  418. package/docs/components/menubar.md +460 -0
  419. package/docs/components/meter.md +298 -0
  420. package/docs/components/navigation-menu.md +1573 -0
  421. package/docs/components/number-input.md +1087 -0
  422. package/docs/components/otp-input.md +558 -0
  423. package/docs/components/pagination.md +639 -0
  424. package/docs/components/password-input.md +649 -0
  425. package/docs/components/popover.md +1433 -0
  426. package/docs/components/preferences.md +243 -0
  427. package/docs/components/progress.md +406 -0
  428. package/docs/components/radio.md +855 -0
  429. package/docs/components/rating.md +431 -0
  430. package/docs/components/resizable.md +866 -0
  431. package/docs/components/scroll-area.md +898 -0
  432. package/docs/components/segmented-control.md +421 -0
  433. package/docs/components/select.md +1957 -0
  434. package/docs/components/separator.md +238 -0
  435. package/docs/components/slider.md +1018 -0
  436. package/docs/components/switch.md +583 -0
  437. package/docs/components/tabs.md +948 -0
  438. package/docs/components/textarea.md +331 -0
  439. package/docs/components/time-input.md +235 -0
  440. package/docs/components/timeline.md +622 -0
  441. package/docs/components/toast.md +1223 -0
  442. package/docs/components/toggle.md +522 -0
  443. package/docs/components/token-input.md +854 -0
  444. package/docs/components/toolbar.md +815 -0
  445. package/docs/components/tooltip.md +860 -0
  446. package/docs/components/tree.md +1243 -0
  447. package/docs/components/trigger-menu.md +1110 -0
  448. package/docs/components/waterfall.md +709 -0
  449. package/docs/controllers.md +66 -0
  450. package/docs/core.md +8027 -0
  451. package/docs/custom-parts.md +91 -0
  452. package/docs/first-component.md +88 -0
  453. package/docs/forms.md +125 -0
  454. package/docs/installation.md +141 -0
  455. package/docs/introduction.md +32 -0
  456. package/docs/lists-and-menus.md +166 -0
  457. package/docs/llms.txt +1566 -0
  458. package/docs/parts-and-composition.md +57 -0
  459. package/docs/popups.md +92 -0
  460. package/docs/rendering.md +71 -0
  461. package/docs/server-rendering.md +118 -0
  462. package/docs/state-and-events.md +134 -0
  463. package/docs/styling-and-animation.md +104 -0
  464. package/docs/utilities/async-options.md +332 -0
  465. package/docs/utilities/shortcuts.md +184 -0
  466. package/html-custom-data.json +14792 -0
  467. package/package.json +302 -3
@@ -0,0 +1,854 @@
1
+ # Token Input
2
+
3
+ Mix editable text with tokens for files, people, tags, and other references.
4
+
5
+ A token input is a text field that holds tokens alongside the text, like the people mentioned in a message or the files attached to a prompt. Each token moves, deletes and copies as one piece.
6
+
7
+ ```ts title="demo.ts"
8
+ import "@ui-sdk/web/token-input"
9
+ import "@ui-sdk/web/trigger-menu"
10
+ import "@ui-sdk/web/field"
11
+ import { createElement, X } from "lucide"
12
+
13
+ const people = [
14
+ { value: "hollis", label: "Hollis Grant" },
15
+ { value: "ines", label: "Inès Moreau" },
16
+ { value: "kofi", label: "Kofi Mensah" },
17
+ { value: "wren", label: "Wren Takahashi" },
18
+ { value: "tomasz", label: "Tomasz Wójcik" },
19
+ ]
20
+
21
+ function mount(root: HTMLElement) {
22
+ root.innerHTML = `
23
+ <ui-field>
24
+ <ui-field-label>Message</ui-field-label>
25
+ <ui-token-input>
26
+ <ui-token-input-editor placeholder="Type @ to mention someone…"></ui-token-input-editor>
27
+ <template>
28
+ <ui-token-input-token>
29
+ <span data-token-label></span>
30
+ <ui-token-input-token-remove>${createElement(X, { "aria-hidden": "true" }).outerHTML}</ui-token-input-token-remove>
31
+ </ui-token-input-token>
32
+ </template>
33
+ <ui-trigger-menu>
34
+ <ui-trigger-menu-content>
35
+ <ui-trigger-menu-list></ui-trigger-menu-list>
36
+ </ui-trigger-menu-content>
37
+ </ui-trigger-menu>
38
+ </ui-token-input>
39
+ </ui-field>
40
+ `
41
+ root.querySelector("ui-trigger-menu")!.triggers = [
42
+ { char: "@", type: "mention", items: people },
43
+ ]
44
+ }
45
+
46
+ export { mount }
47
+ ```
48
+
49
+ Type @ and choose a person with the arrow keys and Enter. Remove a token with Backspace, or press its remove button.
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ npm install @ui-sdk/web @ui-sdk/core
55
+ ```
56
+
57
+ Importing the component defines its elements. Import the trigger menu and the field too if you use them. On the server the import does nothing.
58
+
59
+ ```ts
60
+ import "@ui-sdk/web/token-input"
61
+ import "@ui-sdk/web/trigger-menu"
62
+ import "@ui-sdk/web/field"
63
+ ```
64
+
65
+ ## Composition
66
+
67
+ Use the following composition to build a `ui-token-input`:
68
+
69
+ ```text
70
+ ui-token-input
71
+ ├── ui-token-input-editor
72
+ └── ui-trigger-menu
73
+ ```
74
+
75
+ And for each token, inside a `<template>`:
76
+
77
+ ```text
78
+ ui-token-input-token
79
+ └── ui-token-input-token-remove
80
+ ```
81
+
82
+ `ui-token-input` holds the value, and `ui-token-input-editor` is the text people edit. A [Trigger Menu](./trigger-menu.md) inside it suggests tokens when someone types `@`, `/`, or another trigger. Put a `<template>` inside it, or set its `renderToken` property, to give each token your own markup.
83
+
84
+ ## Usage
85
+
86
+ Import the parts and put them together:
87
+
88
+ ```html
89
+ <script type="module">
90
+ import "@ui-sdk/web/token-input"
91
+ </script>
92
+
93
+ <ui-token-input value="Explain [@routes.ts](file:src/routes.ts)">
94
+ <ui-token-input-editor aria-label="Prompt"></ui-token-input-editor>
95
+ </ui-token-input>
96
+ ```
97
+
98
+ A value is an array of text and tokens. Each token has a type, a value for your app, and a label for the reader. The `value` attribute writes it as codec text; set the `defaultValue` property before the element connects to pass an array instead. The editor manages its own content, including tokens, selection, and undo, so let it render that content and use a `<template>` or `renderToken` for custom token markup.
99
+
100
+ ## Token Input or Trigger Menu
101
+
102
+ Token Input holds the text and tokens. [Trigger Menu](./trigger-menu.md) suggests what to insert when someone types a trigger character.
103
+
104
+ Use Token Input on its own when your code supplies the tokens. Add a Trigger Menu for suggestions, as in the demo above. Trigger Menu also works with ordinary inputs and textareas.
105
+
106
+ ## Prompt Input
107
+
108
+ Combine file suggestions, skills, and a send action. This example marks files as pending while they load, then uses `updateToken()` to show a skill running. Enter sends; Shift+Enter adds a line. An open suggestion menu or an active input method takes precedence over sending. Enter submits the form the input is in, so the send button is that form's submit button.
109
+
110
+ ```ts title="prompt-input.ts"
111
+ import "@ui-sdk/web/trigger-menu"
112
+ import { toText, type Token } from "@ui-sdk/web/token-input"
113
+ import { ArrowUp, Check, Clock, Code, createElement, File, X } from "lucide"
114
+ import { log } from "./log"
115
+
116
+ const files = [
117
+ { value: "src/app.tsx", label: "app.tsx", keywords: ["src"] },
118
+ { value: "src/routes.ts", label: "routes.ts", keywords: ["src"] },
119
+ { value: "src/styles.css", label: "styles.css", keywords: ["src"] },
120
+ { value: "README.md", label: "README.md" },
121
+ { value: "package.json", label: "package.json" },
122
+ ]
123
+
124
+ const skills = [
125
+ {
126
+ value: "search",
127
+ label: "search",
128
+ arguments: [{ name: "query", hint: "<query>", required: true }],
129
+ },
130
+ { value: "review", label: "review" },
131
+ { value: "summarize", label: "summarize" },
132
+ ]
133
+
134
+ const loadFile = () => new Promise<void>((resolve) => setTimeout(resolve, 800))
135
+
136
+ function mount(root: HTMLElement) {
137
+ root.innerHTML = `
138
+ <form>
139
+ <ui-token-input>
140
+ <div data-slot="card">
141
+ <ui-token-input-editor aria-label="Prompt" placeholder="Ask anything. Type @ or /"></ui-token-input-editor>
142
+ <div data-slot="row">
143
+ <button type="button" data-size="sm">Attach README</button>
144
+ <button type="submit" data-variant="solid" data-size="sm" data-shape="round" aria-label="Send">
145
+ ${createElement(ArrowUp, { "aria-hidden": "true" }).outerHTML}
146
+ </button>
147
+ </div>
148
+ </div>
149
+ <ui-trigger-menu>
150
+ <ui-trigger-menu-hint></ui-trigger-menu-hint>
151
+ <ui-trigger-menu-content>
152
+ <ui-trigger-menu-empty>No matches</ui-trigger-menu-empty>
153
+ <ui-trigger-menu-list></ui-trigger-menu-list>
154
+ </ui-trigger-menu-content>
155
+ </ui-trigger-menu>
156
+ </ui-token-input>
157
+ </form>
158
+ `
159
+ const input = root.querySelector("ui-token-input")!
160
+ const prompt = input.api
161
+ const menu = root.querySelector("ui-trigger-menu")!
162
+ const [attach, send] = root.querySelectorAll("button")
163
+ let running = false
164
+ let sendTimer: ReturnType<typeof setTimeout> | undefined
165
+
166
+ input.renderToken = (token, host) => {
167
+ host.innerHTML = `
168
+ <ui-token-input-token>
169
+ ${createElement(token.type === "skill" ? Code : File, { "aria-hidden": "true" }).outerHTML}
170
+ <span></span>
171
+ ${token.data?.run === "running" ? createElement(Clock, { "aria-hidden": "true" }).outerHTML : ""}
172
+ ${token.data?.run === "done" ? createElement(Check, { "aria-hidden": "true" }).outerHTML : ""}
173
+ <ui-token-input-token-remove>${createElement(X, { "aria-hidden": "true" }).outerHTML}</ui-token-input-token-remove>
174
+ </ui-token-input-token>
175
+ `
176
+ host.querySelector("span")!.textContent =
177
+ token.type === "skill" ? `/${token.label}` : token.label
178
+ }
179
+ menu.triggers = [
180
+ { char: "@", type: "file", items: files },
181
+ { char: "/", boundary: "start", type: "skill", items: skills },
182
+ ]
183
+ menu.addEventListener("itemselect", (event) => {
184
+ if (event.detail.trigger === "@") {
185
+ event.detail.waitUntil(loadFile())
186
+ }
187
+ })
188
+
189
+ const setRunning = (next: boolean) => {
190
+ running = next
191
+ send.disabled = next
192
+ send.setAttribute("aria-label", next ? "Running" : "Send")
193
+ send.innerHTML = createElement(next ? Clock : ArrowUp, {
194
+ "aria-hidden": "true",
195
+ }).outerHTML
196
+ }
197
+
198
+ attach.addEventListener("mousedown", (event) => event.preventDefault())
199
+ attach.addEventListener("click", () =>
200
+ prompt.insert(
201
+ { type: "file", value: "README.md", label: "README.md" },
202
+ { resolve: loadFile() }
203
+ )
204
+ )
205
+ root.querySelector("form")!.addEventListener("submit", (event) => {
206
+ event.preventDefault()
207
+ if (running || !prompt.getLabel().trim()) {
208
+ return
209
+ }
210
+ setRunning(true)
211
+ const skillTokens = prompt
212
+ .getValue()
213
+ .filter(
214
+ (segment): segment is Token =>
215
+ typeof segment !== "string" && segment.type === "skill"
216
+ )
217
+ for (const skill of skillTokens) {
218
+ prompt.updateToken(skill.id!, { data: { ...skill.data, run: "running" } })
219
+ }
220
+ sendTimer = setTimeout(() => {
221
+ for (const skill of skillTokens) {
222
+ prompt.updateToken(skill.id!, { data: { ...skill.data, run: "done" } })
223
+ }
224
+ log(root, `Sent ${toText(prompt.getValue())}`)
225
+ prompt.clear()
226
+ setRunning(false)
227
+ }, 1500)
228
+ })
229
+
230
+ return () => clearTimeout(sendTimer)
231
+ }
232
+
233
+ export { mount }
234
+ ```
235
+
236
+ Type @ for files or / at the start for skills. For /search, enter a query and press Enter to insert the command. Press Enter again to send, and the console logs the message.
237
+
238
+ ## Deleting Tokens
239
+
240
+ Choose what Backspace does at a token with `token-deletion`:
241
+
242
+ - `whole` removes the token in one press.
243
+ - `select` selects it first, then removes it on the next press.
244
+ - `revert` turns it back into editable text, so the trigger menu opens on it again.
245
+
246
+ ```ts title="deletion.ts"
247
+ import "@ui-sdk/web/token-input"
248
+ import "@ui-sdk/web/select"
249
+ import "@ui-sdk/web/trigger-menu"
250
+ import "@ui-sdk/web/field"
251
+ import type { TokenDeletion, TokenInputValue } from "@ui-sdk/web/token-input"
252
+ import { Check, ChevronDown, createElement, File } from "lucide"
253
+ import { log } from "./log"
254
+
255
+ const modes = [
256
+ { value: "whole", label: "Whole" },
257
+ { value: "select", label: "Select" },
258
+ { value: "revert", label: "Revert" },
259
+ ]
260
+
261
+ const files = [
262
+ { value: "src/app.tsx", label: "app.tsx", keywords: ["src"] },
263
+ { value: "src/routes.ts", label: "routes.ts", keywords: ["src"] },
264
+ { value: "src/styles.css", label: "styles.css", keywords: ["src"] },
265
+ { value: "README.md", label: "README.md" },
266
+ { value: "package.json", label: "package.json" },
267
+ ]
268
+
269
+ const draft: TokenInputValue = [
270
+ "Explain ",
271
+ {
272
+ type: "file",
273
+ value: "src/routes.ts",
274
+ label: "routes.ts",
275
+ data: { trigger: "@" },
276
+ },
277
+ " in two sentences.",
278
+ ]
279
+
280
+ function mount(root: HTMLElement) {
281
+ root.innerHTML = `
282
+ <div data-slot="stack">
283
+ <div data-slot="controls">
284
+ <ui-select default-value="whole">
285
+ <ui-select-label>Backspace</ui-select-label>
286
+ <ui-select-trigger>
287
+ <button>
288
+ <ui-select-value></ui-select-value>
289
+ ${createElement(ChevronDown, { "aria-hidden": "true" }).outerHTML}
290
+ </button>
291
+ </ui-select-trigger>
292
+ <ui-select-content>
293
+ ${modes
294
+ .map(
295
+ (mode) => `
296
+ <ui-select-item value="${mode.value}">
297
+ ${mode.label}
298
+ <ui-select-item-indicator>${createElement(Check, { "aria-hidden": "true" }).outerHTML}</ui-select-item-indicator>
299
+ </ui-select-item>
300
+ `
301
+ )
302
+ .join("")}
303
+ </ui-select-content>
304
+ </ui-select>
305
+ </div>
306
+ <ui-field>
307
+ <ui-field-label>Prompt</ui-field-label>
308
+ </ui-field>
309
+ </div>
310
+ `
311
+ const prompt = document.createElement("ui-token-input")
312
+ prompt.tokenDeletion = "whole"
313
+ prompt.defaultValue = draft
314
+ prompt.innerHTML = `
315
+ <ui-token-input-editor></ui-token-input-editor>
316
+ <template>
317
+ <ui-token-input-token>
318
+ ${createElement(File, { "aria-hidden": "true" }).outerHTML}
319
+ <span data-token-label></span>
320
+ </ui-token-input-token>
321
+ </template>
322
+ <ui-trigger-menu>
323
+ <ui-trigger-menu-content>
324
+ <ui-trigger-menu-list></ui-trigger-menu-list>
325
+ </ui-trigger-menu-content>
326
+ </ui-trigger-menu>
327
+ `
328
+ root.querySelector("ui-field")!.append(prompt)
329
+ root.querySelector("ui-trigger-menu")!.triggers = [
330
+ { char: "@", type: "file", items: files },
331
+ ]
332
+ root.querySelector("ui-select")!.addEventListener("valuechange", (event) => {
333
+ if (event.detail.value) {
334
+ prompt.tokenDeletion = event.detail.value as TokenDeletion
335
+ }
336
+ })
337
+ prompt.addEventListener("valuechange", (event) => {
338
+ for (const token of event.detail.removed) {
339
+ log(root, `Removed ${token.label} (${prompt.tokenDeletion})`)
340
+ }
341
+ })
342
+ }
343
+
344
+ export { mount }
345
+ ```
346
+
347
+ Choose a Backspace behavior, click just after routes.ts, and press Backspace. Undo to try another behavior.
348
+
349
+ ## Codec
350
+
351
+ A codec converts tokens to text for the clipboard, forms, and saved drafts. The default writes `[@label](type:value)`. Copy that text into another app and paste it back to restore the token.
352
+
353
+ Use `toText`, `fromText`, and `toLabel` to convert values yourself. Set the `codec` property for another format, as this example does for `<@hollis>`. With `copy="label"`, copying writes what people read, and pasting back into a token input still restores the tokens. The default parser accepts letters, digits, `_`, and `-` in token types; other types need a custom codec. The `value` attribute reads with the default codec, so set `codec` and `defaultValue` before the element connects.
354
+
355
+ ```ts title="codec.ts"
356
+ import "@ui-sdk/web/field"
357
+ import { fromText, toText, type TokenCodec } from "@ui-sdk/web/token-input"
358
+ import { log } from "./log"
359
+
360
+ const chat: TokenCodec = {
361
+ format: (token) => `<@${token.value}>`,
362
+ parse: (text) =>
363
+ text.split(/(<@[\w.-]+>)/).map((part) => {
364
+ const id = /^<@([\w.-]+)>$/.exec(part)?.[1]
365
+ return id ? { type: "mention", value: id, label: `@${id}` } : part
366
+ }),
367
+ }
368
+
369
+ const draft = fromText("Ping <@hollis> and <@ines> about the launch", chat)
370
+
371
+ function mount(root: HTMLElement) {
372
+ root.innerHTML = `
373
+ <ui-field>
374
+ <ui-field-label>Message</ui-field-label>
375
+ </ui-field>
376
+ `
377
+ const message = document.createElement("ui-token-input")
378
+ message.codec = chat
379
+ message.setAttribute("copy", "label")
380
+ message.defaultValue = draft
381
+ message.innerHTML = `<ui-token-input-editor></ui-token-input-editor>`
382
+ message.addEventListener("valuechange", (event) =>
383
+ log(root, toText(event.detail.value, chat))
384
+ )
385
+ root.querySelector("ui-field")!.append(message)
386
+ }
387
+
388
+ export { mount }
389
+ ```
390
+
391
+ Edit the message. The console logs it in the custom format, with each mention as <@id>.
392
+
393
+ ## Form
394
+
395
+ Give the input a `name` to submit its serialized text. `required`, `disabled`, and `read-only` control form behavior. The `form` attribute associates it with a form elsewhere on the page, as shown here.
396
+
397
+ ```ts title="form.ts"
398
+ import "@ui-sdk/web/checkbox"
399
+ import "@ui-sdk/web/field"
400
+ import { toText, type TokenInputValue } from "@ui-sdk/web/token-input"
401
+ import { Check, createElement } from "lucide"
402
+ import { log } from "./log"
403
+
404
+ const draft: TokenInputValue = [
405
+ "Explain ",
406
+ { type: "file", value: "src/routes.ts", label: "routes.ts" },
407
+ " in two sentences.",
408
+ ]
409
+
410
+ function mount(root: HTMLElement) {
411
+ const formId = crypto.randomUUID()
412
+ root.innerHTML = `
413
+ <div data-slot="stack">
414
+ <div data-slot="controls">
415
+ <label data-slot="label">
416
+ <ui-checkbox>
417
+ <ui-checkbox-indicator>${createElement(Check, { "aria-hidden": "true" }).outerHTML}</ui-checkbox-indicator>
418
+ </ui-checkbox>
419
+ Disabled
420
+ </label>
421
+ <label data-slot="label">
422
+ <ui-checkbox>
423
+ <ui-checkbox-indicator>${createElement(Check, { "aria-hidden": "true" }).outerHTML}</ui-checkbox-indicator>
424
+ </ui-checkbox>
425
+ Read-only
426
+ </label>
427
+ </div>
428
+ <div data-slot="stack">
429
+ <ui-field>
430
+ <ui-field-label>Prompt</ui-field-label>
431
+ <ui-token-input form="${formId}" name="prompt" required value="${toText(draft)}">
432
+ <ui-token-input-editor></ui-token-input-editor>
433
+ </ui-token-input>
434
+ </ui-field>
435
+ <form id="${formId}" data-slot="row">
436
+ <button type="submit" data-variant="solid">Submit</button>
437
+ <button type="reset">Reset</button>
438
+ </form>
439
+ </div>
440
+ </div>
441
+ `
442
+ const field = root.querySelector("ui-field")!
443
+ const prompt = root.querySelector("ui-token-input")!
444
+ const [disabled, readOnly] = root.querySelectorAll("ui-checkbox")
445
+ disabled.addEventListener("checkedchange", (event) => {
446
+ field.toggleAttribute("disabled", event.detail.value === true)
447
+ })
448
+ readOnly.addEventListener("checkedchange", (event) => {
449
+ prompt.toggleAttribute("read-only", event.detail.value === true)
450
+ })
451
+ const form = root.querySelector("form")!
452
+ form.addEventListener("submit", (event) => {
453
+ event.preventDefault()
454
+ log(root, `Submitted ${new FormData(form).get("prompt") ?? ""}`)
455
+ })
456
+ }
457
+
458
+ export { mount }
459
+ ```
460
+
461
+ Press Submit to log the prompt's serialized value. Try Disabled and Read-only, then Reset.
462
+
463
+ ## Controlled
464
+
465
+ Set the `value` attribute or property, and listen for `valuechange`. The event's detail includes the reason, input type, and removed tokens. The input still manages its editing history.
466
+
467
+ ```ts title="controlled.ts"
468
+ import "@ui-sdk/web/trigger-menu"
469
+ import "@ui-sdk/web/field"
470
+ import { toText, type TokenInputValue } from "@ui-sdk/web/token-input"
471
+ import { log } from "./log"
472
+
473
+ const files = [
474
+ { value: "src/app.tsx", label: "app.tsx", keywords: ["src"] },
475
+ { value: "src/routes.ts", label: "routes.ts", keywords: ["src"] },
476
+ { value: "src/styles.css", label: "styles.css", keywords: ["src"] },
477
+ { value: "README.md", label: "README.md" },
478
+ { value: "package.json", label: "package.json" },
479
+ ]
480
+
481
+ const draft: TokenInputValue = [
482
+ "Explain ",
483
+ { type: "file", value: "src/routes.ts", label: "routes.ts" },
484
+ " in two sentences.",
485
+ ]
486
+
487
+ function mount(root: HTMLElement) {
488
+ root.innerHTML = `
489
+ <ui-field>
490
+ <ui-field-label>Prompt</ui-field-label>
491
+ <ui-token-input value="${toText(draft)}">
492
+ <ui-token-input-editor></ui-token-input-editor>
493
+ <ui-trigger-menu>
494
+ <ui-trigger-menu-content>
495
+ <ui-trigger-menu-list></ui-trigger-menu-list>
496
+ </ui-trigger-menu-content>
497
+ </ui-trigger-menu>
498
+ </ui-token-input>
499
+ </ui-field>
500
+ `
501
+ const prompt = root.querySelector("ui-token-input")!
502
+ prompt.history = { limit: 50, groupDelay: 1000 }
503
+ prompt.getTokenDescription = (token) =>
504
+ token.type === "file" ? "attached file" : token.type
505
+ root.querySelector("ui-trigger-menu")!.triggers = [
506
+ { char: "@", type: "file", items: files },
507
+ ]
508
+ prompt.addEventListener("valuechange", (event) => {
509
+ const { value, reason } = event.detail
510
+ const removed = event.detail.removed.map((token) => token.label).join(", ")
511
+ log(
512
+ root,
513
+ `${toText(value)} (${reason}${removed ? `, removed ${removed}` : ""})`
514
+ )
515
+ })
516
+ }
517
+
518
+ export { mount }
519
+ ```
520
+
521
+ Type, add a file with @, or remove a token. The console logs the value and the reason for each change.
522
+
523
+ ## Controller
524
+
525
+ Use the element's `api` to insert, update, or remove tokens from code. Pass a promise as `resolve` to mark an inserted token as pending until its data is ready. Updating a token doesn't add an undo step.
526
+
527
+ ```ts title="controller.ts"
528
+ import "@ui-sdk/web/field"
529
+ import {
530
+ toText,
531
+ type Token,
532
+ type TokenInputValue,
533
+ } from "@ui-sdk/web/token-input"
534
+
535
+ const draft: TokenInputValue = [
536
+ "Compare ",
537
+ { type: "file", value: "src/routes.ts", label: "routes.ts" },
538
+ " with ",
539
+ ]
540
+
541
+ const loadFile = () => new Promise<void>((resolve) => setTimeout(resolve, 800))
542
+
543
+ function mount(root: HTMLElement) {
544
+ root.innerHTML = `
545
+ <div data-slot="stack">
546
+ <div data-slot="controls">
547
+ <button type="button" data-action="attach">Attach File</button>
548
+ <button type="button" data-action="path">Show Path</button>
549
+ <button type="button" data-action="remove">Remove First</button>
550
+ <button type="button" data-action="undo">Undo</button>
551
+ <button type="button" data-action="clear">Clear</button>
552
+ </div>
553
+ <ui-field>
554
+ <ui-field-label>Prompt</ui-field-label>
555
+ <ui-token-input value="${toText(draft)}">
556
+ <ui-token-input-editor></ui-token-input-editor>
557
+ </ui-token-input>
558
+ </ui-field>
559
+ </div>
560
+ `
561
+ const prompt = root.querySelector("ui-token-input")!.api
562
+ const firstToken = () =>
563
+ prompt
564
+ .getValue()
565
+ .find((segment): segment is Token => typeof segment !== "string")
566
+ const actions: Record<string, () => void> = {
567
+ attach: () =>
568
+ prompt.insert(
569
+ { type: "file", value: "package.json", label: "package.json" },
570
+ { at: "end", resolve: loadFile() }
571
+ ),
572
+ path: () => {
573
+ const token = firstToken()
574
+ if (token) {
575
+ prompt.updateToken(token.id!, { label: token.value })
576
+ }
577
+ },
578
+ remove: () => {
579
+ const token = firstToken()
580
+ if (token) {
581
+ prompt.removeToken(token.id!)
582
+ }
583
+ },
584
+ undo: () => prompt.undo(),
585
+ clear: () => prompt.clear(),
586
+ }
587
+ root
588
+ .querySelector("[data-slot=controls]")!
589
+ .addEventListener("mousedown", (event) => event.preventDefault())
590
+ root
591
+ .querySelectorAll<HTMLButtonElement>("[data-action]")
592
+ .forEach((button) => {
593
+ button.addEventListener("click", () => actions[button.dataset.action!]())
594
+ })
595
+ }
596
+
597
+ export { mount }
598
+ ```
599
+
600
+ Attach a file and watch it load. Show the first token's full path or remove it, then use Undo or Clear.
601
+
602
+ ## Submit Shortcut
603
+
604
+ Set `submit-shortcut` to `mod+enter` for a multiline message. Enter then inserts a line, and Command or Control+Enter submits the form the input is in.
605
+
606
+ ```ts title="submit-shortcut.ts"
607
+ import "@ui-sdk/web/field"
608
+ import { toLabel } from "@ui-sdk/web/token-input"
609
+ import { log } from "./log"
610
+
611
+ function mount(root: HTMLElement) {
612
+ root.innerHTML = `
613
+ <form>
614
+ <ui-field>
615
+ <ui-field-label>Message</ui-field-label>
616
+ <ui-token-input submit-shortcut="mod+enter">
617
+ <ui-token-input-editor placeholder="Write a message…"></ui-token-input-editor>
618
+ </ui-token-input>
619
+ </ui-field>
620
+ </form>
621
+ `
622
+ const message = root.querySelector("ui-token-input")!
623
+ root.querySelector("form")!.addEventListener("submit", (event) => {
624
+ event.preventDefault()
625
+ log(root, `Sent ${toLabel(message.value)}`)
626
+ })
627
+ }
628
+
629
+ export { mount }
630
+ ```
631
+
632
+ Write a message. Enter adds a line; Command+Enter on a Mac or Control+Enter elsewhere sends it to the console.
633
+
634
+ ## Custom Rendering
635
+
636
+ Put a `<template>` inside `ui-token-input` to render each token's content, usually a `ui-token-input-token` with a `ui-token-input-token-remove` inside. An element with `data-token-label` in it gets the token's label. To choose an icon by the token's type or show its `data`, set the `renderToken` property instead: it receives the token and the element that holds it. Without either, each token shows its label.
637
+
638
+ Elements have no render functions. See [Parts and Composition](../parts-and-composition.md) for the rendering contract and [State](#state) for each part's fields.
639
+
640
+ ## Styling
641
+
642
+ Style the editor, the tokens and their remove buttons. The editor shows `data-empty` while it holds nothing; show the placeholder with `content: attr(aria-placeholder)` on its `::before`. Tokens show `data-token-type`, `data-pending`, `data-unresolved` and `data-selected`. Without a template or `renderToken`, the element that holds each token, `token-input-host`, carries the same attributes, so you can style tokens without custom markup.
643
+
644
+ Each part has a `data-slot`, such as `token-input-token`, and shows its state through the attributes listed under [Data Attributes](#data-attributes).
645
+
646
+ ## Data Attributes
647
+
648
+ ### `<ui-token-input-editor>`
649
+ `[data-slot="token-input-editor"]`
650
+
651
+ - `data-empty`: Present while the input holds nothing. Show the placeholder with it.
652
+ - `data-disabled`: Present when the input is disabled, by its own prop, a field or a `<fieldset>`.
653
+ - `data-readonly`: Present when the input is read-only.
654
+
655
+ ### `<ui-token-input-token>`
656
+ `[data-slot="token-input-token"]`
657
+
658
+ - `data-token-type` (`file`): The token's type, like `file` or `mention`. Also on its host.
659
+ - `data-pending`: Present while the token loads. Also on its host.
660
+ - `data-disabled`: Present when the input is disabled, by its own prop, a field or a `<fieldset>`.
661
+ - `data-readonly`: Present when the input is read-only.
662
+ - `data-slot`
663
+ - `data-selected`: Present while the token is in the selection, or selected for removal. Also on its host.
664
+ - `data-unresolved`: Present while the token needs the user, like an ambiguous mention. Also on its host.
665
+
666
+ ### `<ui-token-input-token-remove>`
667
+ `[data-slot="token-input-token-remove"]`
668
+
669
+ - `data-disabled`: Present when the input is disabled, by its own prop, a field or a `<fieldset>`.
670
+ - `data-readonly`: Present when the input is read-only.
671
+
672
+ ## API Reference
673
+
674
+ Props are attributes in kebab case, like `submit-shortcut` and `token-deletion`. `codec`, `defaultValue`, `getTokenDescription`, `history`, `controller` and `renderToken` are properties. Callbacks are DOM events.
675
+
676
+ ### TokenInput
677
+
678
+ - `value?` (`TokenInputValue`): The value. Pass it to control the input.
679
+ - `defaultValue?` (`TokenInputValue`): The value at first, when uncontrolled. A form reset returns to it.
680
+ - `valuechange event`: Runs when typing, pasting, a menu, undo or a controller wants to change the value. `details.reason` says why, `details.removed` lists removed tokens, and `details.cancel()` stops it.
681
+ - `submit event`: Runs on the submit shortcut, unless an input method is composing or a trigger menu is open. Without it, the shortcut submits the form the input is in. With neither, the key is left alone, so Enter starts a new line.
682
+ - `submitShortcut?` (`"enter" | "mod+enter"`): Which keys submit: `"enter"`, with Shift+Enter for a new line, or `"mod+enter"`, with Enter for a new line, which many Japanese and Chinese writers prefer.
683
+ - `tokenDeletion?` (`TokenDeletion`): How Backspace and Delete treat a token next to the caret. `"whole"` removes it in one press, `"select"` selects it first and removes it on the second, and `"revert"` turns it back into its text, so a trigger menu opens on it again.
684
+ - `copy?` (`"codec" | "label"`): What copying writes as plain text: `"codec"` keeps tokens through any app that pastes text, `"label"` writes what people read.
685
+ - `codec?` (`TokenCodec`): How tokens become text and back, for the clipboard and forms.
686
+ - `getTokenDescription?` (`((token: Token) => string)`): What a token says to screen readers besides its label, like its kind and status.
687
+ - `history?` (`UndoStackOptions`): Undo history: how many steps it keeps, and how long a typing pause starts a new step.
688
+ - `disabled?` (`boolean`): Disables the input: it can't be focused or changed, and isn't submitted.
689
+ - `readOnly?` (`boolean`): Keeps the input focusable and submitted, but stops changes.
690
+ - `required?` (`boolean`): Blocks form submission while the input is empty.
691
+ - `name?` (`string`): The name the codec text submits under. Without one, the input submits nothing.
692
+ - `form?` (`string`): The id of a form to belong to, when the input isn't inside it.
693
+ - `controller?` (`object`): Reads, edits and focuses the input from anywhere. Create one with `createTokenInputController()`.
694
+ - `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.
695
+
696
+ `renderToken(token, host)` renders each token's content into `host`. Without it, a `<template>` inside the element is copied for each token.
697
+
698
+ ### TokenInputEditor
699
+
700
+ - `placeholder?` (`string`): Text shown while the input is empty, through `aria-placeholder`. Show it with `data-empty:before:content-[attr(aria-placeholder)]`.
701
+
702
+ ### TokenInputToken
703
+
704
+ A token's content, inside the template or `renderToken`, with its state for styling.
705
+
706
+ ### TokenInputTokenRemove
707
+
708
+ Removes its token when pressed and keeps focus in the editor. It's hidden from assistive technology, since keyboard users remove tokens with Backspace.
709
+
710
+ ### Token
711
+
712
+ - `type` (`string`): Kind, like `"mention"`, `"file"` or `"skill"`.
713
+ - `value` (`string`): The id it stands for.
714
+ - `label` (`string`): The text it shows, reads as and falls back to.
715
+ - `id?` (`string`): Stable identity, generated when missing.
716
+ - `status?` (`"pending" | "unresolved"`): `"pending"` while it loads, `"unresolved"` when it needs the user, like an ambiguous mention.
717
+ - `data?` (`Record<string, unknown>`): What the chip renders from, like an icon or a run state. Never serialized.
718
+
719
+ ### Codec
720
+
721
+ - `format` (`(token: Token) => string`): The text a token is written as.
722
+ - `parse` (`(text: string) => TokenInputValue`): Text back into a value, with tokens wherever their text appears.
723
+ - `escape?` (`((text: string, next: Token | undefined) => string)`): How plain text is written so `parse` reads it back as text. `next` is the token that follows it, if any. Defaults to the text as is.
724
+
725
+ ### State
726
+
727
+ `TokenInputEditor`:
728
+
729
+ - `empty` (`boolean`): Whether the input holds nothing.
730
+ - `disabled` (`boolean`): Whether the input is disabled, by itself or by a `<fieldset>`.
731
+ - `readOnly` (`boolean`): Whether the input is read-only: it stays focusable, but typing, pastes and drops don't change it.
732
+
733
+ `TokenInputToken`:
734
+
735
+ - `token` (`Token`): The token this part shows: the one the token input renders its content for.
736
+ - `selected` (`boolean`): Whether the token is in the selection, or selected for removal.
737
+ - `pending` (`boolean`): Whether the token is loading.
738
+ - `unresolved` (`boolean`): Whether the token needs the user, like an ambiguous mention.
739
+ - `disabled` (`boolean`): Whether the input is disabled, by itself or by a `<fieldset>`.
740
+ - `readOnly` (`boolean`): Whether the input is read-only, so the token's remove button does nothing.
741
+
742
+ ### Reasons
743
+
744
+ - `input-change` (`Event`): Typing, pasting or dropping changed a text field's value; in a combobox it can also open or close it, or Enter keeps the typed text as the value.
745
+ - `paste` (`ClipboardEvent`): Files were pasted, like a screenshot, or text and tokens into a token input.
746
+ - `drop` (`DragEvent`): Files were dropped on a drop zone, or text and tokens on a token input.
747
+ - `cut` (`ClipboardEvent`): A selection was cut from a token input.
748
+ - `undo` (`KeyboardEvent | InputEvent`): Undo, from the keyboard, the Edit menu or a controller.
749
+ - `redo` (`KeyboardEvent | InputEvent`): Redo, from the keyboard, the Edit menu or a controller.
750
+ - `remove-press` (`MouseEvent | KeyboardEvent`): A chip's remove part was pressed, or Backspace or Delete removed a chip or a span.
751
+ - `item-press` (`MouseEvent | KeyboardEvent`): A member of a collection was chosen: a menu item, a tab, a radio or a checkbox item.
752
+ - `reset` (`none`): A form reset.
753
+ - `restore` (`none`): The browser restored state, like after going back, or a saved value was read back from storage.
754
+ - `imperative` (`none`): A controller or `api` call, or a property set on a web component.
755
+
756
+ ### Controller
757
+
758
+ The element's `api` property has the same methods. Or create one with `createTokenInputController()` and set it as the `controller` property.
759
+
760
+ - `getValue()` (`() => TokenInputValue`): The value: text and tokens.
761
+ - `setValue(value, options?)` (`(value: TokenInputValue, options?: TokenInputChangeOptions | undefined) => boolean`): Replaces the value as one undoable step. Returns false when the change was canceled or nothing changed.
762
+ - `getText(codec?)` (`(codec?: TokenCodec | undefined) => string`): The value as codec text, like `Ask [@Ada](mention:ada)`.
763
+ - `getLabel()` (`() => string`): The value as people read it, with each token's label.
764
+ - `insert(content, options?)` (`(content: string | Token | TokenInputValue, options?: (TokenInputChangeOptions & { at?: TextRange | "caret" | "end" | undefined; resolve?: PromiseLike<...> | undefined; }) | undefined) => boolean`): Inserts text, a token or a value at the caret, the end or a range, as one undoable step. With `resolve`, a token is pending until it settles: updated with what it resolves to, removed if it rejects. Returns false when the change was canceled.
765
+ - `updateToken(id, patch)` (`(id: string, patch: Partial<Omit<Token, "id">>) => boolean`): Changes a token's status, data or label without an undo step or a caret move. Returns false when there's no such token or nothing changed.
766
+ - `removeToken(id, options?)` (`(id: string, options?: TokenInputChangeOptions | undefined) => boolean`): Removes a token as one undoable step. Returns false when the change was canceled or nothing changed.
767
+ - `undo()` (`() => boolean`): Undoes the last step. Returns false when there was none or the change was canceled.
768
+ - `redo()` (`() => boolean`): Redoes the last undone step. Returns false when there was none or the change was canceled.
769
+ - `canUndo()` (`() => boolean`): Whether there's a step to undo.
770
+ - `canRedo()` (`() => boolean`): Whether there's a step to redo.
771
+ - `clear(options?)` (`(options?: TokenInputChangeOptions | undefined) => boolean`): Empties the input as one undoable step. Returns false when the change was canceled or nothing changed.
772
+ - `focus(options?)` (`(options?: { at?: "end" | "start" | undefined; } | undefined) => void`): Focuses the editor, with the caret at its start or end.
773
+ - `editor` (`TextEditorAdapter`): The editor a TriggerMenu outside the token input reads and writes. A menu inside it finds it on its own.
774
+
775
+ ### Events
776
+
777
+ Events fire on their own element and don't bubble, with the new state in `event.detail.value`.
778
+
779
+ | Member | On | Description |
780
+ | --------------------------- | ---------------- | --------------------------------------------------------------------------- |
781
+ | `value` property, attribute | `ui-token-input` | The value. The attribute and a string property are read as codec text |
782
+ | `api` property | `ui-token-input` | The [controller](#controller-1) |
783
+ | `valuechange` event | `ui-token-input` | `detail: { value, reason, inputType, removed }`: the [reason](#reasons) too |
784
+
785
+ There's no submit event: the submit shortcut submits the form the input is in, so the form's own `submit` event hears it. Setting the `value` property is one undoable step, like `setValue()`.
786
+
787
+ ## Accessibility
788
+
789
+ The editor is a multiline text box: it has the `textbox` role with `aria-multiline`, and a Trigger Menu inside it adds `aria-autocomplete` and `aria-haspopup` for its suggestions. Give it a visible label through a [Field](./field.md), or an `aria-label`. Each token reads as its label and its kind, like "routes.ts file", and inserting or removing one is announced. Typing keeps the browser's spelling, autocorrect, and input method support.
790
+
791
+ ### Keyboard
792
+
793
+ | Key | Does |
794
+ | ---------------------------- | ----------------------------------------------------------------------------- |
795
+ | Backspace, Delete | Removes the token before or after the caret, as `token-deletion` says |
796
+ | ArrowLeft, ArrowRight | Moves the caret past a token in one press; the caret never stops inside one |
797
+ | Enter | Submits. While a trigger menu is open, chooses the highlighted suggestion |
798
+ | Shift+Enter | Starts a new line |
799
+ | Command+Enter, Control+Enter | Submits when `submit-shortcut` is `"mod+enter"`; Enter then starts a new line |
800
+ | Command+Z, Control+Z | Undoes the last step. Typing is grouped; pastes and token changes are steps |
801
+ | Shift+Command+Z, Control+Y | Redoes the last undone step |
802
+
803
+ ### Tested Behavior
804
+
805
+ Every line below is an automated test.
806
+
807
+ **Value**
808
+
809
+ - Renders text and tokens, each token as one chip.
810
+ - Tokens it starts with show their rendered content once, and read as their label and kind.
811
+ - Tokens and their remove parts mark a read-only or disabled input.
812
+ - Is empty with a placeholder until something is typed.
813
+ - Typing after a token goes after it.
814
+ - Shift+Enter starts a new line.
815
+
816
+ **Tokens**
817
+
818
+ - @ opens the menu inside the input, and choosing inserts a token and a space.
819
+ - A controlled input takes tokens from its menu and keeps typing in order.
820
+ - Enter in an open menu chooses and doesn't submit.
821
+ - One Backspace removes a whole token, and says so.
822
+ - Backspace removes tokens one by one, with no keystroke spent on anchors.
823
+ - Delete removes the token after the caret.
824
+ - The caret crosses a token with one arrow press each way.
825
+ - The caret can sit between two adjacent tokens.
826
+ - Clicking past a final token and typing lands after it.
827
+ - Word deletion stops at a token.
828
+ - The remove button removes its token and keeps focus.
829
+ - With tokenDeletion select, the first Backspace selects the token and the second removes it.
830
+ - With tokenDeletion revert, Backspace turns the token back into text and the menu opens on it.
831
+
832
+ **History**
833
+
834
+ - Undo and Redo step through edits, a token insertion on its own.
835
+ - Undo brings back a removed token.
836
+ - A pending token shows loading, then settles without an undo step.
837
+ - A pending token whose load fails is removed.
838
+
839
+ **Clipboard**
840
+
841
+ - Copying tokens into plain text and back keeps them.
842
+ - Copy writes codec text and HTML with the tokens.
843
+ - Pasting codec text makes tokens.
844
+ - With copy label, plain text gets what people read.
845
+
846
+ **Submit**
847
+
848
+ - Enter submits the codec text.
849
+ - With mod+enter, Enter is a new line and Cmd or Ctrl+Enter submits.
850
+ - A form submits the codec text under the input's name.
851
+ - Enter submits the form the input's form attribute names, not the one it's in.
852
+ - Enter while an input method composes doesn't submit.
853
+
854
+ Runs in React, Vue and web components.