@jini-ai/ui 0.3.13 → 0.4.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 (334) hide show
  1. package/CHANGELOG.md +139 -0
  2. package/README.md +120 -26
  3. package/dist/browser/index.js +1 -1
  4. package/dist/browser/useDismissOnOutsideOrEscape.d.ts +10 -1
  5. package/dist/browser/useDismissOnOutsideOrEscape.js +7 -4
  6. package/dist/browser/useGlobalKeydown.d.ts +14 -2
  7. package/dist/browser/useGlobalKeydown.js +8 -17
  8. package/dist/features/a2ui/catalog-from-registry.d.ts +6 -3
  9. package/dist/features/a2ui/catalog-from-registry.js +1 -1
  10. package/dist/features/a2ui/index.d.ts +1 -1
  11. package/dist/features/a2ui/protocol.d.ts +1 -1
  12. package/dist/features/a2ui/renderer.js +23 -10
  13. package/dist/features/a2ui/use-a2ui-surface.d.ts +11 -6
  14. package/dist/features/a2ui/use-a2ui-surface.js +40 -10
  15. package/dist/features/admin-widgets/components/ComingSoonNotice.d.ts +11 -0
  16. package/dist/features/admin-widgets/components/ComingSoonNotice.js +7 -0
  17. package/dist/features/admin-widgets/components/ComingSoonPanel.d.ts +10 -0
  18. package/dist/features/admin-widgets/components/ComingSoonPanel.js +10 -0
  19. package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +16 -0
  20. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +13 -0
  21. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +46 -0
  22. package/dist/features/admin-widgets/components/ImagePreviewModal.js +13 -0
  23. package/dist/features/admin-widgets/components/InfoTip.d.ts +18 -0
  24. package/dist/features/admin-widgets/components/InfoTip.hooks.d.ts +16 -0
  25. package/dist/features/admin-widgets/components/InfoTip.hooks.js +45 -0
  26. package/dist/features/admin-widgets/components/InfoTip.js +12 -0
  27. package/dist/features/admin-widgets/components/SeeMore/SeeMore.d.ts +41 -0
  28. package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.d.ts +14 -0
  29. package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +57 -0
  30. package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +24 -0
  31. package/dist/features/admin-widgets/components/Select/Select.d.ts +39 -0
  32. package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +105 -0
  33. package/dist/features/admin-widgets/components/Select/Select.hooks.js +359 -0
  34. package/dist/features/admin-widgets/components/Select/Select.js +46 -0
  35. package/dist/features/admin-widgets/index.d.ts +20 -0
  36. package/dist/features/admin-widgets/index.js +11 -0
  37. package/dist/features/admin-widgets/styles/admin-widgets.css +2 -0
  38. package/dist/features/appearance/constants.d.ts +2 -2
  39. package/dist/features/appearance/constants.js +2 -1
  40. package/dist/features/appearance/react/components/AppearanceTab.js +5 -5
  41. package/dist/features/appearance/rules.d.ts +10 -4
  42. package/dist/features/appearance/rules.js +5 -5
  43. package/dist/features/appearance/types.d.ts +1 -1
  44. package/dist/features/appearance/types.js +1 -1
  45. package/dist/features/asset-grid/react/components/AssetGrid.js +1 -1
  46. package/dist/features/asset-grid/react/components/DeleteConfirmDialog.js +1 -1
  47. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +23 -21
  48. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +1 -1
  49. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +1 -1
  50. package/dist/features/asset-tree-browser/ports.d.ts +3 -1
  51. package/dist/features/asset-tree-browser/react/hooks/useAssetTreeCopyLocalPath.js +1 -1
  52. package/dist/features/browser-chrome/react/components/BrowserViewportControls.js +1 -1
  53. package/dist/features/browser-chrome/types.js +1 -1
  54. package/dist/features/command-palette/ports.js +1 -1
  55. package/dist/features/connectors/ConnectorsBrowser.js +2 -2
  56. package/dist/features/connectors/components/ConnectorCard.js +3 -3
  57. package/dist/features/connectors/components/ConnectorDetailDrawer.js +1 -1
  58. package/dist/features/connectors/components/ConnectorGrid.js +2 -2
  59. package/dist/features/connectors/components/ConnectorSearchBar.js +2 -2
  60. package/dist/features/connectors/components/ProviderTabBar.js +2 -2
  61. package/dist/features/connectors/constants.d.ts +1 -1
  62. package/dist/features/connectors/constants.js +1 -1
  63. package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
  64. package/dist/features/connectors/rules.d.ts +2 -2
  65. package/dist/features/connectors/rules.js +1 -1
  66. package/dist/features/connectors/types.d.ts +2 -2
  67. package/dist/features/connectors/types.js +1 -1
  68. package/dist/features/execution/react/components/ByokProviderForm.js +3 -3
  69. package/dist/features/execution/react/components/ExecutionTab.js +2 -2
  70. package/dist/features/execution/react/components/LocalCliAgentCard.js +3 -3
  71. package/dist/features/execution/react/components/LocalCliAgentList.js +2 -2
  72. package/dist/features/execution/react/components/ProviderChipGroup.js +2 -2
  73. package/dist/features/execution/react/components/SearchableModelSelect.js +1 -1
  74. package/dist/features/execution/rules.js +1 -1
  75. package/dist/features/file-dropzone/react/components/FileDropzone.js +5 -3
  76. package/dist/features/file-dropzone/react/hooks/useFileDropzone.d.ts +1 -1
  77. package/dist/features/file-dropzone/react/hooks/useFileDropzone.js +1 -1
  78. package/dist/features/file-dropzone/types.d.ts +1 -1
  79. package/dist/features/file-dropzone/types.js +1 -1
  80. package/dist/features/folder-path-drop/react/hooks/useFolderPathDropCapture.js +6 -4
  81. package/dist/features/html-editor/canvas-content-wrapper.js +1 -1
  82. package/dist/features/html-editor/canvas-embed-placeholders.js +7 -7
  83. package/dist/features/html-editor/canvas-style.d.ts +4 -0
  84. package/dist/features/html-editor/canvas-style.js +6 -21
  85. package/dist/features/html-viewer/constants.d.ts +1 -1
  86. package/dist/features/html-viewer/constants.js +1 -1
  87. package/dist/features/html-viewer/react/components/PresentMenu.js +1 -1
  88. package/dist/features/html-viewer/react/components/ZoomMenu.js +1 -1
  89. package/dist/features/html-viewer/types.d.ts +1 -1
  90. package/dist/features/html-viewer/types.js +1 -1
  91. package/dist/features/i18n/dictionaries/index.d.ts +2 -3
  92. package/dist/features/i18n/dictionaries/settings-dialog.en.d.ts +1 -1
  93. package/dist/features/i18n/dictionary-translator.d.ts +16 -0
  94. package/dist/features/i18n/dictionary-translator.js +14 -0
  95. package/dist/features/i18n/index.d.ts +3 -0
  96. package/dist/features/i18n/index.js +2 -0
  97. package/dist/features/i18n/locale.d.ts +1 -1
  98. package/dist/features/i18n/template-i18n.d.ts +26 -0
  99. package/dist/features/i18n/template-i18n.js +36 -0
  100. package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.d.ts +1 -1
  101. package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +1 -1
  102. package/dist/features/instructions/react/components/InstructionsTab.js +1 -1
  103. package/dist/features/integrations/react/components/ClientPicker.js +4 -4
  104. package/dist/features/integrations/react/components/CodexInstallToggleButton.js +1 -1
  105. package/dist/features/integrations/react/components/IntegrationsTab.js +2 -2
  106. package/dist/features/integrations/react/components/SnippetBlock.js +1 -1
  107. package/dist/features/integrations/types.d.ts +1 -1
  108. package/dist/features/integrations/types.js +1 -1
  109. package/dist/features/interactive-ui/index.js +13 -13
  110. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  111. package/dist/features/interactive-ui/providers/recharts/bar-chart.js +1 -1
  112. package/dist/features/interactive-ui/providers/recharts/line-chart.js +1 -1
  113. package/dist/features/interactive-ui/providers/recharts/pie-chart.js +2 -2
  114. package/dist/features/interactive-ui/providers/shadcn/lib/utils.d.ts +1 -1
  115. package/dist/features/interactive-ui/providers/shadcn/lib/utils.js +1 -1
  116. package/dist/features/interactive-ui/registry.d.ts +15 -4
  117. package/dist/features/interactive-ui/registry.js +5 -5
  118. package/dist/features/language/react/components/LanguageTab.js +2 -2
  119. package/dist/features/list-detail-panel/types.d.ts +1 -1
  120. package/dist/features/list-detail-panel/types.js +1 -1
  121. package/dist/features/mcp-ui/confirmation-store.js +2 -1
  122. package/dist/features/mcp-ui/surfaces/bridge.d.ts +2 -1
  123. package/dist/features/mcp-ui/surfaces/bridge.js +17 -7
  124. package/dist/features/mcp-ui/surfaces/confirmation.d.ts +20 -0
  125. package/dist/features/mcp-ui/surfaces/confirmation.js +38 -6
  126. package/dist/features/mcp-ui/surfaces/document.d.ts +7 -1
  127. package/dist/features/mcp-ui/surfaces/document.js +19 -1
  128. package/dist/features/mcp-ui/surfaces/text-input.js +4 -4
  129. package/dist/features/mcp-ui/surfaces/tokens.d.ts +17 -20
  130. package/dist/features/mcp-ui/surfaces/tokens.js +33 -35
  131. package/dist/features/media-providers/index.d.ts +1 -1
  132. package/dist/features/media-providers/index.js +1 -1
  133. package/dist/features/media-providers/react/components/MediaProvidersTab.js +4 -4
  134. package/dist/features/media-providers/rules.js +1 -1
  135. package/dist/features/memory/async-commit-guard.d.ts +1 -1
  136. package/dist/features/memory/constants.d.ts +1 -1
  137. package/dist/features/memory/constants.js +1 -1
  138. package/dist/features/memory/dependencies.d.ts +11 -23
  139. package/dist/features/memory/dependencies.js +116 -106
  140. package/dist/features/memory/index.d.ts +1 -1
  141. package/dist/features/memory/index.js +1 -1
  142. package/dist/features/memory/react/components/MemoryAdvancedModal.js +2 -2
  143. package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
  144. package/dist/features/memory/react/components/MemoryExtractionCard.js +1 -1
  145. package/dist/features/memory/react/components/MemoryHooksPanel.js +1 -1
  146. package/dist/features/memory/react/components/MemoryList.js +5 -5
  147. package/dist/features/memory/react/components/MemoryManualEditor.js +5 -5
  148. package/dist/features/memory/react/components/MemorySettingsPanel.js +1 -1
  149. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +1 -1
  150. package/dist/features/memory/react/hooks/useMemoryNavigation.hooks.js +1 -1
  151. package/dist/features/memory/react/styles.js +1 -1
  152. package/dist/features/memory/rules.js +1 -1
  153. package/dist/features/memory/types.d.ts +1 -1
  154. package/dist/features/mention-autocomplete/react/hooks/useMentionAutocomplete.js +1 -1
  155. package/dist/features/notifications/react/components/NotificationsTab.js +7 -7
  156. package/dist/features/notifications/types.d.ts +1 -1
  157. package/dist/features/observability/boot-timing.js +2 -2
  158. package/dist/features/observability/stuck-run.js +1 -1
  159. package/dist/features/observability/white-screen.js +4 -4
  160. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +35 -0
  161. package/dist/features/panel-kit/fetch-query/adapter.react.js +122 -0
  162. package/dist/features/panel-kit/fetch-query/cache.d.ts +123 -0
  163. package/dist/features/panel-kit/fetch-query/cache.js +231 -0
  164. package/dist/features/panel-kit/fetch-query/environment.browser.d.ts +4 -0
  165. package/dist/features/panel-kit/fetch-query/environment.browser.js +25 -0
  166. package/dist/features/panel-kit/fetch-query/index.d.ts +4 -0
  167. package/dist/features/panel-kit/fetch-query/index.js +2 -0
  168. package/dist/features/panel-kit/fetch-query/types.d.ts +91 -0
  169. package/dist/features/panel-kit/fetch-query/types.js +2 -0
  170. package/dist/features/panel-kit/helpers/format-timestamp.d.ts +18 -0
  171. package/dist/features/panel-kit/helpers/format-timestamp.js +20 -0
  172. package/dist/features/panel-kit/helpers/permissions.d.ts +11 -0
  173. package/dist/features/panel-kit/helpers/permissions.js +10 -0
  174. package/dist/features/panel-kit/helpers/resolve-active-tab-id.d.ts +13 -0
  175. package/dist/features/panel-kit/helpers/resolve-active-tab-id.js +13 -0
  176. package/dist/features/panel-kit/helpers/retry-unreachable.d.ts +20 -0
  177. package/dist/features/panel-kit/helpers/retry-unreachable.js +39 -0
  178. package/dist/features/panel-kit/hooks/use-async-action.hooks.d.ts +13 -0
  179. package/dist/features/panel-kit/hooks/use-async-action.hooks.js +27 -0
  180. package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.d.ts +18 -0
  181. package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +33 -0
  182. package/dist/features/panel-kit/hooks/use-focus-trap.hooks.d.ts +8 -0
  183. package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +66 -0
  184. package/dist/features/panel-kit/hooks/use-serial-writes.hooks.d.ts +26 -0
  185. package/dist/features/panel-kit/hooks/use-serial-writes.hooks.js +41 -0
  186. package/dist/features/panel-kit/hooks/use-settlement-generation.hooks.d.ts +9 -0
  187. package/dist/features/panel-kit/hooks/use-settlement-generation.hooks.js +25 -0
  188. package/dist/features/panel-kit/index.d.ts +19 -0
  189. package/dist/features/panel-kit/index.js +13 -0
  190. package/dist/features/privacy/react/components/PrivacyTab.js +2 -2
  191. package/dist/features/privacy/types.d.ts +1 -1
  192. package/dist/features/privacy/types.js +1 -1
  193. package/dist/features/progress-card/reference-adapters.d.ts +1 -1
  194. package/dist/features/progress-card/rules.d.ts +1 -1
  195. package/dist/features/progress-card/rules.js +1 -1
  196. package/dist/features/progress-card/types.d.ts +1 -1
  197. package/dist/features/progress-card/types.js +1 -1
  198. package/dist/features/resource-dashboard/dependencies.d.ts +1 -1
  199. package/dist/features/resource-dashboard/ports.d.ts +1 -1
  200. package/dist/features/resource-dashboard/react/hooks/useResourceBoard.d.ts +1 -1
  201. package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
  202. package/dist/features/resource-dashboard/rules.d.ts +1 -1
  203. package/dist/features/resource-dashboard/rules.js +2 -2
  204. package/dist/features/resource-dashboard/types.d.ts +4 -4
  205. package/dist/features/resource-dashboard/types.js +1 -1
  206. package/dist/features/schedule-picker/react/hooks/useRecurringSchedulePicker.js +1 -1
  207. package/dist/features/settings/dialog/styles/settings-dialog.css +62 -60
  208. package/dist/features/sketch-editor/constants.d.ts +1 -1
  209. package/dist/features/sketch-editor/constants.js +1 -1
  210. package/dist/features/sketch-editor/dom.d.ts +1 -1
  211. package/dist/features/sketch-editor/dom.js +1 -1
  212. package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.d.ts +1 -1
  213. package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +11 -9
  214. package/dist/features/sketch-editor/types.d.ts +1 -1
  215. package/dist/features/sketch-editor/types.js +1 -1
  216. package/dist/features/skills/react/components/SkillDraftForm.js +1 -1
  217. package/dist/features/skills/react/components/SkillRow.js +1 -1
  218. package/dist/features/skills/react/components/SkillsTab.js +2 -2
  219. package/dist/features/source-config-list/agent-handles.js +2 -2
  220. package/dist/features/source-config-list/react/hooks/useSourceConfigAddForm.d.ts +1 -1
  221. package/dist/features/source-config-list/react/hooks/useSourceConfigAddForm.js +1 -1
  222. package/dist/features/source-config-list/rules.d.ts +1 -1
  223. package/dist/features/source-config-list/rules.js +3 -3
  224. package/dist/features/source-config-list/types.d.ts +1 -1
  225. package/dist/features/source-config-list/types.js +1 -1
  226. package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +1 -1
  227. package/dist/features/tab-strip/index.d.ts +4 -0
  228. package/dist/features/tab-strip/index.js +2 -0
  229. package/dist/features/tab-strip/react/components/TabBar.d.ts +23 -0
  230. package/dist/features/tab-strip/react/components/TabBar.hooks.d.ts +25 -0
  231. package/dist/features/tab-strip/react/components/TabBar.hooks.js +57 -0
  232. package/dist/features/tab-strip/react/components/TabBar.js +18 -0
  233. package/dist/features/tab-strip/react/components/TabStrip.js +2 -1
  234. package/dist/features/tab-strip/react/components/TabStripFrame.d.ts +3 -0
  235. package/dist/features/tab-strip/react/components/TabStripFrame.js +7 -0
  236. package/dist/features/tabbed-dialog/react/hooks/useTabbedDialog.js +1 -1
  237. package/dist/features/tabbed-dialog/styles/tabbed-dialog.css +8 -141
  238. package/dist/features/tabbed-dialog/types.d.ts +1 -1
  239. package/dist/features/tabbed-dialog/types.js +1 -1
  240. package/dist/features/version-manager/ports.d.ts +1 -1
  241. package/dist/features/version-manager/react/components/VersionPromptPopover.js +5 -3
  242. package/dist/features/version-manager/react/components/VersionRestoreControl.js +1 -1
  243. package/dist/features/version-manager/types.d.ts +1 -1
  244. package/dist/features/version-manager/types.js +1 -1
  245. package/dist/features/viewer-shell/dependencies.js +1 -1
  246. package/dist/features/viewer-shell/ports.d.ts +1 -1
  247. package/dist/features/viewer-shell/react/components/ViewportSwitcher.js +1 -1
  248. package/dist/features/viewer-shell/react/hooks/useMarkdownScrollSync.d.ts +1 -1
  249. package/dist/features/viewer-shell/react/hooks/useMarkdownScrollSync.js +1 -1
  250. package/dist/features/viewer-shell/types.d.ts +1 -1
  251. package/dist/features/viewer-shell/types.js +1 -1
  252. package/dist/index.d.ts +420 -0
  253. package/dist/index.js +421 -1
  254. package/dist/react/components/ComponentKitPreview.js +1 -1
  255. package/dist/react/components/EditorIcon.d.ts +1 -1
  256. package/dist/react/components/EditorIcon.js +22 -22
  257. package/dist/react/components/ExportDiagnosticsButton.d.ts +8 -1
  258. package/dist/react/components/ExportDiagnosticsButton.js +6 -6
  259. package/dist/react/components/PaletteTweaks.js +5 -5
  260. package/dist/react/hooks/useBrandFonts.d.ts +19 -4
  261. package/dist/react/hooks/useBrandFonts.js +11 -7
  262. package/dist/react/hooks/useDebouncedValue.d.ts +12 -1
  263. package/dist/react/hooks/useDebouncedValue.js +9 -4
  264. package/dist/react/hooks/useStableHandler.d.ts +3 -1
  265. package/dist/react/hooks/useStableHandler.js +1 -1
  266. package/dist/renderers/annotation-canvas/drawing.d.ts +4 -4
  267. package/dist/renderers/annotation-canvas/drawing.js +28 -15
  268. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +2 -2
  269. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +4 -3
  270. package/dist/renderers/annotation-canvas/rules.d.ts +1 -1
  271. package/dist/renderers/annotation-canvas/theme.d.ts +13 -0
  272. package/dist/renderers/annotation-canvas/theme.js +16 -0
  273. package/dist/renderers/annotation-canvas/types.d.ts +1 -1
  274. package/dist/renderers/index.d.ts +1 -1
  275. package/dist/renderers/new-tab-preview.d.ts +3 -0
  276. package/dist/renderers/new-tab-preview.js +3 -1
  277. package/dist/renderers/preview-modal-shell/react/hooks/usePreviewModalShell.d.ts +1 -1
  278. package/dist/renderers/preview-modal-shell/react/hooks/usePreviewModalShell.js +1 -1
  279. package/dist/renderers/preview-modal-shell/rules.d.ts +1 -1
  280. package/dist/renderers/preview-modal-shell/types.d.ts +3 -3
  281. package/dist/renderers/preview-modal-shell/types.js +2 -2
  282. package/dist/renderers/react/components/ArtifactView.d.ts +1 -1
  283. package/dist/renderers/react/components/ArtifactView.js +1 -1
  284. package/dist/renderers/registry.d.ts +12 -6
  285. package/dist/renderers/registry.js +7 -9
  286. package/dist/renderers/renderers/html.js +2 -2
  287. package/dist/renderers/renderers/index.js +1 -1
  288. package/dist/renderers/renderers/markdown.js +2 -2
  289. package/dist/renderers/renderers/react-component.js +1 -1
  290. package/dist/renderers/renderers/svg.js +1 -1
  291. package/dist/renderers/shiki.js +1 -1
  292. package/dist/renderers/srcdoc/build.d.ts +1 -1
  293. package/dist/renderers/srcdoc/build.js +1 -1
  294. package/dist/renderers/url-load-decision.d.ts +1 -1
  295. package/dist/renderers/url-load-decision.js +1 -1
  296. package/dist/styles/admin.css +273 -0
  297. package/dist/styles/variables.css +117 -0
  298. package/dist/theme/apply.d.ts +9 -0
  299. package/dist/theme/apply.js +77 -0
  300. package/dist/theme/color-scheme.d.ts +8 -0
  301. package/dist/theme/color-scheme.js +9 -0
  302. package/dist/theme/default.d.ts +4 -0
  303. package/dist/theme/default.js +11 -0
  304. package/dist/theme/index.d.ts +6 -0
  305. package/dist/theme/index.js +5 -0
  306. package/dist/theme/stylesheet.d.ts +8 -0
  307. package/dist/theme/stylesheet.js +14 -0
  308. package/dist/theme/types.d.ts +39 -0
  309. package/dist/theme/types.js +2 -0
  310. package/dist/theme/validation.d.ts +15 -0
  311. package/dist/theme/validation.js +55 -0
  312. package/dist/utils/appearance.js +1 -1
  313. package/dist/utils/browser-request.d.ts +12 -0
  314. package/dist/utils/browser-request.js +10 -0
  315. package/dist/utils/color-math.d.ts +20 -6
  316. package/dist/utils/color-math.js +12 -12
  317. package/dist/utils/copy-to-clipboard.d.ts +19 -8
  318. package/dist/utils/copy-to-clipboard.js +15 -11
  319. package/dist/utils/dom-subscriptions.js +1 -1
  320. package/dist/utils/endpoint-policy.d.ts +9 -3
  321. package/dist/utils/endpoint-policy.js +5 -5
  322. package/dist/utils/markdown-scroll-sync.js +3 -3
  323. package/dist/utils/notifications.d.ts +1 -1
  324. package/dist/utils/notifications.js +1 -1
  325. package/dist/utils/polygon-selection.d.ts +1 -1
  326. package/dist/utils/polygon-selection.js +1 -1
  327. package/dist/utils/scroll-tabs-with-wheel.d.ts +4 -1
  328. package/dist/utils/scroll-tabs-with-wheel.js +1 -1
  329. package/dist/utils/smooth-scroll-to-top.js +1 -1
  330. package/dist/utils/sse.d.ts +3 -1
  331. package/dist/utils/sse.js +1 -1
  332. package/package.json +105 -16
  333. package/dist/features/lexical-rich-text-editor/react/test-support/lexical-harness.d.ts +0 -11
  334. package/dist/features/lexical-rich-text-editor/react/test-support/lexical-harness.js +0 -35
