react-cheminfo 0.64.1 → 0.65.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 (604) hide show
  1. package/README.md +282 -0
  2. package/lib/card/core/cardAddress.d.ts +70 -0
  3. package/lib/card/core/cardAddress.d.ts.map +1 -0
  4. package/lib/card/core/cardAddress.js +59 -0
  5. package/lib/card/core/cardAddress.js.map +1 -0
  6. package/lib/card/core/cardPageUrl.d.ts +49 -0
  7. package/lib/card/core/cardPageUrl.d.ts.map +1 -0
  8. package/lib/card/core/cardPageUrl.js +59 -0
  9. package/lib/card/core/cardPageUrl.js.map +1 -0
  10. package/lib/card/core/index.d.ts +7 -0
  11. package/lib/card/core/index.d.ts.map +1 -0
  12. package/lib/card/core/index.js +4 -0
  13. package/lib/card/core/index.js.map +1 -0
  14. package/lib/card/core/panelRoom.d.ts +40 -0
  15. package/lib/card/core/panelRoom.d.ts.map +1 -0
  16. package/lib/card/core/panelRoom.js +40 -0
  17. package/lib/card/core/panelRoom.js.map +1 -0
  18. package/lib/card/ui/CardDetailsButton.d.ts +38 -0
  19. package/lib/card/ui/CardDetailsButton.d.ts.map +1 -0
  20. package/lib/card/ui/CardDetailsButton.js +50 -0
  21. package/lib/card/ui/CardDetailsButton.js.map +1 -0
  22. package/lib/card/ui/CardFigure.d.ts +51 -0
  23. package/lib/card/ui/CardFigure.d.ts.map +1 -0
  24. package/lib/card/ui/CardFigure.js +27 -0
  25. package/lib/card/ui/CardFigure.js.map +1 -0
  26. package/lib/card/ui/CardFrame.d.ts +30 -0
  27. package/lib/card/ui/CardFrame.d.ts.map +1 -0
  28. package/lib/card/ui/CardFrame.js +20 -0
  29. package/lib/card/ui/CardFrame.js.map +1 -0
  30. package/lib/card/ui/CopyTableButton.d.ts +37 -0
  31. package/lib/card/ui/CopyTableButton.d.ts.map +1 -0
  32. package/lib/card/ui/CopyTableButton.js +19 -0
  33. package/lib/card/ui/CopyTableButton.js.map +1 -0
  34. package/lib/card/ui/cardTooltip.d.ts +14 -0
  35. package/lib/card/ui/cardTooltip.d.ts.map +1 -0
  36. package/lib/card/ui/cardTooltip.js +15 -0
  37. package/lib/card/ui/cardTooltip.js.map +1 -0
  38. package/lib/card/ui/embed.d.ts +15 -0
  39. package/lib/card/ui/embed.d.ts.map +1 -0
  40. package/lib/card/ui/embed.js +24 -0
  41. package/lib/card/ui/embed.js.map +1 -0
  42. package/lib/card/ui/fitCardToFrame.d.ts +31 -0
  43. package/lib/card/ui/fitCardToFrame.d.ts.map +1 -0
  44. package/lib/card/ui/fitCardToFrame.js +66 -0
  45. package/lib/card/ui/fitCardToFrame.js.map +1 -0
  46. package/lib/card/ui/holdRoomForPanels.d.ts +16 -0
  47. package/lib/card/ui/holdRoomForPanels.d.ts.map +1 -0
  48. package/lib/card/ui/holdRoomForPanels.js +76 -0
  49. package/lib/card/ui/holdRoomForPanels.js.map +1 -0
  50. package/lib/card/ui/index.d.ts +11 -0
  51. package/lib/card/ui/index.d.ts.map +1 -0
  52. package/lib/card/ui/index.js +7 -0
  53. package/lib/card/ui/index.js.map +1 -0
  54. package/lib/card/ui/openPanels.d.ts +25 -0
  55. package/lib/card/ui/openPanels.d.ts.map +1 -0
  56. package/lib/card/ui/openPanels.js +85 -0
  57. package/lib/card/ui/openPanels.js.map +1 -0
  58. package/lib/card.d.ts +13 -0
  59. package/lib/card.d.ts.map +1 -0
  60. package/lib/card.js +13 -0
  61. package/lib/card.js.map +1 -0
  62. package/lib/conformers.d.ts +1 -0
  63. package/lib/conformers.d.ts.map +1 -1
  64. package/lib/conformers.js +1 -0
  65. package/lib/conformers.js.map +1 -1
  66. package/lib/core.d.ts +4 -0
  67. package/lib/core.d.ts.map +1 -1
  68. package/lib/core.js +5 -0
  69. package/lib/core.js.map +1 -1
  70. package/lib/fetch/core/apiError.d.ts +56 -0
  71. package/lib/fetch/core/apiError.d.ts.map +1 -0
  72. package/lib/fetch/core/apiError.js +43 -0
  73. package/lib/fetch/core/apiError.js.map +1 -0
  74. package/lib/fetch/core/fetchJson.d.ts +47 -0
  75. package/lib/fetch/core/fetchJson.d.ts.map +1 -0
  76. package/lib/fetch/core/fetchJson.js +109 -0
  77. package/lib/fetch/core/fetchJson.js.map +1 -0
  78. package/lib/fetch/core/index.d.ts +5 -0
  79. package/lib/fetch/core/index.d.ts.map +1 -0
  80. package/lib/fetch/core/index.js +3 -0
  81. package/lib/fetch/core/index.js.map +1 -0
  82. package/lib/formula/core/formulaText.d.ts +46 -0
  83. package/lib/formula/core/formulaText.d.ts.map +1 -0
  84. package/lib/formula/core/formulaText.js +74 -0
  85. package/lib/formula/core/formulaText.js.map +1 -0
  86. package/lib/formula/core/index.d.ts +6 -0
  87. package/lib/formula/core/index.d.ts.map +1 -0
  88. package/lib/formula/core/index.js +4 -0
  89. package/lib/formula/core/index.js.map +1 -0
  90. package/lib/formula/core/normalizeFormula.d.ts +22 -0
  91. package/lib/formula/core/normalizeFormula.d.ts.map +1 -0
  92. package/lib/formula/core/normalizeFormula.js +46 -0
  93. package/lib/formula/core/normalizeFormula.js.map +1 -0
  94. package/lib/formula/core/readFormula.d.ts +73 -0
  95. package/lib/formula/core/readFormula.d.ts.map +1 -0
  96. package/lib/formula/core/readFormula.js +132 -0
  97. package/lib/formula/core/readFormula.js.map +1 -0
  98. package/lib/formula/ui/CopyableFormula.d.ts +31 -0
  99. package/lib/formula/ui/CopyableFormula.d.ts.map +1 -0
  100. package/lib/formula/ui/CopyableFormula.js +19 -0
  101. package/lib/formula/ui/CopyableFormula.js.map +1 -0
  102. package/lib/formula/ui/FormulaInput.d.ts +29 -0
  103. package/lib/formula/ui/FormulaInput.d.ts.map +1 -0
  104. package/lib/formula/ui/FormulaInput.js +16 -0
  105. package/lib/formula/ui/FormulaInput.js.map +1 -0
  106. package/lib/formula/ui/QuestionFormula.d.ts +14 -0
  107. package/lib/formula/ui/QuestionFormula.d.ts.map +1 -0
  108. package/lib/formula/ui/QuestionFormula.js +13 -0
  109. package/lib/formula/ui/QuestionFormula.js.map +1 -0
  110. package/lib/formula/ui/index.d.ts +7 -0
  111. package/lib/formula/ui/index.d.ts.map +1 -0
  112. package/lib/formula/ui/index.js +4 -0
  113. package/lib/formula/ui/index.js.map +1 -0
  114. package/lib/formula.d.ts +11 -0
  115. package/lib/formula.d.ts.map +1 -0
  116. package/lib/formula.js +11 -0
  117. package/lib/formula.js.map +1 -0
  118. package/lib/hooks/ui/index.d.ts +1 -0
  119. package/lib/hooks/ui/index.d.ts.map +1 -1
  120. package/lib/hooks/ui/index.js.map +1 -1
  121. package/lib/hooks/ui/keyTargets.d.ts +4 -2
  122. package/lib/hooks/ui/keyTargets.d.ts.map +1 -1
  123. package/lib/hooks/ui/keyTargets.js +5 -3
  124. package/lib/hooks/ui/keyTargets.js.map +1 -1
  125. package/lib/hooks/ui/useAsync.d.ts +20 -5
  126. package/lib/hooks/ui/useAsync.d.ts.map +1 -1
  127. package/lib/hooks/ui/useAsync.js +29 -14
  128. package/lib/hooks/ui/useAsync.js.map +1 -1
  129. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  130. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  131. package/lib/locales/de.json +37 -0
  132. package/lib/locales/en.json +37 -0
  133. package/lib/locales/es.json +37 -0
  134. package/lib/locales/fr.json +37 -0
  135. package/lib/locales/it.json +37 -0
  136. package/lib/moleculesClient/core/index.d.ts +5 -0
  137. package/lib/moleculesClient/core/index.d.ts.map +1 -0
  138. package/lib/moleculesClient/core/index.js +3 -0
  139. package/lib/moleculesClient/core/index.js.map +1 -0
  140. package/lib/moleculesClient/core/moleculesClient.d.ts +12 -0
  141. package/lib/moleculesClient/core/moleculesClient.d.ts.map +1 -0
  142. package/lib/moleculesClient/core/moleculesClient.js +105 -0
  143. package/lib/moleculesClient/core/moleculesClient.js.map +1 -0
  144. package/lib/moleculesClient/core/moleculesClientApi.d.ts +100 -0
  145. package/lib/moleculesClient/core/moleculesClientApi.d.ts.map +1 -0
  146. package/lib/moleculesClient/core/moleculesClientApi.js +20 -0
  147. package/lib/moleculesClient/core/moleculesClientApi.js.map +1 -0
  148. package/lib/moleculesClient/core/moleculesTypes.d.ts +154 -0
  149. package/lib/moleculesClient/core/moleculesTypes.d.ts.map +1 -0
  150. package/lib/moleculesClient/core/moleculesTypes.js +2 -0
  151. package/lib/moleculesClient/core/moleculesTypes.js.map +1 -0
  152. package/lib/moleculesClient/core/requestRetry.d.ts +50 -0
  153. package/lib/moleculesClient/core/requestRetry.d.ts.map +1 -0
  154. package/lib/moleculesClient/core/requestRetry.js +108 -0
  155. package/lib/moleculesClient/core/requestRetry.js.map +1 -0
  156. package/lib/molstar/core/camera.d.ts +2 -1
  157. package/lib/molstar/core/camera.d.ts.map +1 -1
  158. package/lib/molstar/core/camera.js +3 -2
  159. package/lib/molstar/core/camera.js.map +1 -1
  160. package/lib/molstar/core/framing.d.ts +102 -0
  161. package/lib/molstar/core/framing.d.ts.map +1 -0
  162. package/lib/molstar/core/framing.js +120 -0
  163. package/lib/molstar/core/framing.js.map +1 -0
  164. package/lib/molstar/core/hover.d.ts +16 -0
  165. package/lib/molstar/core/hover.d.ts.map +1 -1
  166. package/lib/molstar/core/hover.js +14 -0
  167. package/lib/molstar/core/hover.js.map +1 -1
  168. package/lib/molstar/core/index.d.ts +4 -1
  169. package/lib/molstar/core/index.d.ts.map +1 -1
  170. package/lib/molstar/core/index.js +2 -1
  171. package/lib/molstar/core/index.js.map +1 -1
  172. package/lib/pedagogy/core/answers.d.ts +46 -0
  173. package/lib/pedagogy/core/answers.d.ts.map +1 -0
  174. package/lib/pedagogy/core/answers.js +77 -0
  175. package/lib/pedagogy/core/answers.js.map +1 -0
  176. package/lib/pedagogy/core/attempts.d.ts +86 -0
  177. package/lib/pedagogy/core/attempts.d.ts.map +1 -0
  178. package/lib/pedagogy/core/attempts.js +117 -0
  179. package/lib/pedagogy/core/attempts.js.map +1 -0
  180. package/lib/pedagogy/core/index.d.ts +8 -0
  181. package/lib/pedagogy/core/index.d.ts.map +1 -1
  182. package/lib/pedagogy/core/index.js +4 -0
  183. package/lib/pedagogy/core/index.js.map +1 -1
  184. package/lib/pedagogy/core/progressController.d.ts +64 -0
  185. package/lib/pedagogy/core/progressController.d.ts.map +1 -0
  186. package/lib/pedagogy/core/progressController.js +56 -0
  187. package/lib/pedagogy/core/progressController.js.map +1 -0
  188. package/lib/pedagogy/core/seed.d.ts +96 -0
  189. package/lib/pedagogy/core/seed.d.ts.map +1 -0
  190. package/lib/pedagogy/core/seed.js +128 -0
  191. package/lib/pedagogy/core/seed.js.map +1 -0
  192. package/lib/pedagogy/core/series.d.ts +77 -0
  193. package/lib/pedagogy/core/series.d.ts.map +1 -0
  194. package/lib/pedagogy/core/series.js +10 -0
  195. package/lib/pedagogy/core/series.js.map +1 -0
  196. package/lib/pedagogy/ui/AnswerFields.d.ts +21 -0
  197. package/lib/pedagogy/ui/AnswerFields.d.ts.map +1 -0
  198. package/lib/pedagogy/ui/AnswerFields.js +24 -0
  199. package/lib/pedagogy/ui/AnswerFields.js.map +1 -0
  200. package/lib/pedagogy/ui/ExerciseList.d.ts +82 -0
  201. package/lib/pedagogy/ui/ExerciseList.d.ts.map +1 -0
  202. package/lib/pedagogy/ui/ExerciseList.js +53 -0
  203. package/lib/pedagogy/ui/ExerciseList.js.map +1 -0
  204. package/lib/pedagogy/ui/ExerciseSeries.d.ts +95 -0
  205. package/lib/pedagogy/ui/ExerciseSeries.d.ts.map +1 -0
  206. package/lib/pedagogy/ui/ExerciseSeries.js +74 -0
  207. package/lib/pedagogy/ui/ExerciseSeries.js.map +1 -0
  208. package/lib/pedagogy/ui/QuestionCard.d.ts +64 -0
  209. package/lib/pedagogy/ui/QuestionCard.d.ts.map +1 -0
  210. package/lib/pedagogy/ui/QuestionCard.js +73 -0
  211. package/lib/pedagogy/ui/QuestionCard.js.map +1 -0
  212. package/lib/pedagogy/ui/index.d.ts +10 -0
  213. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  214. package/lib/pedagogy/ui/index.js +6 -0
  215. package/lib/pedagogy/ui/index.js.map +1 -1
  216. package/lib/pedagogy/ui/seriesCounts.d.ts +17 -0
  217. package/lib/pedagogy/ui/seriesCounts.d.ts.map +1 -0
  218. package/lib/pedagogy/ui/seriesCounts.js +27 -0
  219. package/lib/pedagogy/ui/seriesCounts.js.map +1 -0
  220. package/lib/pedagogy/ui/seriesParts.d.ts +55 -0
  221. package/lib/pedagogy/ui/seriesParts.d.ts.map +1 -0
  222. package/lib/pedagogy/ui/seriesParts.js +38 -0
  223. package/lib/pedagogy/ui/seriesParts.js.map +1 -0
  224. package/lib/pedagogy/ui/useAttemptRecords.d.ts +10 -0
  225. package/lib/pedagogy/ui/useAttemptRecords.d.ts.map +1 -0
  226. package/lib/pedagogy/ui/useAttemptRecords.js +11 -0
  227. package/lib/pedagogy/ui/useAttemptRecords.js.map +1 -0
  228. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  229. package/lib/periodic/ui/PeriodicTable.js +6 -3
  230. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  231. package/lib/property/core/copyableText.d.ts +14 -0
  232. package/lib/property/core/copyableText.d.ts.map +1 -0
  233. package/lib/property/core/copyableText.js +21 -0
  234. package/lib/property/core/copyableText.js.map +1 -0
  235. package/lib/property/core/index.d.ts +2 -0
  236. package/lib/property/core/index.d.ts.map +1 -0
  237. package/lib/property/core/index.js +2 -0
  238. package/lib/property/core/index.js.map +1 -0
  239. package/lib/property/ui/PropertyTable.d.ts +43 -0
  240. package/lib/property/ui/PropertyTable.d.ts.map +1 -0
  241. package/lib/property/ui/PropertyTable.js +19 -0
  242. package/lib/property/ui/PropertyTable.js.map +1 -0
  243. package/lib/property/ui/index.d.ts +3 -0
  244. package/lib/property/ui/index.d.ts.map +1 -0
  245. package/lib/property/ui/index.js +2 -0
  246. package/lib/property/ui/index.js.map +1 -0
  247. package/lib/router/core/history.d.ts +24 -3
  248. package/lib/router/core/history.d.ts.map +1 -1
  249. package/lib/router/core/history.js +55 -7
  250. package/lib/router/core/history.js.map +1 -1
  251. package/lib/router/core/index.d.ts +3 -3
  252. package/lib/router/core/index.d.ts.map +1 -1
  253. package/lib/router/core/index.js +2 -2
  254. package/lib/router/core/index.js.map +1 -1
  255. package/lib/router/core/languageRoute.d.ts +61 -0
  256. package/lib/router/core/languageRoute.d.ts.map +1 -0
  257. package/lib/router/core/languageRoute.js +96 -0
  258. package/lib/router/core/languageRoute.js.map +1 -0
  259. package/lib/router/core/siteAddresses.d.ts +23 -0
  260. package/lib/router/core/siteAddresses.d.ts.map +1 -1
  261. package/lib/router/core/siteAddresses.js +26 -0
  262. package/lib/router/core/siteAddresses.js.map +1 -1
  263. package/lib/router/core/tabRouter.d.ts +2 -108
  264. package/lib/router/core/tabRouter.d.ts.map +1 -1
  265. package/lib/router/core/tabRouter.js +38 -5
  266. package/lib/router/core/tabRouter.js.map +1 -1
  267. package/lib/router/core/tabRouterTypes.d.ts +154 -0
  268. package/lib/router/core/tabRouterTypes.d.ts.map +1 -0
  269. package/lib/router/core/tabRouterTypes.js +2 -0
  270. package/lib/router/core/tabRouterTypes.js.map +1 -0
  271. package/lib/seo/core/fitDescription.d.ts +40 -0
  272. package/lib/seo/core/fitDescription.d.ts.map +1 -0
  273. package/lib/seo/core/fitDescription.js +45 -0
  274. package/lib/seo/core/fitDescription.js.map +1 -0
  275. package/lib/seo/core/index.d.ts +7 -0
  276. package/lib/seo/core/index.d.ts.map +1 -1
  277. package/lib/seo/core/index.js +4 -0
  278. package/lib/seo/core/index.js.map +1 -1
  279. package/lib/seo/core/limits.d.ts +24 -0
  280. package/lib/seo/core/limits.d.ts.map +1 -0
  281. package/lib/seo/core/limits.js +24 -0
  282. package/lib/seo/core/limits.js.map +1 -0
  283. package/lib/seo/core/pageContent.d.ts +25 -0
  284. package/lib/seo/core/pageContent.d.ts.map +1 -0
  285. package/lib/seo/core/pageContent.js +25 -0
  286. package/lib/seo/core/pageContent.js.map +1 -0
  287. package/lib/seo/core/plainDescription.d.ts.map +1 -1
  288. package/lib/seo/core/plainDescription.js +3 -2
  289. package/lib/seo/core/plainDescription.js.map +1 -1
  290. package/lib/seo/core/routeProblems.d.ts.map +1 -1
  291. package/lib/seo/core/routeProblems.js +1 -6
  292. package/lib/seo/core/routeProblems.js.map +1 -1
  293. package/lib/seo/core/routeTable.d.ts +31 -0
  294. package/lib/seo/core/routeTable.d.ts.map +1 -0
  295. package/lib/seo/core/routeTable.js +96 -0
  296. package/lib/seo/core/routeTable.js.map +1 -0
  297. package/lib/seo/vite/index.d.ts +2 -0
  298. package/lib/seo/vite/index.d.ts.map +1 -1
  299. package/lib/seo/vite/index.js +1 -0
  300. package/lib/seo/vite/index.js.map +1 -1
  301. package/lib/seo/vite/prerender.d.ts +10 -0
  302. package/lib/seo/vite/prerender.d.ts.map +1 -1
  303. package/lib/seo/vite/prerender.js +12 -1
  304. package/lib/seo/vite/prerender.js.map +1 -1
  305. package/lib/seo/vite/routeTable.d.ts +40 -0
  306. package/lib/seo/vite/routeTable.d.ts.map +1 -0
  307. package/lib/seo/vite/routeTable.js +44 -0
  308. package/lib/seo/vite/routeTable.js.map +1 -0
  309. package/lib/server/answerAddresses.d.ts +51 -0
  310. package/lib/server/answerAddresses.d.ts.map +1 -0
  311. package/lib/server/answerAddresses.js +72 -0
  312. package/lib/server/answerAddresses.js.map +1 -0
  313. package/lib/server/cardMeta.d.ts +57 -0
  314. package/lib/server/cardMeta.d.ts.map +1 -0
  315. package/lib/server/cardMeta.js +52 -0
  316. package/lib/server/cardMeta.js.map +1 -0
  317. package/lib/server/config.d.ts +72 -0
  318. package/lib/server/config.d.ts.map +1 -0
  319. package/lib/server/config.js +67 -0
  320. package/lib/server/config.js.map +1 -0
  321. package/lib/server/envNumber.d.ts +35 -0
  322. package/lib/server/envNumber.d.ts.map +1 -0
  323. package/lib/server/envNumber.js +42 -0
  324. package/lib/server/envNumber.js.map +1 -0
  325. package/lib/server/healthRoute.d.ts +26 -0
  326. package/lib/server/healthRoute.d.ts.map +1 -0
  327. package/lib/server/healthRoute.js +22 -0
  328. package/lib/server/healthRoute.js.map +1 -0
  329. package/lib/server/listenSite.d.ts +38 -0
  330. package/lib/server/listenSite.d.ts.map +1 -0
  331. package/lib/server/listenSite.js +60 -0
  332. package/lib/server/listenSite.js.map +1 -0
  333. package/lib/server/mcpServer.d.ts +8 -0
  334. package/lib/server/mcpServer.d.ts.map +1 -0
  335. package/lib/server/mcpServer.js +11 -0
  336. package/lib/server/mcpServer.js.map +1 -0
  337. package/lib/server/repositoryVersion.d.ts +16 -0
  338. package/lib/server/repositoryVersion.d.ts.map +1 -0
  339. package/lib/server/repositoryVersion.js +33 -0
  340. package/lib/server/repositoryVersion.js.map +1 -0
  341. package/lib/server/routeOptions.d.ts +23 -0
  342. package/lib/server/routeOptions.d.ts.map +1 -0
  343. package/lib/server/routeOptions.js +20 -0
  344. package/lib/server/routeOptions.js.map +1 -0
  345. package/lib/server/routeTable.d.ts +14 -0
  346. package/lib/server/routeTable.d.ts.map +1 -0
  347. package/lib/server/routeTable.js +32 -0
  348. package/lib/server/routeTable.js.map +1 -0
  349. package/lib/server/siteView.d.ts +29 -0
  350. package/lib/server/siteView.d.ts.map +1 -0
  351. package/lib/server/siteView.js +21 -0
  352. package/lib/server/siteView.js.map +1 -0
  353. package/lib/server/spaPages.d.ts +32 -0
  354. package/lib/server/spaPages.d.ts.map +1 -0
  355. package/lib/server/spaPages.js +126 -0
  356. package/lib/server/spaPages.js.map +1 -0
  357. package/lib/server/spaSite.d.ts +30 -0
  358. package/lib/server/spaSite.d.ts.map +1 -0
  359. package/lib/server/spaSite.js +170 -0
  360. package/lib/server/spaSite.js.map +1 -0
  361. package/lib/server/spaSiteOptions.d.ts +126 -0
  362. package/lib/server/spaSiteOptions.d.ts.map +1 -0
  363. package/lib/server/spaSiteOptions.js +2 -0
  364. package/lib/server/spaSiteOptions.js.map +1 -0
  365. package/lib/server/staticSite.d.ts +9 -0
  366. package/lib/server/staticSite.d.ts.map +1 -1
  367. package/lib/server/staticSite.js +41 -19
  368. package/lib/server/staticSite.js.map +1 -1
  369. package/lib/server/toolSiteServer.d.ts +77 -0
  370. package/lib/server/toolSiteServer.d.ts.map +1 -0
  371. package/lib/server/toolSiteServer.js +58 -0
  372. package/lib/server/toolSiteServer.js.map +1 -0
  373. package/lib/server/trustProxy.d.ts +20 -0
  374. package/lib/server/trustProxy.d.ts.map +1 -0
  375. package/lib/server/trustProxy.js +32 -0
  376. package/lib/server/trustProxy.js.map +1 -0
  377. package/lib/server/types.d.ts +13 -0
  378. package/lib/server/types.d.ts.map +1 -0
  379. package/lib/server/types.js +2 -0
  380. package/lib/server/types.js.map +1 -0
  381. package/lib/server.d.ts +22 -0
  382. package/lib/server.d.ts.map +1 -1
  383. package/lib/server.js +12 -0
  384. package/lib/server.js.map +1 -1
  385. package/lib/share/core/config.d.ts +18 -0
  386. package/lib/share/core/config.d.ts.map +1 -1
  387. package/lib/share/core/config.js +33 -2
  388. package/lib/share/core/config.js.map +1 -1
  389. package/lib/share/core/index.d.ts +3 -1
  390. package/lib/share/core/index.d.ts.map +1 -1
  391. package/lib/share/core/index.js +2 -1
  392. package/lib/share/core/index.js.map +1 -1
  393. package/lib/share/core/keySetParam.d.ts +40 -0
  394. package/lib/share/core/keySetParam.d.ts.map +1 -0
  395. package/lib/share/core/keySetParam.js +60 -0
  396. package/lib/share/core/keySetParam.js.map +1 -0
  397. package/lib/share/core/vocabulary.d.ts +8 -0
  398. package/lib/share/core/vocabulary.d.ts.map +1 -1
  399. package/lib/shell/ui/ShareControl.d.ts +75 -0
  400. package/lib/shell/ui/ShareControl.d.ts.map +1 -0
  401. package/lib/shell/ui/ShareControl.js +40 -0
  402. package/lib/shell/ui/ShareControl.js.map +1 -0
  403. package/lib/shell/ui/ShellFrame.d.ts +14 -0
  404. package/lib/shell/ui/ShellFrame.d.ts.map +1 -0
  405. package/lib/shell/ui/ShellFrame.js +45 -0
  406. package/lib/shell/ui/ShellFrame.js.map +1 -0
  407. package/lib/shell/ui/SiteShell.d.ts +251 -0
  408. package/lib/shell/ui/SiteShell.d.ts.map +1 -0
  409. package/lib/shell/ui/SiteShell.js +39 -0
  410. package/lib/shell/ui/SiteShell.js.map +1 -0
  411. package/lib/shell/ui/index.d.ts +5 -0
  412. package/lib/shell/ui/index.d.ts.map +1 -0
  413. package/lib/shell/ui/index.js +3 -0
  414. package/lib/shell/ui/index.js.map +1 -0
  415. package/lib/state/core/index.d.ts +1 -0
  416. package/lib/state/core/index.d.ts.map +1 -1
  417. package/lib/state/core/index.js.map +1 -1
  418. package/lib/state/core/legacyEntries.d.ts +30 -0
  419. package/lib/state/core/legacyEntries.d.ts.map +1 -0
  420. package/lib/state/core/legacyEntries.js +51 -0
  421. package/lib/state/core/legacyEntries.js.map +1 -0
  422. package/lib/state/core/persistBucket.d.ts +26 -2
  423. package/lib/state/core/persistBucket.d.ts.map +1 -1
  424. package/lib/state/core/persistBucket.js +26 -9
  425. package/lib/state/core/persistBucket.js.map +1 -1
  426. package/lib/state/core/persistSignalBucket.d.ts +26 -0
  427. package/lib/state/core/persistSignalBucket.d.ts.map +1 -1
  428. package/lib/state/core/persistSignalBucket.js +31 -0
  429. package/lib/state/core/persistSignalBucket.js.map +1 -1
  430. package/lib/state/core/storageEntry.d.ts +15 -0
  431. package/lib/state/core/storageEntry.d.ts.map +1 -1
  432. package/lib/state/core/storageEntry.js +33 -0
  433. package/lib/state/core/storageEntry.js.map +1 -1
  434. package/lib/structure/ui/StructureExportButton.d.ts +27 -0
  435. package/lib/structure/ui/StructureExportButton.d.ts.map +1 -0
  436. package/lib/structure/ui/StructureExportButton.js +21 -0
  437. package/lib/structure/ui/StructureExportButton.js.map +1 -0
  438. package/lib/structure/ui/index.d.ts +4 -0
  439. package/lib/structure/ui/index.d.ts.map +1 -1
  440. package/lib/structure/ui/index.js +2 -0
  441. package/lib/structure/ui/index.js.map +1 -1
  442. package/lib/structure/ui/useStructureDraft.d.ts +32 -0
  443. package/lib/structure/ui/useStructureDraft.d.ts.map +1 -0
  444. package/lib/structure/ui/useStructureDraft.js +20 -0
  445. package/lib/structure/ui/useStructureDraft.js.map +1 -0
  446. package/lib/ui.d.ts +2 -0
  447. package/lib/ui.d.ts.map +1 -1
  448. package/lib/ui.js +2 -0
  449. package/lib/ui.js.map +1 -1
  450. package/lib/worker/core/index.d.ts +1 -1
  451. package/lib/worker/core/index.d.ts.map +1 -1
  452. package/lib/worker/core/messages.d.ts +4 -2
  453. package/lib/worker/core/messages.d.ts.map +1 -1
  454. package/lib/worker/core/messages.js.map +1 -1
  455. package/lib/worker/core/oclResourcesUrl.d.ts +16 -0
  456. package/lib/worker/core/oclResourcesUrl.d.ts.map +1 -0
  457. package/lib/worker/core/oclResourcesUrl.js +19 -0
  458. package/lib/worker/core/oclResourcesUrl.js.map +1 -0
  459. package/lib/worker/core/serveWorkerRequests.d.ts +8 -0
  460. package/lib/worker/core/serveWorkerRequests.d.ts.map +1 -1
  461. package/lib/worker/core/serveWorkerRequests.js +15 -2
  462. package/lib/worker/core/serveWorkerRequests.js.map +1 -1
  463. package/lib/worker/core/workerChannel.d.ts +3 -4
  464. package/lib/worker/core/workerChannel.d.ts.map +1 -1
  465. package/lib/worker/core/workerChannel.js +72 -67
  466. package/lib/worker/core/workerChannel.js.map +1 -1
  467. package/lib/worker/core/workerChannelParts.d.ts +17 -6
  468. package/lib/worker/core/workerChannelParts.d.ts.map +1 -1
  469. package/lib/worker/core/workerChannelParts.js +20 -4
  470. package/lib/worker/core/workerChannelParts.js.map +1 -1
  471. package/lib/worker/core/workerChannelTypes.d.ts +46 -2
  472. package/lib/worker/core/workerChannelTypes.d.ts.map +1 -1
  473. package/lib/worker/core/workerSlot.d.ts +66 -0
  474. package/lib/worker/core/workerSlot.d.ts.map +1 -0
  475. package/lib/worker/core/workerSlot.js +107 -0
  476. package/lib/worker/core/workerSlot.js.map +1 -0
  477. package/package.json +16 -1
  478. package/src/card/core/cardAddress.ts +100 -0
  479. package/src/card/core/cardPageUrl.ts +97 -0
  480. package/src/card/core/index.ts +6 -0
  481. package/src/card/core/panelRoom.ts +66 -0
  482. package/src/card/ui/CardDetailsButton.tsx +104 -0
  483. package/src/card/ui/CardFigure.tsx +86 -0
  484. package/src/card/ui/CardFrame.tsx +46 -0
  485. package/src/card/ui/CopyTableButton.tsx +81 -0
  486. package/src/card/ui/cardTooltip.ts +18 -0
  487. package/src/card/ui/embed.ts +27 -0
  488. package/src/card/ui/fitCardToFrame.ts +76 -0
  489. package/src/card/ui/holdRoomForPanels.ts +83 -0
  490. package/src/card/ui/index.ts +14 -0
  491. package/src/card/ui/openPanels.ts +106 -0
  492. package/src/card.ts +13 -0
  493. package/src/conformers.ts +4 -0
  494. package/src/core.ts +5 -0
  495. package/src/fetch/core/apiError.ts +65 -0
  496. package/src/fetch/core/fetchJson.ts +129 -0
  497. package/src/fetch/core/index.ts +4 -0
  498. package/src/formula/core/formulaText.ts +96 -0
  499. package/src/formula/core/index.ts +20 -0
  500. package/src/formula/core/normalizeFormula.ts +50 -0
  501. package/src/formula/core/readFormula.ts +211 -0
  502. package/src/formula/ui/CopyableFormula.tsx +51 -0
  503. package/src/formula/ui/FormulaInput.tsx +50 -0
  504. package/src/formula/ui/QuestionFormula.tsx +20 -0
  505. package/src/formula/ui/index.ts +6 -0
  506. package/src/formula.ts +11 -0
  507. package/src/hooks/ui/index.ts +1 -0
  508. package/src/hooks/ui/keyTargets.ts +5 -3
  509. package/src/hooks/ui/useAsync.ts +50 -14
  510. package/src/locales/de.json +37 -0
  511. package/src/locales/en.json +37 -0
  512. package/src/locales/es.json +37 -0
  513. package/src/locales/fr.json +37 -0
  514. package/src/locales/it.json +37 -0
  515. package/src/moleculesClient/core/index.ts +19 -0
  516. package/src/moleculesClient/core/moleculesClient.ts +175 -0
  517. package/src/moleculesClient/core/moleculesClientApi.ts +120 -0
  518. package/src/moleculesClient/core/moleculesTypes.ts +163 -0
  519. package/src/moleculesClient/core/requestRetry.ts +118 -0
  520. package/src/molstar/core/camera.ts +3 -2
  521. package/src/molstar/core/framing.ts +200 -0
  522. package/src/molstar/core/hover.ts +26 -0
  523. package/src/molstar/core/index.ts +21 -1
  524. package/src/pedagogy/core/answers.ts +94 -0
  525. package/src/pedagogy/core/attempts.ts +205 -0
  526. package/src/pedagogy/core/index.ts +36 -0
  527. package/src/pedagogy/core/progressController.ts +116 -0
  528. package/src/pedagogy/core/seed.ts +177 -0
  529. package/src/pedagogy/core/series.ts +82 -0
  530. package/src/pedagogy/ui/AnswerFields.tsx +63 -0
  531. package/src/pedagogy/ui/ExerciseList.tsx +202 -0
  532. package/src/pedagogy/ui/ExerciseSeries.tsx +250 -0
  533. package/src/pedagogy/ui/QuestionCard.tsx +231 -0
  534. package/src/pedagogy/ui/index.ts +18 -0
  535. package/src/pedagogy/ui/seriesCounts.ts +34 -0
  536. package/src/pedagogy/ui/seriesParts.tsx +127 -0
  537. package/src/pedagogy/ui/useAttemptRecords.ts +16 -0
  538. package/src/periodic/ui/PeriodicTable.tsx +6 -3
  539. package/src/property/core/copyableText.ts +20 -0
  540. package/src/property/core/index.ts +1 -0
  541. package/src/property/ui/PropertyTable.tsx +83 -0
  542. package/src/property/ui/index.ts +2 -0
  543. package/src/router/core/history.ts +61 -7
  544. package/src/router/core/index.ts +3 -2
  545. package/src/router/core/languageRoute.ts +136 -0
  546. package/src/router/core/siteAddresses.ts +38 -0
  547. package/src/router/core/tabRouter.ts +59 -117
  548. package/src/router/core/tabRouterTypes.ts +158 -0
  549. package/src/seo/core/fitDescription.ts +74 -0
  550. package/src/seo/core/index.ts +17 -0
  551. package/src/seo/core/limits.ts +27 -0
  552. package/src/seo/core/pageContent.ts +42 -0
  553. package/src/seo/core/plainDescription.ts +4 -2
  554. package/src/seo/core/routeProblems.ts +1 -7
  555. package/src/seo/core/routeTable.ts +103 -0
  556. package/src/seo/vite/index.ts +2 -0
  557. package/src/seo/vite/prerender.ts +26 -1
  558. package/src/seo/vite/routeTable.ts +79 -0
  559. package/src/server/answerAddresses.ts +92 -0
  560. package/src/server/cardMeta.ts +88 -0
  561. package/src/server/config.ts +125 -0
  562. package/src/server/envNumber.ts +65 -0
  563. package/src/server/healthRoute.ts +42 -0
  564. package/src/server/listenSite.ts +90 -0
  565. package/src/server/mcpServer.ts +14 -0
  566. package/src/server/repositoryVersion.ts +33 -0
  567. package/src/server/routeOptions.ts +26 -0
  568. package/src/server/routeTable.ts +35 -0
  569. package/src/server/siteView.ts +42 -0
  570. package/src/server/spaPages.ts +179 -0
  571. package/src/server/spaSite.ts +216 -0
  572. package/src/server/spaSiteOptions.ts +133 -0
  573. package/src/server/staticSite.ts +65 -35
  574. package/src/server/toolSiteServer.ts +127 -0
  575. package/src/server/trustProxy.ts +32 -0
  576. package/src/server/types.ts +25 -0
  577. package/src/server.ts +40 -0
  578. package/src/share/core/config.ts +45 -2
  579. package/src/share/core/index.ts +4 -0
  580. package/src/share/core/keySetParam.ts +92 -0
  581. package/src/share/core/vocabulary.ts +8 -0
  582. package/src/shell/ui/ShareControl.tsx +150 -0
  583. package/src/shell/ui/ShellFrame.tsx +180 -0
  584. package/src/shell/ui/SiteShell.tsx +297 -0
  585. package/src/shell/ui/index.ts +9 -0
  586. package/src/state/core/index.ts +1 -0
  587. package/src/state/core/legacyEntries.ts +76 -0
  588. package/src/state/core/persistBucket.ts +50 -10
  589. package/src/state/core/persistSignalBucket.ts +52 -0
  590. package/src/state/core/storageEntry.ts +32 -0
  591. package/src/structure/ui/StructureExportButton.tsx +57 -0
  592. package/src/structure/ui/index.ts +4 -0
  593. package/src/structure/ui/useStructureDraft.ts +47 -0
  594. package/src/ui.ts +2 -0
  595. package/src/worker/core/index.ts +1 -0
  596. package/src/worker/core/messages.ts +4 -3
  597. package/src/worker/core/oclResourcesUrl.ts +21 -0
  598. package/src/worker/core/serveWorkerRequests.ts +30 -2
  599. package/src/worker/core/workerChannel.ts +74 -74
  600. package/src/worker/core/workerChannelParts.ts +33 -13
  601. package/src/worker/core/workerChannelTypes.ts +47 -2
  602. package/src/worker/core/workerSlot.ts +181 -0
  603. package/styles/card.css +145 -0
  604. package/styles/chrome.css +248 -0
