react-cheminfo 0.64.0 → 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 (640) 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/molecule3d/core/highlight.d.ts.map +1 -1
  137. package/lib/molecule3d/core/highlight.js +2 -8
  138. package/lib/molecule3d/core/highlight.js.map +1 -1
  139. package/lib/molecule3d/core/index.d.ts +1 -1
  140. package/lib/molecule3d/core/index.d.ts.map +1 -1
  141. package/lib/molecule3d/core/index.js +1 -1
  142. package/lib/molecule3d/core/index.js.map +1 -1
  143. package/lib/molecule3d/core/measurement.d.ts +17 -0
  144. package/lib/molecule3d/core/measurement.d.ts.map +1 -1
  145. package/lib/molecule3d/core/measurement.js +43 -0
  146. package/lib/molecule3d/core/measurement.js.map +1 -1
  147. package/lib/molecule3d/ui/drawScene.d.ts +4 -2
  148. package/lib/molecule3d/ui/drawScene.d.ts.map +1 -1
  149. package/lib/molecule3d/ui/drawScene.js +1 -1
  150. package/lib/molecule3d/ui/drawScene.js.map +1 -1
  151. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +3 -1
  152. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  153. package/lib/molecule3d/ui/sceneDrawer.d.ts +47 -0
  154. package/lib/molecule3d/ui/sceneDrawer.d.ts.map +1 -0
  155. package/lib/molecule3d/ui/sceneDrawer.js +103 -0
  156. package/lib/molecule3d/ui/sceneDrawer.js.map +1 -0
  157. package/lib/molecule3d/ui/useMoleculeScene.d.ts +2 -1
  158. package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -1
  159. package/lib/molecule3d/ui/useMoleculeScene.js +13 -22
  160. package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -1
  161. package/lib/molecule3d/ui/useSharedCamera.d.ts +1 -3
  162. package/lib/molecule3d/ui/useSharedCamera.d.ts.map +1 -1
  163. package/lib/molecule3d/ui/useSharedCamera.js.map +1 -1
  164. package/lib/moleculesClient/core/index.d.ts +5 -0
  165. package/lib/moleculesClient/core/index.d.ts.map +1 -0
  166. package/lib/moleculesClient/core/index.js +3 -0
  167. package/lib/moleculesClient/core/index.js.map +1 -0
  168. package/lib/moleculesClient/core/moleculesClient.d.ts +12 -0
  169. package/lib/moleculesClient/core/moleculesClient.d.ts.map +1 -0
  170. package/lib/moleculesClient/core/moleculesClient.js +105 -0
  171. package/lib/moleculesClient/core/moleculesClient.js.map +1 -0
  172. package/lib/moleculesClient/core/moleculesClientApi.d.ts +100 -0
  173. package/lib/moleculesClient/core/moleculesClientApi.d.ts.map +1 -0
  174. package/lib/moleculesClient/core/moleculesClientApi.js +20 -0
  175. package/lib/moleculesClient/core/moleculesClientApi.js.map +1 -0
  176. package/lib/moleculesClient/core/moleculesTypes.d.ts +154 -0
  177. package/lib/moleculesClient/core/moleculesTypes.d.ts.map +1 -0
  178. package/lib/moleculesClient/core/moleculesTypes.js +2 -0
  179. package/lib/moleculesClient/core/moleculesTypes.js.map +1 -0
  180. package/lib/moleculesClient/core/requestRetry.d.ts +50 -0
  181. package/lib/moleculesClient/core/requestRetry.d.ts.map +1 -0
  182. package/lib/moleculesClient/core/requestRetry.js +108 -0
  183. package/lib/moleculesClient/core/requestRetry.js.map +1 -0
  184. package/lib/molstar/core/camera.d.ts +2 -1
  185. package/lib/molstar/core/camera.d.ts.map +1 -1
  186. package/lib/molstar/core/camera.js +3 -2
  187. package/lib/molstar/core/camera.js.map +1 -1
  188. package/lib/molstar/core/framing.d.ts +102 -0
  189. package/lib/molstar/core/framing.d.ts.map +1 -0
  190. package/lib/molstar/core/framing.js +120 -0
  191. package/lib/molstar/core/framing.js.map +1 -0
  192. package/lib/molstar/core/hover.d.ts +16 -0
  193. package/lib/molstar/core/hover.d.ts.map +1 -1
  194. package/lib/molstar/core/hover.js +14 -0
  195. package/lib/molstar/core/hover.js.map +1 -1
  196. package/lib/molstar/core/index.d.ts +4 -1
  197. package/lib/molstar/core/index.d.ts.map +1 -1
  198. package/lib/molstar/core/index.js +2 -1
  199. package/lib/molstar/core/index.js.map +1 -1
  200. package/lib/pedagogy/core/answers.d.ts +46 -0
  201. package/lib/pedagogy/core/answers.d.ts.map +1 -0
  202. package/lib/pedagogy/core/answers.js +77 -0
  203. package/lib/pedagogy/core/answers.js.map +1 -0
  204. package/lib/pedagogy/core/attempts.d.ts +86 -0
  205. package/lib/pedagogy/core/attempts.d.ts.map +1 -0
  206. package/lib/pedagogy/core/attempts.js +117 -0
  207. package/lib/pedagogy/core/attempts.js.map +1 -0
  208. package/lib/pedagogy/core/index.d.ts +8 -0
  209. package/lib/pedagogy/core/index.d.ts.map +1 -1
  210. package/lib/pedagogy/core/index.js +4 -0
  211. package/lib/pedagogy/core/index.js.map +1 -1
  212. package/lib/pedagogy/core/progressController.d.ts +64 -0
  213. package/lib/pedagogy/core/progressController.d.ts.map +1 -0
  214. package/lib/pedagogy/core/progressController.js +56 -0
  215. package/lib/pedagogy/core/progressController.js.map +1 -0
  216. package/lib/pedagogy/core/seed.d.ts +96 -0
  217. package/lib/pedagogy/core/seed.d.ts.map +1 -0
  218. package/lib/pedagogy/core/seed.js +128 -0
  219. package/lib/pedagogy/core/seed.js.map +1 -0
  220. package/lib/pedagogy/core/series.d.ts +77 -0
  221. package/lib/pedagogy/core/series.d.ts.map +1 -0
  222. package/lib/pedagogy/core/series.js +10 -0
  223. package/lib/pedagogy/core/series.js.map +1 -0
  224. package/lib/pedagogy/ui/AnswerFields.d.ts +21 -0
  225. package/lib/pedagogy/ui/AnswerFields.d.ts.map +1 -0
  226. package/lib/pedagogy/ui/AnswerFields.js +24 -0
  227. package/lib/pedagogy/ui/AnswerFields.js.map +1 -0
  228. package/lib/pedagogy/ui/ExerciseList.d.ts +82 -0
  229. package/lib/pedagogy/ui/ExerciseList.d.ts.map +1 -0
  230. package/lib/pedagogy/ui/ExerciseList.js +53 -0
  231. package/lib/pedagogy/ui/ExerciseList.js.map +1 -0
  232. package/lib/pedagogy/ui/ExerciseSeries.d.ts +95 -0
  233. package/lib/pedagogy/ui/ExerciseSeries.d.ts.map +1 -0
  234. package/lib/pedagogy/ui/ExerciseSeries.js +74 -0
  235. package/lib/pedagogy/ui/ExerciseSeries.js.map +1 -0
  236. package/lib/pedagogy/ui/QuestionCard.d.ts +64 -0
  237. package/lib/pedagogy/ui/QuestionCard.d.ts.map +1 -0
  238. package/lib/pedagogy/ui/QuestionCard.js +73 -0
  239. package/lib/pedagogy/ui/QuestionCard.js.map +1 -0
  240. package/lib/pedagogy/ui/index.d.ts +10 -0
  241. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  242. package/lib/pedagogy/ui/index.js +6 -0
  243. package/lib/pedagogy/ui/index.js.map +1 -1
  244. package/lib/pedagogy/ui/seriesCounts.d.ts +17 -0
  245. package/lib/pedagogy/ui/seriesCounts.d.ts.map +1 -0
  246. package/lib/pedagogy/ui/seriesCounts.js +27 -0
  247. package/lib/pedagogy/ui/seriesCounts.js.map +1 -0
  248. package/lib/pedagogy/ui/seriesParts.d.ts +55 -0
  249. package/lib/pedagogy/ui/seriesParts.d.ts.map +1 -0
  250. package/lib/pedagogy/ui/seriesParts.js +38 -0
  251. package/lib/pedagogy/ui/seriesParts.js.map +1 -0
  252. package/lib/pedagogy/ui/useAttemptRecords.d.ts +10 -0
  253. package/lib/pedagogy/ui/useAttemptRecords.d.ts.map +1 -0
  254. package/lib/pedagogy/ui/useAttemptRecords.js +11 -0
  255. package/lib/pedagogy/ui/useAttemptRecords.js.map +1 -0
  256. package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
  257. package/lib/periodic/ui/PeriodicTable.js +6 -3
  258. package/lib/periodic/ui/PeriodicTable.js.map +1 -1
  259. package/lib/property/core/copyableText.d.ts +14 -0
  260. package/lib/property/core/copyableText.d.ts.map +1 -0
  261. package/lib/property/core/copyableText.js +21 -0
  262. package/lib/property/core/copyableText.js.map +1 -0
  263. package/lib/property/core/index.d.ts +2 -0
  264. package/lib/property/core/index.d.ts.map +1 -0
  265. package/lib/property/core/index.js +2 -0
  266. package/lib/property/core/index.js.map +1 -0
  267. package/lib/property/ui/PropertyTable.d.ts +43 -0
  268. package/lib/property/ui/PropertyTable.d.ts.map +1 -0
  269. package/lib/property/ui/PropertyTable.js +19 -0
  270. package/lib/property/ui/PropertyTable.js.map +1 -0
  271. package/lib/property/ui/index.d.ts +3 -0
  272. package/lib/property/ui/index.d.ts.map +1 -0
  273. package/lib/property/ui/index.js +2 -0
  274. package/lib/property/ui/index.js.map +1 -0
  275. package/lib/router/core/history.d.ts +24 -3
  276. package/lib/router/core/history.d.ts.map +1 -1
  277. package/lib/router/core/history.js +55 -7
  278. package/lib/router/core/history.js.map +1 -1
  279. package/lib/router/core/index.d.ts +3 -3
  280. package/lib/router/core/index.d.ts.map +1 -1
  281. package/lib/router/core/index.js +2 -2
  282. package/lib/router/core/index.js.map +1 -1
  283. package/lib/router/core/languageRoute.d.ts +61 -0
  284. package/lib/router/core/languageRoute.d.ts.map +1 -0
  285. package/lib/router/core/languageRoute.js +96 -0
  286. package/lib/router/core/languageRoute.js.map +1 -0
  287. package/lib/router/core/siteAddresses.d.ts +23 -0
  288. package/lib/router/core/siteAddresses.d.ts.map +1 -1
  289. package/lib/router/core/siteAddresses.js +26 -0
  290. package/lib/router/core/siteAddresses.js.map +1 -1
  291. package/lib/router/core/tabRouter.d.ts +2 -108
  292. package/lib/router/core/tabRouter.d.ts.map +1 -1
  293. package/lib/router/core/tabRouter.js +38 -5
  294. package/lib/router/core/tabRouter.js.map +1 -1
  295. package/lib/router/core/tabRouterTypes.d.ts +154 -0
  296. package/lib/router/core/tabRouterTypes.d.ts.map +1 -0
  297. package/lib/router/core/tabRouterTypes.js +2 -0
  298. package/lib/router/core/tabRouterTypes.js.map +1 -0
  299. package/lib/seo/core/fitDescription.d.ts +40 -0
  300. package/lib/seo/core/fitDescription.d.ts.map +1 -0
  301. package/lib/seo/core/fitDescription.js +45 -0
  302. package/lib/seo/core/fitDescription.js.map +1 -0
  303. package/lib/seo/core/index.d.ts +7 -0
  304. package/lib/seo/core/index.d.ts.map +1 -1
  305. package/lib/seo/core/index.js +4 -0
  306. package/lib/seo/core/index.js.map +1 -1
  307. package/lib/seo/core/limits.d.ts +24 -0
  308. package/lib/seo/core/limits.d.ts.map +1 -0
  309. package/lib/seo/core/limits.js +24 -0
  310. package/lib/seo/core/limits.js.map +1 -0
  311. package/lib/seo/core/pageContent.d.ts +25 -0
  312. package/lib/seo/core/pageContent.d.ts.map +1 -0
  313. package/lib/seo/core/pageContent.js +25 -0
  314. package/lib/seo/core/pageContent.js.map +1 -0
  315. package/lib/seo/core/plainDescription.d.ts.map +1 -1
  316. package/lib/seo/core/plainDescription.js +3 -2
  317. package/lib/seo/core/plainDescription.js.map +1 -1
  318. package/lib/seo/core/routeProblems.d.ts.map +1 -1
  319. package/lib/seo/core/routeProblems.js +1 -6
  320. package/lib/seo/core/routeProblems.js.map +1 -1
  321. package/lib/seo/core/routeTable.d.ts +31 -0
  322. package/lib/seo/core/routeTable.d.ts.map +1 -0
  323. package/lib/seo/core/routeTable.js +96 -0
  324. package/lib/seo/core/routeTable.js.map +1 -0
  325. package/lib/seo/vite/index.d.ts +2 -0
  326. package/lib/seo/vite/index.d.ts.map +1 -1
  327. package/lib/seo/vite/index.js +1 -0
  328. package/lib/seo/vite/index.js.map +1 -1
  329. package/lib/seo/vite/prerender.d.ts +10 -0
  330. package/lib/seo/vite/prerender.d.ts.map +1 -1
  331. package/lib/seo/vite/prerender.js +12 -1
  332. package/lib/seo/vite/prerender.js.map +1 -1
  333. package/lib/seo/vite/routeTable.d.ts +40 -0
  334. package/lib/seo/vite/routeTable.d.ts.map +1 -0
  335. package/lib/seo/vite/routeTable.js +44 -0
  336. package/lib/seo/vite/routeTable.js.map +1 -0
  337. package/lib/server/answerAddresses.d.ts +51 -0
  338. package/lib/server/answerAddresses.d.ts.map +1 -0
  339. package/lib/server/answerAddresses.js +72 -0
  340. package/lib/server/answerAddresses.js.map +1 -0
  341. package/lib/server/cardMeta.d.ts +57 -0
  342. package/lib/server/cardMeta.d.ts.map +1 -0
  343. package/lib/server/cardMeta.js +52 -0
  344. package/lib/server/cardMeta.js.map +1 -0
  345. package/lib/server/config.d.ts +72 -0
  346. package/lib/server/config.d.ts.map +1 -0
  347. package/lib/server/config.js +67 -0
  348. package/lib/server/config.js.map +1 -0
  349. package/lib/server/envNumber.d.ts +35 -0
  350. package/lib/server/envNumber.d.ts.map +1 -0
  351. package/lib/server/envNumber.js +42 -0
  352. package/lib/server/envNumber.js.map +1 -0
  353. package/lib/server/healthRoute.d.ts +26 -0
  354. package/lib/server/healthRoute.d.ts.map +1 -0
  355. package/lib/server/healthRoute.js +22 -0
  356. package/lib/server/healthRoute.js.map +1 -0
  357. package/lib/server/listenSite.d.ts +38 -0
  358. package/lib/server/listenSite.d.ts.map +1 -0
  359. package/lib/server/listenSite.js +60 -0
  360. package/lib/server/listenSite.js.map +1 -0
  361. package/lib/server/mcpServer.d.ts +8 -0
  362. package/lib/server/mcpServer.d.ts.map +1 -0
  363. package/lib/server/mcpServer.js +11 -0
  364. package/lib/server/mcpServer.js.map +1 -0
  365. package/lib/server/repositoryVersion.d.ts +16 -0
  366. package/lib/server/repositoryVersion.d.ts.map +1 -0
  367. package/lib/server/repositoryVersion.js +33 -0
  368. package/lib/server/repositoryVersion.js.map +1 -0
  369. package/lib/server/routeOptions.d.ts +23 -0
  370. package/lib/server/routeOptions.d.ts.map +1 -0
  371. package/lib/server/routeOptions.js +20 -0
  372. package/lib/server/routeOptions.js.map +1 -0
  373. package/lib/server/routeTable.d.ts +14 -0
  374. package/lib/server/routeTable.d.ts.map +1 -0
  375. package/lib/server/routeTable.js +32 -0
  376. package/lib/server/routeTable.js.map +1 -0
  377. package/lib/server/siteView.d.ts +29 -0
  378. package/lib/server/siteView.d.ts.map +1 -0
  379. package/lib/server/siteView.js +21 -0
  380. package/lib/server/siteView.js.map +1 -0
  381. package/lib/server/spaPages.d.ts +32 -0
  382. package/lib/server/spaPages.d.ts.map +1 -0
  383. package/lib/server/spaPages.js +126 -0
  384. package/lib/server/spaPages.js.map +1 -0
  385. package/lib/server/spaSite.d.ts +30 -0
  386. package/lib/server/spaSite.d.ts.map +1 -0
  387. package/lib/server/spaSite.js +170 -0
  388. package/lib/server/spaSite.js.map +1 -0
  389. package/lib/server/spaSiteOptions.d.ts +126 -0
  390. package/lib/server/spaSiteOptions.d.ts.map +1 -0
  391. package/lib/server/spaSiteOptions.js +2 -0
  392. package/lib/server/spaSiteOptions.js.map +1 -0
  393. package/lib/server/staticSite.d.ts +9 -0
  394. package/lib/server/staticSite.d.ts.map +1 -1
  395. package/lib/server/staticSite.js +41 -19
  396. package/lib/server/staticSite.js.map +1 -1
  397. package/lib/server/toolSiteServer.d.ts +77 -0
  398. package/lib/server/toolSiteServer.d.ts.map +1 -0
  399. package/lib/server/toolSiteServer.js +58 -0
  400. package/lib/server/toolSiteServer.js.map +1 -0
  401. package/lib/server/trustProxy.d.ts +20 -0
  402. package/lib/server/trustProxy.d.ts.map +1 -0
  403. package/lib/server/trustProxy.js +32 -0
  404. package/lib/server/trustProxy.js.map +1 -0
  405. package/lib/server/types.d.ts +13 -0
  406. package/lib/server/types.d.ts.map +1 -0
  407. package/lib/server/types.js +2 -0
  408. package/lib/server/types.js.map +1 -0
  409. package/lib/server.d.ts +22 -0
  410. package/lib/server.d.ts.map +1 -1
  411. package/lib/server.js +12 -0
  412. package/lib/server.js.map +1 -1
  413. package/lib/share/core/config.d.ts +18 -0
  414. package/lib/share/core/config.d.ts.map +1 -1
  415. package/lib/share/core/config.js +33 -2
  416. package/lib/share/core/config.js.map +1 -1
  417. package/lib/share/core/index.d.ts +3 -1
  418. package/lib/share/core/index.d.ts.map +1 -1
  419. package/lib/share/core/index.js +2 -1
  420. package/lib/share/core/index.js.map +1 -1
  421. package/lib/share/core/keySetParam.d.ts +40 -0
  422. package/lib/share/core/keySetParam.d.ts.map +1 -0
  423. package/lib/share/core/keySetParam.js +60 -0
  424. package/lib/share/core/keySetParam.js.map +1 -0
  425. package/lib/share/core/vocabulary.d.ts +8 -0
  426. package/lib/share/core/vocabulary.d.ts.map +1 -1
  427. package/lib/shell/ui/ShareControl.d.ts +75 -0
  428. package/lib/shell/ui/ShareControl.d.ts.map +1 -0
  429. package/lib/shell/ui/ShareControl.js +40 -0
  430. package/lib/shell/ui/ShareControl.js.map +1 -0
  431. package/lib/shell/ui/ShellFrame.d.ts +14 -0
  432. package/lib/shell/ui/ShellFrame.d.ts.map +1 -0
  433. package/lib/shell/ui/ShellFrame.js +45 -0
  434. package/lib/shell/ui/ShellFrame.js.map +1 -0
  435. package/lib/shell/ui/SiteShell.d.ts +251 -0
  436. package/lib/shell/ui/SiteShell.d.ts.map +1 -0
  437. package/lib/shell/ui/SiteShell.js +39 -0
  438. package/lib/shell/ui/SiteShell.js.map +1 -0
  439. package/lib/shell/ui/index.d.ts +5 -0
  440. package/lib/shell/ui/index.d.ts.map +1 -0
  441. package/lib/shell/ui/index.js +3 -0
  442. package/lib/shell/ui/index.js.map +1 -0
  443. package/lib/state/core/index.d.ts +1 -0
  444. package/lib/state/core/index.d.ts.map +1 -1
  445. package/lib/state/core/index.js.map +1 -1
  446. package/lib/state/core/legacyEntries.d.ts +30 -0
  447. package/lib/state/core/legacyEntries.d.ts.map +1 -0
  448. package/lib/state/core/legacyEntries.js +51 -0
  449. package/lib/state/core/legacyEntries.js.map +1 -0
  450. package/lib/state/core/persistBucket.d.ts +26 -2
  451. package/lib/state/core/persistBucket.d.ts.map +1 -1
  452. package/lib/state/core/persistBucket.js +26 -9
  453. package/lib/state/core/persistBucket.js.map +1 -1
  454. package/lib/state/core/persistSignalBucket.d.ts +26 -0
  455. package/lib/state/core/persistSignalBucket.d.ts.map +1 -1
  456. package/lib/state/core/persistSignalBucket.js +31 -0
  457. package/lib/state/core/persistSignalBucket.js.map +1 -1
  458. package/lib/state/core/storageEntry.d.ts +15 -0
  459. package/lib/state/core/storageEntry.d.ts.map +1 -1
  460. package/lib/state/core/storageEntry.js +33 -0
  461. package/lib/state/core/storageEntry.js.map +1 -1
  462. package/lib/structure/ui/StructureExportButton.d.ts +27 -0
  463. package/lib/structure/ui/StructureExportButton.d.ts.map +1 -0
  464. package/lib/structure/ui/StructureExportButton.js +21 -0
  465. package/lib/structure/ui/StructureExportButton.js.map +1 -0
  466. package/lib/structure/ui/index.d.ts +4 -0
  467. package/lib/structure/ui/index.d.ts.map +1 -1
  468. package/lib/structure/ui/index.js +2 -0
  469. package/lib/structure/ui/index.js.map +1 -1
  470. package/lib/structure/ui/useStructureDraft.d.ts +32 -0
  471. package/lib/structure/ui/useStructureDraft.d.ts.map +1 -0
  472. package/lib/structure/ui/useStructureDraft.js +20 -0
  473. package/lib/structure/ui/useStructureDraft.js.map +1 -0
  474. package/lib/ui.d.ts +2 -0
  475. package/lib/ui.d.ts.map +1 -1
  476. package/lib/ui.js +2 -0
  477. package/lib/ui.js.map +1 -1
  478. package/lib/worker/core/index.d.ts +1 -1
  479. package/lib/worker/core/index.d.ts.map +1 -1
  480. package/lib/worker/core/messages.d.ts +4 -2
  481. package/lib/worker/core/messages.d.ts.map +1 -1
  482. package/lib/worker/core/messages.js.map +1 -1
  483. package/lib/worker/core/oclResourcesUrl.d.ts +16 -0
  484. package/lib/worker/core/oclResourcesUrl.d.ts.map +1 -0
  485. package/lib/worker/core/oclResourcesUrl.js +19 -0
  486. package/lib/worker/core/oclResourcesUrl.js.map +1 -0
  487. package/lib/worker/core/serveWorkerRequests.d.ts +8 -0
  488. package/lib/worker/core/serveWorkerRequests.d.ts.map +1 -1
  489. package/lib/worker/core/serveWorkerRequests.js +15 -2
  490. package/lib/worker/core/serveWorkerRequests.js.map +1 -1
  491. package/lib/worker/core/workerChannel.d.ts +3 -4
  492. package/lib/worker/core/workerChannel.d.ts.map +1 -1
  493. package/lib/worker/core/workerChannel.js +72 -67
  494. package/lib/worker/core/workerChannel.js.map +1 -1
  495. package/lib/worker/core/workerChannelParts.d.ts +17 -6
  496. package/lib/worker/core/workerChannelParts.d.ts.map +1 -1
  497. package/lib/worker/core/workerChannelParts.js +20 -4
  498. package/lib/worker/core/workerChannelParts.js.map +1 -1
  499. package/lib/worker/core/workerChannelTypes.d.ts +46 -2
  500. package/lib/worker/core/workerChannelTypes.d.ts.map +1 -1
  501. package/lib/worker/core/workerSlot.d.ts +66 -0
  502. package/lib/worker/core/workerSlot.d.ts.map +1 -0
  503. package/lib/worker/core/workerSlot.js +107 -0
  504. package/lib/worker/core/workerSlot.js.map +1 -0
  505. package/package.json +16 -1
  506. package/src/card/core/cardAddress.ts +100 -0
  507. package/src/card/core/cardPageUrl.ts +97 -0
  508. package/src/card/core/index.ts +6 -0
  509. package/src/card/core/panelRoom.ts +66 -0
  510. package/src/card/ui/CardDetailsButton.tsx +104 -0
  511. package/src/card/ui/CardFigure.tsx +86 -0
  512. package/src/card/ui/CardFrame.tsx +46 -0
  513. package/src/card/ui/CopyTableButton.tsx +81 -0
  514. package/src/card/ui/cardTooltip.ts +18 -0
  515. package/src/card/ui/embed.ts +27 -0
  516. package/src/card/ui/fitCardToFrame.ts +76 -0
  517. package/src/card/ui/holdRoomForPanels.ts +83 -0
  518. package/src/card/ui/index.ts +14 -0
  519. package/src/card/ui/openPanels.ts +106 -0
  520. package/src/card.ts +13 -0
  521. package/src/conformers.ts +4 -0
  522. package/src/core.ts +5 -0
  523. package/src/fetch/core/apiError.ts +65 -0
  524. package/src/fetch/core/fetchJson.ts +129 -0
  525. package/src/fetch/core/index.ts +4 -0
  526. package/src/formula/core/formulaText.ts +96 -0
  527. package/src/formula/core/index.ts +20 -0
  528. package/src/formula/core/normalizeFormula.ts +50 -0
  529. package/src/formula/core/readFormula.ts +211 -0
  530. package/src/formula/ui/CopyableFormula.tsx +51 -0
  531. package/src/formula/ui/FormulaInput.tsx +50 -0
  532. package/src/formula/ui/QuestionFormula.tsx +20 -0
  533. package/src/formula/ui/index.ts +6 -0
  534. package/src/formula.ts +11 -0
  535. package/src/hooks/ui/index.ts +1 -0
  536. package/src/hooks/ui/keyTargets.ts +5 -3
  537. package/src/hooks/ui/useAsync.ts +50 -14
  538. package/src/locales/de.json +37 -0
  539. package/src/locales/en.json +37 -0
  540. package/src/locales/es.json +37 -0
  541. package/src/locales/fr.json +37 -0
  542. package/src/locales/it.json +37 -0
  543. package/src/molecule3d/core/highlight.ts +2 -8
  544. package/src/molecule3d/core/index.ts +1 -0
  545. package/src/molecule3d/core/measurement.ts +47 -0
  546. package/src/molecule3d/ui/drawScene.ts +13 -2
  547. package/src/molecule3d/ui/moleculeViewer3DProps.ts +3 -1
  548. package/src/molecule3d/ui/sceneDrawer.ts +132 -0
  549. package/src/molecule3d/ui/useMoleculeScene.ts +16 -26
  550. package/src/molecule3d/ui/useSharedCamera.ts +1 -3
  551. package/src/moleculesClient/core/index.ts +19 -0
  552. package/src/moleculesClient/core/moleculesClient.ts +175 -0
  553. package/src/moleculesClient/core/moleculesClientApi.ts +120 -0
  554. package/src/moleculesClient/core/moleculesTypes.ts +163 -0
  555. package/src/moleculesClient/core/requestRetry.ts +118 -0
  556. package/src/molstar/core/camera.ts +3 -2
  557. package/src/molstar/core/framing.ts +200 -0
  558. package/src/molstar/core/hover.ts +26 -0
  559. package/src/molstar/core/index.ts +21 -1
  560. package/src/pedagogy/core/answers.ts +94 -0
  561. package/src/pedagogy/core/attempts.ts +205 -0
  562. package/src/pedagogy/core/index.ts +36 -0
  563. package/src/pedagogy/core/progressController.ts +116 -0
  564. package/src/pedagogy/core/seed.ts +177 -0
  565. package/src/pedagogy/core/series.ts +82 -0
  566. package/src/pedagogy/ui/AnswerFields.tsx +63 -0
  567. package/src/pedagogy/ui/ExerciseList.tsx +202 -0
  568. package/src/pedagogy/ui/ExerciseSeries.tsx +250 -0
  569. package/src/pedagogy/ui/QuestionCard.tsx +231 -0
  570. package/src/pedagogy/ui/index.ts +18 -0
  571. package/src/pedagogy/ui/seriesCounts.ts +34 -0
  572. package/src/pedagogy/ui/seriesParts.tsx +127 -0
  573. package/src/pedagogy/ui/useAttemptRecords.ts +16 -0
  574. package/src/periodic/ui/PeriodicTable.tsx +6 -3
  575. package/src/property/core/copyableText.ts +20 -0
  576. package/src/property/core/index.ts +1 -0
  577. package/src/property/ui/PropertyTable.tsx +83 -0
  578. package/src/property/ui/index.ts +2 -0
  579. package/src/router/core/history.ts +61 -7
  580. package/src/router/core/index.ts +3 -2
  581. package/src/router/core/languageRoute.ts +136 -0
  582. package/src/router/core/siteAddresses.ts +38 -0
  583. package/src/router/core/tabRouter.ts +59 -117
  584. package/src/router/core/tabRouterTypes.ts +158 -0
  585. package/src/seo/core/fitDescription.ts +74 -0
  586. package/src/seo/core/index.ts +17 -0
  587. package/src/seo/core/limits.ts +27 -0
  588. package/src/seo/core/pageContent.ts +42 -0
  589. package/src/seo/core/plainDescription.ts +4 -2
  590. package/src/seo/core/routeProblems.ts +1 -7
  591. package/src/seo/core/routeTable.ts +103 -0
  592. package/src/seo/vite/index.ts +2 -0
  593. package/src/seo/vite/prerender.ts +26 -1
  594. package/src/seo/vite/routeTable.ts +79 -0
  595. package/src/server/answerAddresses.ts +92 -0
  596. package/src/server/cardMeta.ts +88 -0
  597. package/src/server/config.ts +125 -0
  598. package/src/server/envNumber.ts +65 -0
  599. package/src/server/healthRoute.ts +42 -0
  600. package/src/server/listenSite.ts +90 -0
  601. package/src/server/mcpServer.ts +14 -0
  602. package/src/server/repositoryVersion.ts +33 -0
  603. package/src/server/routeOptions.ts +26 -0
  604. package/src/server/routeTable.ts +35 -0
  605. package/src/server/siteView.ts +42 -0
  606. package/src/server/spaPages.ts +179 -0
  607. package/src/server/spaSite.ts +216 -0
  608. package/src/server/spaSiteOptions.ts +133 -0
  609. package/src/server/staticSite.ts +65 -35
  610. package/src/server/toolSiteServer.ts +127 -0
  611. package/src/server/trustProxy.ts +32 -0
  612. package/src/server/types.ts +25 -0
  613. package/src/server.ts +40 -0
  614. package/src/share/core/config.ts +45 -2
  615. package/src/share/core/index.ts +4 -0
  616. package/src/share/core/keySetParam.ts +92 -0
  617. package/src/share/core/vocabulary.ts +8 -0
  618. package/src/shell/ui/ShareControl.tsx +150 -0
  619. package/src/shell/ui/ShellFrame.tsx +180 -0
  620. package/src/shell/ui/SiteShell.tsx +297 -0
  621. package/src/shell/ui/index.ts +9 -0
  622. package/src/state/core/index.ts +1 -0
  623. package/src/state/core/legacyEntries.ts +76 -0
  624. package/src/state/core/persistBucket.ts +50 -10
  625. package/src/state/core/persistSignalBucket.ts +52 -0
  626. package/src/state/core/storageEntry.ts +32 -0
  627. package/src/structure/ui/StructureExportButton.tsx +57 -0
  628. package/src/structure/ui/index.ts +4 -0
  629. package/src/structure/ui/useStructureDraft.ts +47 -0
  630. package/src/ui.ts +2 -0
  631. package/src/worker/core/index.ts +1 -0
  632. package/src/worker/core/messages.ts +4 -3
  633. package/src/worker/core/oclResourcesUrl.ts +21 -0
  634. package/src/worker/core/serveWorkerRequests.ts +30 -2
  635. package/src/worker/core/workerChannel.ts +74 -74
  636. package/src/worker/core/workerChannelParts.ts +33 -13
  637. package/src/worker/core/workerChannelTypes.ts +47 -2
  638. package/src/worker/core/workerSlot.ts +181 -0
  639. package/styles/card.css +145 -0
  640. package/styles/chrome.css +248 -0