@@ -21,17 +21,17 @@ import { rechartsBarChartManifest, BarChart, rechartsLineChartManifest, LineChar
21
21
  * boundary that matters — this cast doesn't weaken that, it only widens a type this file cannot
22
22
  * make TypeScript accept structurally.
23
23
  */
24
- export const DEFAULT_INTERACTIVE_UI_REGISTRY = new InteractiveUiRegistry([
25
- { ...shadcnDataTableManifest, Component: ShadcnDataTable },
26
- { ...nativeDataTableManifest, Component: NativeDataTable },
27
- { ...shadcnButtonManifest, Component: ActionButton },
28
- { ...shadcnCheckboxManifest, Component: CheckboxField },
29
- { ...shadcnRadioGroupManifest, Component: RadioGroupField },
30
- { ...shadcnTextInputManifest, Component: TextInputField },
31
- { ...shadcnSelectManifest, Component: SelectField },
32
- { ...shadcnCardManifest, Component: ContentCard },
33
- { ...rechartsBarChartManifest, Component: BarChart },
34
- { ...rechartsLineChartManifest, Component: LineChart },
35
- { ...rechartsPieChartManifest, Component: PieChart },
36
- ]);
24
+ export const DEFAULT_INTERACTIVE_UI_REGISTRY = new InteractiveUiRegistry({ entries: [
25
+ { ...shadcnDataTableManifest, Component: ShadcnDataTable },
26
+ { ...nativeDataTableManifest, Component: NativeDataTable },
27
+ { ...shadcnButtonManifest, Component: ActionButton },
28
+ { ...shadcnCheckboxManifest, Component: CheckboxField },
29
+ { ...shadcnRadioGroupManifest, Component: RadioGroupField },
30
+ { ...shadcnTextInputManifest, Component: TextInputField },
31
+ { ...shadcnSelectManifest, Component: SelectField },
32
+ { ...shadcnCardManifest, Component: ContentCard },
33
+ { ...rechartsBarChartManifest, Component: BarChart },
34
+ { ...rechartsLineChartManifest, Component: LineChart },
35
+ { ...rechartsPieChartManifest, Component: PieChart },
36
+ ] });
37
37
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--radius-sm:.25rem;--radius-md:.375rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-input:#27272a;--color-ring:#d4d4d8;--color-background:#09090b;--color-foreground:#fafafa;--color-primary:#fafafa;--color-primary-foreground:#18181b;--color-secondary:#27272a;--color-secondary-foreground:#fafafa;--color-muted:#27272a;--color-muted-foreground:#a1a1aa;--color-accent:#27272a;--color-accent-foreground:#fafafa;--color-destructive:#7f1d1d;--color-destructive-foreground:#fafafa}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.right-2{right:calc(var(--spacing) * 2)}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.my-1{margin-block:var(--spacing)}.mt-4{margin-top:calc(var(--spacing) * 4)}.block{display:block}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-row{display:table-row}.aspect-square{aspect-ratio:1}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-px{height:1px}.max-h-\[--radix-select-content-available-height\]{max-height:--radix-select-content-available-height}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-9{width:calc(var(--spacing) * 9)}.w-full{width:100%}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.origin-\[--radix-select-content-transform-origin\]{transform-origin:--radix-select-content-transform-origin}.cursor-default{cursor:default}.flex-col{flex-direction:column}.place-content-center{place-content:center}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-input{border-color:var(--color-input)}.border-primary{border-color:var(--color-primary)}.bg-background{background-color:var(--color-background)}.bg-destructive{background-color:var(--color-destructive)}.bg-muted{background-color:var(--color-muted)}.bg-muted\/50{background-color:#27272a80}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--color-muted) 50%, transparent)}}.bg-primary{background-color:var(--color-primary)}.bg-secondary{background-color:var(--color-secondary)}.bg-transparent{background-color:#0000}.fill-primary{fill:var(--color-primary)}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-6{padding:calc(var(--spacing) * 6)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.pt-0{padding-top:0}.pr-8{padding-right:calc(var(--spacing) * 8)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-left{text-align:left}.align-middle{vertical-align:middle}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.whitespace-nowrap{white-space:nowrap}.text-current{color:currentColor}.text-destructive-foreground{color:var(--color-destructive-foreground)}.text-foreground{color:var(--color-foreground)}.text-input{color:var(--color-input)}.text-muted-foreground{color:var(--color-muted-foreground)}.text-primary{color:var(--color-primary)}.text-primary-foreground{color:var(--color-primary-foreground)}.text-secondary-foreground{color:var(--color-secondary-foreground)}.underline-offset-4{text-underline-offset:4px}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-offset-background{--tw-ring-offset-color:var(--color-background)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-70:is(:where(.peer):disabled~*){opacity:.7}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--color-foreground)}.placeholder\:text-muted-foreground::placeholder{color:var(--color-muted-foreground)}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--color-accent)}.hover\:bg-destructive\/90:hover{background-color:#7f1d1de6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab, var(--color-destructive) 90%, transparent)}}.hover\:bg-muted\/50:hover{background-color:#27272a80}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--color-muted) 50%, transparent)}}.hover\:bg-primary\/90:hover{background-color:#fafafae6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--color-primary) 90%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:#27272acc}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--color-secondary) 80%, transparent)}}.hover\:text-accent-foreground:hover{color:var(--color-accent-foreground)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:bg-accent:focus{background-color:var(--color-accent)}.focus\:text-accent-foreground:focus{color:var(--color-accent-foreground)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-ring:focus{--tw-ring-color:var(--color-ring)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--color-ring)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.has-aria-expanded\:bg-muted\/50:has([aria-expanded=true]){background-color:#27272a80}@supports (color:color-mix(in lab, red, red)){.has-aria-expanded\:bg-muted\/50:has([aria-expanded=true]){background-color:color-mix(in oklab, var(--color-muted) 50%, transparent)}}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:var(--color-muted-foreground)}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--color-primary)}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--color-primary-foreground)}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--color-muted)}@media (min-width:48rem){.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>span\]\:line-clamp-1>span{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}:root,[data-admin-theme],[data-color-scheme=light]{color-scheme:light;--jini-bg:var(--jini-theme-light-bg,#fff);--jini-surface:var(--jini-theme-light-surface,#f5f5f5);--jini-text:var(--jini-theme-light-text,#202020);--jini-muted:var(--jini-theme-light-muted,#666);--jini-border:var(--jini-theme-light-border,#d9d9d9);--jini-primary:var(--jini-theme-light-primary,#363636);--jini-primary-ink:var(--jini-theme-light-primary-ink,#fff);--jini-danger:var(--jini-theme-light-danger,#b42318);--jini-success:var(--jini-theme-light-success,#18763b);--jini-warning:var(--jini-theme-light-warning,#845800)}[data-color-scheme=dark]{color-scheme:dark;--jini-bg:var(--jini-theme-dark-bg,#171717);--jini-surface:var(--jini-theme-dark-surface,#242424);--jini-text:var(--jini-theme-dark-text,#f0f0f0);--jini-muted:var(--jini-theme-dark-muted,#b3b3b3);--jini-border:var(--jini-theme-dark-border,#454545);--jini-primary:var(--jini-theme-dark-primary,#e0e0e0);--jini-primary-ink:var(--jini-theme-dark-primary-ink,#202020);--jini-danger:var(--jini-theme-dark-danger,#ff8b80);--jini-success:var(--jini-theme-dark-success,#79d69b);--jini-warning:var(--jini-theme-dark-warning,#ebc36b)}:root{--jini-font-body:system-ui, sans-serif;--jini-font-heading:system-ui, sans-serif;--jini-font-mono:ui-monospace, monospace;--jini-radius:8px;--jini-density:1}:root,[data-admin-theme],[data-color-scheme]{--jini-bg-panel:var(--jini-surface);--jini-bg-subtle:var(--jini-surface)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-bg-subtle:color-mix(in srgb, var(--jini-surface) 75%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-bg-elevated:var(--jini-surface);--jini-border-soft:var(--jini-border);--jini-border-strong:var(--jini-border)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-border-strong:color-mix(in srgb, var(--jini-border) 75%, var(--jini-text))}}:root,[data-admin-theme],[data-color-scheme]{--jini-backdrop:var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-backdrop:color-mix(in srgb, var(--jini-text) 42%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-text-strong:var(--jini-text);--jini-text-secondary:var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-text-secondary:color-mix(in srgb, var(--jini-text) 80%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-text-muted:var(--jini-muted);--jini-text-faint:var(--jini-muted)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-text-faint:color-mix(in srgb, var(--jini-muted) 75%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-text-disabled:var(--jini-muted)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-text-disabled:color-mix(in srgb, var(--jini-muted) 60%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-accent:var(--jini-primary);--jini-accent-hover:var(--jini-primary)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-accent-hover:color-mix(in srgb, var(--jini-primary) 88%, var(--jini-text))}}:root,[data-admin-theme],[data-color-scheme]{--jini-accent-strong:var(--jini-primary)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-accent-strong:color-mix(in srgb, var(--jini-primary) 85%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-accent-ink:var(--jini-primary-ink);--jini-accent-soft:var(--jini-primary)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-accent-soft:color-mix(in srgb, var(--jini-primary) 10%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-accent-ring:var(--jini-primary)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-accent-ring:color-mix(in srgb, var(--jini-primary) 22%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-neutral-accent:var(--jini-text);--jini-neutral-accent-hover:var(--jini-muted);--jini-neutral-accent-ink:var(--jini-bg);--jini-neutral-accent-text:var(--jini-text);--jini-neutral-accent-soft:var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-neutral-accent-soft:color-mix(in srgb, var(--jini-text) 7%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-neutral-accent-ring:var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-neutral-accent-ring:color-mix(in srgb, var(--jini-text) 16%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-link:var(--jini-primary);--jini-link-ink:var(--jini-primary-ink);--jini-success-bg:var(--jini-success)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-success-bg:color-mix(in srgb, var(--jini-success) 12%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-success-solid:var(--jini-success);--jini-success-solid-ink:var(--jini-bg);--jini-danger-bg:var(--jini-danger)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-danger-bg:color-mix(in srgb, var(--jini-danger) 12%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-warning-bg:var(--jini-warning)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-warning-bg:color-mix(in srgb, var(--jini-warning) 12%, var(--jini-bg))}}:root,[data-admin-theme],[data-color-scheme]{--jini-font-ui:var(--jini-font-body);--jini-font-display:var(--jini-font-heading);--jini-shadow-xs:0 1px 0 var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-xs:0 1px 0 color-mix(in srgb, var(--jini-text) 4%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-sm:0 1px 3px var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-sm:0 1px 3px color-mix(in srgb, var(--jini-text) 10%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-md:0 6px 24px var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-md:0 6px 24px color-mix(in srgb, var(--jini-text) 15%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-lg:0 24px 60px var(--jini-text)}@supports (color:color-mix(in lab, red, red)){:root,[data-admin-theme],[data-color-scheme]{--jini-shadow-lg:0 24px 60px color-mix(in srgb, var(--jini-text) 22%, transparent)}}:root,[data-admin-theme],[data-color-scheme]{--jini-radius-xs:calc(var(--jini-radius) * .5);--jini-radius-sm:calc(var(--jini-radius) * .75);--jini-radius-md:calc(var(--jini-radius) * 1.25);--jini-radius-lg:calc(var(--jini-radius) * 1.5);--jini-radius-pill:999px;--jini-space-1:calc(.25rem * var(--jini-density));--jini-space-2:calc(.5rem * var(--jini-density));--jini-space-3:calc(.75rem * var(--jini-density));--jini-space-4:calc(1rem * var(--jini-density));--jini-space-5:calc(1.25rem * var(--jini-density));--jini-space-6:calc(1.5rem * var(--jini-density));--jini-space-7:calc(2rem * var(--jini-density));--jini-space-8:calc(2.5rem * var(--jini-density));--jini-font-size-2xs:.6875rem;--jini-font-size-xs:.75rem;--jini-font-size-sm:.8125rem;--jini-font-size-base:.875rem;--jini-font-size-md:.95rem;--jini-font-size-lg:1.05rem;--jini-font-size-xl:1.65rem;--jini-font-weight-normal:400;--jini-font-weight-medium:500;--jini-font-weight-semibold:600;--jini-font-weight-bold:700;--jini-line-tight:1.25;--jini-line-normal:1.5;--jini-line-relaxed:1.7;--jini-duration-fast:.12s;--jini-duration-base:.2s;--jini-duration-slow:.32s;--jini-ease-out:cubic-bezier(.23, 1, .32, 1);--jini-ease-in-out:cubic-bezier(.4, 0, .2, 1);--jini-transition-base:var(--jini-duration-base) var(--jini-ease-out);--jini-z-dropdown:100;--jini-z-sticky:200;--jini-z-overlay:300;--jini-z-modal:400;--jini-z-toast:500;--jini-modal-padding:24px;--jini-sidebar-width:240px}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--radius-sm:.25rem;--radius-md:.375rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.right-2{right:calc(var(--spacing) * 2)}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.my-1{margin-block:var(--spacing)}.mt-4{margin-top:calc(var(--spacing) * 4)}.block{display:block}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.table{display:table}.table-caption{display:table-caption}.table-cell{display:table-cell}.table-row{display:table-row}.aspect-square{aspect-ratio:1}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-px{height:1px}.max-h-\[--radix-select-content-available-height\]{max-height:--radix-select-content-available-height}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-9{width:calc(var(--spacing) * 9)}.w-full{width:100%}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.origin-\[--radix-select-content-transform-origin\]{transform-origin:--radix-select-content-transform-origin}.cursor-default{cursor:default}.flex-col{flex-direction:column}.place-content-center{place-content:center}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-input{border-color:var(--jini-border)}.border-primary{border-color:var(--jini-primary)}.bg-background{background-color:var(--jini-bg)}.bg-destructive{background-color:var(--jini-danger)}.bg-muted,.bg-muted\/50{background-color:var(--jini-surface)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--jini-surface) 50%, transparent)}}.bg-primary{background-color:var(--jini-primary)}.bg-secondary{background-color:var(--jini-surface)}.bg-transparent{background-color:#0000}.fill-primary{fill:var(--jini-primary)}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-6{padding:calc(var(--spacing) * 6)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.pt-0{padding-top:0}.pr-8{padding-right:calc(var(--spacing) * 8)}.pl-2{padding-left:calc(var(--spacing) * 2)}.text-left{text-align:left}.align-middle{vertical-align:middle}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.whitespace-nowrap{white-space:nowrap}.text-current{color:currentColor}.text-destructive-foreground{color:var(--jini-bg)}.text-foreground{color:var(--jini-text)}.text-input{color:var(--jini-border)}.text-muted-foreground{color:var(--jini-muted)}.text-primary{color:var(--jini-primary)}.text-primary-foreground{color:var(--jini-primary-ink)}.text-secondary-foreground{color:var(--jini-text)}.underline-offset-4{text-underline-offset:4px}.opacity-50{opacity:.5}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-offset-background{--tw-ring-offset-color:var(--jini-bg)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.peer-disabled\:cursor-not-allowed:is(:where(.peer):disabled~*){cursor:not-allowed}.peer-disabled\:opacity-70:is(:where(.peer):disabled~*){opacity:.7}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--jini-text)}.placeholder\:text-muted-foreground::placeholder{color:var(--jini-muted)}@media (hover:hover){.hover\:bg-accent:hover{background-color:var(--jini-surface)}.hover\:bg-destructive\/90:hover{background-color:var(--jini-danger)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab, var(--jini-danger) 90%, transparent)}}.hover\:bg-muted\/50:hover{background-color:var(--jini-surface)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--jini-surface) 50%, transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--jini-primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--jini-primary) 90%, transparent)}}.hover\:bg-secondary\/80:hover{background-color:var(--jini-surface)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--jini-surface) 80%, transparent)}}.hover\:text-accent-foreground:hover{color:var(--jini-text)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:bg-accent:focus{background-color:var(--jini-surface)}.focus\:text-accent-foreground:focus{color:var(--jini-text)}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-ring:focus{--tw-ring-color:var(--jini-primary)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color:var(--jini-primary)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.has-aria-expanded\:bg-muted\/50:has([aria-expanded=true]){background-color:var(--jini-surface)}@supports (color:color-mix(in lab, red, red)){.has-aria-expanded\:bg-muted\/50:has([aria-expanded=true]){background-color:color-mix(in oklab, var(--jini-surface) 50%, transparent)}}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:var(--jini-muted)}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--jini-primary)}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--jini-primary-ink)}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--jini-surface)}@media (min-width:48rem){.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>span\]\:line-clamp-1>span{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Bar, BarChart as RechartsBarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
3
- export function BarChart({ data, categoryKey, valueKey, color = '#2563eb' }) {
3
+ export function BarChart({ data, categoryKey, valueKey, color = 'var(--jini-primary)' }) {
4
4
  return (_jsx(ResponsiveContainer, { width: "100%", height: 300, children: _jsxs(RechartsBarChart, { data: data, children: [_jsx(CartesianGrid, { strokeDasharray: "3 3" }), _jsx(XAxis, { dataKey: categoryKey, interval: 0 }), _jsx(YAxis, {}), _jsx(Tooltip, {}), _jsx(Bar, { dataKey: valueKey, fill: color, isAnimationActive: false })] }) }));
5
5
  }
6
6
  //# sourceMappingURL=bar-chart.js.map
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CartesianGrid, Line, LineChart as RechartsLineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
3
- export function LineChart({ data, categoryKey, valueKey, color = '#2563eb' }) {
3
+ export function LineChart({ data, categoryKey, valueKey, color = 'var(--jini-primary)' }) {
4
4
  return (_jsx(ResponsiveContainer, { width: "100%", height: 300, children: _jsxs(RechartsLineChart, { data: data, children: [_jsx(CartesianGrid, { strokeDasharray: "3 3" }), _jsx(XAxis, { dataKey: categoryKey, interval: 0 }), _jsx(YAxis, {}), _jsx(Tooltip, {}), _jsx(Line, { type: "monotone", dataKey: valueKey, stroke: color, isAnimationActive: false })] }) }));
5
5
  }
6
6
  //# sourceMappingURL=line-chart.js.map
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Cell, Pie, PieChart as RechartsPieChart, ResponsiveContainer, Tooltip } from 'recharts';
3
- const DEFAULT_COLORS = ['#2563eb', '#16a34a', '#d97706', '#dc2626', '#7c3aed', '#0891b2'];
3
+ const DEFAULT_COLORS = ['var(--jini-primary)', 'var(--jini-success)', 'var(--jini-warning)', 'var(--jini-danger)', 'var(--jini-muted)', 'var(--jini-text)'];
4
4
  export function PieChart({ data, color }) {
5
- return (_jsx(ResponsiveContainer, { width: "100%", height: 300, children: _jsxs(RechartsPieChart, { children: [_jsx(Tooltip, {}), _jsx(Pie, { data: data, dataKey: "value", nameKey: "name", cx: "50%", cy: "50%", outerRadius: 100, label: true, isAnimationActive: false, children: data.map((entry, index) => (_jsx(Cell, { fill: color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length] ?? '#2563eb' }, entry.name))) })] }) }));
5
+ return (_jsx(ResponsiveContainer, { width: "100%", height: 300, children: _jsxs(RechartsPieChart, { children: [_jsx(Tooltip, {}), _jsx(Pie, { data: data, dataKey: "value", nameKey: "name", cx: "50%", cy: "50%", outerRadius: 100, label: true, isAnimationActive: false, children: data.map((entry, index) => (_jsx(Cell, { fill: color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length] ?? 'var(--jini-primary)' }, entry.name))) })] }) }));
6
6
  }
