@miragon/mcp-toolkit-ui 2.7.0 → 2.8.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 (387) 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 +9 -6
  122. package/dist/components/DrillButton.d.ts.map +1 -1
  123. package/dist/components/DrillButton.js +8 -6
  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.tsx +23 -10
  319. package/src/components/EmptyState.tsx +6 -4
  320. package/src/components/ErrorState.tsx +31 -9
  321. package/src/components/FilterBar.test.tsx +82 -0
  322. package/src/components/FilterBar.tsx +52 -26
  323. package/src/components/KpiGrid.test.tsx +279 -0
  324. package/src/components/KpiGrid.tsx +297 -90
  325. package/src/components/ListFooter.test.tsx +116 -0
  326. package/src/components/ListFooter.tsx +102 -15
  327. package/src/components/PagedListFooter.test.tsx +140 -0
  328. package/src/components/PagedListFooter.tsx +107 -0
  329. package/src/components/Pills.test.tsx +77 -0
  330. package/src/components/Pills.tsx +63 -10
  331. package/src/components/SectionHeading.tsx +9 -3
  332. package/src/components/Toast.tsx +37 -19
  333. package/src/components/WidgetHeader.test.tsx +78 -0
  334. package/src/components/WidgetHeader.tsx +63 -16
  335. package/src/components/feedback-states.test.tsx +98 -9
  336. package/src/components/tone-figures.test.tsx +8 -4
  337. package/src/hooks/index.ts +6 -3
  338. package/src/hooks/tool-result-recovery-model.test.ts +744 -0
  339. package/src/hooks/tool-result-recovery-model.ts +418 -0
  340. package/src/hooks/use-tool-query.effects.test.tsx +205 -0
  341. package/src/hooks/use-tool-query.ts +156 -33
  342. package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
  343. package/src/hooks/use-tool-result-recovery.test.ts +3 -4
  344. package/src/hooks/use-tool-result-recovery.ts +84 -142
  345. package/src/hooks/use-view-data.test.tsx +118 -9
  346. package/src/hooks/use-view-data.ts +128 -18
  347. package/src/hooks/use-view-tool-query.ts +25 -19
  348. package/src/i18n-coverage.test.tsx +104 -2
  349. package/src/index.ts +48 -11
  350. package/src/lib/focus-return.test.ts +288 -0
  351. package/src/lib/focus-return.ts +96 -0
  352. package/src/lib/parse-tool-result.test.ts +46 -1
  353. package/src/lib/parse-tool-result.ts +40 -2
  354. package/src/lib/toast-model.test.ts +166 -1
  355. package/src/lib/toast-model.ts +104 -2
  356. package/src/lib/tone-utils.test.ts +86 -10
  357. package/src/lib/tone-utils.ts +89 -8
  358. package/src/lib/tool-query.test.ts +569 -0
  359. package/src/lib/tool-query.ts +253 -0
  360. package/src/lib/tool-result-observer.test.ts +296 -0
  361. package/src/lib/tool-result-observer.ts +211 -0
  362. package/src/lib/typography.test.ts +45 -0
  363. package/src/lib/typography.ts +47 -0
  364. package/src/lib/utils.ts +12 -1
  365. package/src/locale/index.ts +1 -0
  366. package/src/locale/message-types.ts +118 -2
  367. package/src/locale/messages-de.ts +49 -10
  368. package/src/locale/messages-en.ts +49 -10
  369. package/src/locale/toolkit-messages.test.ts +133 -0
  370. package/src/locale/toolkit-messages.ts +63 -2
  371. package/src/primitives/alert.tsx +3 -0
  372. package/src/primitives/badge.tsx +9 -4
  373. package/src/primitives/button.tsx +1 -1
  374. package/src/primitives/dialog.tsx +10 -1
  375. package/src/primitives/select.tsx +1 -1
  376. package/src/primitives/sheet.tsx +7 -0
  377. package/src/providers/query-provider.test.tsx +154 -0
  378. package/src/providers/query-provider.tsx +66 -5
  379. package/src/render-cases-primitives.tsx +1 -1
  380. package/src/render-cases.tsx +38 -6
  381. package/src/render-effects.tsx +96 -0
  382. package/src/theme/cd-tokens.test.ts +3 -1
  383. package/src/theme/create-theme.test.ts +10 -0
  384. package/src/theme/create-theme.ts +28 -0
  385. package/src/theme/theme-css.test.ts +51 -0
  386. package/src/theme.css +31 -1
  387. package/ui-catalog.json +448 -41
