@xemahq/ui-kernel 0.8.0 → 0.9.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 (544) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +6 -21
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/biome-host/agent-validation.js +5 -9
  6. package/dist/lib/biome-host/agent-validation.js.map +1 -1
  7. package/dist/lib/biome-host/biome-builders.js +5 -9
  8. package/dist/lib/biome-host/biome-builders.js.map +1 -1
  9. package/dist/lib/biome-host/biome-mode.js +1 -2
  10. package/dist/lib/biome-host/biome-navigation.js +6 -10
  11. package/dist/lib/biome-host/biome-navigation.js.map +1 -1
  12. package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
  13. package/dist/lib/biome-host/biome-registry.js +27 -29
  14. package/dist/lib/biome-host/biome-registry.js.map +1 -1
  15. package/dist/lib/biome-host/biome-scope.js +9 -14
  16. package/dist/lib/biome-host/biome-scope.js.map +1 -1
  17. package/dist/lib/biome-host/biome-scoped-query.js +8 -13
  18. package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
  19. package/dist/lib/biome-host/create-biome-orval-config.js +1 -4
  20. package/dist/lib/biome-host/create-biome-orval-config.js.map +1 -1
  21. package/dist/lib/biome-host/define-web-biome.js +3 -6
  22. package/dist/lib/biome-host/define-web-biome.js.map +1 -1
  23. package/dist/lib/biome-host/errors.js +1 -4
  24. package/dist/lib/biome-host/errors.js.map +1 -1
  25. package/dist/lib/biome-host/frontend-biome.js +3 -6
  26. package/dist/lib/biome-host/frontend-biome.js.map +1 -1
  27. package/dist/lib/biome-host/host-bridge.js +5 -9
  28. package/dist/lib/biome-host/host-bridge.js.map +1 -1
  29. package/dist/lib/biome-host/host-sources.js +1 -2
  30. package/dist/lib/biome-host/i18n-hooks.js +5 -9
  31. package/dist/lib/biome-host/i18n-hooks.js.map +1 -1
  32. package/dist/lib/biome-host/i18n-port.js +1 -4
  33. package/dist/lib/biome-host/i18n-port.js.map +1 -1
  34. package/dist/lib/biome-host/index.js +22 -38
  35. package/dist/lib/biome-host/index.js.map +1 -1
  36. package/dist/lib/biome-host/realtime-hooks.js +7 -12
  37. package/dist/lib/biome-host/realtime-hooks.js.map +1 -1
  38. package/dist/lib/biome-host/realtime-port.js +1 -2
  39. package/dist/lib/biome-host/response-envelope.js +2 -6
  40. package/dist/lib/biome-host/response-envelope.js.map +1 -1
  41. package/dist/lib/biome-host/session-contributions.js +1 -2
  42. package/dist/lib/biome-host/session-profiles.js +7 -11
  43. package/dist/lib/biome-host/session-profiles.js.map +1 -1
  44. package/dist/lib/biome-host/use-mutation-with-error-toast.js +7 -10
  45. package/dist/lib/biome-host/use-mutation-with-error-toast.js.map +1 -1
  46. package/dist/lib/biome-host/use-page-state.js +16 -21
  47. package/dist/lib/biome-host/use-page-state.js.map +1 -1
  48. package/dist/lib/capabilities/capability-provider.js +11 -15
  49. package/dist/lib/capabilities/capability-provider.js.map +1 -1
  50. package/dist/lib/capabilities/index.js +3 -19
  51. package/dist/lib/capabilities/index.js.map +1 -1
  52. package/dist/lib/capabilities/types.js +1 -2
  53. package/dist/lib/capabilities/use-capability.js +5 -9
  54. package/dist/lib/capabilities/use-capability.js.map +1 -1
  55. package/dist/lib/contribution-registry/contribution-registry.d.ts +24 -0
  56. package/dist/lib/contribution-registry/contribution-registry.d.ts.map +1 -0
  57. package/dist/lib/contribution-registry/contribution-registry.js +67 -0
  58. package/dist/lib/contribution-registry/contribution-registry.js.map +1 -0
  59. package/dist/lib/contribution-registry/index.d.ts +3 -0
  60. package/dist/lib/contribution-registry/index.d.ts.map +1 -0
  61. package/dist/lib/contribution-registry/index.js +3 -0
  62. package/dist/lib/contribution-registry/index.js.map +1 -0
  63. package/dist/lib/contribution-registry/renderable-registry.d.ts +33 -0
  64. package/dist/lib/contribution-registry/renderable-registry.d.ts.map +1 -0
  65. package/dist/lib/contribution-registry/renderable-registry.js +51 -0
  66. package/dist/lib/contribution-registry/renderable-registry.js.map +1 -0
  67. package/dist/lib/system-bus/capability-invoke.js +1 -2
  68. package/dist/lib/system-bus/deeplink.js +12 -17
  69. package/dist/lib/system-bus/deeplink.js.map +1 -1
  70. package/dist/lib/system-bus/enums.js +10 -13
  71. package/dist/lib/system-bus/enums.js.map +1 -1
  72. package/dist/lib/system-bus/host-ports.js +1 -2
  73. package/dist/lib/system-bus/index.js +10 -26
  74. package/dist/lib/system-bus/index.js.map +1 -1
  75. package/dist/lib/system-bus/intent-registry.js +6 -10
  76. package/dist/lib/system-bus/intent-registry.js.map +1 -1
  77. package/dist/lib/system-bus/intents.js +1 -2
  78. package/dist/lib/system-bus/palette.js +1 -2
  79. package/dist/lib/system-bus/system-bus-builder.js +10 -13
  80. package/dist/lib/system-bus/system-bus-builder.js.map +1 -1
  81. package/dist/lib/system-bus/system-bus.js +1 -2
  82. package/dist/lib/system-bus/windows.js +1 -2
  83. package/dist/offline/id.js +1 -4
  84. package/dist/offline/id.js.map +1 -1
  85. package/dist/offline/index.js +8 -25
  86. package/dist/offline/index.js.map +1 -1
  87. package/dist/offline/mutation.js +5 -8
  88. package/dist/offline/mutation.js.map +1 -1
  89. package/dist/offline/offline-status-badge.js +7 -10
  90. package/dist/offline/offline-status-badge.js.map +1 -1
  91. package/dist/offline/online-controller.js +2 -7
  92. package/dist/offline/online-controller.js.map +1 -1
  93. package/dist/offline/outbox.js +22 -26
  94. package/dist/offline/outbox.js.map +1 -1
  95. package/dist/offline/react.js +15 -21
  96. package/dist/offline/react.js.map +1 -1
  97. package/dist/offline/storage.js +3 -9
  98. package/dist/offline/storage.js.map +1 -1
  99. package/dist/offline/types.js +2 -5
  100. package/dist/offline/types.js.map +1 -1
  101. package/dist/org-db/components/DbResultTable.js +7 -10
  102. package/dist/org-db/components/DbResultTable.js.map +1 -1
  103. package/dist/org-db/index.js +1 -5
  104. package/dist/org-db/index.js.map +1 -1
  105. package/dist/pdf/index.d.ts +2 -0
  106. package/dist/pdf/index.d.ts.map +1 -0
  107. package/dist/pdf/index.js +2 -0
  108. package/dist/pdf/index.js.map +1 -0
  109. package/dist/registry/index.js +8 -24
  110. package/dist/registry/index.js.map +1 -1
  111. package/dist/registry/lib/agent-validation-host.js +5 -8
  112. package/dist/registry/lib/agent-validation-host.js.map +1 -1
  113. package/dist/registry/lib/biome-slot.js +9 -12
  114. package/dist/registry/lib/biome-slot.js.map +1 -1
  115. package/dist/registry/lib/biomes-enabled-context.js +5 -9
  116. package/dist/registry/lib/biomes-enabled-context.js.map +1 -1
  117. package/dist/registry/lib/extension-points.js +1 -4
  118. package/dist/registry/lib/extension-points.js.map +1 -1
  119. package/dist/registry/lib/primitives/SessionEventCard.js +7 -10
  120. package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
  121. package/dist/registry/lib/primitives/SessionEventTimeline.js +9 -12
  122. package/dist/registry/lib/primitives/SessionEventTimeline.js.map +1 -1
  123. package/dist/registry/lib/primitives/SessionMutationBar.js +3 -6
  124. package/dist/registry/lib/primitives/SessionMutationBar.js.map +1 -1
  125. package/dist/registry/lib/primitives/SessionTabbedDrawer.js +11 -14
  126. package/dist/registry/lib/primitives/SessionTabbedDrawer.js.map +1 -1
  127. package/dist/registry/lib/primitives/index.js +4 -20
  128. package/dist/registry/lib/primitives/index.js.map +1 -1
  129. package/dist/registry/lib/session-context-builder.js +6 -10
  130. package/dist/registry/lib/session-context-builder.js.map +1 -1
  131. package/dist/registry/lib/session-context-provider.js +9 -14
  132. package/dist/registry/lib/session-context-provider.js.map +1 -1
  133. package/dist/registry/lib/session-selectors.js +30 -39
  134. package/dist/registry/lib/session-selectors.js.map +1 -1
  135. package/dist/session/comments/CommentRail.js +6 -9
  136. package/dist/session/comments/CommentRail.js.map +1 -1
  137. package/dist/session/index.js +3 -9
  138. package/dist/session/index.js.map +1 -1
  139. package/dist/session/lib/cn.js +4 -7
  140. package/dist/session/lib/cn.js.map +1 -1
  141. package/dist/session/shell/SessionWorkspaceShell.js +5 -8
  142. package/dist/session/shell/SessionWorkspaceShell.js.map +1 -1
  143. package/dist/session-kit/approvals/ApprovalButton.js +3 -6
  144. package/dist/session-kit/approvals/ApprovalButton.js.map +1 -1
  145. package/dist/session-kit/approvals/ApprovalCard.js +30 -33
  146. package/dist/session-kit/approvals/ApprovalCard.js.map +1 -1
  147. package/dist/session-kit/approvals/ApprovalsCenter.js +29 -32
  148. package/dist/session-kit/approvals/ApprovalsCenter.js.map +1 -1
  149. package/dist/session-kit/approvals/CapabilityApprovalStickyBar.js +12 -15
  150. package/dist/session-kit/approvals/CapabilityApprovalStickyBar.js.map +1 -1
  151. package/dist/session-kit/approvals/Obligation.js +12 -16
  152. package/dist/session-kit/approvals/Obligation.js.map +1 -1
  153. package/dist/session-kit/approvals/ScopedBody.js +34 -37
  154. package/dist/session-kit/approvals/ScopedBody.js.map +1 -1
  155. package/dist/session-kit/approvals/approval-icons.js +1 -2
  156. package/dist/session-kit/approvals/approval-model.js +6 -11
  157. package/dist/session-kit/approvals/approval-model.js.map +1 -1
  158. package/dist/session-kit/approvals/index.js +11 -27
  159. package/dist/session-kit/approvals/index.js.map +1 -1
  160. package/dist/session-kit/approvals/obligation-display.js +13 -16
  161. package/dist/session-kit/approvals/obligation-display.js.map +1 -1
  162. package/dist/session-kit/approvals/risk-accent.js +6 -9
  163. package/dist/session-kit/approvals/risk-accent.js.map +1 -1
  164. package/dist/session-kit/approvals/scope-icons.js +2 -5
  165. package/dist/session-kit/approvals/scope-icons.js.map +1 -1
  166. package/dist/session-kit/combobox/Combobox.js +19 -22
  167. package/dist/session-kit/combobox/Combobox.js.map +1 -1
  168. package/dist/session-kit/combobox/use-click-outside.js +4 -7
  169. package/dist/session-kit/combobox/use-click-outside.js.map +1 -1
  170. package/dist/session-kit/display/ContextHeader.js +10 -13
  171. package/dist/session-kit/display/ContextHeader.js.map +1 -1
  172. package/dist/session-kit/display/FileDiffCard.js +11 -14
  173. package/dist/session-kit/display/FileDiffCard.js.map +1 -1
  174. package/dist/session-kit/display/MD.js +14 -17
  175. package/dist/session-kit/display/MD.js.map +1 -1
  176. package/dist/session-kit/display/MessageTurn.js +20 -23
  177. package/dist/session-kit/display/MessageTurn.js.map +1 -1
  178. package/dist/session-kit/display/ThinkingPanel.js +7 -10
  179. package/dist/session-kit/display/ThinkingPanel.js.map +1 -1
  180. package/dist/session-kit/display/TodoChecklist.js +13 -16
  181. package/dist/session-kit/display/TodoChecklist.js.map +1 -1
  182. package/dist/session-kit/display/TokenMeter.js +8 -11
  183. package/dist/session-kit/display/TokenMeter.js.map +1 -1
  184. package/dist/session-kit/display/ToolStrip.js +26 -30
  185. package/dist/session-kit/display/ToolStrip.js.map +1 -1
  186. package/dist/session-kit/display/TypingDots.js +3 -6
  187. package/dist/session-kit/display/TypingDots.js.map +1 -1
  188. package/dist/session-kit/index.js +20 -36
  189. package/dist/session-kit/index.js.map +1 -1
  190. package/dist/session-kit/lib/enums.js +14 -17
  191. package/dist/session-kit/lib/enums.js.map +1 -1
  192. package/dist/session-kit/lib/portal-accent.js +1 -4
  193. package/dist/session-kit/lib/portal-accent.js.map +1 -1
  194. package/dist/session-kit/lib/status-dot.js +19 -24
  195. package/dist/session-kit/lib/status-dot.js.map +1 -1
  196. package/dist/session-kit/primitives/Avatar.js +3 -6
  197. package/dist/session-kit/primitives/Avatar.js.map +1 -1
  198. package/dist/session-kit/primitives/PortalGlyph.js +8 -11
  199. package/dist/session-kit/primitives/PortalGlyph.js.map +1 -1
  200. package/dist/session-kit/primitives/RiskPill.js +10 -14
  201. package/dist/session-kit/primitives/RiskPill.js.map +1 -1
  202. package/dist/session-kit/primitives/ScopeDot.js +7 -10
  203. package/dist/session-kit/primitives/ScopeDot.js.map +1 -1
  204. package/dist/session-kit/primitives/Segmented.js +4 -7
  205. package/dist/session-kit/primitives/Segmented.js.map +1 -1
  206. package/dist/ui/branding/app-branding-provider.js +13 -51
  207. package/dist/ui/branding/app-branding-provider.js.map +1 -1
  208. package/dist/ui/branding/sanitize.js +3 -8
  209. package/dist/ui/branding/sanitize.js.map +1 -1
  210. package/dist/ui/breakpoints.js +1 -4
  211. package/dist/ui/breakpoints.js.map +1 -1
  212. package/dist/ui/capture/document-preview.js +16 -19
  213. package/dist/ui/capture/document-preview.js.map +1 -1
  214. package/dist/ui/capture/field-spec-to-zod.d.ts +1 -0
  215. package/dist/ui/capture/field-spec-to-zod.d.ts.map +1 -1
  216. package/dist/ui/capture/field-spec-to-zod.js +51 -36
  217. package/dist/ui/capture/field-spec-to-zod.js.map +1 -1
  218. package/dist/ui/capture/field-spec-validate.d.ts +4 -0
  219. package/dist/ui/capture/field-spec-validate.d.ts.map +1 -0
  220. package/dist/ui/capture/field-spec-validate.js +129 -0
  221. package/dist/ui/capture/field-spec-validate.js.map +1 -0
  222. package/dist/ui/capture/field-spec.d.ts +13 -1
  223. package/dist/ui/capture/field-spec.d.ts.map +1 -1
  224. package/dist/ui/capture/field-spec.js +31 -13
  225. package/dist/ui/capture/field-spec.js.map +1 -1
  226. package/dist/ui/capture/index.d.ts +4 -2
  227. package/dist/ui/capture/index.d.ts.map +1 -1
  228. package/dist/ui/capture/index.js +12 -30
  229. package/dist/ui/capture/index.js.map +1 -1
  230. package/dist/ui/capture/schema-field-input.d.ts.map +1 -1
  231. package/dist/ui/capture/schema-field-input.js +82 -58
  232. package/dist/ui/capture/schema-field-input.js.map +1 -1
  233. package/dist/ui/capture/schema-form.js +11 -14
  234. package/dist/ui/capture/schema-form.js.map +1 -1
  235. package/dist/ui/capture/submit-values.d.ts +6 -0
  236. package/dist/ui/capture/submit-values.d.ts.map +1 -0
  237. package/dist/ui/capture/submit-values.js +28 -0
  238. package/dist/ui/capture/submit-values.js.map +1 -0
  239. package/dist/ui/capture/use-prefill.js +13 -16
  240. package/dist/ui/capture/use-prefill.js.map +1 -1
  241. package/dist/ui/capture/use-schema-validation.js +13 -16
  242. package/dist/ui/capture/use-schema-validation.js.map +1 -1
  243. package/dist/ui/capture/use-wizard.js +15 -18
  244. package/dist/ui/capture/use-wizard.js.map +1 -1
  245. package/dist/ui/capture/value-format.js +4 -8
  246. package/dist/ui/capture/value-format.js.map +1 -1
  247. package/dist/ui/capture/wizard.js +10 -14
  248. package/dist/ui/capture/wizard.js.map +1 -1
  249. package/dist/ui/charts/bar-chart.js +14 -17
  250. package/dist/ui/charts/bar-chart.js.map +1 -1
  251. package/dist/ui/charts/chart-frame.js +11 -16
  252. package/dist/ui/charts/chart-frame.js.map +1 -1
  253. package/dist/ui/charts/chart-types.js +1 -2
  254. package/dist/ui/charts/chart-utils.js +7 -15
  255. package/dist/ui/charts/chart-utils.js.map +1 -1
  256. package/dist/ui/charts/donut-chart.js +11 -14
  257. package/dist/ui/charts/donut-chart.js.map +1 -1
  258. package/dist/ui/charts/index.js +6 -20
  259. package/dist/ui/charts/index.js.map +1 -1
  260. package/dist/ui/charts/line-chart.js +15 -18
  261. package/dist/ui/charts/line-chart.js.map +1 -1
  262. package/dist/ui/charts/sparkline.js +9 -12
  263. package/dist/ui/charts/sparkline.js.map +1 -1
  264. package/dist/ui/chrome/AsyncBoundary.js +9 -15
  265. package/dist/ui/chrome/AsyncBoundary.js.map +1 -1
  266. package/dist/ui/chrome/EmptyState.js +9 -12
  267. package/dist/ui/chrome/EmptyState.js.map +1 -1
  268. package/dist/ui/chrome/ErrorCard.js +8 -11
  269. package/dist/ui/chrome/ErrorCard.js.map +1 -1
  270. package/dist/ui/chrome/LoadingState.js +8 -11
  271. package/dist/ui/chrome/LoadingState.js.map +1 -1
  272. package/dist/ui/chrome/PageHeader.js +10 -14
  273. package/dist/ui/chrome/PageHeader.js.map +1 -1
  274. package/dist/ui/chrome/StateCard.js +7 -11
  275. package/dist/ui/chrome/StateCard.js.map +1 -1
  276. package/dist/ui/chrome/confirm-delete-dialog.js +5 -8
  277. package/dist/ui/chrome/confirm-delete-dialog.js.map +1 -1
  278. package/dist/ui/chrome/page-shell.js +9 -15
  279. package/dist/ui/chrome/page-shell.js.map +1 -1
  280. package/dist/ui/chrome/scope-badge.js +5 -8
  281. package/dist/ui/chrome/scope-badge.js.map +1 -1
  282. package/dist/ui/chrome/status-badge.js +7 -10
  283. package/dist/ui/chrome/status-badge.js.map +1 -1
  284. package/dist/ui/cn.js +5 -8
  285. package/dist/ui/cn.js.map +1 -1
  286. package/dist/ui/design-tokens.js +21 -28
  287. package/dist/ui/design-tokens.js.map +1 -1
  288. package/dist/ui/hooks/use-debounced-value.js +4 -7
  289. package/dist/ui/hooks/use-debounced-value.js.map +1 -1
  290. package/dist/ui/hooks/use-is-mobile.js +8 -11
  291. package/dist/ui/hooks/use-is-mobile.js.map +1 -1
  292. package/dist/ui/index.d.ts +1 -1
  293. package/dist/ui/index.d.ts.map +1 -1
  294. package/dist/ui/index.js +47 -87
  295. package/dist/ui/index.js.map +1 -1
  296. package/dist/ui/pdf/pdf-preview.js +17 -20
  297. package/dist/ui/pdf/pdf-preview.js.map +1 -1
  298. package/dist/ui/primitives/alert-dialog.js +14 -60
  299. package/dist/ui/primitives/alert-dialog.js.map +1 -1
  300. package/dist/ui/primitives/async-combobox.js +18 -21
  301. package/dist/ui/primitives/async-combobox.js.map +1 -1
  302. package/dist/ui/primitives/badge.js +7 -44
  303. package/dist/ui/primitives/badge.js.map +1 -1
  304. package/dist/ui/primitives/button.js +9 -46
  305. package/dist/ui/primitives/button.js.map +1 -1
  306. package/dist/ui/primitives/card.js +10 -51
  307. package/dist/ui/primitives/card.js.map +1 -1
  308. package/dist/ui/primitives/checkbox.js +7 -43
  309. package/dist/ui/primitives/checkbox.js.map +1 -1
  310. package/dist/ui/primitives/collapsible.js +2 -40
  311. package/dist/ui/primitives/collapsible.js.map +1 -1
  312. package/dist/ui/primitives/dialog.js +12 -57
  313. package/dist/ui/primitives/dialog.js.map +1 -1
  314. package/dist/ui/primitives/dropdown-menu.js +15 -65
  315. package/dist/ui/primitives/dropdown-menu.js.map +1 -1
  316. package/dist/ui/primitives/form-stepper.js +8 -12
  317. package/dist/ui/primitives/form-stepper.js.map +1 -1
  318. package/dist/ui/primitives/input.js +5 -41
  319. package/dist/ui/primitives/input.js.map +1 -1
  320. package/dist/ui/primitives/label.js +8 -44
  321. package/dist/ui/primitives/label.js.map +1 -1
  322. package/dist/ui/primitives/overflow-tabs.d.ts +5 -0
  323. package/dist/ui/primitives/overflow-tabs.d.ts.map +1 -1
  324. package/dist/ui/primitives/overflow-tabs.js +19 -22
  325. package/dist/ui/primitives/overflow-tabs.js.map +1 -1
  326. package/dist/ui/primitives/popover.js +6 -44
  327. package/dist/ui/primitives/popover.js.map +1 -1
  328. package/dist/ui/primitives/preview-device-frame.js +16 -19
  329. package/dist/ui/primitives/preview-device-frame.js.map +1 -1
  330. package/dist/ui/primitives/radio-group.js +8 -45
  331. package/dist/ui/primitives/radio-group.js.map +1 -1
  332. package/dist/ui/primitives/resizable.js +11 -16
  333. package/dist/ui/primitives/resizable.js.map +1 -1
  334. package/dist/ui/primitives/scroll-area.js +7 -44
  335. package/dist/ui/primitives/scroll-area.js.map +1 -1
  336. package/dist/ui/primitives/select.js +15 -60
  337. package/dist/ui/primitives/select.js.map +1 -1
  338. package/dist/ui/primitives/separator.js +6 -42
  339. package/dist/ui/primitives/separator.js.map +1 -1
  340. package/dist/ui/primitives/sheet.js +14 -59
  341. package/dist/ui/primitives/sheet.js.map +1 -1
  342. package/dist/ui/primitives/skeleton.js +5 -7
  343. package/dist/ui/primitives/skeleton.js.map +1 -1
  344. package/dist/ui/primitives/switch.js +6 -42
  345. package/dist/ui/primitives/switch.js.map +1 -1
  346. package/dist/ui/primitives/table.js +12 -55
  347. package/dist/ui/primitives/table.js.map +1 -1
  348. package/dist/ui/primitives/tabs.js +8 -47
  349. package/dist/ui/primitives/tabs.js.map +1 -1
  350. package/dist/ui/primitives/tag-multi-select.js +24 -27
  351. package/dist/ui/primitives/tag-multi-select.js.map +1 -1
  352. package/dist/ui/primitives/textarea.js +5 -41
  353. package/dist/ui/primitives/textarea.js.map +1 -1
  354. package/dist/ui/primitives/tooltip.js +6 -45
  355. package/dist/ui/primitives/tooltip.js.map +1 -1
  356. package/dist/ui/primitives/url-preview-chrome.d.ts +8 -0
  357. package/dist/ui/primitives/url-preview-chrome.d.ts.map +1 -0
  358. package/dist/ui/primitives/url-preview-chrome.js +40 -0
  359. package/dist/ui/primitives/url-preview-chrome.js.map +1 -0
  360. package/dist/vista/GenericCatalogueSurface.d.ts +10 -0
  361. package/dist/vista/GenericCatalogueSurface.d.ts.map +1 -0
  362. package/dist/vista/GenericCatalogueSurface.js +80 -0
  363. package/dist/vista/GenericCatalogueSurface.js.map +1 -0
  364. package/dist/vista/SurfaceFallbackCard.d.ts +9 -0
  365. package/dist/vista/SurfaceFallbackCard.d.ts.map +1 -0
  366. package/dist/vista/SurfaceFallbackCard.js +44 -0
  367. package/dist/vista/SurfaceFallbackCard.js.map +1 -0
  368. package/dist/vista/VistaPanel.d.ts +21 -0
  369. package/dist/vista/VistaPanel.d.ts.map +1 -0
  370. package/dist/vista/VistaPanel.js +31 -0
  371. package/dist/vista/VistaPanel.js.map +1 -0
  372. package/dist/vista/html/CustomUiFrame.d.ts +20 -0
  373. package/dist/vista/html/CustomUiFrame.d.ts.map +1 -0
  374. package/dist/vista/html/CustomUiFrame.js +69 -0
  375. package/dist/vista/html/CustomUiFrame.js.map +1 -0
  376. package/dist/vista/html/custom-ui-frame-bridge.d.ts +13 -0
  377. package/dist/vista/html/custom-ui-frame-bridge.d.ts.map +1 -0
  378. package/dist/vista/html/custom-ui-frame-bridge.js +30 -0
  379. package/dist/vista/html/custom-ui-frame-bridge.js.map +1 -0
  380. package/dist/vista/html/custom-ui-frame-contract.d.ts +29 -0
  381. package/dist/vista/html/custom-ui-frame-contract.d.ts.map +1 -0
  382. package/dist/vista/html/custom-ui-frame-contract.js +16 -0
  383. package/dist/vista/html/custom-ui-frame-contract.js.map +1 -0
  384. package/dist/vista/html/custom-ui-intents.d.ts +20 -0
  385. package/dist/vista/html/custom-ui-intents.d.ts.map +1 -0
  386. package/dist/vista/html/custom-ui-intents.js +57 -0
  387. package/dist/vista/html/custom-ui-intents.js.map +1 -0
  388. package/dist/vista/html/custom-ui-srcdoc.d.ts +17 -0
  389. package/dist/vista/html/custom-ui-srcdoc.d.ts.map +1 -0
  390. package/dist/vista/html/custom-ui-srcdoc.js +70 -0
  391. package/dist/vista/html/custom-ui-srcdoc.js.map +1 -0
  392. package/dist/vista/html/index.d.ts +6 -0
  393. package/dist/vista/html/index.d.ts.map +1 -0
  394. package/dist/vista/html/index.js +6 -0
  395. package/dist/vista/html/index.js.map +1 -0
  396. package/dist/vista/index.d.ts +18 -0
  397. package/dist/vista/index.d.ts.map +1 -0
  398. package/dist/vista/index.js +18 -0
  399. package/dist/vista/index.js.map +1 -0
  400. package/dist/vista/surface-catalogue.d.ts +5 -0
  401. package/dist/vista/surface-catalogue.d.ts.map +1 -0
  402. package/dist/vista/surface-catalogue.js +30 -0
  403. package/dist/vista/surface-catalogue.js.map +1 -0
  404. package/dist/vista/surface-icons.d.ts +7 -0
  405. package/dist/vista/surface-icons.d.ts.map +1 -0
  406. package/dist/vista/surface-icons.js +26 -0
  407. package/dist/vista/surface-icons.js.map +1 -0
  408. package/dist/vista/surface-registry.d.ts +7 -0
  409. package/dist/vista/surface-registry.d.ts.map +1 -0
  410. package/dist/vista/surface-registry.js +7 -0
  411. package/dist/vista/surface-registry.js.map +1 -0
  412. package/dist/vista/surfaces/ChartSurface.d.ts +4 -0
  413. package/dist/vista/surfaces/ChartSurface.d.ts.map +1 -0
  414. package/dist/vista/surfaces/ChartSurface.js +17 -0
  415. package/dist/vista/surfaces/ChartSurface.js.map +1 -0
  416. package/dist/vista/surfaces/FilesSurface.d.ts +15 -0
  417. package/dist/vista/surfaces/FilesSurface.d.ts.map +1 -0
  418. package/dist/vista/surfaces/FilesSurface.js +121 -0
  419. package/dist/vista/surfaces/FilesSurface.js.map +1 -0
  420. package/dist/vista/surfaces/FormSurface.d.ts +4 -0
  421. package/dist/vista/surfaces/FormSurface.d.ts.map +1 -0
  422. package/dist/vista/surfaces/FormSurface.js +97 -0
  423. package/dist/vista/surfaces/FormSurface.js.map +1 -0
  424. package/dist/vista/surfaces/HtmlSurface.d.ts +4 -0
  425. package/dist/vista/surfaces/HtmlSurface.d.ts.map +1 -0
  426. package/dist/vista/surfaces/HtmlSurface.js +11 -0
  427. package/dist/vista/surfaces/HtmlSurface.js.map +1 -0
  428. package/dist/vista/surfaces/TableSurface.d.ts +4 -0
  429. package/dist/vista/surfaces/TableSurface.d.ts.map +1 -0
  430. package/dist/vista/surfaces/TableSurface.js +42 -0
  431. package/dist/vista/surfaces/TableSurface.js.map +1 -0
  432. package/dist/vista/surfaces/UrlSurface.d.ts +4 -0
  433. package/dist/vista/surfaces/UrlSurface.d.ts.map +1 -0
  434. package/dist/vista/surfaces/UrlSurface.js +7 -0
  435. package/dist/vista/surfaces/UrlSurface.js.map +1 -0
  436. package/dist/vista/surfaces/blob-surfaces.d.ts +6 -0
  437. package/dist/vista/surfaces/blob-surfaces.d.ts.map +1 -0
  438. package/dist/vista/surfaces/blob-surfaces.js +38 -0
  439. package/dist/vista/surfaces/blob-surfaces.js.map +1 -0
  440. package/dist/vista/surfaces/elicitation-transport.d.ts +18 -0
  441. package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -0
  442. package/dist/vista/surfaces/elicitation-transport.js +100 -0
  443. package/dist/vista/surfaces/elicitation-transport.js.map +1 -0
  444. package/dist/vista/surfaces/index.d.ts +11 -0
  445. package/dist/vista/surfaces/index.d.ts.map +1 -0
  446. package/dist/vista/surfaces/index.js +89 -0
  447. package/dist/vista/surfaces/index.js.map +1 -0
  448. package/dist/vista/surfaces/text-surfaces.d.ts +8 -0
  449. package/dist/vista/surfaces/text-surfaces.d.ts.map +1 -0
  450. package/dist/vista/surfaces/text-surfaces.js +54 -0
  451. package/dist/vista/surfaces/text-surfaces.js.map +1 -0
  452. package/dist/vista/use-vista-tabs.d.ts +30 -0
  453. package/dist/vista/use-vista-tabs.d.ts.map +1 -0
  454. package/dist/vista/use-vista-tabs.js +77 -0
  455. package/dist/vista/use-vista-tabs.js.map +1 -0
  456. package/dist/vista/vista-code-renderer.d.ts +12 -0
  457. package/dist/vista/vista-code-renderer.d.ts.map +1 -0
  458. package/dist/vista/vista-code-renderer.js +10 -0
  459. package/dist/vista/vista-code-renderer.js.map +1 -0
  460. package/dist/vista/vista-file-source.d.ts +20 -0
  461. package/dist/vista/vista-file-source.d.ts.map +1 -0
  462. package/dist/vista/vista-file-source.js +69 -0
  463. package/dist/vista/vista-file-source.js.map +1 -0
  464. package/dist/vista/vista-form-host.d.ts +16 -0
  465. package/dist/vista/vista-form-host.d.ts.map +1 -0
  466. package/dist/vista/vista-form-host.js +10 -0
  467. package/dist/vista/vista-form-host.js.map +1 -0
  468. package/dist/vista/vista-model.d.ts +12 -0
  469. package/dist/vista/vista-model.d.ts.map +1 -0
  470. package/dist/vista/vista-model.js +72 -0
  471. package/dist/vista/vista-model.js.map +1 -0
  472. package/dist/vista/vista-open-context.d.ts +9 -0
  473. package/dist/vista/vista-open-context.d.ts.map +1 -0
  474. package/dist/vista/vista-open-context.js +10 -0
  475. package/dist/vista/vista-open-context.js.map +1 -0
  476. package/dist/vista/vista-payloads.d.ts +107 -0
  477. package/dist/vista/vista-payloads.d.ts.map +1 -0
  478. package/dist/vista/vista-payloads.js +305 -0
  479. package/dist/vista/vista-payloads.js.map +1 -0
  480. package/dist/vista/vista-tabs-manifest.d.ts +17 -0
  481. package/dist/vista/vista-tabs-manifest.d.ts.map +1 -0
  482. package/dist/vista/vista-tabs-manifest.js +60 -0
  483. package/dist/vista/vista-tabs-manifest.js.map +1 -0
  484. package/dist/vista/vista-tools.d.ts +41 -0
  485. package/dist/vista/vista-tools.d.ts.map +1 -0
  486. package/dist/vista/vista-tools.js +113 -0
  487. package/dist/vista/vista-tools.js.map +1 -0
  488. package/package.json +10 -3
  489. package/src/index.ts +5 -0
  490. package/src/lib/biome-host/biome-registry.ts +31 -11
  491. package/src/lib/contribution-registry/contribution-registry.spec.ts +141 -0
  492. package/src/lib/contribution-registry/contribution-registry.ts +202 -0
  493. package/src/lib/contribution-registry/index.ts +9 -0
  494. package/src/lib/contribution-registry/renderable-registry.ts +142 -0
  495. package/src/pdf/index.ts +11 -0
  496. package/src/ui/capture/field-spec-to-zod.ts +22 -0
  497. package/src/ui/capture/field-spec-validate.ts +147 -0
  498. package/src/ui/capture/field-spec.ts +62 -0
  499. package/src/ui/capture/index.ts +9 -1
  500. package/src/ui/capture/schema-field-input.tsx +134 -14
  501. package/src/ui/capture/submit-values.test.ts +70 -0
  502. package/src/ui/capture/submit-values.ts +63 -0
  503. package/src/ui/index.ts +8 -1
  504. package/src/ui/primitives/overflow-tabs.tsx +24 -4
  505. package/src/ui/primitives/url-preview-chrome.tsx +102 -0
  506. package/src/vista/GenericCatalogueSurface.tsx +177 -0
  507. package/src/vista/SurfaceFallbackCard.tsx +109 -0
  508. package/src/vista/VistaPanel.tsx +155 -0
  509. package/src/vista/form-payload.spec.ts +93 -0
  510. package/src/vista/html/CustomUiFrame.spec.tsx +125 -0
  511. package/src/vista/html/CustomUiFrame.tsx +204 -0
  512. package/src/vista/html/custom-ui-frame-bridge.spec.ts +191 -0
  513. package/src/vista/html/custom-ui-frame-bridge.ts +92 -0
  514. package/src/vista/html/custom-ui-frame-contract.ts +88 -0
  515. package/src/vista/html/custom-ui-intents.spec.ts +133 -0
  516. package/src/vista/html/custom-ui-intents.ts +151 -0
  517. package/src/vista/html/custom-ui-srcdoc.spec.ts +151 -0
  518. package/src/vista/html/custom-ui-srcdoc.ts +193 -0
  519. package/src/vista/html/index.ts +13 -0
  520. package/src/vista/index.ts +48 -0
  521. package/src/vista/surface-catalogue.spec.ts +140 -0
  522. package/src/vista/surface-catalogue.ts +84 -0
  523. package/src/vista/surface-icons.ts +57 -0
  524. package/src/vista/surface-registry.ts +56 -0
  525. package/src/vista/surfaces/ChartSurface.tsx +34 -0
  526. package/src/vista/surfaces/FilesSurface.tsx +268 -0
  527. package/src/vista/surfaces/FormSurface.tsx +264 -0
  528. package/src/vista/surfaces/HtmlSurface.tsx +43 -0
  529. package/src/vista/surfaces/TableSurface.tsx +99 -0
  530. package/src/vista/surfaces/UrlSurface.tsx +40 -0
  531. package/src/vista/surfaces/blob-surfaces.tsx +129 -0
  532. package/src/vista/surfaces/elicitation-transport.spec.ts +187 -0
  533. package/src/vista/surfaces/elicitation-transport.ts +175 -0
  534. package/src/vista/surfaces/index.tsx +157 -0
  535. package/src/vista/surfaces/text-surfaces.tsx +119 -0
  536. package/src/vista/use-vista-tabs.ts +188 -0
  537. package/src/vista/vista-code-renderer.tsx +46 -0
  538. package/src/vista/vista-file-source.tsx +163 -0
  539. package/src/vista/vista-form-host.tsx +78 -0
  540. package/src/vista/vista-model.ts +130 -0
  541. package/src/vista/vista-open-context.tsx +42 -0
  542. package/src/vista/vista-payloads.ts +514 -0
  543. package/src/vista/vista-tabs-manifest.ts +123 -0
  544. package/src/vista/vista-tools.ts +220 -0
