@miragon/mcp-toolkit-ui 2.7.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +7 -4
  2. package/dist/app/adapt-data-widget.d.ts +1 -22
  3. package/dist/app/adapt-data-widget.d.ts.map +1 -1
  4. package/dist/app/adapt-data-widget.js +1 -35
  5. package/dist/app/adapt-data-widget.js.map +1 -1
  6. package/dist/app/builder/BuilderBanners.js +1 -1
  7. package/dist/app/builder/BuilderBanners.js.map +1 -1
  8. package/dist/app/builder/CanvasRow.d.ts +4 -2
  9. package/dist/app/builder/CanvasRow.d.ts.map +1 -1
  10. package/dist/app/builder/CanvasRow.js +21 -7
  11. package/dist/app/builder/CanvasRow.js.map +1 -1
  12. package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
  13. package/dist/app/builder/CatalogueSheet.js +11 -4
  14. package/dist/app/builder/CatalogueSheet.js.map +1 -1
  15. package/dist/app/builder/CellPropsSheet.d.ts +7 -3
  16. package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
  17. package/dist/app/builder/CellPropsSheet.js +10 -3
  18. package/dist/app/builder/CellPropsSheet.js.map +1 -1
  19. package/dist/app/builder/DiscardDialog.d.ts +18 -0
  20. package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
  21. package/dist/app/builder/DiscardDialog.js +18 -0
  22. package/dist/app/builder/DiscardDialog.js.map +1 -0
  23. package/dist/app/builder/LayoutSurface.d.ts +33 -9
  24. package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
  25. package/dist/app/builder/LayoutSurface.js +74 -23
  26. package/dist/app/builder/LayoutSurface.js.map +1 -1
  27. package/dist/app/builder/PipelineStrip.d.ts +2 -1
  28. package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
  29. package/dist/app/builder/PipelineStrip.js +26 -13
  30. package/dist/app/builder/PipelineStrip.js.map +1 -1
  31. package/dist/app/builder/SaveDialog.d.ts +9 -1
  32. package/dist/app/builder/SaveDialog.d.ts.map +1 -1
  33. package/dist/app/builder/SaveDialog.js +8 -2
  34. package/dist/app/builder/SaveDialog.js.map +1 -1
  35. package/dist/app/builder/Toolbar.d.ts +12 -4
  36. package/dist/app/builder/Toolbar.d.ts.map +1 -1
  37. package/dist/app/builder/Toolbar.js +18 -7
  38. package/dist/app/builder/Toolbar.js.map +1 -1
  39. package/dist/app/builder/Workspace.d.ts +23 -3
  40. package/dist/app/builder/Workspace.d.ts.map +1 -1
  41. package/dist/app/builder/Workspace.js +58 -8
  42. package/dist/app/builder/Workspace.js.map +1 -1
  43. package/dist/app/builder/builder-model.d.ts +143 -1
  44. package/dist/app/builder/builder-model.d.ts.map +1 -1
  45. package/dist/app/builder/builder-model.js +191 -1
  46. package/dist/app/builder/builder-model.js.map +1 -1
  47. package/dist/app/builder/reveal.d.ts +10 -0
  48. package/dist/app/builder/reveal.d.ts.map +1 -0
  49. package/dist/app/builder/reveal.js +10 -0
  50. package/dist/app/builder/reveal.js.map +1 -0
  51. package/dist/app/builder/use-builder-catalogue.d.ts +4 -1
  52. package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
  53. package/dist/app/builder/use-builder-catalogue.js +44 -17
  54. package/dist/app/builder/use-builder-catalogue.js.map +1 -1
  55. package/dist/app/builder/use-builder-session.d.ts +30 -0
  56. package/dist/app/builder/use-builder-session.d.ts.map +1 -0
  57. package/dist/app/builder/use-builder-session.js +58 -0
  58. package/dist/app/builder/use-builder-session.js.map +1 -0
  59. package/dist/app/builder/use-display-resolver.d.ts +17 -0
  60. package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
  61. package/dist/app/builder/use-display-resolver.js +16 -0
  62. package/dist/app/builder/use-display-resolver.js.map +1 -0
  63. package/dist/app/index.d.ts +8 -3
  64. package/dist/app/index.d.ts.map +1 -1
  65. package/dist/app/index.js +8 -2
  66. package/dist/app/index.js.map +1 -1
  67. package/dist/app/layout-builder.d.ts +13 -25
  68. package/dist/app/layout-builder.d.ts.map +1 -1
  69. package/dist/app/layout-builder.js +75 -81
  70. package/dist/app/layout-builder.js.map +1 -1
  71. package/dist/app/mcp-app-view-chrome.d.ts +12 -3
  72. package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
  73. package/dist/app/mcp-app-view-chrome.js +21 -5
  74. package/dist/app/mcp-app-view-chrome.js.map +1 -1
  75. package/dist/app/mcp-app-view-states.d.ts +11 -3
  76. package/dist/app/mcp-app-view-states.d.ts.map +1 -1
  77. package/dist/app/mcp-app-view-states.js +29 -8
  78. package/dist/app/mcp-app-view-states.js.map +1 -1
  79. package/dist/app/mcp-app-view.d.ts +33 -1
  80. package/dist/app/mcp-app-view.d.ts.map +1 -1
  81. package/dist/app/mcp-app-view.js +181 -127
  82. package/dist/app/mcp-app-view.js.map +1 -1
  83. package/dist/app/mcp-toolkit-app.d.ts +6 -1
  84. package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
  85. package/dist/app/mcp-toolkit-app.js +8 -1
  86. package/dist/app/mcp-toolkit-app.js.map +1 -1
  87. package/dist/app/mcp-use-host-bridge.d.ts +15 -6
  88. package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
  89. package/dist/app/mcp-use-host-bridge.js +51 -22
  90. package/dist/app/mcp-use-host-bridge.js.map +1 -1
  91. package/dist/app/model-context.d.ts +71 -0
  92. package/dist/app/model-context.d.ts.map +1 -0
  93. package/dist/app/model-context.js +101 -0
  94. package/dist/app/model-context.js.map +1 -0
  95. package/dist/app/use-build-mode-focus.d.ts +33 -0
  96. package/dist/app/use-build-mode-focus.d.ts.map +1 -0
  97. package/dist/app/use-build-mode-focus.js +59 -0
  98. package/dist/app/use-build-mode-focus.js.map +1 -0
  99. package/dist/app/use-view-actions.d.ts +31 -0
  100. package/dist/app/use-view-actions.d.ts.map +1 -0
  101. package/dist/app/use-view-actions.js +81 -0
  102. package/dist/app/use-view-actions.js.map +1 -0
  103. package/dist/app/use-view-lifecycle.d.ts +4 -0
  104. package/dist/app/use-view-lifecycle.d.ts.map +1 -1
  105. package/dist/app/use-view-lifecycle.js +2 -0
  106. package/dist/app/use-view-lifecycle.js.map +1 -1
  107. package/dist/app/view-lifecycle.d.ts +80 -4
  108. package/dist/app/view-lifecycle.d.ts.map +1 -1
  109. package/dist/app/view-lifecycle.js +90 -3
  110. package/dist/app/view-lifecycle.js.map +1 -1
  111. package/dist/app/widget-fixture.d.ts +10 -3
  112. package/dist/app/widget-fixture.d.ts.map +1 -1
  113. package/dist/app/widget-fixture.js +21 -8
  114. package/dist/app/widget-fixture.js.map +1 -1
  115. package/dist/app/widget-props-sheet.d.ts +3 -1
  116. package/dist/app/widget-props-sheet.d.ts.map +1 -1
  117. package/dist/app/widget-props-sheet.js +22 -10
  118. package/dist/app/widget-props-sheet.js.map +1 -1
  119. package/dist/app/widget-renderer.js +1 -1
  120. package/dist/app/widget-renderer.js.map +1 -1
  121. package/dist/components/DrillButton.d.ts +14 -6
  122. package/dist/components/DrillButton.d.ts.map +1 -1
  123. package/dist/components/DrillButton.js +14 -7
  124. package/dist/components/DrillButton.js.map +1 -1
  125. package/dist/components/EmptyState.d.ts.map +1 -1
  126. package/dist/components/EmptyState.js +4 -2
  127. package/dist/components/EmptyState.js.map +1 -1
  128. package/dist/components/ErrorState.d.ts +5 -2
  129. package/dist/components/ErrorState.d.ts.map +1 -1
  130. package/dist/components/ErrorState.js +25 -8
  131. package/dist/components/ErrorState.js.map +1 -1
  132. package/dist/components/FilterBar.d.ts +15 -4
  133. package/dist/components/FilterBar.d.ts.map +1 -1
  134. package/dist/components/FilterBar.js +11 -6
  135. package/dist/components/FilterBar.js.map +1 -1
  136. package/dist/components/KpiGrid.d.ts +66 -21
  137. package/dist/components/KpiGrid.d.ts.map +1 -1
  138. package/dist/components/KpiGrid.js +101 -34
  139. package/dist/components/KpiGrid.js.map +1 -1
  140. package/dist/components/ListFooter.d.ts +31 -4
  141. package/dist/components/ListFooter.d.ts.map +1 -1
  142. package/dist/components/ListFooter.js +30 -11
  143. package/dist/components/ListFooter.js.map +1 -1
  144. package/dist/components/PagedListFooter.d.ts +57 -0
  145. package/dist/components/PagedListFooter.d.ts.map +1 -0
  146. package/dist/components/PagedListFooter.js +27 -0
  147. package/dist/components/PagedListFooter.js.map +1 -0
  148. package/dist/components/Pills.d.ts +27 -7
  149. package/dist/components/Pills.d.ts.map +1 -1
  150. package/dist/components/Pills.js +21 -6
  151. package/dist/components/Pills.js.map +1 -1
  152. package/dist/components/SectionHeading.d.ts +3 -1
  153. package/dist/components/SectionHeading.d.ts.map +1 -1
  154. package/dist/components/SectionHeading.js +6 -2
  155. package/dist/components/SectionHeading.js.map +1 -1
  156. package/dist/components/Toast.d.ts +9 -3
  157. package/dist/components/Toast.d.ts.map +1 -1
  158. package/dist/components/Toast.js +31 -16
  159. package/dist/components/Toast.js.map +1 -1
  160. package/dist/components/WidgetHeader.d.ts +34 -10
  161. package/dist/components/WidgetHeader.d.ts.map +1 -1
  162. package/dist/components/WidgetHeader.js +11 -6
  163. package/dist/components/WidgetHeader.js.map +1 -1
  164. package/dist/hooks/index.d.ts +4 -4
  165. package/dist/hooks/index.d.ts.map +1 -1
  166. package/dist/hooks/index.js +1 -1
  167. package/dist/hooks/index.js.map +1 -1
  168. package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
  169. package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
  170. package/dist/hooks/tool-result-recovery-model.js +273 -0
  171. package/dist/hooks/tool-result-recovery-model.js.map +1 -0
  172. package/dist/hooks/use-tool-query.d.ts +56 -14
  173. package/dist/hooks/use-tool-query.d.ts.map +1 -1
  174. package/dist/hooks/use-tool-query.js +102 -25
  175. package/dist/hooks/use-tool-query.js.map +1 -1
  176. package/dist/hooks/use-tool-result-recovery.d.ts +47 -52
  177. package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
  178. package/dist/hooks/use-tool-result-recovery.js +58 -120
  179. package/dist/hooks/use-tool-result-recovery.js.map +1 -1
  180. package/dist/hooks/use-view-data.d.ts +52 -10
  181. package/dist/hooks/use-view-data.d.ts.map +1 -1
  182. package/dist/hooks/use-view-data.js +81 -16
  183. package/dist/hooks/use-view-data.js.map +1 -1
  184. package/dist/hooks/use-view-tool-query.d.ts +12 -7
  185. package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
  186. package/dist/hooks/use-view-tool-query.js +15 -14
  187. package/dist/hooks/use-view-tool-query.js.map +1 -1
  188. package/dist/index.d.ts +17 -10
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +18 -6
  191. package/dist/index.js.map +1 -1
  192. package/dist/lib/focus-return.d.ts +61 -0
  193. package/dist/lib/focus-return.d.ts.map +1 -0
  194. package/dist/lib/focus-return.js +46 -0
  195. package/dist/lib/focus-return.js.map +1 -0
  196. package/dist/lib/parse-tool-result.d.ts +23 -1
  197. package/dist/lib/parse-tool-result.d.ts.map +1 -1
  198. package/dist/lib/parse-tool-result.js +38 -2
  199. package/dist/lib/parse-tool-result.js.map +1 -1
  200. package/dist/lib/toast-model.d.ts +41 -1
  201. package/dist/lib/toast-model.d.ts.map +1 -1
  202. package/dist/lib/toast-model.js +67 -1
  203. package/dist/lib/toast-model.js.map +1 -1
  204. package/dist/lib/tone-utils.d.ts +58 -6
  205. package/dist/lib/tone-utils.d.ts.map +1 -1
  206. package/dist/lib/tone-utils.js +66 -4
  207. package/dist/lib/tone-utils.js.map +1 -1
  208. package/dist/lib/tool-query.d.ts +107 -0
  209. package/dist/lib/tool-query.d.ts.map +1 -0
  210. package/dist/lib/tool-query.js +182 -0
  211. package/dist/lib/tool-query.js.map +1 -0
  212. package/dist/lib/tool-result-observer.d.ts +108 -0
  213. package/dist/lib/tool-result-observer.d.ts.map +1 -0
  214. package/dist/lib/tool-result-observer.js +158 -0
  215. package/dist/lib/tool-result-observer.js.map +1 -0
  216. package/dist/lib/typography.d.ts +37 -0
  217. package/dist/lib/typography.d.ts.map +1 -0
  218. package/dist/lib/typography.js +41 -0
  219. package/dist/lib/typography.js.map +1 -0
  220. package/dist/lib/utils.d.ts.map +1 -1
  221. package/dist/lib/utils.js +11 -1
  222. package/dist/lib/utils.js.map +1 -1
  223. package/dist/locale/index.d.ts +1 -1
  224. package/dist/locale/index.d.ts.map +1 -1
  225. package/dist/locale/message-types.d.ts +117 -4
  226. package/dist/locale/message-types.d.ts.map +1 -1
  227. package/dist/locale/messages-de.d.ts.map +1 -1
  228. package/dist/locale/messages-de.js +44 -10
  229. package/dist/locale/messages-de.js.map +1 -1
  230. package/dist/locale/messages-en.d.ts.map +1 -1
  231. package/dist/locale/messages-en.js +44 -10
  232. package/dist/locale/messages-en.js.map +1 -1
  233. package/dist/locale/toolkit-messages.d.ts +19 -1
  234. package/dist/locale/toolkit-messages.d.ts.map +1 -1
  235. package/dist/locale/toolkit-messages.js +54 -1
  236. package/dist/locale/toolkit-messages.js.map +1 -1
  237. package/dist/primitives/alert.d.ts +1 -1
  238. package/dist/primitives/alert.d.ts.map +1 -1
  239. package/dist/primitives/alert.js +2 -0
  240. package/dist/primitives/alert.js.map +1 -1
  241. package/dist/primitives/badge.d.ts +1 -1
  242. package/dist/primitives/badge.d.ts.map +1 -1
  243. package/dist/primitives/badge.js +9 -4
  244. package/dist/primitives/badge.js.map +1 -1
  245. package/dist/primitives/button.d.ts +1 -1
  246. package/dist/primitives/button.js +1 -1
  247. package/dist/primitives/button.js.map +1 -1
  248. package/dist/primitives/dialog.d.ts +1 -1
  249. package/dist/primitives/dialog.d.ts.map +1 -1
  250. package/dist/primitives/dialog.js +10 -3
  251. package/dist/primitives/dialog.js.map +1 -1
  252. package/dist/primitives/select.js +1 -1
  253. package/dist/primitives/select.js.map +1 -1
  254. package/dist/primitives/sheet.d.ts +1 -1
  255. package/dist/primitives/sheet.d.ts.map +1 -1
  256. package/dist/primitives/sheet.js +6 -2
  257. package/dist/primitives/sheet.js.map +1 -1
  258. package/dist/providers/query-provider.d.ts +32 -1
  259. package/dist/providers/query-provider.d.ts.map +1 -1
  260. package/dist/providers/query-provider.js +53 -4
  261. package/dist/providers/query-provider.js.map +1 -1
  262. package/dist/render-cases-primitives.js +1 -1
  263. package/dist/render-cases-primitives.js.map +1 -1
  264. package/dist/render-cases.d.ts.map +1 -1
  265. package/dist/render-cases.js +30 -6
  266. package/dist/render-cases.js.map +1 -1
  267. package/dist/render-effects.d.ts +42 -0
  268. package/dist/render-effects.d.ts.map +1 -0
  269. package/dist/render-effects.js +81 -0
  270. package/dist/render-effects.js.map +1 -0
  271. package/dist/theme/create-theme.d.ts +19 -1
  272. package/dist/theme/create-theme.d.ts.map +1 -1
  273. package/dist/theme/create-theme.js +15 -0
  274. package/dist/theme/create-theme.js.map +1 -1
  275. package/package.json +5 -4
  276. package/src/app/adapt-data-widget.tsx +2 -42
  277. package/src/app/builder/BuilderBanners.tsx +1 -1
  278. package/src/app/builder/CanvasRow.tsx +63 -17
  279. package/src/app/builder/CatalogueSheet.tsx +50 -29
  280. package/src/app/builder/CellPropsSheet.tsx +17 -2
  281. package/src/app/builder/DiscardDialog.tsx +59 -0
  282. package/src/app/builder/LayoutSurface.tsx +206 -66
  283. package/src/app/builder/PipelineStrip.tsx +253 -153
  284. package/src/app/builder/SaveDialog.tsx +14 -2
  285. package/src/app/builder/Toolbar.tsx +144 -59
  286. package/src/app/builder/Workspace.tsx +226 -58
  287. package/src/app/builder/builder-model.ts +341 -2
  288. package/src/app/builder/builder-model.ux.test.ts +456 -0
  289. package/src/app/builder/builder-ux.test.tsx +844 -0
  290. package/src/app/builder/reveal.ts +10 -0
  291. package/src/app/builder/use-builder-catalogue.ts +56 -19
  292. package/src/app/builder/use-builder-session.ts +68 -0
  293. package/src/app/builder/use-display-resolver.ts +24 -0
  294. package/src/app/index.ts +12 -2
  295. package/src/app/layout-builder.tsx +178 -191
  296. package/src/app/mcp-app-view-chrome.test.tsx +141 -1
  297. package/src/app/mcp-app-view-chrome.tsx +56 -6
  298. package/src/app/mcp-app-view-states.tsx +51 -11
  299. package/src/app/mcp-app-view.effects.test.tsx +292 -0
  300. package/src/app/mcp-app-view.test.tsx +222 -2
  301. package/src/app/mcp-app-view.tsx +267 -117
  302. package/src/app/mcp-toolkit-app.test.tsx +40 -0
  303. package/src/app/mcp-toolkit-app.tsx +8 -1
  304. package/src/app/mcp-use-host-bridge.test.tsx +180 -0
  305. package/src/app/mcp-use-host-bridge.tsx +67 -24
  306. package/src/app/model-context.test.tsx +116 -0
  307. package/src/app/model-context.tsx +125 -0
  308. package/src/app/use-build-mode-focus.ts +62 -0
  309. package/src/app/use-view-actions.ts +89 -0
  310. package/src/app/use-view-lifecycle.ts +6 -0
  311. package/src/app/view-lifecycle.test.ts +216 -0
  312. package/src/app/view-lifecycle.ts +165 -5
  313. package/src/app/widget-fixture.effects.test.tsx +51 -0
  314. package/src/app/widget-fixture.render.test.tsx +81 -0
  315. package/src/app/widget-fixture.tsx +34 -11
  316. package/src/app/widget-props-sheet.tsx +57 -16
  317. package/src/app/widget-renderer.tsx +1 -1
  318. package/src/components/DrillButton.test.tsx +48 -0
  319. package/src/components/DrillButton.tsx +26 -11
  320. package/src/components/EmptyState.tsx +6 -4
  321. package/src/components/ErrorState.tsx +31 -9
  322. package/src/components/FilterBar.test.tsx +82 -0
  323. package/src/components/FilterBar.tsx +52 -26
  324. package/src/components/KpiGrid.test.tsx +279 -0
  325. package/src/components/KpiGrid.tsx +297 -90
  326. package/src/components/ListFooter.test.tsx +116 -0
  327. package/src/components/ListFooter.tsx +102 -15
  328. package/src/components/PagedListFooter.test.tsx +140 -0
  329. package/src/components/PagedListFooter.tsx +107 -0
  330. package/src/components/Pills.test.tsx +77 -0
  331. package/src/components/Pills.tsx +63 -10
  332. package/src/components/SectionHeading.tsx +9 -3
  333. package/src/components/Toast.tsx +37 -19
  334. package/src/components/WidgetHeader.test.tsx +78 -0
  335. package/src/components/WidgetHeader.tsx +63 -16
  336. package/src/components/feedback-states.test.tsx +98 -9
  337. package/src/components/tone-figures.test.tsx +8 -4
  338. package/src/hooks/index.ts +6 -3
  339. package/src/hooks/tool-result-recovery-model.test.ts +744 -0
  340. package/src/hooks/tool-result-recovery-model.ts +418 -0
  341. package/src/hooks/use-tool-query.effects.test.tsx +205 -0
  342. package/src/hooks/use-tool-query.ts +156 -33
  343. package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
  344. package/src/hooks/use-tool-result-recovery.test.ts +3 -4
  345. package/src/hooks/use-tool-result-recovery.ts +84 -142
  346. package/src/hooks/use-view-data.test.tsx +118 -9
  347. package/src/hooks/use-view-data.ts +128 -18
  348. package/src/hooks/use-view-tool-query.ts +25 -19
  349. package/src/i18n-coverage.test.tsx +104 -2
  350. package/src/index.ts +48 -11
  351. package/src/lib/focus-return.test.ts +288 -0
  352. package/src/lib/focus-return.ts +96 -0
  353. package/src/lib/parse-tool-result.test.ts +46 -1
  354. package/src/lib/parse-tool-result.ts +40 -2
  355. package/src/lib/toast-model.test.ts +166 -1
  356. package/src/lib/toast-model.ts +104 -2
  357. package/src/lib/tone-utils.test.ts +86 -10
  358. package/src/lib/tone-utils.ts +89 -8
  359. package/src/lib/tool-query.test.ts +569 -0
  360. package/src/lib/tool-query.ts +253 -0
  361. package/src/lib/tool-result-observer.test.ts +296 -0
  362. package/src/lib/tool-result-observer.ts +211 -0
  363. package/src/lib/typography.test.ts +45 -0
  364. package/src/lib/typography.ts +47 -0
  365. package/src/lib/utils.ts +12 -1
  366. package/src/locale/index.ts +1 -0
  367. package/src/locale/message-types.ts +118 -2
  368. package/src/locale/messages-de.ts +49 -10
  369. package/src/locale/messages-en.ts +49 -10
  370. package/src/locale/toolkit-messages.test.ts +133 -0
  371. package/src/locale/toolkit-messages.ts +63 -2
  372. package/src/primitives/alert.tsx +3 -0
  373. package/src/primitives/badge.tsx +9 -4
  374. package/src/primitives/button.tsx +1 -1
  375. package/src/primitives/dialog.tsx +10 -1
  376. package/src/primitives/select.tsx +1 -1
  377. package/src/primitives/sheet.tsx +7 -0
  378. package/src/providers/query-provider.test.tsx +154 -0
  379. package/src/providers/query-provider.tsx +66 -5
  380. package/src/render-cases-primitives.tsx +1 -1
  381. package/src/render-cases.tsx +38 -6
  382. package/src/render-effects.tsx +96 -0
  383. package/src/theme/cd-tokens.test.ts +3 -1
  384. package/src/theme/create-theme.test.ts +10 -0
  385. package/src/theme/create-theme.ts +28 -0
  386. package/src/theme/theme-css.test.ts +51 -0
  387. package/src/theme.css +31 -1
  388. package/ui-catalog.json +448 -41
