@xemahq/ui-kernel 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/README.md +2 -2
  2. package/dist/lib/biome-host/biome-builders.d.ts.map +1 -1
  3. package/dist/lib/biome-host/biome-builders.js +3 -1
  4. package/dist/lib/biome-host/biome-builders.js.map +1 -1
  5. package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
  6. package/dist/lib/biome-host/biome-registry.js.map +1 -1
  7. package/dist/lib/biome-host/biome-scope-hooks.d.ts +11 -0
  8. package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -0
  9. package/dist/lib/biome-host/biome-scope-hooks.js +25 -0
  10. package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -0
  11. package/dist/lib/biome-host/biome-scope.d.ts +1 -10
  12. package/dist/lib/biome-host/biome-scope.d.ts.map +1 -1
  13. package/dist/lib/biome-host/biome-scope.js +1 -24
  14. package/dist/lib/biome-host/biome-scope.js.map +1 -1
  15. package/dist/lib/biome-host/biome-scoped-query.d.ts +1 -1
  16. package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
  17. package/dist/lib/biome-host/biome-scoped-query.js +1 -1
  18. package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
  19. package/dist/lib/biome-host/create-biome-orval-config.js +2 -2
  20. package/dist/lib/biome-host/create-biome-orval-config.js.map +1 -1
  21. package/dist/lib/biome-host/errors.js.map +1 -1
  22. package/dist/lib/biome-host/index.d.ts +1 -2
  23. package/dist/lib/biome-host/index.d.ts.map +1 -1
  24. package/dist/lib/biome-host/index.js +1 -2
  25. package/dist/lib/biome-host/index.js.map +1 -1
  26. package/dist/lib/biome-host/session-contributions.d.ts +9 -4
  27. package/dist/lib/biome-host/session-contributions.d.ts.map +1 -1
  28. package/dist/lib/capabilities/capability-context.d.ts +9 -0
  29. package/dist/lib/capabilities/capability-context.d.ts.map +1 -0
  30. package/dist/lib/capabilities/capability-context.js +13 -0
  31. package/dist/lib/capabilities/capability-context.js.map +1 -0
  32. package/dist/lib/capabilities/capability-provider.d.ts +2 -8
  33. package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
  34. package/dist/lib/capabilities/capability-provider.js +1 -12
  35. package/dist/lib/capabilities/capability-provider.js.map +1 -1
  36. package/dist/lib/capabilities/index.d.ts +1 -0
  37. package/dist/lib/capabilities/index.d.ts.map +1 -1
  38. package/dist/lib/capabilities/index.js +1 -0
  39. package/dist/lib/capabilities/index.js.map +1 -1
  40. package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
  41. package/dist/lib/capabilities/use-capability.js +1 -1
  42. package/dist/lib/capabilities/use-capability.js.map +1 -1
  43. package/dist/lib/system-bus/deeplink.js.map +1 -1
  44. package/dist/lib/system-bus/host-ports.d.ts +2 -1
  45. package/dist/lib/system-bus/host-ports.d.ts.map +1 -1
  46. package/dist/lib/system-bus/intent-registry.d.ts.map +1 -1
  47. package/dist/lib/system-bus/intent-registry.js.map +1 -1
  48. package/dist/offline/index.d.ts +2 -1
  49. package/dist/offline/index.d.ts.map +1 -1
  50. package/dist/offline/index.js +2 -1
  51. package/dist/offline/index.js.map +1 -1
  52. package/dist/offline/offline-status-badge.js +1 -1
  53. package/dist/offline/offline-status-badge.js.map +1 -1
  54. package/dist/offline/outbox.js.map +1 -1
  55. package/dist/offline/react-hooks.d.ts +7 -0
  56. package/dist/offline/react-hooks.d.ts.map +1 -0
  57. package/dist/offline/react-hooks.js +25 -0
  58. package/dist/offline/react-hooks.js.map +1 -0
  59. package/dist/offline/react.d.ts +0 -4
  60. package/dist/offline/react.d.ts.map +1 -1
  61. package/dist/offline/react.js +2 -24
  62. package/dist/offline/react.js.map +1 -1
  63. package/dist/offline/storage.d.ts.map +1 -1
  64. package/dist/offline/storage.js +8 -5
  65. package/dist/offline/storage.js.map +1 -1
  66. package/dist/registry/index.d.ts +1 -0
  67. package/dist/registry/index.d.ts.map +1 -1
  68. package/dist/registry/index.js +1 -0
  69. package/dist/registry/index.js.map +1 -1
  70. package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
  71. package/dist/registry/lib/primitives/SessionEventCard.js +1 -1
  72. package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
  73. package/dist/registry/lib/session-context-builder.d.ts +10 -2
  74. package/dist/registry/lib/session-context-builder.d.ts.map +1 -1
  75. package/dist/registry/lib/session-context-builder.js +14 -7
  76. package/dist/registry/lib/session-context-builder.js.map +1 -1
  77. package/dist/registry/lib/session-context-provider.d.ts +1 -3
  78. package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
  79. package/dist/registry/lib/session-context-provider.js +2 -15
  80. package/dist/registry/lib/session-context-provider.js.map +1 -1
  81. package/dist/registry/lib/session-context.d.ts +5 -0
  82. package/dist/registry/lib/session-context.d.ts.map +1 -0
  83. package/dist/registry/lib/session-context.js +15 -0
  84. package/dist/registry/lib/session-context.js.map +1 -0
  85. package/dist/registry/lib/session-selectors.d.ts.map +1 -1
  86. package/dist/registry/lib/session-selectors.js +3 -1
  87. package/dist/registry/lib/session-selectors.js.map +1 -1
  88. package/dist/ui/branding/app-branding-context.d.ts +9 -0
  89. package/dist/ui/branding/app-branding-context.d.ts.map +1 -0
  90. package/dist/ui/branding/app-branding-context.js +10 -0
  91. package/dist/ui/branding/app-branding-context.js.map +1 -0
  92. package/dist/ui/branding/app-branding-provider.d.ts +0 -6
  93. package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
  94. package/dist/ui/branding/app-branding-provider.js +1 -8
  95. package/dist/ui/branding/app-branding-provider.js.map +1 -1
  96. package/dist/ui/capture/schema-field-input.js +1 -1
  97. package/dist/ui/capture/schema-field-input.js.map +1 -1
  98. package/dist/ui/capture/use-prefill.d.ts.map +1 -1
  99. package/dist/ui/capture/use-prefill.js +3 -1
  100. package/dist/ui/capture/use-prefill.js.map +1 -1
  101. package/dist/ui/capture/use-wizard.d.ts +1 -1
  102. package/dist/ui/capture/use-wizard.d.ts.map +1 -1
  103. package/dist/ui/capture/use-wizard.js +1 -1
  104. package/dist/ui/capture/use-wizard.js.map +1 -1
  105. package/dist/ui/capture/wizard.d.ts.map +1 -1
  106. package/dist/ui/capture/wizard.js.map +1 -1
  107. package/dist/ui/index.d.ts +5 -1
  108. package/dist/ui/index.d.ts.map +1 -1
  109. package/dist/ui/index.js +5 -1
  110. package/dist/ui/index.js.map +1 -1
  111. package/dist/ui/primitives/alert-dialog.js +1 -1
  112. package/dist/ui/primitives/alert-dialog.js.map +1 -1
  113. package/dist/ui/primitives/badge-variants.d.ts +4 -0
  114. package/dist/ui/primitives/badge-variants.d.ts.map +1 -0
  115. package/dist/ui/primitives/badge-variants.js +15 -0
  116. package/dist/ui/primitives/badge-variants.js.map +1 -0
  117. package/dist/ui/primitives/badge.d.ts +3 -5
  118. package/dist/ui/primitives/badge.d.ts.map +1 -1
  119. package/dist/ui/primitives/badge.js +2 -15
  120. package/dist/ui/primitives/badge.js.map +1 -1
  121. package/dist/ui/primitives/button-variants.d.ts +5 -0
  122. package/dist/ui/primitives/button-variants.d.ts.map +1 -0
  123. package/dist/ui/primitives/button-variants.js +24 -0
  124. package/dist/ui/primitives/button-variants.js.map +1 -0
  125. package/dist/ui/primitives/button.d.ts +3 -6
  126. package/dist/ui/primitives/button.d.ts.map +1 -1
  127. package/dist/ui/primitives/button.js +2 -24
  128. package/dist/ui/primitives/button.js.map +1 -1
  129. package/dist/ui/primitives/form-stepper.d.ts +1 -13
  130. package/dist/ui/primitives/form-stepper.d.ts.map +1 -1
  131. package/dist/ui/primitives/form-stepper.js +1 -6
  132. package/dist/ui/primitives/form-stepper.js.map +1 -1
  133. package/dist/ui/primitives/form-stepper.types.d.ts +14 -0
  134. package/dist/ui/primitives/form-stepper.types.d.ts.map +1 -0
  135. package/dist/ui/primitives/form-stepper.types.js +7 -0
  136. package/dist/ui/primitives/form-stepper.types.js.map +1 -0
  137. package/dist/ui/primitives/preview-device-frame.js +1 -1
  138. package/dist/ui/primitives/preview-device-frame.js.map +1 -1
  139. package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
  140. package/dist/ui/primitives/tag-multi-select.js +1 -1
  141. package/dist/ui/primitives/tag-multi-select.js.map +1 -1
  142. package/dist/vista/index.d.ts +4 -0
  143. package/dist/vista/index.d.ts.map +1 -1
  144. package/dist/vista/index.js +4 -0
  145. package/dist/vista/index.js.map +1 -1
  146. package/dist/vista/surfaces/FilesSurface.d.ts +1 -12
  147. package/dist/vista/surfaces/FilesSurface.d.ts.map +1 -1
  148. package/dist/vista/surfaces/FilesSurface.js +2 -46
  149. package/dist/vista/surfaces/FilesSurface.js.map +1 -1
  150. package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
  151. package/dist/vista/surfaces/FormSurface.js +39 -12
  152. package/dist/vista/surfaces/FormSurface.js.map +1 -1
  153. package/dist/vista/surfaces/elicitation-transport.d.ts +12 -3
  154. package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
  155. package/dist/vista/surfaces/elicitation-transport.js +96 -3
  156. package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
  157. package/dist/vista/surfaces/file-surface-utils.d.ts +13 -0
  158. package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -0
  159. package/dist/vista/surfaces/file-surface-utils.js +46 -0
  160. package/dist/vista/surfaces/file-surface-utils.js.map +1 -0
  161. package/dist/vista/surfaces/index.d.ts +4 -3
  162. package/dist/vista/surfaces/index.d.ts.map +1 -1
  163. package/dist/vista/surfaces/index.js +4 -81
  164. package/dist/vista/surfaces/index.js.map +1 -1
  165. package/dist/vista/surfaces/register-surfaces.d.ts +2 -0
  166. package/dist/vista/surfaces/register-surfaces.d.ts.map +1 -0
  167. package/dist/vista/surfaces/register-surfaces.js +80 -0
  168. package/dist/vista/surfaces/register-surfaces.js.map +1 -0
  169. package/dist/vista/surfaces/text-surfaces.js +1 -1
  170. package/dist/vista/surfaces/text-surfaces.js.map +1 -1
  171. package/dist/vista/vista-code-renderer-context.d.ts +9 -0
  172. package/dist/vista/vista-code-renderer-context.d.ts.map +1 -0
  173. package/dist/vista/vista-code-renderer-context.js +6 -0
  174. package/dist/vista/vista-code-renderer-context.js.map +1 -0
  175. package/dist/vista/vista-code-renderer.d.ts +1 -6
  176. package/dist/vista/vista-code-renderer.d.ts.map +1 -1
  177. package/dist/vista/vista-code-renderer.js +1 -5
  178. package/dist/vista/vista-code-renderer.js.map +1 -1
  179. package/dist/vista/vista-file-context.d.ts +8 -0
  180. package/dist/vista/vista-file-context.d.ts.map +1 -0
  181. package/dist/vista/vista-file-context.js +6 -0
  182. package/dist/vista/vista-file-context.js.map +1 -0
  183. package/dist/vista/vista-file-source.d.ts +1 -6
  184. package/dist/vista/vista-file-source.d.ts.map +1 -1
  185. package/dist/vista/vista-file-source.js +2 -5
  186. package/dist/vista/vista-file-source.js.map +1 -1
  187. package/dist/vista/vista-form-context.d.ts +13 -0
  188. package/dist/vista/vista-form-context.d.ts.map +1 -0
  189. package/dist/vista/vista-form-context.js +6 -0
  190. package/dist/vista/vista-form-context.js.map +1 -0
  191. package/dist/vista/vista-form-host.d.ts +1 -10
  192. package/dist/vista/vista-form-host.d.ts.map +1 -1
  193. package/dist/vista/vista-form-host.js +1 -5
  194. package/dist/vista/vista-form-host.js.map +1 -1
  195. package/dist/vista/vista-open-context.d.ts +1 -3
  196. package/dist/vista/vista-open-context.d.ts.map +1 -1
  197. package/dist/vista/vista-open-context.js +1 -5
  198. package/dist/vista/vista-open-context.js.map +1 -1
  199. package/dist/vista/vista-open-state.d.ts +5 -0
  200. package/dist/vista/vista-open-state.d.ts.map +1 -0
  201. package/dist/vista/vista-open-state.js +6 -0
  202. package/dist/vista/vista-open-state.js.map +1 -0
  203. package/dist/vista/vista-payloads.d.ts +2 -3
  204. package/dist/vista/vista-payloads.d.ts.map +1 -1
  205. package/dist/vista/vista-payloads.js +18 -21
  206. package/dist/vista/vista-payloads.js.map +1 -1
  207. package/dist/vista/vista-tools.d.ts.map +1 -1
  208. package/dist/vista/vista-tools.js.map +1 -1
  209. package/package.json +3 -3
  210. package/src/lib/biome-host/biome-builders.ts +4 -1
  211. package/src/lib/biome-host/biome-registry.ts +0 -1
  212. package/src/lib/biome-host/biome-scope-hooks.ts +39 -0
  213. package/src/lib/biome-host/biome-scope.tsx +1 -68
  214. package/src/lib/biome-host/biome-scoped-query.ts +4 -1
  215. package/src/lib/biome-host/create-biome-orval-config.ts +2 -2
  216. package/src/lib/biome-host/errors.ts +1 -1
  217. package/src/lib/biome-host/index.ts +1 -2
  218. package/src/lib/biome-host/session-contributions.ts +21 -18
  219. package/src/lib/capabilities/capability-context.ts +25 -0
  220. package/src/lib/capabilities/capability-provider.tsx +5 -34
  221. package/src/lib/capabilities/index.ts +1 -0
  222. package/src/lib/capabilities/use-capability.ts +4 -1
  223. package/src/lib/system-bus/deeplink.ts +1 -1
  224. package/src/lib/system-bus/host-ports.ts +2 -1
  225. package/src/lib/system-bus/intent-registry.ts +1 -2
  226. package/src/offline/index.ts +4 -2
  227. package/src/offline/offline-status-badge.tsx +1 -1
  228. package/src/offline/outbox.test.ts +23 -16
  229. package/src/offline/outbox.ts +1 -1
  230. package/src/offline/react-hooks.ts +37 -0
  231. package/src/offline/react.tsx +1 -40
  232. package/src/offline/storage.ts +11 -6
  233. package/src/registry/index.ts +1 -0
  234. package/src/registry/lib/primitives/SessionEventCard.tsx +4 -2
  235. package/src/registry/lib/session-context-builder.ts +33 -17
  236. package/src/registry/lib/session-context-provider.tsx +8 -25
  237. package/src/registry/lib/session-context.ts +21 -0
  238. package/src/registry/lib/session-selectors.ts +3 -1
  239. package/src/ui/branding/app-branding-context.ts +20 -0
  240. package/src/ui/branding/app-branding-provider.tsx +5 -27
  241. package/src/ui/capture/schema-field-input.tsx +7 -1
  242. package/src/ui/capture/use-prefill.ts +4 -1
  243. package/src/ui/capture/use-wizard.ts +2 -2
  244. package/src/ui/capture/wizard.tsx +2 -1
  245. package/src/ui/index.ts +7 -2
  246. package/src/ui/primitives/alert-dialog.tsx +1 -1
  247. package/src/ui/primitives/badge-variants.ts +21 -0
  248. package/src/ui/primitives/badge.tsx +3 -19
  249. package/src/ui/primitives/button-variants.ts +31 -0
  250. package/src/ui/primitives/button.tsx +3 -28
  251. package/src/ui/primitives/form-stepper.tsx +1 -16
  252. package/src/ui/primitives/form-stepper.types.ts +15 -0
  253. package/src/ui/primitives/preview-device-frame.tsx +1 -1
  254. package/src/ui/primitives/tag-multi-select.tsx +3 -4
  255. package/src/vista/form-payload.spec.ts +71 -25
  256. package/src/vista/index.ts +4 -0
  257. package/src/vista/surfaces/FilesSurface.tsx +2 -68
  258. package/src/vista/surfaces/FormSurface.tsx +125 -26
  259. package/src/vista/surfaces/elicitation-transport.spec.ts +205 -23
  260. package/src/vista/surfaces/elicitation-transport.ts +192 -14
  261. package/src/vista/surfaces/file-surface-utils.ts +62 -0
  262. package/src/vista/surfaces/index.ts +24 -0
  263. package/src/vista/surfaces/{index.tsx → register-surfaces.tsx} +1 -21
  264. package/src/vista/surfaces/text-surfaces.tsx +1 -1
  265. package/src/vista/vista-code-renderer-context.ts +16 -0
  266. package/src/vista/vista-code-renderer.tsx +4 -16
  267. package/src/vista/vista-file-context.ts +14 -0
  268. package/src/vista/vista-file-source.tsx +5 -28
  269. package/src/vista/vista-form-context.ts +20 -0
  270. package/src/vista/vista-form-host.tsx +11 -36
  271. package/src/vista/vista-open-context.tsx +4 -14
  272. package/src/vista/vista-open-state.ts +11 -0
  273. package/src/vista/vista-payloads.ts +44 -46
  274. package/src/vista/vista-tools.ts +2 -2
  275. package/dist/lib/biome-host/response-envelope.d.ts +0 -3
  276. package/dist/lib/biome-host/response-envelope.d.ts.map +0 -1
  277. package/dist/lib/biome-host/response-envelope.js +0 -21
  278. package/dist/lib/biome-host/response-envelope.js.map +0 -1
  279. package/dist/lib/biome-host/session-profiles.d.ts +0 -18
  280. package/dist/lib/biome-host/session-profiles.d.ts.map +0 -1
  281. package/dist/lib/biome-host/session-profiles.js +0 -35
  282. package/dist/lib/biome-host/session-profiles.js.map +0 -1
  283. package/src/lib/biome-host/response-envelope.ts +0 -69
  284. package/src/lib/biome-host/session-profiles.ts +0 -99
