@prestack/thread-ui 0.0.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 (408) hide show
  1. package/CHANGELOG.md +348 -0
  2. package/dist/attach.d.ts +1 -0
  3. package/dist/attach.js +1 -0
  4. package/dist/ui/animations/anm_appear.d.ts +16 -0
  5. package/dist/ui/animations/anm_appear.js +10 -0
  6. package/dist/ui/animations/anm_blur_in.d.ts +22 -0
  7. package/dist/ui/animations/anm_blur_in.js +16 -0
  8. package/dist/ui/animations/anm_blur_out.d.ts +22 -0
  9. package/dist/ui/animations/anm_blur_out.js +16 -0
  10. package/dist/ui/animations/anm_dismiss.d.ts +22 -0
  11. package/dist/ui/animations/anm_dismiss.js +16 -0
  12. package/dist/ui/animations/anm_drop.d.ts +22 -0
  13. package/dist/ui/animations/anm_drop.js +16 -0
  14. package/dist/ui/animations/anm_fall.d.ts +22 -0
  15. package/dist/ui/animations/anm_fall.js +16 -0
  16. package/dist/ui/animations/anm_flash.d.ts +19 -0
  17. package/dist/ui/animations/anm_flash.js +16 -0
  18. package/dist/ui/animations/anm_glow.d.ts +16 -0
  19. package/dist/ui/animations/anm_glow.js +14 -0
  20. package/dist/ui/animations/anm_lift.d.ts +16 -0
  21. package/dist/ui/animations/anm_lift.js +14 -0
  22. package/dist/ui/animations/anm_nudge.d.ts +16 -0
  23. package/dist/ui/animations/anm_nudge.js +14 -0
  24. package/dist/ui/animations/anm_pop_in.d.ts +29 -0
  25. package/dist/ui/animations/anm_pop_in.js +20 -0
  26. package/dist/ui/animations/anm_pop_out.d.ts +29 -0
  27. package/dist/ui/animations/anm_pop_out.js +20 -0
  28. package/dist/ui/animations/anm_press.d.ts +19 -0
  29. package/dist/ui/animations/anm_press.js +10 -0
  30. package/dist/ui/animations/anm_pulse.d.ts +20 -0
  31. package/dist/ui/animations/anm_pulse.js +11 -0
  32. package/dist/ui/animations/anm_rise.d.ts +22 -0
  33. package/dist/ui/animations/anm_rise.js +16 -0
  34. package/dist/ui/animations/anm_shake.d.ts +23 -0
  35. package/dist/ui/animations/anm_shake.js +11 -0
  36. package/dist/ui/animations/anm_slide_in_left.d.ts +22 -0
  37. package/dist/ui/animations/anm_slide_in_left.js +16 -0
  38. package/dist/ui/animations/anm_slide_in_right.d.ts +22 -0
  39. package/dist/ui/animations/anm_slide_in_right.js +16 -0
  40. package/dist/ui/animations/anm_slide_out_left.d.ts +22 -0
  41. package/dist/ui/animations/anm_slide_out_left.js +16 -0
  42. package/dist/ui/animations/anm_slide_out_right.d.ts +22 -0
  43. package/dist/ui/animations/anm_slide_out_right.js +16 -0
  44. package/dist/ui/animations/anm_spin.d.ts +16 -0
  45. package/dist/ui/animations/anm_spin.js +10 -0
  46. package/dist/ui/animations/anm_swell.d.ts +16 -0
  47. package/dist/ui/animations/anm_swell.js +14 -0
  48. package/dist/ui/animations/anm_wobble.d.ts +27 -0
  49. package/dist/ui/animations/anm_wobble.js +22 -0
  50. package/dist/ui/animations/anm_zoom_in.d.ts +22 -0
  51. package/dist/ui/animations/anm_zoom_in.js +16 -0
  52. package/dist/ui/animations/anm_zoom_out.d.ts +22 -0
  53. package/dist/ui/animations/anm_zoom_out.js +16 -0
  54. package/dist/ui/animations.d.ts +59 -0
  55. package/dist/ui/animations.js +227 -0
  56. package/dist/ui/attach.d.ts +3 -0
  57. package/dist/ui/attach.js +497 -0
  58. package/dist/ui/charts.d.ts +32 -0
  59. package/dist/ui/charts.js +35 -0
  60. package/dist/ui/checked.d.ts +19 -0
  61. package/dist/ui/checked.js +3 -0
  62. package/dist/ui/collector.d.ts +32 -0
  63. package/dist/ui/collector.js +75 -0
  64. package/dist/ui/compositions.d.ts +21 -0
  65. package/dist/ui/compositions.js +305 -0
  66. package/dist/ui/consent.d.ts +22 -0
  67. package/dist/ui/consent.js +44 -0
  68. package/dist/ui/content.d.ts +9 -0
  69. package/dist/ui/content.js +11 -0
  70. package/dist/ui/contrast.d.ts +3 -0
  71. package/dist/ui/contrast.js +23 -0
  72. package/dist/ui/controls.d.ts +14 -0
  73. package/dist/ui/controls.js +2 -0
  74. package/dist/ui/disclosure.d.ts +14 -0
  75. package/dist/ui/disclosure.js +2 -0
  76. package/dist/ui/dismiss-layer.d.ts +14 -0
  77. package/dist/ui/dismiss-layer.js +66 -0
  78. package/dist/ui/door.d.ts +40 -0
  79. package/dist/ui/door.js +100 -0
  80. package/dist/ui/drag.d.ts +82 -0
  81. package/dist/ui/drag.js +212 -0
  82. package/dist/ui/elements/accordion.d.ts +12 -0
  83. package/dist/ui/elements/accordion.js +16 -0
  84. package/dist/ui/elements/accordion.works.d.ts +22 -0
  85. package/dist/ui/elements/accordion.works.js +44 -0
  86. package/dist/ui/elements/aspect-ratio.d.ts +10 -0
  87. package/dist/ui/elements/aspect-ratio.js +9 -0
  88. package/dist/ui/elements/aspect-ratio.works.d.ts +2 -0
  89. package/dist/ui/elements/aspect-ratio.works.js +3 -0
  90. package/dist/ui/elements/avatar.d.ts +11 -0
  91. package/dist/ui/elements/avatar.js +10 -0
  92. package/dist/ui/elements/avatar.works.d.ts +4 -0
  93. package/dist/ui/elements/avatar.works.js +16 -0
  94. package/dist/ui/elements/badge.d.ts +11 -0
  95. package/dist/ui/elements/badge.js +10 -0
  96. package/dist/ui/elements/badge.works.d.ts +5 -0
  97. package/dist/ui/elements/badge.works.js +6 -0
  98. package/dist/ui/elements/bars.d.ts +14 -0
  99. package/dist/ui/elements/bars.js +17 -0
  100. package/dist/ui/elements/bars.works.d.ts +12 -0
  101. package/dist/ui/elements/bars.works.js +20 -0
  102. package/dist/ui/elements/box.d.ts +12 -0
  103. package/dist/ui/elements/box.js +11 -0
  104. package/dist/ui/elements/breadcrumb.d.ts +10 -0
  105. package/dist/ui/elements/breadcrumb.js +12 -0
  106. package/dist/ui/elements/breadcrumb.works.d.ts +7 -0
  107. package/dist/ui/elements/breadcrumb.works.js +21 -0
  108. package/dist/ui/elements/button.d.ts +17 -0
  109. package/dist/ui/elements/button.js +16 -0
  110. package/dist/ui/elements/button.works.d.ts +17 -0
  111. package/dist/ui/elements/button.works.js +34 -0
  112. package/dist/ui/elements/column.d.ts +9 -0
  113. package/dist/ui/elements/column.js +8 -0
  114. package/dist/ui/elements/consent.d.ts +13 -0
  115. package/dist/ui/elements/consent.js +21 -0
  116. package/dist/ui/elements/consent.works.d.ts +41 -0
  117. package/dist/ui/elements/consent.works.js +79 -0
  118. package/dist/ui/elements/donut.d.ts +13 -0
  119. package/dist/ui/elements/donut.js +16 -0
  120. package/dist/ui/elements/donut.works.d.ts +11 -0
  121. package/dist/ui/elements/donut.works.js +28 -0
  122. package/dist/ui/elements/each.d.ts +14 -0
  123. package/dist/ui/elements/each.js +9 -0
  124. package/dist/ui/elements/each.works.d.ts +3 -0
  125. package/dist/ui/elements/each.works.js +68 -0
  126. package/dist/ui/elements/empty.d.ts +9 -0
  127. package/dist/ui/elements/empty.js +12 -0
  128. package/dist/ui/elements/field.d.ts +16 -0
  129. package/dist/ui/elements/field.js +15 -0
  130. package/dist/ui/elements/field.works.d.ts +17 -0
  131. package/dist/ui/elements/field.works.js +45 -0
  132. package/dist/ui/elements/funnel.d.ts +14 -0
  133. package/dist/ui/elements/funnel.js +17 -0
  134. package/dist/ui/elements/funnel.works.d.ts +12 -0
  135. package/dist/ui/elements/funnel.works.js +23 -0
  136. package/dist/ui/elements/gauge.d.ts +12 -0
  137. package/dist/ui/elements/gauge.js +15 -0
  138. package/dist/ui/elements/gauge.works.d.ts +11 -0
  139. package/dist/ui/elements/gauge.works.js +31 -0
  140. package/dist/ui/elements/glyph.d.ts +10 -0
  141. package/dist/ui/elements/glyph.js +9 -0
  142. package/dist/ui/elements/glyph.works.d.ts +5 -0
  143. package/dist/ui/elements/glyph.works.js +16 -0
  144. package/dist/ui/elements/grid.d.ts +9 -0
  145. package/dist/ui/elements/grid.js +8 -0
  146. package/dist/ui/elements/heatmap.d.ts +15 -0
  147. package/dist/ui/elements/heatmap.js +17 -0
  148. package/dist/ui/elements/heatmap.works.d.ts +11 -0
  149. package/dist/ui/elements/heatmap.works.js +11 -0
  150. package/dist/ui/elements/hit-box.d.ts +19 -0
  151. package/dist/ui/elements/hit-box.js +15 -0
  152. package/dist/ui/elements/hit-box.works.d.ts +87 -0
  153. package/dist/ui/elements/hit-box.works.js +451 -0
  154. package/dist/ui/elements/image.d.ts +10 -0
  155. package/dist/ui/elements/image.js +9 -0
  156. package/dist/ui/elements/line-chart.d.ts +13 -0
  157. package/dist/ui/elements/line-chart.js +16 -0
  158. package/dist/ui/elements/line-chart.works.d.ts +12 -0
  159. package/dist/ui/elements/line-chart.works.js +27 -0
  160. package/dist/ui/elements/link.d.ts +12 -0
  161. package/dist/ui/elements/link.js +15 -0
  162. package/dist/ui/elements/link.works.d.ts +10 -0
  163. package/dist/ui/elements/link.works.js +15 -0
  164. package/dist/ui/elements/media.d.ts +11 -0
  165. package/dist/ui/elements/media.js +22 -0
  166. package/dist/ui/elements/menu.d.ts +12 -0
  167. package/dist/ui/elements/menu.js +18 -0
  168. package/dist/ui/elements/menu.works.d.ts +50 -0
  169. package/dist/ui/elements/menu.works.js +100 -0
  170. package/dist/ui/elements/money.d.ts +10 -0
  171. package/dist/ui/elements/money.js +9 -0
  172. package/dist/ui/elements/money.works.d.ts +4 -0
  173. package/dist/ui/elements/money.works.js +4 -0
  174. package/dist/ui/elements/pagination.d.ts +11 -0
  175. package/dist/ui/elements/pagination.js +12 -0
  176. package/dist/ui/elements/pagination.works.d.ts +5 -0
  177. package/dist/ui/elements/pagination.works.js +15 -0
  178. package/dist/ui/elements/progress.d.ts +11 -0
  179. package/dist/ui/elements/progress.js +11 -0
  180. package/dist/ui/elements/progress.works.d.ts +2 -0
  181. package/dist/ui/elements/progress.works.js +6 -0
  182. package/dist/ui/elements/radio-group.d.ts +15 -0
  183. package/dist/ui/elements/radio-group.js +16 -0
  184. package/dist/ui/elements/radio-group.works.d.ts +10 -0
  185. package/dist/ui/elements/radio-group.works.js +22 -0
  186. package/dist/ui/elements/row.d.ts +9 -0
  187. package/dist/ui/elements/row.js +8 -0
  188. package/dist/ui/elements/scatter.d.ts +13 -0
  189. package/dist/ui/elements/scatter.js +15 -0
  190. package/dist/ui/elements/scatter.works.d.ts +11 -0
  191. package/dist/ui/elements/scatter.works.js +24 -0
  192. package/dist/ui/elements/select.d.ts +13 -0
  193. package/dist/ui/elements/select.js +11 -0
  194. package/dist/ui/elements/select.works.d.ts +4 -0
  195. package/dist/ui/elements/select.works.js +3 -0
  196. package/dist/ui/elements/separator.d.ts +10 -0
  197. package/dist/ui/elements/separator.js +9 -0
  198. package/dist/ui/elements/skeleton.d.ts +8 -0
  199. package/dist/ui/elements/skeleton.js +9 -0
  200. package/dist/ui/elements/slider.d.ts +14 -0
  201. package/dist/ui/elements/slider.js +10 -0
  202. package/dist/ui/elements/slider.works.d.ts +4 -0
  203. package/dist/ui/elements/slider.works.js +3 -0
  204. package/dist/ui/elements/sparkline.d.ts +10 -0
  205. package/dist/ui/elements/sparkline.js +15 -0
  206. package/dist/ui/elements/sparkline.works.d.ts +10 -0
  207. package/dist/ui/elements/sparkline.works.js +19 -0
  208. package/dist/ui/elements/spinner.d.ts +9 -0
  209. package/dist/ui/elements/spinner.js +12 -0
  210. package/dist/ui/elements/stack.d.ts +9 -0
  211. package/dist/ui/elements/stack.js +8 -0
  212. package/dist/ui/elements/stat.d.ts +12 -0
  213. package/dist/ui/elements/stat.js +10 -0
  214. package/dist/ui/elements/stat.works.d.ts +3 -0
  215. package/dist/ui/elements/stat.works.js +10 -0
  216. package/dist/ui/elements/surface.d.ts +9 -0
  217. package/dist/ui/elements/surface.js +15 -0
  218. package/dist/ui/elements/surface.works.d.ts +7 -0
  219. package/dist/ui/elements/surface.works.js +4 -0
  220. package/dist/ui/elements/table.d.ts +13 -0
  221. package/dist/ui/elements/table.js +16 -0
  222. package/dist/ui/elements/table.works.d.ts +11 -0
  223. package/dist/ui/elements/table.works.js +15 -0
  224. package/dist/ui/elements/tabs.d.ts +12 -0
  225. package/dist/ui/elements/tabs.js +16 -0
  226. package/dist/ui/elements/tabs.works.d.ts +25 -0
  227. package/dist/ui/elements/tabs.works.js +53 -0
  228. package/dist/ui/elements/text.d.ts +13 -0
  229. package/dist/ui/elements/text.js +9 -0
  230. package/dist/ui/elements/textarea.d.ts +14 -0
  231. package/dist/ui/elements/textarea.js +11 -0
  232. package/dist/ui/elements/textarea.works.d.ts +4 -0
  233. package/dist/ui/elements/textarea.works.js +3 -0
  234. package/dist/ui/elements/time.d.ts +11 -0
  235. package/dist/ui/elements/time.js +14 -0
  236. package/dist/ui/elements/time.works.d.ts +11 -0
  237. package/dist/ui/elements/time.works.js +16 -0
  238. package/dist/ui/elements/toggle.d.ts +11 -0
  239. package/dist/ui/elements/toggle.js +10 -0
  240. package/dist/ui/elements/toggle.works.d.ts +4 -0
  241. package/dist/ui/elements/toggle.works.js +3 -0
  242. package/dist/ui/elements/tooltip.d.ts +12 -0
  243. package/dist/ui/elements/tooltip.js +15 -0
  244. package/dist/ui/elements/tooltip.works.d.ts +28 -0
  245. package/dist/ui/elements/tooltip.works.js +54 -0
  246. package/dist/ui/elements/value.d.ts +12 -0
  247. package/dist/ui/elements/value.js +9 -0
  248. package/dist/ui/elements/value.works.d.ts +4 -0
  249. package/dist/ui/elements/value.works.js +4 -0
  250. package/dist/ui/elements.d.ts +1143 -0
  251. package/dist/ui/elements.js +68 -0
  252. package/dist/ui/focus-scope.d.ts +7 -0
  253. package/dist/ui/focus-scope.js +109 -0
  254. package/dist/ui/fonts.d.ts +103 -0
  255. package/dist/ui/fonts.js +243 -0
  256. package/dist/ui/generators/dev.d.ts +2 -0
  257. package/dist/ui/generators/dev.js +61 -0
  258. package/dist/ui/generators/elements.d.ts +31 -0
  259. package/dist/ui/generators/elements.js +520 -0
  260. package/dist/ui/generators/i18n.d.ts +5 -0
  261. package/dist/ui/generators/i18n.js +264 -0
  262. package/dist/ui/generators/icons.d.ts +1 -0
  263. package/dist/ui/generators/icons.js +187 -0
  264. package/dist/ui/generators/react.d.ts +26 -0
  265. package/dist/ui/generators/react.js +218 -0
  266. package/dist/ui/generators/routes.d.ts +11 -0
  267. package/dist/ui/generators/routes.js +597 -0
  268. package/dist/ui/generators/show.d.ts +1 -0
  269. package/dist/ui/generators/show.js +231 -0
  270. package/dist/ui/generators/styles.d.ts +1 -0
  271. package/dist/ui/generators/styles.js +502 -0
  272. package/dist/ui/generators/variants.d.ts +12 -0
  273. package/dist/ui/generators/variants.js +162 -0
  274. package/dist/ui/i18n/catalogs/en.d.ts +172 -0
  275. package/dist/ui/i18n/catalogs/en.js +148 -0
  276. package/dist/ui/i18n/format.d.ts +13 -0
  277. package/dist/ui/i18n/format.js +161 -0
  278. package/dist/ui/i18n/locales.d.ts +9 -0
  279. package/dist/ui/i18n/locales.js +20 -0
  280. package/dist/ui/i18n/parse.d.ts +45 -0
  281. package/dist/ui/i18n/parse.js +249 -0
  282. package/dist/ui/i18n/translator.d.ts +10 -0
  283. package/dist/ui/i18n/translator.js +22 -0
  284. package/dist/ui/i18n/types.d.ts +33 -0
  285. package/dist/ui/i18n/types.js +9 -0
  286. package/dist/ui/icons.d.ts +67 -0
  287. package/dist/ui/icons.js +249 -0
  288. package/dist/ui/islands/map.d.ts +33 -0
  289. package/dist/ui/islands/map.js +44 -0
  290. package/dist/ui/localizations.d.ts +33 -0
  291. package/dist/ui/localizations.js +51 -0
  292. package/dist/ui/makers/message.d.ts +1 -0
  293. package/dist/ui/makers/message.js +230 -0
  294. package/dist/ui/material.d.ts +83 -0
  295. package/dist/ui/material.js +95 -0
  296. package/dist/ui/materials/mat_bordered.d.ts +22 -0
  297. package/dist/ui/materials/mat_bordered.js +12 -0
  298. package/dist/ui/materials/mat_ceramic.d.ts +22 -0
  299. package/dist/ui/materials/mat_ceramic.js +12 -0
  300. package/dist/ui/materials/mat_clay.d.ts +22 -0
  301. package/dist/ui/materials/mat_clay.js +12 -0
  302. package/dist/ui/materials/mat_elevated.d.ts +32 -0
  303. package/dist/ui/materials/mat_elevated.js +23 -0
  304. package/dist/ui/materials/mat_flat.d.ts +50 -0
  305. package/dist/ui/materials/mat_flat.js +33 -0
  306. package/dist/ui/materials/mat_glass.d.ts +32 -0
  307. package/dist/ui/materials/mat_glass.js +19 -0
  308. package/dist/ui/materials/mat_lit.d.ts +22 -0
  309. package/dist/ui/materials/mat_lit.js +12 -0
  310. package/dist/ui/materials/mat_moulded.d.ts +16 -0
  311. package/dist/ui/materials/mat_moulded.js +10 -0
  312. package/dist/ui/materials.d.ts +56 -0
  313. package/dist/ui/materials.js +175 -0
  314. package/dist/ui/modes.d.ts +25 -0
  315. package/dist/ui/modes.js +25 -0
  316. package/dist/ui/navigation.d.ts +3 -0
  317. package/dist/ui/navigation.js +24 -0
  318. package/dist/ui/positioning.d.ts +24 -0
  319. package/dist/ui/positioning.js +48 -0
  320. package/dist/ui/presented.d.ts +10 -0
  321. package/dist/ui/presented.js +81 -0
  322. package/dist/ui/provider.d.ts +31 -0
  323. package/dist/ui/provider.js +104 -0
  324. package/dist/ui/render-loop.d.ts +12 -0
  325. package/dist/ui/render-loop.js +94 -0
  326. package/dist/ui/roving-focus.d.ts +15 -0
  327. package/dist/ui/roving-focus.js +143 -0
  328. package/dist/ui/screens.d.ts +17 -0
  329. package/dist/ui/screens.js +112 -0
  330. package/dist/ui/scroll-lock.d.ts +2 -0
  331. package/dist/ui/scroll-lock.js +24 -0
  332. package/dist/ui/series.d.ts +9 -0
  333. package/dist/ui/series.js +67 -0
  334. package/dist/ui/signals.d.ts +120 -0
  335. package/dist/ui/signals.js +286 -0
  336. package/dist/ui/styleguide.d.ts +27 -0
  337. package/dist/ui/styleguide.js +138 -0
  338. package/dist/ui/styleguides.d.ts +11 -0
  339. package/dist/ui/styleguides.js +299 -0
  340. package/dist/ui/themes.d.ts +5 -0
  341. package/dist/ui/themes.js +16 -0
  342. package/dist/ui/token.d.ts +16 -0
  343. package/dist/ui/token.js +37 -0
  344. package/dist/ui/tokens/shadow.d.ts +6 -0
  345. package/dist/ui/tokens/shadow.js +17 -0
  346. package/dist/ui/tokens.d.ts +180 -0
  347. package/dist/ui/tokens.js +200 -0
  348. package/dist/ui/validators.d.ts +37 -0
  349. package/dist/ui/validators.js +184 -0
  350. package/dist/ui/variant.d.ts +122 -0
  351. package/dist/ui/variant.js +201 -0
  352. package/dist/ui/variants/var_avatar-round.d.ts +23 -0
  353. package/dist/ui/variants/var_avatar-round.js +13 -0
  354. package/dist/ui/variants/var_bubble-me.d.ts +21 -0
  355. package/dist/ui/variants/var_bubble-me.js +13 -0
  356. package/dist/ui/variants/var_bubble-them.d.ts +18 -0
  357. package/dist/ui/variants/var_bubble-them.js +12 -0
  358. package/dist/ui/variants/var_button-border.d.ts +116 -0
  359. package/dist/ui/variants/var_button-border.js +75 -0
  360. package/dist/ui/variants/var_button-cta.d.ts +116 -0
  361. package/dist/ui/variants/var_button-cta.js +75 -0
  362. package/dist/ui/variants/var_button-destructive-ghost.d.ts +113 -0
  363. package/dist/ui/variants/var_button-destructive-ghost.js +71 -0
  364. package/dist/ui/variants/var_button-destructive.d.ts +116 -0
  365. package/dist/ui/variants/var_button-destructive.js +75 -0
  366. package/dist/ui/variants/var_button-fill.d.ts +116 -0
  367. package/dist/ui/variants/var_button-fill.js +75 -0
  368. package/dist/ui/variants/var_button-ghost.d.ts +113 -0
  369. package/dist/ui/variants/var_button-ghost.js +71 -0
  370. package/dist/ui/variants/var_button-glass.d.ts +84 -0
  371. package/dist/ui/variants/var_button-glass.js +54 -0
  372. package/dist/ui/variants/var_button-normal.d.ts +116 -0
  373. package/dist/ui/variants/var_button-normal.js +75 -0
  374. package/dist/ui/variants/var_button-quiet.d.ts +119 -0
  375. package/dist/ui/variants/var_button-quiet.js +73 -0
  376. package/dist/ui/variants/var_card.d.ts +30 -0
  377. package/dist/ui/variants/var_card.js +16 -0
  378. package/dist/ui/variants/var_chip.d.ts +18 -0
  379. package/dist/ui/variants/var_chip.js +12 -0
  380. package/dist/ui/variants/var_choice.d.ts +26 -0
  381. package/dist/ui/variants/var_choice.js +14 -0
  382. package/dist/ui/variants/var_framed.d.ts +11 -0
  383. package/dist/ui/variants/var_framed.js +9 -0
  384. package/dist/ui/variants/var_glyph-plain.d.ts +14 -0
  385. package/dist/ui/variants/var_glyph-plain.js +10 -0
  386. package/dist/ui/variants/var_input.d.ts +61 -0
  387. package/dist/ui/variants/var_input.js +42 -0
  388. package/dist/ui/variants/var_link-inline.d.ts +39 -0
  389. package/dist/ui/variants/var_link-inline.js +28 -0
  390. package/dist/ui/variants/var_list-row.d.ts +47 -0
  391. package/dist/ui/variants/var_list-row.js +33 -0
  392. package/dist/ui/variants/var_rule.d.ts +11 -0
  393. package/dist/ui/variants/var_rule.js +9 -0
  394. package/dist/ui/variants/var_skeleton-block.d.ts +17 -0
  395. package/dist/ui/variants/var_skeleton-block.js +11 -0
  396. package/dist/ui/variants/var_spinner-turning.d.ts +17 -0
  397. package/dist/ui/variants/var_spinner-turning.js +11 -0
  398. package/dist/ui/variants/var_stat-tile.d.ts +18 -0
  399. package/dist/ui/variants/var_stat-tile.js +12 -0
  400. package/dist/ui/variants/var_tab-bar.d.ts +24 -0
  401. package/dist/ui/variants/var_tab-bar.js +14 -0
  402. package/dist/ui/variants/var_tap-target.d.ts +33 -0
  403. package/dist/ui/variants/var_tap-target.js +24 -0
  404. package/dist/ui/variants.d.ts +174 -0
  405. package/dist/ui/variants.js +50 -0
  406. package/dist/ui/wrappers.d.ts +128 -0
  407. package/dist/ui/wrappers.js +220 -0
  408. package/package.json +16 -0
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+ import { arrow as arrowMiddleware, computePosition, flip, offset, shift, size, } from '@floating-ui/dom';
3
+ import { useFloating, autoUpdate } from '@floating-ui/react-dom';
4
+ const DEFAULT_GAP = 4;
5
+ const DEFAULT_PADDING = 8;
6
+ function middleware(options) {
7
+ const padding = options.padding ?? DEFAULT_PADDING;
8
+ const list = [
9
+ offset(options.gap ?? DEFAULT_GAP),
10
+ flip({ padding }),
11
+ shift({ padding }),
12
+ size({
13
+ padding,
14
+ apply({ availableWidth, availableHeight, elements }) {
15
+ Object.assign(elements.floating.style, {
16
+ maxWidth: `${Math.max(0, availableWidth)}px`,
17
+ maxHeight: `${Math.max(0, availableHeight)}px`,
18
+ overflow: 'auto',
19
+ });
20
+ },
21
+ }),
22
+ ];
23
+ if (options.arrowRef !== undefined) {
24
+ list.push(arrowMiddleware({ element: options.arrowRef.current, padding }));
25
+ }
26
+ return list;
27
+ }
28
+ export async function positionOf(reference, floating, options = {}) {
29
+ const result = await computePosition(reference, floating, {
30
+ placement: options.placement ?? 'bottom',
31
+ middleware: middleware(options),
32
+ ...(options.platform === undefined ? {} : { platform: options.platform }),
33
+ });
34
+ const arrowData = result.middlewareData.arrow;
35
+ return {
36
+ x: result.x,
37
+ y: result.y,
38
+ placement: result.placement,
39
+ ...(arrowData === undefined ? {} : { arrow: { ...(arrowData.x === undefined ? {} : { x: arrowData.x }), ...(arrowData.y === undefined ? {} : { y: arrowData.y }) } }),
40
+ };
41
+ }
42
+ export function useAnchored(options = {}) {
43
+ return useFloating({
44
+ placement: options.placement ?? 'bottom',
45
+ middleware: middleware(options),
46
+ whileElementsMounted: autoUpdate,
47
+ });
48
+ }
@@ -0,0 +1,10 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type Presentation } from './door.ts';
3
+ export interface PresentedProps {
4
+ readonly presentation: Presentation;
5
+ readonly open?: boolean;
6
+ readonly onDismiss?: () => void;
7
+ readonly className?: string;
8
+ readonly children: ReactNode;
9
+ }
10
+ export declare function Presented(props: PresentedProps): ReactNode;
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from 'react';
4
+ import { createPortal } from 'react-dom';
5
+ import { PRESENTATION_BEHAVIOUR } from "./door.js";
6
+ import { useDismissLayer } from "./dismiss-layer.js";
7
+ import { useFocusScope } from "./focus-scope.js";
8
+ import { lockScroll } from "./scroll-lock.js";
9
+ export function Presented(props) {
10
+ const behaviour = PRESENTATION_BEHAVIOUR[props.presentation];
11
+ const open = props.open ?? true;
12
+ const ref = useRef(null);
13
+ const [leaving, setLeaving] = useState(false);
14
+ const [was, setWas] = useState(open);
15
+ const labelId = useId();
16
+ useFocusScope(ref, {
17
+ active: open,
18
+ trapFocus: behaviour.trapFocus,
19
+ returnFocus: behaviour.returnFocus,
20
+ });
21
+ useDismissLayer(ref, {
22
+ active: open && (behaviour.dismissOnEscape || behaviour.dismissOnOutside),
23
+ dismissOnEscape: behaviour.dismissOnEscape,
24
+ dismissOnOutside: behaviour.dismissOnOutside,
25
+ onDismiss: props.onDismiss ?? (() => undefined),
26
+ });
27
+ useEffect(() => {
28
+ if (!open || !behaviour.backdrop)
29
+ return;
30
+ return lockScroll();
31
+ }, [open, behaviour.backdrop]);
32
+ if (was !== open) {
33
+ setWas(open);
34
+ setLeaving(!open);
35
+ }
36
+ useEffect(() => {
37
+ if (!leaving)
38
+ return undefined;
39
+ const node = ref.current;
40
+ if (node === null) {
41
+ setLeaving(false);
42
+ return undefined;
43
+ }
44
+ const running = typeof globalThis.getComputedStyle === 'function' &&
45
+ globalThis.getComputedStyle(node).animationName !== 'none';
46
+ if (!running) {
47
+ setLeaving(false);
48
+ return undefined;
49
+ }
50
+ const done = () => setLeaving(false);
51
+ node.addEventListener('animationend', done);
52
+ const style = globalThis.getComputedStyle(node);
53
+ const seconds = (one) => one.split(',').reduce((most, part) => Math.max(most, Number.parseFloat(part) || 0), 0);
54
+ const after = (seconds(style.animationDuration) + seconds(style.animationDelay)) * 1000 + 50;
55
+ const timer = setTimeout(done, after);
56
+ return () => {
57
+ node.removeEventListener('animationend', done);
58
+ clearTimeout(timer);
59
+ };
60
+ }, [leaving]);
61
+ useEffect(() => {
62
+ if (!open)
63
+ return;
64
+ const root = ref.current;
65
+ if (root === null)
66
+ return;
67
+ const title = root.querySelector('[data-screen-title], h1, h2, h3, h4, h5, h6');
68
+ if (title === null)
69
+ return;
70
+ if (title.id === '')
71
+ title.id = labelId;
72
+ root.setAttribute('aria-labelledby', title.id);
73
+ }, [open, labelId]);
74
+ if (!open && !leaving)
75
+ return null;
76
+ const surface = (_jsx("div", { ref: ref, className: props.className, "data-presentation": props.presentation, ...(leaving ? { 'data-leaving': '' } : {}), ...(behaviour.trapFocus ? { role: 'dialog', 'aria-modal': true } : {}), ...(props.presentation === 'toast' ? { role: 'status', 'aria-live': 'polite' } : {}), children: props.children }));
77
+ const content = behaviour.backdrop ? (_jsxs(_Fragment, { children: [_jsx("div", { "data-backdrop": "true", "aria-hidden": "true" }), surface] })) : (surface);
78
+ if (!behaviour.portal)
79
+ return content;
80
+ return createPortal(content, document.body);
81
+ }
@@ -0,0 +1,31 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type UiConfig } from './wrappers.tsx';
3
+ export interface ThreadUiProps {
4
+ readonly children: ReactNode;
5
+ readonly palette?: {
6
+ readonly accent: string;
7
+ readonly surface: string;
8
+ };
9
+ readonly mode?: 'light' | 'dark';
10
+ readonly locale?: string;
11
+ readonly wording?: Readonly<Record<string, Readonly<Record<string, string>>>>;
12
+ readonly actor?: {
13
+ readonly id: string | null;
14
+ readonly roles: readonly string[];
15
+ readonly entitlements: readonly string[];
16
+ };
17
+ readonly asking?: readonly {
18
+ readonly id: string;
19
+ readonly selector: string;
20
+ }[];
21
+ readonly platform?: string;
22
+ readonly telemetry?: {
23
+ readonly endpoint?: string;
24
+ readonly allowed: () => boolean;
25
+ readonly sample?: number;
26
+ };
27
+ readonly dispatch?: (name: string, input?: Readonly<Record<string, unknown>>) => Promise<unknown>;
28
+ readonly navigateTo?: (screen: string) => void;
29
+ readonly config?: UiConfig;
30
+ }
31
+ export declare function ThreadUi(props: ThreadUiProps): ReactNode;
@@ -0,0 +1,104 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from 'react';
4
+ import { en } from "./i18n/catalogs/en.js";
5
+ import { createTranslator } from "./i18n/translator.js";
6
+ import { EDGE_SCROLL_DEFAULTS } from "./drag.js";
7
+ import { createCollector, INERT_COLLECTOR } from "./collector.js";
8
+ import { Clock, Ticker } from "./door.js";
9
+ import { UiContext, UiProvider } from "./wrappers.js";
10
+ function useMedia(query, fallback) {
11
+ const subscribe = useCallback((onChange) => {
12
+ if (typeof globalThis.matchMedia !== 'function')
13
+ return () => { };
14
+ const list = globalThis.matchMedia(query);
15
+ list.addEventListener('change', onChange);
16
+ return () => list.removeEventListener('change', onChange);
17
+ }, [query]);
18
+ const read = useCallback(() => (typeof globalThis.matchMedia === 'function' ? globalThis.matchMedia(query).matches : fallback), [query, fallback]);
19
+ return useSyncExternalStore(subscribe, read, () => fallback);
20
+ }
21
+ function readPalette() {
22
+ if (typeof globalThis.getComputedStyle !== 'function' || typeof globalThis.document !== 'object') {
23
+ return { accent: '', surface: '' };
24
+ }
25
+ const style = globalThis.getComputedStyle(globalThis.document.documentElement);
26
+ const read = (name) => style.getPropertyValue(name).trim();
27
+ return {
28
+ accent: read('--thread-palette-accent'),
29
+ surface: read('--thread-palette-surface'),
30
+ };
31
+ }
32
+ function readEdgeScroll() {
33
+ if (typeof globalThis.getComputedStyle !== 'function' || typeof globalThis.document !== 'object')
34
+ return { ...EDGE_SCROLL_DEFAULTS };
35
+ const style = globalThis.getComputedStyle(globalThis.document.documentElement);
36
+ const read = (name, fallback) => {
37
+ const value = Number.parseFloat(style.getPropertyValue(name));
38
+ return Number.isFinite(value) ? value : fallback;
39
+ };
40
+ return {
41
+ band: read('--thread-edge-scroll-band', EDGE_SCROLL_DEFAULTS.band),
42
+ speed: read('--thread-edge-scroll-speed', EDGE_SCROLL_DEFAULTS.speed),
43
+ };
44
+ }
45
+ export function ThreadUi(props) {
46
+ const existing = useContext(UiContext);
47
+ const opinionated = props.mode !== undefined ||
48
+ props.locale !== undefined ||
49
+ props.palette !== undefined ||
50
+ props.platform !== undefined ||
51
+ props.telemetry !== undefined ||
52
+ props.wording !== undefined ||
53
+ props.config !== undefined;
54
+ const prefersDark = useMedia('(prefers-color-scheme: dark)', false);
55
+ const reduceMotion = useMedia('(prefers-reduced-motion: reduce)', false);
56
+ const appearance = {
57
+ mode: props.mode ?? (prefersDark ? 'dark' : 'light'),
58
+ reduceMotion,
59
+ };
60
+ const language = props.locale ?? 'en';
61
+ const translate = useMemo(() => {
62
+ const held = props.wording?.[language];
63
+ if (props.wording !== undefined && held === undefined) {
64
+ throw new Error(`This app was handed wording and none of it is in "${language}". It has ` +
65
+ `${Object.keys(props.wording).sort().join(', ')} — declare the language in ` +
66
+ '`_threads/localizations.ts` and run `thread i18n`, or ask for one it is in.');
67
+ }
68
+ return createTranslator(held ?? en, { locale: language });
69
+ }, [language, props.wording]);
70
+ const clock = useMemo(() => new Clock(), []);
71
+ const ticker = useMemo(() => new Ticker(), []);
72
+ const telemetryOff = props.telemetry === undefined;
73
+ const collector = useMemo(() => {
74
+ if (props.telemetry === undefined)
75
+ return INERT_COLLECTOR;
76
+ return createCollector({
77
+ endpoint: props.telemetry.endpoint ?? '/obs/client',
78
+ allowed: props.telemetry.allowed,
79
+ ...(props.telemetry.sample === undefined ? {} : { sample: props.telemetry.sample }),
80
+ ...(typeof navigator === 'object' && typeof navigator.sendBeacon === 'function'
81
+ ? { beacon: (url, body) => navigator.sendBeacon(url, new Blob([body], { type: 'application/json' })) }
82
+ : {}),
83
+ });
84
+ }, [telemetryOff, props.telemetry?.endpoint, props.telemetry?.sample, props.telemetry?.allowed]);
85
+ useEffect(() => () => collector.stop(), [collector]);
86
+ const derived = useMemo(() => ({
87
+ palette: props.palette ?? readPalette(),
88
+ appearance,
89
+ clock,
90
+ ticker,
91
+ now: () => Date.now(),
92
+ edgeScroll: readEdgeScroll(),
93
+ ...(props.actor === undefined ? {} : { actor: props.actor }),
94
+ ...(props.asking === undefined ? {} : { asking: props.asking }),
95
+ ...(props.platform === undefined ? {} : { platform: props.platform }),
96
+ ...(props.dispatch === undefined ? {} : { dispatch: props.dispatch }),
97
+ ...(props.navigateTo === undefined ? {} : { navigateTo: props.navigateTo }),
98
+ collector,
99
+ translate: (key, params) => translate(key, params),
100
+ }), [props.actor, props.asking, props.palette, props.platform, props.dispatch, props.navigateTo, appearance.mode, appearance.reduceMotion, clock, ticker, collector, translate]);
101
+ if (existing !== null && !opinionated)
102
+ return props.children;
103
+ return _jsx(UiProvider, { config: props.config ?? derived, children: props.children });
104
+ }
@@ -0,0 +1,12 @@
1
+ export interface RenderLoop {
2
+ readonly component: string;
3
+ readonly renders: number;
4
+ readonly withinMs: number;
5
+ readonly unstable: readonly string[];
6
+ readonly differing: readonly string[];
7
+ }
8
+ export declare class RenderLoopError extends Error {
9
+ readonly loop: RenderLoop;
10
+ constructor(loop: RenderLoop);
11
+ }
12
+ export declare function useRenderLoopDetector(component: string, props: Record<string, unknown>): void;
@@ -0,0 +1,94 @@
1
+ 'use client';
2
+ import { useRef } from 'react';
3
+ const RENDER_LIMIT = 40;
4
+ const WINDOW_MS = 1000;
5
+ const COMPARE_DEPTH = 3;
6
+ function armed() {
7
+ return process.env.NODE_ENV !== 'production';
8
+ }
9
+ export class RenderLoopError extends Error {
10
+ loop;
11
+ constructor(loop) {
12
+ super(describe(loop));
13
+ this.name = 'RenderLoopError';
14
+ this.loop = loop;
15
+ }
16
+ }
17
+ function describe(loop) {
18
+ const head = `${loop.component} rendered ${loop.renders} times in ${loop.withinMs}ms, which is a render loop.`;
19
+ if (loop.unstable.length > 0) {
20
+ const props = loop.unstable.join(', ');
21
+ return (`${head} ${props} arrived with a new identity every render while its value stayed equal, so ` +
22
+ `every render caused the next one. Return the same object for the same answer — that is the ` +
23
+ `read layer's job (ADR-180 rule 10), not the component's — or compute the value inside render ` +
24
+ `instead of syncing it into state from an effect (rule 11).`);
25
+ }
26
+ if (loop.differing.length > 0) {
27
+ return (`${head} ${loop.differing.join(', ')} changed VALUE on every render, so this is not an identity ` +
28
+ `problem: something is writing during render. Move the write to an event or an action.`);
29
+ }
30
+ return (`${head} No prop changed at all, so the re-render comes from state or context inside the ` +
31
+ `component — look for a setter called from an effect body (ADR-180 rule 11).`);
32
+ }
33
+ function equalValue(a, b, depth = 0) {
34
+ if (Object.is(a, b))
35
+ return true;
36
+ if (depth >= COMPARE_DEPTH)
37
+ return false;
38
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
39
+ return false;
40
+ if (Array.isArray(a) || Array.isArray(b)) {
41
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)
42
+ return false;
43
+ return a.every((item, index) => equalValue(item, b[index], depth + 1));
44
+ }
45
+ const left = a;
46
+ const right = b;
47
+ const keys = Object.keys(left);
48
+ if (keys.length !== Object.keys(right).length)
49
+ return false;
50
+ return keys.every((key) => key in right && equalValue(left[key], right[key], depth + 1));
51
+ }
52
+ function compare(previous, next) {
53
+ const unstable = [];
54
+ const differing = [];
55
+ for (const key of [...new Set([...Object.keys(previous), ...Object.keys(next)])].sort()) {
56
+ if (Object.is(previous[key], next[key]))
57
+ continue;
58
+ if (equalValue(previous[key], next[key]))
59
+ unstable.push(key);
60
+ else
61
+ differing.push(key);
62
+ }
63
+ return { unstable, differing };
64
+ }
65
+ export function useRenderLoopDetector(component, props) {
66
+ const renders = useRef(0);
67
+ const openedAt = useRef(0);
68
+ const previous = useRef(undefined);
69
+ const tripped = useRef(undefined);
70
+ if (armed()) {
71
+ if (tripped.current !== undefined)
72
+ throw new RenderLoopError(tripped.current);
73
+ const now = Date.now();
74
+ const elapsed = now - openedAt.current;
75
+ if (openedAt.current === 0 || elapsed > WINDOW_MS) {
76
+ openedAt.current = now;
77
+ renders.current = 0;
78
+ }
79
+ renders.current += 1;
80
+ if (renders.current > RENDER_LIMIT) {
81
+ const loop = {
82
+ component,
83
+ renders: renders.current,
84
+ withinMs: now - openedAt.current,
85
+ ...compare(previous.current ?? {}, props),
86
+ };
87
+ tripped.current = loop;
88
+ renders.current = 0;
89
+ openedAt.current = now;
90
+ throw new RenderLoopError(loop);
91
+ }
92
+ }
93
+ previous.current = props;
94
+ }
@@ -0,0 +1,15 @@
1
+ import { type RefObject } from 'react';
2
+ export declare const ITEM_ATTR = "data-roving-item";
3
+ export interface RovingOptions {
4
+ readonly orientation: 'vertical' | 'horizontal';
5
+ readonly wrap?: boolean;
6
+ readonly active?: boolean;
7
+ }
8
+ interface Item {
9
+ readonly element: HTMLElement;
10
+ readonly disabled: boolean;
11
+ readonly text: string;
12
+ }
13
+ export declare function typeaheadMatch(list: readonly Item[], buffer: string, current: number): number;
14
+ export declare function useRovingFocus(ref: RefObject<HTMLElement | null>, options: RovingOptions): void;
15
+ export {};
@@ -0,0 +1,143 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useRef } from 'react';
3
+ export const ITEM_ATTR = 'data-roving-item';
4
+ function items(root) {
5
+ if (root === null)
6
+ return [];
7
+ return [...root.querySelectorAll(`[${ITEM_ATTR}]`)].map((element) => ({
8
+ element,
9
+ disabled: element.hasAttribute('disabled') || element.getAttribute('aria-disabled') === 'true',
10
+ text: (element.textContent ?? '').trim().toLowerCase(),
11
+ }));
12
+ }
13
+ function step(list, from, direction, wrap) {
14
+ const count = list.length;
15
+ if (count === 0)
16
+ return -1;
17
+ let index = from;
18
+ for (let moved = 0; moved < count; moved += 1) {
19
+ const next = index + direction;
20
+ if (next < 0 || next >= count) {
21
+ if (!wrap)
22
+ return from;
23
+ index = direction === 1 ? 0 : count - 1;
24
+ }
25
+ else {
26
+ index = next;
27
+ }
28
+ if (!list[index].disabled)
29
+ return index;
30
+ }
31
+ return from;
32
+ }
33
+ function firstEnabled(list, from = 0) {
34
+ for (let i = from; i < list.length; i += 1)
35
+ if (!list[i].disabled)
36
+ return i;
37
+ return -1;
38
+ }
39
+ function lastEnabled(list) {
40
+ for (let i = list.length - 1; i >= 0; i -= 1)
41
+ if (!list[i].disabled)
42
+ return i;
43
+ return -1;
44
+ }
45
+ function isRtl(element) {
46
+ const declared = element.closest('[dir]')?.getAttribute('dir')?.toLowerCase();
47
+ if (declared === 'rtl')
48
+ return true;
49
+ if (declared === 'ltr')
50
+ return false;
51
+ return getComputedStyle(element).direction === 'rtl';
52
+ }
53
+ const TYPEAHEAD_MS = 1000;
54
+ export function typeaheadMatch(list, buffer, current) {
55
+ const enabled = list.map((item, index) => ({ item, index })).filter(({ item }) => !item.disabled);
56
+ if (enabled.length === 0 || buffer.length === 0)
57
+ return -1;
58
+ const repeated = buffer.length > 1 && [...buffer].every((c) => c === buffer[0]);
59
+ const prefix = repeated ? buffer[0] : buffer;
60
+ const startAt = enabled.findIndex(({ index }) => index === current);
61
+ for (let i = 0; i < enabled.length; i += 1) {
62
+ const candidate = enabled[(startAt + 1 + i) % enabled.length];
63
+ if (candidate.item.text.startsWith(prefix))
64
+ return candidate.index;
65
+ }
66
+ return -1;
67
+ }
68
+ export function useRovingFocus(ref, options) {
69
+ const { orientation, wrap = false, active = true } = options;
70
+ const indexRef = useRef(0);
71
+ const bufferRef = useRef('');
72
+ const timerRef = useRef(undefined);
73
+ const applyTabIndex = useCallback((list, index) => {
74
+ list.forEach((item, i) => {
75
+ item.element.setAttribute('tabindex', i === index ? '0' : '-1');
76
+ });
77
+ }, []);
78
+ useEffect(() => {
79
+ if (!active)
80
+ return;
81
+ const root = ref.current;
82
+ if (root === null)
83
+ return;
84
+ const list = items(root);
85
+ const start = firstEnabled(list);
86
+ indexRef.current = start === -1 ? 0 : start;
87
+ applyTabIndex(list, indexRef.current);
88
+ const move = (to) => {
89
+ const current = items(root);
90
+ if (to < 0 || to >= current.length)
91
+ return;
92
+ indexRef.current = to;
93
+ applyTabIndex(current, to);
94
+ current[to].element.focus();
95
+ };
96
+ const onKeyDown = (event) => {
97
+ const current = items(root);
98
+ if (current.length === 0)
99
+ return;
100
+ const rtl = isRtl(root);
101
+ const forward = orientation === 'horizontal' ? (rtl ? 'ArrowLeft' : 'ArrowRight') : 'ArrowDown';
102
+ const backward = orientation === 'horizontal' ? (rtl ? 'ArrowRight' : 'ArrowLeft') : 'ArrowUp';
103
+ if (event.key === forward) {
104
+ event.preventDefault();
105
+ move(step(current, indexRef.current, 1, wrap));
106
+ return;
107
+ }
108
+ if (event.key === backward) {
109
+ event.preventDefault();
110
+ move(step(current, indexRef.current, -1, wrap));
111
+ return;
112
+ }
113
+ if (event.key === 'Home') {
114
+ event.preventDefault();
115
+ move(firstEnabled(current));
116
+ return;
117
+ }
118
+ if (event.key === 'End') {
119
+ event.preventDefault();
120
+ move(lastEnabled(current));
121
+ return;
122
+ }
123
+ if (event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey)
124
+ return;
125
+ event.preventDefault();
126
+ bufferRef.current += event.key.toLowerCase();
127
+ if (timerRef.current !== undefined)
128
+ clearTimeout(timerRef.current);
129
+ timerRef.current = setTimeout(() => {
130
+ bufferRef.current = '';
131
+ }, TYPEAHEAD_MS);
132
+ const found = typeaheadMatch(current, bufferRef.current, indexRef.current);
133
+ if (found !== -1)
134
+ move(found);
135
+ };
136
+ root.addEventListener('keydown', onKeyDown);
137
+ return () => {
138
+ root.removeEventListener('keydown', onKeyDown);
139
+ if (timerRef.current !== undefined)
140
+ clearTimeout(timerRef.current);
141
+ };
142
+ }, [active, orientation, wrap, ref, applyTabIndex]);
143
+ }
@@ -0,0 +1,17 @@
1
+ import type { Threaded } from '@prestack/thread/core/thread';
2
+ export declare const declares: readonly Threaded[];
3
+ export declare const SCREENS: Threaded & {
4
+ readonly files: string;
5
+ };
6
+ export declare function nameOf(at: string): string;
7
+ export declare const PAGE: "page";
8
+ export declare function presentedIn(source: string): string;
9
+ export declare function routeFor(id: string, entry: boolean): string;
10
+ export declare function pageAt(route: string): string;
11
+ export declare function entryAmong(rows: readonly {
12
+ readonly id: string;
13
+ }[], shownAs: (id: string) => string): string | undefined;
14
+ export declare function seeds(rows: readonly Threaded[], held: (at: string) => boolean): readonly {
15
+ readonly path: string;
16
+ readonly content: string;
17
+ }[];
@@ -0,0 +1,112 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
10
+ import { basename, dirname, join } from 'node:path';
11
+ import { stdout } from 'node:process';
12
+ import { pathToFileURL } from 'node:url';
13
+ import { exit, invoked } from "@prestack/thread/core/invoked";
14
+ import { findTree, inTree } from "@prestack/thread/core/tree";
15
+ import { undeclared } from "./compositions.js";
16
+ import { PRESENTATIONS } from "./door.js";
17
+ const here = 'thread/ui/screens.ts';
18
+ const said = [
19
+ {
20
+ on: '2026-08-25',
21
+ said: 'Screens are basically compositions arranged in a screen. And this is where we have breakpoint, etc. Compositions maybe also have breakpoints.',
22
+ },
23
+ {
24
+ on: '2026-08-25',
25
+ said: 'Arrangement is a real fucking thing. IT IS HOW THE STUFF LOOKS IN A SCREEN',
26
+ },
27
+ {
28
+ on: '2026-08-25',
29
+ said: 'Both',
30
+ },
31
+ {
32
+ on: '2026-09-09',
33
+ said: 'We have one screen or more. A button navigates to other screen. From THAT the routes are generated.',
34
+ },
35
+ ];
36
+ export const declares = [];
37
+ export const SCREENS = {
38
+ id: 'screen',
39
+ at: here,
40
+ files: 'screens/scr_*.tsx',
41
+ describes: 'Compositions arranged, and the way it is presented: page, sheet, popover, overlay or toast. Where it lives is never typed. The first page an app declares answers `/`, every other page answers its own name, and a sheet, popover, overlay or toast has no route, because a press opens it where somebody already is. The arrangement is the whole of what a screen adds, because how things sit on a screen is declared rather than markup written twice. Each row names a file prefixed `scr_`, sets the properties that lay its compositions out, and may set them differently under a mode, which is where a breakpoint lives: a width is a media query the same way dark is. A composition may set its own arrangement too. The framework ships none, because what an app is made of is the app’s, and this row says what a screen is, never what is inside it.',
42
+ version: 1,
43
+ cites: said,
44
+ declares,
45
+ };
46
+ const PASCAL = (id) => id
47
+ .split(/[-_]/)
48
+ .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
49
+ .join('');
50
+ export function nameOf(at) {
51
+ const file = at.split('\\').join('/').split('/').at(-1) ?? at;
52
+ return PASCAL(file.replace(/^scr_/, '').replace(/\.[^.]+$/, ''));
53
+ }
54
+ export const PAGE = PRESENTATIONS[0];
55
+ const PRESENTED = /screen\(\s*'[^']*'\s*,\s*\{[^}]*as:\s*'([^']*)'/;
56
+ export function presentedIn(source) {
57
+ return PRESENTED.exec(source)?.[1] ?? PAGE;
58
+ }
59
+ export function routeFor(id, entry) {
60
+ return entry ? '/' : `/${id}`;
61
+ }
62
+ export function pageAt(route) {
63
+ const trimmed = route.replace(/^\/+|\/+$/g, '');
64
+ return trimmed === '' ? `app/page.${'tsx'}` : `app/${trimmed}/page.${'tsx'}`;
65
+ }
66
+ export function entryAmong(rows, shownAs) {
67
+ return rows.find((row) => shownAs(row.id) === PAGE)?.id;
68
+ }
69
+ function starter(row) {
70
+ const name = nameOf(row.at);
71
+ return `'use client'
72
+
73
+ import { screen } from './wrappers.tsx'
74
+
75
+ export const ${name} = screen('${row.id}', {}, () => (
76
+ <>
77
+ </>
78
+ ))
79
+ `;
80
+ }
81
+ export function seeds(rows, held) {
82
+ return rows.filter((row) => !held(row.at)).map((row) => ({ path: row.at, content: starter(row) }));
83
+ }
84
+ async function run() {
85
+ const tree = findTree();
86
+ const at = inTree(tree, 'screens.ts');
87
+ if (!existsSync(at)) {
88
+ stdout.write(`thread: this tree has no ${tree.name}/${basename(at)}, so it declares no screen and there is nothing to seed or check.\n`);
89
+ return 0;
90
+ }
91
+ const held = (await import(__rewriteRelativeImportExtension(pathToFileURL(at).href)));
92
+ if (held.SCREEN === undefined) {
93
+ stdout.write(`thread: ${tree.name}/screens.ts exports no \`SCREEN\`, so nothing declares a screen here.\n`);
94
+ return 1;
95
+ }
96
+ const rows = held.SCREEN.declares ?? [];
97
+ const made = seeds(rows, (where) => existsSync(join(tree.at, where)));
98
+ for (const one of made) {
99
+ mkdirSync(dirname(join(tree.at, one.path)), { recursive: true });
100
+ writeFileSync(join(tree.at, one.path), one.content, 'utf8');
101
+ stdout.write(`thread: seeded ${one.path}\n`);
102
+ }
103
+ const loose = await undeclared(tree, rows);
104
+ for (const one of loose)
105
+ stdout.write(`thread: ${one}\n`);
106
+ stdout.write(`thread: ${String(rows.length)} screen(s) declared, ${String(made.length)} seeded, ` +
107
+ `${String(rows.length - made.length)} already written, ` +
108
+ `${loose.length === 0 ? 'none reaching anything undeclared' : `${String(loose.length)} reaching something undeclared`}\n`);
109
+ return loose.length === 0 ? 0 : 1;
110
+ }
111
+ if (invoked(import.meta.url))
112
+ exit(await run());
@@ -0,0 +1,2 @@
1
+ export declare function lockScroll(): () => void;
2
+ export declare function scrollLocks(): number;