react-cheminfo 0.76.0 → 0.78.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 (389) hide show
  1. package/README.md +141 -31
  2. package/lib/card/core/cardAddress.d.ts +19 -2
  3. package/lib/card/core/cardAddress.d.ts.map +1 -1
  4. package/lib/card/core/cardAddress.js +35 -2
  5. package/lib/card/core/cardAddress.js.map +1 -1
  6. package/lib/card/core/cardPageUrl.d.ts +7 -1
  7. package/lib/card/core/cardPageUrl.d.ts.map +1 -1
  8. package/lib/card/core/cardPageUrl.js +4 -2
  9. package/lib/card/core/cardPageUrl.js.map +1 -1
  10. package/lib/card/core/index.d.ts +1 -1
  11. package/lib/card/core/index.d.ts.map +1 -1
  12. package/lib/card/core/index.js +1 -1
  13. package/lib/card/core/index.js.map +1 -1
  14. package/lib/credits/core/credits.d.ts +30 -0
  15. package/lib/credits/core/credits.d.ts.map +1 -1
  16. package/lib/credits/core/credits.js +35 -0
  17. package/lib/credits/core/credits.js.map +1 -1
  18. package/lib/download/core/downloadFigure.d.ts +12 -1
  19. package/lib/download/core/downloadFigure.d.ts.map +1 -1
  20. package/lib/download/core/downloadFigure.js +21 -0
  21. package/lib/download/core/downloadFigure.js.map +1 -1
  22. package/lib/download/core/figureDpi.d.ts +59 -0
  23. package/lib/download/core/figureDpi.d.ts.map +1 -0
  24. package/lib/download/core/figureDpi.js +75 -0
  25. package/lib/download/core/figureDpi.js.map +1 -0
  26. package/lib/download/core/figurePng.d.ts +4 -1
  27. package/lib/download/core/figurePng.d.ts.map +1 -1
  28. package/lib/download/core/figurePng.js +11 -2
  29. package/lib/download/core/figurePng.js.map +1 -1
  30. package/lib/download/core/index.d.ts +4 -1
  31. package/lib/download/core/index.d.ts.map +1 -1
  32. package/lib/download/core/index.js +3 -1
  33. package/lib/download/core/index.js.map +1 -1
  34. package/lib/download/core/pngDpi.d.ts +22 -0
  35. package/lib/download/core/pngDpi.d.ts.map +1 -0
  36. package/lib/download/core/pngDpi.js +79 -0
  37. package/lib/download/core/pngDpi.js.map +1 -0
  38. package/lib/download/ui/FigureDownloadPanel.d.ts +13 -0
  39. package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
  40. package/lib/download/ui/FigureDownloadPanel.js +18 -34
  41. package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
  42. package/lib/download/ui/figureDownloadHint.d.ts +5 -0
  43. package/lib/download/ui/figureDownloadHint.d.ts.map +1 -1
  44. package/lib/download/ui/figureDownloadHint.js +8 -0
  45. package/lib/download/ui/figureDownloadHint.js.map +1 -1
  46. package/lib/download/ui/figureDownloadOptions.d.ts +84 -0
  47. package/lib/download/ui/figureDownloadOptions.d.ts.map +1 -0
  48. package/lib/download/ui/figureDownloadOptions.js +2 -0
  49. package/lib/download/ui/figureDownloadOptions.js.map +1 -0
  50. package/lib/download/ui/resolutionChoices.d.ts +27 -0
  51. package/lib/download/ui/resolutionChoices.d.ts.map +1 -0
  52. package/lib/download/ui/resolutionChoices.js +48 -0
  53. package/lib/download/ui/resolutionChoices.js.map +1 -0
  54. package/lib/download/ui/useFigureActions.d.ts +4 -1
  55. package/lib/download/ui/useFigureActions.d.ts.map +1 -1
  56. package/lib/download/ui/useFigureActions.js +17 -8
  57. package/lib/download/ui/useFigureActions.js.map +1 -1
  58. package/lib/download/ui/useFigureDownload.d.ts +2 -55
  59. package/lib/download/ui/useFigureDownload.d.ts.map +1 -1
  60. package/lib/download/ui/useFigureDownload.js +45 -13
  61. package/lib/download/ui/useFigureDownload.js.map +1 -1
  62. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  63. package/lib/ecosystem/core/sites.js +14 -0
  64. package/lib/ecosystem/core/sites.js.map +1 -1
  65. package/lib/ecosystem/core/types.d.ts +1 -1
  66. package/lib/ecosystem/core/types.d.ts.map +1 -1
  67. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  68. package/lib/ecosystem/ui/glyphs.js +3 -0
  69. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  70. package/lib/host/core/connectHost.js +1 -1
  71. package/lib/host/core/connectHost.js.map +1 -1
  72. package/lib/host/core/connectTool.d.ts +103 -0
  73. package/lib/host/core/connectTool.d.ts.map +1 -0
  74. package/lib/host/core/connectTool.js +169 -0
  75. package/lib/host/core/connectTool.js.map +1 -0
  76. package/lib/host/core/hostOutputs.d.ts +16 -3
  77. package/lib/host/core/hostOutputs.d.ts.map +1 -1
  78. package/lib/host/core/hostOutputs.js +38 -4
  79. package/lib/host/core/hostOutputs.js.map +1 -1
  80. package/lib/host/core/index.d.ts +8 -2
  81. package/lib/host/core/index.d.ts.map +1 -1
  82. package/lib/host/core/index.js +4 -1
  83. package/lib/host/core/index.js.map +1 -1
  84. package/lib/host/core/kinds.d.ts +31 -3
  85. package/lib/host/core/kinds.d.ts.map +1 -1
  86. package/lib/host/core/kinds.js +35 -4
  87. package/lib/host/core/kinds.js.map +1 -1
  88. package/lib/host/core/messageValues.d.ts +29 -0
  89. package/lib/host/core/messageValues.d.ts.map +1 -0
  90. package/lib/host/core/messageValues.js +57 -0
  91. package/lib/host/core/messageValues.js.map +1 -0
  92. package/lib/host/core/protocol.d.ts +2 -5
  93. package/lib/host/core/protocol.d.ts.map +1 -1
  94. package/lib/host/core/protocol.js +3 -37
  95. package/lib/host/core/protocol.js.map +1 -1
  96. package/lib/host/core/resultKinds.d.ts +74 -0
  97. package/lib/host/core/resultKinds.d.ts.map +1 -0
  98. package/lib/host/core/resultKinds.js +40 -0
  99. package/lib/host/core/resultKinds.js.map +1 -0
  100. package/lib/host/core/toolMessages.d.ts +24 -0
  101. package/lib/host/core/toolMessages.d.ts.map +1 -0
  102. package/lib/host/core/toolMessages.js +136 -0
  103. package/lib/host/core/toolMessages.js.map +1 -0
  104. package/lib/host/ui/index.d.ts +2 -0
  105. package/lib/host/ui/index.d.ts.map +1 -1
  106. package/lib/host/ui/index.js +1 -0
  107. package/lib/host/ui/index.js.map +1 -1
  108. package/lib/host/ui/useFramedTool.d.ts +74 -0
  109. package/lib/host/ui/useFramedTool.d.ts.map +1 -0
  110. package/lib/host/ui/useFramedTool.js +125 -0
  111. package/lib/host/ui/useFramedTool.js.map +1 -0
  112. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  113. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  114. package/lib/locales/de.json +30 -1
  115. package/lib/locales/en.json +30 -1
  116. package/lib/locales/es.json +30 -1
  117. package/lib/locales/fr.json +30 -1
  118. package/lib/locales/it.json +30 -1
  119. package/lib/molecule3d/ui/Molecule3DStage.d.ts +4 -33
  120. package/lib/molecule3d/ui/Molecule3DStage.d.ts.map +1 -1
  121. package/lib/molecule3d/ui/Molecule3DStage.js +3 -37
  122. package/lib/molecule3d/ui/Molecule3DStage.js.map +1 -1
  123. package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
  124. package/lib/molecule3d/ui/MoleculeCanvas3D.js +10 -2
  125. package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
  126. package/lib/molecule3d/ui/exportMoleculeImage.d.ts +10 -0
  127. package/lib/molecule3d/ui/exportMoleculeImage.d.ts.map +1 -1
  128. package/lib/molecule3d/ui/exportMoleculeImage.js +17 -0
  129. package/lib/molecule3d/ui/exportMoleculeImage.js.map +1 -1
  130. package/lib/molecule3d/ui/index.d.ts +1 -1
  131. package/lib/molecule3d/ui/index.d.ts.map +1 -1
  132. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +23 -0
  133. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  134. package/lib/molecule3d/ui/useImageExport.d.ts +3 -0
  135. package/lib/molecule3d/ui/useImageExport.d.ts.map +1 -1
  136. package/lib/molecule3d/ui/useImageExport.js +21 -3
  137. package/lib/molecule3d/ui/useImageExport.js.map +1 -1
  138. package/lib/osiris/core/barGeometry.d.ts +42 -0
  139. package/lib/osiris/core/barGeometry.d.ts.map +1 -0
  140. package/lib/osiris/core/barGeometry.js +46 -0
  141. package/lib/osiris/core/barGeometry.js.map +1 -0
  142. package/lib/osiris/core/computeProperties.d.ts +42 -0
  143. package/lib/osiris/core/computeProperties.d.ts.map +1 -0
  144. package/lib/osiris/core/computeProperties.js +115 -0
  145. package/lib/osiris/core/computeProperties.js.map +1 -0
  146. package/lib/osiris/core/constants.d.ts +70 -0
  147. package/lib/osiris/core/constants.d.ts.map +1 -0
  148. package/lib/osiris/core/constants.js +99 -0
  149. package/lib/osiris/core/constants.js.map +1 -0
  150. package/lib/osiris/core/fitness.d.ts +32 -0
  151. package/lib/osiris/core/fitness.d.ts.map +1 -0
  152. package/lib/osiris/core/fitness.js +48 -0
  153. package/lib/osiris/core/fitness.js.map +1 -0
  154. package/lib/osiris/core/index.d.ts +29 -0
  155. package/lib/osiris/core/index.d.ts.map +1 -0
  156. package/lib/osiris/core/index.js +19 -0
  157. package/lib/osiris/core/index.js.map +1 -0
  158. package/lib/osiris/core/poolSize.d.ts +17 -0
  159. package/lib/osiris/core/poolSize.d.ts.map +1 -0
  160. package/lib/osiris/core/poolSize.js +22 -0
  161. package/lib/osiris/core/poolSize.js.map +1 -0
  162. package/lib/osiris/core/poolTypes.d.ts +140 -0
  163. package/lib/osiris/core/poolTypes.d.ts.map +1 -0
  164. package/lib/osiris/core/poolTypes.js +12 -0
  165. package/lib/osiris/core/poolTypes.js.map +1 -0
  166. package/lib/osiris/core/predictIdCode.d.ts +39 -0
  167. package/lib/osiris/core/predictIdCode.d.ts.map +1 -0
  168. package/lib/osiris/core/predictIdCode.js +54 -0
  169. package/lib/osiris/core/predictIdCode.js.map +1 -0
  170. package/lib/osiris/core/predictProtocol.d.ts +67 -0
  171. package/lib/osiris/core/predictProtocol.d.ts.map +1 -0
  172. package/lib/osiris/core/predictProtocol.js +29 -0
  173. package/lib/osiris/core/predictProtocol.js.map +1 -0
  174. package/lib/osiris/core/predictionPool.d.ts +23 -0
  175. package/lib/osiris/core/predictionPool.d.ts.map +1 -0
  176. package/lib/osiris/core/predictionPool.js +186 -0
  177. package/lib/osiris/core/predictionPool.js.map +1 -0
  178. package/lib/osiris/core/predictionQueue.d.ts +46 -0
  179. package/lib/osiris/core/predictionQueue.d.ts.map +1 -0
  180. package/lib/osiris/core/predictionQueue.js +57 -0
  181. package/lib/osiris/core/predictionQueue.js.map +1 -0
  182. package/lib/osiris/core/predictors.d.ts +62 -0
  183. package/lib/osiris/core/predictors.d.ts.map +1 -0
  184. package/lib/osiris/core/predictors.js +100 -0
  185. package/lib/osiris/core/predictors.js.map +1 -0
  186. package/lib/osiris/core/propertyKeys.d.ts +32 -0
  187. package/lib/osiris/core/propertyKeys.d.ts.map +1 -0
  188. package/lib/osiris/core/propertyKeys.js +44 -0
  189. package/lib/osiris/core/propertyKeys.js.map +1 -0
  190. package/lib/osiris/core/riskAppearance.d.ts +60 -0
  191. package/lib/osiris/core/riskAppearance.d.ts.map +1 -0
  192. package/lib/osiris/core/riskAppearance.js +59 -0
  193. package/lib/osiris/core/riskAppearance.js.map +1 -0
  194. package/lib/osiris/core/riskDetail.d.ts +22 -0
  195. package/lib/osiris/core/riskDetail.d.ts.map +1 -0
  196. package/lib/osiris/core/riskDetail.js +86 -0
  197. package/lib/osiris/core/riskDetail.js.map +1 -0
  198. package/lib/osiris/core/riskDetailRequest.d.ts +31 -0
  199. package/lib/osiris/core/riskDetailRequest.d.ts.map +1 -0
  200. package/lib/osiris/core/riskDetailRequest.js +49 -0
  201. package/lib/osiris/core/riskDetailRequest.js.map +1 -0
  202. package/lib/osiris/core/riskFindings.d.ts +26 -0
  203. package/lib/osiris/core/riskFindings.d.ts.map +1 -0
  204. package/lib/osiris/core/riskFindings.js +79 -0
  205. package/lib/osiris/core/riskFindings.js.map +1 -0
  206. package/lib/osiris/core/runPredictionJob.d.ts +20 -0
  207. package/lib/osiris/core/runPredictionJob.d.ts.map +1 -0
  208. package/lib/osiris/core/runPredictionJob.js +43 -0
  209. package/lib/osiris/core/runPredictionJob.js.map +1 -0
  210. package/lib/osiris/core/scales.d.ts +70 -0
  211. package/lib/osiris/core/scales.d.ts.map +1 -0
  212. package/lib/osiris/core/scales.js +185 -0
  213. package/lib/osiris/core/scales.js.map +1 -0
  214. package/lib/osiris/core/types.d.ts +91 -0
  215. package/lib/osiris/core/types.d.ts.map +1 -0
  216. package/lib/osiris/core/types.js +19 -0
  217. package/lib/osiris/core/types.js.map +1 -0
  218. package/lib/osiris/core/valuation.d.ts +28 -0
  219. package/lib/osiris/core/valuation.d.ts.map +1 -0
  220. package/lib/osiris/core/valuation.js +39 -0
  221. package/lib/osiris/core/valuation.js.map +1 -0
  222. package/lib/osiris/ui/PropertyBar.d.ts +27 -0
  223. package/lib/osiris/ui/PropertyBar.d.ts.map +1 -0
  224. package/lib/osiris/ui/PropertyBar.js +27 -0
  225. package/lib/osiris/ui/PropertyBar.js.map +1 -0
  226. package/lib/osiris/ui/PropertyPanel.d.ts +91 -0
  227. package/lib/osiris/ui/PropertyPanel.d.ts.map +1 -0
  228. package/lib/osiris/ui/PropertyPanel.js +77 -0
  229. package/lib/osiris/ui/PropertyPanel.js.map +1 -0
  230. package/lib/osiris/ui/PropertyRows.d.ts +40 -0
  231. package/lib/osiris/ui/PropertyRows.d.ts.map +1 -0
  232. package/lib/osiris/ui/PropertyRows.js +23 -0
  233. package/lib/osiris/ui/PropertyRows.js.map +1 -0
  234. package/lib/osiris/ui/RiskFindings.d.ts +43 -0
  235. package/lib/osiris/ui/RiskFindings.d.ts.map +1 -0
  236. package/lib/osiris/ui/RiskFindings.js +51 -0
  237. package/lib/osiris/ui/RiskFindings.js.map +1 -0
  238. package/lib/osiris/ui/RiskPanel.d.ts +46 -0
  239. package/lib/osiris/ui/RiskPanel.d.ts.map +1 -0
  240. package/lib/osiris/ui/RiskPanel.js +32 -0
  241. package/lib/osiris/ui/RiskPanel.js.map +1 -0
  242. package/lib/osiris/ui/RiskSquare.d.ts +51 -0
  243. package/lib/osiris/ui/RiskSquare.d.ts.map +1 -0
  244. package/lib/osiris/ui/RiskSquare.js +23 -0
  245. package/lib/osiris/ui/RiskSquare.js.map +1 -0
  246. package/lib/osiris/ui/index.d.ts +15 -0
  247. package/lib/osiris/ui/index.d.ts.map +1 -0
  248. package/lib/osiris/ui/index.js +8 -0
  249. package/lib/osiris/ui/index.js.map +1 -0
  250. package/lib/osiris/ui/usePredictions.d.ts +81 -0
  251. package/lib/osiris/ui/usePredictions.d.ts.map +1 -0
  252. package/lib/osiris/ui/usePredictions.js +102 -0
  253. package/lib/osiris/ui/usePredictions.js.map +1 -0
  254. package/lib/osiris-ui.d.ts +11 -0
  255. package/lib/osiris-ui.d.ts.map +1 -0
  256. package/lib/osiris-ui.js +11 -0
  257. package/lib/osiris-ui.js.map +1 -0
  258. package/lib/osiris.d.ts +17 -0
  259. package/lib/osiris.d.ts.map +1 -0
  260. package/lib/osiris.js +17 -0
  261. package/lib/osiris.js.map +1 -0
  262. package/lib/panel/ui/FilterInput.d.ts.map +1 -1
  263. package/lib/panel/ui/FilterInput.js +3 -1
  264. package/lib/panel/ui/FilterInput.js.map +1 -1
  265. package/lib/panel/ui/SidePanelItem.d.ts +39 -0
  266. package/lib/panel/ui/SidePanelItem.d.ts.map +1 -0
  267. package/lib/panel/ui/SidePanelItem.js +63 -0
  268. package/lib/panel/ui/SidePanelItem.js.map +1 -0
  269. package/lib/panel/ui/SidePanelStack.d.ts +11 -10
  270. package/lib/panel/ui/SidePanelStack.d.ts.map +1 -1
  271. package/lib/panel/ui/SidePanelStack.js +22 -15
  272. package/lib/panel/ui/SidePanelStack.js.map +1 -1
  273. package/lib/panel/ui/SpectrumColorSwatch.d.ts.map +1 -1
  274. package/lib/panel/ui/SpectrumColorSwatch.js +4 -2
  275. package/lib/panel/ui/SpectrumColorSwatch.js.map +1 -1
  276. package/lib/panel/ui/usePanelFolds.d.ts +35 -0
  277. package/lib/panel/ui/usePanelFolds.d.ts.map +1 -0
  278. package/lib/panel/ui/usePanelFolds.js +73 -0
  279. package/lib/panel/ui/usePanelFolds.js.map +1 -0
  280. package/lib/shared/ui/FullscreenStage.d.ts +43 -0
  281. package/lib/shared/ui/FullscreenStage.d.ts.map +1 -0
  282. package/lib/shared/ui/FullscreenStage.js +38 -0
  283. package/lib/shared/ui/FullscreenStage.js.map +1 -0
  284. package/lib/shared/ui/canFillScreen.d.ts +7 -0
  285. package/lib/shared/ui/canFillScreen.d.ts.map +1 -0
  286. package/lib/shared/ui/canFillScreen.js +9 -0
  287. package/lib/shared/ui/canFillScreen.js.map +1 -0
  288. package/lib/shared/ui/index.d.ts +3 -0
  289. package/lib/shared/ui/index.d.ts.map +1 -1
  290. package/lib/shared/ui/index.js +2 -0
  291. package/lib/shared/ui/index.js.map +1 -1
  292. package/lib/split/ui/splitPanes.d.ts +3 -3
  293. package/lib/split/ui/splitPanes.js +1 -1
  294. package/lib/structure/core/structureNotations.d.ts +8 -1
  295. package/lib/structure/core/structureNotations.d.ts.map +1 -1
  296. package/lib/structure/core/structureNotations.js +14 -8
  297. package/lib/structure/core/structureNotations.js.map +1 -1
  298. package/lib/structure/ui/StructureExportPanel.d.ts +8 -0
  299. package/lib/structure/ui/StructureExportPanel.d.ts.map +1 -1
  300. package/lib/structure/ui/StructureExportPanel.js +9 -4
  301. package/lib/structure/ui/StructureExportPanel.js.map +1 -1
  302. package/lib/structure/ui/index.d.ts +1 -0
  303. package/lib/structure/ui/index.d.ts.map +1 -1
  304. package/lib/structure/ui/index.js.map +1 -1
  305. package/package.json +4 -1
  306. package/src/card/core/cardAddress.ts +39 -3
  307. package/src/card/core/cardPageUrl.ts +10 -3
  308. package/src/card/core/index.ts +7 -1
  309. package/src/credits/core/credits.ts +40 -0
  310. package/src/download/core/downloadFigure.ts +26 -1
  311. package/src/download/core/figureDpi.ts +94 -0
  312. package/src/download/core/figurePng.ts +11 -2
  313. package/src/download/core/index.ts +13 -1
  314. package/src/download/core/pngDpi.ts +84 -0
  315. package/src/download/ui/FigureDownloadPanel.tsx +41 -51
  316. package/src/download/ui/figureDownloadHint.ts +13 -0
  317. package/src/download/ui/figureDownloadOptions.ts +85 -0
  318. package/src/download/ui/resolutionChoices.ts +67 -0
  319. package/src/download/ui/useFigureActions.ts +24 -9
  320. package/src/download/ui/useFigureDownload.tsx +57 -71
  321. package/src/ecosystem/core/sites.ts +14 -0
  322. package/src/ecosystem/core/types.ts +2 -1
  323. package/src/ecosystem/ui/glyphs.tsx +20 -0
  324. package/src/host/core/connectHost.ts +1 -1
  325. package/src/host/core/connectTool.ts +285 -0
  326. package/src/host/core/hostOutputs.ts +47 -5
  327. package/src/host/core/index.ts +20 -1
  328. package/src/host/core/kinds.ts +53 -8
  329. package/src/host/core/messageValues.ts +58 -0
  330. package/src/host/core/protocol.ts +5 -37
  331. package/src/host/core/resultKinds.ts +65 -0
  332. package/src/host/core/toolMessages.ts +160 -0
  333. package/src/host/ui/index.ts +6 -0
  334. package/src/host/ui/useFramedTool.ts +213 -0
  335. package/src/locales/de.json +30 -1
  336. package/src/locales/en.json +30 -1
  337. package/src/locales/es.json +30 -1
  338. package/src/locales/fr.json +30 -1
  339. package/src/locales/it.json +30 -1
  340. package/src/molecule3d/ui/Molecule3DStage.tsx +4 -88
  341. package/src/molecule3d/ui/MoleculeCanvas3D.tsx +10 -1
  342. package/src/molecule3d/ui/exportMoleculeImage.ts +22 -0
  343. package/src/molecule3d/ui/index.ts +4 -1
  344. package/src/molecule3d/ui/moleculeViewer3DProps.ts +24 -0
  345. package/src/molecule3d/ui/useImageExport.ts +28 -2
  346. package/src/osiris/core/barGeometry.ts +74 -0
  347. package/src/osiris/core/computeProperties.ts +175 -0
  348. package/src/osiris/core/constants.ts +110 -0
  349. package/src/osiris/core/fitness.ts +59 -0
  350. package/src/osiris/core/index.ts +78 -0
  351. package/src/osiris/core/poolSize.ts +24 -0
  352. package/src/osiris/core/poolTypes.ts +140 -0
  353. package/src/osiris/core/predictIdCode.ts +69 -0
  354. package/src/osiris/core/predictProtocol.ts +78 -0
  355. package/src/osiris/core/predictionPool.ts +237 -0
  356. package/src/osiris/core/predictionQueue.ts +89 -0
  357. package/src/osiris/core/predictors.ts +142 -0
  358. package/src/osiris/core/propertyKeys.ts +54 -0
  359. package/src/osiris/core/riskAppearance.ts +86 -0
  360. package/src/osiris/core/riskDetail.ts +120 -0
  361. package/src/osiris/core/riskDetailRequest.ts +64 -0
  362. package/src/osiris/core/riskFindings.ts +92 -0
  363. package/src/osiris/core/runPredictionJob.ts +49 -0
  364. package/src/osiris/core/scales.ts +236 -0
  365. package/src/osiris/core/types.ts +103 -0
  366. package/src/osiris/core/valuation.ts +44 -0
  367. package/src/osiris/ui/PropertyBar.tsx +77 -0
  368. package/src/osiris/ui/PropertyPanel.tsx +227 -0
  369. package/src/osiris/ui/PropertyRows.tsx +92 -0
  370. package/src/osiris/ui/RiskFindings.tsx +137 -0
  371. package/src/osiris/ui/RiskPanel.tsx +81 -0
  372. package/src/osiris/ui/RiskSquare.tsx +108 -0
  373. package/src/osiris/ui/index.ts +17 -0
  374. package/src/osiris/ui/usePredictions.ts +194 -0
  375. package/src/osiris-ui.ts +11 -0
  376. package/src/osiris.ts +17 -0
  377. package/src/panel/ui/FilterInput.tsx +4 -1
  378. package/src/panel/ui/SidePanelItem.tsx +162 -0
  379. package/src/panel/ui/SidePanelStack.tsx +29 -36
  380. package/src/panel/ui/SpectrumColorSwatch.tsx +5 -3
  381. package/src/panel/ui/usePanelFolds.ts +103 -0
  382. package/src/shared/ui/FullscreenStage.tsx +96 -0
  383. package/src/shared/ui/canFillScreen.ts +8 -0
  384. package/src/shared/ui/index.ts +6 -0
  385. package/src/split/ui/splitPanes.tsx +4 -4
  386. package/src/structure/core/structureNotations.ts +25 -8
  387. package/src/structure/ui/StructureExportPanel.tsx +23 -4
  388. package/src/structure/ui/index.ts +4 -0
  389. package/styles/osiris.css +339 -0