package/src/ui/index.ts CHANGED
@@ -24,7 +24,9 @@ export { useIsMobile } from './hooks/use-is-mobile';
24
24
 
25
25
  // ── shadcn primitives ──
26
26
  export * from './primitives/button';
27
+ export * from './primitives/button-variants';
27
28
  export * from './primitives/badge';
29
+ export * from './primitives/badge-variants';
28
30
  export * from './primitives/input';
29
31
  export * from './primitives/label';
30
32
  export * from './primitives/select';
@@ -49,6 +51,7 @@ export * from './primitives/overflow-tabs';
49
51
  export * from './primitives/tag-multi-select';
50
52
  export * from './primitives/sheet';
51
53
  export * from './primitives/form-stepper';
54
+ export * from './primitives/form-stepper.types';
52
55
  export * from './primitives/async-combobox';
53
56
  export {
54
57
  PreviewDeviceFrame,
@@ -65,11 +68,13 @@ export * from './charts';
65
68
  // ── runtime branding applier (Wave 8.4) ──
66
69
  export {
67
70
  AppBrandingProvider,
68
- useAppBranding,
69
71
  APP_PRIMARY_COLOR_VAR,
70
72
  type AppBrandingProviderProps,
71
- type AppBrandingContextValue,
72
73
  } from './branding/app-branding-provider';
74
+ export {
75
+ useAppBranding,
76
+ type AppBrandingContextValue,
77
+ } from './branding/app-branding-context';
73
78
 
74
79
  // ── Xema chrome ──
75
80
  export { default as ErrorCard, type ErrorMessageFormatter } from './chrome/ErrorCard';
@@ -1,7 +1,7 @@
1
1
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
2
2
  import * as React from "react";
3
3
 
4
- import { buttonVariants } from './button';
4
+ import { buttonVariants } from './button-variants';
5
5
  import { cn } from '../cn';
6
6
 
7
7
  const AlertDialog = AlertDialogPrimitive.Root;
@@ -0,0 +1,21 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ export const badgeVariants = cva(
4
+ 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-body-1 font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
5
+ {
6
+ variants: {
7
+ variant: {
8
+ default:
9
+ 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
10
+ secondary:
11
+ 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
12
+ destructive:
13
+ 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
14
+ outline: 'border-rule bg-paper text-ink',
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ variant: 'default',
19
+ },
20
+ },
21
+ );
@@ -1,24 +1,8 @@
1
- import { cva, type VariantProps } from "class-variance-authority";
1
+ import type { VariantProps } from "class-variance-authority";
2
2
  import * as React from "react";
3
3
 
4
4
  import { cn } from '../cn';
5
-
6
- const badgeVariants = cva(
7
- "inline-flex items-center rounded-full border px-2.5 py-0.5 text-body-1 font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8
- {
9
- variants: {
10
- variant: {
11
- default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
12
- secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
13
- destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
14
- outline: "border-rule bg-paper text-ink",
15
- },
16
- },
17
- defaultVariants: {
18
- variant: "default",
19
- },
20
- },
21
- );
5
+ import { badgeVariants } from './badge-variants';
22
6
 
23
7
  export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps<typeof badgeVariants> {}
24
8
 
@@ -29,4 +13,4 @@ const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
29
13
  );
30
14
  Badge.displayName = "Badge";
31
15
 
32
- export { Badge, badgeVariants };
16
+ export { Badge };
@@ -0,0 +1,31 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ export const buttonVariants = cva(
4
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-body-1 font-medium ring-offset-background transition-[background-color,color,border-color,box-shadow] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
5
+ {
6
+ variants: {
7
+ variant: {
8
+ default:
9
+ 'bg-primary text-primary-foreground hover:bg-primary/90',
10
+ destructive:
11
+ 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
12
+ outline:
13
+ 'border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground',
14
+ secondary:
15
+ 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
16
+ ghost: 'text-ink-2 hover:bg-paper-elev hover:text-ink',
17
+ link: 'text-primary underline-offset-4 hover:underline',
18
+ },
19
+ size: {
20
+ default: 'h-10 px-4 py-2',
21
+ sm: 'h-9 rounded-md px-3',
22
+ lg: 'h-11 rounded-md px-8',
23
+ icon: 'h-10 w-10',
24
+ },
25
+ },
26
+ defaultVariants: {
27
+ variant: 'default',
28
+ size: 'default',
29
+ },
30
+ },
31
+ );
@@ -1,34 +1,9 @@
1
1
  import { Slot } from "@radix-ui/react-slot";
2
- import { cva, type VariantProps } from "class-variance-authority";
2
+ import type { VariantProps } from "class-variance-authority";
3
3
  import * as React from "react";
4
4
 
5
5
  import { cn } from '../cn';
6
-
7
- const buttonVariants = cva(
8
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-body-1 font-medium ring-offset-background transition-[background-color,color,border-color,box-shadow] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
9
- {
10
- variants: {
11
- variant: {
12
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
14
- outline: "border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground",
15
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
16
- ghost: "text-ink-2 hover:bg-paper-elev hover:text-ink",
17
- link: "text-primary underline-offset-4 hover:underline",
18
- },
19
- size: {
20
- default: "h-10 px-4 py-2",
21
- sm: "h-9 rounded-md px-3",
22
- lg: "h-11 rounded-md px-8",
23
- icon: "h-10 w-10",
24
- },
25
- },
26
- defaultVariants: {
27
- variant: "default",
28
- size: "default",
29
- },
30
- },
31
- );
6
+ import { buttonVariants } from './button-variants';
32
7
 
33
8
  export interface ButtonProps
34
9
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
@@ -44,4 +19,4 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
44
19
  );
