knobkit 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 (361) hide show
  1. package/LICENSE +21 -0
  2. package/dist/assets/cell-renderer-CLTRlCa5-DIlwS99c.js +1 -0
  3. package/dist/assets/chart-D8ctp-_1.js +36 -0
  4. package/dist/assets/code-BMuLQBYq.js +2 -0
  5. package/dist/assets/column.service-C6hByxPy-XG9X0y3N.js +1 -0
  6. package/dist/assets/debounce-PCRWZliA-BjJpj_P7.js +32 -0
  7. package/dist/assets/dimension.helpers-CGKwSvw6-D_czicbS.js +1 -0
  8. package/dist/assets/dist-1hsZpGRf.js +23 -0
  9. package/dist/assets/dist-B-y4Etc5.js +1 -0
  10. package/dist/assets/dist-B8BXgMDk.js +10 -0
  11. package/dist/assets/dist-BJlXPLNt.js +1 -0
  12. package/dist/assets/dist-ByhR2UY_.js +1 -0
  13. package/dist/assets/dist-C0bxYHYH.js +2 -0
  14. package/dist/assets/dist-C8dagUDy.js +6 -0
  15. package/dist/assets/dist-CtLpohkg.js +1 -0
  16. package/dist/assets/dist-D00mNtIr.js +1 -0
  17. package/dist/assets/dist-Dh1Dvy3h.js +1 -0
  18. package/dist/assets/dist-DlwQ1Qqm.js +1 -0
  19. package/dist/assets/dist-DtZDI7jp.js +1 -0
  20. package/dist/assets/dist-thZFs69d.js +9 -0
  21. package/dist/assets/edit.utils-Dnnbd0xG-OAxDw8WC.js +1 -0
  22. package/dist/assets/events-BvSmBueA-4kqQ57iN.js +1 -0
  23. package/dist/assets/filter.button-BFwo1uvz-CyvQhOO5.js +1 -0
  24. package/dist/assets/header-cell-renderer-BMmXRsd_-BHbC7fao.js +1 -0
  25. package/dist/assets/index-Db3qZoW5-peeY7EGw.js +1 -0
  26. package/dist/assets/markdown-dDCgur7g.js +29 -0
  27. package/dist/assets/revo-grid.entry-CfI6s-uT.js +1 -0
  28. package/dist/assets/revogr-attribution_7.entry-6fUjzImt.js +1 -0
  29. package/dist/assets/revogr-clipboard_3.entry-DmI7LkER.js +2 -0
  30. package/dist/assets/revogr-data_4.entry-CYZIiXNw.js +1 -0
  31. package/dist/assets/revogr-filter-panel.entry-TmQHTQxw.js +1 -0
  32. package/dist/assets/table-Zn7rpfG-.js +1 -0
  33. package/dist/assets/text-editor-C3RUSwH5-DuDr9wKc.js +1 -0
  34. package/dist/assets/theme.service-BmnDvr6P-DftEgmbe.js +3 -0
  35. package/dist/assets/throttle-CaUDyxyU-Djj__DCp.js +1 -0
  36. package/dist/assets/viewport.helpers-CoCAvmZs-ByVRjjkF.js +1 -0
  37. package/dist/assets/viewport.store-_c579YyM-B_ZSqqka.js +1 -0
  38. package/dist/cli/config.d.ts +5 -0
  39. package/dist/cli/config.js +82 -0
  40. package/dist/cli/index.d.ts +2 -0
  41. package/dist/cli/index.js +77 -0
  42. package/dist/cli/mount.d.ts +2 -0
  43. package/dist/cli/mount.js +26 -0
  44. package/dist/cli/serve.d.ts +1 -0
  45. package/dist/cli/serve.js +21 -0
  46. package/dist/client/app.d.ts +8 -0
  47. package/dist/client/app.js +40 -0
  48. package/dist/client/context.d.ts +2 -0
  49. package/dist/client/context.js +16 -0
  50. package/dist/client/mount.d.ts +3 -0
  51. package/dist/client/mount.js +42 -0
  52. package/dist/client/runtime.d.ts +19 -0
  53. package/dist/client/runtime.js +88 -0
  54. package/dist/client/view.d.ts +12 -0
  55. package/dist/client/view.js +1 -0
  56. package/dist/client/widgets/accordion/index.d.ts +5 -0
  57. package/dist/client/widgets/accordion/index.js +8 -0
  58. package/dist/client/widgets/annotated-image/index.d.ts +8 -0
  59. package/dist/client/widgets/annotated-image/index.js +34 -0
  60. package/dist/client/widgets/audio/index.d.ts +5 -0
  61. package/dist/client/widgets/audio/index.js +5 -0
  62. package/dist/client/widgets/button/index.d.ts +4 -0
  63. package/dist/client/widgets/button/index.js +5 -0
  64. package/dist/client/widgets/chart/index.d.ts +5 -0
  65. package/dist/client/widgets/chart/index.js +23 -0
  66. package/dist/client/widgets/chart/lazy.d.ts +3 -0
  67. package/dist/client/widgets/chart/lazy.js +9 -0
  68. package/dist/client/widgets/chat/index.d.ts +6 -0
  69. package/dist/client/widgets/chat/index.js +77 -0
  70. package/dist/client/widgets/checkbox/index.d.ts +6 -0
  71. package/dist/client/widgets/checkbox/index.js +9 -0
  72. package/dist/client/widgets/checkbox-group/index.d.ts +6 -0
  73. package/dist/client/widgets/checkbox-group/index.js +12 -0
  74. package/dist/client/widgets/code/index.d.ts +5 -0
  75. package/dist/client/widgets/code/index.js +101 -0
  76. package/dist/client/widgets/code/lazy.d.ts +3 -0
  77. package/dist/client/widgets/code/lazy.js +10 -0
  78. package/dist/client/widgets/dropdown/index.d.ts +5 -0
  79. package/dist/client/widgets/dropdown/index.js +9 -0
  80. package/dist/client/widgets/file/index.d.ts +6 -0
  81. package/dist/client/widgets/file/index.js +7 -0
  82. package/dist/client/widgets/frame/index.d.ts +6 -0
  83. package/dist/client/widgets/frame/index.js +11 -0
  84. package/dist/client/widgets/gallery/index.d.ts +6 -0
  85. package/dist/client/widgets/gallery/index.js +8 -0
  86. package/dist/client/widgets/highlighted-text/index.d.ts +7 -0
  87. package/dist/client/widgets/highlighted-text/index.js +20 -0
  88. package/dist/client/widgets/html/index.d.ts +4 -0
  89. package/dist/client/widgets/html/index.js +8 -0
  90. package/dist/client/widgets/image/index.d.ts +4 -0
  91. package/dist/client/widgets/image/index.js +4 -0
  92. package/dist/client/widgets/json/index.d.ts +4 -0
  93. package/dist/client/widgets/json/index.js +4 -0
  94. package/dist/client/widgets/label/index.d.ts +7 -0
  95. package/dist/client/widgets/label/index.js +8 -0
  96. package/dist/client/widgets/layout/index.d.ts +4 -0
  97. package/dist/client/widgets/layout/index.js +7 -0
  98. package/dist/client/widgets/log/index.d.ts +4 -0
  99. package/dist/client/widgets/log/index.js +4 -0
  100. package/dist/client/widgets/mic/index.d.ts +6 -0
  101. package/dist/client/widgets/mic/index.js +70 -0
  102. package/dist/client/widgets/number/index.d.ts +5 -0
  103. package/dist/client/widgets/number/index.js +8 -0
  104. package/dist/client/widgets/output/index.d.ts +6 -0
  105. package/dist/client/widgets/output/index.js +13 -0
  106. package/dist/client/widgets/output/markdown.d.ts +3 -0
  107. package/dist/client/widgets/output/markdown.js +8 -0
  108. package/dist/client/widgets/progress/index.d.ts +6 -0
  109. package/dist/client/widgets/progress/index.js +6 -0
  110. package/dist/client/widgets/radio/index.d.ts +6 -0
  111. package/dist/client/widgets/radio/index.js +10 -0
  112. package/dist/client/widgets/registry.d.ts +2 -0
  113. package/dist/client/widgets/registry.js +69 -0
  114. package/dist/client/widgets/slider/index.d.ts +6 -0
  115. package/dist/client/widgets/slider/index.js +9 -0
  116. package/dist/client/widgets/table/index.d.ts +6 -0
  117. package/dist/client/widgets/table/index.js +72 -0
  118. package/dist/client/widgets/table/lazy.d.ts +3 -0
  119. package/dist/client/widgets/table/lazy.js +16 -0
  120. package/dist/client/widgets/tabs/index.d.ts +5 -0
  121. package/dist/client/widgets/tabs/index.js +10 -0
  122. package/dist/client/widgets/text/index.d.ts +6 -0
  123. package/dist/client/widgets/text/index.js +10 -0
  124. package/dist/client/widgets/upload/index.d.ts +6 -0
  125. package/dist/client/widgets/upload/index.js +16 -0
  126. package/dist/client/widgets/video/index.d.ts +5 -0
  127. package/dist/client/widgets/video/index.js +5 -0
  128. package/dist/client/widgets/webcam/index.d.ts +6 -0
  129. package/dist/client/widgets/webcam/index.js +62 -0
  130. package/dist/client.css +1 -0
  131. package/dist/client.js +11 -0
  132. package/dist/knobkit.browser.css +2 -0
  133. package/dist/knobkit.browser.js +151 -0
  134. package/dist/lib/bound.d.ts +12 -0
  135. package/dist/lib/bound.js +10 -0
  136. package/dist/lib/controls.d.ts +9 -0
  137. package/dist/lib/controls.js +35 -0
  138. package/dist/lib/ctx.d.ts +9 -0
  139. package/dist/lib/ctx.js +22 -0
  140. package/dist/lib/declare.d.ts +18 -0
  141. package/dist/lib/declare.js +43 -0
  142. package/dist/lib/event.d.ts +2 -0
  143. package/dist/lib/event.js +9 -0
  144. package/dist/lib/index.d.ts +10 -0
  145. package/dist/lib/index.js +6 -0
  146. package/dist/lib/knobkit.d.ts +19 -0
  147. package/dist/lib/knobkit.js +48 -0
  148. package/dist/lib/on.d.ts +2 -0
  149. package/dist/lib/on.js +1 -0
  150. package/dist/lib/stream.d.ts +1 -0
  151. package/dist/lib/stream.js +33 -0
  152. package/dist/lib/types.d.ts +48 -0
  153. package/dist/lib/types.js +1 -0
  154. package/dist/lib/widget.d.ts +7 -0
  155. package/dist/lib/widget.js +4 -0
  156. package/dist/lib/widgets/annotated-image.d.ts +14 -0
  157. package/dist/lib/widgets/annotated-image.js +16 -0
  158. package/dist/lib/widgets/audio.d.ts +10 -0
  159. package/dist/lib/widgets/audio.js +13 -0
  160. package/dist/lib/widgets/button.d.ts +11 -0
  161. package/dist/lib/widgets/button.js +17 -0
  162. package/dist/lib/widgets/chart.d.ts +20 -0
  163. package/dist/lib/widgets/chart.js +24 -0
  164. package/dist/lib/widgets/chat.d.ts +26 -0
  165. package/dist/lib/widgets/chat.js +24 -0
  166. package/dist/lib/widgets/checkbox-group.d.ts +4 -0
  167. package/dist/lib/widgets/checkbox-group.js +5 -0
  168. package/dist/lib/widgets/checkbox.d.ts +4 -0
  169. package/dist/lib/widgets/checkbox.js +4 -0
  170. package/dist/lib/widgets/code.d.ts +5 -0
  171. package/dist/lib/widgets/code.js +10 -0
  172. package/dist/lib/widgets/dropdown.d.ts +4 -0
  173. package/dist/lib/widgets/dropdown.js +4 -0
  174. package/dist/lib/widgets/embed.d.ts +5 -0
  175. package/dist/lib/widgets/embed.js +23 -0
  176. package/dist/lib/widgets/file.d.ts +11 -0
  177. package/dist/lib/widgets/file.js +15 -0
  178. package/dist/lib/widgets/frame.d.ts +18 -0
  179. package/dist/lib/widgets/frame.js +25 -0
  180. package/dist/lib/widgets/gallery.d.ts +12 -0
  181. package/dist/lib/widgets/gallery.js +17 -0
  182. package/dist/lib/widgets/highlighted-text.d.ts +12 -0
  183. package/dist/lib/widgets/highlighted-text.js +15 -0
  184. package/dist/lib/widgets/html.d.ts +9 -0
  185. package/dist/lib/widgets/html.js +12 -0
  186. package/dist/lib/widgets/image.d.ts +7 -0
  187. package/dist/lib/widgets/image.js +12 -0
  188. package/dist/lib/widgets/index.d.ts +31 -0
  189. package/dist/lib/widgets/index.js +31 -0
  190. package/dist/lib/widgets/json.d.ts +7 -0
  191. package/dist/lib/widgets/json.js +12 -0
  192. package/dist/lib/widgets/label.d.ts +15 -0
  193. package/dist/lib/widgets/label.js +18 -0
  194. package/dist/lib/widgets/layout.d.ts +21 -0
  195. package/dist/lib/widgets/layout.js +29 -0
  196. package/dist/lib/widgets/log.d.ts +8 -0
  197. package/dist/lib/widgets/log.js +15 -0
  198. package/dist/lib/widgets/mic.d.ts +19 -0
  199. package/dist/lib/widgets/mic.js +28 -0
  200. package/dist/lib/widgets/number.d.ts +5 -0
  201. package/dist/lib/widgets/number.js +4 -0
  202. package/dist/lib/widgets/output.d.ts +10 -0
  203. package/dist/lib/widgets/output.js +13 -0
  204. package/dist/lib/widgets/progress.d.ts +10 -0
  205. package/dist/lib/widgets/progress.js +15 -0
  206. package/dist/lib/widgets/radio.d.ts +4 -0
  207. package/dist/lib/widgets/radio.js +5 -0
  208. package/dist/lib/widgets/slider.d.ts +6 -0
  209. package/dist/lib/widgets/slider.js +6 -0
  210. package/dist/lib/widgets/table.d.ts +32 -0
  211. package/dist/lib/widgets/table.js +36 -0
  212. package/dist/lib/widgets/text.d.ts +4 -0
  213. package/dist/lib/widgets/text.js +4 -0
  214. package/dist/lib/widgets/upload.d.ts +3 -0
  215. package/dist/lib/widgets/upload.js +5 -0
  216. package/dist/lib/widgets/value.d.ts +9 -0
  217. package/dist/lib/widgets/value.js +20 -0
  218. package/dist/lib/widgets/video.d.ts +12 -0
  219. package/dist/lib/widgets/video.js +14 -0
  220. package/dist/lib/widgets/webcam.d.ts +21 -0
  221. package/dist/lib/widgets/webcam.js +29 -0
  222. package/dist/server/context.d.ts +2 -0
  223. package/dist/server/context.js +10 -0
  224. package/dist/server/serve.d.ts +5 -0
  225. package/dist/server/serve.js +131 -0
  226. package/package.json +71 -0
  227. package/src/cli/config.ts +83 -0
  228. package/src/cli/index.ts +82 -0
  229. package/src/cli/mount.ts +25 -0
  230. package/src/cli/serve.ts +22 -0
  231. package/src/client/app.test.tsx +70 -0
  232. package/src/client/app.tsx +62 -0
  233. package/src/client/browser-runtime.test.ts +22 -0
  234. package/src/client/browser.ts +3 -0
  235. package/src/client/context.ts +17 -0
  236. package/src/client/embed.test.tsx +58 -0
  237. package/src/client/entry.tsx +25 -0
  238. package/src/client/mount.test.tsx +36 -0
  239. package/src/client/mount.tsx +48 -0
  240. package/src/client/runtime.test.ts +64 -0
  241. package/src/client/runtime.ts +112 -0
  242. package/src/client/serve-stub.ts +3 -0
  243. package/src/client/styles.css +131 -0
  244. package/src/client/view.ts +16 -0
  245. package/src/client/widgets/accordion/accordion.css +35 -0
  246. package/src/client/widgets/accordion/index.tsx +17 -0
  247. package/src/client/widgets/annotated-image/annotated-image.css +62 -0
  248. package/src/client/widgets/annotated-image/index.tsx +73 -0
  249. package/src/client/widgets/audio/audio.css +6 -0
  250. package/src/client/widgets/audio/index.tsx +6 -0
  251. package/src/client/widgets/button/button.css +25 -0
  252. package/src/client/widgets/button/index.tsx +11 -0
  253. package/src/client/widgets/chart/chart.css +12 -0
  254. package/src/client/widgets/chart/index.tsx +63 -0
  255. package/src/client/widgets/chart/lazy.tsx +15 -0
  256. package/src/client/widgets/chat/chat.css +97 -0
  257. package/src/client/widgets/chat/index.tsx +121 -0
  258. package/src/client/widgets/checkbox/checkbox.css +15 -0
  259. package/src/client/widgets/checkbox/index.tsx +15 -0
  260. package/src/client/widgets/checkbox-group/checkbox-group.css +20 -0
  261. package/src/client/widgets/checkbox-group/index.tsx +22 -0
  262. package/src/client/widgets/code/code.css +31 -0
  263. package/src/client/widgets/code/index.tsx +108 -0
  264. package/src/client/widgets/code/lazy.tsx +16 -0
  265. package/src/client/widgets/dropdown/dropdown.css +0 -0
  266. package/src/client/widgets/dropdown/index.tsx +19 -0
  267. package/src/client/widgets/file/file.css +26 -0
  268. package/src/client/widgets/file/index.tsx +12 -0
  269. package/src/client/widgets/frame/frame.css +17 -0
  270. package/src/client/widgets/frame/index.tsx +15 -0
  271. package/src/client/widgets/gallery/gallery.css +26 -0
  272. package/src/client/widgets/gallery/index.tsx +18 -0
  273. package/src/client/widgets/highlighted-text/highlighted-text.css +21 -0
  274. package/src/client/widgets/highlighted-text/index.tsx +42 -0
  275. package/src/client/widgets/html/index.tsx +8 -0
  276. package/src/client/widgets/image/index.tsx +5 -0
  277. package/src/client/widgets/json/index.tsx +5 -0
  278. package/src/client/widgets/json/json.css +0 -0
  279. package/src/client/widgets/label/index.tsx +20 -0
  280. package/src/client/widgets/label/label.css +39 -0
  281. package/src/client/widgets/layout/index.tsx +14 -0
  282. package/src/client/widgets/log/index.tsx +5 -0
  283. package/src/client/widgets/log/log.css +0 -0
  284. package/src/client/widgets/mic/index.tsx +85 -0
  285. package/src/client/widgets/mic/mic.css +8 -0
  286. package/src/client/widgets/number/index.tsx +10 -0
  287. package/src/client/widgets/number/number.css +0 -0
  288. package/src/client/widgets/output/index.tsx +19 -0
  289. package/src/client/widgets/output/markdown.tsx +12 -0
  290. package/src/client/widgets/output/output.css +75 -0
  291. package/src/client/widgets/progress/index.tsx +14 -0
  292. package/src/client/widgets/progress/progress.css +26 -0
  293. package/src/client/widgets/radio/index.tsx +20 -0
  294. package/src/client/widgets/radio/radio.css +20 -0
  295. package/src/client/widgets/registry.tsx +71 -0
  296. package/src/client/widgets/slider/index.tsx +23 -0
  297. package/src/client/widgets/slider/slider.css +18 -0
  298. package/src/client/widgets/table/index.tsx +95 -0
  299. package/src/client/widgets/table/lazy.tsx +23 -0
  300. package/src/client/widgets/table/table.css +15 -0
  301. package/src/client/widgets/tabs/index.tsx +28 -0
  302. package/src/client/widgets/tabs/tabs.css +30 -0
  303. package/src/client/widgets/text/index.tsx +16 -0
  304. package/src/client/widgets/text/text.css +21 -0
  305. package/src/client/widgets/upload/index.tsx +30 -0
  306. package/src/client/widgets/upload/upload.css +30 -0
  307. package/src/client/widgets/video/index.tsx +10 -0
  308. package/src/client/widgets/video/video.css +8 -0
  309. package/src/client/widgets/webcam/index.tsx +81 -0
  310. package/src/client/widgets/webcam/webcam.css +46 -0
  311. package/src/css.d.ts +1 -0
  312. package/src/env.d.ts +1 -0
  313. package/src/lib/bound.ts +30 -0
  314. package/src/lib/controls.ts +36 -0
  315. package/src/lib/ctx.ts +31 -0
  316. package/src/lib/declare.test.ts +46 -0
  317. package/src/lib/declare.ts +74 -0
  318. package/src/lib/event.ts +12 -0
  319. package/src/lib/index.ts +21 -0
  320. package/src/lib/knobkit.ts +57 -0
  321. package/src/lib/on.ts +3 -0
  322. package/src/lib/stream.ts +38 -0
  323. package/src/lib/types.ts +63 -0
  324. package/src/lib/widget.ts +11 -0
  325. package/src/lib/widgets/annotated-image.ts +34 -0
  326. package/src/lib/widgets/audio.ts +20 -0
  327. package/src/lib/widgets/button.ts +27 -0
  328. package/src/lib/widgets/chart.ts +44 -0
  329. package/src/lib/widgets/chat.ts +43 -0
  330. package/src/lib/widgets/checkbox-group.ts +6 -0
  331. package/src/lib/widgets/checkbox.ts +5 -0
  332. package/src/lib/widgets/code.ts +11 -0
  333. package/src/lib/widgets/dropdown.ts +5 -0
  334. package/src/lib/widgets/embed.ts +26 -0
  335. package/src/lib/widgets/file.ts +23 -0
  336. package/src/lib/widgets/frame.ts +36 -0
  337. package/src/lib/widgets/gallery.ts +29 -0
  338. package/src/lib/widgets/highlighted-text.ts +29 -0
  339. package/src/lib/widgets/html.ts +18 -0
  340. package/src/lib/widgets/image.ts +18 -0
  341. package/src/lib/widgets/index.ts +31 -0
  342. package/src/lib/widgets/json.ts +18 -0
  343. package/src/lib/widgets/label.ts +29 -0
  344. package/src/lib/widgets/layout.ts +47 -0
  345. package/src/lib/widgets/log.ts +22 -0
  346. package/src/lib/widgets/mic.ts +42 -0
  347. package/src/lib/widgets/number.ts +5 -0
  348. package/src/lib/widgets/output.ts +20 -0
  349. package/src/lib/widgets/progress.ts +21 -0
  350. package/src/lib/widgets/radio.ts +6 -0
  351. package/src/lib/widgets/slider.ts +7 -0
  352. package/src/lib/widgets/table.ts +58 -0
  353. package/src/lib/widgets/text.ts +5 -0
  354. package/src/lib/widgets/upload.ts +6 -0
  355. package/src/lib/widgets/value.ts +28 -0
  356. package/src/lib/widgets/video.ts +22 -0
  357. package/src/lib/widgets/webcam.ts +46 -0
  358. package/src/server/context.ts +12 -0
  359. package/src/server/serve.test.ts +121 -0
  360. package/src/server/serve.ts +130 -0
  361. package/tsconfig.base.json +14 -0
