@xemahq/ui-kernel 0.11.0 → 0.11.2

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 (237) hide show
  1. package/dist/ui/chrome/page-shell.d.ts +1 -1
  2. package/dist/ui/chrome/page-shell.d.ts.map +1 -1
  3. package/dist/ui/chrome/page-shell.js +9 -4
  4. package/dist/ui/chrome/page-shell.js.map +1 -1
  5. package/package.json +6 -4
  6. package/src/index.ts +0 -17
  7. package/src/lib/biome-host/agent-validation.ts +0 -239
  8. package/src/lib/biome-host/biome-builders.ts +0 -112
  9. package/src/lib/biome-host/biome-mode.ts +0 -6
  10. package/src/lib/biome-host/biome-navigation.ts +0 -37
  11. package/src/lib/biome-host/biome-registry.ts +0 -299
  12. package/src/lib/biome-host/biome-scope-hooks.ts +0 -41
  13. package/src/lib/biome-host/biome-scope.tsx +0 -52
  14. package/src/lib/biome-host/biome-scoped-query.ts +0 -134
  15. package/src/lib/biome-host/create-biome-orval-config.ts +0 -82
  16. package/src/lib/biome-host/define-web-biome.spec.ts +0 -221
  17. package/src/lib/biome-host/define-web-biome.ts +0 -222
  18. package/src/lib/biome-host/errors.ts +0 -220
  19. package/src/lib/biome-host/frontend-biome.ts +0 -256
  20. package/src/lib/biome-host/host-bridge.ts +0 -281
  21. package/src/lib/biome-host/host-sources.ts +0 -54
  22. package/src/lib/biome-host/i18n-hooks.ts +0 -51
  23. package/src/lib/biome-host/i18n-port.test.ts +0 -50
  24. package/src/lib/biome-host/i18n-port.ts +0 -96
  25. package/src/lib/biome-host/index.ts +0 -35
  26. package/src/lib/biome-host/realtime-hooks.ts +0 -75
  27. package/src/lib/biome-host/realtime-port.ts +0 -115
  28. package/src/lib/biome-host/session-contributions.ts +0 -296
  29. package/src/lib/biome-host/use-mutation-with-error-toast.ts +0 -90
  30. package/src/lib/biome-host/use-page-state.ts +0 -248
  31. package/src/lib/capabilities/capability-context.ts +0 -25
  32. package/src/lib/capabilities/capability-provider.tsx +0 -73
  33. package/src/lib/capabilities/index.ts +0 -17
  34. package/src/lib/capabilities/types.ts +0 -69
  35. package/src/lib/capabilities/use-capability.ts +0 -79
  36. package/src/lib/contribution-registry/contribution-registry.spec.ts +0 -141
  37. package/src/lib/contribution-registry/contribution-registry.ts +0 -204
  38. package/src/lib/contribution-registry/index.ts +0 -9
  39. package/src/lib/contribution-registry/renderable-registry.ts +0 -142
  40. package/src/lib/system-bus/capability-invoke.ts +0 -92
  41. package/src/lib/system-bus/deeplink.ts +0 -210
  42. package/src/lib/system-bus/enums.ts +0 -86
  43. package/src/lib/system-bus/host-ports.ts +0 -93
  44. package/src/lib/system-bus/index.ts +0 -16
  45. package/src/lib/system-bus/intent-registry.ts +0 -109
  46. package/src/lib/system-bus/intents.ts +0 -113
  47. package/src/lib/system-bus/palette.ts +0 -78
  48. package/src/lib/system-bus/system-bus-builder.ts +0 -159
  49. package/src/lib/system-bus/system-bus.ts +0 -37
  50. package/src/lib/system-bus/windows.ts +0 -51
  51. package/src/offline/id.ts +0 -16
  52. package/src/offline/index.ts +0 -54
  53. package/src/offline/mutation.ts +0 -75
  54. package/src/offline/offline-status-badge.tsx +0 -51
  55. package/src/offline/online-controller.ts +0 -105
  56. package/src/offline/outbox.test.ts +0 -172
  57. package/src/offline/outbox.ts +0 -348
  58. package/src/offline/react-hooks.ts +0 -40
  59. package/src/offline/react.tsx +0 -32
  60. package/src/offline/storage.ts +0 -112
  61. package/src/offline/types.ts +0 -77
  62. package/src/org-db/components/DbResultTable.tsx +0 -176
  63. package/src/org-db/index.ts +0 -1
  64. package/src/pdf/index.ts +0 -11
  65. package/src/registry/index.ts +0 -9
  66. package/src/registry/lib/agent-validation-host.ts +0 -36
  67. package/src/registry/lib/biome-slot.tsx +0 -50
  68. package/src/registry/lib/biomes-enabled-context.ts +0 -20
  69. package/src/registry/lib/extension-points.ts +0 -134
  70. package/src/registry/lib/primitives/SessionEventCard.tsx +0 -164
  71. package/src/registry/lib/primitives/SessionEventTimeline.tsx +0 -95
  72. package/src/registry/lib/primitives/SessionMutationBar.tsx +0 -76
  73. package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +0 -165
  74. package/src/registry/lib/primitives/index.ts +0 -18
  75. package/src/registry/lib/session-context-builder.ts +0 -84
  76. package/src/registry/lib/session-context-provider.tsx +0 -33
  77. package/src/registry/lib/session-context.ts +0 -21
  78. package/src/registry/lib/session-selectors.ts +0 -272
  79. package/src/session/comments/CommentRail.tsx +0 -164
  80. package/src/session/index.ts +0 -3
  81. package/src/session/lib/cn.ts +0 -11
  82. package/src/session/shell/SessionWorkspaceShell.tsx +0 -147
  83. package/src/session-kit/approvals/ApprovalButton.tsx +0 -89
  84. package/src/session-kit/approvals/ApprovalCard.tsx +0 -341
  85. package/src/session-kit/approvals/ApprovalsCenter.tsx +0 -336
  86. package/src/session-kit/approvals/CapabilityApprovalStickyBar.tsx +0 -118
  87. package/src/session-kit/approvals/Obligation.tsx +0 -111
  88. package/src/session-kit/approvals/ScopedBody.tsx +0 -392
  89. package/src/session-kit/approvals/approval-icons.ts +0 -31
  90. package/src/session-kit/approvals/approval-model.ts +0 -204
  91. package/src/session-kit/approvals/index.ts +0 -22
  92. package/src/session-kit/approvals/obligation-display.ts +0 -100
  93. package/src/session-kit/approvals/risk-accent.ts +0 -47
  94. package/src/session-kit/approvals/scope-icons.ts +0 -19
  95. package/src/session-kit/combobox/Combobox.tsx +0 -358
  96. package/src/session-kit/combobox/use-click-outside.ts +0 -21
  97. package/src/session-kit/display/ContextHeader.tsx +0 -148
  98. package/src/session-kit/display/FileDiffCard.tsx +0 -140
  99. package/src/session-kit/display/MD.tsx +0 -162
  100. package/src/session-kit/display/MessageTurn.tsx +0 -157
  101. package/src/session-kit/display/ThinkingPanel.tsx +0 -81
  102. package/src/session-kit/display/TodoChecklist.tsx +0 -120
  103. package/src/session-kit/display/TokenMeter.tsx +0 -89
  104. package/src/session-kit/display/ToolStrip.tsx +0 -278
  105. package/src/session-kit/display/TypingDots.tsx +0 -24
  106. package/src/session-kit/index.ts +0 -44
  107. package/src/session-kit/lib/enums.ts +0 -66
  108. package/src/session-kit/lib/portal-accent.ts +0 -30
  109. package/src/session-kit/lib/status-dot.ts +0 -68
  110. package/src/session-kit/primitives/Avatar.tsx +0 -44
  111. package/src/session-kit/primitives/PortalGlyph.tsx +0 -51
  112. package/src/session-kit/primitives/RiskPill.tsx +0 -95
  113. package/src/session-kit/primitives/ScopeDot.tsx +0 -47
  114. package/src/session-kit/primitives/Segmented.tsx +0 -71
  115. package/src/ui/branding/app-branding-context.ts +0 -20
  116. package/src/ui/branding/app-branding-provider.tsx +0 -123
  117. package/src/ui/branding/sanitize.ts +0 -89
  118. package/src/ui/breakpoints.ts +0 -14
  119. package/src/ui/capture/document-preview.tsx +0 -166
  120. package/src/ui/capture/field-spec-to-zod.test.ts +0 -81
  121. package/src/ui/capture/field-spec-to-zod.ts +0 -174
  122. package/src/ui/capture/field-spec-validate.ts +0 -236
  123. package/src/ui/capture/field-spec.test.ts +0 -49
  124. package/src/ui/capture/field-spec.ts +0 -274
  125. package/src/ui/capture/index.ts +0 -51
  126. package/src/ui/capture/schema-field-input.tsx +0 -620
  127. package/src/ui/capture/schema-form.tsx +0 -149
  128. package/src/ui/capture/submit-values.test.ts +0 -70
  129. package/src/ui/capture/submit-values.ts +0 -63
  130. package/src/ui/capture/use-prefill.ts +0 -186
  131. package/src/ui/capture/use-schema-validation.ts +0 -145
  132. package/src/ui/capture/use-wizard.ts +0 -180
  133. package/src/ui/capture/value-format.ts +0 -32
  134. package/src/ui/capture/wizard.tsx +0 -105
  135. package/src/ui/charts/bar-chart.tsx +0 -139
  136. package/src/ui/charts/chart-frame.tsx +0 -125
  137. package/src/ui/charts/chart-types.ts +0 -52
  138. package/src/ui/charts/chart-utils.ts +0 -190
  139. package/src/ui/charts/charts.test.tsx +0 -204
  140. package/src/ui/charts/donut-chart.tsx +0 -129
  141. package/src/ui/charts/index.ts +0 -27
  142. package/src/ui/charts/line-chart.tsx +0 -202
  143. package/src/ui/charts/sparkline.tsx +0 -109
  144. package/src/ui/chrome/AsyncBoundary.tsx +0 -74
  145. package/src/ui/chrome/EmptyState.tsx +0 -257
  146. package/src/ui/chrome/ErrorCard.tsx +0 -63
  147. package/src/ui/chrome/LoadingState.tsx +0 -61
  148. package/src/ui/chrome/PageHeader.tsx +0 -137
  149. package/src/ui/chrome/RecordCardList.tsx +0 -98
  150. package/src/ui/chrome/StateCard.tsx +0 -150
  151. package/src/ui/chrome/confirm-delete-dialog.tsx +0 -59
  152. package/src/ui/chrome/page-shell.tsx +0 -189
  153. package/src/ui/chrome/scope-badge.tsx +0 -40
  154. package/src/ui/chrome/status-badge.tsx +0 -79
  155. package/src/ui/cn.ts +0 -32
  156. package/src/ui/design-tokens.ts +0 -372
  157. package/src/ui/hooks/use-debounced-value.ts +0 -16
  158. package/src/ui/hooks/use-is-mobile.ts +0 -28
  159. package/src/ui/index.ts +0 -110
  160. package/src/ui/pdf/pdf-preview.tsx +0 -122
  161. package/src/ui/primitives/alert-dialog.tsx +0 -104
  162. package/src/ui/primitives/async-combobox.tsx +0 -182
  163. package/src/ui/primitives/badge-variants.ts +0 -21
  164. package/src/ui/primitives/badge.tsx +0 -25
  165. package/src/ui/primitives/button-variants.ts +0 -31
  166. package/src/ui/primitives/button.tsx +0 -29
  167. package/src/ui/primitives/card.tsx +0 -43
  168. package/src/ui/primitives/checkbox.tsx +0 -26
  169. package/src/ui/primitives/collapsible.tsx +0 -9
  170. package/src/ui/primitives/dialog.tsx +0 -103
  171. package/src/ui/primitives/dropdown-menu.tsx +0 -179
  172. package/src/ui/primitives/form-stepper.tsx +0 -94
  173. package/src/ui/primitives/form-stepper.types.ts +0 -15
  174. package/src/ui/primitives/input.tsx +0 -22
  175. package/src/ui/primitives/label.tsx +0 -17
  176. package/src/ui/primitives/overflow-tabs.tsx +0 -331
  177. package/src/ui/primitives/popover.tsx +0 -33
  178. package/src/ui/primitives/preview-device-frame.tsx +0 -213
  179. package/src/ui/primitives/radio-group.tsx +0 -36
  180. package/src/ui/primitives/resizable.tsx +0 -67
  181. package/src/ui/primitives/scroll-area.tsx +0 -38
  182. package/src/ui/primitives/select.tsx +0 -143
  183. package/src/ui/primitives/separator.tsx +0 -20
  184. package/src/ui/primitives/sheet.tsx +0 -107
  185. package/src/ui/primitives/skeleton.tsx +0 -99
  186. package/src/ui/primitives/switch.tsx +0 -27
  187. package/src/ui/primitives/table.tsx +0 -72
  188. package/src/ui/primitives/tabs.tsx +0 -53
  189. package/src/ui/primitives/tag-multi-select.tsx +0 -261
  190. package/src/ui/primitives/textarea.tsx +0 -21
  191. package/src/ui/primitives/tooltip.tsx +0 -30
  192. package/src/ui/primitives/url-preview-chrome.tsx +0 -103
  193. package/src/vista/GenericCatalogueSurface.tsx +0 -179
  194. package/src/vista/SurfaceFallbackCard.tsx +0 -109
  195. package/src/vista/VistaPanel.tsx +0 -163
  196. package/src/vista/form-payload.spec.ts +0 -139
  197. package/src/vista/html/CustomUiFrame.spec.tsx +0 -127
  198. package/src/vista/html/CustomUiFrame.tsx +0 -206
  199. package/src/vista/html/custom-ui-frame-bridge.spec.ts +0 -191
  200. package/src/vista/html/custom-ui-frame-bridge.ts +0 -98
  201. package/src/vista/html/custom-ui-frame-contract.ts +0 -88
  202. package/src/vista/html/custom-ui-intents.spec.ts +0 -135
  203. package/src/vista/html/custom-ui-intents.ts +0 -155
  204. package/src/vista/html/custom-ui-srcdoc.spec.ts +0 -151
  205. package/src/vista/html/custom-ui-srcdoc.ts +0 -193
  206. package/src/vista/html/index.ts +0 -13
  207. package/src/vista/index.ts +0 -52
  208. package/src/vista/surface-catalogue.spec.ts +0 -140
  209. package/src/vista/surface-catalogue.ts +0 -90
  210. package/src/vista/surface-icons.ts +0 -57
  211. package/src/vista/surface-registry.ts +0 -56
  212. package/src/vista/surfaces/ChartSurface.tsx +0 -34
  213. package/src/vista/surfaces/FilesSurface.tsx +0 -202
  214. package/src/vista/surfaces/FormSurface.tsx +0 -380
  215. package/src/vista/surfaces/HtmlSurface.tsx +0 -43
  216. package/src/vista/surfaces/TableSurface.tsx +0 -100
  217. package/src/vista/surfaces/UrlSurface.tsx +0 -40
  218. package/src/vista/surfaces/blob-surfaces.tsx +0 -139
  219. package/src/vista/surfaces/elicitation-transport.spec.ts +0 -369
  220. package/src/vista/surfaces/elicitation-transport.ts +0 -367
  221. package/src/vista/surfaces/file-surface-utils.ts +0 -69
  222. package/src/vista/surfaces/index.ts +0 -24
  223. package/src/vista/surfaces/register-surfaces.tsx +0 -139
  224. package/src/vista/surfaces/text-surfaces.tsx +0 -132
  225. package/src/vista/use-vista-tabs.ts +0 -196
  226. package/src/vista/vista-code-renderer-context.ts +0 -16
  227. package/src/vista/vista-code-renderer.tsx +0 -35
  228. package/src/vista/vista-file-context.ts +0 -14
  229. package/src/vista/vista-file-source.tsx +0 -141
  230. package/src/vista/vista-form-context.ts +0 -20
  231. package/src/vista/vista-form-host.tsx +0 -48
  232. package/src/vista/vista-model.ts +0 -137
  233. package/src/vista/vista-open-context.tsx +0 -27
  234. package/src/vista/vista-open-state.ts +0 -11
  235. package/src/vista/vista-payloads.ts +0 -635
  236. package/src/vista/vista-tabs-manifest.ts +0 -138
  237. package/src/vista/vista-tools.ts +0 -232