45
20
  Button.displayName = "Button";
46
21
 
47
- export { Button, buttonVariants };
22
+ export { Button };
@@ -1,22 +1,7 @@
1
1
  import { Check } from 'lucide-react';
2
2
 
3
- import type { ReactNode } from 'react';
4
-
5
3
  import { cn } from '../cn';
6
-
7
- export enum FormStepStatus {
8
- PENDING = 'pending',
9
- ACTIVE = 'active',
10
- DONE = 'done',
11
- }
12
-
13
- export interface FormStep {
14
- readonly key: string;
15
- readonly label: string;
16
- readonly hint?: string;
17
- readonly status: FormStepStatus;
18
- readonly children: ReactNode;
19
- }
4
+ import { FormStepStatus, type FormStep } from './form-stepper.types';
20
5
 
21
6
  interface FormStepperProps {
22
7
  readonly steps: readonly FormStep[];
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ export enum FormStepStatus {
4
+ PENDING = 'pending',
5
+ ACTIVE = 'active',
6
+ DONE = 'done',
7
+ }
8
+
9
+ export interface FormStep {
10
+ readonly key: string;
11
+ readonly label: string;
12
+ readonly hint?: string;
13
+ readonly status: FormStepStatus;
14
+ readonly children: ReactNode;
15
+ }
@@ -181,7 +181,7 @@ function ResponsiveViewport({
181
181
  const observer = new ResizeObserver(compute);
182
182
  observer.observe(el);
183
183
  return () => observer.disconnect();
184
- }, [bezel.width, bezel.height]);
184
+ }, [aspectRatio, bezel.width, bezel.height]);
185
185
 