@@ -4,8 +4,19 @@ import { normalizeMolecule3DSettings } from '../core/settings.ts';
4
4
 
5
5
  import type { Molecule3DViewer } from './viewer.ts';
6
6
 
7
+ /** The operations of the viewer a scene is drawn with. */
8
+ export type SceneViewer = Pick<
9
+ Molecule3DViewer,
10
+ | 'showMolecule'
11
+ | 'hideMolecule'
12
+ | 'showSurface'
13
+ | 'showMeasurements'
14
+ | 'resetCamera'
15
+ | 'setCamera'
16
+ >;
17
+
7
18
  /**
8
- * Draw the scene. `showMolecule` empties it, so the surface and the
19
+ * Draw the whole scene. `showMolecule` empties it, so the surface and the
9
20
  * measurements are added after the model, and the camera is framed last.
10
21
  * @param viewer - The viewer holding the canvas.
11
22
  * @param molfile - What to draw, or `null` to empty the scene.
@@ -17,7 +28,7 @@ import type { Molecule3DViewer } from './viewer.ts';
17
28
  * @returns Nothing; resolves once the scene is complete.
18
29
  */
19
30
  export async function drawScene(
20
- viewer: Molecule3DViewer,
31
+ viewer: SceneViewer,
21
32
  molfile: Molecule3DFile | null,
22
33
  settings: Molecule3DSettings,
23
34
  measurements: readonly Measurement[],
@@ -72,7 +72,9 @@ export interface MoleculeViewer3DProps {
72
72
  /**
73
73
  * The measurements drawn over the model, when the site owns them. They name
74
74
  * atoms by position, so they carry over to another conformer of the same
75
- * molecule; a site showing an unrelated molecule should clear them.
75
+ * molecule; a site showing an unrelated molecule should clear them. Changing
76
+ * them redraws the measurements and nothing else: the model, its highlights
77
+ * and the camera are left as they are.
76
78
  * @default undefined
77
79
  */
78
80
  measurements?: readonly Measurement[];
@@ -0,0 +1,132 @@
1
+ /**
2
+ * What one canvas shows, what it is asked to show next, and the least work
3
+ * between the two.
4
+ *
5
+ * The measurements are drawn over the model, not into it: a change of them
6
+ * alone replaces their own representations and leaves the model, its surface,
7
+ * its highlights and the camera as they are. Only another molecule, or another
8
+ * style for it, draws the scene again, and only another molecule frames the
9
+ * camera. Draws run one after another, so a measurement never lands on a model
10
+ * that is half built, and the last request asked is the one drawn.
11
+ */
12
+
13
+ import type { Molecule3DCamera } from '../core/camera.ts';
14
+ import type { Measurement } from '../core/measurement.ts';
15
+ import { sameMeasurements } from '../core/measurement.ts';
16
+ import type { Molecule3DFile, Molecule3DSettings } from '../core/settings.ts';
17
+ import { sameMolecule3DSettings } from '../core/settings.ts';
18
+
19
+ import type { SceneViewer } from './drawScene.ts';
20
+ import { drawScene } from './drawScene.ts';
21
+
22
+ /** What the canvas is asked to show. */
23
+ export interface SceneRequest {
24
+ /** What to draw, or `null` to empty the scene. */
25
+ molfile: Molecule3DFile | null;
26
+ /** How the model is drawn. */
27
+ settings: Molecule3DSettings;
28
+ /** What is drawn over it. */
29
+ measurements: readonly Measurement[];
30
+ /** How the camera meets a molecule it has not shown before. */
31
+ frameNewMolecule: 'front' | 'keep';
32
+ }
33
+
34
+ /** Keeps one viewer showing the last scene it was asked for. */
35
+ export class SceneDrawer {
36
+ /** The viewer drawn on. */
37
+ readonly viewer: SceneViewer;
38
+ readonly #takeLinkedCamera: () => Molecule3DCamera | null;
39
+ #asked: SceneRequest | null = null;
40
+ // The model on screen, or `null` when the next request must draw it again.
41
+ #drawn: Pick<SceneRequest, 'molfile' | 'settings'> | null = null;
42
+ // The measurements on screen, or `null` when the next request must draw them.
43
+ #measured: readonly Measurement[] | null = [];
44
+ // The molecule the camera was last framed on, so another one is told apart.
45
+ #framed: Molecule3DFile | null = null;
46
+ #queue: Promise<void> = Promise.resolve();
47
+
48
+ /**
49
+ * Start drawing on `viewer`, whose scene is empty.
50
+ * @param viewer - The viewer to draw on.
51
+ * @param takeLinkedCamera - Asked when a molecule is new: a camera to stand
52
+ * at instead of framing it, or `null`.
53
+ */
54
+ constructor(
55
+ viewer: SceneViewer,
56
+ takeLinkedCamera: () => Molecule3DCamera | null,
57
+ ) {
58
+ this.viewer = viewer;
59
+ this.#takeLinkedCamera = takeLinkedCamera;
60
+ }
61
+
62
+ /**
63
+ * Bring the canvas to `request`, once whatever was asked before is drawn.
64
+ * @param request - The scene to show; replaces any request still waiting.
65
+ * @returns Nothing; resolves once the canvas shows the last request asked,
66
+ * and rejects with what stopped it from being drawn.
67
+ */
68
+ draw(request: SceneRequest): Promise<void> {
69
+ this.#asked = request;
70
+ const drawn = this.#queue.then(() => this.#catchUp());
71
+ this.#queue = drawn.catch(ignore);
72
+ return drawn;
73
+ }
74
+
75
+ async #catchUp(): Promise<void> {
76
+ const request = this.#asked;
77
+ if (request === null) return;
78
+ const drawn = this.#drawn;
79
+ if (
80
+ drawn !== null &&
81
+ sameFile(drawn.molfile, request.molfile) &&
82
+ sameMolecule3DSettings(drawn.settings, request.settings)
83
+ ) {
84
+ await this.#measure(request);
85
+ return;
86
+ }
87
+ await this.#redraw(request);
88
+ }
89
+
90
+ // The model stays: only the measurements over it can have changed.
91
+ async #measure(request: SceneRequest): Promise<void> {
92
+ const { molfile, measurements } = request;
93
+ const measured = this.#measured;
94
+ if (measured !== null && sameMeasurements(measured, measurements)) return;
95
+ // As for the model: a list that fails partway is drawn again next time.
96
+ this.#measured = null;
97
+ // An empty scene has nothing to measure; the list waits for a molecule.
98
+ if (molfile !== null) await this.viewer.showMeasurements(measurements);
99
+ this.#measured = measurements;
100
+ }
101
+
102
+ async #redraw(request: SceneRequest): Promise<void> {
103
+ const { molfile, settings, measurements, frameNewMolecule } = request;
104
+ const isNew =
105
+ molfile !== null &&
106
+ (this.#framed === null || !sameFile(this.#framed, molfile));
107
+ this.#framed = molfile;
108
+ // A link's camera is spent on the first molecule framed; afterwards the
109
+ // camera is the reader's and a new molecule is framed as usual.
110
+ const linked = isNew ? this.#takeLinkedCamera() : null;
111
+ const frameCamera = isNew && linked === null ? frameNewMolecule : 'none';
112
+ // Kept only once drawn: a draw that fails is drawn again by the next
113
+ // request, whatever that one changes.
114
+ this.#drawn = null;
115
+ await drawScene(this.viewer, molfile, settings, measurements, frameCamera);
116
+ this.#drawn = { molfile, settings };
117
+ this.#measured = measurements;
118
+ if (linked !== null) await this.viewer.setCamera(linked);
119
+ }
120
+ }
121
+
122
+ function sameFile(
123
+ first: Molecule3DFile | null,
124
+ second: Molecule3DFile | null,
125
+ ): boolean {
126
+ if (first === null || second === null) return first === second;
127
+ return first.format === second.format && first.data === second.data;
128
+ }
129
+
130
+ function ignore(): void {
131
+ // A failure reached the caller of `draw`; the next draw still runs.
132
+ }
@@ -5,18 +5,18 @@
5
5
  * The draw is coalesced into one animation frame, so dragging a slider costs