@@ -114,6 +114,14 @@
114
114
  "site.atoms.tagline": "Elettroni, neutroni, strutture di Lewis e numeri di ossidazione.",
115
115
  "site.moles.tagline": "Bilanciare una reazione e calcolarne la composizione in massa.",
116
116
  "site.inorganic.tagline": "Nominare un composto inorganico e scriverne la formula.",
117
+ "site.iupac-name.tagline": "Il nome IUPAC di una struttura, e la struttura che un nome designa.",
118
+ "site.slides.tagline": "Mettere uno strumento interattivo su una diapositiva, con il link del suo pulsante Condividi.",
119
+ "site.vibrations.tagline": "Spettri IR e Raman calcolati nel browser.",
120
+ "site.draw.tagline": "Strutture di qualità da pubblicazione, in un SVG che conserva la chimica.",
121
+ "site.molecules.tagline": "Cercare una molecola, le sue proprietà calcolate e le sue fonti.",
122
+ "site.chembio.tagline": "Prodotti naturali, e gli organismi in cui sono stati trovati.",
123
+ "site.wikidata.tagline": "La chimica delle infobox di Wikipedia, ricercabile per struttura.",
124
+ "site.mz.tagline": "Spettri di massa, classificati in base a come sono stati misurati.",
117
125
  "share.button": "Condividi",