186
186
  return (
187
187
  <div
@@ -138,9 +138,8 @@ export function TagMultiSelect({
138
138
  className={cn('text-body-1 gap-1 pr-1', chipClass)}
139
139
  >
140
140
  <span className="truncate max-w-[160px]">{opt?.label ?? val}</span>
141
- <span
142
- role="button"
143
- tabIndex={-1}
141
+ <button
142
+ type="button"
144
143
  onClick={(e) => remove(val, e)}
145
144
  onKeyDown={(e) => {
146
145
  if (e.key === 'Enter' || e.key === ' ') {
@@ -153,7 +152,7 @@ export function TagMultiSelect({
153
152
  aria-label={`Remove ${opt?.label ?? val}`}
154
153
  >
155
154
  <X className="h-4 w-4" />
156
- </span>
155
+ </button>
157
156
  </Badge>
158
157
  );
159
158
  })}
@@ -2,22 +2,17 @@
2
2
  * Guards `validateFormPayload` — the structural half of "the value never
3
3
  * reaches the agent".
4
4
  *
5
- * The validator is what makes the submit target un-aimable at the host's own
6
- * origin (where the BFF / chat transport lives): only an ABSOLUTE `http(s)`
7
- * URL is accepted, and a rejected payload draws the typed fallback card rather
8
- * than a form.
5
+ * The payload has no network authority: it carries only a base64url opaque ref,
6
+ * while the trusted service base URL comes from `VistaFormHost`.
9
7
  */
10
8
  import { describe, expect, it } from 'vitest';
11
9
 
12
- import { CaptureFieldType } from '../ui/capture/field-spec';
13
-
14
10
  import { validateFormPayload } from './vista-payloads';
11
+ import { CaptureFieldType } from '../ui/capture/field-spec';
15
12
 
16
13
  const BASE = {
17
14
  ref: 'ref-1',
18
15
  purpose: 'Connect Acme so I can read your tickets.',
19
- submitUrl: 'https://connector-gateway.example.test/credential-elicitations/ref-1/submit',
20
- statusUrl: 'https://connector-gateway.example.test/credential-elicitations/ref-1',
21
16
  fields: [
22
17
  {
23
18
  key: 'apiKey',
@@ -27,7 +22,13 @@ const BASE = {
27
22
  isSecret: true,
28
23
  transform: 'trim',
29
24
  },
30
- { key: 'baseUrl', label: 'Base URL', type: CaptureFieldType.Url, required: true, isSecret: false },
25
+ {
26
+ key: 'baseUrl',
27
+ label: 'Base URL',
28
+ type: CaptureFieldType.Url,
29
+ required: true,
30
+ isSecret: false,
31
+ },
31
32
  ],
32
33
  };
33
34
 
@@ -41,11 +42,17 @@ describe('validateFormPayload', () => {
41
42
  expect(payload?.fields[0]?.transform).toBe('trim');
42
43
  });
43
44
 
44
- it('REJECTS a host-relative submit URL — it could only hit the app itself', () => {
45
- expect(validateFormPayload({ ...BASE, submitUrl: '/credential-elicitations/ref-1/submit' })).toBeNull();
46
- expect(validateFormPayload({ ...BASE, submitUrl: '//evil.example/x' })).toBeNull();
47
- expect(validateFormPayload({ ...BASE, submitUrl: 'javascript:alert(1)' })).toBeNull();
48
- expect(validateFormPayload({ ...BASE, statusUrl: '/credential-elicitations/ref-1' })).toBeNull();
45
+ it('rejects old or malicious payload-selected submit/status authorities', () => {
46
+ for (const target of [
47
+ 'https://evil.example/steal',
48
+ 'https://trusted.example@evil.example/steal',
49
+ '//evil.example/steal',
50
+ '/credential-elicitations/ref-1/submit',
51
+ 'javascript:alert(1)',
52
+ ]) {
53
+ expect(validateFormPayload({ ...BASE, submitUrl: target })).toBeNull();
54
+ expect(validateFormPayload({ ...BASE, statusUrl: target })).toBeNull();
55
+ }
49
56
  });
50
57
 
51
58
  it('accepts an EMPTY field schema — the service is the authority, not the client', () => {
@@ -55,39 +62,78 @@ describe('validateFormPayload', () => {
55
62
  });
56
63
 
57
64
  it('rejects a malformed field spec rather than half-rendering it', () => {
58
- expect(validateFormPayload({ ...BASE, fields: [{ key: 'a', label: 'A', type: 'nope' }] })).toBeNull();
59
- expect(validateFormPayload({ ...BASE, fields: [{ key: 'a', label: 'A' }] })).toBeNull();
60
65
  expect(
61
66
  validateFormPayload({
62
67
  ...BASE,
63
- fields: [{ key: 'a', label: 'A', type: CaptureFieldType.String, isSecret: 'yes' }],
68
+ fields: [{ key: 'a', label: 'A', type: 'nope' }],
69
+ }),
70
+ ).toBeNull();
71
+ expect(
72
+ validateFormPayload({ ...BASE, fields: [{ key: 'a', label: 'A' }] }),
73
+ ).toBeNull();
74
+ expect(
75
+ validateFormPayload({
76
+ ...BASE,
77
+ fields: [
78
+ {
79
+ key: 'a',
80
+ label: 'A',
81
+ type: CaptureFieldType.String,
82
+ isSecret: 'yes',
83
+ },
84
+ ],
64
85
  }),
65
86
  ).toBeNull();
66
87
  expect(validateFormPayload({ ...BASE, fields: {} })).toBeNull();
67
88
  });
68
89
 
69
- it('accepts a launch (oauth2 / app_install) payload with an absolute URL', () => {
90
+ it('accepts a launch payload with a root-relative trusted-service path', () => {
70
91
  const payload = validateFormPayload({
71
92
  ...BASE,
72
93
  fields: [],
73
- launch: { url: 'https://acme.example.test/oauth/authorize?x=1', label: 'Continue to Acme', hint: 'h' },
94
+ launch: {
95
+ path: '/oauth/authorize?x=1',
96
+ label: 'Continue to Acme',
97
+ hint: 'h',
98
+ },
74
99
  });
75
100
  expect(payload?.launch).toEqual({
76
- url: 'https://acme.example.test/oauth/authorize?x=1',
101
+ path: '/oauth/authorize?x=1',
77
102
  label: 'Continue to Acme',
78
103
  hint: 'h',
79
104
  });
80
105
  });
81
106
 
82
- it('rejects a launch with a relative URL or no label', () => {
83
- expect(validateFormPayload({ ...BASE, launch: { url: '/authorize', label: 'Go' } })).toBeNull();
107
+ it('rejects launch authority/scheme confusion and malformed paths', () => {
108
+ for (const path of [
109
+ 'authorize',
110
+ '//evil.example/authorize',
111
+ 'https://evil.example/authorize',
112
+ 'javascript:alert(1)',
113
+ '\\\\evil.example\\authorize',
114
+ ]) {
115
+ expect(
116
+ validateFormPayload({ ...BASE, launch: { path, label: 'Go' } }),
117
+ ).toBeNull();
118
+ }
119
+ expect(
120
+ validateFormPayload({
121
+ ...BASE,
122
+ launch: { url: 'https://evil.example/a', label: 'Go' },
123
+ }),
124
+ ).toBeNull();
84
125
  expect(
85
- validateFormPayload({ ...BASE, launch: { url: 'https://acme.example.test/a', label: '' } }),
126
+ validateFormPayload({
127
+ ...BASE,
128
+ launch: { path: '/authorize', label: '' },
129
+ }),
86
130
  ).toBeNull();
87
131
  });
88
132
 
89
- it('rejects a missing ref', () => {
90
- expect(validateFormPayload({ ...BASE, ref: '' })).toBeNull();
133
+ it('rejects missing refs and path-traversal/encoding input', () => {
134
+ for (const ref of ['', '.', '..', '../steal', 'a/b', '%2e%2e', 'réf']) {
135
+ expect(validateFormPayload({ ...BASE, ref })).toBeNull();
136
+ }
91
137
  expect(validateFormPayload({ ...BASE, ref: undefined })).toBeNull();
92
138
  });
93
139
  });
@@ -36,9 +36,13 @@ export * from './vista-model';
36
36
  export * from './vista-payloads';
37
37
  export * from './vista-tabs-manifest';
38
38
  export * from './vista-file-source';
39
+ export * from './vista-file-context';
39
40
  export * from './vista-form-host';
41
+ export * from './vista-form-context';
40
42
  export * from './vista-code-renderer';
43
+ export * from './vista-code-renderer-context';
41
44
  export * from './vista-open-context';
45
+ export * from './vista-open-state';
42
46
  export * from './use-vista-tabs';
43
47
  export * from './VistaPanel';
44
48
  export * from './vista-tools';
@@ -13,78 +13,12 @@ import { ChevronRight, Folder } from 'lucide-react';
13
13
 
14
14
 
15
15
  import { fileSurface } from '../vista-model';
16
- import { useVistaOpen } from '../vista-open-context';
16
+ import { useVistaOpen } from '../vista-open-state';
17
+ import { fileExtMeta, groupFilesByFolder } from './file-surface-utils';
17
18
 
18
19
  import type { VistaFileEntry, VistaFilesPayload } from '../vista-payloads';
19
20
  import type { ReactElement } from 'react';
20
21
 
21
- /** Extension → colour-coded tile metadata. */
22
- interface FileExtMeta {
23
- readonly color: string;
24
- readonly tag: string;
25
- }
26
-
27
- const EXT_META: Readonly<Record<string, FileExtMeta>> = {
28
- ts: { color: 'hsl(var(--info))', tag: 'TS' },
29
- tsx: { color: 'hsl(var(--info))', tag: 'TSX' },
30
- js: { color: 'hsl(var(--warning))', tag: 'JS' },
31
- jsx: { color: 'hsl(var(--warning))', tag: 'JSX' },
32
- json: { color: 'hsl(var(--ink-3))', tag: 'JSON' },
33
- md: { color: 'hsl(var(--p-people))', tag: 'MD' },
34
- css: { color: 'hsl(var(--p-sales))', tag: 'CSS' },
35
- html: { color: 'hsl(var(--p-sales))', tag: 'HTML' },
36
- yaml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
37
- yml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
38
- };
39
-
40
- /** Resolve the colour-coded tile metadata for a filename. */
41
- export function fileExtMeta(name: string): FileExtMeta {
42
- if (/\.test\.[tj]sx?$/.test(name) || /\.spec\.[tj]sx?$/.test(name)) {
43
- return { color: 'hsl(var(--success))', tag: 'TEST' };
44
- }
45
- const ext = name.split('.').pop() ?? '';
46
- return (
47
- EXT_META[ext] ?? {
48
- color: 'hsl(var(--ink-4))',
49
- tag: (ext || 'FILE').toUpperCase().slice(0, 4),
50
- }
51
- );
52
- }
53
-
54
- /** A group of files under one folder caption. */
55
- export interface VistaFileGroup {
56
- /** Folder path (`''` = root). */
57
- readonly dir: string;
58
- readonly files: readonly VistaFileEntry[];
59
- }
60
-
61
- /** Order folder captions: root first, then alphabetical. */
62
- function compareDirs(a: string, b: string): number {
63
- if (a === '') return -1;
64
- if (b === '') return 1;
65
- return a.localeCompare(b);
66
- }
67
-
68
- /** Group a flat file list by folder, root group first, paths sorted. */
69
- export function groupFilesByFolder(
70
- files: readonly VistaFileEntry[],
71
- ): VistaFileGroup[] {
72
- const groups = new Map<string, VistaFileEntry[]>();
73
- for (const file of files) {
74
- const slash = file.path.lastIndexOf('/');
75
- const dir = slash < 0 ? '' : file.path.slice(0, slash);
76
- const bucket = groups.get(dir);
77
- if (bucket) bucket.push(file);
78
- else groups.set(dir, [file]);
79
- }
80
- return [...groups.keys()].sort(compareDirs).map((dir) => ({
81
- dir,
82
- files: [...(groups.get(dir) ?? [])].sort((a, b) =>
83
- a.path.localeCompare(b.path),
84
- ),
85
- }));
86
- }
87
-
88
22
  export function FilesSurface({
89
23
  files,
90
24
  }: Readonly<VistaFilesPayload>): ReactElement {