@@ -0,0 +1,104 @@
1
+ import { Button, Tooltip } from '@blueprintjs/core';
2
+ import type { CSSProperties, ReactElement } from 'react';
3
+ import { useEffect } from 'react';
4
+
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { pageLocation } from '../../router/core/pageAddress.ts';
7
+ import { useActionTooltip } from '../../shared/ui/useActionTooltip.ts';
8
+ import type { SitePageOptions } from '../core/cardAddress.ts';
9
+ import { sitePageUrl } from '../core/cardAddress.ts';
10
+
11
+ import {
12
+ CARD_TOOLTIP_CLASS,
13
+ CARD_TOOLTIP_DELAY,
14
+ CARD_TOOLTIP_MODIFIERS,
15
+ } from './cardTooltip.ts';
16
+ import { loadEmbed, loadedEmbed } from './embed.ts';
17
+
18
+ /** What {@link CardDetailsButton} opens. */
19
+ export interface CardDetailsButtonProps {
20
+ /**
21
+ * Writes the address of the page the button opens, when it is pressed.
22
+ * @default the card's own address without `card`, `embed`, `hide` and
23
+ * what `address` says only the card reads — `sitePageUrl` over the page's
24
+ * address, the one a sealed link holds in memory included
25
+ */
26
+ page?: () => string;
27
+ /**
28
+ * How the default page is read off the card's address.
29
+ * @default {} - `card`, `embed` and `hide` are left out, and nothing else
30
+ */
31
+ address?: SitePageOptions;
32
+ /**
33
+ * What the tooltip says the button does.
34
+ * @default the chrome's own line, `Open in a new tab`
35
+ */
36
+ tooltip?: string;
37
+ /**
38
+ * Value of the `data-testid` attribute of the button.
39
+ * @default 'card-details'
40
+ */
41
+ testId?: string;
42
+ }
43
+
44
+ /**
45
+ * The way from a card to the site's own page it stands for, with its chrome,
46
+ * at the end of the card: a chat keeps the card's top right corner for its own
47
+ * control. Framed by a chat, the page opens in a new tab, so the conversation
48
+ * keeps its place; opened on its own, the card becomes the page. It never
49
+ * prints.
50
+ * @param props - See {@link CardDetailsButtonProps}.
51
+ * @returns The button, with the tooltip saying where the page opens.
52
+ */
53
+ export function CardDetailsButton(props: CardDetailsButtonProps): ReactElement {
54
+ const { page, address, tooltip, testId = 'card-details' } = props;
55
+ const t = useChromeT();
56
+ const { isOpen, target } = useActionTooltip(false, CARD_TOOLTIP_DELAY);
57
+ useEffect(() => {
58
+ loadEmbed().catch(() => undefined);
59
+ }, []);
60
+ return (
61
+ <Tooltip
62
+ content={tooltip ?? t('card.detailsTitle')}
63
+ placement="top-end"
64
+ modifiers={CARD_TOOLTIP_MODIFIERS}
65
+ popoverClassName={CARD_TOOLTIP_CLASS}
66
+ isOpen={isOpen}
67
+ >
68
+ <span className="no-print" style={WRAP_STYLE} {...target}>
69
+ <Button
70
+ variant="minimal"
71
+ size="small"
72
+ icon="share"
73
+ text={t('card.details')}
74
+ aria-label={t('card.detailsLabel')}
75
+ data-testid={testId}
76
+ onClick={() => {
77
+ const url = page === undefined ? cardSitePage(address) : page();
78
+ const embed = loadedEmbed();
79
+ if (embed === undefined) {
80
+ void loadEmbed().then((module) => module.openSitePage(url));
81
+ } else {
82
+ embed.openSitePage(url);
83
+ }
84
+ }}
85
+ />
86
+ </span>
87
+ </Tooltip>
88
+ );
89
+ }
90
+
91
+ /**
92
+ * The site's page behind the card on screen, read when the button is
93
+ * pressed: the page's own address — held in memory under a sealed link — on
94
+ * the origin the card is served from.
95
+ * @param address - What only the card reads.
96
+ * @returns The page's absolute address.
97
+ */
98
+ function cardSitePage(address: SitePageOptions | undefined): string {
99
+ const { origin } = globalThis.location;
100
+ const { pathname, search } = pageLocation() ?? globalThis.location;
101
+ return sitePageUrl({ origin, pathname, search }, address);
102
+ }
103
+
104
+ const WRAP_STYLE = { display: 'inline-flex' } as const satisfies CSSProperties;
@@ -0,0 +1,86 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import { useId } from 'react';
3
+
4
+ import { FigureDownload } from '../../download/ui/FigureDownload.tsx';
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { OverlayLayer } from '../../overlay/ui/OverlayLayer.tsx';
7
+ import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
8
+
9
+ /** What {@link CardFigure} draws and takes away. */
10
+ export interface CardFigureProps {
11
+ /** The drawing: a chart, a structure, a grid of them. */
12
+ children: ReactNode;
13
+ /** What a saved file is called, without its extension. */
14
+ fileName: string;
15
+ /**
16
+ * Glyphs drawn above the one copying the picture: the copy of the data the
17
+ * figure is drawn from, the notations of its structure
18
+ * (`StructureExportButton` of `react-cheminfo/structure`).
19
+ * @default undefined - the picture's glyph alone
20
+ */
21
+ tools?: ReactNode;
22
+ /**
23
+ * Class of the box the drawing is in, which is what the picture holds.
24
+ * @default undefined
25
+ */
26
+ className?: string;
27
+ /**
28
+ * Take the whole width the card gives, as a grid of structures does.
29
+ * @default false - as wide as the drawing
30
+ */
31
+ fill?: boolean;
32
+ /**
33
+ * The drawing is HTML rather than one SVG or canvas — a grid of cells — and
34
+ * the picture saved is painted from it as it is seen.
35
+ * @default false
36
+ */
37
+ html?: boolean;
38
+ /**
39
+ * What the picture's glyph is called, for the pointer and a screen reader.
40
+ * @default the chrome's own line, `Copy or save the picture`
41
+ */
42
+ label?: string;
43
+ }
44
+
45
+ /**
46
+ * A figure of a card with the glyphs that take it away: the picture copied as
47
+ * a PNG or saved as a PNG or an SVG, as the chat offers it for its own
48
+ * figures, and whatever else the figure carries.
49
+ *
50
+ * The glyphs stand in a column beside the figure's top right corner rather
51
+ * than over it, so they hide no part of a curve or an atom, and they fade
52
+ * until the figure is pointed at or one of them holds the focus: a card shown
53
+ * in a chat is read far more often than it is copied. `styles/card.css` draws
54
+ * the column.
55
+ * @param props - See {@link CardFigureProps}.
56
+ * @returns The figure, with its column of glyphs.
57
+ */
58
+ export function CardFigure(props: CardFigureProps): ReactElement {
59
+ const { children, fileName, tools, className, label } = props;
60
+ const { fill = false, html = false } = props;
61
+ const t = useChromeT();
62
+ const id = useId();
63
+ return (
64
+ <div className={joinClassNames('card-figure', fill && 'card-figure--fill')}>
65
+ <div
66
+ id={id}
67
+ className={joinClassNames('card-figure__drawing', className)}
68
+ data-figure={html ? 'html' : undefined}
69
+ >
70
+ {children}
71
+ </div>
72
+ {/* Compact: the glyphs of a figure shown in somebody else's page. */}
73
+ <OverlayLayer density="compact" awake>
74
+ <div className="card-figure__tools" data-testid="figure-tools">
75
+ {tools}
76
+ <FigureDownload
77
+ targetId={id}
78
+ fileName={fileName}
79
+ label={label ?? t('card.copyPicture')}
80
+ testId="card-save-figure"
81
+ />
82
+ </div>
83
+ </OverlayLayer>
84
+ </div>
85
+ );
86
+ }
@@ -0,0 +1,46 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+
3
+ import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
4
+
5
+ import { fitCardToFrame } from './fitCardToFrame.ts';
6
+
7
+ /** What {@link CardFrame} holds. */
8
+ export interface CardFrameProps {
9
+ /** The card: the answer alone, compactly. */
10
+ children: ReactNode;
11
+ /**
12
+ * Class beside `card`, so a site can reach the card from its stylesheet.
13
+ * @default undefined
14
+ */
15
+ className?: string;
16
+ /**
17
+ * Value of the `data-testid` attribute.
18
+ * @default 'card'
19
+ */
20
+ testId?: string;
21
+ }
22
+
23
+ /**
24
+ * The page a chat frames inline for one answer: the card, with no header, no
25
+ * footer and no form, as tall as what it shows. Framed, it reports its height
26
+ * so the chat fits the frame to it, and grows while a panel it opened is open
27
+ * so the frame holds that too; opened on its own, it is a page like any other.
28
+ *
29
+ * `react-cheminfo/styles/card.css` draws it: no margin on the page around it,
30
+ * the chat's corner left free by `card__header`, and the row of actions at its
31
+ * end, `card__end`.
32
+ * @param props - See {@link CardFrameProps}.
33
+ * @returns The card's root element.
34
+ */
35
+ export function CardFrame(props: CardFrameProps): ReactElement {
36
+ const { children, className, testId = 'card' } = props;
37
+ return (
38
+ <div
39
+ ref={fitCardToFrame}
40
+ className={joinClassNames('card', className)}
41
+ data-testid={testId}
42
+ >
43
+ {children}
44
+ </div>
45
+ );
46
+ }
@@ -0,0 +1,81 @@
1
+ import { Tooltip } from '@blueprintjs/core';
2
+ import type { ReactElement } from 'react';
3
+
4
+ import { CopyButton } from '../../clipboard/ui/CopyButton.tsx';
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
7
+
8
+ import {
9
+ CARD_TOOLTIP_CLASS,
10
+ CARD_TOOLTIP_DELAY,
11
+ CARD_TOOLTIP_MODIFIERS,
12
+ } from './cardTooltip.ts';
13
+
14
+ /** What {@link CopyTableButton} copies. */
15
+ export interface CopyTableButtonProps {
16
+ /**
17
+ * Writes the table, tab-separated and header first, when the button is
18
+ * pressed: a card holding a long table writes nothing until it is asked.
19
+ */
20
+ table: () => string;
21
+ /**
22
+ * What the tooltip says the button copies, e.g. `Copy the conformers as a
23
+ * table, to paste into a spreadsheet`.
24
+ * @default the chrome's own line, `Copy the table, to paste into a
25
+ * spreadsheet`
26
+ */
27
+ tooltip?: string;
28
+ /**
29
+ * Show the glyph alone, which is what a heading of a few letters has room
30
+ * for. The label is still the button's accessible name.
31
+ * @default false - the label shows, and gives way to the glyph on a frame
32
+ * narrower than 30rem
33
+ */
34
+ glyphOnly?: boolean;
35
+ /**
36
+ * Value of the `data-testid` attribute of the button's box.
37
+ * @default 'card-copy-table'
38
+ */
39
+ testId?: string;
40
+ }
41
+
42
+ /**
43
+ * A card's "Copy as table" action: the table, tab-separated and header first,
44
+ * which a spreadsheet pastes into its cells. A tick says the clipboard took
45
+ * it, a cross that the browser refused. It never prints.
46
+ * @param props - See {@link CopyTableButtonProps}.
47
+ * @returns The button, with the tooltip saying what it copies.
48
+ */
49
+ export function CopyTableButton(props: CopyTableButtonProps): ReactElement {
50
+ const {
51
+ table,
52
+ tooltip,
53
+ glyphOnly = false,
54
+ testId = 'card-copy-table',
55
+ } = props;
56
+ const t = useChromeT();
57
+ return (
58
+ <Tooltip
59
+ content={tooltip ?? t('card.copyTableTitle')}
60
+ placement="top-end"
61
+ modifiers={CARD_TOOLTIP_MODIFIERS}
62
+ popoverClassName={CARD_TOOLTIP_CLASS}
63
+ hoverOpenDelay={CARD_TOOLTIP_DELAY}
64
+ >
65
+ <span data-testid={testId}>
66
+ <CopyButton
67
+ content={table}
68
+ label={t('card.copyTable')}
69
+ title=""
70
+ icon="th"
71
+ minimal
72
+ small
73
+ className={joinClassNames(
74
+ 'card__copy-table',
75
+ glyphOnly && 'card__copy-table--glyph',
76
+ )}
77
+ />
78
+ </span>
79
+ </Tooltip>
80
+ );
81
+ }
@@ -0,0 +1,18 @@
1
+ import type { PopoverProps } from '@blueprintjs/core';
2
+
3
+ /**
4
+ * The family's help card, at the width of the few words a card's action
5
+ * says: `styles/card.css` lets `card-tooltip` shrink to its text.
6
+ */
7
+ export const CARD_TOOLTIP_CLASS = 'help-tooltip card-tooltip';
8
+
9
+ /**
10
+ * Where a card's tooltip goes when the frame has no room above its control:
11
+ * beside it, rather than cut by the frame's edge.
12
+ */
13
+ export const CARD_TOOLTIP_MODIFIERS: PopoverProps['modifiers'] = {
14
+ flip: { options: { fallbackPlacements: ['left'] } },
15
+ };
16
+
17
+ /** How long the pointer rests on an action of a card before it is named. */
18
+ export const CARD_TOOLTIP_DELAY = 300;
@@ -0,0 +1,27 @@
1
+ import type * as Embed from 'cheminfo-mcp-server/embed';
2
+
3
+ let loading: Promise<typeof Embed> | undefined;
4
+ let loaded: typeof Embed | undefined;
5
+
6
+ /**
7
+ * Load `cheminfo-mcp-server/embed` once, on first use. It is an optional
8
+ * peer, so `react-cheminfo/card` must import without it; a site that lacks it
9
+ * gets a card that never talks to a frame.
10
+ * @returns The module, once loaded.
11
+ */
12
+ export function loadEmbed(): Promise<typeof Embed> {
13
+ loading ??= import('cheminfo-mcp-server/embed').then((module) => {
14
+ loaded = module;
15
+ return module;
16
+ });
17
+ return loading;
18
+ }
19
+
20
+ /**
21
+ * The module {@link loadEmbed} loaded, read synchronously — a click must open
22
+ * its page in the same task, or the browser blocks the new tab.
23
+ * @returns The module, or undefined while it is still loading.
24
+ */
25
+ export function loadedEmbed(): typeof Embed | undefined {
26
+ return loaded;
27
+ }
@@ -0,0 +1,76 @@
1
+ import type * as Embed from 'cheminfo-mcp-server/embed';
2
+ import type { RefObject } from 'react';
3
+ import { useEffect } from 'react';
4
+
5
+ import { loadEmbed, loadedEmbed } from './embed.ts';
6
+ import { holdRoomForPanels } from './holdRoomForPanels.ts';
7
+
8
+ /**
9
+ * Fit the frame a chat shows a card in to the card: report the card's height
10
+ * to the view framing it, now and on every change, so nothing scrolls twice,
11
+ * and grow the card while a panel it opened is open, so the frame holds the
12
+ * panel too. A card opened on its own is the page: there is no frame to tell
13
+ * and none to grow, and nothing is done.
14
+ *
15
+ * Its shape is a React 19 ref callback's — `ref={fitCardToFrame}` — so it
16
+ * starts once the card is mounted and stops when it is removed. The first
17
+ * card waits for `cheminfo-mcp-server/embed` to load; a site without it gets
18
+ * a card that never reports.
19
+ * @param card - The element holding the whole card; none reports nothing.
20
+ * @returns A function that stops both, or undefined when nothing started.
21
+ */
22
+ export function fitCardToFrame(
23
+ card: HTMLElement | null,
24
+ ): (() => void) | undefined {
25
+ if (card === null) return undefined;
26
+ const embed = loadedEmbed();
27
+ if (embed !== undefined) return fitLoaded(embed, card);
28
+ let stop: (() => void) | undefined;
29
+ let stopped = false;
30
+ loadEmbed().then(
31
+ (module) => {
32
+ if (!stopped) stop = fitLoaded(module, card);
33
+ },
34
+ () => undefined,
35
+ );
36
+ return () => {
37
+ stopped = true;
38
+ stop?.();
39
+ };
40
+ }
41
+
42
+ /**
43
+ * {@link fitCardToFrame} for a card held in a ref, from its first render to
44
+ * its last.
45
+ * @param card - The ref of the element holding the whole card.
46
+ */
47
+ export function useFitCardToFrame(card: RefObject<HTMLElement | null>): void {
48
+ useEffect(() => fitCardToFrame(card.current), [card]);
49
+ }
50
+
51
+ /**
52
+ * Keep a card at least as tall as the dialogs and popovers opened over it,
53
+ * framed or not: {@link holdRoomForPanels} for a card held in a ref. A card
54
+ * whose height is reported elsewhere uses this; one that only needs its frame
55
+ * fitted uses {@link useFitCardToFrame}, which does both.
56
+ * @param card - The ref of the element holding the whole card.
57
+ */
58
+ export function useOverlayRoom(card: RefObject<HTMLElement | null>): void {
59
+ useEffect(() => {
60
+ const element = card.current;
61
+ return element === null ? undefined : holdRoomForPanels(element);
62
+ }, [card]);
63
+ }
64
+
65
+ function fitLoaded(
66
+ embed: typeof Embed,
67
+ card: HTMLElement,
68
+ ): (() => void) | undefined {
69
+ if (!embed.isFramed()) return undefined;
70
+ const stopRoom = holdRoomForPanels(card);
71
+ const stopReport = embed.reportEmbedHeight(card);
72
+ return () => {
73
+ stopReport();
74
+ stopRoom();
75
+ };
76
+ }
@@ -0,0 +1,83 @@
1
+ import { roomForPanels } from '../core/panelRoom.ts';
2
+
3
+ import { anchorBottom, openPanels } from './openPanels.ts';
4
+
5
+ /**
6
+ * Keep a card as tall as the dialogs and popovers open over it need, until
7
+ * the returned function is called; the card gives the height back as each
8
+ * closes. A chat frames a card exactly as tall as the card reports, so a
9
+ * panel taller than the card would otherwise be cut at the frame's edge.
10
+ *
11
+ * The room is measured once per animation frame, whenever the document
12
+ * changes — a panel opening, closing or moving changes the tree or a class —
13
+ * and whenever an open panel changes size, which one whose content arrives
14
+ * after it opens does without touching the tree. A card whose view fills the
15
+ * screen holds no room: its frame is not what is on screen then.
16
+ * @param card - The element whose height the frame follows.
17
+ * @returns A function that stops watching and gives the card its height back.
18
+ */
19
+ export function holdRoomForPanels(card: HTMLElement): () => void {
20
+ let frame = 0;
21
+ const watched = new Set<Element>();
22
+ const sizes =
23
+ typeof ResizeObserver === 'undefined'
24
+ ? undefined
25
+ : new ResizeObserver(schedule);
26
+ const mutations = new MutationObserver(schedule);
27
+
28
+ function measure(): void {
29
+ frame = 0;
30
+ const panels = openPanels(card);
31
+ if (sizes !== undefined) watchSizes(sizes, watched, panels.elements);
32
+ const room = document.fullscreenElement
33
+ ? 0
34
+ : roomForPanels(panels.found, anchorBottom(card));
35
+ const minHeight = room > 0 ? `${room}px` : '';
36
+ if (card.style.minHeight !== minHeight) card.style.minHeight = minHeight;
37
+ }
38
+
39
+ function schedule(): void {
40
+ if (frame === 0) frame = requestAnimationFrame(measure);
41
+ }
42
+
43
+ mutations.observe(document.body, {
44
+ childList: true,
45
+ subtree: true,
46
+ attributes: true,
47
+ attributeFilter: ['class'],
48
+ });
49
+ document.addEventListener('fullscreenchange', schedule);
50
+ schedule();
51
+ return () => {
52
+ mutations.disconnect();
53
+ sizes?.disconnect();
54
+ document.removeEventListener('fullscreenchange', schedule);
55
+ cancelAnimationFrame(frame);
56
+ card.style.minHeight = '';
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Watch the size of the panels on screen, and of no other element.
62
+ * @param sizes - The observer.
63
+ * @param watched - The elements it watches, kept up to date.
64
+ * @param panels - The panels open now.
65
+ */
66
+ function watchSizes(
67
+ sizes: ResizeObserver,
68
+ watched: Set<Element>,
69
+ panels: readonly Element[],
70
+ ): void {
71
+ for (const element of watched) {
72
+ if (!panels.includes(element)) {
73
+ sizes.unobserve(element);
74
+ watched.delete(element);
75
+ }
76
+ }
77
+ for (const element of panels) {
78
+ if (!watched.has(element)) {
79
+ sizes.observe(element);
80
+ watched.add(element);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,14 @@
1
+ export type { CardDetailsButtonProps } from './CardDetailsButton.tsx';
2
+ export { CardDetailsButton } from './CardDetailsButton.tsx';
3
+ export type { CardFigureProps } from './CardFigure.tsx';
4
+ export { CardFigure } from './CardFigure.tsx';
5
+ export type { CardFrameProps } from './CardFrame.tsx';
6
+ export { CardFrame } from './CardFrame.tsx';
7
+ export type { CopyTableButtonProps } from './CopyTableButton.tsx';
8
+ export { CopyTableButton } from './CopyTableButton.tsx';
9
+ export {
10
+ fitCardToFrame,
11
+ useFitCardToFrame,
12
+ useOverlayRoom,
13
+ } from './fitCardToFrame.ts';
14
+ export { holdRoomForPanels } from './holdRoomForPanels.ts';
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The dialogs and popovers Blueprint has open over a card, measured as the
3
+ * room each needs of the card's frame.
4
+ */
5
+
6
+ import { Classes } from '@blueprintjs/core';
7
+
8
+ import type { OpenPanel } from '../core/panelRoom.ts';
9
+
10
+ /** The panels on screen, and the elements measured for them. */
11
+ export interface FoundPanels {
12
+ /** What each panel needs. */
13
+ found: OpenPanel[];
14
+ /** The elements whose size the panels are read from. */
15
+ elements: HTMLElement[];
16
+ }
17
+
18
+ const OPEN = `.${Classes.OVERLAY_OPEN}`;
19
+
20
+ /** A tooltip is read in passing and closes as the pointer leaves: no room. */
21
+ const POPOVERS = `${OPEN} .${Classes.POPOVER}:not(.${Classes.TOOLTIP})`;
22
+
23
+ const DIALOGS = `${OPEN} .${Classes.DIALOG}`;
24
+
25
+ /** A dialog's body, which scrolls past 70 % of the frame's height. */
26
+ const SCROLLED = `.${Classes.DIALOG_BODY_SCROLL_CONTAINER}`;
27
+
28
+ /**
29
+ * A control whose popover is open: Blueprint marks its own target, and a
30
+ * toolbar that renders its target itself — the 3D view's — says it is
31
+ * expanded.
32
+ */
33
+ const OPEN_CONTROLS = `.${Classes.POPOVER_OPEN}, [aria-expanded='true']`;
34
+
35
+ /**
36
+ * The dialogs and popovers on screen, and the room each needs.
37
+ * @param card - The card they are opened over.
38
+ * @returns The panels, and the elements measured for them.
39
+ */
40
+ export function openPanels(card: HTMLElement): FoundPanels {
41
+ const found: OpenPanel[] = [];
42
+ const elements: HTMLElement[] = [];
43
+ const top = card.getBoundingClientRect().top;
44
+ for (const dialog of document.querySelectorAll<HTMLElement>(DIALOGS)) {
45
+ const { marginTop, marginBottom } = globalThis.getComputedStyle(dialog);
46
+ const margins =
47
+ (parseLength(marginTop) ?? 0) + (parseLength(marginBottom) ?? 0);
48
+ found.push({ kind: 'dialog', height: unscrolledHeight(dialog) + margins });
49
+ elements.push(dialog);
50
+ }
51
+ for (const popover of document.querySelectorAll<HTMLElement>(POPOVERS)) {
52
+ // The box that places a popover is never scaled while it opens, so it
53
+ // says where the popover ends; the popover itself is, at first.
54
+ const placed = popover.parentElement?.classList.contains(
55
+ Classes.POPOVER_TRANSITION_CONTAINER,
56
+ )
57
+ ? popover.parentElement
58
+ : popover;
59
+ const bottom = placed.getBoundingClientRect().bottom - top;
60
+ found.push({
61
+ kind: 'popover',
62
+ height: unscrolledHeight(popover),
63
+ ...(bottom > 0 && { bottom }),
64
+ });
65
+ elements.push(popover);
66
+ }
67
+ return { found, elements };
68
+ }
69
+
70
+ /**
71
+ * Where the lowest control of the card whose popover is open ends.
72
+ * @param card - The card.
73
+ * @returns Its bottom edge, in pixels from the top of the card; 0 for none.
74
+ */
75
+ export function anchorBottom(card: HTMLElement): number {
76
+ const top = card.getBoundingClientRect().top;
77
+ let bottom = 0;
78
+ for (const control of card.querySelectorAll(OPEN_CONTROLS)) {
79
+ const edge = control.getBoundingClientRect().bottom - top;
80
+ if (edge > bottom) bottom = edge;
81
+ }
82
+ return bottom;
83
+ }
84
+
85
+ /**
86
+ * The panel's height with what its body scrolls away put back.
87
+ * @param panel - The dialog or the popover.
88
+ * @returns Its height, in pixels.
89
+ */
90
+ function unscrolledHeight(panel: HTMLElement): number {
91
+ let height = panel.offsetHeight;
92
+ for (const body of panel.querySelectorAll<HTMLElement>(SCROLLED)) {
93
+ height += body.scrollHeight - body.clientHeight;
94
+ }
95
+ return height;
96
+ }
97
+
98
+ /**
99
+ * A computed length, in pixels.
100
+ * @param value - E.g. `30px`; empty where nothing computes it.
101
+ * @returns The number, or undefined when it is not one.
102
+ */
103
+ function parseLength(value: string): number | undefined {
104
+ const length = Number.parseFloat(value);
105
+ return Number.isFinite(length) ? length : undefined;
106
+ }
package/src/card.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The card an answer is shown as in a chat: a site's own page under
3
+ * `?embed=1&card=1`, framed inline by mcp.cheminfo.org.
4
+ *
5
+ * An entry point of its own, and not part of `react-cheminfo/ui`, because it
6
+ * talks to the frame through `cheminfo-mcp-server/embed`: a site that serves
7
+ * no tools must never be made to install it. The addresses — `CARD_PARAM`,
8
+ * `sitePageUrl`, `cardPageUrl` — need neither React nor the frame, and are in
9
+ * `react-cheminfo/core` too.
10
+ */
11
+
12
+ export * from './card/core/index.ts';
13
+ export * from './card/ui/index.ts';
package/src/conformers.ts CHANGED
@@ -85,3 +85,7 @@ export {
85
85
  hasFiniteCoordinates,
86
86
  } from './structure/core/conformerShape.ts';
87
87
  export { registerResources } from './structure/core/oclResources.ts';
88
+ export {
89
+ OCL_RESOURCES_FILE,
90
+ oclResourcesUrl,
91
+ } from './worker/core/oclResourcesUrl.ts';