118
126
  "share.buttonTitle": "Condividere un link a questa pagina, o incorporarla nel proprio sito",
119
127
  "share.dialogTitleFor": "Condividere o incorporare — {title}",
@@ -282,10 +290,14 @@
282
290
  "download.resolution": "Risoluzione",
283
291
  "download.resolutionHelp": "Quante volte la figura sullo schermo misura il file. Un PNG riceve altrettanti pixel in più: due va bene per una diapositiva, tre o quattro per la stampa. Un SVG resta nitido a qualsiasi dimensione, e si apre altrettante volte più grande.",
284
292
  "download.resolutionExample": "Una figura larga 640 pixel sullo schermo viene salvata larga 1280 pixel.",
293
+ "download.resolutionDpiHelp": "Punti per pollice, con la figura stampata alla sua dimensione sulla pagina. 150 basta per una diapositiva, 300 per le fotografie di una rivista, da 600 a 1200 per i disegni al tratto. Il PNG lo indica, così un documento lo colloca a quella dimensione.",
294
+ "download.resolutionDpiExample": "Una figura larga 8,5 cm viene salvata larga 1004 pixel.",
285
295
  "download.noFigure": "Non c'è ancora nessuna figura nella pagina da salvare.",
286
296
  "download.hintRasterSvg": "Un SVG che contiene un'immagine di {pixels}: una scena 3D non ha forma vettoriale.",