@@ -0,0 +1,147 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // Total runtime validator for a `CaptureFieldSpec[]` arriving from the wire
3
+ //
4
+ // `fieldSpecToZod` validates the VALUES a form produces. This validates the
5
+ // SCHEMA itself, for the case where the field list is not authored in TypeScript
6
+ // but carried in an envelope (a Vista `form` surface payload, a biome
7
+ // contribution, an agent-authored capture step).
8
+ //
9
+ // Contract: TOTAL and NEVER throws — it returns the narrowed specs or `null`,
10
+ // exactly like the Vista payload validators, so a malformed schema degrades to
11
+ // a visible typed fallback instead of a half-rendered form.
12
+ // ═══════════════════════════════════════════════════════════════════════════
13
+ import { CaptureFieldTransform, CaptureFieldType, type CaptureFieldSpec } from './field-spec';
14
+
15
+ const FIELD_TYPES: ReadonlySet<string> = new Set(Object.values(CaptureFieldType));
16
+ const TRANSFORMS: ReadonlySet<string> = new Set(Object.values(CaptureFieldTransform));
17
+
18
+ type UnknownRecord = Readonly<Record<string, unknown>>;
19
+
20
+ function asRecord(value: unknown): UnknownRecord | null {
21
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
22
+ ? (value as UnknownRecord)
23
+ : null;
24
+ }
25
+
26
+ /** `undefined` passes through; a present non-string is a rejection (`null`). */
27
+ function optionalString(value: unknown): string | undefined | null {
28
+ if (value === undefined) return undefined;
29
+ return typeof value === 'string' ? value : null;
30
+ }
31
+
32
+ /** `undefined` passes through; a present non-boolean is a rejection (`null`). */
33
+ function optionalBoolean(value: unknown): boolean | undefined | null {
34
+ if (value === undefined) return undefined;
35
+ return typeof value === 'boolean' ? value : null;
36
+ }
37
+
38
+ /** `undefined` passes through; a present non-number is a rejection (`null`). */
39
+ function optionalNumber(value: unknown): number | undefined | null {
40
+ if (value === undefined) return undefined;
41
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
42
+ }
43
+
44
+ /** Narrow ONE field spec. Returns `null` for anything malformed. */
45
+ export function validateCaptureField(raw: unknown): CaptureFieldSpec | null {
46
+ const record = asRecord(raw);
47
+ if (record === null) return null;
48
+ if (typeof record.key !== 'string' || record.key.length === 0) return null;
49
+ if (typeof record.label !== 'string' || record.label.length === 0) return null;
50
+ if (typeof record.type !== 'string' || !FIELD_TYPES.has(record.type)) return null;
51
+
52
+ const required = optionalBoolean(record.required);
53
+ if (required === null) return null;
54
+ const isSecret = optionalBoolean(record.isSecret);
55
+ if (isSecret === null) return null;
56
+ const description = optionalString(record.description);
57
+ if (description === null) return null;
58
+ const placeholder = optionalString(record.placeholder);
59
+ if (placeholder === null) return null;
60
+ const section = optionalString(record.section);
61
+ if (section === null) return null;
62
+ const referenceEntity = optionalString(record.referenceEntity);
63
+ if (referenceEntity === null) return null;
64
+ const accept = optionalString(record.accept);
65
+ if (accept === null) return null;
66
+ const min = optionalNumber(record.min);
67
+ if (min === null) return null;
68
+ const max = optionalNumber(record.max);
69
+ if (max === null) return null;
70
+
71
+ let transform: CaptureFieldTransform | undefined;
72
+ if (record.transform !== undefined) {
73
+ if (typeof record.transform !== 'string' || !TRANSFORMS.has(record.transform)) return null;
74
+ transform = record.transform as CaptureFieldTransform;
75
+ }
76
+
77
+ let enumValues: readonly string[] | undefined;
78
+ if (record.enumValues !== undefined) {
79
+ if (!Array.isArray(record.enumValues)) return null;
80
+ if (!record.enumValues.every((v) => typeof v === 'string')) return null;
81
+ enumValues = record.enumValues;
82
+ }
83
+
84
+ let capture: 'user' | 'environment' | undefined;
85
+ if (record.capture !== undefined) {
86
+ if (record.capture !== 'user' && record.capture !== 'environment') return null;
87
+ capture = record.capture;
88
+ }
89
+
90
+ let fields: readonly CaptureFieldSpec[] | undefined;
91
+ if (record.fields !== undefined) {
92
+ const nested = validateCaptureFields(record.fields);
93
+ if (nested === null) return null;
94
+ fields = nested;
95
+ }
96
+
97
+ const spec: {
98
+ key: string;
99
+ label: string;
100
+ type: CaptureFieldType;
101
+ required?: boolean;
102
+ isSecret?: boolean;
103
+ transform?: CaptureFieldTransform;
104
+ description?: string;
105
+ placeholder?: string;
106
+ section?: string;
107
+ referenceEntity?: string;
108
+ accept?: string;
109
+ capture?: 'user' | 'environment';
110
+ enumValues?: readonly string[];
111
+ fields?: readonly CaptureFieldSpec[];
112
+ min?: number;
113
+ max?: number;
114
+ } = { key: record.key, label: record.label, type: record.type as CaptureFieldType };
115
+
116
+ if (required !== undefined) spec.required = required;
117
+ if (isSecret !== undefined) spec.isSecret = isSecret;
118
+ if (transform !== undefined) spec.transform = transform;
119
+ if (description !== undefined) spec.description = description;
120
+ if (placeholder !== undefined) spec.placeholder = placeholder;
121
+ if (section !== undefined) spec.section = section;
122
+ if (referenceEntity !== undefined) spec.referenceEntity = referenceEntity;
123
+ if (accept !== undefined) spec.accept = accept;
124
+ if (capture !== undefined) spec.capture = capture;
125
+ if (enumValues !== undefined) spec.enumValues = enumValues;
126
+ if (fields !== undefined) spec.fields = fields;
127
+ if (min !== undefined) spec.min = min;
128
+ if (max !== undefined) spec.max = max;
129
+
130
+ return spec;
131
+ }
132
+
133
+ /**
134
+ * Narrow a whole field list. An EMPTY array is valid and narrows to `[]` — an
135
+ * empty schema is a real, meaningful state (the server is the authority on
136
+ * whether a form with no fields may be submitted), not a validation failure.
137
+ */
138
+ export function validateCaptureFields(raw: unknown): readonly CaptureFieldSpec[] | null {
139
+ if (!Array.isArray(raw)) return null;
140
+ const out: CaptureFieldSpec[] = [];
141
+ for (const entry of raw) {
142
+ const spec = validateCaptureField(entry);
143
+ if (spec === null) return null;
144
+ out.push(spec);
145
+ }
146
+ return out;
147
+ }
@@ -50,6 +50,53 @@ export enum CaptureFieldType {
50
50
  Image = 'image',
51
51
  File = 'file',
52
52
  Audio = 'audio',
53
+ // ── Scalar text refinements (absorbed from the connector credential form) ──
54
+ // These change only the NATIVE INPUT TYPE (keyboard + browser affordances);
55
+ // the value is a plain string. `Json` additionally renders as a mono textarea
56
+ // and is validated as parseable JSON.
57
+ Email = 'email',
58
+ Url = 'url',
59
+ Json = 'json',
60
+ }
61
+
62
+ /**
63
+ * Normalization applied to a captured STRING value at the input boundary.
64
+ *
65
+ * Value-identical in meaning to the connector `CredentialFieldTransform`
66
+ * (`NONE`/`UPPERCASE`/`LOWERCASE`/`TRIM`) but named in this kit's lowercase
67
+ * vocabulary, because the capture kit is domain-agnostic and must not import a
68
+ * connector contract. The connector→capture adapter lives at the consuming
69
+ * seam, not here.
70
+ *
71
+ * This is the ONLY normalization the kit performs. There is deliberately no
72
+ * blanket trim on submit: an undeclared transform would silently override a
73
+ * field that declared {@link CaptureFieldTransform.None}.
74
+ */
75
+ export enum CaptureFieldTransform {
76
+ None = 'none',
77
+ Uppercase = 'uppercase',
78
+ Lowercase = 'lowercase',
79
+ Trim = 'trim',
80
+ }
81
+
82
+ /** Apply a declared transform to a string value. Total; absent = unchanged. */
83
+ export function applyCaptureTransform(
84
+ value: string,
85
+ transform: CaptureFieldTransform | `${CaptureFieldTransform}` | undefined,
86
+ ): string {
87
+ switch (transform) {
88
+ case CaptureFieldTransform.Uppercase:
89
+ return value.toUpperCase();
90
+ case CaptureFieldTransform.Lowercase:
91
+ return value.toLowerCase();
92
+ case CaptureFieldTransform.Trim:
93
+ return value.trim();
94
+ case CaptureFieldTransform.None:
95
+ case undefined:
96
+ return value;
97
+ default:
98
+ return value;
99
+ }
53
100
  }
