react-cheminfo 0.22.0 → 0.24.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 (464) hide show
  1. package/README.md +51 -28
  2. package/lib/chrome/ui/HeaderToggle.d.ts +52 -0
  3. package/lib/chrome/ui/HeaderToggle.d.ts.map +1 -0
  4. package/lib/chrome/ui/HeaderToggle.js +31 -0
  5. package/lib/chrome/ui/HeaderToggle.js.map +1 -0
  6. package/lib/chrome/ui/index.d.ts +2 -0
  7. package/lib/chrome/ui/index.d.ts.map +1 -1
  8. package/lib/chrome/ui/index.js +1 -0
  9. package/lib/chrome/ui/index.js.map +1 -1
  10. package/lib/citation/core/gfn2Paper.d.ts +10 -0
  11. package/lib/citation/core/gfn2Paper.d.ts.map +1 -0
  12. package/lib/citation/core/gfn2Paper.js +28 -0
  13. package/lib/citation/core/gfn2Paper.js.map +1 -0
  14. package/lib/citation/core/index.d.ts +1 -0
  15. package/lib/citation/core/index.d.ts.map +1 -1
  16. package/lib/citation/core/index.js +1 -0
  17. package/lib/citation/core/index.js.map +1 -1
  18. package/lib/clipboard/ui/ClickToCopy.d.ts +8 -7
  19. package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
  20. package/lib/clipboard/ui/ClickToCopy.js +3 -3
  21. package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
  22. package/lib/conformers.d.ts +27 -0
  23. package/lib/conformers.d.ts.map +1 -0
  24. package/lib/conformers.js +19 -0
  25. package/lib/conformers.js.map +1 -0
  26. package/lib/core.d.ts +1 -0
  27. package/lib/core.d.ts.map +1 -1
  28. package/lib/core.js +1 -0
  29. package/lib/core.js.map +1 -1
  30. package/lib/credits/core/credits.d.ts +12 -0
  31. package/lib/credits/core/credits.d.ts.map +1 -1
  32. package/lib/credits/core/credits.js +14 -0
  33. package/lib/credits/core/credits.js.map +1 -1
  34. package/lib/ecosystem/core/index.d.ts +1 -1
  35. package/lib/ecosystem/core/index.d.ts.map +1 -1
  36. package/lib/ecosystem/core/index.js.map +1 -1
  37. package/lib/ecosystem/core/sites.d.ts +11 -1
  38. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  39. package/lib/ecosystem/core/sites.js +7 -2
  40. package/lib/ecosystem/core/sites.js.map +1 -1
  41. package/lib/ecosystem/ui/EcosystemLinks.d.ts.map +1 -1
  42. package/lib/ecosystem/ui/EcosystemLinks.js +3 -1
  43. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  44. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  45. package/lib/ecosystem/ui/SiteTile.js +3 -1
  46. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  47. package/lib/format/core/index.d.ts +1 -1
  48. package/lib/format/core/index.d.ts.map +1 -1
  49. package/lib/format/core/index.js +1 -1
  50. package/lib/format/core/index.js.map +1 -1
  51. package/lib/format/core/words.d.ts +9 -0
  52. package/lib/format/core/words.d.ts.map +1 -1
  53. package/lib/format/core/words.js +16 -0
  54. package/lib/format/core/words.js.map +1 -1
  55. package/lib/language/core/index.d.ts +3 -0
  56. package/lib/language/core/index.d.ts.map +1 -0
  57. package/lib/language/core/index.js +3 -0
  58. package/lib/language/core/index.js.map +1 -0
  59. package/lib/language/core/languageName.d.ts +8 -0
  60. package/lib/language/core/languageName.d.ts.map +1 -0
  61. package/lib/language/core/languageName.js +16 -0
  62. package/lib/language/core/languageName.js.map +1 -0
  63. package/lib/language/core/languageParam.d.ts +35 -0
  64. package/lib/language/core/languageParam.d.ts.map +1 -0
  65. package/lib/language/core/languageParam.js +67 -0
  66. package/lib/language/core/languageParam.js.map +1 -0
  67. package/lib/language/ui/SiteLanguage.d.ts +20 -0
  68. package/lib/language/ui/SiteLanguage.d.ts.map +1 -0
  69. package/lib/language/ui/SiteLanguage.js +14 -0
  70. package/lib/language/ui/SiteLanguage.js.map +1 -0
  71. package/lib/language/ui/index.d.ts +4 -0
  72. package/lib/language/ui/index.d.ts.map +1 -0
  73. package/lib/language/ui/index.js +3 -0
  74. package/lib/language/ui/index.js.map +1 -0
  75. package/lib/language/ui/siteLanguageContext.d.ts +12 -0
  76. package/lib/language/ui/siteLanguageContext.d.ts.map +1 -0
  77. package/lib/language/ui/siteLanguageContext.js +19 -0
  78. package/lib/language/ui/siteLanguageContext.js.map +1 -0
  79. package/lib/orbital/core/atomicOrbitals.d.ts +9 -1
  80. package/lib/orbital/core/atomicOrbitals.d.ts.map +1 -1
  81. package/lib/orbital/core/atomicOrbitals.js +7 -0
  82. package/lib/orbital/core/atomicOrbitals.js.map +1 -1
  83. package/lib/orbital/core/hydrogenic.d.ts +2 -1
  84. package/lib/orbital/core/hydrogenic.d.ts.map +1 -1
  85. package/lib/orbital/core/hydrogenic.js +2 -1
  86. package/lib/orbital/core/hydrogenic.js.map +1 -1
  87. package/lib/orbital/core/index.d.ts +1 -0
  88. package/lib/orbital/core/index.d.ts.map +1 -1
  89. package/lib/orbital/core/index.js +1 -0
  90. package/lib/orbital/core/index.js.map +1 -1
  91. package/lib/orbital/core/slaterEnergy.d.ts +35 -0
  92. package/lib/orbital/core/slaterEnergy.d.ts.map +1 -0
  93. package/lib/orbital/core/slaterEnergy.js +66 -0
  94. package/lib/orbital/core/slaterEnergy.js.map +1 -0
  95. package/lib/overlay/core/index.d.ts +2 -2
  96. package/lib/overlay/core/index.d.ts.map +1 -1
  97. package/lib/overlay/core/index.js +1 -1
  98. package/lib/overlay/core/index.js.map +1 -1
  99. package/lib/overlay/core/overlayMarks.d.ts +20 -5
  100. package/lib/overlay/core/overlayMarks.d.ts.map +1 -1
  101. package/lib/overlay/core/overlayMarks.js +31 -5
  102. package/lib/overlay/core/overlayMarks.js.map +1 -1
  103. package/lib/overlay/ui/OverlayLegendMark.js +5 -0
  104. package/lib/overlay/ui/OverlayLegendMark.js.map +1 -1
  105. package/lib/projection/core/index.d.ts +4 -4
  106. package/lib/projection/core/index.d.ts.map +1 -1
  107. package/lib/projection/core/index.js +2 -2
  108. package/lib/projection/core/index.js.map +1 -1
  109. package/lib/projection/core/projectionCopy.d.ts +2 -0
  110. package/lib/projection/core/projectionCopy.d.ts.map +1 -1
  111. package/lib/projection/core/projectionCopy.js +1 -0
  112. package/lib/projection/core/projectionCopy.js.map +1 -1
  113. package/lib/projection/core/projectionGroupings.d.ts +44 -0
  114. package/lib/projection/core/projectionGroupings.d.ts.map +1 -0
  115. package/lib/projection/core/projectionGroupings.js +132 -0
  116. package/lib/projection/core/projectionGroupings.js.map +1 -0
  117. package/lib/projection/core/projectionOptions.d.ts +16 -6
  118. package/lib/projection/core/projectionOptions.d.ts.map +1 -1
  119. package/lib/projection/core/projectionOptions.js +7 -1
  120. package/lib/projection/core/projectionOptions.js.map +1 -1
  121. package/lib/projection/core/projectionPanelWords.d.ts +6 -0
  122. package/lib/projection/core/projectionPanelWords.d.ts.map +1 -1
  123. package/lib/projection/core/projectionPanelWords.js +4 -0
  124. package/lib/projection/core/projectionPanelWords.js.map +1 -1
  125. package/lib/projection/core/projectionSamples.d.ts +63 -32
  126. package/lib/projection/core/projectionSamples.d.ts.map +1 -1
  127. package/lib/projection/core/projectionSamples.js +1 -80
  128. package/lib/projection/core/projectionSamples.js.map +1 -1
  129. package/lib/projection/core/projectionStrings.d.ts +2 -0
  130. package/lib/projection/core/projectionStrings.d.ts.map +1 -1
  131. package/lib/projection/core/projectionStrings.js +10 -1
  132. package/lib/projection/core/projectionStrings.js.map +1 -1
  133. package/lib/projection/core/resolveProjectionOptions.d.ts +8 -3
  134. package/lib/projection/core/resolveProjectionOptions.d.ts.map +1 -1
  135. package/lib/projection/core/resolveProjectionOptions.js +58 -5
  136. package/lib/projection/core/resolveProjectionOptions.js.map +1 -1
  137. package/lib/projection/ui/ProjectionBar.d.ts +1 -1
  138. package/lib/projection/ui/ProjectionBar.d.ts.map +1 -1
  139. package/lib/projection/ui/ProjectionBar.js +3 -1
  140. package/lib/projection/ui/ProjectionBar.js.map +1 -1
  141. package/lib/projection/ui/ProjectionGroupingPickers.d.ts +38 -0
  142. package/lib/projection/ui/ProjectionGroupingPickers.d.ts.map +1 -0
  143. package/lib/projection/ui/ProjectionGroupingPickers.js +33 -0
  144. package/lib/projection/ui/ProjectionGroupingPickers.js.map +1 -0
  145. package/lib/projection/ui/ProjectionMapControls.d.ts +6 -7
  146. package/lib/projection/ui/ProjectionMapControls.d.ts.map +1 -1
  147. package/lib/projection/ui/ProjectionMapControls.js +11 -9
  148. package/lib/projection/ui/ProjectionMapControls.js.map +1 -1
  149. package/lib/projection/ui/ProjectionMapLegend.d.ts.map +1 -1
  150. package/lib/projection/ui/ProjectionMapLegend.js +1 -1
  151. package/lib/projection/ui/ProjectionMapLegend.js.map +1 -1
  152. package/lib/projection/ui/ProjectionMapMore.d.ts +2 -2
  153. package/lib/projection/ui/ProjectionMapMore.d.ts.map +1 -1
  154. package/lib/projection/ui/ProjectionMapMore.js +7 -5
  155. package/lib/projection/ui/ProjectionMapMore.js.map +1 -1
  156. package/lib/projection/ui/ProjectionMapTab.d.ts +15 -6
  157. package/lib/projection/ui/ProjectionMapTab.d.ts.map +1 -1
  158. package/lib/projection/ui/ProjectionMapTab.js +11 -7
  159. package/lib/projection/ui/ProjectionMapTab.js.map +1 -1
  160. package/lib/projection/ui/ProjectionPairsMore.d.ts +3 -7
  161. package/lib/projection/ui/ProjectionPairsMore.d.ts.map +1 -1
  162. package/lib/projection/ui/ProjectionPairsMore.js +4 -5
  163. package/lib/projection/ui/ProjectionPairsMore.js.map +1 -1
  164. package/lib/projection/ui/ProjectionPairsTab.d.ts.map +1 -1
  165. package/lib/projection/ui/ProjectionPairsTab.js +2 -2
  166. package/lib/projection/ui/ProjectionPairsTab.js.map +1 -1
  167. package/lib/projection/ui/ProjectionPanel.d.ts +1 -1
  168. package/lib/projection/ui/ProjectionPanel.d.ts.map +1 -1
  169. package/lib/projection/ui/ProjectionPanel.js +1 -1
  170. package/lib/projection/ui/ProjectionPanel.js.map +1 -1
  171. package/lib/projection/ui/ProjectionReadout.d.ts +7 -1
  172. package/lib/projection/ui/ProjectionReadout.d.ts.map +1 -1
  173. package/lib/projection/ui/ProjectionReadout.js +19 -7
  174. package/lib/projection/ui/ProjectionReadout.js.map +1 -1
  175. package/lib/projection/ui/ProjectionSpaceControls.d.ts +3 -5
  176. package/lib/projection/ui/ProjectionSpaceControls.d.ts.map +1 -1
  177. package/lib/projection/ui/ProjectionSpaceControls.js +9 -7
  178. package/lib/projection/ui/ProjectionSpaceControls.js.map +1 -1
  179. package/lib/projection/ui/ProjectionSpaceMore.d.ts +2 -2
  180. package/lib/projection/ui/ProjectionSpaceMore.d.ts.map +1 -1
  181. package/lib/projection/ui/ProjectionSpaceMore.js +5 -4
  182. package/lib/projection/ui/ProjectionSpaceMore.js.map +1 -1
  183. package/lib/projection/ui/ProjectionSpaceTab.d.ts +11 -3
  184. package/lib/projection/ui/ProjectionSpaceTab.d.ts.map +1 -1
  185. package/lib/projection/ui/ProjectionSpaceTab.js +7 -4
  186. package/lib/projection/ui/ProjectionSpaceTab.js.map +1 -1
  187. package/lib/projection/ui/ProjectionViewer.d.ts.map +1 -1
  188. package/lib/projection/ui/ProjectionViewer.js +1 -0
  189. package/lib/projection/ui/ProjectionViewer.js.map +1 -1
  190. package/lib/projection/ui/projectionBarReadings.d.ts +4 -1
  191. package/lib/projection/ui/projectionBarReadings.d.ts.map +1 -1
  192. package/lib/projection/ui/projectionBarReadings.js +14 -4
  193. package/lib/projection/ui/projectionBarReadings.js.map +1 -1
  194. package/lib/projection/ui/projectionBarSlots.d.ts +4 -2
  195. package/lib/projection/ui/projectionBarSlots.d.ts.map +1 -1
  196. package/lib/projection/ui/projectionBarSlots.js +3 -7
  197. package/lib/projection/ui/projectionBarSlots.js.map +1 -1
  198. package/lib/projection/ui/projectionMapChoices.d.ts +31 -6
  199. package/lib/projection/ui/projectionMapChoices.d.ts.map +1 -1
  200. package/lib/projection/ui/projectionMapChoices.js +58 -9
  201. package/lib/projection/ui/projectionMapChoices.js.map +1 -1
  202. package/lib/projection/ui/projectionMapChrome.d.ts +3 -9
  203. package/lib/projection/ui/projectionMapChrome.d.ts.map +1 -1
  204. package/lib/projection/ui/projectionMapChrome.js +41 -27
  205. package/lib/projection/ui/projectionMapChrome.js.map +1 -1
  206. package/lib/projection/ui/projectionMapCorner.d.ts +25 -0
  207. package/lib/projection/ui/projectionMapCorner.d.ts.map +1 -0
  208. package/lib/projection/ui/projectionMapCorner.js +46 -0
  209. package/lib/projection/ui/projectionMapCorner.js.map +1 -0
  210. package/lib/projection/ui/projectionMapModel.d.ts +9 -18
  211. package/lib/projection/ui/projectionMapModel.d.ts.map +1 -1
  212. package/lib/projection/ui/projectionMapModel.js +14 -39
  213. package/lib/projection/ui/projectionMapModel.js.map +1 -1
  214. package/lib/projection/ui/projectionMapView.d.ts +3 -1
  215. package/lib/projection/ui/projectionMapView.d.ts.map +1 -1
  216. package/lib/projection/ui/projectionMapView.js +9 -4
  217. package/lib/projection/ui/projectionMapView.js.map +1 -1
  218. package/lib/projection/ui/projectionSelectionSentence.d.ts +10 -0
  219. package/lib/projection/ui/projectionSelectionSentence.d.ts.map +1 -0
  220. package/lib/projection/ui/projectionSelectionSentence.js +18 -0
  221. package/lib/projection/ui/projectionSelectionSentence.js.map +1 -0
  222. package/lib/projection/ui/projectionStateApi.d.ts +47 -0
  223. package/lib/projection/ui/projectionStateApi.d.ts.map +1 -0
  224. package/lib/projection/ui/projectionStateApi.js +9 -0
  225. package/lib/projection/ui/projectionStateApi.js.map +1 -0
  226. package/lib/projection/ui/projectionTabModels.js +1 -1
  227. package/lib/projection/ui/projectionTabModels.js.map +1 -1
  228. package/lib/projection/ui/useProjectionState.d.ts +1 -29
  229. package/lib/projection/ui/useProjectionState.d.ts.map +1 -1
  230. package/lib/projection/ui/useProjectionState.js +13 -5
  231. package/lib/projection/ui/useProjectionState.js.map +1 -1
  232. package/lib/scatter/core/index.d.ts +1 -0
  233. package/lib/scatter/core/index.d.ts.map +1 -1
  234. package/lib/scatter/core/index.js +1 -0
  235. package/lib/scatter/core/index.js.map +1 -1
  236. package/lib/scatter/core/pointShape.d.ts +18 -0
  237. package/lib/scatter/core/pointShape.d.ts.map +1 -0
  238. package/lib/scatter/core/pointShape.js +70 -0
  239. package/lib/scatter/core/pointShape.js.map +1 -0
  240. package/lib/scatter/ui/ScatterPlot.d.ts.map +1 -1
  241. package/lib/scatter/ui/ScatterPlot.js +3 -2
  242. package/lib/scatter/ui/ScatterPlot.js.map +1 -1
  243. package/lib/scatter/ui/ScatterPointLayer.d.ts +14 -1
  244. package/lib/scatter/ui/ScatterPointLayer.d.ts.map +1 -1
  245. package/lib/scatter/ui/ScatterPointLayer.js +15 -3
  246. package/lib/scatter/ui/ScatterPointLayer.js.map +1 -1
  247. package/lib/scatter/ui/scatterFigureProps.d.ts +13 -0
  248. package/lib/scatter/ui/scatterFigureProps.d.ts.map +1 -1
  249. package/lib/scatter/ui/scatterMarkGlyph.d.ts +2 -1
  250. package/lib/scatter/ui/scatterMarkGlyph.d.ts.map +1 -1
  251. package/lib/scatter/ui/scatterMarkGlyph.js +7 -1
  252. package/lib/scatter/ui/scatterMarkGlyph.js.map +1 -1
  253. package/lib/scatter3d/ui/ScatterCloud.d.ts.map +1 -1
  254. package/lib/scatter3d/ui/ScatterCloud.js +2 -1
  255. package/lib/scatter3d/ui/ScatterCloud.js.map +1 -1
  256. package/lib/shared/ui/MenuButton.d.ts +3 -2
  257. package/lib/shared/ui/MenuButton.d.ts.map +1 -1
  258. package/lib/shared/ui/MenuButton.js +1 -1
  259. package/lib/shared/ui/MenuButton.js.map +1 -1
  260. package/lib/structure/core/conformerMinimise.d.ts +36 -0
  261. package/lib/structure/core/conformerMinimise.d.ts.map +1 -0
  262. package/lib/structure/core/conformerMinimise.js +81 -0
  263. package/lib/structure/core/conformerMinimise.js.map +1 -0
  264. package/lib/structure/core/conformerMinimum.d.ts +62 -0
  265. package/lib/structure/core/conformerMinimum.d.ts.map +1 -0
  266. package/lib/structure/core/conformerMinimum.js +90 -0
  267. package/lib/structure/core/conformerMinimum.js.map +1 -0
  268. package/lib/structure/core/conformerOptions.d.ts +62 -0
  269. package/lib/structure/core/conformerOptions.d.ts.map +1 -0
  270. package/lib/structure/core/conformerOptions.js +83 -0
  271. package/lib/structure/core/conformerOptions.js.map +1 -0
  272. package/lib/structure/core/conformerRefine.d.ts +104 -0
  273. package/lib/structure/core/conformerRefine.d.ts.map +1 -0
  274. package/lib/structure/core/conformerRefine.js +130 -0
  275. package/lib/structure/core/conformerRefine.js.map +1 -0
  276. package/lib/structure/core/conformerRefineRank.d.ts +36 -0
  277. package/lib/structure/core/conformerRefineRank.d.ts.map +1 -0
  278. package/lib/structure/core/conformerRefineRank.js +69 -0
  279. package/lib/structure/core/conformerRefineRank.js.map +1 -0
  280. package/lib/structure/core/conformerSession.d.ts +50 -0
  281. package/lib/structure/core/conformerSession.d.ts.map +1 -0
  282. package/lib/structure/core/conformerSession.js +88 -0
  283. package/lib/structure/core/conformerSession.js.map +1 -0
  284. package/lib/structure/core/conformerShape.d.ts +36 -0
  285. package/lib/structure/core/conformerShape.d.ts.map +1 -0
  286. package/lib/structure/core/conformerShape.js +150 -0
  287. package/lib/structure/core/conformerShape.js.map +1 -0
  288. package/lib/structure/core/conformers.d.ts +107 -0
  289. package/lib/structure/core/conformers.d.ts.map +1 -0
  290. package/lib/structure/core/conformers.js +149 -0
  291. package/lib/structure/core/conformers.js.map +1 -0
  292. package/lib/structure/core/geometryRelaxer.d.ts +66 -0
  293. package/lib/structure/core/geometryRelaxer.d.ts.map +1 -0
  294. package/lib/structure/core/geometryRelaxer.js +2 -0
  295. package/lib/structure/core/geometryRelaxer.js.map +1 -0
  296. package/lib/structure/core/index.d.ts +4 -0
  297. package/lib/structure/core/index.d.ts.map +1 -1
  298. package/lib/structure/core/index.js +2 -0
  299. package/lib/structure/core/index.js.map +1 -1
  300. package/lib/structure/core/moleculeCoordinates.d.ts +31 -0
  301. package/lib/structure/core/moleculeCoordinates.d.ts.map +1 -0
  302. package/lib/structure/core/moleculeCoordinates.js +80 -0
  303. package/lib/structure/core/moleculeCoordinates.js.map +1 -0
  304. package/lib/structure/core/molfileExport.d.ts +42 -0
  305. package/lib/structure/core/molfileExport.d.ts.map +1 -0
  306. package/lib/structure/core/molfileExport.js +47 -0
  307. package/lib/structure/core/molfileExport.js.map +1 -0
  308. package/lib/structure/core/oclResources.d.ts +12 -0
  309. package/lib/structure/core/oclResources.d.ts.map +1 -0
  310. package/lib/structure/core/oclResources.js +35 -0
  311. package/lib/structure/core/oclResources.js.map +1 -0
  312. package/lib/translate/core/catalog.d.ts +61 -0
  313. package/lib/translate/core/catalog.d.ts.map +1 -0
  314. package/lib/translate/core/catalog.js +49 -0
  315. package/lib/translate/core/catalog.js.map +1 -0
  316. package/lib/translate/core/checkTranslation.d.ts +32 -0
  317. package/lib/translate/core/checkTranslation.d.ts.map +1 -0
  318. package/lib/translate/core/checkTranslation.js +98 -0
  319. package/lib/translate/core/checkTranslation.js.map +1 -0
  320. package/lib/translate/core/contribution.d.ts +88 -0
  321. package/lib/translate/core/contribution.d.ts.map +1 -0
  322. package/lib/translate/core/contribution.js +14 -0
  323. package/lib/translate/core/contribution.js.map +1 -0
  324. package/lib/translate/core/index.d.ts +19 -0
  325. package/lib/translate/core/index.d.ts.map +1 -0
  326. package/lib/translate/core/index.js +15 -0
  327. package/lib/translate/core/index.js.map +1 -0
  328. package/lib/translate/core/marker.d.ts +45 -0
  329. package/lib/translate/core/marker.d.ts.map +1 -0
  330. package/lib/translate/core/marker.js +79 -0
  331. package/lib/translate/core/marker.js.map +1 -0
  332. package/lib/translate/core/mergeMessages.d.ts +35 -0
  333. package/lib/translate/core/mergeMessages.d.ts.map +1 -0
  334. package/lib/translate/core/mergeMessages.js +69 -0
  335. package/lib/translate/core/mergeMessages.js.map +1 -0
  336. package/lib/translate/core/session.d.ts +102 -0
  337. package/lib/translate/core/session.d.ts.map +1 -0
  338. package/lib/translate/core/session.js +162 -0
  339. package/lib/translate/core/session.js.map +1 -0
  340. package/lib/translate/core/start.d.ts +70 -0
  341. package/lib/translate/core/start.d.ts.map +1 -0
  342. package/lib/translate/core/start.js +73 -0
  343. package/lib/translate/core/start.js.map +1 -0
  344. package/lib/translate/core/suggestions.d.ts +77 -0
  345. package/lib/translate/core/suggestions.d.ts.map +1 -0
  346. package/lib/translate/core/suggestions.js +143 -0
  347. package/lib/translate/core/suggestions.js.map +1 -0
  348. package/lib/translate/core/tables.d.ts +100 -0
  349. package/lib/translate/core/tables.d.ts.map +1 -0
  350. package/lib/translate/core/tables.js +51 -0
  351. package/lib/translate/core/tables.js.map +1 -0
  352. package/lib/translate.d.ts +2 -0
  353. package/lib/translate.d.ts.map +1 -0
  354. package/lib/translate.js +6 -0
  355. package/lib/translate.js.map +1 -0
  356. package/lib/ui.d.ts +1 -0
  357. package/lib/ui.d.ts.map +1 -1
  358. package/lib/ui.js +1 -0
  359. package/lib/ui.js.map +1 -1
  360. package/lib/xtb/core/xtbRelaxer.d.ts +61 -0
  361. package/lib/xtb/core/xtbRelaxer.d.ts.map +1 -0
  362. package/lib/xtb/core/xtbRelaxer.js +108 -0
  363. package/lib/xtb/core/xtbRelaxer.js.map +1 -0
  364. package/lib/xtb.d.ts +11 -0
  365. package/lib/xtb.d.ts.map +1 -0
  366. package/lib/xtb.js +10 -0
  367. package/lib/xtb.js.map +1 -0
  368. package/package.json +18 -11
  369. package/src/chrome/ui/HeaderToggle.tsx +100 -0
  370. package/src/chrome/ui/index.ts +2 -0
  371. package/src/citation/core/gfn2Paper.ts +32 -0
  372. package/src/citation/core/index.ts +1 -0
  373. package/src/clipboard/ui/ClickToCopy.tsx +8 -7
  374. package/src/conformers.ts +87 -0
  375. package/src/core.ts +1 -0
  376. package/src/credits/core/credits.ts +16 -0
  377. package/src/ecosystem/core/index.ts +1 -0
  378. package/src/ecosystem/core/sites.ts +20 -2
  379. package/src/ecosystem/ui/EcosystemLinks.tsx +3 -1
  380. package/src/ecosystem/ui/SiteTile.tsx +3 -1
  381. package/src/format/core/index.ts +1 -1
  382. package/src/format/core/words.ts +19 -0
  383. package/src/language/core/index.ts +7 -0
  384. package/src/language/core/languageName.ts +16 -0
  385. package/src/language/core/languageParam.ts +70 -0
  386. package/src/language/ui/SiteLanguage.tsx +26 -0
  387. package/src/language/ui/index.ts +3 -0
  388. package/src/language/ui/siteLanguageContext.ts +20 -0
  389. package/src/orbital/core/atomicOrbitals.ts +17 -1
  390. package/src/orbital/core/hydrogenic.ts +2 -1
  391. package/src/orbital/core/index.ts +1 -0
  392. package/src/orbital/core/slaterEnergy.ts +83 -0
  393. package/src/overlay/core/index.ts +6 -2
  394. package/src/overlay/core/overlayMarks.ts +51 -6
  395. package/src/overlay/ui/OverlayLegendMark.tsx +5 -0
  396. package/src/projection/core/index.ts +11 -3
  397. package/src/projection/core/projectionCopy.ts +3 -0
  398. package/src/projection/core/projectionGroupings.ts +174 -0
  399. package/src/projection/core/projectionOptions.ts +18 -7
  400. package/src/projection/core/projectionPanelWords.ts +10 -0
  401. package/src/projection/core/projectionSamples.ts +62 -120
  402. package/src/projection/core/projectionStrings.ts +12 -1
  403. package/src/projection/core/resolveProjectionOptions.ts +66 -4
  404. package/src/projection/ui/ProjectionBar.tsx +4 -2
  405. package/src/projection/ui/ProjectionGroupingPickers.tsx +91 -0
  406. package/src/projection/ui/ProjectionMapControls.tsx +29 -32
  407. package/src/projection/ui/ProjectionMapLegend.tsx +1 -1
  408. package/src/projection/ui/ProjectionMapMore.tsx +14 -4
  409. package/src/projection/ui/ProjectionMapTab.tsx +27 -9
  410. package/src/projection/ui/ProjectionPairsMore.tsx +12 -21
  411. package/src/projection/ui/ProjectionPairsTab.tsx +5 -2
  412. package/src/projection/ui/ProjectionPanel.tsx +7 -3
  413. package/src/projection/ui/ProjectionReadout.tsx +28 -8
  414. package/src/projection/ui/ProjectionSpaceControls.tsx +20 -27
  415. package/src/projection/ui/ProjectionSpaceMore.tsx +12 -3
  416. package/src/projection/ui/ProjectionSpaceTab.tsx +23 -6
  417. package/src/projection/ui/ProjectionViewer.tsx +1 -0
  418. package/src/projection/ui/projectionBarReadings.ts +24 -8
  419. package/src/projection/ui/projectionBarSlots.tsx +10 -9
  420. package/src/projection/ui/projectionMapChoices.ts +71 -14
  421. package/src/projection/ui/projectionMapChrome.ts +55 -30
  422. package/src/projection/ui/projectionMapCorner.ts +67 -0
  423. package/src/projection/ui/projectionMapModel.ts +20 -59
  424. package/src/projection/ui/projectionMapView.ts +15 -8
  425. package/src/projection/ui/projectionSelectionSentence.ts +22 -0
  426. package/src/projection/ui/projectionStateApi.ts +57 -0
  427. package/src/projection/ui/projectionTabModels.ts +1 -1
  428. package/src/projection/ui/useProjectionState.ts +33 -37
  429. package/src/scatter/core/index.ts +1 -0
  430. package/src/scatter/core/pointShape.ts +80 -0
  431. package/src/scatter/ui/ScatterPlot.tsx +4 -1
  432. package/src/scatter/ui/ScatterPointLayer.tsx +39 -11
  433. package/src/scatter/ui/scatterFigureProps.ts +13 -0
  434. package/src/scatter/ui/scatterMarkGlyph.tsx +9 -1
  435. package/src/scatter3d/ui/ScatterCloud.tsx +3 -0
  436. package/src/shared/ui/MenuButton.tsx +4 -3
  437. package/src/structure/core/conformerMinimise.ts +99 -0
  438. package/src/structure/core/conformerMinimum.ts +125 -0
  439. package/src/structure/core/conformerOptions.ts +125 -0
  440. package/src/structure/core/conformerRefine.ts +234 -0
  441. package/src/structure/core/conformerRefineRank.ts +89 -0
  442. package/src/structure/core/conformerSession.ts +123 -0
  443. package/src/structure/core/conformerShape.ts +181 -0
  444. package/src/structure/core/conformers.ts +282 -0
  445. package/src/structure/core/geometryRelaxer.ts +71 -0
  446. package/src/structure/core/index.ts +13 -0
  447. package/src/structure/core/moleculeCoordinates.ts +93 -0
  448. package/src/structure/core/molfileExport.ts +62 -0
  449. package/src/structure/core/oclResources.ts +41 -0
  450. package/src/translate/core/catalog.ts +83 -0
  451. package/src/translate/core/checkTranslation.ts +128 -0
  452. package/src/translate/core/contribution.ts +99 -0
  453. package/src/translate/core/index.ts +72 -0
  454. package/src/translate/core/marker.ts +85 -0
  455. package/src/translate/core/mergeMessages.ts +74 -0
  456. package/src/translate/core/session.ts +250 -0
  457. package/src/translate/core/start.ts +121 -0
  458. package/src/translate/core/suggestions.ts +211 -0
  459. package/src/translate/core/tables.ts +120 -0
  460. package/src/translate.ts +5 -0
  461. package/src/ui.ts +1 -0
  462. package/src/xtb/core/xtbRelaxer.ts +160 -0
  463. package/src/xtb.ts +16 -0
  464. package/styles/chrome.css +61 -30