287
297
  "download.hintSvg": "Si apre a {pixels}, e resta nitido a qualsiasi dimensione.",
288
298
  "download.hintPng": "Salvato {pixels}.",
299
+ "download.hintSvgDpi": "Si stampa a {width} × {height} cm, e resta nitido a qualsiasi dimensione.",
300
+ "download.hintPngDpi": "Salvato {pixels}, che si stampano a {width} × {height} cm.",
289
301
  "download.hintCopied": "Copiato negli appunti: PNG di {pixels}.",
290
302
  "download.copyUnsupported": "Questo browser non può mettere un'immagine negli appunti. Salvala invece.",
291
303
  "download.size": "Dimensione",
@@ -794,5 +806,22 @@
794
806
  "ir.raman.doc.sampled": "Una banda è data nel punto campionato in cui raggiunge il massimo: la sua posizione non è più precisa della griglia su cui lo spettro è stato registrato.",
795
807
  "ir.raman.aboutLead": "Disegna uno spettro Raman, ne trova le bande e le elenca accanto al grafico.",
796
808
  "ir.raman.credit.picking": "**ir-spectrum** (cheminfo, MIT) trova le bande, con il rilevatore di picchi di **common-spectrum** e **ml-gsd**.",
797
- "ir.raman.credit.jcamp": "**convert-to-jcamp** (cheminfo, MIT) scrive il file JCAMP-DX scaricato."
809
+ "ir.raman.credit.jcamp": "**convert-to-jcamp** (cheminfo, MIT) scrive il file JCAMP-DX scaricato.",
810
+ "panel.focus": "Concentrati sul pannello {panel}",
811
+ "panel.focusTooltip": "Concentrati su questo pannello: comprimi tutti gli altri",
812
+ "panel.unfocusTooltip": "Espandi di nuovo gli altri pannelli",
813
+ "panel.fillScreen": "Mostra il pannello {panel} a schermo intero",
814
+ "panel.fillScreenTooltip": "Mostra questo pannello a schermo intero",
815
+ "panel.fold": "Comprimi il pannello {panel}",
816
+ "panel.unfold": "Espandi il pannello {panel}",
817
+ "panel.foldTooltip": "Comprimi questo pannello",
818
+ "panel.unfoldTooltip": "Espandilo",
819
+ "panel.close": "Chiudi il pannello {panel}",
820
+ "panel.closeTooltip": "Chiudi questo pannello",
821
+ "panel.leaveFullScreen": "Esci dallo schermo intero",
822
+ "panel.leaveFullScreenTooltip": "Esci dallo schermo intero (Esc)",
823
+ "panel.clearFilter": "Cancella il filtro",
824
+ "panel.colourOf": "Colore di {name}",
825
+ "panel.drawIn": "Disegna {name} in {color}",
826
+ "panel.changeColour": "Disegna questo spettro in un altro colore"
798
827
  }