7
7
  //# sourceMappingURL=pie-chart.js.map
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Ported verbatim from `npx shadcn@latest add table` (real CLI run, 2026-08-08, against a
3
- * scratch Vite+Tailwind v4 project — see source-map.md). Only the import path changed:
3
+ * scratch Vite+Tailwind v4 project — see archived provenance ledger). Only the import path changed:
4
4
  * shadcn's default `@/lib/utils` alias doesn't exist in this monorepo, so `table.tsx` imports
5
5
  * this by relative path instead.
6
6
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Ported verbatim from `npx shadcn@latest add table` (real CLI run, 2026-08-08, against a
3
- * scratch Vite+Tailwind v4 project — see source-map.md). Only the import path changed:
3
+ * scratch Vite+Tailwind v4 project — see archived provenance ledger). Only the import path changed:
4
4
  * shadcn's default `@/lib/utils` alias doesn't exist in this monorepo, so `table.tsx` imports
5
5
  * this by relative path instead.
6
6
  */
@@ -8,6 +8,9 @@ import type { InteractiveComponentManifest } from './types.js';
8
8
  */
9
9
  export interface InteractiveComponentEntry<Props = Record<string, unknown>> extends InteractiveComponentManifest {
10
10
  readonly Component: ComponentType<Props>;
11
+ /** Host-wired action callback prop for custom providers; never part of the agent's wire schema.
12
+ * Built-in providers use their documented callback; other entries retain the legacy `onRowClick` default. */
13
+ readonly actionProp?: string;
11
14
  }