54
101
 
55
102
  /**
@@ -96,6 +143,21 @@ export interface CaptureFieldSpec {
96
143
  * explicit). See {@link groupFieldsBySection}.
97
144
  */
98
145
  readonly section?: string;
146
+ /**
147
+ * DECLARED write-only secrecy. When true the input is masked, never
148
+ * pre-filled from a read, and never echoed back by any read path.
149
+ *
150
+ * Secrecy is DECLARED, never inferred from {@link type}: a plain-`string`
151
+ * field can be a secret and a `password`-shaped field can be public. The
152
+ * renderer reads this flag and nothing else — do not re-introduce a
153
+ * `type === password` inference.
154
+ */
155
+ readonly isSecret?: boolean;
156
+ /**
157
+ * Declared normalization applied to the string value at the input boundary.
158
+ * Absent = {@link CaptureFieldTransform.None}.
159
+ */
160
+ readonly transform?: CaptureFieldTransform | `${CaptureFieldTransform}`;
99
161
  }
100
162
 
101
163
  /** A titled group of fields — the explicit sectioned schema shape. */
@@ -11,6 +11,8 @@
11
11
  // ── field-spec model (aligned superset of app-forge's AppFieldType) ──
12
12
  export {
13
13
  CaptureFieldType,
14
+ CaptureFieldTransform,
15
+ applyCaptureTransform,
14
16
  isSectioned,
15
17
  toFieldList,
16
18
  toSections,
@@ -21,8 +23,14 @@ export {
21
23
  type CaptureValues,
22
24
  } from './field-spec';
23
25
 
26
+ // ── total runtime validator for a wire-carried schema ──
27
+ export { validateCaptureField, validateCaptureFields } from './field-spec-validate';
28
+
24
29
  // ── schema → zod adapter ──
25
- export { fieldSpecToZod, isEmptyValue } from './field-spec-to-zod';
30
+ export { fieldSpecToZod, isEmptyValue, isParsableJson } from './field-spec-to-zod';
31
+
32
+ // ── values → wire payload ──
33
+ export { captureValuesToStringMap, captureValuesToSubmitPayload } from './submit-values';
26
34
 
27
35
  // ── validation + "missing info" ──
28
36
  export { useSchemaValidation, type SchemaValidationResult } from './use-schema-validation';
@@ -6,8 +6,14 @@
6
6
  // items) composites. `reference` is source-agnostic here: it defaults to a text
7
7
  // input, but a caller can inject a picker via `renderReference` (that is the
8
8
  // seam app-forge uses to plug its record-backed `ReferenceSelect`).
9
+ //
10
+ // This is the ONE schema→input renderer in the tree. The connector-specific
11
+ // `CredentialFormRenderer` was folded in here: a DECLARED-secret field
12
+ // (`spec.isSecret`) renders the write-only masked input, and `email`/`url`/
13
+ // `json` are ordinary capture field types. Secrecy is never inferred from the
14
+ // field type.
9
15
  // ═══════════════════════════════════════════════════════════════════════════
10
- import { Plus, Trash2 } from 'lucide-react';
16
+ import { Eye, EyeOff, Plus, Trash2 } from 'lucide-react';
11
17
  import { useCallback, useRef, useState, type ReactNode } from 'react';
12
18
 
13
19
  import { cn } from '../cn';
@@ -17,7 +23,7 @@ import { Input } from '../primitives/input';
17
23
  import { Label } from '../primitives/label';
18
24
  import { Textarea } from '../primitives/textarea';
19
25
 
20
- import { CaptureFieldType, type CaptureFieldSpec, type CaptureValues } from './field-spec';
26
+ import { applyCaptureTransform, CaptureFieldType, type CaptureFieldSpec, type CaptureValues } from './field-spec';
21
27
  import { asString } from './value-format';
22
28
 
23
29
  const SELECT_CLASS =
@@ -44,42 +50,78 @@ export interface SchemaFieldInputProps {
44
50
  readonly renderReference?: RenderReference;
45
51
  }
46
52
 
53
+ /** Native `type` for the single-line text-ish capture types. */
54
+ function nativeInputType(type: CaptureFieldSpec['type']): 'text' | 'email' | 'url' {
55
+ switch (type) {
56
+ case CaptureFieldType.Email:
57
+ return 'email';
58
+ case CaptureFieldType.Url:
59
+ return 'url';
60
+ default:
61
+ return 'text';
62
+ }
63
+ }
64
+
47
65
  export function SchemaFieldInput(props: SchemaFieldInputProps) {
48
66
  const { field, value, onChange, disabled, path, renderReference } = props;
49
67
  const inputId = `field-${path}`;
50
68
 
69
+ // The ONE place a captured string is normalized. Composites (object/list)
70
+ // emit records/arrays and pass through untouched.
71
+ const emit = (next: unknown): void =>
72
+ onChange(typeof next === 'string' ? applyCaptureTransform(next, field.transform) : next);
73
+
74
+ // DECLARED secrecy wins over the field type: a secret is always write-only
75
+ // and masked, whatever shape it has. Never inferred from `type`.
76
+ if (field.isSecret === true) {
77
+ return <SecretFieldInput field={field} value={value} onChange={emit} disabled={disabled} inputId={inputId} />;
78
+ }
79
+
51
80
  switch (field.type) {
52
81
  case CaptureFieldType.Text:
53
- return <Textarea id={inputId} value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} rows={4} placeholder={field.placeholder} />;
82
+ return <Textarea id={inputId} value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} rows={4} placeholder={field.placeholder} />;
83
+ case CaptureFieldType.Json:
84
+ return (
85
+ <Textarea
86
+ id={inputId}
87
+ value={asString(value)}
88
+ onChange={(e) => emit(e.target.value)}
89
+ disabled={disabled}
90
+ rows={6}
91
+ spellCheck={false}
92
+ className="min-h-[120px] font-mono"
93
+ placeholder={field.placeholder}
94
+ />
95
+ );
54
96
  case CaptureFieldType.Number:
55
97
  return (
56
98
  <Input
57
99
  id={inputId}
58
100
  type="number"
59
101
  value={asString(value)}
60
- onChange={(e) => onChange(e.target.value === '' ? '' : Number(e.target.value))}
102
+ onChange={(e) => emit(e.target.value === '' ? '' : Number(e.target.value))}
61
103
  disabled={disabled}
62
104
  placeholder={field.placeholder}
63
105
  />
64
106
  );
65
107
  case CaptureFieldType.Decimal:
66
108
  // NUMERIC carried verbatim as text — never Number()-coerced (precision).
67
- return <Input id={inputId} type="text" inputMode="decimal" value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? '0.00'} />;
109
+ return <Input id={inputId} type="text" inputMode="decimal" value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? '0.00'} />;
68
110
  case CaptureFieldType.User:
69
- return <Input id={inputId} value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? 'subject id'} />;
111
+ return <Input id={inputId} value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? 'subject id'} />;
70
112
  case CaptureFieldType.Boolean:
71
113
  return (
72
114
  <div className="mt-1">
73
- <Checkbox id={inputId} checked={value === true} onCheckedChange={(checked) => onChange(checked === true)} disabled={disabled} />
115
+ <Checkbox id={inputId} checked={value === true} onCheckedChange={(checked) => emit(checked === true)} disabled={disabled} />
74
116
  </div>
75
117
  );
76
118
  case CaptureFieldType.Date:
77
- return <Input id={inputId} type="date" value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} />;
119
+ return <Input id={inputId} type="date" value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} />;
78
120
  case CaptureFieldType.Datetime:
79
- return <Input id={inputId} type="datetime-local" value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} />;
121
+ return <Input id={inputId} type="datetime-local" value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} />;
80
122
  case CaptureFieldType.Enum:
81
123
  return (
82
- <select id={inputId} className={SELECT_CLASS} value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled}>
124
+ <select id={inputId} className={SELECT_CLASS} value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled}>
83
125
  <option value="">— select —</option>
84
126
  {(field.enumValues ?? []).map((v) => (
85
127
  <option key={v} value={v}>
@@ -90,9 +132,9 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
90
132
  );
91
133
  case CaptureFieldType.Reference:
92
134
  return renderReference ? (
93
- <>{renderReference({ field, value, onChange, disabled, inputId })}</>
135
+ <>{renderReference({ field, value, onChange: emit, disabled, inputId })}</>
94
136
  ) : (
95
- <Input id={inputId} value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? 'reference id'} />
137
+ <Input id={inputId} value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} placeholder={field.placeholder ?? 'reference id'} />
96
138
  );