@@ -1,92 +1,8 @@
1
1
  /**
2
2
  * The box the molecule canvas and its toolbars are drawn in, which is also the
3
- * box that fills the screen.
4
- *
5
- * A box filling the screen hides everything outside it, and the popovers and
6
- * tooltips of the toolbars are portalled to `document.body`: while the box
7
- * fills the screen they are portalled into it instead, the way react-science's
8
- * `RootLayout` keeps its own menus visible. Otherwise the portal options of the
9
- * page around the viewer are passed through untouched.
3
+ * box that fills the screen. It is the shared fullscreen stage, so the
4
+ * toolbars' popovers stay visible while it does.
10
5
  */
11
6
 
12
- import { PortalContext, PortalProvider } from '@blueprintjs/core';
13
- import type { CSSProperties, ReactElement, ReactNode } from 'react';
14
- import { useCallback, useContext, useState } from 'react';
15
- import { FullScreenProvider, useFullscreen } from 'react-science/ui';
16
-
17
- import type { Molecule3DFullscreen } from './Molecule3DToolbar.tsx';
18
-
19
- /** Props of {@link Molecule3DStage}. */
20
- export interface Molecule3DStageProps {
21
- /**
22
- * Style of the box, or a function handed whether the box fills the screen,
23
- * for a box shaped differently while it does.
24
- */
25
- style: CSSProperties | ((fillsScreen: boolean) => CSSProperties);
26
- /**
27
- * Called with the box once it is mounted, and with `null` once it is gone.
28
- * @default undefined
29
- */
30
- onStage?: (element: HTMLDivElement | null) => void;
31
- /**
32
- * What is drawn in the box, handed whether it fills the screen and the
33
- * toggle, or `undefined` where the browser cannot fill the screen.
34
- */
35
- children: (fullscreen: Molecule3DFullscreen | undefined) => ReactNode;
36
- }
37
-
38
- /**
39
- * The box of the canvas, able to fill the screen.
40
- * @param props - See {@link Molecule3DStageProps}.
41
- * @returns The box.
42
- */
43
- export function Molecule3DStage(props: Molecule3DStageProps): ReactElement {
44
- return (
45
- <FullScreenProvider>
46
- {(fullscreenRef) => <Stage {...props} fullscreenRef={fullscreenRef} />}
47
- </FullScreenProvider>
48
- );
49
- }
50
-
51
- interface StageProps extends Molecule3DStageProps {
52
- /** Where `FullScreenProvider` expects the element that fills the screen. */
53
- fullscreenRef: { current: HTMLDivElement | null };
54
- }
55
-
56
- function Stage(props: StageProps): ReactElement {
57
- const { style, onStage, children, fullscreenRef } = props;
58
- const { isFullScreen, toggle } = useFullscreen();
59
- const portal = useContext(PortalContext);
60
- const [canFillScreen] = useState(isFullscreenEnabled);
61
- const [stage, setStage] = useState<HTMLDivElement | null>(null);
62
- const stageRef = useCallback(
63
- (element: HTMLDivElement | null) => {
64
- fullscreenRef.current = element;
65
- setStage(element);
66
- onStage?.(element);
67
- },
68
- [fullscreenRef, onStage],
69
- );
70
-
71
- // The provider is always there, so entering full screen changes a value
72
- // rather than the tree, and the canvas inside is never mounted again.
73
- return (
74
- <div
75
- ref={stageRef}
76
- style={typeof style === 'function' ? style(isFullScreen) : style}
77
- >
78
- <PortalProvider
79
- portalClassName={portal.portalClassName}
80
- portalContainer={
81
- isFullScreen && stage !== null ? stage : portal.portalContainer
82
- }
83
- >
84
- {children(canFillScreen ? { active: isFullScreen, toggle } : undefined)}
85
- </PortalProvider>
86
- </div>
87
- );
88
- }
89
-
90
- function isFullscreenEnabled(): boolean {
91
- return typeof document !== 'undefined' && document.fullscreenEnabled;
92
- }
7
+ export type { FullscreenStageProps as Molecule3DStageProps } from '../../shared/ui/FullscreenStage.tsx';
8
+ export { FullscreenStage as Molecule3DStage } from '../../shared/ui/FullscreenStage.tsx';
@@ -64,6 +64,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
64
64
  fileName = 'molecule',
65
65
  background,
66
66
  minHeight = 320,
67
+ onCapture,
67
68
  onFailureChange,
68
69
  } = props;
69
70
  const tools = resolveMolecule3DTools(toolsProp);
@@ -139,13 +140,21 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
139
140
  camera: props,
140
141
  });
141
142
 