12
15
  /**
13
16
  * Resolves an agent's capability request (`"data table"`) to registered component entries, in
@@ -17,11 +20,19 @@ export interface InteractiveComponentEntry<Props = Record<string, unknown>> exte
17
20
  */
18
21
  export declare class InteractiveUiRegistry {
19
22
  private readonly entries;
20
- constructor(entries: readonly InteractiveComponentEntry[]);
23
+ constructor({ entries }: {
24
+ entries: readonly InteractiveComponentEntry[];
25
+ });
21
26
  list(): readonly InteractiveComponentEntry[];
22
- resolveById(id: string): InteractiveComponentEntry | null;
23
- resolveByCapability(capability: string): readonly InteractiveComponentEntry[];
27
+ resolveById({ id }: {
28
+ id: string;
29
+ }): InteractiveComponentEntry | null;
30
+ resolveByCapability({ capability }: {
31
+ capability: string;
32
+ }): readonly InteractiveComponentEntry[];
24
33
  /** Returns a new registry with `entry` appended (or replacing an existing entry of the same id). */
25
- register(entry: InteractiveComponentEntry): InteractiveUiRegistry;
34
+ register({ entry }: {
35
+ entry: InteractiveComponentEntry;
36
+ }): InteractiveUiRegistry;
26
37
  }