@@ -0,0 +1,282 @@
1
+ import type { Molecule } from 'openchemlib';
2
+
3
+ import { ordinal } from '../../format/core/words.ts';
4
+
5
+ import { minimiseConformer, rankByEnergy } from './conformerMinimise.ts';
6
+ import { isKeptMinimum, minimisedShapes } from './conformerMinimum.ts';
7
+ import type {
8
+ ConformerOptions,
9
+ MinimisationAlgorithm,
10
+ } from './conformerOptions.ts';
11
+ import type {
12
+ ConformerRefinement,
13
+ ConformerSetRefinement,
14
+ } from './conformerRefine.ts';
15
+ import type { ConformerSession } from './conformerSession.ts';
16
+ import {
17
+ keepConformerSession,
18
+ openConformerSession,
19
+ readPotentialCount,
20
+ } from './conformerSession.ts';
21
+ import type { ConformerShape } from './conformerShape.ts';
22
+ import { conformerShape, hasFiniteCoordinates } from './conformerShape.ts';
23
+ import type { MolfileExport } from './molfileExport.ts';
24
+ import { toMolfileExport } from './molfileExport.ts';
25
+
26
+ export { strategyConstant } from './conformerSession.ts';
27
+
28
+ /** One conformer of the input structure, ready to display and to export. */
29
+ export interface Conformer {
30
+ /** 1-based position in {@link ConformerSet.conformers}. */
31
+ id: number;
32
+ /** The 3D structure, as a molfile the viewer can parse. */
33
+ molfile: MolfileExport;
34
+ /** Total force-field energy in kcal/mol, `null` when it was not computed. */
35
+ energy: number | null;
36
+ /** Energy above the lowest conformer of the set, `null` without an energy. */
37
+ relativeEnergy: number | null;
38
+ /**
39
+ * What a better method said about this conformer, once `refineConformers` has
40
+ * relaxed it. `null` until then, which is what a plain force-field run leaves.
41
+ * @default null
42
+ */
43
+ refinement: ConformerRefinement | null;
44
+ }
45
+
46
+ /**
47
+ * Which energies a set is ordered by: the force field's own, or the ones a
48
+ * refinement pass produced.
49
+ */
50
+ export type ConformerRanking = 'force-field' | 'refined';
51
+
52
+ /** Why {@link generateConformers} stopped asking for more conformers. */
53
+ export type StopReason = 'exhausted' | 'count' | 'timeout';
54
+
55
+ /** The complete outcome of one conformer run. */
56
+ export interface ConformerSet {
57
+ /** The conformers kept, most stable first; one without an energy follows every one that has one. */
58
+ conformers: Conformer[];
59
+ /** OpenChemLib's estimate of the reachable conformers, `-1` when unavailable. */
60
+ potentialConformerCount: number;
61
+ /** Which of the three limits ended the run. */
62
+ stoppedBy: StopReason;
63
+ /** Wall-clock duration of the run, initialisation and continuations included. */
64
+ elapsedMilliseconds: number;
65
+ /** Plain sentences about conformers that were dropped or left unminimised. */
66
+ warnings: string[];
67
+ /** The force field that was asked for, echoed so a reader knows what the energies mean. */
68
+ minimisation: MinimisationAlgorithm;
69
+ /** Conformers the generator handed back, dropped ones included: where a continuation resumes. */
70
+ produced: number;
71
+ /** The options of the run, so a continuation draws from the same sequence. */
72
+ options: ConformerOptions;
73
+ /** Which of the two energies {@link ConformerSet.conformers} is ordered by. */
74
+ rankedBy: ConformerRanking;
75
+ /**
76
+ * What the refinement pass did, `null` for a set no better method has seen.
77
+ * @default null
78
+ */
79
+ refinement: ConformerSetRefinement | null;
80
+ }
81
+
82
+ /** The two options a continuation takes from the caller rather than from the run. */
83
+ export type ConformerLimits = Pick<
84
+ ConformerOptions,
85
+ 'maxConformers' | 'timeoutSeconds'
86
+ >;
87
+
88
+ /**
89
+ * Generate conformers of a structure, optionally relaxing each one with MMFF94.
90
+ *
91
+ * The caller's molecule is never touched: the run works on a compact copy that
92
+ * receives the explicit hydrogens the generator needs.
93
+ *
94
+ * The run ends on the first of three limits — the generator runs out of new
95
+ * torsion sets, `maxConformers` conformers are in hand, or the time budget is
96
+ * spent. **A timeout is not an error**: whatever was produced is returned, with
97
+ * `stoppedBy` saying why there is not more.
98
+ *
99
+ * The budget covers the whole call, initialisation included, and is read again
100
+ * once a conformer is in hand, so no further minimisation starts past the
101
+ * deadline. The one step already running cannot be cut short, so a caller
102
+ * waiting from another thread must allow one step on top of `timeoutSeconds`.
103
+ *
104
+ * Minimisation is best-effort: a conformer MMFF94 refuses is kept with a `null`
105
+ * energy and a warning rather than lost. A minimised conformer that lands in a
106
+ * minimum already kept, such as the flipped copy of a cyclohexane chair, is
107
+ * not kept a second time; the mirror image of a chiral minimum, such as the
108
+ * second gauche butane, is a minimum of its own.
109
+ * @param molecule - Structure to embed. Not mutated.
110
+ * @param options - Strategy, limits, seed and force field.
111
+ * @param now - Clock used for the time budget, injectable for tests.
112
+ * @returns Every conformer kept, most stable first, with relative energies and any warnings.
113
+ * @throws {Error} When the structure is empty or OpenChemLib refuses to initialise it.
114
+ */
115
+ export function generateConformers(
116
+ molecule: Molecule,
117
+ options: ConformerOptions,
118
+ now: () => number = defaultClock,
119
+ ): ConformerSet {
120
+ return runConformers(molecule, options, null, now);
121
+ }
122
+
123
+ /**
124
+ * Ask the run that produced `previous` for more conformers.
125
+ *
126
+ * The continuation draws from the same seeded sequence with the same force
127
+ * field, so the result is the set a single larger run would have produced:
128
+ * the new conformers are ranked among the previous ones, the ids follow that
129
+ * order, and every relative energy is measured again from the lowest of all.
130
+ * A refined set cannot be extended: its molfiles hold the relaxed geometries
131
+ * while its `energy` fields still hold the force field's numbers, so the two
132
+ * would no longer describe one conformer and the duplicate check would compare
133
+ * shapes against energies that do not belong to them. Generate a larger set and
134
+ * refine that instead.
135
+ * @param molecule - The structure `previous` was generated from. Not mutated.
136
+ * @param previous - The set to extend. Not mutated.
137
+ * @param limits - How many more conformers to find, and the time budget of this call.
138
+ * @param now - Clock used for the time budget, injectable for tests.
139
+ * @returns The extended set, its duration the sum of both runs.
140
+ * @throws {Error} When the structure is empty, when `previous` has been refined,
141
+ * or when OpenChemLib refuses to initialise it.
142
+ */
143
+ export function continueConformers(
144
+ molecule: Molecule,
145
+ previous: ConformerSet,
146
+ limits: ConformerLimits,
147
+ now: () => number = defaultClock,
148
+ ): ConformerSet {
149
+ const options: ConformerOptions = {
150
+ ...previous.options,
151
+ maxConformers: limits.maxConformers,
152
+ timeoutSeconds: limits.timeoutSeconds,
153
+ };
154
+ return runConformers(molecule, options, previous, now);
155
+ }
156
+
157
+ function defaultClock(): number {
158
+ return performance.now();
159
+ }
160
+
161
+ interface Accumulator {
162
+ conformers: Conformer[];
163
+ /** Shape of each conformer, `null` for one without an energy. */
164
+ shapes: Array<ConformerShape | null>;
165
+ warnings: string[];
166
+ }
167
+
168
+ function runConformers(
169
+ molecule: Molecule,
170
+ options: ConformerOptions,
171
+ previous: ConformerSet | null,
172
+ now: () => number,
173
+ ): ConformerSet {
174
+ if (previous?.refinement != null) {
175
+ throw new Error(
176
+ `This set was refined with ${previous.refinement.method}, so it cannot be extended. Generate a larger set, then refine it again.`,
177
+ );
178
+ }
179
+ const prepared = molecule.getCompactCopy();
180
+ prepared.addImplicitHydrogens();
181
+ if (prepared.getAllAtoms() === 0) {
182
+ throw new Error('The structure is empty: there is nothing to embed in 3D.');
183
+ }
184
+
185
+ // Setting up the torsion sets is the slow half of a flexible run — seconds on
186
+ // a long chain — so it is inside both the budget and the reported duration.
187
+ const start = now();
188
+ const session = openConformerSession(
189
+ prepared,
190
+ options,
191
+ previous?.produced ?? 0,
192
+ );
193
+ const potentialConformerCount =
194
+ previous?.potentialConformerCount ?? readPotentialCount(session);
195
+ const conformers =
196
+ previous === null ? [] : copyConformers(previous.conformers);
197
+ const into: Accumulator = {
198
+ conformers,
199
+ shapes: minimisedShapes(conformers),
200
+ warnings: previous === null ? [] : [...previous.warnings],
201
+ };
202
+ const budget = Math.max(options.timeoutSeconds * 1000, 0);
203
+ const stoppedBy = collect(
204
+ session,
205
+ options,
206
+ into.conformers.length + options.maxConformers,
207
+ () => now() - start >= budget,
208
+ into,
209
+ );
210
+ keepConformerSession(prepared, options, session);
211
+
212
+ return {
213
+ conformers: rankByEnergy(into.conformers),
214
+ potentialConformerCount,
215
+ stoppedBy,
216
+ elapsedMilliseconds: (previous?.elapsedMilliseconds ?? 0) + now() - start,
217
+ warnings: into.warnings,
218
+ minimisation: options.minimisation,
219
+ produced: session.produced,
220
+ options,
221
+ rankedBy: 'force-field',
222
+ refinement: null,
223
+ };
224
+ }
225
+
226
+ function collect(
227
+ session: ConformerSession,
228
+ options: ConformerOptions,
229
+ target: number,
230
+ spent: () => boolean,
231
+ into: Accumulator,
232
+ ): StopReason {
233
+ while (true) {
234
+ if (into.conformers.length >= target) return 'count';
235
+ if (spent()) return 'timeout';
236
+ const conformer =
237
+ session.pending ?? session.generator.getNextConformerAsMolecule();
238
+ session.pending = null;
239
+ if (conformer === null) return 'exhausted';
240
+ // Minimisation runs to completion once entered, so a conformer that arrives
241
+ // past the deadline is kept aside for a continuation rather than bought now.
242
+ if (spent()) {
243
+ session.pending = conformer;
244
+ return 'timeout';
245
+ }
246
+ session.produced++;
247
+ if (!hasFiniteCoordinates(conformer)) {
248
+ into.warnings.push(
249
+ `The ${ordinal(session.produced)} conformer produced was dropped: the generator placed some of its atoms at non-finite coordinates.`,
250
+ );
251
+ continue;
252
+ }
253
+ const energy = minimiseConformer(
254
+ conformer,
255
+ options,
256
+ session.produced,
257
+ into.warnings,
258
+ );
259
+ const shape = energy === null ? null : conformerShape(conformer);
260
+ if (
261
+ energy !== null &&
262
+ shape !== null &&
263
+ isKeptMinimum(energy, shape, into.conformers, into.shapes)
264
+ ) {
265
+ continue;
266
+ }
267
+ into.conformers.push({
268
+ id: into.conformers.length + 1,
269
+ molfile: toMolfileExport(conformer),
270
+ energy,
271
+ relativeEnergy: null,
272
+ refinement: null,
273
+ });
274
+ into.shapes.push(shape);
275
+ }
276
+ }
277
+
278
+ function copyConformers(conformers: readonly Conformer[]): Conformer[] {
279
+ const copies: Conformer[] = [];
280
+ for (const conformer of conformers) copies.push({ ...conformer });
281
+ return copies;
282
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * A geometry a relaxer is handed: element symbols plus flat Cartesian
3
+ * coordinates in ångström, `x,y,z` per atom.
4
+ */
5
+ export interface RelaxableGeometry {
6
+ /** Element symbol per atom, explicit hydrogens included. */
7
+ elements: string[];
8
+ /** Flat `x,y,z` per atom in ångström, length `3 · elements.length`. */
9
+ coordinates: Float64Array;
10
+ }
11
+
12
+ /** What a relaxer reports for one structure. */
13
+ export interface RelaxedGeometry {
14
+ /**
15
+ * The relaxed coordinates, in the input's atom order. Translated freely;
16
+ * never rotated, which is what lets {@link RelaxedGeometry} be compared with
17
+ * the geometry it came from by removing both centroids.
18
+ */
19
+ coordinates: Float64Array;
20
+ /**
21
+ * Total energy at `coordinates`, **in kcal/mol**, so it can be read against a
22
+ * force-field energy without a second unit in the UI.
23
+ */
24
+ energy: number;
25
+ /**
26
+ * The dispersion term of `energy`, kcal/mol, or `null` from a method that has
27
+ * none. It is the part a force field of the MMFF94 era does not model at all,
28
+ * and a large part of why conformers re-rank.
29
+ * @default null
30
+ */
31
+ dispersionEnergy: number | null;
32
+ /** Optimizer cycles spent. `0` when there was nothing to relax. */
33
+ cycles: number;
34
+ /** Whether the optimizer met its convergence criteria. */
35
+ converged: boolean;
36
+ /** Plain sentences about anything the caller should know. */
37
+ warnings: string[];
38
+ }
39
+
40
+ /** How a relaxation run is watched and cancelled. */
41
+ export interface RelaxerOptions {
42
+ /**
43
+ * Called as each structure finishes, so a caller can show progress over a
44
+ * batch that runs for seconds.
45
+ * @default undefined
46
+ */
47
+ onSettled?: (done: number, total: number) => void;
48
+ /**
49
+ * Gives the run up. A relaxer is not obliged to be able to interrupt a
50
+ * structure already in flight.
51
+ * @default undefined
52
+ */
53
+ signal?: AbortSignal;
54
+ }
55
+
56
+ /**
57
+ * Something that relaxes geometries with a real electronic structure behind it,
58
+ * and reports the energy **at the geometry it returns**.
59
+ *
60
+ * This is the seam between a site and the semi-empirical engine: nothing in
61
+ * `react-cheminfo/core` imports one, so a site that never refines a geometry
62
+ * downloads no WebAssembly. `xtbRelaxer` from `react-cheminfo/xtb` is the
63
+ * implementation, GFN2-xTB through `xtb-wasm`.
64
+ *
65
+ * An implementation must return one result per request, in request order, and
66
+ * must keep each structure's atom order.
67
+ */
68
+ export type GeometryRelaxer = (
69
+ geometries: readonly RelaxableGeometry[],
70
+ options?: RelaxerOptions,
71
+ ) => Promise<RelaxedGeometry[]>;
@@ -34,12 +34,25 @@ export type { IdCodeValue } from './editorValue.ts';
34
34
  export { isEmptyIdCode, splitEditorValue, splitIdCode } from './editorValue.ts';
35
35
  export type { FragmentQuery } from './fragmentQuery.ts';
36
36
  export { fragmentQuery, sameFragmentQuery } from './fragmentQuery.ts';
37
+ export type {
38
+ GeometryRelaxer,
39
+ RelaxableGeometry,
40
+ RelaxedGeometry,
41
+ RelaxerOptions,
42
+ } from './geometryRelaxer.ts';
43
+ export {
44
+ centredRmsd,
45
+ readRelaxableGeometry,
46
+ writeRelaxedCoordinates,
47
+ } from './moleculeCoordinates.ts';
37
48
  export type { MolfileClassification, MolfileVersion } from './molfile.ts';
38
49
  export {
39
50
  classifyMolfile,
40
51
  looksLikeMolfile,
41
52
  molfileAtomCount,
42
53
  } from './molfile.ts';
54
+ export type { MolfileExport } from './molfileExport.ts';
55
+ export { readMolfileExport, toMolfileExport } from './molfileExport.ts';
43
56
  export type { ReadStructureResult, StructureKind } from './readStructure.ts';
44
57
  export { looksLikeSmarts, readStructure } from './readStructure.ts';
45
58
  export type { StructureError } from './structureError.ts';
@@ -0,0 +1,93 @@
1
+ import type { Molecule } from 'openchemlib';
2
+
3
+ import type { RelaxableGeometry } from './geometryRelaxer.ts';
4
+
5
+ /**
6
+ * Read the elements and 3D coordinates of a molecule into the flat form an
7
+ * engine takes.
8
+ * @param molecule - A molecule carrying 3D coordinates. Not modified.
9
+ * @returns Its geometry in ångström, one entry per atom of `getAllAtoms()`.
10
+ */
11
+ export function readRelaxableGeometry(molecule: Molecule): RelaxableGeometry {
12
+ const atoms = molecule.getAllAtoms();
13
+ const elements = new Array<string>(atoms);
14
+ const coordinates = new Float64Array(atoms * 3);
15
+ for (let atom = 0; atom < atoms; atom++) {
16
+ elements[atom] = molecule.getAtomLabel(atom);
17
+ coordinates[atom * 3] = molecule.getAtomX(atom);
18
+ coordinates[atom * 3 + 1] = molecule.getAtomY(atom);
19
+ coordinates[atom * 3 + 2] = molecule.getAtomZ(atom);
20
+ }
21
+ return { elements, coordinates };
22
+ }
23
+
24
+ /**
25
+ * Write flat coordinates back onto a molecule, atom for atom.
26
+ * @param molecule - The molecule to move. Mutated.
27
+ * @param coordinates - Flat `x,y,z` per atom in ångström.
28
+ * @throws {Error} When there is not one position per atom.
29
+ */
30
+ export function writeRelaxedCoordinates(
31
+ molecule: Molecule,
32
+ coordinates: Float64Array,
33
+ ): void {
34
+ const atoms = molecule.getAllAtoms();
35
+ if (coordinates.length !== atoms * 3) {
36
+ throw new Error(
37
+ `The relaxed geometry has ${coordinates.length / 3} positions for ${atoms} atoms.`,
38
+ );
39
+ }
40
+ for (let atom = 0; atom < atoms; atom++) {
41
+ molecule.setAtomX(atom, coordinates[atom * 3] as number);
42
+ molecule.setAtomY(atom, coordinates[atom * 3 + 1] as number);
43
+ molecule.setAtomZ(atom, coordinates[atom * 3 + 2] as number);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Root-mean-square displacement between two geometries of the same atoms, each
49
+ * taken about its own centroid, in ångström.
50
+ *
51
+ * Removing the centroids is what makes the number mean "how far the atoms
52
+ * moved" rather than "how far the molecule was translated": a relaxer is free
53
+ * to recentre a molecule, and the `GeometryRelaxer` contract forbids it to
54
+ * rotate one.
55
+ * @param before - Flat coordinates before.
56
+ * @param after - Flat coordinates after.
57
+ * @returns The RMSD in ångström, `0` for an empty geometry.
58
+ * @throws {Error} When the two do not hold the same number of atoms.
59
+ */
60
+ export function centredRmsd(before: Float64Array, after: Float64Array): number {
61
+ if (before.length !== after.length) {
62
+ throw new Error(
63
+ `Cannot compare ${before.length / 3} positions with ${after.length / 3}.`,
64
+ );
65
+ }
66
+ const atoms = before.length / 3;
67
+ if (atoms === 0) return 0;
68
+ const centreBefore = centroid(before, atoms);
69
+ const centreAfter = centroid(after, atoms);
70
+ let total = 0;
71
+ for (let atom = 0; atom < atoms; atom++) {
72
+ for (let axis = 0; axis < 3; axis++) {
73
+ const gap =
74
+ (before[atom * 3 + axis] as number) -
75
+ (centreBefore[axis] as number) -
76
+ ((after[atom * 3 + axis] as number) - (centreAfter[axis] as number));
77
+ total += gap * gap;
78
+ }
79
+ }
80
+ return Math.sqrt(total / atoms);
81
+ }
82
+
83
+ function centroid(coordinates: Float64Array, atoms: number): Float64Array {
84
+ let x = 0;
85
+ let y = 0;
86
+ let z = 0;
87
+ for (let atom = 0; atom < atoms; atom++) {
88
+ x += coordinates[atom * 3] as number;
89
+ y += coordinates[atom * 3 + 1] as number;
90
+ z += coordinates[atom * 3 + 2] as number;
91
+ }
92
+ return new Float64Array([x / atoms, y / atoms, z / atoms]);
93
+ }
@@ -0,0 +1,62 @@
1
+ import type { Molecule } from 'openchemlib';
2
+
3
+ import { classifyMolfile } from './molfile.ts';
4
+
5
+ /** A molfile plus the molstar format id that can actually parse it. */
6
+ export interface MolfileExport {
7
+ /** molstar's format id: `mol` reads V2000, `sdf` reads V2000 and V3000. */
8
+ format: 'mol' | 'sdf';
9
+ /** The molfile text, exactly as OpenChemLib wrote it. */
10
+ data: string;
11
+ }
12
+
13
+ /**
14
+ * Serialise a molecule for the 3D viewer and for export.
15
+ *
16
+ * V2000 is written whenever it can be: its counts line holds three digits per
17
+ * field, so above 999 atoms OpenChemLib writes `?` where the count belongs and
18
+ * the file becomes unreadable. V3000 is used from that size on.
19
+ *
20
+ * Coordinates are emitted exactly as OpenChemLib writes them — the whole
21
+ * molecule is negated in y and z relative to `getAtomY/Z`, which is a rigid
22
+ * rotation and therefore invisible to the viewer, to the energies and to any
23
+ * other file consumer.
24
+ *
25
+ * Hydrogens are in the file only if they are explicit atoms, so call this on a
26
+ * conformer, which always carries them.
27
+ * @param molecule - Structure with 3D coordinates already set. Not mutated.
28
+ * @returns The molfile and the format id to hand molstar.
29
+ * @throws {Error} When the molfile carries no atoms.
30
+ */
31
+ export function toMolfileExport(molecule: Molecule): MolfileExport {
32
+ const data =
33
+ molecule.getAllAtoms() > V2000_MAX_ATOMS
34
+ ? molecule.toMolfileV3()
35
+ : molecule.toMolfile();
36
+ return readMolfileExport(data);
37
+ }
38
+
39
+ /**
40
+ * Pick the molstar format id for a molfile of unknown version, and refuse the
41
+ * ones that would render nothing.
42
+ *
43
+ * molstar's `mol` parser does not understand a V3000 CTAB: it returns zero atoms
44
+ * with `isError: false`, so the viewer shows an empty scene and reports no
45
+ * error. The version is read from the text rather than assumed from whichever
46
+ * writer produced it, because the text is the only thing molstar itself looks
47
+ * at.
48
+ * @param data - A molfile, V2000 or V3000.
49
+ * @returns The format id paired with the unchanged text.
50
+ * @throws {Error} When the molfile carries no atoms — the silent failure this guards.
51
+ */
52
+ export function readMolfileExport(data: string): MolfileExport {
53
+ const { version, atomCount } = classifyMolfile(data);
54
+ if (atomCount === 0) {
55
+ throw new Error(
56
+ 'Molfile has an empty atom block: molstar would render an empty scene without reporting an error.',
57
+ );
58
+ }
59
+ return { format: version === 'v3000' ? 'sdf' : 'mol', data };
60
+ }
61
+
62
+ const V2000_MAX_ATOMS = 999;
@@ -0,0 +1,41 @@
1
+ import { Resources } from 'openchemlib';
2
+
3
+ /**
4
+ * Register OpenChemLib's static resources once, without which
5
+ * `ConformerGenerator` and `ForceFieldMMFF94` throw on construction.
6
+ *
7
+ * Repeated calls share the first call's promise; a failed registration is
8
+ * forgotten so a later call can retry.
9
+ * @param url - Where to fetch `resources.json`. Omit under Node.js to read it
10
+ * from the installed package; in a browser or a worker it is required.
11
+ * @returns A promise that settles once the resources are usable.
12
+ */
13
+ export function registerResources(url?: string): Promise<void> {
14
+ registration ??= register(url).catch((error: unknown) => {
15
+ registration = null;
16
+ throw error;
17
+ });
18
+ return registration;
19
+ }
20
+
21
+ let registration: Promise<void> | null = null;
22
+
23
+ async function register(url?: string): Promise<void> {
24
+ if (url !== undefined) {
25
+ await Resources.registerFromUrl(url);
26
+ return;
27
+ }
28
+ const runtime = globalThis as { process?: { versions?: { node?: string } } };
29
+ if (runtime.process?.versions?.node === undefined) {
30
+ throw new Error(
31
+ 'registerResources needs a url outside Node.js: a browser page or worker cannot read resources.json from node_modules',
32
+ );
33
+ }
34
+ const { createRequire } = await import('node:module');
35
+ const require = createRequire(import.meta.url);
36
+ Resources.registerFromNodejs(
37
+ require
38
+ .resolve('openchemlib')
39
+ .replace(/openchemlib\.js$/, 'resources.json'),
40
+ );
41
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The shape of the messages a site or a library owns, and where they are kept.
3
+ *
4
+ * A catalog is one directory of a repository holding `en.json`, the source of
5
+ * truth, and one flat file per locale beside it. The site registers each of
6
+ * its catalogs with the repository and the directory, so a translation made
7
+ * anywhere on the page can be sent back to the file it belongs to.
8
+ */
9
+
10
+ /** Messages by key; every value is an ICU MessageFormat string. */
11
+ export type Messages = Record<string, string>;
12
+
13
+ /** The locale every catalog is written in first. */
14
+ export const SOURCE_LOCALE = 'en';
15
+
16
+ /** One catalog a page renders messages from. */
17
+ export interface CatalogSource {
18
+ /**
19
+ * The name the page knows the catalog by, unique on the page, e.g.
20
+ * `translate.cheminfo.org` or `react-cheminfo/share`.
21
+ */
22
+ id: string;
23
+ /** The GitHub repository the files live in, written `owner/repo`. */
24
+ repository: string;
25
+ /**
26
+ * The directory holding `en.json` and the locale files, relative to the
27
+ * repository root, e.g. `frontend/src/locales`.
28
+ */
29
+ directory: string;
30
+ /** The English messages. */
31
+ messages: Messages;
32
+ }
33
+
34
+ /** Which message of which catalog. */
35
+ export interface MessageRef {
36
+ /** The catalog, by the id the page registered it under. */
37
+ catalogId: string;
38
+ /** The key of the message in that catalog. */
39
+ key: string;
40
+ }
41
+
42
+ const DIRECTORY_SEGMENT = /^[\w-][\w.-]*$/;
43
+
44
+ /**
45
+ * The message a catalog holds under a key, never one inherited from
46
+ * `Object.prototype`: a key like `constructor` is only a message when the
47
+ * catalog defines it.
48
+ * @param messages - The catalog's messages.
49
+ * @param key - The key asked for.
50
+ * @returns The message, or `undefined` when the catalog has none.
51
+ */
52
+ export function ownMessage(
53
+ messages: Messages,
54
+ key: string,
55
+ ): string | undefined {
56
+ return Object.hasOwn(messages, key) ? messages[key] : undefined;
57
+ }
58
+
59
+ /**
60
+ * Whether a path can name a catalog directory: relative, without `.` or `..`
61
+ * segments, and ending in a directory called `locales`. The server only ever
62
+ * writes inside such a directory.
63
+ * @param value - The candidate path, e.g. `frontend/src/locales`.
64
+ * @returns True when the path is acceptable.
65
+ */
66
+ export function isCatalogDirectory(value: string): boolean {
67
+ const segments = value.split('/');
68
+ if (segments.at(-1) !== 'locales') return false;
69
+ for (const segment of segments) {
70
+ if (!DIRECTORY_SEGMENT.test(segment)) return false;
71
+ }
72
+ return true;
73
+ }
74
+
75
+ /**
76
+ * The file a catalog keeps one locale's messages in.
77
+ * @param directory - The catalog directory.
78
+ * @param locale - The locale.
79
+ * @returns The path, relative to the repository root.
80
+ */
81
+ export function catalogFile(directory: string, locale: string): string {
82
+ return `${directory}/${locale}.json`;
83
+ }