@@ -1,5 +1,6 @@
1
- import { createContext, useContext, type ReactNode } from "react"
1
+ import { createContext, useContext, useMemo, type ReactNode } from "react"
2
2
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
3
+ import { useHostBridgeOrNull } from "../app/host-bridge.js"
3
4
 
4
5
  // `object` (not `Record<string, unknown>`) because generated tool input
5
6
  // interfaces lack an implicit index signature and TS rejects the assignment
@@ -8,6 +9,9 @@ type CallToolFn = (name: string, args: object) => Promise<unknown>
8
9
 
9
10
  const CallToolContext = createContext<CallToolFn | undefined>(undefined)
10
11
 
12
+ /** Whether the data hooks put the tool name into their cache keys (`toolQueryKey`). */
13
+ const ToolNameInQueryKeyContext = createContext(false)
14
+
11
15
  const queryClient = new QueryClient({
12
16
  defaultOptions: {
13
17
  queries: {
@@ -17,22 +21,79 @@ const queryClient = new QueryClient({
17
21
  },
18
22
  })
19
23
 
24
+ /** The client of the nearest `AppQueryProvider`, which a nested one without `client` keeps. */
25
+ const AppQueryClientContext = createContext<QueryClient>(queryClient)
26
+
27
+ /**
28
+ * The query client and tool transport of the toolkit's data hooks.
29
+ *
30
+ * `callTool` is how `useToolQuery` & co. reach the server; without it they
31
+ * fall back to the nearest `HostBridgeProvider`'s bridge (toolkit#176 N25).
32
+ * `client` replaces the shared module-level client, e.g. one per mount;
33
+ * omitted, a nested provider keeps its parent's client (as `McpAppView`'s
34
+ * own provider does), and the outermost one shares the toolkit's client
35
+ * (`queryClient`). `toolNameInQueryKey` puts the tool name into the hooks'
36
+ * cache keys (`[...queryKey, toolName, args]`, see `toolQueryKey`), so two
37
+ * tools never share an entry; omitted, a nested provider keeps its parent's
38
+ * setting, and the outermost one uses the 2.x key `[...queryKey, args]`. The
39
+ * next major makes the tool name the default.
40
+ */
20
41
  export function AppQueryProvider({
21
42
  children,
22
43
  callTool,
44
+ client,
45
+ toolNameInQueryKey,
23
46
  }: {
24
47
  children: ReactNode
25
48
  callTool?: CallToolFn
49
+ client?: QueryClient
50
+ toolNameInQueryKey?: boolean
26
51
  }) {
52
+ const inheritedClient = useAppQueryClient()
53
+ const inherited = useContext(ToolNameInQueryKeyContext)
54
+ const effective = client ?? inheritedClient
27
55
  return (
28
- <QueryClientProvider client={queryClient}>
29
- <CallToolContext.Provider value={callTool}>{children}</CallToolContext.Provider>
30
- </QueryClientProvider>
56
+ <AppQueryClientContext.Provider value={effective}>
57
+ <QueryClientProvider client={effective}>
58
+ <CallToolContext.Provider value={callTool}>
59
+ <ToolNameInQueryKeyContext.Provider value={toolNameInQueryKey ?? inherited}>
60
+ {children}
61
+ </ToolNameInQueryKeyContext.Provider>
62
+ </CallToolContext.Provider>
63
+ </QueryClientProvider>
64
+ </AppQueryClientContext.Provider>
31
65
  )
32
66
  }
33
67
 
68
+ /**
69
+ * The client an `AppQueryProvider` without `client` uses at this point: the
70
+ * nearest `AppQueryProvider`'s, else the toolkit's shared `queryClient`. A
71
+ * plain TanStack `QueryClientProvider` does not count.
72
+ */
73
+ export function useAppQueryClient(): QueryClient {
74
+ return useContext(AppQueryClientContext)
75
+ }
76
+
77
+ /**
78
+ * Whether the nearest `AppQueryProvider` puts the tool name into the data
79
+ * hooks' cache keys (`toolNameInQueryKey`); `false` outside one.
80
+ */
81
+ export function useToolNameInQueryKey(): boolean {
82
+ return useContext(ToolNameInQueryKeyContext)
83
+ }
84
+
85
+ /**
86
+ * The tool transport of the data hooks: `AppQueryProvider`'s `callTool`,
87
+ * else the nearest `HostBridgeProvider`'s `callTool`, else `undefined`.
88
+ */
34
89
  export function useCallTool(): CallToolFn | undefined {
35
- return useContext(CallToolContext)
90
+ const explicit = useContext(CallToolContext)
91
+ const bridge = useHostBridgeOrNull()
92
+ return useMemo<CallToolFn | undefined>(() => {
93
+ if (explicit) return explicit
94
+ if (!bridge) return undefined
95
+ return (name, args) => bridge.callTool(name, args as Record<string, unknown>)
96
+ }, [explicit, bridge])
36
97
  }
37
98
 
38
99
  export { queryClient }
@@ -226,7 +226,7 @@ export const PRIMITIVE_RENDER_CASES: RenderCase[] = [
226
226
  name: "Alert",
227
227
  marker: "RC:Alert",
228
228
  render: () => (
229
- <Alert variant="destructive">
229
+ <Alert variant="danger">
230
230
  <AlertTitle>RC:Alert</AlertTitle>
231
231
  <AlertDescription>The engine rejected the job.</AlertDescription>
232
232
  </Alert>
@@ -1,5 +1,5 @@
1
1
  import type { ReactElement } from "react"
2
- import { Inbox } from "lucide-react"
2
+ import { ExternalLink, Inbox } from "lucide-react"
3
3
  import {
4
4
  Button,
5
5
  CountPill,
@@ -11,10 +11,13 @@ import {
11
11
  GridLayout,
12
12
  GroupCard,
13
13
  KpiGrid,
14
+ KpiGridSkeleton,
14
15
  ListFooter,
15
16
  LivePill,
16
17
  LocaleProvider,
18
+ PagedListFooter,
17
19
  SectionHeading,
20
+ StatusBadge,
18
21
  ThemeProvider,
19
22
  themePresets,
20
23
  ToastProvider,
@@ -22,7 +25,7 @@ import {
22
25
  WidgetHeader,
23
26
  } from "./index.js"
24
27
  import { createStandaloneHostBridge, HostBridgeProvider, useHostBridge } from "./app/host-bridge.js"
25
- import { HostModelContext } from "./app/adapt-data-widget.js"
28
+ import { HostModelContext } from "./app/model-context.js"
26
29
  import { WidgetFixtureHost, type FixtureWidget } from "./app/widget-fixture.js"
27
30
  import { PRIMITIVE_RENDER_CASES, type RenderCase } from "./render-cases-primitives.js"
28
31
 
@@ -111,11 +114,17 @@ export const RENDER_CASES: RenderCase[] = [
111
114
  trendDirection: "up",
112
115
  },
113
116
  { label: "Done", value: 12, fraction: "/19", tone: "success" },
114
- { label: "Total", value: 19, onClick: noop, ariaLabel: "Show all" },
117
+ { label: "Total", value: 19, onClick: noop, actionHint: "Shows all orders" },
115
118
  ]}
116
119
  />
117
120
  ),
118
121
  },
122
+ {
123
+ // A skeleton has no text; the marker is its busy state.
124
+ name: "KpiGridSkeleton",
125
+ marker: 'aria-busy="true"',
126
+ render: () => <KpiGridSkeleton cells={4} boxed />,
127
+ },
119
128
  {
120
129
  name: "LivePill",
121
130
  marker: "RC:LivePill",
@@ -126,6 +135,11 @@ export const RENDER_CASES: RenderCase[] = [
126
135
  marker: "RC:CountPill",
127
136
  render: () => <CountPill tone="warning">RC:CountPill</CountPill>,
128
137
  },
138
+ {
139
+ name: "StatusBadge",
140
+ marker: "RC:StatusBadge",
141
+ render: () => <StatusBadge tone="warning">RC:StatusBadge</StatusBadge>,
142
+ },
129
143
  {
130
144
  name: "SectionHeading",
131
145
  marker: "RC:SectionHeading",
@@ -136,9 +150,9 @@ export const RENDER_CASES: RenderCase[] = [
136
150
  marker: "RC:WidgetHeader",
137
151
  render: () => (
138
152
  <WidgetHeader
139
- icon="✓"
140
- iconTone="info"
153
+ as="h2"
141
154
  title="RC:WidgetHeader"
155
+ badge={<StatusBadge tone="info">Running</StatusBadge>}
142
156
  sub={<LivePill>Live</LivePill>}
143
157
  actions={
144
158
  <Button size="sm" variant="ghost" onClick={noop}>
@@ -178,7 +192,7 @@ export const RENDER_CASES: RenderCase[] = [
178
192
  name: "DrillButton",
179
193
  marker: "RC:DrillButton",
180
194
  render: () => (
181
- <DrillButton onDrill={noop} icon="↗" size="sm" ariaLabel="Open order o-1001">
195
+ <DrillButton onDrill={noop} icon={<ExternalLink />} size="sm" ariaLabel="Open order o-1001">
182
196
  RC:DrillButton
183
197
  </DrillButton>
184
198
  ),
@@ -188,6 +202,24 @@ export const RENDER_CASES: RenderCase[] = [
188
202
  marker: "of 42 tasks",
189
203
  render: () => <ListFooter shown={8} total={42} hasMore onLoadMore={noop} noun="tasks" />,
190
204
  },
205
+ {
206
+ name: "PagedListFooter",
207
+ marker: "of 3 orders",
208
+ render: () => (
209
+ <PagedListFooter
210
+ paged={{
211
+ items: ["o-1", "o-2"],
212
+ total: 3,
213
+ hasMore: true,
214
+ loadMore: noop,
215
+ refreshing: true,
216
+ firstPage: {},
217
+ loadMoreError: new Error("HTTP 503"),
218
+ }}
219
+ noun="orders"
220
+ />
221
+ ),
222
+ },
191
223
 
192
224
  // ── Feedback and states ──
193
225
  {
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Effect-running renders for the WIRING tests SSR cannot see: effects,
3
+ * subscriptions and timers of the view lifecycle and the data hooks
4
+ * (toolkit#176 review). `react-dom/client` + `act` in a test file that opts
5
+ * into a DOM with `// @vitest-environment happy-dom`. Not an interaction kit:
6
+ * the house render path stays SSR (`renderToStaticMarkup`), and these tests
7
+ * drive hooks through their inputs; a `click()` only where the wiring starts
8
+ * at a button.
9
+ */
10
+ import { act, useEffect, type ReactNode } from "react"
11
+ import { createRoot } from "react-dom/client"
12
+
13
+ // React warns about updates outside act() unless the runtime says it is a test.
14
+ ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true
15
+
16
+ /**
17
+ * Run `work` in an ASYNC act scope: the promises it starts (a tool call that
18
+ * resolves, a state update after it) settle, and their renders commit,
19
+ * before the scope ends.
20
+ */
21
+ export function inAct(work: () => unknown): Promise<void> {
22
+ return act(() => {
23
+ work()
24
+ return Promise.resolve()
25
+ })
26
+ }
27
+
28
+ export interface EffectRender {
29
+ container: HTMLElement
30
+ /** Render `node` into the same root (a new host state, new props). */
31
+ rerender: (node: ReactNode) => Promise<void>
32
+ /** Unmount and run the cleanups; a second call does nothing. */
33
+ unmount: () => Promise<void>
34
+ }
35
+
36
+ /** Mount `node` and run its effects. */
37
+ export async function renderWithEffects(node: ReactNode): Promise<EffectRender> {
38
+ const container = document.createElement("div")
39
+ document.body.append(container)
40
+ const root = createRoot(container)
41
+ await inAct(() => root.render(node))
42
+ let mounted = true
43
+ return {
44
+ container,
45
+ rerender: (next) => inAct(() => root.render(next)),
46
+ unmount: async () => {
47
+ if (!mounted) return
48
+ mounted = false
49
+ await inAct(() => root.unmount())
50
+ container.remove()
51
+ },
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Settle pending promises and the effects and renders they cause, with real
57
+ * timers: TanStack Query notifies its observers on a 0 ms timer, so each
58
+ * round lets one land (under fake timers use {@link advanceTimers}).
59
+ */
60
+ export async function flushEffects(rounds = 3): Promise<void> {
61
+ for (let round = 0; round < rounds; round++) {
62
+ await act(async () => {
63
+ await new Promise((resolve) => setTimeout(resolve, 0))
64
+ })
65
+ }
66
+ }
67
+
68
+ /** Advance fake timers by `ms` inside act, so the renders they cause commit. */
69
+ export function advanceTimers(advance: (ms: number) => unknown, ms: number): Promise<void> {
70
+ return inAct(() => advance(ms))
71
+ }
72
+
73
+ /**
74
+ * Renders `useValue` in a probe and keeps its latest committed value: read
75
+ * `current` after a render or flush.
76
+ */
77
+ export function hookProbe<T>(useValue: () => T): {
78
+ Probe: () => null
79
+ current: () => T
80
+ } {
81
+ const box: { value?: { current: T } } = {}
82
+ function Probe(): null {
83
+ const value = useValue()
84
+ useEffect(() => {
85
+ box.value = { current: value }
86
+ })
87
+ return null
88
+ }
89
+ return {
90
+ Probe,
91
+ current: () => {
92
+ if (!box.value) throw new Error("the probe has not committed yet")
93
+ return box.value.current
94
+ },
95
+ }
96
+ }
@@ -17,7 +17,9 @@ import { CD_TOKENS, CD_TOKENS_VERSION } from "./cd-tokens.js"
17
17
  * compared to it directly; everywhere else (CI) the pinned hash below holds it.
18
18
  *
19
19
  * To re-vendor: copy the new upstream file below the marker line, update the
20
- * version in the marker, CD_TOKENS_VERSION, UPSTREAM_SHA256 and CD_TOKENS.
20
+ * version in the marker, CD_TOKENS_VERSION, UPSTREAM_SHA256 and CD_TOKENS,
21
+ * then copy the result to docs/.vitepress/theme/ (the docs site vendors the
22
+ * same file; examples/test/docs-theme.test.ts holds the two byte-identical).
21
23
  */
22
24
  const UPSTREAM_SHA256 = "36d76f3a330a1250d332c6862be1dc4f7564d2461e7051d9a565ba723ef2c379"
23
25
  const UPSTREAM_REL = join("skills", "modeler-tool-design", "assets", "cd-tokens.generated.css")
@@ -63,6 +63,11 @@ describe("tokensToVars (token → CSS-var mapping)", () => {
63
63
  fontSans: "Inter, sans-serif",
64
64
  fontMono: "JetBrains Mono, monospace",
65
65
  fontHeading: "Sora, sans-serif",
66
+ textTitle: "2rem",
67
+ textSection: "1.5rem",
68
+ textBody: "1.0625rem",
69
+ textDense: "0.9375rem",
70
+ textSmall: "0.875rem",
66
71
  }
67
72
  expect(tokensToVars(full)).toEqual({
68
73
  "--primary": "oklch(0.55 0.2 264)",
@@ -113,6 +118,11 @@ describe("tokensToVars (token → CSS-var mapping)", () => {
113
118
  "--font-sans": "Inter, sans-serif",
114
119
  "--font-mono": "JetBrains Mono, monospace",
115
120
  "--font-heading": "Sora, sans-serif",
121
+ "--text-title": "2rem",
122
+ "--text-section": "1.5rem",
123
+ "--text-body": "1.0625rem",
124
+ "--text-dense": "0.9375rem",
125
+ "--text-small": "0.875rem",
116
126
  })
117
127
  })
118
128
 
@@ -134,6 +134,19 @@ export interface ThemeTokens {
134
134
  fontMono?: string
135
135
  /** Heading font-family list. Maps to `--font-heading`. */
136
136
  fontHeading?: string
137
+ /** Page title size (CI h2, 28 px). Maps to `--text-title` (`text-title`). */
138
+ textTitle?: string
139
+ /** Section title size (CI h3, 21 px). Maps to `--text-section` (`text-section`). */
140
+ textSection?: string
141
+ /** Running text size (16 px). Maps to `--text-body` (`text-body`). */
142
+ textBody?: string
143
+ /** Dense tables and controls (14 px), never running text. Maps to `--text-dense` (`text-dense`). */
144
+ textDense?: string
145
+ /**
146
+ * Captions, labels and hints: the smallest text the kit renders (13 px;
147
+ * keep it at 13 px or more). Maps to `--text-small` (`text-small`).
148
+ */
149
+ textSmall?: string
137
150
  }
138
151
 
139
152
  /** The CSS custom-property name a {@link ThemeTokens} field resolves to. */
@@ -194,6 +207,11 @@ export const TOKEN_TO_CSS_VAR = {
194
207
  fontSans: "--font-sans",
195
208
  fontMono: "--font-mono",
196
209
  fontHeading: "--font-heading",
210
+ textTitle: "--text-title",
211
+ textSection: "--text-section",
212
+ textBody: "--text-body",
213
+ textDense: "--text-dense",
214
+ textSmall: "--text-small",
197
215
  } as const satisfies Record<keyof ThemeTokens, CssVarName>
198
216
 
199
217
  /**
@@ -245,6 +263,11 @@ export const ROLE_TOKENS = [
245
263
  "--ease",
246
264
  "--font-sans",
247
265
  "--font-mono",
266
+ "--text-title",
267
+ "--text-section",
268
+ "--text-body",
269
+ "--text-dense",
270
+ "--text-small",
248
271
  ] as const satisfies readonly CssVarName[]
249
272
 
250
273
  /**
@@ -279,6 +302,11 @@ export const MODE_INVARIANT_VARS: ReadonlySet<CssVarName> = new Set<CssVarName>(
279
302
  "--font-sans",
280
303
  "--font-mono",
281
304
  "--font-heading",
305
+ "--text-title",
306
+ "--text-section",
307
+ "--text-body",
308
+ "--text-dense",
309
+ "--text-small",
282
310
  ])
283
311
 
284
312
  /** A serializable map of CSS custom properties (`--primary` → value). */
@@ -8,6 +8,7 @@ import {
8
8
  resolveThemeVars,
9
9
  type ThemeVars,
10
10
  } from "./create-theme.js"
11
+ import { TYPE_FLOOR_PX, TYPE_STEPS } from "../lib/typography.js"
11
12
  import { HOST_FONT_VARIABLES } from "./host-fonts.js"
12
13
  import { themePresets } from "./presets.js"
13
14
 
@@ -242,6 +243,56 @@ describe("theme.css — the role-token contract", () => {
242
243
  for (const value of Object.values(THEME_REFERENCE)) expect(value).not.toContain("calc(")
243
244
  })
244
245
 
246
+ it("defines the type scale per CI §4 (page title h2, section h3, body, dense, small) with a 13 px floor", () => {
247
+ const px = (rem: string | undefined) => Number(/^([\d.]+)rem$/.exec(rem ?? "")?.[1]) * 16
248
+ const scale = Object.fromEntries(
249
+ TYPE_STEPS.map((step) => [
250
+ step,
251
+ {
252
+ px: px(ROOT[`--text-${step}`]),
253
+ lineHeight: ROOT[`--text-${step}--line-height`],
254
+ weight: ROOT[`--text-${step}--font-weight`],
255
+ },
256
+ ]),
257
+ )
258
+ expect(scale).toEqual({
259
+ title: { px: 28, lineHeight: "1.2", weight: "700" },
260
+ section: { px: 21, lineHeight: "1.3", weight: "600" },
261
+ body: { px: 16, lineHeight: "1.6", weight: undefined },
262
+ dense: { px: 14, lineHeight: "1.5", weight: undefined },
263
+ small: { px: 13, lineHeight: "1.5", weight: undefined },
264
+ })
265
+ for (const { px: size } of Object.values(scale)) {
266
+ expect(size).toBeGreaterThanOrEqual(TYPE_FLOOR_PX)
267
+ }
268
+ // Mode-independent roles of the contract, themeable like the radii.
269
+ for (const step of TYPE_STEPS) {
270
+ expect(ROLE_TOKENS).toContain(`--text-${step}`)
271
+ expect(MODE_INVARIANT_VARS.has(`--text-${step}`)).toBe(true)
272
+ expect(LIGHT, step).not.toHaveProperty(`--text-${step}`)
273
+ expect(DARK, step).not.toHaveProperty(`--text-${step}`)
274
+ }
275
+ })
276
+
277
+ it("maps the type-scale utilities (text-title … text-small) onto the roles, size, leading and weight", () => {
278
+ for (const step of TYPE_STEPS) {
279
+ expect(THEME_REFERENCE[`--text-${step}`], step).toBe(`var(--text-${step})`)
280
+ expect(THEME_REFERENCE[`--text-${step}--line-height`], step).toBe(
281
+ `var(--text-${step}--line-height)`,
282
+ )
283
+ }
284
+ for (const step of ["title", "section"]) {
285
+ expect(THEME_REFERENCE[`--text-${step}--font-weight`], step).toBe(
286
+ `var(--text-${step}--font-weight)`,
287
+ )
288
+ }
289
+ // Tailwind's own steps stay untouched (text-xs is still 12 px): the floor
290
+ // is a gate on the kit's sources, not a redefinition of a consumer's scale.
291
+ for (const name of Object.keys({ ...THEME_INLINE, ...THEME_REFERENCE })) {
292
+ expect(name).not.toMatch(/^--text-(?:xs|sm|base|lg|\d?xl)\b/)
293
+ }
294
+ })
295
+
245
296
  it("exposes the new colour roles as utilities (bg-scrim, text-link, ring-focus, text-*-ink, …)", () => {
246
297
  for (const name of [
247
298
  "link",
package/src/theme.css CHANGED
@@ -105,8 +105,22 @@
105
105
  /* Utilities whose role carries the utility's own name (`rounded-md` →
106
106
  `var(--radius-md)`, `shadow-2` → `var(--shadow-2)`, `font-mono` →
107
107
  `var(--font-mono)`). `reference` keeps Tailwind from emitting the
108
- self-referencing theme variable; the roles below define the values. */
108
+ self-referencing theme variable; the roles below define the values.
109
+ The type scale works the same way: `text-small` sets the font size, line
110
+ height and weight of the `--text-small` role. */
109
111
  @theme inline reference {
112
+ --text-title: var(--text-title);
113
+ --text-title--line-height: var(--text-title--line-height);
114
+ --text-title--font-weight: var(--text-title--font-weight);
115
+ --text-section: var(--text-section);
116
+ --text-section--line-height: var(--text-section--line-height);
117
+ --text-section--font-weight: var(--text-section--font-weight);
118
+ --text-body: var(--text-body);
119
+ --text-body--line-height: var(--text-body--line-height);
120
+ --text-dense: var(--text-dense);
121
+ --text-dense--line-height: var(--text-dense--line-height);
122
+ --text-small: var(--text-small);
123
+ --text-small--line-height: var(--text-small--line-height);
110
124
  --radius-sm: var(--radius-sm);
111
125
  --radius-md: var(--radius-md);
112
126
  --radius-lg: var(--radius-lg);
@@ -132,6 +146,22 @@
132
146
  --motion-base: var(--cd-motion-base);
133
147
  --motion-slow: var(--cd-motion-slow);
134
148
  --ease: var(--cd-ease);
149
+ /* Type scale (modeler-tool-design §4, adapted for embedded widgets: the
150
+ page title is the CI h2, dense tables keep 14 px as the documented
151
+ product exception). 13 px is the floor: nothing renders smaller. In rem,
152
+ so a reader's font-size setting scales it. */
153
+ --text-title: 1.75rem; /* 28px */
154
+ --text-title--line-height: 1.2;
155
+ --text-title--font-weight: 700;
156
+ --text-section: 1.3125rem; /* 21px */
157
+ --text-section--line-height: 1.3;
158
+ --text-section--font-weight: 600;
159
+ --text-body: 1rem; /* 16px */
160
+ --text-body--line-height: 1.6;
161
+ --text-dense: 0.875rem; /* 14px */
162
+ --text-dense--line-height: 1.5;
163
+ --text-small: 0.8125rem; /* 13px */
164
+ --text-small--line-height: 1.5;
135
165
  /* Geist first, then the host's font, then the system stack. Loading Geist
136
166
  is opt-in (fonts.css or fontFaces()); where it is not loaded the next
137
167
  family renders. A SEP-1865 host sends its font as --font-sans and