27
38
  //# sourceMappingURL=registry.d.ts.map
@@ -6,22 +6,22 @@
6
6
  */
7
7
  export class InteractiveUiRegistry {
8
8
  entries;
9
- constructor(entries) {
9
+ constructor({ entries }) {
10
10
  this.entries = entries;
11
11
  }
12
12
  list() {
13
13
  return this.entries;
14
14
  }
15
- resolveById(id) {
15
+ resolveById({ id }) {
16
16
  return this.entries.find((entry) => entry.id === id) ?? null;
17
17
  }
18
- resolveByCapability(capability) {
18
+ resolveByCapability({ capability }) {
19
19
  return this.entries.filter((entry) => entry.capabilities.includes(capability));
20
20
  }
21
21
  /** Returns a new registry with `entry` appended (or replacing an existing entry of the same id). */
22
- register(entry) {
22
+ register({ entry }) {
23
23
  const withoutExisting = this.entries.filter((item) => item.id !== entry.id);
24
- return new InteractiveUiRegistry([...withoutExisting, entry]);
24
+ return new InteractiveUiRegistry({ entries: [...withoutExisting, entry] });
25
25
  }
26
26
  }
27
27
  //# sourceMappingURL=registry.js.map
@@ -11,10 +11,10 @@ import { Icon } from '../../../../react/components/Icon.js';
11
11
  export function LanguageTab({ locales, selectedLocale, onSelectLocale, ariaLabel, agentHandle }) {
12
12
  const t = useT();
13
13
  const resolvedAriaLabel = ariaLabel ?? t('Language');
14
- const tileHandles = agentHandle ? buildAgentListHandles(agentHandle, locales.map((l) => l.code)) : undefined;
14
+ const tileHandles = agentHandle ? buildAgentListHandles({ prefix: agentHandle, ids: locales.map((l) => l.code) }) : undefined;
15
15
  return (_jsx("section", { className: "jini-settings-section jini-settings-language", children: _jsx("div", { className: "jini-settings-language-grid", role: "radiogroup", "aria-label": resolvedAriaLabel, children: locales.map(({ code, label }, index) => {
16
16
  const active = selectedLocale === code;
17
- return (_jsxs("button", { type: "button", role: "radio", "aria-checked": active, className: `jini-settings-language-tile${active ? ' active' : ''}`, onClick: () => onSelectLocale(code), ...agentHandleProps(tileHandles?.[index], { role: 'button', label }), children: [_jsxs("span", { className: "jini-settings-language-tile-text", children: [_jsx("span", { className: "jini-settings-language-tile-title", children: label }), _jsx("span", { className: "jini-settings-language-tile-code", children: code })] }), active ? _jsx(Icon, { name: "check", size: 16 }) : null] }, code));
17
+ return (_jsxs("button", { type: "button", role: "radio", "aria-checked": active, className: `jini-settings-language-tile${active ? ' active' : ''}`, onClick: () => onSelectLocale(code), ...agentHandleProps({}, { base: tileHandles?.[index], ...({ role: 'button', label }) }), children: [_jsxs("span", { className: "jini-settings-language-tile-text", children: [_jsx("span", { className: "jini-settings-language-tile-title", children: label }), _jsx("span", { className: "jini-settings-language-tile-code", children: code })] }), active ? _jsx(Icon, { name: "check", size: 16 }) : null] }, code));
18
18
  }) }) }));
19
19
  }
20
20
  //# sourceMappingURL=LanguageTab.js.map
@@ -6,7 +6,7 @@
6
6
  * selection-interaction chrome and the selection-validity rule.
7
7
  *
8
8
  * Origin: `DesignSystemsTab.tsx` in the real OD source (the confirmed
9
- * instance of this shape — see `packages/ui/source-map.md` for why
9
+ * instance of this shape — see `packages/ui/archived provenance ledger` for why
10
10
  * `PluginsView.tsx`'s detail modal and `ProjectView.tsx`'s composition were
11
11
  * verified NOT to share it despite the surface-level "conceptually related"
12
12
  * flag in `ADS-memory/reports/jini-port/recon/r6-god-component-internals.md`).
@@ -6,7 +6,7 @@
6
6
  * selection-interaction chrome and the selection-validity rule.
7
7
  *
8
8
  * Origin: `DesignSystemsTab.tsx` in the real OD source (the confirmed
9
- * instance of this shape — see `packages/ui/source-map.md` for why
9
+ * instance of this shape — see `packages/ui/archived provenance ledger` for why
10
10
  * `PluginsView.tsx`'s detail modal and `ProjectView.tsx`'s composition were
11
11
  * verified NOT to share it despite the surface-level "conceptually related"
12
12
  * flag in `ADS-memory/reports/jini-port/recon/r6-god-component-internals.md`).
@@ -79,9 +79,10 @@ function defaultRandomToken() {
79
79
  const source = globalThis.crypto;
80
80
  if (typeof source?.getRandomValues !== 'function') {
81
81
  // No `Math.random` fallback. A predictable confirmation token is a confirmation bypass, and a
82
- // store that silently degrades to one is worse than a store that refuses to start — every
82
+ // store that silently degrades to one is worse than a store that refuses to mint — every
83
83
  // browser and every supported Node exposes `getRandomValues` (it needs no secure context,
84
84
  // unlike `crypto.subtle`), so reaching this means something is deeply wrong with the host.
85
+ // Creation is lazy: the default token source is checked on mint, not when the store is created.
85
86
  throw new Error('createConfirmationStore requires crypto.getRandomValues; pass deps.randomToken to override.');
86
87
  }
87
88
  const bytes = source.getRandomValues(new Uint8Array(TOKEN_BYTES));
@@ -26,7 +26,8 @@ export interface BridgeScriptSpec {
26
26
  * rejected with the Host's own error message on a JSON-RPC error response.
27
27
  * - `notify(method, params)` → a raw fire-and-forget notification, for the lifecycle messages a
28
28
  * surface may want beyond what the bridge sends itself.
29
- * - `openLink(url)` → `ui/open-link`, the only way an isolated frame can navigate anything.
29
+ * - `openLink(url)` → `Promise` of the Host's answer to the `ui/open-link` REQUEST (queued until the
30
+ * handshake completes, like `callTool`) — the only way an isolated frame can navigate anything.
30
31
  * - `requestTeardown()` → `ui/notifications/request-teardown`, the draft-spec way for a "Done"
31
32
  * button to ask the Host to remove the frame.
32
33
  * - `whenReady(fn)` → runs `fn` after the handshake, immediately if it already completed.
@@ -60,7 +60,8 @@ export const SURFACE_HANDSHAKE_FAILED_ATTRIBUTE = 'data-mcpui-handshake-failed';
60
60
  * rejected with the Host's own error message on a JSON-RPC error response.
61
61
  * - `notify(method, params)` → a raw fire-and-forget notification, for the lifecycle messages a
62
62
  * surface may want beyond what the bridge sends itself.
63
- * - `openLink(url)` → `ui/open-link`, the only way an isolated frame can navigate anything.
63
+ * - `openLink(url)` → `Promise` of the Host's answer to the `ui/open-link` REQUEST (queued until the
64
+ * handshake completes, like `callTool`) — the only way an isolated frame can navigate anything.
64
65
  * - `requestTeardown()` → `ui/notifications/request-teardown`, the draft-spec way for a "Done"
65
66
  * button to ask the Host to remove the frame.
66
67
  * - `whenReady(fn)` → runs `fn` after the handshake, immediately if it already completed.
@@ -115,14 +116,23 @@ export function renderBridgeScript(spec) {
115
116
  // tools/call with a JSON-RPC invalidRequest, so sending early would turn "the user clicked a
116
117
  // little too fast" into a refusal the surface would have to explain. A call held when the
117
118
  // handshake FAILS is rejected rather than held forever, so the dialog can say so.
118
- function callTool(name, args) {
119
- var params = { name: name, arguments: args || {} };
120
- if (ready) return request("tools/call", params);
119
+ function requestWhenReady(method, params) {
120
+ if (ready) return request(method, params);
121
121
  return new Promise(function (resolve, reject) {
122
- queuedCalls.push({ resolve: resolve, reject: reject, params: params });
122
+ queuedCalls.push({ resolve: resolve, reject: reject, method: method, params: params });
123
123
  });
124
124
  }
125
125
 
126
+ function callTool(name, args) {
127
+ return requestWhenReady("tools/call", { name: name, arguments: args || {} });
128
+ }
129
+
130
+ // A REQUEST, not a notification: the spec defines ui/open-link as a request, and @mcp-ui/client's
131
+ // AppBridge registers it with setRequestHandler, so an id-less message is silently dropped.
132
+ function openLink(url) {
133
+ return requestWhenReady("ui/open-link", { url: url });
134
+ }
135
+
126
136
  function reportSize() {
127
137
  var root = document.documentElement;
128
138
  notify("ui/notifications/size-changed", { width: root.scrollWidth, height: root.scrollHeight });
@@ -164,7 +174,7 @@ export function renderBridgeScript(spec) {
164
174
  var handlers = readyHandlers;
165
175
  queuedCalls = [];
166
176
  readyHandlers = [];
167
- for (var i = 0; i < calls.length; i++) request("tools/call", calls[i].params).then(calls[i].resolve, calls[i].reject);
177
+ for (var i = 0; i < calls.length; i++) request(calls[i].method, calls[i].params).then(calls[i].resolve, calls[i].reject);
168
178
  for (var j = 0; j < handlers.length; j++) handlers[j]();
169
179
  if (typeof ResizeObserver === "function") new ResizeObserver(reportSize).observe(document.documentElement);
170
180
  }
@@ -190,7 +200,7 @@ export function renderBridgeScript(spec) {
190
200
  window.${global} = {
191
201
  callTool: callTool,
192
202
  notify: notify,
193
- openLink: function (url) { notify("ui/open-link", { url: url }); },
203
+ openLink: openLink,
194
204
  requestTeardown: function () { notify("ui/notifications/request-teardown"); },
195
205
  whenReady: function (fn) { if (ready) fn(); else if (!settled) readyHandlers.push(fn); },
196
206
  hostContext: function () { return hostContext; },
@@ -38,6 +38,18 @@ export interface ConfirmationToolAction {
38
38
  /** Passed verbatim as the tool's `arguments`. The only safe home for a confirmation token. */
39
39
  readonly params: Readonly<Record<string, unknown>>;
40
40
  }
41
+ /**
42
+ * A further affirmative button beside confirm, such as "Allow for this chat" next to "Allow" — see
43
+ * {@link ConfirmationSurfaceSpec.alternatives}.
44
+ */
45
+ export interface ConfirmationAlternative extends ConfirmationToolAction {
46
+ /**
47
+ * The button's `data-mcpui-action` handle. A lowercase `[a-z0-9]+(-[a-z0-9]+)*` handle, unique,
48
+ * and never `confirm` or `cancel`: the script dispatches on it, and an agent driving the frame
49
+ * finds the button by it (`mcpui-action-<id>`).
50
+ */
51
+ readonly id: string;
52
+ }
41
53
  /** One row of an optional per-item checkbox list — see {@link ConfirmationSurfaceSpec.choices}. */
42
54
  export interface ConfirmationChoice {
43
55
  /**
@@ -74,6 +86,14 @@ export interface ConfirmationSurfaceSpec {
74
86
  /** Styles the affirmative button as destructive. Affects presentation only; it changes no behavior. */
75
87
  readonly danger?: boolean;
76
88
  readonly confirm: ConfirmationToolAction;
89
+ /**
90
+ * Further affirmative buttons, rendered after confirm and before cancel, each calling its own tool
91
+ * with its own params. Every one is held to exactly what confirm is held to: disabled until the
92
+ * dwell has run, only a trusted click counts, one call locks the whole dialog, and ticked
93
+ * {@link choices} ride along on it the way they ride on confirm. With none, the dialog renders and
94
+ * behaves exactly as the two-button one does.
95
+ */
96
+ readonly alternatives?: readonly ConfirmationAlternative[];
77
97
  /** Omit for a dialog whose cancel only dismisses. Give it a tool to burn a pending token server-side. */
78
98
  readonly cancel?: ConfirmationToolAction | {
79
99
  readonly label: string;
@@ -40,6 +40,17 @@ import { renderCheckbox } from './checkbox.js';
40
40
  */
41
41
  export const CONFIRM_DWELL_MS = 1500;
42
42
  const DEFAULT_APP = { appName: 'jini-mcp-ui-confirmation', appVersion: '1' };
43
+ const ALTERNATIVE_ID_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
44
+ /** Refuses an alternative id the script or a driver could confuse with another button. */
45
+ function assertAlternativeIds(alternatives) {
46
+ const seen = new Set(['confirm', 'cancel']);
47
+ for (const alternative of alternatives) {
48
+ if (!ALTERNATIVE_ID_PATTERN.test(alternative.id) || seen.has(alternative.id)) {
49
+ throw new Error(`Confirmation alternative ids must be unique lowercase handles other than "confirm" and "cancel"; ${JSON.stringify(alternative.id)} is not.`);
50
+ }
51
+ seen.add(alternative.id);
52
+ }
53
+ }
43
54
  function isToolAction(action) {
44
55
  return action !== undefined && 'toolName' in action;
45
56
  }
@@ -93,6 +104,7 @@ function renderChoices(choices) {
93
104
  function confirmationActions(spec) {
94
105
  const actions = [
95
106
  { id: 'confirm', label: spec.confirm.label, variant: spec.danger === true ? 'danger' : 'primary' },
107
+ ...(spec.alternatives ?? []).map((alternative) => ({ id: alternative.id, label: alternative.label, variant: 'neutral' })),
96
108
  ];
97
109
  if (spec.cancel !== undefined)
98
110
  actions.push({ id: 'cancel', label: spec.cancel.label, variant: 'neutral' });
@@ -106,7 +118,16 @@ export function renderConfirmationDocument(spec) {
106
118
  if ((spec.choices ?? []).length > 0 && Object.prototype.hasOwnProperty.call(spec.confirm.params, choicesParam)) {
107
119
  throw new Error(`choicesParam ${JSON.stringify(choicesParam)} collides with a key already in confirm.params.`);
108
120
  }
121
+ for (const alternative of (spec.choices ?? []).length > 0 ? (spec.alternatives ?? []) : []) {
122
+ if (Object.prototype.hasOwnProperty.call(alternative.params, choicesParam)) {
123
+ throw new Error(`choicesParam ${JSON.stringify(choicesParam)} collides with a key already in the params of alternative ${JSON.stringify(alternative.id)}.`);
124
+ }
125
+ }
126
+ const alternatives = spec.alternatives ?? [];
127
+ assertAlternativeIds(alternatives);
109
128
  const actions = confirmationActions(spec);
129
+ // Every affirmative button starts disabled and waits out the dwell; only cancel is live at once.
130
+ const affirmative = new Set(['confirm', ...alternatives.map((alternative) => alternative.id)]);
110
131
  const warning = spec.warning === undefined ? '' : `<p class="mcpui-warning">${escapeHtml(spec.warning)}</p>`;
111
132
  const bodyHtml = [
112
133
  renderSurfaceHeader(spec.description === undefined ? { title: spec.title } : { title: spec.title, description: spec.description }),
@@ -114,7 +135,7 @@ export function renderConfirmationDocument(spec) {
114
135
  renderChoices(spec.choices ?? []),
115
136
  warning,
116
137
  // Confirm starts disabled; the script enables it once the dwell has run out.
117
- renderActions(actions.map((action) => (action.id === 'confirm' ? { ...action, disabled: true } : action))),
138
+ renderActions(actions.map((action) => (affirmative.has(action.id) ? { ...action, disabled: true } : action))),
118
139
  renderStatusRegion(),
119
140
  ]
120
141
  .filter((fragment) => fragment !== '')
@@ -125,6 +146,9 @@ export function renderConfirmationDocument(spec) {
125
146
  const plan = {
126
147
  confirm: { toolName: spec.confirm.toolName, params: spec.confirm.params },
127
148
  };
149
+ for (const alternative of alternatives) {
150
+ plan[alternative.id] = { toolName: alternative.toolName, params: alternative.params };
151
+ }
128
152
  if (spec.cancel !== undefined) {
129
153
  plan['cancel'] = isToolAction(spec.cancel)
130
154
  ? { toolName: spec.cancel.toolName, params: spec.cancel.params }
@@ -137,6 +161,10 @@ ${SURFACE_SCRIPT_PRELUDE}
137
161
  var TEXT = ${escapeJsValue(text)};
138
162
  var DWELL_MS = ${CONFIRM_DWELL_MS};
139
163
  var CHOICES_PARAM = ${escapeJsValue(choicesParam)};
164
+ var AFFIRMATIVE = ${escapeJsValue([...affirmative])};
165
+ function isAffirmative(action) {
166
+ return AFFIRMATIVE.indexOf(action) !== -1;
167
+ }
140
168
 
141
169
  // Monotonic where available: a wall clock set backwards would otherwise stretch the dwell.
142
170
  function now() {
@@ -150,14 +178,18 @@ ${SURFACE_SCRIPT_PRELUDE}
150
178
  // has not been seen, so its dwell starts when it is shown, and restarts each time it is shown again.
151
179
  var visibleSince = null;
152
180
  var dwellTimer = null;
153
- var confirmButton = document.querySelector('[data-mcpui-action="confirm"]');
181
+ var affirmativeButtons = actionButtons.filter(function (node) {
182
+ return isAffirmative(node.getAttribute("data-mcpui-action"));
183
+ });
154
184
 
155
185
  function dwellDone() {
156
186
  return visibleSince !== null && now() - visibleSince >= DWELL_MS;
157
187
  }
158
- // Confirm is enabled exactly when the dwell has run out and no call holds the dialog.
188
+ // Confirm (and every alternative) is enabled exactly when the dwell has run out and no call holds
189
+ // the dialog.
159
190
  function syncConfirm() {
160
- if (confirmButton !== null && !locked) confirmButton.disabled = !dwellDone();
191
+ if (locked) return;
192
+ for (var b = 0; b < affirmativeButtons.length; b++) affirmativeButtons[b].disabled = !dwellDone();
161
193
  }
162
194
  // Re-checks rather than trusts the timer: setTimeout and now() are different clocks, and a timer
163
195
  // that fired a hair early must not leave confirm disabled for good.
@@ -231,7 +263,7 @@ ${SURFACE_SCRIPT_PRELUDE}
231
263
  var step = PLAN[action];
232
264
  if (step === undefined) return;
233
265
  // Cancel is exempt: backing out early is never the harm this guards against.
234
- if (action === "confirm" && !dwellDone()) return;
266
+ if (isAffirmative(action) && !dwellDone()) return;
235
267
  locked = true;
236
268
  setChoicesDisabled(true);
237
269
  if (step === null) {
@@ -243,7 +275,7 @@ ${SURFACE_SCRIPT_PRELUDE}
243
275
  // Choices ride only on confirm, and only when this document has any -- with none, \`params\` stays
244
276
  // the exact \`step.params\` reference PLAN was built from, byte-identical to before this existed.
245
277
  var params = step.params;
246
- if (action === "confirm" && choiceInputs.length > 0) {
278
+ if (isAffirmative(action) && choiceInputs.length > 0) {
247
279
  var merged = {};
248
280
  var key;
249
281
  for (key in step.params) if (Object.prototype.hasOwnProperty.call(step.params, key)) merged[key] = step.params[key];
@@ -8,7 +8,7 @@ import { type SurfaceTokenName } from './tokens.js';
8
8
  * be a color no caller could reskin. `var(--x, fallback)` appears only where a value is genuinely
9
9
  * optional.
10
10
  */
11
- export declare const SURFACE_BASE_CSS = "*, *::before, *::after { box-sizing: border-box; }\nhtml, body { margin: 0; padding: 0; }\nbody {\n /* Transparent, not var(--jini-mcpui-bg): this document has no page of its own to paint. It is an\n allow-scripts-only sandboxed iframe embedded directly in a host's chat transcript, and html's\n background is left at its (also transparent) initial value, so the host's own pane shows\n straight through to .mcpui-surface below rather than through a second, unrelated rectangle of\n fill color sitting between the two. --jini-mcpui-bg stays declared for a caller styling\n something else via extraCss -- nothing in this stylesheet reads it anymore. */\n background: transparent;\n color: var(--jini-mcpui-text);\n font-family: var(--jini-mcpui-font);\n font-size: 14px;\n line-height: 1.5;\n padding: 16px;\n -webkit-font-smoothing: antialiased;\n}\n.mcpui-surface {\n background: linear-gradient(135deg,\n color-mix(in srgb, var(--jini-mcpui-accent) 5%, var(--jini-mcpui-panel)) 0%,\n var(--jini-mcpui-panel) 60%);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 18%, var(--jini-mcpui-border));\n border-radius: var(--jini-mcpui-radius-md);\n box-shadow: var(--jini-mcpui-surface-shadow);\n padding: 18px 20px 16px;\n max-width: 640px;\n margin: 0 auto;\n}\n.mcpui-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--jini-mcpui-text-strong);\n}\n.mcpui-description { margin: 6px 0 0; color: var(--jini-mcpui-text-muted); }\n.mcpui-details {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr);\n gap: 4px 14px;\n margin: 14px 0 0;\n}\n.mcpui-details dt { color: var(--jini-mcpui-text-soft); font-weight: 500; }\n.mcpui-details dd { margin: 0; overflow-wrap: anywhere; color: var(--jini-mcpui-text); }\n.mcpui-warning {\n margin: 14px 0 0;\n padding: 9px 11px;\n border-radius: var(--jini-mcpui-radius-md);\n border: 1px solid var(--jini-mcpui-danger);\n background: var(--jini-mcpui-danger-tint);\n color: var(--jini-mcpui-text-strong);\n}\n.mcpui-fields { display: flex; flex-direction: column; gap: 12px; margin: 16px 0 0; border: 0; padding: 0; }\n.mcpui-field { display: flex; flex-direction: column; gap: 4px; }\n.mcpui-field-inline { flex-direction: row; align-items: flex-start; gap: 8px; }\n.mcpui-label { font-weight: 500; color: var(--jini-mcpui-text-strong); }\n.mcpui-required { color: var(--jini-mcpui-accent); margin-left: 2px; }\n.mcpui-hint { color: var(--jini-mcpui-text-soft); font-size: 13px; }\n.mcpui-input, .mcpui-select, .mcpui-textarea {\n font: inherit;\n color: var(--jini-mcpui-text);\n background: var(--jini-mcpui-panel);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 14%, var(--jini-mcpui-border-strong));\n border-radius: var(--jini-mcpui-radius-sm);\n padding: 7px 9px;\n width: 100%;\n min-width: 0;\n}\n.mcpui-textarea { resize: vertical; min-height: 72px; font-family: var(--jini-mcpui-font); }\n.mcpui-checkbox { margin: 3px 0 0; accent-color: var(--jini-mcpui-accent); }\n.mcpui-choice-group { border: 0; padding: 0; margin: 0; min-width: 0; }\n.mcpui-choice { display: flex; flex-direction: row; align-items: flex-start; gap: 8px; margin: 6px 0 0; }\n.mcpui-choice-label { color: var(--jini-mcpui-text); font-weight: 400; }\n.mcpui-input:focus-visible, .mcpui-select:focus-visible, .mcpui-textarea:focus-visible,\n.mcpui-checkbox:focus-visible, .mcpui-button:focus-visible {\n outline: 2px solid var(--jini-mcpui-accent-ring);\n outline-offset: 1px;\n border-color: var(--jini-mcpui-accent);\n}\n.mcpui-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 0; }\n.mcpui-button {\n font: inherit;\n font-weight: 500;\n padding: 7px 15px;\n border-radius: var(--jini-mcpui-radius-pill);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 14%, var(--jini-mcpui-border-strong));\n background: var(--jini-mcpui-panel);\n color: var(--jini-mcpui-text);\n cursor: pointer;\n}\n.mcpui-button:hover:not([disabled]) { background: var(--jini-mcpui-accent-tint); }\n.mcpui-button-primary {\n background: var(--jini-mcpui-accent);\n border-color: var(--jini-mcpui-accent);\n color: var(--jini-mcpui-panel);\n}\n.mcpui-button-primary:hover:not([disabled]) { background: var(--jini-mcpui-accent-hover); border-color: var(--jini-mcpui-accent-hover); }\n.mcpui-button-danger {\n background: var(--jini-mcpui-danger);\n border-color: var(--jini-mcpui-danger);\n color: var(--jini-mcpui-panel);\n}\n.mcpui-button-danger:hover:not([disabled]) { background: var(--jini-mcpui-danger-hover); border-color: var(--jini-mcpui-danger-hover); }\n.mcpui-button[disabled] { opacity: 0.55; cursor: default; }\n.mcpui-status { margin: 12px 0 0; min-height: 1.4em; color: var(--jini-mcpui-text-muted); }\n.mcpui-status[data-state=\"failed\"], .mcpui-status[data-state=\"invalid\"], .mcpui-status[data-state=\"expired\"] { color: var(--jini-mcpui-danger); }\n.mcpui-status[data-state=\"done\"] { color: var(--jini-mcpui-text-strong); }\n/* Neither a plain success nor a failure \u2014 e.g. an outcome surface reporting \"uploaded, not yet\n reachable\" (outcome.ts's own state: partial). Distinct from both --jini-mcpui-danger (would\n wrongly read as \"this failed\") and --jini-mcpui-text-strong (would wrongly read as \"this is\n fully done\"); the accent token reads as \"worth a second look\" without asserting either. */\n.mcpui-status[data-state=\"partial\"] { color: var(--jini-mcpui-accent); }\n.mcpui-code { font-family: var(--jini-mcpui-font-mono); font-size: 13px; color: var(--jini-mcpui-text-faint); }";
11
+ export declare const SURFACE_BASE_CSS = "*, *::before, *::after { box-sizing: border-box; }\nhtml, body { margin: 0; padding: 0; }\nbody {\n /* Transparent, not var(--jini-mcpui-bg): this document has no page of its own to paint. It is an\n allow-scripts-only sandboxed iframe embedded directly in a host's chat transcript, and html's\n background is left at its (also transparent) initial value, so the host's own pane shows\n straight through to .mcpui-surface below rather than through a second, unrelated rectangle of\n fill color sitting between the two. --jini-mcpui-bg stays declared for a caller styling\n something else via extraCss -- nothing in this stylesheet reads it anymore. */\n background: transparent;\n color: var(--jini-mcpui-text);\n font-family: var(--jini-mcpui-font);\n font-size: 14px;\n line-height: 1.5;\n padding: 16px;\n -webkit-font-smoothing: antialiased;\n}\n.mcpui-surface {\n background: linear-gradient(135deg,\n color-mix(in srgb, var(--jini-mcpui-accent) 5%, var(--jini-mcpui-panel)) 0%,\n var(--jini-mcpui-panel) 60%);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 18%, var(--jini-mcpui-border));\n border-radius: var(--jini-mcpui-radius-md);\n box-shadow: var(--jini-mcpui-surface-shadow);\n padding: 18px 20px 16px;\n max-width: 640px;\n margin: 0 auto;\n}\n.mcpui-title {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: -0.01em;\n color: var(--jini-mcpui-text-strong);\n}\n.mcpui-description { margin: 6px 0 0; color: var(--jini-mcpui-text-muted); }\n.mcpui-details {\n display: grid;\n grid-template-columns: max-content minmax(0, 1fr);\n gap: 4px 14px;\n margin: 14px 0 0;\n}\n.mcpui-details dt { color: var(--jini-mcpui-text-soft); font-weight: 500; }\n.mcpui-details dd { margin: 0; overflow-wrap: anywhere; color: var(--jini-mcpui-text); }\n.mcpui-code {\n margin: 0;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n max-height: 16em;\n overflow: auto;\n font-family: var(--jini-mcpui-font-mono);\n font-size: 12.5px;\n line-height: 1.45;\n padding: 6px 8px;\n border: 1px solid var(--jini-mcpui-border);\n border-radius: var(--jini-mcpui-radius-sm);\n background: var(--jini-mcpui-bg);\n}\n.mcpui-warning {\n margin: 14px 0 0;\n padding: 9px 11px;\n border-radius: var(--jini-mcpui-radius-md);\n border: 1px solid var(--jini-mcpui-danger);\n background: var(--jini-mcpui-danger-tint);\n color: var(--jini-mcpui-text-strong);\n}\n.mcpui-fields { display: flex; flex-direction: column; gap: 12px; margin: 16px 0 0; border: 0; padding: 0; }\n.mcpui-field { display: flex; flex-direction: column; gap: 4px; }\n.mcpui-field-inline { flex-direction: row; align-items: flex-start; gap: 8px; }\n.mcpui-label { font-weight: 500; color: var(--jini-mcpui-text-strong); }\n.mcpui-required { color: var(--jini-mcpui-accent); margin-left: 2px; }\n.mcpui-hint { color: var(--jini-mcpui-text-soft); font-size: 13px; }\n.mcpui-input, .mcpui-select, .mcpui-textarea {\n font: inherit;\n color: var(--jini-mcpui-text);\n background: var(--jini-mcpui-panel);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 14%, var(--jini-mcpui-border-strong));\n border-radius: var(--jini-mcpui-radius-sm);\n padding: 7px 9px;\n width: 100%;\n min-width: 0;\n}\n.mcpui-textarea { resize: vertical; min-height: 72px; font-family: var(--jini-mcpui-font); }\n.mcpui-checkbox { margin: 3px 0 0; accent-color: var(--jini-mcpui-accent); }\n.mcpui-choice-group { border: 0; padding: 0; margin: 0; min-width: 0; }\n.mcpui-choice { display: flex; flex-direction: row; align-items: flex-start; gap: 8px; margin: 6px 0 0; }\n.mcpui-choice-label { color: var(--jini-mcpui-text); font-weight: 400; }\n.mcpui-input:focus-visible, .mcpui-select:focus-visible, .mcpui-textarea:focus-visible,\n.mcpui-checkbox:focus-visible, .mcpui-button:focus-visible {\n outline: 2px solid var(--jini-mcpui-accent-ring);\n outline-offset: 1px;\n border-color: var(--jini-mcpui-accent);\n}\n.mcpui-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0 0; }\n.mcpui-button {\n font: inherit;\n font-weight: 500;\n padding: 7px 15px;\n border-radius: var(--jini-mcpui-radius-pill);\n border: 1px solid color-mix(in srgb, var(--jini-mcpui-accent) 14%, var(--jini-mcpui-border-strong));\n background: var(--jini-mcpui-panel);\n color: var(--jini-mcpui-text);\n cursor: pointer;\n}\n.mcpui-button:hover:not([disabled]) { background: var(--jini-mcpui-accent-tint); }\n.mcpui-button-primary {\n background: var(--jini-mcpui-accent);\n border-color: var(--jini-mcpui-accent);\n color: var(--jini-mcpui-panel);\n}\n.mcpui-button-primary:hover:not([disabled]) { background: var(--jini-mcpui-accent-hover); border-color: var(--jini-mcpui-accent-hover); }\n.mcpui-button-danger {\n background: var(--jini-mcpui-danger);\n border-color: var(--jini-mcpui-danger);\n color: var(--jini-mcpui-panel);\n}\n.mcpui-button-danger:hover:not([disabled]) { background: var(--jini-mcpui-danger-hover); border-color: var(--jini-mcpui-danger-hover); }\n.mcpui-button[disabled] { opacity: 0.55; cursor: default; }\n.mcpui-status { margin: 12px 0 0; min-height: 1.4em; color: var(--jini-mcpui-text-muted); }\n.mcpui-status[data-state=\"failed\"], .mcpui-status[data-state=\"invalid\"], .mcpui-status[data-state=\"expired\"] { color: var(--jini-mcpui-danger); }\n.mcpui-status[data-state=\"done\"] { color: var(--jini-mcpui-text-strong); }\n/* Neither a plain success nor a failure \u2014 e.g. an outcome surface reporting \"uploaded, not yet\n reachable\" (outcome.ts's own state: partial). Distinct from both --jini-mcpui-danger (would\n wrongly read as \"this failed\") and --jini-mcpui-text-strong (would wrongly read as \"this is\n fully done\"); the accent token reads as \"worth a second look\" without asserting either. */\n.mcpui-status[data-state=\"partial\"] { color: var(--jini-mcpui-accent); }\n.mcpui-code { font-family: var(--jini-mcpui-font-mono); font-size: 13px; color: var(--jini-mcpui-text-faint); }";
12
12
  /**
13
13
  * The Content-Security-Policy every generated surface declares in its own `<head>`.
14
14
  *
@@ -66,6 +66,12 @@ export declare function renderSurfaceHeader(spec: {
66
66
  export interface SurfaceDetail {
67
67
  readonly label: string;
68
68
  readonly value: string;
69
+ /**
70
+ * `code` renders the value in a monospace `<pre>` that keeps its line breaks and scrolls inside
71
+ * its own box past a fixed height, so a long SQL statement or JSON argument stays readable without
72
+ * stretching the dialog past its frame. Omitted (or `text`) keeps the plain inline value.
73
+ */
74
+ readonly format?: 'text' | 'code';
69
75
  }
70
76
  /**
71
77
  * Renders a `label: value` description list.
@@ -67,6 +67,20 @@ body {
67
67
  }
68
68
  .mcpui-details dt { color: var(--jini-mcpui-text-soft); font-weight: 500; }
69
69
  .mcpui-details dd { margin: 0; overflow-wrap: anywhere; color: var(--jini-mcpui-text); }
70
+ .mcpui-code {
71
+ margin: 0;
72
+ white-space: pre-wrap;
73
+ overflow-wrap: anywhere;
74
+ max-height: 16em;
75
+ overflow: auto;
76
+ font-family: var(--jini-mcpui-font-mono);
77
+ font-size: 12.5px;
78
+ line-height: 1.45;
79
+ padding: 6px 8px;
80
+ border: 1px solid var(--jini-mcpui-border);
81
+ border-radius: var(--jini-mcpui-radius-sm);
82
+ background: var(--jini-mcpui-bg);
83
+ }
70
84
  .mcpui-warning {
71
85
  margin: 14px 0 0;
72
86
  padding: 9px 11px;
@@ -209,7 +223,11 @@ export function renderDetailList(details) {
209
223
  if (details.length === 0)
210
224
  return '';
211
225
  const rows = details
212
- .map((detail) => ` <dt>${escapeHtml(detail.label)}</dt><dd>${escapeHtml(detail.value)}</dd>`)
226
+ .map((detail) => {
227
+ const value = escapeHtml(detail.value);
228
+ const body = detail.format === 'code' ? `<pre class="mcpui-code">${value}</pre>` : value;
229
+ return ` <dt>${escapeHtml(detail.label)}</dt><dd>${body}</dd>`;
230
+ })
213
231
  .join('\n');
214
232
  return `<dl class="mcpui-details">\n${rows}\n</dl>`;
215
233
  }