142
- const { canvasSize, exportImage, copyImage } = useImageExport(
143
+ const { canvasSize, exportImage, copyImage, capture } = useImageExport(
143
144
  container,
144
145
  viewerRef,
145
146
  fileName,
146
147
  framesPerSecond,
147
148
  );
148
149
 
150
+ useEffect(() => {
151
+ if (onCapture === undefined || container === null) return;
152
+ onCapture(capture);
153
+ return () => {
154
+ onCapture(null);
155
+ };
156
+ }, [onCapture, container, capture]);
157
+
149
158
  return (
150
159
  <Molecule3DStage style={{ ...STAGE_STYLE, minHeight }}>
151
160
  {(fullscreen) => (
@@ -59,6 +59,28 @@ export async function captureMoleculePng(
59
59
  return new Blob([dataUriBytes(dataUri)], { type: FIGURE_PNG_TYPE });
60
60
  }
61
61
 
62
+ /**
63
+ * Render the scene as an SVG holding the rendered image, as the export writes
64
+ * it.
65
+ * @param viewer - The viewer holding the scene.
66
+ * @param scale - Multiple of the canvas on screen it is rendered at.
67
+ * @param size - Size of the canvas on screen, CSS pixels.
68
+ * @returns The SVG markup.
69
+ * @throws {Error} When the viewer has nothing to render.
70
+ */
71
+ export async function captureMoleculeSvg(
72
+ viewer: SceneCapture,
73
+ scale: number,
74
+ size: ImageSize,
75
+ ): Promise<string> {
76
+ const pixels = figurePixels(size, scale);
77
+ const dataUri = await viewer.captureImage(pixels);
78
+ if (dataUri === undefined) {
79
+ throw new Error('There is no picture to copy yet.');
80
+ }
81
+ return rasterSvgMarkup(dataUri, pixels);
82
+ }
83
+
62
84
  /**
63
85
  * Render the scene and hand it to the browser as a file.
64
86
  * @param viewer - The viewer holding the scene.
@@ -25,4 +25,7 @@ export { exportMoleculeImage } from './exportMoleculeImage.ts';
25
25
  export type { ImageExport } from './useImageExport.ts';
26
26
  export { useImageExport } from './useImageExport.ts';
27
27
  export { MoleculeViewer3D } from './MoleculeViewer3D.tsx';
28
- export type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
28
+ export type {
29
+ Molecule3DCapture,
30
+ MoleculeViewer3DProps,
31
+ } from './moleculeViewer3DProps.ts';
@@ -7,6 +7,23 @@ import type { Molecule3DHighlight } from '../core/highlight.ts';
7
7
  import type { Measurement } from '../core/measurement.ts';
8
8
  import type { Molecule3DSettings, Molecule3DTools } from '../core/settings.ts';
9
9
 
10
+ /** The scene on screen, rendered as a picture on request. */
11
+ export interface Molecule3DCapture {
12
+ /**
13
+ * Render the scene as an SVG document holding the rendered image: a molecule
14
+ * drawn by WebGL has no vector form.
15
+ * @param scale - Multiple of the canvas on screen it is rendered at.
16
+ * @returns The SVG markup.
17
+ */
18
+ svg: (scale: number) => Promise<string>;
19
+ /**
20
+ * Render the scene as a PNG.
21
+ * @param scale - Multiple of the canvas on screen it is rendered at.
22
+ * @returns The PNG.
23
+ */
24
+ png: (scale: number) => Promise<Blob>;
25
+ }
26
+
10
27
  /**
11
28
  * Props of `MoleculeViewer3D`.
12
29
  *
@@ -129,6 +146,13 @@ export interface MoleculeViewer3DProps {
129
146
  * @default 'molecule'
130
147
  */
131
148
  fileName?: string;
149
+ /**
150
+ * Handed the means to render the scene on screen once the viewer exists, and
151
+ * `null` when it goes — for a page that hands the picture on, to a host
152
+ * framing it. Keep it stable: a new function is handed the means again.
153
+ * @default undefined
154
+ */
155
+ onCapture?: (capture: Molecule3DCapture | null) => void;
132
156
  /**
133
157
  * Scene background, as `#rrggbb`.
134
158
  * @default '#ffffff'
@@ -1,5 +1,5 @@
1
1
  import type { RefObject } from 'react';
2
- import { useCallback } from 'react';
2
+ import { useCallback, useMemo } from 'react';
3
3
 
4
4
  import type { FigureNotice } from '../../download/core/copyFigure.ts';
5
5
  import { copyFigure } from '../../download/core/copyFigure.ts';
@@ -10,8 +10,10 @@ import { DEFAULT_FRAMES_PER_SECOND } from '../core/animatedPng.ts';
10
10
  import type { SceneCapture } from './exportMoleculeImage.ts';
11
11
  import {
12
12
  captureMoleculePng,
13
+ captureMoleculeSvg,
13
14
  exportMoleculeImage,
14
15
  } from './exportMoleculeImage.ts';
16
+ import type { Molecule3DCapture } from './moleculeViewer3DProps.ts';
15
17
 
16
18
  /** What {@link useImageExport} hands the export panel. */
17
19
  export interface ImageExport {
@@ -31,6 +33,8 @@ export interface ImageExport {
31
33
  * from the click itself: Safari only allows a write the click started.
32
34
  */
33
35
  copyImage: (scale: number) => Promise<FigureNotice>;
36
+ /** The scene rendered on request, for a page handing the picture on. */
37
+ capture: Molecule3DCapture;
34
38
  }
35
39
 
36
40
  /**
@@ -85,5 +89,27 @@ export function useImageExport(
85
89
  [canvasSize, viewerRef],
86
90
  );
87
91
 
88
- return { canvasSize, exportImage, copyImage };
92
+ const capture = useMemo(
93
+ (): Molecule3DCapture => ({
94
+ svg: async (scale) => {
95
+ const viewer = viewerRef.current;
96
+ const size = canvasSize();
97
+ if (viewer === null || size === null) {
98
+ throw new Error('There is no picture to copy yet.');
99
+ }
100
+ return captureMoleculeSvg(viewer, scale, size);
101
+ },
102
+ png: async (scale) => {
103
+ const viewer = viewerRef.current;
104
+ const size = canvasSize();
105
+ if (viewer === null || size === null) {
106
+ throw new Error('There is no picture to copy yet.');
107
+ }
108
+ return captureMoleculePng(viewer, scale, size);
109
+ },
110
+ }),
111
+ [canvasSize, viewerRef],
112
+ );
113
+
114
+ return { canvasSize, exportImage, copyImage, capture };
89
115
  }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Where a property's bar starts, how far it runs, and where its labelled mark
3
+ * goes.
4
+ *
5
+ * Three numbers come out of the domain and are merely arranged here. The
6
+ * **position** is how far along the scale the value sits and gives the bar its
7
+ * length; the **fitness** is DataWarrior's own `getValuation`, a continuous
8
+ * 0-to-1 score that the stylesheet reads as the green-to-red ramp; the
9
+ * **threshold** is the published rule of thumb — cLogP ≤ 5, logS > −4,
10
+ * molweight < 450, drug-likeness > 0 — drawn as a mark on the track.
11
+ *
12
+ * Nothing here invents a cut-off. A bar whose colour disagreed with the panel's
13
+ * own scale record would be a second opinion nobody could trace.
14
+ */
15
+
16
+ import { propertyFitness, propertyPosition } from './fitness.ts';
17
+ import type { PropertyKey } from './propertyKeys.ts';
18
+ import { propertyScale } from './scales.ts';
19
+
20
+ /** Where a bar's fill and its mark go, all as fractions of the track. */
21
+ export interface BarGeometry {
22
+ /** Where the fill starts, 0 at the left end of the track and 1 at the right. */
23
+ start: number;
24
+ /** How much of the track the fill covers, 0 to 1. */
25
+ length: number;
26
+ /** How good the value is: 0 as bad as the ramp goes, 1 inside the preferred band. */
27
+ fitness: number;
28
+ /**
29
+ * Where the fill grows from: the left end of the track, or its middle for a
30
+ * quantity that runs either side of zero. Drawn as a tick, because a fill
31
+ * that starts at a quarter of the way along says nothing without it.
32
+ */
33
+ origin: number;
34
+ /** Where the published threshold is marked, or `null` where the property has none. */
35
+ mark: number | null;
36
+ /** How that threshold reads, e.g. `≤ 5`, or `null`. */
37
+ markLabel: string | null;
38
+ }
39
+
40
+ /**
41
+ * Where a diverging bar grows from: the middle of its own range, which is
42
+ * drug-likeness 0 and drug score 0.
43
+ */
44
+ const DIVERGING_ORIGIN = 0.5;
45
+
46
+ /**
47
+ * Lay out one property's bar.
48
+ * @param key - Which of the ten properties.
49
+ * @param value - The predicted number, or `null` when the predictor could not answer.
50
+ * @returns The geometry, or `null` when there is no bar to draw.
51
+ */
52
+ export function barGeometry(
53
+ key: PropertyKey,
54
+ value: number | null,
55
+ ): BarGeometry | null {
56
+ const position = propertyPosition(key, value);
57
+ if (position === null) return null;
58
+
59
+ const scale = propertyScale(key);
60
+ const origin = scale.diverging ? DIVERGING_ORIGIN : 0;
61
+ const mark =
62
+ scale.threshold === null
63
+ ? null
64
+ : propertyPosition(key, scale.threshold.value);
65
+
66
+ return {
67
+ start: Math.min(origin, position),
68
+ length: Math.abs(position - origin),
69
+ fitness: propertyFitness(key, value) ?? 0,
70
+ origin,
71
+ mark,
72
+ markLabel: scale.threshold?.label ?? null,
73
+ };
74
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Everything the tool predicts about one molecule, in one pass.
3
+ *
4
+ * The order of the reads is not arbitrary. `MoleculeProperties`' constructor
5
+ * normalises ambiguous bonds on the molecule it is handed, so the work is done
6
+ * on a copy and the caller's molecule — the one the editor is still drawing —
7
+ * is never touched. Its fields are prototype getters that rerun the whole
8
+ * predictor on every read, at 13 µs each, and the object cannot be spread or
9
+ * serialised at all, so each field is read exactly once into a plain object,
10
+ * and that plain object is what crosses the worker boundary.
11
+ *
12
+ * Nothing here trusts OpenChemLib to fail loudly. An empty molecule answers a
13
+ * full set of innocent numbers and a drug score of 0.63; a failed predictor
14
+ * answers -999, -1 or 0, never `NaN`; and `DrugScoreCalculator` consumes every
15
+ * one of those and returns something plausible. So the empty molecule is
16
+ * refused first, every sentinel becomes `null`, and a drug score is computed
17
+ * only when all of its inputs are real.
18
+ */
19
+
20
+ import type * as OCL from 'openchemlib';
21
+
22
+ import {
23
+ NO_FRAGMENT_MATCHED,
24
+ RISK_TYPE_CODES,
25
+ UNKNOWN_NUMBER,
26
+ UNKNOWN_SURFACE_AREA,
27
+ riskCodeOf,
28
+ riskLevelOf,
29
+ } from './constants.ts';
30
+ import type { OsirisPredictors } from './predictors.ts';
31
+ import type { OsirisProperties, RiskLevel, RiskType } from './types.ts';
32
+ import { RISK_TYPES } from './types.ts';
33
+
34
+ /** What a caller knows about the molecule that the molecule does not. */
35
+ export interface ComputePropertiesOptions {
36
+ /**
37
+ * The name the source carried. The canonical SMILES is used when there is
38
+ * none, so a row always has something to be called.
39
+ * @default the canonical SMILES
40
+ */
41
+ label?: string;
42
+ }
43
+
44
+ /** A structure with no atoms, which has nothing to predict. */
45
+ export const EMPTY_MOLECULE_MESSAGE =
46
+ 'This structure has no atoms, so there is nothing to predict.';
47
+
48
+ /**
49
+ * Predict everything the tool shows for one molecule.
50
+ * @param molecule - The molecule. It is copied before anything touches it, so the caller keeps it exactly as it was.
51
+ * @param predictors - OpenChemLib with its resources registered and checked.
52
+ * @param options - See {@link ComputePropertiesOptions}.
53
+ * @returns The ten numbers, the four risks, and what to call the molecule.
54
+ * @throws {Error} When the molecule has no atoms.
55
+ */
56
+ export function computeProperties(
57
+ molecule: OCL.Molecule,
58
+ predictors: OsirisPredictors,
59
+ options: ComputePropertiesOptions = {},
60
+ ): OsirisProperties {
61
+ if (molecule.getAllAtoms() === 0) throw new Error(EMPTY_MOLECULE_MESSAGE);
62
+
63
+ const working = molecule.getCompactCopy();
64
+ const idCode = working.getIDCode();
65
+ const smiles = working.toIsomericSmiles();
66
+ const { formula, relativeWeight } = working.getMolecularFormula();
67
+
68
+ const properties = new predictors.MoleculeProperties(working);
69
+ const logP = real(properties.logP, UNKNOWN_NUMBER);
70
+ const logS = real(properties.logS, UNKNOWN_NUMBER);
71
+ const polarSurfaceArea = real(
72
+ properties.polarSurfaceArea,
73
+ UNKNOWN_SURFACE_AREA,
74
+ );
75
+ const acceptorCount = properties.acceptorCount;
76
+ const donorCount = properties.donorCount;
77
+ const stereoCenterCount = properties.stereoCenterCount;
78
+ const rotatableBondCount = properties.rotatableBondCount;
79
+
80
+ const assessed = predictors.druglikeness.assessDruglikeness(working);
81
+ const druglikeness =
82
+ assessed === UNKNOWN_NUMBER || assessed === NO_FRAGMENT_MATCHED
83
+ ? null
84
+ : assessed;
85
+
86
+ const risks = assessRisks(working, predictors);
87
+
88
+ return {
89
+ idCode,
90
+ smiles,
91
+ label: options.label ?? smiles,
92
+ molecularFormula: formula,
93
+ molecularWeight: relativeWeight,
94
+ logP,
95
+ logS,
96
+ polarSurfaceArea,
97
+ druglikeness,
98
+ drugScore: drugScore(predictors, {
99
+ logP,
100
+ logS,
101
+ relativeWeight,
102
+ druglikeness,
103
+ risks,
104
+ }),
105
+ acceptorCount,
106
+ donorCount,
107
+ stereoCenterCount,
108
+ rotatableBondCount,
109
+ risks,
110
+ };
111
+ }
112
+
113
+ function assessRisks(
114
+ molecule: OCL.Molecule,
115
+ predictors: OsirisPredictors,
116
+ ): Record<RiskType, RiskLevel> {
117
+ const risks = {} as Record<RiskType, RiskLevel>;
118
+ for (const risk of RISK_TYPES) {
119
+ risks[risk] = riskLevelOf(
120
+ predictors.toxicity.assessRisk(molecule, RISK_TYPE_CODES[risk]),
121
+ );
122
+ }
123
+ return risks;
124
+ }
125
+
126
+ interface DrugScoreInputs {
127
+ logP: number | null;
128
+ logS: number | null;
129
+ relativeWeight: number;
130
+ druglikeness: number | null;
131
+ risks: Record<RiskType, RiskLevel>;
132
+ }
133
+
134
+ /**
135
+ * The drug score, or `null` when any of its five inputs was unknown.
136
+ *
137
+ * `calculate` never refuses: a drug-likeness of -999 simply makes that factor
138
+ * exactly 0.5 and the score comes back looking ordinary, and an unassessed risk
139
+ * applies no penalty where a high one would have applied 0.6. Both read as good
140
+ * news, which is why they are refused here instead.
141
+ *
142
+ * The second argument is the **solubility**. The legacy explorer passed the
143
+ * polar surface area, which is a different number in a different unit; see the
144
+ * test that pins both.
145
+ * @param predictors - OpenChemLib with its resources registered and checked.
146
+ * @param inputs - The four predicted numbers and the four risks.
147
+ * @returns The score, or `null` when it cannot be trusted.
148
+ */
149
+ function drugScore(
150
+ predictors: OsirisPredictors,
151
+ inputs: DrugScoreInputs,
152
+ ): number | null {
153
+ const { logP, logS, relativeWeight, druglikeness, risks } = inputs;
154
+ if (logP === null || logS === null || druglikeness === null) return null;
155
+
156
+ const codes: number[] = [];
157
+ for (const risk of RISK_TYPES) {
158
+ const level = risks[risk];
159
+ if (level === 'unknown') return null;
160
+ codes.push(riskCodeOf(level));
161
+ }
162
+
163
+ return predictors.DrugScoreCalculator.calculate(
164
+ logP,
165
+ logS,
166
+ relativeWeight,
167
+ druglikeness,
168
+ codes,
169
+ );
170
+ }
171
+
172
+ function real(value: number, sentinel: number): number | null {
173
+ if (value === sentinel || !Number.isFinite(value)) return null;
174
+ return value;
175
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The numbers OpenChemLib speaks, and the words this site says instead.
3
+ *
4
+ * Two translations live here and nowhere else. The first is the library's risk
5
+ * numbering, which is easy to get backwards: `ToxicityPredictor.RISK_NAMES` is
6
+ * indexed by risk *type*, not by risk *level*, and the library exports no level
7
+ * names at all — so reading a level out of `RISK_NAMES` gives a confident,
8
+ * wrong answer. The second is the set of sentinels every predictor returns
9
+ * instead of failing: none of them is `NaN`, and `DrugScoreCalculator` consumes
10
+ * every one of them and hands back a plausible number.
11
+ */
12
+
13
+ import type { RiskLevel, RiskType } from './types.ts';
14
+
15
+ /**
16
+ * Where each risk sits in the library's numbering — `TYPE_MUTAGENIC` 0 through
17
+ * `TYPE_REPRODUCTIVE_EFFECTIVE` 3. It is also the order `DrugScoreCalculator`
18
+ * expects its `toxRisks` array in.
19
+ */
20
+ export const RISK_TYPE_CODES: Record<RiskType, number> = {
21
+ mutagenic: 0,
22
+ tumorigenic: 1,
23
+ irritant: 2,
24
+ reproductive: 3,
25
+ };
26
+
27
+ /**
28
+ * What `assessRisk` returns, read as a word: `RISK_UNKNOWN` 0, `RISK_NO` 1,
29
+ * `RISK_LOW` 2, `RISK_HIGH` 3.
30
+ */
31
+ export const RISK_LEVELS: readonly RiskLevel[] = [
32
+ 'unknown',
33
+ 'none',
34
+ 'low',
35
+ 'high',
36
+ ];
37
+
38
+ /**
39
+ * What the library calls each risk, matching `ToxicityPredictor.RISK_NAMES`.
40
+ * Written out here so reading a label costs no import of a megabyte of
41
+ * OpenChemLib on a page that only draws a table.
42
+ */
43
+ export const RISK_LABELS: Record<RiskType, string> = {
44
+ mutagenic: 'Mutagenicity',
45
+ tumorigenic: 'Tumorigenicity',
46
+ irritant: 'Irritating effects',
47
+ reproductive: 'Reproductive effects',
48
+ };
49
+
50
+ /**
51
+ * How each level reads on screen. OSIRIS's own three words, plus one for the
52
+ * state where the tables did not load — which is not "no risk" and must never
53
+ * be shown as one.
54
+ */
55
+ export const RISK_LEVEL_LABELS: Record<RiskLevel, string> = {
56
+ unknown: 'Not assessed',
57
+ none: 'No risk',
58
+ low: 'Medium risk',
59
+ high: 'High risk',
60
+ };
61
+
62
+ /**
63
+ * What each level multiplies the drug score by, decoded from
64
+ * `DrugScoreCalculator.calculate`. `unknown` applies no factor at all, which is
65
+ * why a score is refused rather than shown when a risk came back unassessed.
66
+ */
67
+ export const DRUG_SCORE_RISK_FACTORS: Record<RiskLevel, number> = {
68
+ unknown: 1,
69
+ none: 1,
70
+ low: 0.8,
71
+ high: 0.6,
72
+ };
73
+
74
+ /**
75
+ * What cLogP, solubility and drug-likeness answer when the predictor failed
76
+ * outright. `CLogPPredictor` returns it on an internal exception, and both
77
+ * `SolubilityPredictor.cSolubilityUnknown` and
78
+ * `DruglikenessPredictor.DRUGLIKENESS_UNKNOWN` are this value.
79
+ */
80
+ export const UNKNOWN_NUMBER = -999;
81
+
82
+ /** What the polar surface area answers when it is unknown — not `-999`. */
83
+ export const UNKNOWN_SURFACE_AREA = -1;
84
+
85
+ /**
86
+ * What `assessDruglikeness` answers when the molecule matched none of the 5294
87
+ * fragments. It is a real return value, not a failure, and it is
88
+ * indistinguishable from a drug-likeness that happens to be exactly -1.
89
+ */
90
+ export const NO_FRAGMENT_MATCHED = -1;
91
+
92
+ /**
93
+ * The word for a risk the library answered with a number.
94
+ * @param code - What `assessRisk` returned, 0 to 3.
95
+ * @returns The level, `unknown` for anything outside the four the library defines.
96
+ */
97
+ export function riskLevelOf(code: number): RiskLevel {
98
+ return RISK_LEVELS[code] ?? 'unknown';
99
+ }
100
+
101
+ /**
102
+ * The number the library uses for a level, for the `toxRisks` argument of
103
+ * `DrugScoreCalculator.calculate`.
104
+ * @param level - The level.
105
+ * @returns 0 to 3.
106
+ */
107
+ export function riskCodeOf(level: RiskLevel): number {
108
+ const code = RISK_LEVELS.indexOf(level);
109
+ return code === -1 ? 0 : code;
110
+ }