97
139
  case CaptureFieldType.Object:
98
140
  return <ObjectInput {...props} />;
@@ -103,10 +145,88 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
103
145
  return <MediaFieldInput {...props} />;
104
146
  case CaptureFieldType.Audio:
105
147
  return <AudioFieldInput {...props} />;
106
- // string (and any unknown) — plain single-line input.
148
+ // string / email / url (and any unknown) — single-line input.
107
149
  default:
108
- return <Input id={inputId} value={asString(value)} onChange={(e) => onChange(e.target.value)} disabled={disabled} placeholder={field.placeholder} />;
150
+ return <Input id={inputId} type={nativeInputType(field.type)} value={asString(value)} onChange={(e) => emit(e.target.value)} disabled={disabled} placeholder={field.placeholder} />;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Write-only input for a DECLARED-secret field.
156
+ *
157
+ * `autoComplete="off"` + `data-lpignore` keep password managers and the browser
158
+ * credential store from persisting the value; the reveal toggle is local and
159
+ * transient. The component holds no cache: it renders exactly the value the
160
+ * caller passes and nothing else, so a read path that returns no secret
161
+ * material (the only kind this kit is used with) can never repopulate it.
162
+ */
163
+ function SecretFieldInput({
164
+ field,
165
+ value,
166
+ onChange,
167
+ disabled,
168
+ inputId,
169
+ }: Readonly<{
170
+ field: CaptureFieldSpec;
171
+ value: unknown;
172
+ onChange: (next: unknown) => void;
173
+ disabled?: boolean;
174
+ inputId: string;
175
+ }>) {
176
+ const [reveal, setReveal] = useState(false);
177
+ const multiline = field.type === CaptureFieldType.Json || field.type === CaptureFieldType.Text;
178
+
179
+ if (multiline && reveal) {
180
+ return (
181
+ <div className="relative">
182
+ <Textarea
183
+ id={inputId}
184
+ value={asString(value)}
185
+ onChange={(e) => onChange(e.target.value)}
186
+ disabled={disabled}
187
+ rows={6}
188
+ spellCheck={false}
189
+ autoComplete="off"
190
+ className="min-h-[120px] pr-9 font-mono"
191
+ placeholder={field.placeholder}
192
+ />
193
+ <RevealToggle reveal={reveal} onToggle={() => setReveal((v) => !v)} />
194
+ </div>
195
+ );
109
196
  }
197
+
198
+ return (
199
+ <div className="relative">
200
+ <Input
201
+ id={inputId}
202
+ type={reveal ? 'text' : 'password'}
203
+ value={asString(value)}
204
+ onChange={(e) => onChange(e.target.value)}
205
+ disabled={disabled}
206
+ autoComplete="off"
207
+ spellCheck={false}
208
+ data-lpignore="true"
209
+ className="pr-9 font-mono"
210
+ placeholder={field.placeholder}
211
+ />
212
+ <RevealToggle reveal={reveal} onToggle={() => setReveal((v) => !v)} />
213
+ </div>
214
+ );
215
+ }
216
+
217
+ function RevealToggle({ reveal, onToggle }: Readonly<{ reveal: boolean; onToggle: () => void }>) {
218
+ return (
219
+ <Button
220
+ type="button"
221
+ size="sm"
222
+ variant="ghost"
223
+ className="absolute right-0 top-0 h-9 w-9 p-0"
224
+ onClick={onToggle}
225
+ aria-label={reveal ? 'Hide value' : 'Show value'}
226
+ >
227
+ {reveal ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
228
+ </Button>
229
+ );
110
230
  }
111
231
 
112
232
  const FILE_INPUT_CLASS =
@@ -0,0 +1,70 @@
1
+ // Pure-logic proofs for the ONE values→wire projection and the declared
2
+ // transform. Runs under the host-web vitest runner (this package carries no
3
+ // vitest dep — see tsconfig exclude).
4
+ import { describe, expect, it } from 'vitest';
5
+
6
+ import { applyCaptureTransform, CaptureFieldTransform, CaptureFieldType, type CaptureFieldSpec } from './field-spec';
7
+ import { fieldSpecToZod } from './field-spec-to-zod';
8
+ import { captureValuesToStringMap, captureValuesToSubmitPayload } from './submit-values';
9
+
10
+ const fields: CaptureFieldSpec[] = [
11
+ { key: 'apiKey', label: 'API key', type: CaptureFieldType.String, required: true, isSecret: true },
12
+ { key: 'baseUrl', label: 'Base URL', type: CaptureFieldType.Url, required: true },
13
+ { key: 'serviceAccount', label: 'Service account', type: CaptureFieldType.Json, required: false },
14
+ ];
15
+
16
+ describe('applyCaptureTransform', () => {
17
+ it('applies only the DECLARED transform', () => {
18
+ expect(applyCaptureTransform(' a ', CaptureFieldTransform.Trim)).toBe('a');
19
+ expect(applyCaptureTransform('a', CaptureFieldTransform.Uppercase)).toBe('A');
20
+ expect(applyCaptureTransform('A', CaptureFieldTransform.Lowercase)).toBe('a');
21
+ expect(applyCaptureTransform(' a ', CaptureFieldTransform.None)).toBe(' a ');
22
+ // Absent = no normalization. There is no implicit blanket trim.
23
+ expect(applyCaptureTransform(' a ', undefined)).toBe(' a ');
24
+ });
25
+ });
26
+
27
+ describe('captureValuesToStringMap', () => {
28
+ it('projects ONLY declared keys, as strings', () => {
29
+ expect(
30
+ captureValuesToStringMap(fields, {
31
+ apiKey: 'sk-1',
32
+ baseUrl: 'https://acme.test',
33
+ rogue: 'should not travel',
34
+ }),
35
+ ).toEqual({ apiKey: 'sk-1', baseUrl: 'https://acme.test', serviceAccount: '' });
36
+ });
37
+ });
38
+
39
+ describe('captureValuesToSubmitPayload', () => {
40
+ it('parses a json field and leaves the rest untouched', () => {
41
+ expect(
42
+ captureValuesToSubmitPayload(fields, {
43
+ apiKey: 'sk-1',
44
+ baseUrl: 'https://acme.test',
45
+ serviceAccount: '{"a":1}',
46
+ }),
47
+ ).toEqual({ apiKey: 'sk-1', baseUrl: 'https://acme.test', serviceAccount: { a: 1 } });
48
+ });
49
+
50
+ it('does not drop an unparseable json value — validation is the gate', () => {
51
+ expect(captureValuesToSubmitPayload(fields, { serviceAccount: '{' }).serviceAccount).toBe('{');
52
+ });
53
+ });
54
+
55
+ describe('json field validation', () => {
56
+ const schema = fieldSpecToZod(fields);
57
+
58
+ it('rejects an unparseable json blob', () => {
59
+ expect(schema.safeParse({ apiKey: 'k', baseUrl: 'u', serviceAccount: '{' }).success).toBe(false);
60
+ });
61
+
62
+ it('accepts a parseable json blob and an omitted optional one', () => {
63
+ expect(schema.safeParse({ apiKey: 'k', baseUrl: 'u', serviceAccount: '{"a":1}' }).success).toBe(true);
64
+ expect(schema.safeParse({ apiKey: 'k', baseUrl: 'u' }).success).toBe(true);
65
+ });
66
+
67
+ it('requires a non-empty url/email field when required', () => {
68
+ expect(schema.safeParse({ apiKey: 'k', baseUrl: '' }).success).toBe(false);
69
+ });
70
+ });
@@ -0,0 +1,63 @@
1
+ // ═══════════════════════════════════════════════════════════════════════════
2
+ // Capture values → submit payload
3
+ //
4
+ // The ONE projection from the form's in-memory `CaptureValues` to what goes on
5
+ // the wire. Two faces, because two wire contracts exist and neither should grow
6
+ // its own inline projection:
7
+ //
8
+ // • `captureValuesToStringMap` — every field as a STRING (the shape a
9
+ // credential submit takes: `fields: Record<string, string>`).
10
+ // • `captureValuesToSubmitPayload` — same, except a `json` field is PARSED
11
+ // into its structured value (the shape the connection credential write
12
+ // takes: `credentials: Record<string, unknown>`).
13
+ //
14
+ // Both are field-driven: only DECLARED keys are projected, so a stray key in
15
+ // the values record can never reach the wire. Neither performs an undeclared
16
+ // normalization — trimming/casing is `CaptureFieldTransform`, applied once at
17
+ // the input boundary. A blanket trim here would silently override a field that
18
+ // declared `transform: none`.
19
+ // ═══════════════════════════════════════════════════════════════════════════
20
+ import { CaptureFieldType, toFieldList, type CaptureFieldSpec, type CaptureSchema, type CaptureSection, type CaptureValues } from './field-spec';
21
+ import { asString } from './value-format';
22
+
23
+ type Schema = CaptureSchema | readonly CaptureFieldSpec[] | readonly CaptureSection[];
24
+
25
+ /** Project the declared fields to a flat `string` map (fields-only wire). */
26
+ export function captureValuesToStringMap(
27
+ schema: Schema,
28
+ values: CaptureValues,
29
+ ): Record<string, string> {
30
+ const payload: Record<string, string> = {};
31
+ for (const field of toFieldList(schema)) {
32
+ payload[field.key] = asString(values[field.key]);
33
+ }
34
+ return payload;
35
+ }
36
+
37
+ /**
38
+ * Project the declared fields, parsing `json` fields into structured values.
39
+ *
40
+ * A `json` field that does not parse is left as its raw string — validation is
41
+ * `useSchemaValidation`'s job and it must run first; this projection does not
42
+ * silently drop a value it cannot parse.
43
+ */
44
+ export function captureValuesToSubmitPayload(
45
+ schema: Schema,
46
+ values: CaptureValues,
47
+ ): CaptureValues {
48
+ const payload: CaptureValues = {};
49
+ for (const field of toFieldList(schema)) {
50
+ const raw = values[field.key];
51
+ if (field.type !== CaptureFieldType.Json) {
52
+ payload[field.key] = raw;
53
+ continue;
54
+ }
55
+ const text = asString(raw);
56
+ try {
57
+ payload[field.key] = JSON.parse(text);
58
+ } catch {
59
+ payload[field.key] = text;
60
+ }
61
+ }
62
+ return payload;
63
+ }
package/src/ui/index.ts CHANGED
@@ -54,6 +54,10 @@ export {
54
54
  PreviewDeviceFrame,
55
55
  type PreviewDevice,
56
56
  } from './primitives/preview-device-frame';
57
+ export {
58
+ UrlPreviewChrome,
59
+ type UrlPreviewChromeProps,
60
+ } from './primitives/url-preview-chrome';
57
61
 
58
62
  // ── chart primitives (Wave 9.2 — pure SVG, no external chart lib) ──
59
63
  export * from './charts';
@@ -87,7 +91,10 @@ export { default as PageHeader, PageToolbar } from './chrome/PageHeader';
87
91
  export { default as LoadingState, type LoadingStateVariant } from './chrome/LoadingState';
88
92
  export { default as AsyncBoundary } from './chrome/AsyncBoundary';
89
93
 
90
- export { PdfPreview, type PdfPreviewProps } from './pdf/pdf-preview';
94
+ // NOTE: `PdfPreview` intentionally does NOT live in this barrel. It pulls in
95
+ // `react-pdf` → `pdfjs-dist` (~1.9 MB), so it ships from the dedicated subpath
96
+ // `@xemahq/ui-kernel/pdf` to keep this `/ui` surface (and app-ui's AppShell)
97
+ // tree-shakeable. Import it from `@xemahq/ui-kernel/pdf`.
91
98
 
92
99
  // ── guided-capture UX kit (B5 — wizard, validation, prefill, schema form) ──
93
100
  export * from './capture';