@@ -22,6 +22,6 @@ interface PageShellProps {
22
22
  backTo?: PageBackTarget;
23
23
  topbarActions?: ReactNode;
24
24
  }
25
- export default function PageShell({ icon: _Icon, title, description, children, actions, tabs, activeTab, onTabChange, maxWidth, embedded, eyebrow, backTo, topbarActions, }: Readonly<PageShellProps>): import("react").JSX.Element;
25
+ export default function PageShell(props: Readonly<PageShellProps>): import("react").JSX.Element;
26
26
  export {};
27
27
  //# sourceMappingURL=page-shell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-shell.d.ts","sourceRoot":"","sources":["../../../src/ui/chrome/page-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG1E,UAAU,MAAM;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,MAAM,CAAC,EAAE,cAAc,CAAC;IAOxB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC3B;AAQD,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,IAAI,EAAE,KAAK,EACX,KAAK,EACL,WAAW,EACX,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,MAAM,EACN,aAAa,GACd,EAAE,QAAQ,CAAC,cAAc,CAAC,+BA+H1B"}
1
+ {"version":3,"file":"page-shell.d.ts","sourceRoot":"","sources":["../../../src/ui/chrome/page-shell.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG1E,UAAU,MAAM;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,MAAM,CAAC;IAKjB,MAAM,CAAC,EAAE,cAAc,CAAC;IAOxB,aAAa,CAAC,EAAE,SAAS,CAAC;CAC3B;AAsBD,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,+BAMhE"}
@@ -3,7 +3,15 @@ import { FileQuestion } from 'lucide-react';
3
3
  import EmptyState from './EmptyState';
4
4
  import { useHostBridge } from '../../lib/biome-host';
5
5
  import { Tabs, TabsList, TabsTrigger } from '../primitives/tabs';
6
- export default function PageShell({ icon: _Icon, title, description, children, actions, tabs, activeTab, onTabChange, maxWidth, embedded, eyebrow, backTo, topbarActions, }) {
6
+ export default function PageShell(props) {
7
+ return props.embedded ? (_jsx(EmbeddedPageShell, { ...props })) : (_jsx(FullPageShell, { ...props }));
8
+ }
9
+ function EmbeddedPageShell({ children, actions, tabs, activeTab, onTabChange, }) {
10
+ {
11
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-paper", children: [(tabs && tabs.length > 0) || actions ? (_jsx("div", { className: "shrink-0 border-b border-rule bg-paper-elev/40", children: _jsxs("div", { className: "flex items-center gap-3 px-4 py-2 lg:px-6", children: [tabs && tabs.length > 0 && (_jsx(Tabs, { value: activeTab, onValueChange: onTabChange, className: "flex-1 min-w-0", children: _jsx("div", { className: "overflow-x-auto", children: _jsx(TabsList, { className: "h-7 bg-transparent p-0 gap-0", children: tabs.map((tab) => (_jsxs(TabsTrigger, { value: tab.value, className: "rounded-none border-b-2 border-transparent px-2 py-1 text-body-2 font-medium text-ink-3 transition-colors data-[state=active]:border-primary data-[state=active]:text-ink data-[state=active]:bg-transparent data-[state=active]:shadow-none", children: [tab.label, tab.count !== undefined && (_jsx("span", { className: "ml-1.5 text-caption tabular-nums opacity-70", children: tab.count })), tab.indicator && (_jsx("span", { className: "ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-warning" }))] }, tab.value))) }) }) })), !tabs && _jsx("div", { className: "flex-1" }), actions && (_jsx("div", { className: "flex items-center gap-2 shrink-0", children: actions }))] }) })) : null, _jsx("div", { className: "flex-1 overflow-auto min-h-0", children: _jsx("div", { className: "flex h-full min-h-0 flex-col px-4 pb-4 pt-3 lg:px-6", children: children }) })] }));
12
+ }
13
+ }
14
+ function FullPageShell({ title, description, children, actions, tabs, activeTab, onTabChange, maxWidth, eyebrow, backTo, topbarActions, }) {
7
15
  useHostBridge().pageMeta.usePageMeta({
8
16
  title,
9
17
  description,
@@ -11,9 +19,6 @@ export default function PageShell({ icon: _Icon, title, description, children, a
11
19
  backTo,
12
20
  topbarActions,
13
21
  });
14
- if (embedded) {
15
- return (_jsxs("div", { className: "flex h-full min-h-0 flex-col bg-paper", children: [(tabs && tabs.length > 0) || actions ? (_jsx("div", { className: "shrink-0 border-b border-rule bg-paper-elev/40", children: _jsxs("div", { className: "flex items-center gap-3 px-4 py-2 lg:px-6", children: [tabs && tabs.length > 0 && (_jsx(Tabs, { value: activeTab, onValueChange: onTabChange, className: "flex-1 min-w-0", children: _jsx("div", { className: "overflow-x-auto", children: _jsx(TabsList, { className: "h-7 bg-transparent p-0 gap-0", children: tabs.map((tab) => (_jsxs(TabsTrigger, { value: tab.value, className: "rounded-none border-b-2 border-transparent px-2 py-1 text-body-2 font-medium text-ink-3 transition-colors data-[state=active]:border-primary data-[state=active]:text-ink data-[state=active]:bg-transparent data-[state=active]:shadow-none", children: [tab.label, tab.count !== undefined && (_jsx("span", { className: "ml-1.5 text-caption tabular-nums opacity-70", children: tab.count })), tab.indicator && (_jsx("span", { className: "ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-warning" }))] }, tab.value))) }) }) })), !tabs && _jsx("div", { className: "flex-1" }), actions && (_jsx("div", { className: "flex items-center gap-2 shrink-0", children: actions }))] }) })) : null, _jsx("div", { className: "flex-1 overflow-auto min-h-0", children: _jsx("div", { className: "flex h-full min-h-0 flex-col px-4 pb-4 pt-3 lg:px-6", children: children }) })] }));
16
- }
17
22
  return (_jsxs("div", { className: `flex h-full min-h-0 flex-col ${maxWidth ?? ''}`, children: [(tabs || actions) && (_jsx("div", { className: "shrink-0 border-b border-border/50 px-4 sm:px-5 lg:px-8", children: _jsxs("div", { className: "flex min-h-[34px] flex-col gap-2 py-1.5 sm:flex-row sm:items-center sm:gap-3 sm:py-0", children: [tabs && tabs.length > 0 && (_jsx(Tabs, { value: activeTab, onValueChange: onTabChange, className: "flex-1 min-w-0", children: _jsx("div", { className: "overflow-x-auto", children: _jsx(TabsList, { className: "h-7 bg-transparent p-0 gap-0", children: tabs.map((tab) => (_jsxs(TabsTrigger, { value: tab.value, className: "whitespace-nowrap rounded-none border-b-2 border-transparent px-2.5 py-1.5 text-caption font-medium text-ink-3/90 transition-colors data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-ink data-[state=active]:shadow-none hover:text-ink", children: [tab.label, tab.count !== undefined && (_jsx("span", { className: "ml-1.5 text-caption tabular-nums opacity-60", children: tab.count })), tab.indicator && (_jsx("span", { className: "ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-warning" }))] }, tab.value))) }) }) })), !tabs && _jsx("div", { className: "flex-1" }), actions && (_jsx("div", { className: "flex w-full flex-wrap items-center gap-2 sm:w-auto sm:shrink-0 sm:justify-end", children: actions }))] }) })), _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-auto px-4 pb-5 pt-4 sm:px-6 sm:pb-6 sm:pt-5", children: children || (_jsx(EmptyState, { icon: FileQuestion, title: "Nothing to show yet", description: "This page has no content to display. Check back once the workspace has data." })) })] }));
18
23
  }
19
24
  //# sourceMappingURL=page-shell.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page-shell.js","sourceRoot":"","sources":["../../../src/ui/chrome/page-shell.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"page-shell.js","sourceRoot":"","sources":["../../../src/ui/chrome/page-shell.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xemahq/ui-kernel",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Host-framework-agnostic UI kernel for the Xema OS. Defines the SystemBus orchestration contract (capability.invoke, cross-biome intents, command palette, xema:// deeplinks, window manager) AND the biome-host contract surface (FrontendBiome/FrontendBiomeFactory, HostBridge, the singleton biomeRegistry, session contributions) that every frontend biome composes against. No Vite, Next.js, or React-Router — React itself IS allowed as the shared component model (the contracts traffic in ReactNode/ComponentType and a React context). Concrete host adapters (router/auth/toast wiring) live in separate packages that consume this kernel. The SystemBus is pure orchestration: it never authorizes, the backend capability-router enforces all policy.",
@@ -31,7 +31,6 @@
31
31
  "types": "dist/index.d.ts",
32
32
  "files": [
33
33
  "dist",
34
- "src",
35
34
  "README.md",
36
35
  "LICENSE"
37
36
  ],
@@ -74,10 +73,13 @@
74
73
  "@tanstack/react-query": "^5.100.13",
75
74
  "@types/node": "25.2.3",
76
75
  "@types/react": "^18.3.30",
76
+ "@types/react-dom": "^18.3.7",
77
+ "@xemahq/kernel-contracts": "^8.0.0",
77
78
  "prettier": "3.6.2",
78
79
  "react": "^18.3.1",
80
+ "react-dom": "^18.3.1",
79
81
  "typescript": "5.9.3",
80
- "@xemahq/kernel-contracts": "^5.0.0"
82
+ "vitest": "^3.2.4"
81
83
  },
82
84
  "exports": {
83
85
  ".": {
@@ -109,7 +111,7 @@
109
111
  "scripts": {
110
112
  "clean": "rm -rf dist",
111
113
  "build": "tsc -p tsconfig.json",
112
- "test": "echo '[ui-kernel] *.{test,spec} files run under host-web vitest (this package carries no vitest dep by design — see tsconfig exclude). Write tests with vitest; the frontend-bridge sync fails on a node:test file.'",
114
+ "test": "echo '[ui-kernel] *.{test,spec} files RUN under host-web vitest (this package has no vitest runner config). vitest is a devDependency here for TYPES only, so tsc typechecks the specs in the repo that owns them.'",
113
115
  "format": "prettier --write \"src/**/*.{ts,tsx}\"",
114
116
  "lint": "eslint .",
115
117
  "typecheck": "tsc -p tsconfig.lint.json --noEmit"
package/src/index.ts DELETED
@@ -1,17 +0,0 @@
1
- export * from './lib/system-bus';
2
- export * from './lib/biome-host';
3
- export * from './lib/capabilities';
4
-
5
- // The shared closed-first-party + open-biome contribution registry core (and
6
- // its versioned/validated renderable flavour). Every plane that lets a biome
7
- // contribute into a set the platform also ships builtins for is built on this.
8
- export * from './lib/contribution-registry';
9
-
10
- // Guided-capture UX kit (B5). Also available at the `@xemahq/ui-kernel/ui`
11
- // subpath alongside the rest of the shared UI surface; re-exported here so the
12
- // capture primitives are reachable from the package root too.
13
- export * from './ui/capture';
14
-
15
- // Offline field-capture kit — durable outbox that queues mutations while
16
- // disconnected and drains them on reconnect. Also at `@xemahq/ui-kernel/offline`.
17
- export * from './offline';
@@ -1,239 +0,0 @@
1
- /**
2
- * Lightweight cross-biome composition validation.
3
- *
4
- * After the host bootstrap registers every enabled web biome, the merged
5
- * surface must be internally consistent: no two biomes may claim the same
6
- * route, no two may claim the same nav id, and every panel must target a
7
- * slot the composition can actually render. The runtime tolerates a lot of
8
- * this silently (the nav merge last-writer-wins on a duplicate id; a panel
9
- * pointing at a non-existent slot simply never renders), which is exactly
10
- * the kind of hidden degradation the platform forbids — so we surface it.
11
- *
12
- * This module is the PURE validator: it takes the registered biomes plus
13
- * the set of host-defined slot ids and returns structured diagnostics. It
14
- * is host-framework-agnostic and knows nothing about `HostExtensionSlots`
15
- * (that catalog lives in `biome-registry-web`, which passes it in). It does
16
- * NOT throw and it does NOT log — callers decide the policy (the host
17
- * bootstrap fail-fasts on `Error`-severity diagnostics and surfaces
18
- * `Warning`-severity ones). This is deliberately NOT a permission matrix:
19
- * it validates structural composition only, never authorization.
20
- */
21
-
22
- import type { FrontendBiome } from './frontend-biome';
23
-
24
- /** Closed set — how serious a composition diagnostic is. */
25
- export enum CompositionDiagnosticSeverity {
26
- /**
27
- * A genuine composition bug that makes the merged surface ambiguous
28
- * (two routes/nav ids collide). Deterministic and author-fixable; the
29
- * host fail-fasts so it is caught in dev/CI, never silently shipped.
30
- */
31
- Error = 'error',
32
- /**
33
- * A probable mistake that the runtime tolerates (a panel targeting an
34
- * unknown or not-yet-loaded slot). Non-fatal because it can also be a
35
- * legitimate cross-deployment state (host shell older than the biome,
36
- * or the slot-owning biome disabled for this org).
37
- */
38
- Warning = 'warning',
39
- }
40
-
41
- /** Closed set — the kind of composition problem detected. */
42
- export enum CompositionDiagnosticCode {
43
- /** Two biomes contribute a route with the same `(path, projectScoped)`. */
44
- DuplicateRoutePath = 'duplicate_route_path',
45
- /** Two biomes contribute a nav item with the same `id`. */
46
- DuplicateNavId = 'duplicate_nav_id',
47
- /**
48
- * A panel targets a slot that is neither a known host slot nor a
49
- * well-formed `<owner>/<name>` biome-owned slot — almost always a typo.
50
- */
51
- UnknownSlot = 'unknown_slot',
52
- /**
53
- * A panel targets a biome-owned slot (`<owner>/<name>`) whose owning
54
- * biome is not registered, so the panel can never render.
55
- */
56
- OrphanedPanelSlot = 'orphaned_panel_slot',
57
- }
58
-
59
- export interface CompositionDiagnostic {
60
- readonly code: CompositionDiagnosticCode;
61
- readonly severity: CompositionDiagnosticSeverity;
62
- /** The biome id(s) implicated, for actionable reporting. */
63
- readonly biomeIds: readonly string[];
64
- /** Human-readable, actionable description. */
65
- readonly message: string;
66
- }
67
-
68
- export interface ValidateBiomeCompositionOptions {
69
- /**
70
- * Host-defined slot ids the shell renders (the `HostExtensionSlots`
71
- * values). A panel slot that is neither one of these nor a well-formed
72
- * `<owner>/<name>` biome-owned slot is flagged as `UnknownSlot`.
73
- */
74
- readonly knownSlots: ReadonlySet<string>;
75
- }
76
-
77
- /**
78
- * Biome-owned slots are namespaced `<owner>/<name>` where `owner` is the
79
- * id of the biome that publishes the slot. Exactly one `/`, both segments
80
- * non-empty. Returns the owner id, or `null` if the slot is not a
81
- * well-formed biome-owned slot.
82
- */
83
- function biomeOwnedSlotOwner(slot: string): string | null {
84
- const slashIndex = slot.indexOf('/');
85
- if (slashIndex <= 0) {
86
- return null;
87
- } // no slash, or leading slash (empty owner)
88
- if (slot.indexOf('/', slashIndex + 1) !== -1) {
89
- return null;
90
- } // more than one slash
91
- const owner = slot.slice(0, slashIndex);
92
- const name = slot.slice(slashIndex + 1);
93
- if (owner.length === 0 || name.length === 0) {
94
- return null;
95
- }
96
- return owner;
97
- }
98
-
99
- /**
100
- * Validate the merged composition of every registered biome. Pure: returns
101
- * diagnostics, never throws, never logs. Diagnostics are returned in a
102
- * deterministic order (by code, then by the offending key) so callers and
103
- * tests see stable output.
104
- */
105
- export function validateBiomeComposition(
106
- biomes: readonly FrontendBiome[],
107
- options: ValidateBiomeCompositionOptions,
108
- ): readonly CompositionDiagnostic[] {
109
- const diagnostics: CompositionDiagnostic[] = [];
110
- const biomeIds = new Set(biomes.map((b) => b.id));
111
-
112
- // ── Duplicate route paths ────────────────────────────────────────────
113
- // Routes collide only within the same scope: a project-scoped `/x`
114
- // mounts under `/spaces/projects/:projectId/x`, an org-scoped `/x` under `/x`,
115
- // so they never clash. Key on `(scope, path)`.
116
- const routeOwners = new Map<string, string[]>();
117
- for (const biome of biomes) {
118
- for (const route of biome.routes ?? []) {
119
- const scope = route.projectScoped ? 'project' : 'root';
120
- const key = `${scope}:${route.path}`;
121
- const owners = routeOwners.get(key);
122
- if (owners) {
123
- owners.push(biome.id);
124
- } else {
125
- routeOwners.set(key, [biome.id]);
126
- }
127
- }
128
- }
129
- for (const [key, owners] of routeOwners) {
130
- if (owners.length < 2) {
131
- continue;
132
- }
133
- const [scope, path] = splitFirst(key, ':');
134
- diagnostics.push({
135
- code: CompositionDiagnosticCode.DuplicateRoutePath,
136
- severity: CompositionDiagnosticSeverity.Error,
137
- biomeIds: owners,
138
- message:
139
- `Route path '${path}' (${scope}-scoped) is contributed by multiple biomes: ` +
140
- `${owners.join(', ')}. Each route must be unique within its scope — ` +
141
- `only one would mount and the others would be unreachable.`,
142
- });
143
- }
144
-
145
- // ── Duplicate nav ids ────────────────────────────────────────────────
146
- // The nav merge keys on `navItem.id`; a duplicate id makes one item
147
- // silently overwrite the other in the feature-route map and collide as a
148
- // React key in the rendered list.
149
- const navOwners = new Map<string, string[]>();
150
- for (const biome of biomes) {
151
- for (const navItem of biome.navItems ?? []) {
152
- const owners = navOwners.get(navItem.id);
153
- if (owners) {
154
- owners.push(biome.id);
155
- } else {
156
- navOwners.set(navItem.id, [biome.id]);
157
- }
158
- }
159
- }
160
- for (const [navId, owners] of navOwners) {
161
- if (owners.length < 2) {
162
- continue;
163
- }
164
- diagnostics.push({
165
- code: CompositionDiagnosticCode.DuplicateNavId,
166
- severity: CompositionDiagnosticSeverity.Error,
167
- biomeIds: owners,
168
- message:
169
- `Nav id '${navId}' is contributed by multiple biomes: ${owners.join(', ')}. ` +
170
- `Nav ids must be unique — a duplicate silently overwrites the ` +
171
- `feature-route mapping and collides as a render key.`,
172
- });
173
- }
174
-
175
- // ── Panel slots: known-slot + dependency-closure ─────────────────────
176
- for (const biome of biomes) {
177
- for (const panel of biome.panels ?? []) {
178
- if (options.knownSlots.has(panel.slot)) {
179
- continue;
180
- }
181
- const owner = biomeOwnedSlotOwner(panel.slot);
182
- if (owner === null) {
183
- diagnostics.push({
184
- code: CompositionDiagnosticCode.UnknownSlot,
185
- severity: CompositionDiagnosticSeverity.Warning,
186
- biomeIds: [biome.id],
187
- message:
188
- `Biome '${biome.id}' panel '${panel.id}' targets slot '${panel.slot}', ` +
189
- `which is neither a known host slot nor a well-formed ` +
190
- `'<owner>/<name>' biome-owned slot. It will never render — ` +
191
- `check for a typo against the host slot catalog.`,
192
- });
193
- continue;
194
- }
195
- // Well-formed biome-owned slot — its owner must be registered for the
196
- // panel to ever render (dependency-closure sanity). A biome may own
197
- // its own slot, which is always satisfied.
198
- if (!biomeIds.has(owner)) {
199
- diagnostics.push({
200
- code: CompositionDiagnosticCode.OrphanedPanelSlot,
201
- severity: CompositionDiagnosticSeverity.Warning,
202
- biomeIds: [biome.id],
203
- message:
204
- `Biome '${biome.id}' panel '${panel.id}' targets biome-owned slot ` +
205
- `'${panel.slot}', but its owner biome '${owner}' is not registered. ` +
206
- `The panel will never render until '${owner}' is enabled.`,
207
- });
208
- }
209
- }
210
- }
211
-
212
- return sortDiagnostics(diagnostics);
213
- }
214
-
215
- /** Split on the first occurrence of `sep` into a `[head, tail]` pair. */
216
- function splitFirst(value: string, sep: string): [string, string] {
217
- const idx = value.indexOf(sep);
218
- if (idx === -1) {
219
- return [value, ''];
220
- }
221
- return [value.slice(0, idx), value.slice(idx + sep.length)];
222
- }
223
-
224
- /** Stable ordering: by code, then by the joined biome ids, then message. */
225
- function sortDiagnostics(
226
- diagnostics: CompositionDiagnostic[],
227
- ): CompositionDiagnostic[] {
228
- return diagnostics.slice().sort((a, b) => {
229
- if (a.code !== b.code) {
230
- return a.code.localeCompare(b.code);
231
- }
232
- const ai = a.biomeIds.join(',');
233
- const bi = b.biomeIds.join(',');
234
- if (ai !== bi) {
235
- return ai.localeCompare(bi);
236
- }
237
- return a.message.localeCompare(b.message);
238
- });
239
- }
@@ -1,112 +0,0 @@
1
- /**
2
- * Frontend-biome route/biome builders.
3
- *
4
- * The `createElement(Suspense, { fallback: null }, createElement(LazyPage))`
5
- * wrapper is hand-repeated ~74× across biome `index.ts` files — once per lazy
6
- * route. `lazyRoute` collapses it to one call; `defineSinglePageBiome` builds
7
- * the whole one-page biome (nav item + single route) that the vast majority of
8
- * biomes are. Host-framework-agnostic: pure React (`lazy` / `Suspense` /
9
- * `createElement`), no router and no Next.js.
10
- */
11
- import {
12
- Suspense,
13
- createElement,
14
- lazy,
15
- type ComponentType,
16
- type ReactNode,
17
- } from 'react';
18
-
19
- import type {
20
- FrontendBiome,
21
- NavItemContribution,
22
- RouteAccess,
23
- RouteContribution,
24
- } from './frontend-biome';
25
-
26
- /** A dynamic import of a module whose default export is a React component. */
27
- export type LazyComponentImport = () => Promise<{ default: ComponentType }>;
28
-
29
- /**
30
- * Wrap a dynamic page import as a `RouteContribution['element']` factory: lazy
31
- * import + `<Suspense>` boundary. Replaces the hand-written
32
- * `createElement(Suspense, { fallback }, createElement(lazy(importFn)))` block.
33
- *
34
- * The `lazy(...)` call is hoisted out of the returned thunk so the component is
35
- * created ONCE (not on every route render), matching how biomes hand-declare
36
- * `const Page = lazy(() => import('./Page'))` at module scope.
37
- *
38
- * @param importFn Dynamic import of the page module (`() => import('./Page')`).
39
- * @param fallback Suspense fallback. Defaults to `null` (the prevailing biome
40
- * convention) — pass a skeleton to be explicit.
41
- */
42
- export function lazyRoute(
43
- importFn: LazyComponentImport,
44
- fallback: ReactNode = null,
45
- ): () => ReactNode {
46
- const Lazy = lazy(importFn);
47
- const LazyRoute = () =>
48
- createElement(Suspense, { fallback }, createElement(Lazy));
49
- LazyRoute.displayName = 'LazyRoute';
50
- return LazyRoute;
51
- }
52
-
53
- export interface SinglePageBiomeRoute {
54
- /** Route path. May include `:param` segments. */
55
- readonly path: string;
56
- /** Dynamic import of the page module. */
57
- readonly page: LazyComponentImport;
58
- /**
59
- * Whether the route mounts under `/projects/:projectId` (project-scoped) or
60
- * at the org root. REQUIRED — mirrors {@link RouteContribution.projectScoped}.
61
- */
62
- readonly projectScoped: boolean;
63
- /** Access tier required to render. Defaults to `'member'`. */
64
- readonly access?: RouteAccess;
65
- /** Suspense fallback for the lazy page. Defaults to `null`. */
66
- readonly fallback?: ReactNode;
67
- }
68
-
69
- export interface SinglePageBiomeSpec {
70
- /** Stable biome id; matches `xema-biome.json` `xema.id`. */
71
- readonly id: string;
72
- /** Displayed name. */
73
- readonly displayName: string;
74
- /** The single nav item this biome contributes. */
75
- readonly nav: NavItemContribution;
76
- /** The single route this biome contributes. */
77
- readonly route: SinglePageBiomeRoute;
78
- }
79
-
80
- /**
81
- * Build a `FrontendBiome` for the common one-nav-item / one-route biome.
82
- *
83
- * Most biomes are exactly this shape — a nav entry plus a single lazy page —
84
- * yet each re-declares the nav array, the route array, the `lazy(...)`, and the
85
- * `Suspense` wrapper by hand. This builder centralizes all four.
86
- *
87
- * @example
88
- * const biome: FrontendBiomeFactory = () =>
89
- * defineSinglePageBiome({
90
- * id: 'org-databases',
91
- * displayName: 'Organization Databases',
92
- * nav: { id: 'org-databases', label: 'Databases', route: 'org-databases',
93
- * icon: Database, section: 'Organization', weight: 30 },
94
- * route: { path: 'org-databases', projectScoped: false,
95
- * page: () => import('./pages/DatabasesListPage') },
96
- * });
97
- */
98
- export function defineSinglePageBiome(spec: SinglePageBiomeSpec): FrontendBiome {
99
- const { route } = spec;
100
- const contribution: RouteContribution = {
101
- path: route.path,
102
- projectScoped: route.projectScoped,
103
- element: lazyRoute(route.page, route.fallback ?? null),
104
- ...(route.access ? { access: route.access } : {}),
105
- };
106
- return {
107
- id: spec.id,
108
- displayName: spec.displayName,
109
- navItems: [spec.nav],
110
- routes: [contribution],
111
- };
112
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Master switch for the biome subsystem. A host passes `'disabled'` to opt
3
- * the whole biome runtime out (no biomes load / register) — e.g. for a
4
- * minimal shell or a degraded mode. Framework-agnostic.
5
- */
6
- export type BiomesMode = 'enabled' | 'disabled';
@@ -1,37 +0,0 @@
1
- /**
2
- * Bridge-backed navigation convenience hooks for frontend biomes.
3
- *
4
- * These wrap the host-agnostic `HostBridge.navigation` surface so biome code
5
- * never imports a router primitive (`next/navigation`, `react-router-dom`)
6
- * directly — the host wires the concrete implementation once on the bridge and
7
- * every biome reads it through here. Host-framework-agnostic: no Next.js, no
8
- * React-Router. React itself IS used (these are React hooks).
9
- */
10
- import { useMemo } from 'react';
11
-
12
- import { useHostBridge } from './host-bridge';
13
-
14
- /**
15
- * Current URL query string as a read-only `URLSearchParams`, read through the
16
- * host-provided navigation adapter (`bridge.navigation.useSearchParams`).
17
- *
18
- * The one router primitive biomes could not previously reach through the
19
- * bridge. Use this INSTEAD of `import { useSearchParams } from
20
- * 'next/navigation'` so biome code stays portable across hosts.
21
- */
22
- export function useSearchParams(): URLSearchParams {
23
- return useHostBridge().navigation.useSearchParams();
24
- }
25
-
26
- /**
27
- * Read a single query-string parameter by key, or `null` when absent.
28
- *
29
- * Sugar over {@link useSearchParams} for the common "one param" case (e.g.
30
- * `?tab=overview`, `?runId=…`) that otherwise forces a direct
31
- * `next/navigation` import. Returns the first value when a key repeats,
32
- * matching `URLSearchParams.get` semantics.
33
- */
34
- export function useQueryParam(key: string): string | null {
35
- const searchParams = useSearchParams();
36
- return useMemo(() => searchParams.get(key), [searchParams, key]);
37
- }