@@ -0,0 +1,62 @@
1
+ @layer components {
2
+ .pu-annimg {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 8px;
6
+ }
7
+ .pu-annimg-frame {
8
+ position: relative;
9
+ display: inline-block;
10
+ line-height: 0;
11
+ }
12
+ .pu-annimg-base {
13
+ display: block;
14
+ max-width: 100%;
15
+ border-radius: 8px;
16
+ }
17
+ .pu-annimg-mask {
18
+ position: absolute;
19
+ inset: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ opacity: 0.5;
23
+ mix-blend-mode: multiply;
24
+ pointer-events: none;
25
+ }
26
+ .pu-annimg-box {
27
+ position: absolute;
28
+ border: 2px solid;
29
+ border-radius: 4px;
30
+ box-sizing: border-box;
31
+ }
32
+ .pu-annimg-tag {
33
+ position: absolute;
34
+ top: -1px;
35
+ left: -2px;
36
+ transform: translateY(-100%);
37
+ color: #fff;
38
+ font-size: 11px;
39
+ font-weight: 650;
40
+ line-height: 1.4;
41
+ padding: 1px 5px;
42
+ border-radius: 4px 4px 4px 0;
43
+ white-space: nowrap;
44
+ }
45
+ .pu-annimg-legend {
46
+ display: flex;
47
+ flex-wrap: wrap;
48
+ gap: 6px 12px;
49
+ }
50
+ .pu-annimg-chip {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: 6px;
54
+ font-size: 13px;
55
+ color: var(--pu-muted, #6b7280);
56
+ }
57
+ .pu-annimg-swatch {
58
+ width: 12px;
59
+ height: 12px;
60
+ border-radius: 3px;
61
+ }
62
+ }
@@ -0,0 +1,73 @@
1
+ import "./annotated-image.css";
2
+ import { useState } from "react";
3
+ import type { ViewProps } from "../../view.js";
4
+ import type { Annotation } from "../../../lib/widgets/annotated-image.js";
5
+
6
+ const PALETTE = ["#2563eb", "#16a34a", "#dc2626", "#d97706", "#7c3aed", "#0891b2", "#db2777", "#65a30d"];
7
+
8
+ function colorFor(label: string, colorMap: Record<string, string>): string {
9
+ if (colorMap[label]) return colorMap[label];
10
+ let h = 0;
11
+ for (let i = 0; i < label.length; i++) h = (h * 31 + label.charCodeAt(i)) | 0;
12
+ return PALETTE[Math.abs(h) % PALETTE.length];
13
+ }
14
+
15
+ export function AnnotatedImageView({
16
+ state,
17
+ }: ViewProps<any, { src: string; annotations: Annotation[]; colorMap: Record<string, string> }>) {
18
+ // The image's natural pixel size — only known once the <img> loads — turns the author's pixel boxes
19
+ // into percentages of the (possibly resized) displayed image. Boxes wait for it.
20
+ const [nat, setNat] = useState<{ w: number; h: number } | null>(null);
21
+ if (!state.src) return <div className="pu-output">—</div>;
22
+ const annotations = state.annotations ?? [];
23
+ const colorMap = state.colorMap ?? {};
24
+ // Distinct labels for the legend, in first-seen order.
25
+ const labels = [...new Set(annotations.map((a) => a.label))];
26
+ return (
27
+ <div className="pu-annimg">
28
+ <div className="pu-annimg-frame">
29
+ <img
30
+ className="pu-annimg-base"
31
+ src={state.src}
32
+ alt=""
33
+ onLoad={(e) => setNat({ w: e.currentTarget.naturalWidth, h: e.currentTarget.naturalHeight })}
34
+ />
35
+ {nat &&
36
+ annotations.map((a, i) => {
37
+ const color = colorFor(a.label, colorMap);
38
+ return (
39
+ <span key={i}>
40
+ {a.mask && <img className="pu-annimg-mask" src={a.mask} alt="" />}
41
+ {a.box && (
42
+ <span
43
+ className="pu-annimg-box"
44
+ style={{
45
+ left: `${(a.box[0] / nat.w) * 100}%`,
46
+ top: `${(a.box[1] / nat.h) * 100}%`,
47
+ width: `${((a.box[2] - a.box[0]) / nat.w) * 100}%`,
48
+ height: `${((a.box[3] - a.box[1]) / nat.h) * 100}%`,
49
+ borderColor: color,
50
+ }}
51
+ >
52
+ <span className="pu-annimg-tag" style={{ background: color }}>
53
+ {a.label}
54
+ </span>
55
+ </span>
56
+ )}
57
+ </span>
58
+ );
59
+ })}
60
+ </div>
61
+ {labels.length > 0 && (
62
+ <div className="pu-annimg-legend">
63
+ {labels.map((l) => (
64
+ <span key={l} className="pu-annimg-chip">
65
+ <span className="pu-annimg-swatch" style={{ background: colorFor(l, colorMap) }} />
66
+ {l}
67
+ </span>
68
+ ))}
69
+ </div>
70
+ )}
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,6 @@
1
+ @layer components {
2
+ audio {
3
+ width: 100%;
4
+ display: block;
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ import "./audio.css";
2
+ import type { ViewProps } from "../../view.js";
3
+
4
+ export function AudioView({ widget, state }: ViewProps<any, { src: string }>) {
5
+ return state.src ? <audio src={state.src} controls autoPlay={Boolean(widget.autoplay)} /> : null;
6
+ }
@@ -0,0 +1,25 @@
1
+ @layer components {
2
+ .pu-submit {
3
+ padding: 9px 16px;
4
+ border: none;
5
+ border-radius: 8px;
6
+ background: var(--pu-accent, #2563eb);
7
+ color: #fff;
8
+ font: inherit;
9
+ font-weight: 600;
10
+ cursor: pointer;
11
+ transition: background 0.12s, transform 0.06s;
12
+ }
13
+ .pu-submit:hover {
14
+ background: var(--pu-accent-press, #1d4ed8);
15
+ }
16
+ .pu-submit:active {
17
+ transform: translateY(1px);
18
+ }
19
+ .pu-submit:disabled {
20
+ opacity: 0.55;
21
+ cursor: default;
22
+ background: var(--pu-accent, #2563eb);
23
+ transform: none;
24
+ }
25
+ }
@@ -0,0 +1,11 @@
1
+ import "./button.css";
2
+ import type { ViewProps } from "../../view.js";
3
+ import type { ButtonWidget, ButtonState } from "../../../lib/widgets/button.js";
4
+
5
+ export function ButtonView({ widget, state, enabled, emit }: ViewProps<ButtonWidget, ButtonState>) {
6
+ return (
7
+ <button className="pu-submit" disabled={!enabled} onClick={() => emit(widget.clicked())}>
8
+ {state.label}
9
+ </button>
10
+ );
11
+ }
@@ -0,0 +1,12 @@
1
+ @layer components {
2
+ .pu-chart {
3
+ width: 100%;
4
+ border: 1px solid var(--pu-border, #e3e6ea);
5
+ border-radius: 8px;
6
+ padding: 12px 8px 4px;
7
+ background: #fff;
8
+ }
9
+ .pu-chart .recharts-cartesian-axis-tick text {
10
+ fill: var(--pu-muted, #6b7280);
11
+ }
12
+ }
@@ -0,0 +1,63 @@
1
+ // chart.css is imported by ./lazy.tsx (the static entry wrapper) so it lands in client.css.
2
+ import { ResponsiveContainer, CartesianGrid, XAxis, YAxis, Tooltip, Legend, BarChart, Bar, LineChart, Line, AreaChart, Area } from "recharts";
3
+ import type { ReactElement } from "react";
4
+ import type { ViewProps } from "../../view.js";
5
+ import type { ChartWidget, Point } from "../../../lib/widgets/chart.js";
6
+
7
+ const COLORS = ["#2563eb", "#16a34a", "#dc2626", "#d97706", "#7c3aed"]; // knobkit accent + a small palette
8
+
9
+ export function ChartView({ widget, state }: ViewProps<ChartWidget, { data: Point[] }>) {
10
+ const kind = (widget.kind as string) ?? "bar";
11
+ const x = widget.x as string;
12
+ const series = Array.isArray(widget.y) ? (widget.y as string[]) : [widget.y as string];
13
+ const height = (widget.maxHeight as number) ?? 300;
14
+ const data = state.data;
15
+
16
+ const axes = (
17
+ <>
18
+ <CartesianGrid strokeDasharray="3 3" stroke="var(--pu-border, #e3e6ea)" />
19
+ <XAxis dataKey={x} tick={{ fontSize: 12 }} />
20
+ <YAxis tick={{ fontSize: 12 }} />
21
+ <Tooltip />
22
+ {series.length > 1 && <Legend />}
23
+ </>
24
+ );
25
+
26
+ let inner: ReactElement;
27
+ if (kind === "line") {
28
+ inner = (
29
+ <LineChart data={data}>
30
+ {axes}
31
+ {series.map((k, i) => (
32
+ <Line key={k} type="monotone" dataKey={k} stroke={COLORS[i % COLORS.length]} dot={false} />
33
+ ))}
34
+ </LineChart>
35
+ );
36
+ } else if (kind === "area") {
37
+ inner = (
38
+ <AreaChart data={data}>
39
+ {axes}
40
+ {series.map((k, i) => (
41
+ <Area key={k} type="monotone" dataKey={k} stroke={COLORS[i % COLORS.length]} fill={COLORS[i % COLORS.length]} fillOpacity={0.2} />
42
+ ))}
43
+ </AreaChart>
44
+ );
45
+ } else {
46
+ inner = (
47
+ <BarChart data={data}>
48
+ {axes}
49
+ {series.map((k, i) => (
50
+ <Bar key={k} dataKey={k} fill={COLORS[i % COLORS.length]} />
51
+ ))}
52
+ </BarChart>
53
+ );
54
+ }
55
+
56
+ return (
57
+ <div className="pu-chart">
58
+ <ResponsiveContainer width="100%" height={height}>
59
+ {inner}
60
+ </ResponsiveContainer>
61
+ </div>
62
+ );
63
+ }
@@ -0,0 +1,15 @@
1
+ import "./chart.css"; // kept in the entry bundle (client.css) so no /assets css chunk to serve
2
+ import { lazy, Suspense, type ComponentType } from "react";
3
+ import type { ViewProps } from "../../view.js";
4
+
5
+ // Recharts is sizeable; load it only when an app actually renders a chart widget.
6
+ const Impl = lazy(async () => ({ default: (await import("./index.js")).ChartView as unknown as ComponentType<ViewProps> }));
7
+
8
+ export function ChartView(props: ViewProps) {
9
+ const height = ((props.widget as { maxHeight?: number }).maxHeight ?? 300) + 16; // + container padding
10
+ return (
11
+ <Suspense fallback={<div className="pu-chart" style={{ height }} />}>
12
+ <Impl {...props} />
13
+ </Suspense>
14
+ );
15
+ }
@@ -0,0 +1,97 @@
1
+ @layer components {
2
+ .pu-chat {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 8px;
6
+ }
7
+ .pu-msg {
8
+ margin: 0;
9
+ max-width: 85%;
10
+ padding: 8px 12px;
11
+ border-radius: 12px;
12
+ white-space: pre-wrap;
13
+ word-break: break-word;
14
+ }
15
+ .pu-msg b {
16
+ display: none;
17
+ }
18
+ .pu-user {
19
+ align-self: flex-end;
20
+ background: var(--pu-accent, #2563eb);
21
+ color: #fff;
22
+ border-bottom-right-radius: 4px;
23
+ }
24
+ .pu-assistant {
25
+ align-self: flex-start;
26
+ background: #f1f3f5;
27
+ color: var(--pu-text, #1c1f23);
28
+ border-bottom-left-radius: 4px;
29
+ }
30
+ .pu-composer {
31
+ display: flex;
32
+ gap: 8px;
33
+ align-items: center;
34
+ margin-top: 4px;
35
+ }
36
+ .pu-composer .pu-input {
37
+ flex: 1;
38
+ }
39
+ .pu-mic {
40
+ flex: none;
41
+ width: 40px;
42
+ height: 40px;
43
+ border: none;
44
+ border-radius: 50%;
45
+ background: #f1f3f5;
46
+ cursor: pointer;
47
+ font-size: 16px;
48
+ line-height: 1;
49
+ }
50
+ .pu-mic.pu-rec {
51
+ background: #dc2626;
52
+ color: #fff;
53
+ }
54
+ .pu-msg-image {
55
+ display: block;
56
+ margin-top: 6px;
57
+ max-width: 160px;
58
+ max-height: 160px;
59
+ border-radius: 8px;
60
+ }
61
+ .pu-attachment {
62
+ position: relative;
63
+ align-self: flex-end;
64
+ width: 96px;
65
+ }
66
+ .pu-attachment img {
67
+ width: 96px;
68
+ height: 96px;
69
+ object-fit: cover;
70
+ border-radius: 8px;
71
+ }
72
+ .pu-attach-x {
73
+ position: absolute;
74
+ top: -6px;
75
+ right: -6px;
76
+ width: 20px;
77
+ height: 20px;
78
+ border: none;
79
+ border-radius: 50%;
80
+ background: #1c1f23;
81
+ color: #fff;
82
+ cursor: pointer;
83
+ font-size: 11px;
84
+ line-height: 1;
85
+ }
86
+ .pu-attach {
87
+ flex: none;
88
+ width: 40px;
89
+ height: 40px;
90
+ border: none;
91
+ border-radius: 50%;
92
+ background: #f1f3f5;
93
+ cursor: pointer;
94
+ font-size: 20px;
95
+ line-height: 1;
96
+ }
97
+ }
@@ -0,0 +1,121 @@
1
+ import "./chat.css";
2
+ import { useRef, useState } from "react";
3
+ import type { ViewProps } from "../../view.js";
4
+ import type { ChatWidget, Message } from "../../../lib/widgets/chat.js";
5
+
6
+ // shrink a picked image so attachments (and later history reads) stay small
7
+ async function downscale(dataUrl: string, max = 768): Promise<string> {
8
+ const img = await new Promise<HTMLImageElement>((res, rej) => {
9
+ const i = new Image();
10
+ i.onload = () => res(i);
11
+ i.onerror = rej;
12
+ i.src = dataUrl;
13
+ });
14
+ const scale = Math.min(1, max / Math.max(img.width, img.height));
15
+ if (scale === 1) return dataUrl;
16
+ const canvas = document.createElement("canvas");
17
+ canvas.width = Math.round(img.width * scale);
18
+ canvas.height = Math.round(img.height * scale);
19
+ canvas.getContext("2d")!.drawImage(img, 0, 0, canvas.width, canvas.height);
20
+ return canvas.toDataURL("image/jpeg", 0.85);
21
+ }
22
+
23
+ export function ChatView({ widget, state, emit }: ViewProps<ChatWidget, { messages: Message[] }>) {
24
+ const streamRef = useRef<MediaStream | null>(null);
25
+ const recRef = useRef<MediaRecorder | null>(null);
26
+ const pressedRef = useRef(false);
27
+ const fileRef = useRef<HTMLInputElement>(null);
28
+ const [recording, setRecording] = useState(false);
29
+ const [pending, setPending] = useState<string | null>(null);
30
+
31
+ const send = (input: HTMLInputElement) => {
32
+ if (!input.value.trim() && !pending) return;
33
+ emit(widget.sent({ text: input.value, image: pending ?? undefined }));
34
+ input.value = "";
35
+ setPending(null);
36
+ };
37
+
38
+ const pick = (e: React.ChangeEvent<HTMLInputElement>) => {
39
+ const f = e.currentTarget.files?.[0];
40
+ if (!f) return;
41
+ const r = new FileReader();
42
+ r.onload = async () => setPending(await downscale(String(r.result)));
43
+ r.readAsDataURL(f);
44
+ e.currentTarget.value = "";
45
+ };
46
+
47
+ const start = async () => {
48
+ if (streamRef.current || pressedRef.current || !navigator.mediaDevices?.getUserMedia) return;
49
+ pressedRef.current = true;
50
+ setRecording(true);
51
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
52
+ if (!pressedRef.current) return stream.getTracks().forEach((t) => t.stop());
53
+ streamRef.current = stream;
54
+ const ac = new AudioContext({ sampleRate: 16000 });
55
+ const chunks: Blob[] = [];
56
+ const rec = new MediaRecorder(stream);
57
+ recRef.current = rec;
58
+ rec.ondataavailable = (e) => chunks.push(e.data);
59
+ rec.onstop = async () => {
60
+ const a = await ac.decodeAudioData(await new Blob(chunks).arrayBuffer());
61
+ emit(widget.recorded(a.getChannelData(0)));
62
+ };
63
+ rec.start();
64
+ };
65
+
66
+ const stop = () => {
67
+ pressedRef.current = false;
68
+ setRecording(false);
69
+ if (recRef.current?.state === "recording") recRef.current.stop();
70
+ streamRef.current?.getTracks().forEach((t) => t.stop());
71
+ streamRef.current = null;
72
+ recRef.current = null;
73
+ };
74
+
75
+ return (
76
+ <div className="pu-chat">
77
+ {state.messages.map((m, i) => (
78
+ <p key={i} className={`pu-msg pu-${m.role}`}>
79
+ <b>{m.role}:</b> {m.content}
80
+ {m.image && <img className="pu-msg-image" src={m.image} alt="" />}
81
+ </p>
82
+ ))}
83
+ {pending && (
84
+ <div className="pu-attachment">
85
+ <img src={pending} alt="" />
86
+ <button className="pu-attach-x" onClick={() => setPending(null)} aria-label="Remove image">
87
+
88
+ </button>
89
+ </div>
90
+ )}
91
+ <div className="pu-composer">
92
+ {widget.images && (
93
+ <>
94
+ <input ref={fileRef} type="file" accept="image/*" hidden onChange={pick} />
95
+ <button className="pu-attach" onClick={() => fileRef.current?.click()} aria-label="Attach image">
96
+ +
97
+ </button>
98
+ </>
99
+ )}
100
+ <input
101
+ className="pu-input"
102
+ placeholder={widget.placeholder}
103
+ onKeyDown={(e) => {
104
+ if (e.key === "Enter") send(e.currentTarget);
105
+ }}
106
+ />
107
+ {widget.voice && (
108
+ <button
109
+ className={`pu-mic${recording ? " pu-rec" : ""}`}
110
+ onPointerDown={start}
111
+ onPointerUp={stop}
112
+ onPointerLeave={() => pressedRef.current && stop()}
113
+ aria-label="Hold to talk"
114
+ >
115
+ {recording ? "●" : "🎤"}
116
+ </button>
117
+ )}
118
+ </div>
119
+ </div>
120
+ );
121
+ }
@@ -0,0 +1,15 @@
1
+ @layer components {
2
+ .pu-check {
3
+ display: inline-flex;
4
+ align-items: center;
5
+ gap: 8px;
6
+ cursor: pointer;
7
+ user-select: none;
8
+ }
9
+ .pu-check input {
10
+ width: 16px;
11
+ height: 16px;
12
+ accent-color: var(--pu-accent, #2563eb);
13
+ cursor: pointer;
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import "./checkbox.css";
2
+ import type { ViewProps } from "../../view.js";
3
+ import type { ValueWidget } from "../../../lib/widgets/value.js";
4
+
5
+ export function CheckboxView({ widget, state, emit, set }: ViewProps<ValueWidget<boolean>, { value: boolean }>) {
6
+ const update = (v: boolean) => {
7
+ set(["value"], v);
8
+ emit(widget.changed(v));
9
+ };
10
+ return (
11
+ <label className="pu-check">
12
+ <input type="checkbox" checked={state.value} onChange={(e) => update(e.currentTarget.checked)} /> {widget.label as string}
13
+ </label>
14
+ );
15
+ }
@@ -0,0 +1,20 @@
1
+ @layer components {
2
+ .pu-checkgroup {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 8px;
6
+ }
7
+ .pu-checkgroup-opt {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: 8px;
11
+ cursor: pointer;
12
+ user-select: none;
13
+ }
14
+ .pu-checkgroup-opt input {
15
+ width: 16px;
16
+ height: 16px;
17
+ accent-color: var(--pu-accent, #2563eb);
18
+ cursor: pointer;
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ import "./checkbox-group.css";
2
+ import type { ViewProps } from "../../view.js";
3
+ import type { ValueWidget } from "../../../lib/widgets/value.js";
4
+
5
+ export function CheckboxGroupView({ widget, state, emit, set }: ViewProps<ValueWidget<string[]>, { value: string[] }>) {
6
+ const choices = (widget.choices as string[]) ?? [];
7
+ const selected = state.value ?? [];
8
+ const toggle = (c: string) => {
9
+ const next = selected.includes(c) ? selected.filter((x) => x !== c) : [...selected, c];
10
+ set(["value"], next);
11
+ emit(widget.changed(next));
12
+ };
13
+ return (
14
+ <div className="pu-checkgroup">
15
+ {choices.map((c) => (
16
+ <label key={c} className="pu-checkgroup-opt">
17
+ <input type="checkbox" checked={selected.includes(c)} onChange={() => toggle(c)} /> {c}
18
+ </label>
19
+ ))}
20
+ </div>
21
+ );
22
+ }
@@ -0,0 +1,31 @@
1
+ @layer components {
2
+ .pu-code .cm-editor {
3
+ border: 1px solid var(--pu-border, #e3e6ea);
4
+ border-radius: 8px;
5
+ overflow: hidden;
6
+ background: #fff;
7
+ }
8
+ .pu-code .cm-editor.cm-focused {
9
+ border-color: var(--pu-accent, #2563eb);
10
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
11
+ outline: none;
12
+ }
13
+ .pu-code .cm-scroller {
14
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
15
+ font-size: 13px;
16
+ line-height: 1.55;
17
+ max-height: 420px;
18
+ }
19
+ .pu-code .cm-gutters {
20
+ background: var(--pu-bg, #f6f7f9);
21
+ border-right: 1px solid var(--pu-border, #e3e6ea);
22
+ color: var(--pu-muted, #6b7280);
23
+ }
24
+ /* a read-only viewer: dim the gutter, hide the caret, sit on the page background */
25
+ .pu-code-ro .cm-editor {
26
+ background: var(--pu-bg, #f6f7f9);
27
+ }
28
+ .pu-code-ro .cm-cursor {
29
+ display: none;
30
+ }
31
+ }