@@ -1,17 +1,95 @@
1
1
  import { memo } from "react"
2
- import { Check, Eye, Layers, Library, LucideProvider, Save } from "lucide-react"
2
+ import { Check, Library, LucideProvider, Save, Undo2, Wrench } from "lucide-react"
3
3
  import { DENSE_ICON_STROKE } from "../../lib/icon-stroke.js"
4
+ import { FOCUS_RING } from "../../lib/focus-ring.js"
4
5
  import { Badge } from "../../primitives/badge.js"
5
6
  import { Button } from "../../primitives/button.js"
6
- import { TONE_DOT, TONE_SOFT } from "../../lib/tone-utils.js"
7
+ import { TONE_DOT } from "../../lib/tone-utils.js"
7
8
  import { cn } from "../../lib/utils.js"
8
9
  import type { LayoutBuilderLabels, RefreshStatus } from "./labels.js"
9
10
  import { StatusChip } from "./status-chip.js"
10
11
 
11
12
  // -------------------------------------------------------------------------- //
12
- // Toolbar — sticky top, dense status row + actions
13
+ // Toolbar — sticky top: title + unsaved marker, then the actions
13
14
  // -------------------------------------------------------------------------- //
14
15
 
16
+ export interface ToolbarProps {
17
+ L: Required<LayoutBuilderLabels>
18
+ previewMode: boolean
19
+ isBusy: boolean
20
+ status: RefreshStatus
21
+ liveKeys: number
22
+ reachableCount: number
23
+ unreachableCount: number
24
+ /** Advanced mode: shows the stats and the catalogue (the data sources tab lives below). */
25
+ advanced: boolean
26
+ onToggleAdvanced: () => void
27
+ /** The draft has changes that would be lost (the marker next to the title). */
28
+ unsaved: boolean
29
+ onOpenCatalogue: () => void
30
+ onOpenSave: () => void
31
+ /** Leaves the builder without the edits (or, without `onApply`, resets the draft in place). */
32
+ onDiscard: () => void
33
+ /** Shows the draft in the view and leaves the builder; absent when there is no view to apply to. */
34
+ onApply?: () => void
35
+ hasAnyCell: boolean
36
+ }
37
+
38
+ /** The live-context stats and the refresh state: data-source vocabulary, so advanced mode only. */
39
+ function Stats({
40
+ L,
41
+ status,
42
+ liveKeys,
43
+ reachableCount,
44
+ unreachableCount,
45
+ }: Pick<ToolbarProps, "L" | "status" | "liveKeys" | "reachableCount" | "unreachableCount">) {
46
+ return (
47
+ <div className="text-muted-foreground text-small hidden items-center gap-3 sm:flex">
48
+ <span className="inline-flex items-center gap-1.5">
49
+ <span aria-hidden="true" className={`size-1.5 rounded-full ${TONE_DOT.success}`} />
50
+ <span>
51
+ <span className="text-foreground font-medium">{liveKeys}</span> {L.statsLive}
52
+ </span>
53
+ </span>
54
+ <span className="bg-border h-3 w-px" aria-hidden="true" />
55
+ <span>
56
+ <span className="text-foreground font-medium">{reachableCount}</span> {L.statsReachable}
57
+ </span>
58
+ {unreachableCount > 0 && (
59
+ <>
60
+ <span className="bg-border h-3 w-px" aria-hidden="true" />
61
+ <span>
62
+ <span className="text-foreground font-medium">{unreachableCount}</span>{" "}
63
+ {L.statsUnreachable}
64
+ </span>
65
+ </>
66
+ )}
67
+ <StatusChip status={status} L={L} />
68
+ </div>
69
+ )
70
+ }
71
+
72
+ /**
73
+ * The unsaved marker. The live region is always mounted (only its content
74
+ * changes), so a screen reader hears the marker appear and go.
75
+ */
76
+ function UnsavedMarker({ L, unsaved }: { L: Required<LayoutBuilderLabels>; unsaved: boolean }) {
77
+ return (
78
+ <span
79
+ role="status"
80
+ data-slot="builder-unsaved"
81
+ className="text-muted-foreground text-small inline-flex items-center gap-1.5"
82
+ >
83
+ {unsaved && (
84
+ <>
85
+ <span aria-hidden="true" className={`size-2 rounded-full ${TONE_DOT.warning}`} />
86
+ {L.unsavedChanges}
87
+ </>
88
+ )}
89
+ </span>
90
+ )
91
+ }
92
+
15
93
  function ToolbarImpl({
16
94
  L,
17
95
  previewMode,
@@ -20,74 +98,81 @@ function ToolbarImpl({
20
98
  liveKeys,
21
99
  reachableCount,
22
100
  unreachableCount,
101
+ advanced,
102
+ onToggleAdvanced,
103
+ unsaved,
23
104
  onOpenCatalogue,
24
105
  onOpenSave,
25
- onDone,
106
+ onDiscard,
107
+ onApply,
26
108
  hasAnyCell,
27
- }: {
28
- L: Required<LayoutBuilderLabels>
29
- previewMode: boolean
30
- isBusy: boolean
31
- status: RefreshStatus
32
- liveKeys: number
33
- reachableCount: number
34
- unreachableCount: number
35
- onOpenCatalogue: () => void
36
- onOpenSave: () => void
37
- onDone?: () => void
38
- hasAnyCell: boolean
39
- }) {
109
+ }: ToolbarProps) {
40
110
  return (
41
- <header className="bg-background/80 sticky top-0 z-10 -mx-1 flex flex-wrap items-center gap-3 border-b px-1 py-2 backdrop-blur">
42
- <div className="flex items-center gap-2">
43
- <span
44
- className={cn(
45
- "inline-flex size-6 items-center justify-center rounded-md",
46
- previewMode ? TONE_SOFT.success : TONE_SOFT.info,
47
- )}
48
- aria-hidden="true"
111
+ <header className="bg-background/80 sticky top-0 z-10 -mx-1 flex flex-wrap items-center gap-x-3 gap-y-2 border-b px-1 py-2 backdrop-blur">
112
+ <div className="flex min-w-0 flex-wrap items-center gap-2">
113
+ {/* No tinted icon tile before the title: a mode is no status, and the
114
+ badge next to the title already names it (anti-slop U2, CI §3.3).
115
+ The focus target when build mode opens (McpAppView moves focus here). */}
116
+ <h2
117
+ data-slot="builder-title"
118
+ tabIndex={-1}
119
+ className={cn("rounded-sm text-sm font-semibold tracking-tight", FOCUS_RING)}
49
120
  >
50
- {previewMode ? <Eye className="size-3.5" /> : <Layers className="size-3.5" />}
51
- </span>
52
- <h2 className="text-sm font-semibold tracking-tight">{L.title}</h2>
121
+ {L.title}
122
+ </h2>
53
123
  <Badge variant={previewMode ? "outline" : "secondary"} className="font-normal">
54
124
  {previewMode ? L.previewBadge : L.builderBadge}
55
125
  </Badge>
126
+ <UnsavedMarker L={L} unsaved={unsaved} />
56
127
  </div>
57
128
 
58
- <div className="text-muted-foreground hidden items-center gap-3 text-[11px] sm:flex">
59
- <span className="inline-flex items-center gap-1.5">
60
- <span aria-hidden="true" className={`size-1.5 rounded-full ${TONE_DOT.success}`} />
61
- <span>
62
- <span className="text-foreground font-medium">{liveKeys}</span> {L.statsLive}
63
- </span>
64
- </span>
65
- <span className="bg-border h-3 w-px" aria-hidden="true" />
66
- <span>
67
- <span className="text-foreground font-medium">{reachableCount}</span> {L.statsReachable}
68
- </span>
69
- {unreachableCount > 0 && (
70
- <>
71
- <span className="bg-border h-3 w-px" aria-hidden="true" />
72
- <span>
73
- <span className="text-foreground font-medium">{unreachableCount}</span>{" "}
74
- {L.statsUnreachable}
75
- </span>
76
- </>
77
- )}
78
- <StatusChip status={status} L={L} />
79
- </div>
129
+ {advanced && (
130
+ <Stats
131
+ L={L}
132
+ status={status}
133
+ liveKeys={liveKeys}
134
+ reachableCount={reachableCount}
135
+ unreachableCount={unreachableCount}
136
+ />
137
+ )}
80
138
 
81
- <div className="ml-auto flex items-center gap-1">
82
- <Button variant="ghost" size="sm" onClick={onOpenCatalogue}>
83
- <Library /> {L.catalogue}
139
+ <div className="ml-auto flex flex-wrap items-center gap-1">
140
+ <Button
141
+ variant="ghost"
142
+ size="sm"
143
+ aria-pressed={advanced}
144
+ title={L.advancedHint}
145
+ onClick={onToggleAdvanced}
146
+ className="aria-pressed:bg-accent aria-pressed:text-accent-foreground"
147
+ >
148
+ <Wrench aria-hidden="true" /> {L.advanced}
149
+ </Button>
150
+ {advanced && (
151
+ <Button variant="ghost" size="sm" onClick={onOpenCatalogue}>
152
+ <Library aria-hidden="true" /> {L.catalogue}
153
+ </Button>
154
+ )}
155
+ <Button
156
+ variant="outline"
157
+ size="sm"
158
+ title={L.saveHint}
159
+ onClick={onOpenSave}
160
+ disabled={isBusy || !hasAnyCell}
161
+ >
162
+ <Save aria-hidden="true" /> {L.save}
84
163
  </Button>
85
- <Button size="sm" onClick={onOpenSave} disabled={isBusy || !hasAnyCell}>
86
- <Save /> {L.save}
164
+ <Button
165
+ variant="ghost"
166
+ size="sm"
167
+ // Without Apply there is no view to leave to: Discard resets in place.
168
+ title={onApply ? L.discardHint : L.discardHintStandalone}
169
+ onClick={onDiscard}
170
+ >
171
+ <Undo2 aria-hidden="true" /> {L.discard}
87
172
  </Button>
88
- {onDone && (
89
- <Button variant="outline" size="sm" onClick={onDone}>
90
- <Check /> {L.done}
173
+ {onApply && (
174
+ <Button size="sm" title={L.applyHint} onClick={onApply}>
175
+ <Check aria-hidden="true" /> {L.apply}
91
176
  </Button>
92
177
  )}
93
178
  </div>
@@ -96,7 +181,7 @@ function ToolbarImpl({
96
181
  }
97
182
 
98
183
  /** A dense chrome bar: its Lucide icons draw at stroke 2 (CI §11), not the view's 2.5. */
99
- function DenseToolbar(props: Parameters<typeof ToolbarImpl>[0]) {
184
+ function DenseToolbar(props: ToolbarProps) {
100
185
  return (
101
186
  <LucideProvider strokeWidth={DENSE_ICON_STROKE}>
102
187
  <ToolbarImpl {...props} />
@@ -1,13 +1,17 @@
1
- import { memo } from "react"
2
- import { GripVertical, Plus } from "lucide-react"
3
- import type { ReachableWidget, RowDef, WidgetProps } from "@miragon/mcp-toolkit-core"
1
+ import { memo, useId } from "react"
2
+ import { GripVertical, Plus, SlidersHorizontal } from "lucide-react"
3
+ import type { DisplayText, ReachableWidget, RowDef, WidgetProps } from "@miragon/mcp-toolkit-core"
4
+ import { FOCUS_RING } from "../../lib/focus-ring.js"
5
+ import { cn } from "../../lib/utils.js"
4
6
  import { Badge } from "../../primitives/badge.js"
5
7
  import { Button } from "../../primitives/button.js"
6
- import { ScrollArea } from "../../primitives/scroll-area.js"
8
+ import { Skeleton } from "../../primitives/skeleton.js"
7
9
  import type { WidgetComponent } from "../widget-renderer.js"
10
+ import { displayLabel } from "./builder-model.js"
8
11
  import type { LayoutBuilderLabels } from "./labels.js"
9
12
  import { WIDGET_DRAG_MIME } from "./labels.js"
10
13
  import { CanvasRow } from "./CanvasRow.js"
14
+ import { useDisplayResolver } from "./use-display-resolver.js"
11
15
 
12
16
  // -------------------------------------------------------------------------- //
13
17
  // Workspace — palette + canvas (palette sticky on lg+)
@@ -21,7 +25,13 @@ import { CanvasRow } from "./CanvasRow.js"
21
25
  export interface WorkspaceProps {
22
26
  L: Required<LayoutBuilderLabels>
23
27
  paletteByApp: [string, ReachableWidget[]][]
28
+ /** Each app's title (or its key) by app name: the palette's group headings. */
29
+ appDisplayByName: Map<string, DisplayText>
24
30
  paletteCount: number
31
+ /** The first catalogue answer is still on its way: the palette shows a loading state. */
32
+ paletteLoading: boolean
33
+ /** The empty palette's next step: show the data sources (it turns on advanced mode). */
34
+ onOpenDataSources: () => void
25
35
  activeRows: RowDef[]
26
36
  focusedRowIndex: number
27
37
  setFocusedRowIndex: (idx: number) => void
@@ -35,16 +45,23 @@ export interface WorkspaceProps {
35
45
  onAddWidget: (widgetId: string, targetRowIdx?: number) => void
36
46
  onConfigureCell: (rowIdx: number, cellIdx: number) => void
37
47
  propsSchemaByWidgetId: Map<string, Record<string, unknown>>
48
+ /** Title, summary (or their keys) per widget id: the canvas cells' names. */
49
+ displayByWidgetId: Map<string, DisplayText>
50
+ /** Advanced mode adds the technical lines (a widget's required keys, cell ids). */
51
+ advanced: boolean
38
52
  widgets: Record<string, WidgetComponent>
39
53
  widgetProps: WidgetProps
40
- showAddTabButton?: boolean
54
+ /** Offered next to "Add row" while the draft has no tabs yet. */
41
55
  onAddTab?: () => void
42
56
  }
43
57
 
44
58
  function WorkspaceImpl({
45
59
  L,
46
60
  paletteByApp,
61
+ appDisplayByName,
47
62
  paletteCount,
63
+ paletteLoading,
64
+ onOpenDataSources,
48
65
  activeRows,
49
66
  focusedRowIndex,
50
67
  setFocusedRowIndex,
@@ -58,53 +75,24 @@ function WorkspaceImpl({
58
75
  onAddWidget,
59
76
  onConfigureCell,
60
77
  propsSchemaByWidgetId,
78
+ displayByWidgetId,
79
+ advanced,
61
80
  widgets,
62
81
  widgetProps,
63
- showAddTabButton,
64
82
  onAddTab,
65
83
  }: WorkspaceProps) {
66
84
  return (
67
85
  <div className="grid grid-cols-12 gap-4">
68
- <aside className="col-span-12 lg:col-span-3 xl:col-span-2">
69
- <div className="lg:sticky lg:top-16">
70
- <div className="text-muted-foreground mb-2 flex items-center gap-2 text-[10px] font-semibold tracking-[0.12em] uppercase">
71
- {L.paletteHeader}
72
- <Badge variant="outline" className="px-1.5 text-[10px]">
73
- {paletteCount}
74
- </Badge>
75
- </div>
76
- {paletteCount === 0 ? (
77
- <div className="text-muted-foreground rounded-md border border-dashed p-3 text-xs">
78
- {L.paletteEmpty}
79
- </div>
80
- ) : (
81
- <ScrollArea className="lg:max-h-[70vh]">
82
- <div className="flex flex-col gap-3 pr-1">
83
- {paletteByApp.map(([app, ws]) => (
84
- <div key={app} className="flex flex-col gap-1">
85
- <div className="text-muted-foreground text-[10px] font-semibold tracking-wide uppercase">
86
- {app}
87
- </div>
88
- {ws.map((w) => (
89
- <PaletteItem key={w.id} w={w} onClick={() => onAddWidget(w.id)} />
90
- ))}
91
- </div>
92
- ))}
93
- </div>
94
- </ScrollArea>
95
- )}
96
- {showAddTabButton && onAddTab && (
97
- <Button
98
- variant="ghost"
99
- size="xs"
100
- onClick={onAddTab}
101
- className="text-muted-foreground hover:text-foreground mt-3"
102
- >
103
- <Plus /> {L.addTab}
104
- </Button>
105
- )}
106
- </div>
107
- </aside>
86
+ <Palette
87
+ L={L}
88
+ paletteByApp={paletteByApp}
89
+ appDisplayByName={appDisplayByName}
90
+ paletteCount={paletteCount}
91
+ loading={paletteLoading}
92
+ advanced={advanced}
93
+ onAddWidget={onAddWidget}
94
+ onOpenDataSources={onOpenDataSources}
95
+ />
108
96
 
109
97
  <section className="col-span-12 lg:col-span-9 xl:col-span-10">
110
98
  <div className="flex flex-col gap-3">
@@ -127,13 +115,22 @@ function WorkspaceImpl({
127
115
  onAddWidget={onAddWidget}
128
116
  onConfigureCell={onConfigureCell}
129
117
  propsSchemaByWidgetId={propsSchemaByWidgetId}
118
+ displayByWidgetId={displayByWidgetId}
119
+ advanced={advanced}
130
120
  widgets={widgets}
131
121
  widgetProps={widgetProps}
132
122
  />
133
123
  ))}
134
- <Button variant="outline" size="sm" onClick={onAddRow} className="self-start text-xs">
135
- <Plus /> {L.addRow}
136
- </Button>
124
+ <div className="flex flex-wrap items-center gap-2">
125
+ <Button variant="outline" size="sm" onClick={onAddRow}>
126
+ <Plus aria-hidden="true" /> {L.addRow}
127
+ </Button>
128
+ {onAddTab && (
129
+ <Button variant="ghost" size="sm" onClick={onAddTab}>
130
+ <Plus aria-hidden="true" /> {L.addTab}
131
+ </Button>
132
+ )}
133
+ </div>
137
134
  </div>
138
135
  </section>
139
136
  </div>
@@ -142,31 +139,202 @@ function WorkspaceImpl({
142
139
 
143
140
  export const Workspace = memo(WorkspaceImpl)
144
141
 
142
+ // -------------------------------------------------------------------------- //
143
+ // Palette — the elements to add, grouped by app (sticky on lg+)
144
+ // -------------------------------------------------------------------------- //
145
+
146
+ function Palette({
147
+ L,
148
+ paletteByApp,
149
+ appDisplayByName,
150
+ paletteCount,
151
+ loading,
152
+ advanced,
153
+ onAddWidget,
154
+ onOpenDataSources,
155
+ }: Pick<WorkspaceProps, "L" | "paletteByApp" | "appDisplayByName" | "paletteCount" | "advanced"> & {
156
+ loading: boolean
157
+ onAddWidget: (widgetId: string) => void
158
+ onOpenDataSources: () => void
159
+ }) {
160
+ const headingId = useId()
161
+ return (
162
+ <aside aria-labelledby={headingId} className="col-span-12 lg:col-span-3 xl:col-span-2">
163
+ <div className="lg:sticky lg:top-16">
164
+ <h3
165
+ id={headingId}
166
+ className="text-muted-foreground text-small mb-2 flex items-center gap-2 font-semibold"
167
+ >
168
+ {L.paletteHeader}
169
+ {/* No count while loading: "0" would say there are none. */}
170
+ {!loading && (
171
+ <Badge variant="outline" className="px-1.5">
172
+ {paletteCount}
173
+ </Badge>
174
+ )}
175
+ </h3>
176
+ {loading ? (
177
+ <PaletteLoading L={L} />
178
+ ) : paletteCount === 0 ? (
179
+ <PaletteEmpty L={L} onOpenDataSources={onOpenDataSources} />
180
+ ) : (
181
+ // A native scroll box: its height is its own, so nothing after the
182
+ // palette can be painted over by the list (the old ScrollArea let
183
+ // the list overflow its max height).
184
+ <div className="flex flex-col gap-3 lg:max-h-[70vh] lg:overflow-y-auto lg:pr-1">
185
+ {paletteByApp.map(([app, ws]) => (
186
+ <div key={app} className="flex flex-col gap-1">
187
+ <PaletteGroupHeading
188
+ app={app}
189
+ display={appDisplayByName.get(app)}
190
+ advanced={advanced}
191
+ />
192
+ <ul className="flex flex-col gap-1">
193
+ {ws.map((w) => (
194
+ <li key={w.id}>
195
+ <PaletteItem
196
+ L={L}
197
+ w={w}
198
+ advanced={advanced}
199
+ onClick={() => onAddWidget(w.id)}
200
+ />
201
+ </li>
202
+ ))}
203
+ </ul>
204
+ </div>
205
+ ))}
206
+ </div>
207
+ )}
208
+ </div>
209
+ </aside>
210
+ )
211
+ }
212
+
213
+ /** The palette while the first catalogue answer is on its way (CI §9: a skeleton, not "none"). */
214
+ function PaletteLoading({ L }: { L: Required<LayoutBuilderLabels> }) {
215
+ return (
216
+ <div data-slot="builder-palette-loading" className="flex flex-col gap-1">
217
+ <Skeleton aria-hidden="true" className="h-9 w-full" />
218
+ <Skeleton aria-hidden="true" className="h-9 w-full" />
219
+ <Skeleton aria-hidden="true" className="h-9 w-3/4" />
220
+ <p role="status" className="text-muted-foreground text-small mt-1">
221
+ {L.paletteLoading}
222
+ </p>
223
+ </div>
224
+ )
225
+ }
226
+
227
+ /**
228
+ * The palette without any element. It speaks no data-source words (they sit
229
+ * behind Advanced); its one next step opens the data sources, also when the
230
+ * layout already has cells and the builder's empty state is not shown.
231
+ * Exported for its tests only.
232
+ */
233
+ export function PaletteEmpty({
234
+ L,
235
+ onOpenDataSources,
236
+ }: {
237
+ L: Required<LayoutBuilderLabels>
238
+ onOpenDataSources: () => void
239
+ }) {
240
+ return (
241
+ <div
242
+ data-slot="builder-palette-empty"
243
+ className="text-muted-foreground text-small flex flex-col items-start gap-2 rounded-md border border-dashed p-3"
244
+ >
245
+ <p>{L.paletteEmpty}</p>
246
+ <Button size="sm" variant="outline" onClick={onOpenDataSources}>
247
+ <SlidersHorizontal aria-hidden="true" /> {L.openDataSources}
248
+ </Button>
249
+ </div>
250
+ )
251
+ }
252
+
253
+ // -------------------------------------------------------------------------- //
254
+ // Palette group heading
255
+ // -------------------------------------------------------------------------- //
256
+
257
+ /**
258
+ * The heading of one app's group in the palette: the app's title. Without a
259
+ * title the app's name is a technical namespace, so it heads the group only in
260
+ * advanced mode; there it also follows a title as a quiet mono hint.
261
+ */
262
+ function PaletteGroupHeading({
263
+ app,
264
+ display,
265
+ advanced,
266
+ }: {
267
+ app: string
268
+ display: DisplayText | undefined
269
+ advanced: boolean
270
+ }) {
271
+ const { locale, resolveKey } = useDisplayResolver()
272
+ const { label, hint } = displayLabel(display ?? {}, app, locale, resolveKey)
273
+ if (hint === undefined && !advanced) return null
274
+ return (
275
+ <div
276
+ data-slot="builder-palette-group"
277
+ className="text-muted-foreground text-small font-semibold"
278
+ >
279
+ {label}
280
+ {advanced && hint && <span className="ml-1.5 font-mono font-normal">{hint}</span>}
281
+ </div>
282
+ )
283
+ }
284
+
145
285
  // -------------------------------------------------------------------------- //
146
286
  // Palette item
147
287
  // -------------------------------------------------------------------------- //
148
288
 
149
- function PaletteItemImpl({ w, onClick }: { w: ReachableWidget; onClick: () => void }) {
289
+ /**
290
+ * One widget in the palette: its title and one-line summary, the widget id as
291
+ * a quiet mono line (only next to a real title), and in advanced mode the keys
292
+ * it needs. A click (or Enter) adds it to the target row; dragging drops it
293
+ * on any row.
294
+ */
295
+ function PaletteItemImpl({
296
+ L,
297
+ w,
298
+ advanced,
299
+ onClick,
300
+ }: {
301
+ L: Required<LayoutBuilderLabels>
302
+ w: ReachableWidget
303
+ advanced: boolean
304
+ onClick: () => void
305
+ }) {
306
+ const { locale, resolveKey } = useDisplayResolver()
307
+ const { label, hint, summary } = displayLabel(w, w.id, locale, resolveKey)
308
+ // On the hovered --accent surface quiet text takes the surface's
309
+ // foreground: --muted-foreground drops to 3.66:1 there in dark.
310
+ const quiet = "text-muted-foreground group-hover:text-accent-foreground block w-full truncate"
150
311
  return (
151
312
  <button
152
313
  type="button"
153
314
  draggable
315
+ data-slot="builder-palette-item"
154
316
  onDragStart={(e) => {
155
317
  e.dataTransfer.setData(WIDGET_DRAG_MIME, w.id)
156
318
  e.dataTransfer.effectAllowed = "copy"
157
319
  }}
158
320
  onClick={onClick}
159
- className="hover:bg-accent hover:text-accent-foreground group bg-background/50 flex cursor-grab flex-col items-start gap-0.5 rounded-md border px-2 py-1.5 text-left text-xs transition-colors active:cursor-grabbing"
321
+ className={cn(
322
+ "hover:bg-accent hover:text-accent-foreground group bg-background flex w-full cursor-grab flex-col items-start gap-0.5 rounded-md border px-2 py-1.5 text-left transition-colors active:cursor-grabbing",
323
+ FOCUS_RING,
324
+ )}
160
325
  >
161
326
  <span className="flex w-full items-center justify-between gap-2">
162
- <span className="truncate font-mono">{w.id}</span>
163
- <GripVertical className="text-muted-foreground group-hover:text-accent-foreground size-3" />
327
+ <span className="truncate text-sm font-medium">{label}</span>
328
+ <GripVertical
329
+ aria-hidden="true"
330
+ className="text-muted-foreground group-hover:text-accent-foreground size-3.5 shrink-0"
331
+ />
164
332
  </span>
165
- {w.requires.length > 0 && (
166
- // On the hovered --accent surface quiet text takes the surface's
167
- // foreground: --muted-foreground drops to 3.66:1 there in dark.
168
- <span className="text-muted-foreground group-hover:text-accent-foreground truncate font-mono text-[10px]">
169
- ← {w.requires.join(", ")}
333
+ {summary && <span className={cn(quiet, "text-small")}>{summary}</span>}
334
+ {hint && <span className={cn(quiet, "text-small font-mono")}>{hint}</span>}
335
+ {advanced && w.requires.length > 0 && (
336
+ <span className={cn(quiet, "text-small")}>
337
+ {L.catalogueNeedsKeys} <span className="font-mono">{w.requires.join(", ")}</span>
170
338
  </span>
171
339
  )}
172
340
  </button>