6
6
  * one rebuild rather than one per pixel, and the camera is framed only when the
7
7
  * molecule is new — a restyle that snapped the view back would undo the
8
- * reader's orientation.
8
+ * reader's orientation. What each draw rebuilds is the scene drawer's call: a
9
+ * change of the measurements alone redraws them and nothing else.
9
10
  */
10
11
 
11
12
  import type { RefObject } from 'react';
12
13
  import { useCallback, useEffect, useRef } from 'react';
13
14
 
14
- import type { Molecule3DCamera } from '../core/camera.ts';
15
15
  import type { Measurement } from '../core/measurement.ts';
16
16
  import type { Molecule3DFile, Molecule3DSettings } from '../core/settings.ts';
17
17
 
18
- import { drawScene } from './drawScene.ts';
19
18
  import type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
19
+ import { SceneDrawer } from './sceneDrawer.ts';
20
20
  import {
21
21
  DEFAULT_CAMERA_SETTLE_DELAY,
22
22
  useSharedCamera,
@@ -71,10 +71,7 @@ export function useMoleculeScene(options: MoleculeSceneOptions): MoleculeScene {
71
71
  onFailureChange,
72
72
  camera: cameraProps,
73
73
  } = options;
74
- const framedRef = useRef<{
75
- molfile: Molecule3DFile;
76
- viewer: Molecule3DViewer;
77
- } | null>(null);
74
+ const drawerRef = useRef<SceneDrawer | null>(null);
78
75
  const reportFailure = useRef(onFailureChange);
79
76
  useEffect(() => {
80
77
  reportFailure.current = onFailureChange;
@@ -92,31 +89,24 @@ export function useMoleculeScene(options: MoleculeSceneOptions): MoleculeScene {
92
89
  useEffect(() => {
93
90
  const viewer = viewerRef.current;
94
91
  if (container === null || viewer === null) return;
92
+ // A new viewer starts from an empty scene, so it gets a drawer of its own.
93
+ if (drawerRef.current?.viewer !== viewer) {
94
+ drawerRef.current = new SceneDrawer(viewer, camera.takeLinkedCamera);
95
+ }
96
+ const drawer = drawerRef.current;
95
97
  let cancelled = false;
96
98
  const frame = requestAnimationFrame(() => {
97
- const framed = framedRef.current;
98
- const isNew =
99
- molfile !== null &&
100
- (framed?.molfile !== molfile || framed.viewer !== viewer);
101
- framedRef.current = molfile === null ? null : { molfile, viewer };
102
- // The link's camera is spent on the first molecule framed; afterwards the
103
- // camera is the reader's and a new molecule is framed as usual.
104
- const linked: Molecule3DCamera | null = isNew
105
- ? camera.takeLinkedCamera()
106
- : null;
107
- const frameCamera = isNew && linked === null ? frameNewMolecule : 'none';
108
- void drawScene(viewer, molfile, settings, measurements, frameCamera)
109
- .then(() => {
110
- if (cancelled) return;
111
- if (linked !== null) void viewer.setCamera(linked);
112
- reportFailure.current(null);
113
- })
114
- .catch((error: unknown) => {
99
+ drawer.draw({ molfile, settings, measurements, frameNewMolecule }).then(
100
+ () => {
101
+ if (!cancelled) reportFailure.current(null);
102
+ },
103
+ (error: unknown) => {
115
104
  if (cancelled) return;
116
105
  reportFailure.current(
117
106
  error instanceof Error ? error.message : String(error),
118
107
  );
119
- });
108
+ },
109
+ );
120
110
  });
121
111
  return () => {
122
112
  cancelled = true;
@@ -37,9 +37,7 @@ export interface SharedCameraOptions {
37
37
 
38
38
  /**
39
39
  * What {@link useSharedCamera} answers. The same object on every render: the
40
- * draw effect keys on it, and a fresh one would tear the scene down and build
41
- * it again — which makes molstar frame the model afresh and loses the camera a
42
- * link had just restored.
40
+ * draw effect keys on it, and a fresh one would run it again for nothing.
43
41
  */
44
42
  export interface SharedCamera {
45
43
  /**
@@ -0,0 +1,19 @@
1
+ export { createMoleculesClient } from './moleculesClient.ts';
2
+ export type {
3
+ MoleculesClient,
4
+ MoleculesClientOptions,
5
+ } from './moleculesClientApi.ts';
6
+ export { MoleculesError } from './moleculesClientApi.ts';
7
+ export type {
8
+ ImportStarted,
9
+ ImportState,
10
+ LookupResponse,
11
+ LookupResult,
12
+ MoleculeInfo,
13
+ MoleculeInput,
14
+ PurgeResponse,
15
+ RetryDetails,
16
+ SubmitResponse,
17
+ SubmitResult,
18
+ SubmitSummary,
19
+ } from './moleculesTypes.ts';
@@ -0,0 +1,175 @@
1
+ import { XSadd } from 'ml-xsadd';
2
+
3
+ import { trimTrailingSlash } from '../../router/core/address.ts';
4
+
5
+ import type {
6
+ MoleculesClient,
7
+ MoleculesClientOptions,
8
+ } from './moleculesClientApi.ts';
9
+ import { MoleculesError } from './moleculesClientApi.ts';
10
+ import type {
11
+ ImportStarted,
12
+ ImportState,
13
+ LookupResponse,
14
+ PurgeResponse,
15
+ SubmitResponse,
16
+ } from './moleculesTypes.ts';
17
+ import {
18
+ causeOf,
19
+ gzipBody,
20
+ messageOf,
21
+ pause,
22
+ requestSignal,
23
+ retryAfter,
24
+ } from './requestRetry.ts';
25
+
26
+ /** Statuses a request is tried again on: the server is busy or in between. */
27
+ const RETRIED_STATUSES = new Set([429, 502, 503, 504]);
28
+
29
+ /** The doublings of the pause, after which it stays where it is. */
30
+ const MAX_DOUBLINGS = 20;
31
+
32
+ /** One request, as it is tried again. */
33
+ interface Call {
34
+ method: 'GET' | 'POST';
35
+ path: string;
36
+ payload: Uint8Array<ArrayBuffer> | undefined;
37
+ started: number;
38
+ }
39
+
40
+ /** What one attempt came to: the answer, or why another is worth it. */
41
+ type Outcome<T> =
42
+ | { answered: true; value: T }
43
+ | {
44
+ answered: false;
45
+ status: number | undefined;
46
+ reason: string;
47
+ retryAfterMs: number | undefined;
48
+ };
49
+
50
+ /**
51
+ * A client of the routes a source writes through on molecules.cheminfo.org,
52
+ * retrying while the server is busy (503), throttling (429), being restarted
53
+ * (502, 504) or out of reach. Each attempt has its own deadline, the pauses
54
+ * double with a spread and honour `Retry-After`, and bodies travel gzipped.
55
+ * Browser-safe: it reads no Node module.
56
+ * @param options - Where it answers, the token, and how hard to insist.
57
+ * @returns The client.
58
+ */
59
+ export function createMoleculesClient(
60
+ options: MoleculesClientOptions,
61
+ ): MoleculesClient {
62
+ const {
63
+ token,
64
+ maxRetryMs = 1_800_000,
65
+ initialDelayMs = 1000,
66
+ maxDelayMs = 60_000,
67
+ requestTimeoutMs = 600_000,
68
+ signal,
69
+ onRetry,
70
+ fetch: fetchImplementation = globalThis.fetch,
71
+ random = new XSadd().random,
72
+ } = options;
73
+ const baseUrl = trimTrailingSlash(options.baseUrl);
74
+
75
+ async function attemptOnce<T>(call: Call): Promise<Outcome<T>> {
76
+ let response: Response;
77
+ try {
78
+ response = await fetchImplementation(`${baseUrl}${call.path}`, {
79
+ method: call.method,
80
+ headers: {
81
+ authorization: `Bearer ${token}`,
82
+ ...(call.payload === undefined
83
+ ? {}
84
+ : {
85
+ 'content-type': 'application/json',
86
+ 'content-encoding': 'gzip',
87
+ }),
88
+ },
89
+ body: call.payload,
90
+ signal: requestSignal(signal, requestTimeoutMs),
91
+ });
92
+ if (response.ok) {
93
+ return { answered: true, value: (await response.json()) as T };
94
+ }
95
+ } catch (error: unknown) {
96
+ if (signal?.aborted) throw signal.reason;
97
+ return {
98
+ answered: false,
99
+ status: undefined,
100
+ reason: causeOf(error),
101
+ retryAfterMs: undefined,
102
+ };
103
+ }
104
+ const text = await response.text();
105
+ const reason = messageOf(text) ?? response.statusText;
106
+ if (!RETRIED_STATUSES.has(response.status)) {
107
+ throw new MoleculesError(
108
+ `${call.method} ${call.path} answered ${response.status}: ${reason}`,
109
+ response.status,
110
+ text,
111
+ );
112
+ }
113
+ const asked = retryAfter(response.headers.get('retry-after'), Date.now());
114
+ return {
115
+ answered: false,
116
+ status: response.status,
117
+ reason,
118
+ retryAfterMs: asked,
119
+ };
120
+ }
121
+
122
+ async function attempt<T>(call: Call, number: number): Promise<T> {
123
+ signal?.throwIfAborted();
124
+ const outcome = await attemptOnce<T>(call);
125
+ if (outcome.answered) return outcome.value;
126
+ const backoff =
127
+ initialDelayMs *
128
+ 2 ** Math.min(number - 1, MAX_DOUBLINGS) *
129
+ (0.5 + random() * 0.5);
130
+ const delayMs = Math.min(maxDelayMs, outcome.retryAfterMs ?? backoff);
131
+ const elapsed = Date.now() - call.started;
132
+ if (elapsed + delayMs > maxRetryMs) {
133
+ throw new MoleculesError(
134
+ `${call.method} ${call.path} kept failing for ${Math.round(elapsed / 1000)} s: ${outcome.reason}`,
135
+ outcome.status ?? 0,
136
+ outcome.reason,
137
+ );
138
+ }
139
+ onRetry?.({
140
+ method: call.method,
141
+ path: call.path,
142
+ attempt: number,
143
+ status: outcome.status,
144
+ reason: outcome.reason,
145
+ delayMs,
146
+ });
147
+ await pause(delayMs, signal);
148
+ return attempt<T>(call, number + 1);
149
+ }
150
+
151
+ async function request<T>(
152
+ method: 'GET' | 'POST',
153
+ path: string,
154
+ body?: unknown,
155
+ ): Promise<T> {
156
+ const started = Date.now();
157
+ const payload =
158
+ body === undefined ? undefined : await gzipBody(JSON.stringify(body));
159
+ return attempt<T>({ method, path, payload, started }, 1);
160
+ }
161
+
162
+ return {
163
+ startImport: () => request<ImportStarted>('POST', '/v1/imports'),
164
+ importState: () => request<ImportState>('GET', '/v1/imports'),
165
+ submit: (molecules, { returnInfo = false } = {}) =>
166
+ request<SubmitResponse>('POST', '/v1/submit', { molecules, returnInfo }),
167
+ lookup: (queries, kind) =>
168
+ request<LookupResponse>('POST', '/v1/batch', { queries, kind }),
169
+ purge: (importKey, { dryRun = false, force = false } = {}) =>
170
+ request<PurgeResponse>('POST', `/v1/imports/${importKey}/purge`, {
171
+ dryRun,
172
+ force,
173
+ }),
174
+ };
175
+ }
@@ -0,0 +1,120 @@
1
+ import type {
2
+ ImportStarted,
3
+ ImportState,
4
+ LookupResponse,
5
+ MoleculeInput,
6
+ PurgeResponse,
7
+ RetryDetails,
8
+ SubmitResponse,
9
+ } from './moleculesTypes.ts';
10
+
11
+ /** How a client reaches molecules.cheminfo.org, and how hard it insists. */
12
+ export interface MoleculesClientOptions {
13
+ /** Where molecules.cheminfo.org answers, e.g. `https://molecules.cheminfo.org`. */
14
+ baseUrl: string;
15
+ /** The token issued for the source the client writes for. */
16
+ token: string;
17
+ /**
18
+ * How long one request may keep being retried while the server is busy or
19
+ * unreachable, in milliseconds.
20
+ * @default 1_800_000 - half an hour
21
+ */
22
+ maxRetryMs?: number;
23
+ /**
24
+ * The first pause before a retry; each next one doubles, up to `maxDelayMs`.
25
+ * @default 1000
26
+ */
27
+ initialDelayMs?: number;
28
+ /**
29
+ * The longest pause between two attempts, a `Retry-After` included.
30
+ * @default 60_000
31
+ */
32
+ maxDelayMs?: number;
33
+ /**
34
+ * How long one attempt may take before it is given up and retried.
35
+ * @default 600_000
36
+ */
37
+ requestTimeoutMs?: number;
38
+ /**
39
+ * Stops every request, and every pause between two attempts.
40
+ * @default undefined - nothing stops them
41
+ */
42
+ signal?: AbortSignal;
43
+ /**
44
+ * Told about every retry, e.g. to log it.
45
+ * @default undefined - retries are silent
46
+ */
47
+ onRetry?: (details: RetryDetails) => void;
48
+ /**
49
+ * The fetch to use, for tests.
50
+ * @default globalThis.fetch
51
+ */
52
+ fetch?: typeof fetch;
53
+ /**
54
+ * A number from 0 to 1 that spreads the pauses, so clients that failed
55
+ * together do not all come back at the same instant.
56
+ * @default an unseeded `XSadd`
57
+ */
58
+ random?: () => number;
59
+ }
60
+
61
+ /** The routes a source writes through on molecules.cheminfo.org. */
62
+ export interface MoleculesClient {
63
+ /** Take the source's next import key: the start of a full import. */
64
+ startImport: () => Promise<ImportStarted>;
65
+ /** Where the source's import stands. */
66
+ importState: () => Promise<ImportState>;
67
+ /**
68
+ * Send up to 1000 molecules for the source, under its current import key.
69
+ * @param molecules - Each with its identifier and exactly one notation.
70
+ * @param options - Whether every answer carries the molecule's properties.
71
+ * @param options.returnInfo - Ask for them; `false` by default.
72
+ */
73
+ submit: (
74
+ molecules: MoleculeInput[],
75
+ options?: { returnInfo?: boolean },
76
+ ) => Promise<SubmitResponse>;
77
+ /**
78
+ * Compute up to 1000 molecules without storing anything, for a source
79
+ * molecules.cheminfo.org imports itself.
80
+ * @param queries - The structures, all in one notation.
81
+ * @param kind - The notation.
82
+ */
83
+ lookup: (
84
+ queries: string[],
85
+ kind: 'smiles' | 'molfile' | 'idCode',
86
+ ) => Promise<LookupResponse>;
87
+ /**
88
+ * Remove the entries an import did not send again.
89
+ * @param importKey - The key the import took.
90
+ * @param options - Only count, or remove even more than half.
91
+ * @param options.dryRun - Only count; `false` by default.
92
+ * @param options.force - Remove even when that is more than half; `false` by
93
+ * default.
94
+ */
95
+ purge: (
96
+ importKey: number,
97
+ options?: { dryRun?: boolean; force?: boolean },
98
+ ) => Promise<PurgeResponse>;
99
+ }
100
+
101
+ /** A request molecules.cheminfo.org refused, or that kept failing. */
102
+ export class MoleculesError extends Error {
103
+ /** The status answered, or 0 when nothing was. */
104
+ readonly status: number;
105
+ /** What the server said, as text. */
106
+ readonly body: string;
107
+
108
+ /**
109
+ * A failed request, with what the server answered.
110
+ * @param message - What failed, and why.
111
+ * @param status - The status answered, or 0 when nothing was.
112
+ * @param body - What the server said.
113
+ */
114
+ constructor(message: string, status: number, body: string) {
115
+ super(message);
116
+ this.name = 'MoleculesError';
117
+ this.status = status;
118
+ this.body = body;
119
+ }
120
+ }