react-cheminfo 0.65.0 → 0.67.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 (466) hide show
  1. package/README.md +33 -17
  2. package/lib/download/ui/FigureDownloadPanel.d.ts +7 -1
  3. package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
  4. package/lib/download/ui/FigureDownloadPanel.js +2 -2
  5. package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
  6. package/lib/ecosystem/core/sites.js +3 -3
  7. package/lib/ecosystem/core/sites.js.map +1 -1
  8. package/lib/ecosystem/core/types.d.ts +1 -1
  9. package/lib/ecosystem/core/types.d.ts.map +1 -1
  10. package/lib/ecosystem/ui/glyphs.js +1 -1
  11. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  12. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  13. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  14. package/lib/i18n/core/messageCatalog.d.ts +2 -2
  15. package/lib/i18n/vite/localeCatalog.d.ts +1 -1
  16. package/lib/ir/core/analysisSpectra.d.ts +23 -6
  17. package/lib/ir/core/analysisSpectra.d.ts.map +1 -1
  18. package/lib/ir/core/analysisSpectra.js.map +1 -1
  19. package/lib/ir/core/bandLabelPlan.d.ts.map +1 -1
  20. package/lib/ir/core/bandLabelPlan.js +11 -6
  21. package/lib/ir/core/bandLabelPlan.js.map +1 -1
  22. package/lib/ir/core/index.d.ts +15 -11
  23. package/lib/ir/core/index.d.ts.map +1 -1
  24. package/lib/ir/core/index.js +9 -6
  25. package/lib/ir/core/index.js.map +1 -1
  26. package/lib/ir/core/irBand.d.ts +45 -14
  27. package/lib/ir/core/irBand.d.ts.map +1 -1
  28. package/lib/ir/core/irBand.js +28 -6
  29. package/lib/ir/core/irBand.js.map +1 -1
  30. package/lib/ir/core/irCommands.d.ts +11 -0
  31. package/lib/ir/core/irCommands.d.ts.map +1 -1
  32. package/lib/ir/core/irCommands.js +11 -1
  33. package/lib/ir/core/irCommands.js.map +1 -1
  34. package/lib/ir/core/irDomain.d.ts +4 -3
  35. package/lib/ir/core/irDomain.d.ts.map +1 -1
  36. package/lib/ir/core/irDomain.js +10 -7
  37. package/lib/ir/core/irDomain.js.map +1 -1
  38. package/lib/ir/core/irEditorApi.d.ts +12 -0
  39. package/lib/ir/core/irEditorApi.d.ts.map +1 -1
  40. package/lib/ir/core/irFormat.d.ts +14 -2
  41. package/lib/ir/core/irFormat.d.ts.map +1 -1
  42. package/lib/ir/core/irFormat.js +33 -4
  43. package/lib/ir/core/irFormat.js.map +1 -1
  44. package/lib/ir/core/irMode.d.ts +35 -8
  45. package/lib/ir/core/irMode.d.ts.map +1 -1
  46. package/lib/ir/core/irMode.js +38 -10
  47. package/lib/ir/core/irMode.js.map +1 -1
  48. package/lib/ir/core/irReducer.d.ts +2 -30
  49. package/lib/ir/core/irReducer.d.ts.map +1 -1
  50. package/lib/ir/core/irReducer.js +1 -24
  51. package/lib/ir/core/irReducer.js.map +1 -1
  52. package/lib/ir/core/irSidePanels.d.ts +7 -1
  53. package/lib/ir/core/irSidePanels.d.ts.map +1 -1
  54. package/lib/ir/core/irSpectrum.d.ts +52 -26
  55. package/lib/ir/core/irSpectrum.d.ts.map +1 -1
  56. package/lib/ir/core/irSpectrum.js +21 -15
  57. package/lib/ir/core/irSpectrum.js.map +1 -1
  58. package/lib/ir/core/irState.d.ts +46 -5
  59. package/lib/ir/core/irState.d.ts.map +1 -1
  60. package/lib/ir/core/irState.js +38 -1
  61. package/lib/ir/core/irState.js.map +1 -1
  62. package/lib/ir/core/irTechnique.d.ts +94 -0
  63. package/lib/ir/core/irTechnique.d.ts.map +1 -0
  64. package/lib/ir/core/irTechnique.js +87 -0
  65. package/lib/ir/core/irTechnique.js.map +1 -0
  66. package/lib/ir/core/irTechniqueCommands.d.ts +26 -0
  67. package/lib/ir/core/irTechniqueCommands.d.ts.map +1 -0
  68. package/lib/ir/core/irTechniqueCommands.js +68 -0
  69. package/lib/ir/core/irTechniqueCommands.js.map +1 -0
  70. package/lib/ir/core/pickBands.d.ts +6 -5
  71. package/lib/ir/core/pickBands.d.ts.map +1 -1
  72. package/lib/ir/core/pickBands.js +49 -26
  73. package/lib/ir/core/pickBands.js.map +1 -1
  74. package/lib/ir/core/ramanBands.d.ts +30 -0
  75. package/lib/ir/core/ramanBands.d.ts.map +1 -0
  76. package/lib/ir/core/ramanBands.js +83 -0
  77. package/lib/ir/core/ramanBands.js.map +1 -0
  78. package/lib/ir/core/spectrumJcamp.d.ts +10 -5
  79. package/lib/ir/core/spectrumJcamp.d.ts.map +1 -1
  80. package/lib/ir/core/spectrumJcamp.js +63 -15
  81. package/lib/ir/core/spectrumJcamp.js.map +1 -1
  82. package/lib/ir/core/toIrSpectrum.d.ts.map +1 -1
  83. package/lib/ir/core/toIrSpectrum.js +17 -2
  84. package/lib/ir/core/toIrSpectrum.js.map +1 -1
  85. package/lib/ir/ui/BandRow.d.ts +30 -0
  86. package/lib/ir/ui/BandRow.d.ts.map +1 -0
  87. package/lib/ir/ui/BandRow.js +42 -0
  88. package/lib/ir/ui/BandRow.js.map +1 -0
  89. package/lib/ir/ui/BandsPanel.d.ts +4 -0
  90. package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
  91. package/lib/ir/ui/BandsPanel.js +14 -59
  92. package/lib/ir/ui/BandsPanel.js.map +1 -1
  93. package/lib/ir/ui/IrAboutDialog.d.ts +7 -0
  94. package/lib/ir/ui/IrAboutDialog.d.ts.map +1 -1
  95. package/lib/ir/ui/IrAboutDialog.js +16 -3
  96. package/lib/ir/ui/IrAboutDialog.js.map +1 -1
  97. package/lib/ir/ui/IrCanvas.d.ts +7 -0
  98. package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
  99. package/lib/ir/ui/IrCanvas.js +9 -4
  100. package/lib/ir/ui/IrCanvas.js.map +1 -1
  101. package/lib/ir/ui/IrChart.d.ts +2 -1
  102. package/lib/ir/ui/IrChart.d.ts.map +1 -1
  103. package/lib/ir/ui/IrChart.js +22 -21
  104. package/lib/ir/ui/IrChart.js.map +1 -1
  105. package/lib/ir/ui/IrCommandProvider.d.ts +7 -0
  106. package/lib/ir/ui/IrCommandProvider.d.ts.map +1 -1
  107. package/lib/ir/ui/IrCommandProvider.js +2 -2
  108. package/lib/ir/ui/IrCommandProvider.js.map +1 -1
  109. package/lib/ir/ui/IrCommandTooltip.d.ts +7 -0
  110. package/lib/ir/ui/IrCommandTooltip.d.ts.map +1 -1
  111. package/lib/ir/ui/IrCommandTooltip.js +3 -2
  112. package/lib/ir/ui/IrCommandTooltip.js.map +1 -1
  113. package/lib/ir/ui/IrDocumentationDialog.d.ts +8 -1
  114. package/lib/ir/ui/IrDocumentationDialog.d.ts.map +1 -1
  115. package/lib/ir/ui/IrDocumentationDialog.js +30 -7
  116. package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
  117. package/lib/ir/ui/IrEditor.d.ts +25 -5
  118. package/lib/ir/ui/IrEditor.d.ts.map +1 -1
  119. package/lib/ir/ui/IrEditor.js +3 -20
  120. package/lib/ir/ui/IrEditor.js.map +1 -1
  121. package/lib/ir/ui/IrHeader.d.ts.map +1 -1
  122. package/lib/ir/ui/IrHeader.js +5 -1
  123. package/lib/ir/ui/IrHeader.js.map +1 -1
  124. package/lib/ir/ui/IrLogo.d.ts +11 -3
  125. package/lib/ir/ui/IrLogo.d.ts.map +1 -1
  126. package/lib/ir/ui/IrLogo.js +14 -5
  127. package/lib/ir/ui/IrLogo.js.map +1 -1
  128. package/lib/ir/ui/IrShell.d.ts +9 -1
  129. package/lib/ir/ui/IrShell.d.ts.map +1 -1
  130. package/lib/ir/ui/IrShell.js +26 -74
  131. package/lib/ir/ui/IrShell.js.map +1 -1
  132. package/lib/ir/ui/IrSidePanel.d.ts +11 -0
  133. package/lib/ir/ui/IrSidePanel.d.ts.map +1 -1
  134. package/lib/ir/ui/IrSidePanel.js +12 -3
  135. package/lib/ir/ui/IrSidePanel.js.map +1 -1
  136. package/lib/ir/ui/IrStatusBar.d.ts +3 -2
  137. package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
  138. package/lib/ir/ui/IrStatusBar.js +14 -9
  139. package/lib/ir/ui/IrStatusBar.js.map +1 -1
  140. package/lib/ir/ui/IrToolbar.d.ts +3 -0
  141. package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
  142. package/lib/ir/ui/IrToolbar.js +10 -3
  143. package/lib/ir/ui/IrToolbar.js.map +1 -1
  144. package/lib/ir/ui/IrTraces.d.ts +4 -1
  145. package/lib/ir/ui/IrTraces.d.ts.map +1 -1
  146. package/lib/ir/ui/IrTraces.js +2 -0
  147. package/lib/ir/ui/IrTraces.js.map +1 -1
  148. package/lib/ir/ui/RamanEditor.d.ts +64 -0
  149. package/lib/ir/ui/RamanEditor.d.ts.map +1 -0
  150. package/lib/ir/ui/RamanEditor.js +17 -0
  151. package/lib/ir/ui/RamanEditor.js.map +1 -0
  152. package/lib/ir/ui/SpectraPanel.d.ts.map +1 -1
  153. package/lib/ir/ui/SpectraPanel.js +2 -2
  154. package/lib/ir/ui/SpectraPanel.js.map +1 -1
  155. package/lib/ir/ui/SpectrumRow.d.ts +7 -0
  156. package/lib/ir/ui/SpectrumRow.d.ts.map +1 -1
  157. package/lib/ir/ui/SpectrumRow.js +4 -5
  158. package/lib/ir/ui/SpectrumRow.js.map +1 -1
  159. package/lib/ir/ui/VibrationalEditor.d.ts +62 -0
  160. package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -0
  161. package/lib/ir/ui/VibrationalEditor.js +33 -0
  162. package/lib/ir/ui/VibrationalEditor.js.map +1 -0
  163. package/lib/ir/ui/bandsTsv.d.ts +19 -0
  164. package/lib/ir/ui/bandsTsv.d.ts.map +1 -0
  165. package/lib/ir/ui/bandsTsv.js +38 -0
  166. package/lib/ir/ui/bandsTsv.js.map +1 -0
  167. package/lib/ir/ui/index.d.ts +1 -0
  168. package/lib/ir/ui/index.d.ts.map +1 -1
  169. package/lib/ir/ui/index.js.map +1 -1
  170. package/lib/ir/ui/irActions.d.ts +3 -3
  171. package/lib/ir/ui/irActions.d.ts.map +1 -1
  172. package/lib/ir/ui/irChartProps.d.ts +21 -4
  173. package/lib/ir/ui/irChartProps.d.ts.map +1 -1
  174. package/lib/ir/ui/irChartProps.js +3 -2
  175. package/lib/ir/ui/irChartProps.js.map +1 -1
  176. package/lib/ir/ui/irCommandContext.d.ts +8 -0
  177. package/lib/ir/ui/irCommandContext.d.ts.map +1 -1
  178. package/lib/ir/ui/irCommandContext.js +14 -3
  179. package/lib/ir/ui/irCommandContext.js.map +1 -1
  180. package/lib/ir/ui/irHostPanels.d.ts +53 -0
  181. package/lib/ir/ui/irHostPanels.d.ts.map +1 -0
  182. package/lib/ir/ui/irHostPanels.js +41 -0
  183. package/lib/ir/ui/irHostPanels.js.map +1 -0
  184. package/lib/ir/ui/useIrEditor.d.ts +3 -3
  185. package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
  186. package/lib/ir/ui/useIrEditor.js +13 -4
  187. package/lib/ir/ui/useIrEditor.js.map +1 -1
  188. package/lib/ir/ui/useIrHandle.d.ts +14 -0
  189. package/lib/ir/ui/useIrHandle.d.ts.map +1 -0
  190. package/lib/ir/ui/useIrHandle.js +39 -0
  191. package/lib/ir/ui/useIrHandle.js.map +1 -0
  192. package/lib/ir/ui/useIrSide.d.ts +27 -0
  193. package/lib/ir/ui/useIrSide.d.ts.map +1 -0
  194. package/lib/ir/ui/useIrSide.js +42 -0
  195. package/lib/ir/ui/useIrSide.js.map +1 -0
  196. package/lib/ir/ui/useIrText.d.ts +40 -0
  197. package/lib/ir/ui/useIrText.d.ts.map +1 -0
  198. package/lib/ir/ui/useIrText.js +118 -0
  199. package/lib/ir/ui/useIrText.js.map +1 -0
  200. package/lib/ir/ui/useIrZoom.d.ts +15 -0
  201. package/lib/ir/ui/useIrZoom.d.ts.map +1 -1
  202. package/lib/ir/ui/useIrZoom.js +6 -4
  203. package/lib/ir/ui/useIrZoom.js.map +1 -1
  204. package/lib/ir/ui/useValueAxisZoom.d.ts +20 -0
  205. package/lib/ir/ui/useValueAxisZoom.d.ts.map +1 -0
  206. package/lib/ir/ui/useValueAxisZoom.js +54 -0
  207. package/lib/ir/ui/useValueAxisZoom.js.map +1 -0
  208. package/lib/ir.d.ts +3 -0
  209. package/lib/ir.d.ts.map +1 -1
  210. package/lib/ir.js +3 -0
  211. package/lib/ir.js.map +1 -1
  212. package/lib/locales/de.json +29 -2
  213. package/lib/locales/en.json +29 -2
  214. package/lib/locales/es.json +29 -2
  215. package/lib/locales/fr.json +29 -2
  216. package/lib/locales/it.json +29 -2
  217. package/lib/molecule3d/core/animatedPng.d.ts +25 -0
  218. package/lib/molecule3d/core/animatedPng.d.ts.map +1 -0
  219. package/lib/molecule3d/core/animatedPng.js +59 -0
  220. package/lib/molecule3d/core/animatedPng.js.map +1 -0
  221. package/lib/molecule3d/core/file.d.ts +24 -0
  222. package/lib/molecule3d/core/file.d.ts.map +1 -0
  223. package/lib/molecule3d/core/file.js +2 -0
  224. package/lib/molecule3d/core/file.js.map +1 -0
  225. package/lib/molecule3d/core/index.d.ts +4 -1
  226. package/lib/molecule3d/core/index.d.ts.map +1 -1
  227. package/lib/molecule3d/core/index.js +1 -0
  228. package/lib/molecule3d/core/index.js.map +1 -1
  229. package/lib/molecule3d/core/settings.d.ts +0 -7
  230. package/lib/molecule3d/core/settings.d.ts.map +1 -1
  231. package/lib/molecule3d/core/settings.js.map +1 -1
  232. package/lib/molecule3d/ui/Molecule3DExport.d.ts +10 -2
  233. package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
  234. package/lib/molecule3d/ui/Molecule3DExport.js +15 -2
  235. package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
  236. package/lib/molecule3d/ui/Molecule3DToolbar.js +9 -2
  237. package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
  238. package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
  239. package/lib/molecule3d/ui/MoleculeCanvas3D.js +23 -41
  240. package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
  241. package/lib/molecule3d/ui/drawScene.d.ts +2 -1
  242. package/lib/molecule3d/ui/drawScene.d.ts.map +1 -1
  243. package/lib/molecule3d/ui/drawScene.js.map +1 -1
  244. package/lib/molecule3d/ui/exportMoleculeImage.d.ts +15 -1
  245. package/lib/molecule3d/ui/exportMoleculeImage.d.ts.map +1 -1
  246. package/lib/molecule3d/ui/exportMoleculeImage.js +14 -2
  247. package/lib/molecule3d/ui/exportMoleculeImage.js.map +1 -1
  248. package/lib/molecule3d/ui/moleculeFrames.d.ts +47 -0
  249. package/lib/molecule3d/ui/moleculeFrames.d.ts.map +1 -0
  250. package/lib/molecule3d/ui/moleculeFrames.js +65 -0
  251. package/lib/molecule3d/ui/moleculeFrames.js.map +1 -0
  252. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +14 -1
  253. package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
  254. package/lib/molecule3d/ui/renderMolecule.d.ts +3 -3
  255. package/lib/molecule3d/ui/renderMolecule.d.ts.map +1 -1
  256. package/lib/molecule3d/ui/renderMolecule.js +2 -1
  257. package/lib/molecule3d/ui/renderMolecule.js.map +1 -1
  258. package/lib/molecule3d/ui/sceneDrawer.d.ts +2 -1
  259. package/lib/molecule3d/ui/sceneDrawer.d.ts.map +1 -1
  260. package/lib/molecule3d/ui/sceneDrawer.js +9 -1
  261. package/lib/molecule3d/ui/sceneDrawer.js.map +1 -1
  262. package/lib/molecule3d/ui/useImageExport.d.ts +8 -3
  263. package/lib/molecule3d/ui/useImageExport.d.ts.map +1 -1
  264. package/lib/molecule3d/ui/useImageExport.js +13 -4
  265. package/lib/molecule3d/ui/useImageExport.js.map +1 -1
  266. package/lib/molecule3d/ui/useMoleculeScene.d.ts +2 -1
  267. package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -1
  268. package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -1
  269. package/lib/molecule3d/ui/useMoleculeViewer.d.ts +16 -0
  270. package/lib/molecule3d/ui/useMoleculeViewer.d.ts.map +1 -0
  271. package/lib/molecule3d/ui/useMoleculeViewer.js +37 -0
  272. package/lib/molecule3d/ui/useMoleculeViewer.js.map +1 -0
  273. package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts +3 -3
  274. package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts.map +1 -1
  275. package/lib/molecule3d/ui/usePolarSurfaceArea.js +4 -3
  276. package/lib/molecule3d/ui/usePolarSurfaceArea.js.map +1 -1
  277. package/lib/molecule3d/ui/viewer.d.ts +4 -1
  278. package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
  279. package/lib/molecule3d/ui/viewer.js +21 -19
  280. package/lib/molecule3d/ui/viewer.js.map +1 -1
  281. package/lib/molecule3d/ui/viewerTypes.d.ts +6 -0
  282. package/lib/molecule3d/ui/viewerTypes.d.ts.map +1 -1
  283. package/lib/molstar/core/captureScene.d.ts +19 -1
  284. package/lib/molstar/core/captureScene.d.ts.map +1 -1
  285. package/lib/molstar/core/captureScene.js +57 -2
  286. package/lib/molstar/core/captureScene.js.map +1 -1
  287. package/lib/molstar/core/index.d.ts +5 -2
  288. package/lib/molstar/core/index.d.ts.map +1 -1
  289. package/lib/molstar/core/index.js +4 -2
  290. package/lib/molstar/core/index.js.map +1 -1
  291. package/lib/molstar/core/trajectory.d.ts +56 -0
  292. package/lib/molstar/core/trajectory.d.ts.map +1 -0
  293. package/lib/molstar/core/trajectory.js +96 -0
  294. package/lib/molstar/core/trajectory.js.map +1 -0
  295. package/lib/panel/ui/PanelRail.d.ts.map +1 -1
  296. package/lib/panel/ui/PanelRail.js +1 -1
  297. package/lib/panel/ui/PanelRail.js.map +1 -1
  298. package/lib/raman.d.ts +17 -0
  299. package/lib/raman.d.ts.map +1 -0
  300. package/lib/raman.js +12 -0
  301. package/lib/raman.js.map +1 -0
  302. package/lib/router/core/basePath.d.ts +2 -2
  303. package/lib/router/core/basePath.js +2 -2
  304. package/lib/router/core/siteAddresses.d.ts +1 -1
  305. package/lib/router/core/siteAddresses.js +1 -1
  306. package/lib/seo/core/siteFiles.js +1 -1
  307. package/lib/seo/core/siteFiles.js.map +1 -1
  308. package/lib/server/answerAddresses.d.ts +3 -3
  309. package/lib/server/answerAddresses.js +3 -3
  310. package/lib/structure/core/index.d.ts +2 -0
  311. package/lib/structure/core/index.d.ts.map +1 -1
  312. package/lib/structure/core/index.js +1 -0
  313. package/lib/structure/core/index.js.map +1 -1
  314. package/lib/structure/core/structureTransfer.d.ts +29 -0
  315. package/lib/structure/core/structureTransfer.d.ts.map +1 -0
  316. package/lib/structure/core/structureTransfer.js +26 -0
  317. package/lib/structure/core/structureTransfer.js.map +1 -0
  318. package/lib/structure/ui/EditorImportButton.d.ts +20 -0
  319. package/lib/structure/ui/EditorImportButton.d.ts.map +1 -0
  320. package/lib/structure/ui/EditorImportButton.js +24 -0
  321. package/lib/structure/ui/EditorImportButton.js.map +1 -0
  322. package/lib/structure/ui/EditorImportProblem.d.ts +17 -0
  323. package/lib/structure/ui/EditorImportProblem.d.ts.map +1 -0
  324. package/lib/structure/ui/EditorImportProblem.js +32 -0
  325. package/lib/structure/ui/EditorImportProblem.js.map +1 -0
  326. package/lib/structure/ui/StructureDrop.d.ts +39 -0
  327. package/lib/structure/ui/StructureDrop.d.ts.map +1 -0
  328. package/lib/structure/ui/StructureDrop.js +19 -0
  329. package/lib/structure/ui/StructureDrop.js.map +1 -0
  330. package/lib/structure/ui/StructureDropOverlay.d.ts +16 -0
  331. package/lib/structure/ui/StructureDropOverlay.d.ts.map +1 -0
  332. package/lib/structure/ui/StructureDropOverlay.js +29 -0
  333. package/lib/structure/ui/StructureDropOverlay.js.map +1 -0
  334. package/lib/structure/ui/StructureEditor.d.ts +3 -80
  335. package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
  336. package/lib/structure/ui/StructureEditor.js +21 -33
  337. package/lib/structure/ui/StructureEditor.js.map +1 -1
  338. package/lib/structure/ui/importedStructure.d.ts +25 -0
  339. package/lib/structure/ui/importedStructure.d.ts.map +1 -0
  340. package/lib/structure/ui/importedStructure.js +74 -0
  341. package/lib/structure/ui/importedStructure.js.map +1 -0
  342. package/lib/structure/ui/index.d.ts +2 -0
  343. package/lib/structure/ui/index.d.ts.map +1 -1
  344. package/lib/structure/ui/index.js +1 -0
  345. package/lib/structure/ui/index.js.map +1 -1
  346. package/lib/structure/ui/structureEditorProps.d.ts +98 -0
  347. package/lib/structure/ui/structureEditorProps.d.ts.map +1 -0
  348. package/lib/structure/ui/structureEditorProps.js +2 -0
  349. package/lib/structure/ui/structureEditorProps.js.map +1 -0
  350. package/lib/structure/ui/useDebouncedChange.d.ts +16 -0
  351. package/lib/structure/ui/useDebouncedChange.d.ts.map +1 -0
  352. package/lib/structure/ui/useDebouncedChange.js +30 -0
  353. package/lib/structure/ui/useDebouncedChange.js.map +1 -0
  354. package/lib/structure/ui/useStructureDrop.d.ts +30 -0
  355. package/lib/structure/ui/useStructureDrop.d.ts.map +1 -0
  356. package/lib/structure/ui/useStructureDrop.js +49 -0
  357. package/lib/structure/ui/useStructureDrop.js.map +1 -0
  358. package/lib/structure/ui/useStructureImport.d.ts +45 -0
  359. package/lib/structure/ui/useStructureImport.d.ts.map +1 -0
  360. package/lib/structure/ui/useStructureImport.js +62 -0
  361. package/lib/structure/ui/useStructureImport.js.map +1 -0
  362. package/package.json +5 -1
  363. package/src/download/ui/FigureDownloadPanel.tsx +9 -2
  364. package/src/ecosystem/core/sites.ts +3 -3
  365. package/src/ecosystem/core/types.ts +1 -1
  366. package/src/ecosystem/ui/glyphs.tsx +1 -1
  367. package/src/i18n/core/messageCatalog.ts +2 -2
  368. package/src/i18n/vite/localeCatalog.ts +1 -1
  369. package/src/ir/core/analysisSpectra.ts +26 -10
  370. package/src/ir/core/bandLabelPlan.ts +21 -10
  371. package/src/ir/core/index.ts +31 -7
  372. package/src/ir/core/irBand.ts +52 -14
  373. package/src/ir/core/irCommands.ts +15 -1
  374. package/src/ir/core/irDomain.ts +9 -7
  375. package/src/ir/core/irEditorApi.ts +13 -0
  376. package/src/ir/core/irFormat.ts +39 -6
  377. package/src/ir/core/irMode.ts +42 -10
  378. package/src/ir/core/irReducer.ts +3 -51
  379. package/src/ir/core/irSidePanels.ts +8 -1
  380. package/src/ir/core/irSpectrum.ts +59 -30
  381. package/src/ir/core/irState.ts +73 -5
  382. package/src/ir/core/irTechnique.ts +115 -0
  383. package/src/ir/core/irTechniqueCommands.ts +82 -0
  384. package/src/ir/core/pickBands.ts +63 -28
  385. package/src/ir/core/ramanBands.ts +105 -0
  386. package/src/ir/core/spectrumJcamp.ts +65 -16
  387. package/src/ir/core/toIrSpectrum.ts +20 -2
  388. package/src/ir/ui/BandRow.tsx +107 -0
  389. package/src/ir/ui/BandsPanel.tsx +32 -125
  390. package/src/ir/ui/IrAboutDialog.tsx +69 -28
  391. package/src/ir/ui/IrCanvas.tsx +29 -3
  392. package/src/ir/ui/IrChart.tsx +31 -24
  393. package/src/ir/ui/IrCommandProvider.tsx +10 -3
  394. package/src/ir/ui/IrCommandTooltip.tsx +11 -2
  395. package/src/ir/ui/IrDocumentationDialog.tsx +99 -55
  396. package/src/ir/ui/IrEditor.tsx +27 -40
  397. package/src/ir/ui/IrHeader.tsx +10 -3
  398. package/src/ir/ui/IrLogo.tsx +28 -9
  399. package/src/ir/ui/IrShell.tsx +47 -96
  400. package/src/ir/ui/IrSidePanel.tsx +36 -10
  401. package/src/ir/ui/IrStatusBar.tsx +17 -12
  402. package/src/ir/ui/IrToolbar.tsx +26 -15
  403. package/src/ir/ui/IrTraces.tsx +5 -1
  404. package/src/ir/ui/RamanEditor.tsx +71 -0
  405. package/src/ir/ui/SpectraPanel.tsx +2 -1
  406. package/src/ir/ui/SpectrumRow.tsx +14 -5
  407. package/src/ir/ui/VibrationalEditor.tsx +113 -0
  408. package/src/ir/ui/bandsTsv.ts +46 -0
  409. package/src/ir/ui/index.ts +1 -0
  410. package/src/ir/ui/irActions.ts +3 -3
  411. package/src/ir/ui/irChartProps.ts +21 -4
  412. package/src/ir/ui/irCommandContext.tsx +18 -3
  413. package/src/ir/ui/irHostPanels.ts +76 -0
  414. package/src/ir/ui/useIrEditor.ts +20 -8
  415. package/src/ir/ui/useIrHandle.ts +51 -0
  416. package/src/ir/ui/useIrSide.ts +60 -0
  417. package/src/ir/ui/useIrText.ts +170 -0
  418. package/src/ir/ui/useIrZoom.ts +22 -3
  419. package/src/ir/ui/useValueAxisZoom.ts +67 -0
  420. package/src/ir.ts +3 -0
  421. package/src/locales/de.json +29 -2
  422. package/src/locales/en.json +29 -2
  423. package/src/locales/es.json +29 -2
  424. package/src/locales/fr.json +29 -2
  425. package/src/locales/it.json +29 -2
  426. package/src/molecule3d/core/animatedPng.ts +79 -0
  427. package/src/molecule3d/core/file.ts +23 -0
  428. package/src/molecule3d/core/index.ts +3 -1
  429. package/src/molecule3d/core/settings.ts +0 -8
  430. package/src/molecule3d/ui/Molecule3DExport.tsx +43 -5
  431. package/src/molecule3d/ui/Molecule3DToolbar.tsx +9 -2
  432. package/src/molecule3d/ui/MoleculeCanvas3D.tsx +24 -38
  433. package/src/molecule3d/ui/drawScene.ts +2 -1
  434. package/src/molecule3d/ui/exportMoleculeImage.ts +28 -3
  435. package/src/molecule3d/ui/moleculeFrames.ts +88 -0
  436. package/src/molecule3d/ui/moleculeViewer3DProps.ts +14 -5
  437. package/src/molecule3d/ui/renderMolecule.ts +5 -3
  438. package/src/molecule3d/ui/sceneDrawer.ts +14 -2
  439. package/src/molecule3d/ui/useImageExport.ts +22 -5
  440. package/src/molecule3d/ui/useMoleculeScene.ts +2 -1
  441. package/src/molecule3d/ui/useMoleculeViewer.ts +46 -0
  442. package/src/molecule3d/ui/usePolarSurfaceArea.ts +6 -4
  443. package/src/molecule3d/ui/viewer.ts +34 -27
  444. package/src/molecule3d/ui/viewerTypes.ts +6 -0
  445. package/src/molstar/core/captureScene.ts +85 -2
  446. package/src/molstar/core/index.ts +13 -2
  447. package/src/molstar/core/trajectory.ts +117 -0
  448. package/src/panel/ui/PanelRail.tsx +3 -0
  449. package/src/raman.ts +20 -0
  450. package/src/router/core/basePath.ts +2 -2
  451. package/src/router/core/siteAddresses.ts +1 -1
  452. package/src/seo/core/siteFiles.ts +1 -1
  453. package/src/server/answerAddresses.ts +3 -3
  454. package/src/structure/core/index.ts +8 -0
  455. package/src/structure/core/structureTransfer.ts +37 -0
  456. package/src/structure/ui/EditorImportButton.tsx +59 -0
  457. package/src/structure/ui/EditorImportProblem.tsx +63 -0
  458. package/src/structure/ui/StructureDrop.tsx +66 -0
  459. package/src/structure/ui/StructureDropOverlay.tsx +50 -0
  460. package/src/structure/ui/StructureEditor.tsx +49 -134
  461. package/src/structure/ui/importedStructure.ts +83 -0
  462. package/src/structure/ui/index.ts +2 -0
  463. package/src/structure/ui/structureEditorProps.ts +103 -0
  464. package/src/structure/ui/useDebouncedChange.ts +41 -0
  465. package/src/structure/ui/useStructureDrop.ts +76 -0
  466. package/src/structure/ui/useStructureImport.ts +122 -0
@@ -6,9 +6,9 @@
6
6
  * The two are written however the deployment writes them — an origin, an
7
7
  * origin and a mount, with or without a trailing slash — and a page is named
8
8
  * from the site's own root, `/titration` and `titration` alike: every helper
9
- * joins the two with exactly one slash, so `https://www.cheminfo.org/surge`
10
- * and `https://www.cheminfo.org/surge/` both put `/generator` at
11
- * `https://www.cheminfo.org/surge/generator`.
9
+ * joins the two with exactly one slash, so `https://www.cheminfo.org/isomers`
10
+ * and `https://www.cheminfo.org/isomers/` both put `/generator` at
11
+ * `https://www.cheminfo.org/isomers/generator`.
12
12
  */
13
13
 
14
14
  import { trimTrailingSlash } from '../router/core/address.ts';
@@ -82,3 +82,11 @@ export type {
82
82
  StructureSourceInput,
83
83
  } from './structureSource.ts';
84
84
  export { structureSource } from './structureSource.ts';
85
+ export type {
86
+ StructureTransfer,
87
+ StructureTransferSource,
88
+ } from './structureTransfer.ts';
89
+ export {
90
+ carriesStructure,
91
+ readStructureTransfer,
92
+ } from './structureTransfer.ts';
@@ -0,0 +1,37 @@
1
+ /** What a paste or a drop carried that a structure can be read from. */
2
+ export type StructureTransfer =
3
+ { kind: 'files'; files: File[] } | { kind: 'text'; text: string };
4
+
5
+ /** The part of a `DataTransfer` a structure is read from. */
6
+ export interface StructureTransferSource {
7
+ files: ArrayLike<File>;
8
+ getData: (format: string) => string;
9
+ }
10
+
11
+ /**
12
+ * What a paste or a drop holds: its files when it carries any, otherwise its
13
+ * text — a SMILES, an idCode, a molfile. A file copied in the file manager also
14
+ * carries its name as text, so the files win.
15
+ * @param transfer - The clipboard or drag data, `null` when the event has none.
16
+ * @returns The files or the trimmed text, or `null` when there is nothing.
17
+ */
18
+ export function readStructureTransfer(
19
+ transfer: StructureTransferSource | null,
20
+ ): StructureTransfer | null {
21
+ if (transfer === null) return null;
22
+ if (transfer.files.length > 0) {
23
+ return { kind: 'files', files: Array.from(transfer.files) };
24
+ }
25
+ const text = transfer.getData('text').trim();
26
+ return text === '' ? null : { kind: 'text', text };
27
+ }
28
+
29
+ /**
30
+ * Whether a drag in progress may carry a structure. Until the drop only the
31
+ * types are readable, never the content, so a file or plain text is enough.
32
+ * @param types - `DataTransfer.types` of the drag.
33
+ * @returns Whether it is worth offering to take the drop.
34
+ */
35
+ export function carriesStructure(types: readonly string[]): boolean {
36
+ return types.includes('Files') || types.includes('text/plain');
37
+ }
@@ -0,0 +1,59 @@
1
+ import { Button } from '@blueprintjs/core';
2
+ import type { ReactElement } from 'react';
3
+ import { useRef } from 'react';
4
+
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
7
+ import type { StructureTransfer } from '../core/structureTransfer.ts';
8
+
9
+ /** What {@link EditorImportButton} needs. */
10
+ export interface EditorImportButtonProps {
11
+ /** Called with the files chosen. */
12
+ onImport: (transfer: StructureTransfer) => void;
13
+ /**
14
+ * The file types the picker offers, as an `accept` attribute.
15
+ * @default undefined
16
+ */
17
+ accept?: string;
18
+ }
19
+
20
+ /**
21
+ * The editor's open button, beside the export one, for a visitor who cannot
22
+ * drag a file onto the canvas — on a phone, or from a picker.
23
+ * @param props - See {@link EditorImportButtonProps}.
24
+ * @returns The button and its hidden file input.
25
+ */
26
+ export function EditorImportButton(
27
+ props: EditorImportButtonProps,
28
+ ): ReactElement {
29
+ const { onImport, accept } = props;
30
+ const t = useChromeT();
31
+ const input = useRef<HTMLInputElement>(null);
32
+
33
+ return (
34
+ <>
35
+ <ActionTooltip content={t('structure.import.open')} placement="left">
36
+ <Button
37
+ variant="minimal"
38
+ size="small"
39
+ icon="import"
40
+ aria-label={t('structure.import.open')}
41
+ onClick={() => input.current?.click()}
42
+ />
43
+ </ActionTooltip>
44
+ <input
45
+ ref={input}
46
+ type="file"
47
+ accept={accept}
48
+ hidden
49
+ data-testid="structure-editor-file"
50
+ onChange={(event) => {
51
+ const files = Array.from(event.currentTarget.files ?? []);
52
+ // Cleared, so choosing the same file again is a change.
53
+ event.currentTarget.value = '';
54
+ if (files.length > 0) onImport({ kind: 'files', files });
55
+ }}
56
+ />
57
+ </>
58
+ );
59
+ }
@@ -0,0 +1,63 @@
1
+ import { Button, Callout } from '@blueprintjs/core';
2
+ import type { CSSProperties, ReactElement } from 'react';
3
+
4
+ import { useChromeT } from '../../i18n/ui/useT.ts';
5
+
6
+ import type { StructureImportProblem } from './useStructureImport.ts';
7
+
8
+ /** What {@link EditorImportProblem} needs. */
9
+ export interface EditorImportProblemProps {
10
+ /** What went wrong. */
11
+ problem: StructureImportProblem;
12
+ /** Forget it. */
13
+ onDismiss: () => void;
14
+ }
15
+
16
+ /**
17
+ * The line along the bottom of the canvas that says a drop loaded nothing,
18
+ * and that the drawing is still there.
19
+ * @param props - See {@link EditorImportProblemProps}.
20
+ * @returns The line.
21
+ */
22
+ export function EditorImportProblem(
23
+ props: EditorImportProblemProps,
24
+ ): ReactElement {
25
+ const { problem, onDismiss } = props;
26
+ const t = useChromeT();
27
+ return (
28
+ <div role="alert" style={PLACE}>
29
+ <Callout intent="danger" icon={null} compact style={LINE}>
30
+ <span style={TEXT}>
31
+ {problem.file === null
32
+ ? t('structure.import.unreadableText')
33
+ : t('structure.import.unreadableFile', { name: problem.file })}
34
+ </span>
35
+ <Button
36
+ variant="minimal"
37
+ size="small"
38
+ icon="cross"
39
+ aria-label={t('overlay.dismiss')}
40
+ onClick={onDismiss}
41
+ />
42
+ </Callout>
43
+ </div>
44
+ );
45
+ }
46
+
47
+ /** Clear of the tool palette, two 21px columns in a 2px border, at the left. */
48
+ const PLACE: CSSProperties = {
49
+ position: 'absolute',
50
+ right: 4,
51
+ bottom: 4,
52
+ left: 52,
53
+ zIndex: 10,
54
+ };
55
+
56
+ const LINE: CSSProperties = {
57
+ display: 'flex',
58
+ alignItems: 'center',
59
+ gap: 6,
60
+ fontSize: 12,
61
+ };
62
+
63
+ const TEXT: CSSProperties = { flex: 1 };
@@ -0,0 +1,66 @@
1
+ import type { CSSProperties, ReactElement, ReactNode } from 'react';
2
+
3
+ import { useChromeT } from '../../i18n/ui/useT.ts';
4
+ import type { StructureTransfer } from '../core/structureTransfer.ts';
5
+
6
+ import { StructureDropOverlay } from './StructureDropOverlay.tsx';
7
+ import { useStructureDrop } from './useStructureDrop.ts';
8
+
9
+ /** What {@link StructureDrop} needs. */
10
+ export interface StructureDropProps {
11
+ /** Called with the files or the text dropped. */
12
+ onDrop: (transfer: StructureTransfer) => void;
13
+ /** What the drop lands on. */
14
+ children: ReactNode;
15
+ /**
16
+ * What the overlay says while something is dragged over.
17
+ * @default 'Drop to load the structure', in the page's language
18
+ */
19
+ label?: string;
20
+ /**
21
+ * Take no drop, while a load is already running for instance.
22
+ * @default false
23
+ */
24
+ disabled?: boolean;
25
+ /**
26
+ * Class of the wrapping element.
27
+ * @default undefined
28
+ */
29
+ className?: string;
30
+ /**
31
+ * Extra style for the wrapping element, which is positioned so the overlay
32
+ * covers it.
33
+ * @default undefined
34
+ */
35
+ style?: CSSProperties;
36
+ }
37
+
38
+ /**
39
+ * Make an area take a structure file, or structure text dragged from another
40
+ * page, with the same veil the structure editor raises over its canvas. What
41
+ * was dropped is handed over unread: the page knows which formats it takes.
42
+ * @param props - See {@link StructureDropProps}.
43
+ * @returns The area.
44
+ */
45
+ export function StructureDrop(props: StructureDropProps): ReactElement {
46
+ const { onDrop, children, label, disabled = false } = props;
47
+ const { className, style } = props;
48
+ const t = useChromeT();
49
+ const drop = useStructureDrop(disabled ? undefined : onDrop);
50
+
51
+ return (
52
+ <div
53
+ className={className}
54
+ style={{ position: 'relative', ...style }}
55
+ {...drop.targetProps}
56
+ >
57
+ {children}
58
+ {drop.over ? (
59
+ <StructureDropOverlay
60
+ label={label ?? t('structure.import.drop')}
61
+ handlers={drop.overlayProps}
62
+ />
63
+ ) : null}
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,50 @@
1
+ import { Icon } from '@blueprintjs/core';
2
+ import type { CSSProperties, ReactElement } from 'react';
3
+
4
+ import type { DropHandlers } from './useStructureDrop.ts';
5
+
6
+ /** What {@link StructureDropOverlay} needs. */
7
+ export interface StructureDropOverlayProps {
8
+ /** What the overlay says. */
9
+ label: string;
10
+ /** The overlay handlers of `useStructureDrop`. */
11
+ handlers: DropHandlers;
12
+ }
13
+
14
+ /**
15
+ * The veil a drop target raises while a file or text is dragged over it.
16
+ * @param props - See {@link StructureDropOverlayProps}.
17
+ * @returns The overlay.
18
+ */
19
+ export function StructureDropOverlay(
20
+ props: StructureDropOverlayProps,
21
+ ): ReactElement {
22
+ const { label, handlers } = props;
23
+ return (
24
+ <div data-testid="structure-drop-overlay" style={OVERLAY} {...handlers}>
25
+ {/* Nothing inside takes the pointer, so leaving the overlay is the only
26
+ dragleave it hears. */}
27
+ <Icon icon="import" size={28} style={PASSIVE} />
28
+ <span style={PASSIVE}>{label}</span>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ const OVERLAY: CSSProperties = {
34
+ position: 'absolute',
35
+ inset: 0,
36
+ zIndex: 20,
37
+ display: 'flex',
38
+ flexDirection: 'column',
39
+ alignItems: 'center',
40
+ justifyContent: 'center',
41
+ gap: 8,
42
+ border: '2px dashed var(--accent)',
43
+ borderRadius: 'inherit',
44
+ background: 'color-mix(in oklab, var(--accent) 10%, rgb(255 255 255 / 88%))',
45
+ color: 'var(--accent)',
46
+ fontSize: 14,
47
+ fontWeight: 600,
48
+ };
49
+
50
+ const PASSIVE: CSSProperties = { pointerEvents: 'none' };
@@ -8,29 +8,26 @@
8
8
  */
9
9
 
10
10
  import type { CSSProperties, ReactElement } from 'react';
11
- import {
12
- Suspense,
13
- lazy,
14
- useCallback,
15
- useEffect,
16
- useRef,
17
- useState,
18
- } from 'react';
19
- import type { CanvasEditorInputFormat } from 'react-ocl';
11
+ import { Suspense, lazy, useCallback } from 'react';
20
12
 
21
13
  import { useChromeT } from '../../i18n/ui/useT.ts';
22
14
  import { TOKEN } from '../../tokens/core/familyTokens.ts';
23
- import { createPendingCall } from '../core/pendingCall.ts';
24
15
 
25
16
  import { EditorHelpButton } from './EditorHelpButton.tsx';
17
+ import { EditorImportButton } from './EditorImportButton.tsx';
18
+ import { EditorImportProblem } from './EditorImportProblem.tsx';
19
+ import { StructureDropOverlay } from './StructureDropOverlay.tsx';
26
20
  import { ToolbarTooltip } from './ToolbarTooltip.tsx';
27
- import type {
28
- StructureEditorChange,
29
- StructureEditorMode,
30
- } from './editorChange.ts';
21
+ import type { StructureEditorChange } from './editorChange.ts';
22
+ import type { StructureEditorProps } from './structureEditorProps.ts';
23
+ import { useDebouncedChange } from './useDebouncedChange.ts';
31
24
  import { useEditorStructure } from './useEditorStructure.ts';
25
+ import { useStructureDrop } from './useStructureDrop.ts';
26
+ import { useStructureImport } from './useStructureImport.ts';
32
27
  import { useToolbarFloor } from './useToolbarFloor.ts';
33
28
 
29
+ export type { StructureEditorProps } from './structureEditorProps.ts';
30
+
34
31
  const EditorExportButton = lazy(async () => {
35
32
  const module = await import('./EditorExportButton.tsx');
36
33
  return { default: module.EditorExportButton };
@@ -41,84 +38,6 @@ const EditorCanvas = lazy(async () => {
41
38
  return { default: module.EditorCanvas };
42
39
  });
43
40
 
44
- /** What {@link StructureEditor} needs. */
45
- export interface StructureEditorProps {
46
- /**
47
- * Called after every edit, once the drawing has been still for `debounce`
48
- * milliseconds, with every notation read out of the editor.
49
- */
50
- onChange: (change: StructureEditorChange) => void;
51
- /**
52
- * Draw a query fragment rather than a whole structure, which is what a
53
- * substructure filter needs.
54
- * @default false
55
- */
56
- fragment?: boolean;
57
- /**
58
- * How `value` is written.
59
- * @default 'idcode'
60
- */
61
- inputFormat?: CanvasEditorInputFormat;
62
- /**
63
- * What the canvas holds. Read once, when the editor appears and again on
64
- * every change of `revision`: the editor is uncontrolled, so feeding the
65
- * drawing back into it would replace the structure and reset every
66
- * coordinate under the pen.
67
- * @default ''
68
- */
69
- value?: string;
70
- /**
71
- * Bumped by the caller to load `value` into the canvas again, which is what
72
- * an example, a share link or a Clear button does. Changing it discards
73
- * whatever was being drawn.
74
- * @default 0
75
- */
76
- revision?: number;
77
- /**
78
- * How long the drawing has to be still before `onChange` is called, in
79
- * milliseconds. Long enough that drawing a ring does not publish six
80
- * structures; `0` reports every stroke.
81
- * @default 300
82
- */
83
- debounce?: number;
84
- /**
85
- * Smallest height of the drawing area, in pixels. Raised to whatever the
86
- * toolbar needs, which is usually more.
87
- * @default 320
88
- */
89
- minHeight?: number;
90
- /**
91
- * Whether the editor draws one structure or a reaction. A reaction canvas
92
- * has its own toolbar and its own arrow.
93
- * @default 'molecule'
94
- */
95
- mode?: StructureEditorMode;
96
- /**
97
- * Explain each toolbar button in a tooltip, and put a button in the corner
98
- * that opens a guide to the mouse and the keyboard, which F1 opens too.
99
- * @default true
100
- */
101
- help?: boolean;
102
- /**
103
- * Put a button in the corner that opens every notation of the drawing — its
104
- * SMILES, its molfiles, its canonical identifiers — and the picture of it,
105
- * ready to copy or to save. A reaction has none of those, so it is never
106
- * offered one.
107
- * @default true
108
- */
109
- exportable?: boolean;
110
- /**
111
- * Class the container carries, so a site can reach it from its stylesheet.
112
- * @default undefined
113
- */
114
- className?: string;
115
- /**
116
- * Extra style for the container, merged over the packaged one.
117
- * @default undefined
118
- */
119
- style?: CSSProperties;
120
- }
121
-
122
41
  /**
123
42
  * The canvas structure editor, sized to fill its container and never to hide
124
43
  * part of its toolbar, with a tooltip on every toolbar button and a guide to
@@ -138,13 +57,15 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
138
57
  mode = 'molecule',
139
58
  help = true,
140
59
  exportable = true,
60
+ importable = true,
61
+ onImport,
141
62
  className,
142
63
  style,
143
64
  } = props;
144
65
 
145
66
  const t = useChromeT();
146
67
  const containerRef = useToolbarFloor({ minHeight, revision });
147
- const handleChange = useDebounced(onChange, debounce, revision);
68
+ const handleChange = useDebouncedChange(onChange, debounce, revision);
148
69
  const drawing = useEditorStructure({ value, inputFormat, revision });
149
70
  const handleEdit = useCallback(
150
71
  (change: StructureEditorChange) => {
@@ -155,12 +76,21 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
155
76
  },
156
77
  [drawing, handleChange],
157
78
  );
79
+ const imports = useStructureImport({
80
+ revision,
81
+ fragment,
82
+ onImport,
83
+ onRead: handleEdit,
84
+ });
85
+ const takesImports = importable && mode === 'molecule';
86
+ const drop = useStructureDrop(takesImports ? imports.load : undefined);
158
87
 
159
88
  return (
160
89
  <div
161
90
  ref={containerRef}
162
91
  className={className}
163
92
  style={{ ...ROOT_STYLE, minHeight, ...style }}
93
+ {...drop.targetProps}
164
94
  >
165
95
  <Suspense
166
96
  fallback={
@@ -168,17 +98,23 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
168
98
  }
169
99
  >
170
100
  <EditorCanvas
171
- key={revision}
101
+ key={imports.canvasKey}
172
102
  onChange={handleEdit}
173
103
  fragment={fragment}
174
- inputFormat={inputFormat}
175
- value={value}
104
+ inputFormat={imports.idCode === null ? inputFormat : 'idcode'}
105
+ value={imports.idCode ?? value}
176
106
  mode={mode}
177
107
  />
178
108
  {help ? (
179
109
  <ToolbarTooltip containerRef={containerRef} mode={mode} />
180
110
  ) : null}
181
111
  <div style={CORNER_STYLE}>
112
+ {takesImports ? (
113
+ <EditorImportButton
114
+ onImport={imports.load}
115
+ accept={onImport === undefined ? STRUCTURE_FILES : undefined}
116
+ />
117
+ ) : null}
182
118
  {exportable && mode === 'molecule' ? (
183
119
  <EditorExportButton
184
120
  source={drawing.source}
@@ -194,47 +130,23 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
194
130
  />
195
131
  ) : null}
196
132
  </div>
133
+ {imports.problem === null ? null : (
134
+ <EditorImportProblem
135
+ problem={imports.problem}
136
+ onDismiss={imports.dismiss}
137
+ />
138
+ )}
197
139
  </Suspense>
140
+ {drop.over ? (
141
+ <StructureDropOverlay
142
+ label={t('structure.import.drop')}
143
+ handlers={drop.overlayProps}
144
+ />
145
+ ) : null}
198
146
  </div>
199
147
  );
200
148
  }
201
149
 
202
- /**
203
- * Report the last edit of a burst rather than every one of them.
204
- *
205
- * The editor's own event is read out before the wait starts, so what arrives
206
- * late is a plain object rather than a handle on an editor that has moved on.
207
- * An editor removed mid-burst — a tab switched, a card folded — still reports
208
- * its last edit, which would otherwise be lost with the timer.
209
- * @param onChange - What the caller wants told.
210
- * @param delay - How long the drawing has to be still, in milliseconds.
211
- * @param resetKey - Dropped edits: a burst still waiting when the caller
212
- * replaces the structure describes a canvas that no longer exists.
213
- * @returns The handler to give the canvas.
214
- */
215
- function useDebounced(
216
- onChange: (change: StructureEditorChange) => void,
217
- delay: number,
218
- resetKey: number,
219
- ): (change: StructureEditorChange) => void {
220
- const [pending] = useState(createPendingCall<StructureEditorChange>);
221
- const onChangeRef = useRef(onChange);
222
- useEffect(() => {
223
- onChangeRef.current = onChange;
224
- });
225
- useEffect(() => {
226
- pending.drop();
227
- }, [pending, resetKey]);
228
- useEffect(() => () => pending.flush(), [pending]);
229
-
230
- return useCallback(
231
- (change: StructureEditorChange) => {
232
- pending.push(change, delay, (value) => onChangeRef.current(value));
233
- },
234
- [pending, delay],
235
- );
236
- }
237
-
238
150
  /**
239
151
  * The canvas is positioned out of the height computation, so the container's
240
152
  * own height is what the measured toolbar floor writes on it. The `minHeight`
@@ -252,8 +164,8 @@ const ROOT_STYLE: CSSProperties = {
252
164
  };
253
165
 
254
166
  /**
255
- * The corner the editor's own buttons sit in: export first, then help, so the
256
- * one that does something to the drawing is the nearer of the two to it.
167
+ * The corner the editor's own buttons sit in: open, export, then help — the
168
+ * drawing in, the drawing out, and the guide last.
257
169
  */
258
170
  const CORNER_STYLE: CSSProperties = {
259
171
  position: 'absolute',
@@ -273,3 +185,6 @@ const LOADING_STYLE: CSSProperties = {
273
185
  color: TOKEN.textFaint,
274
186
  fontSize: 13,
275
187
  };
188
+
189
+ /** What the editor reads itself, offered first by the file picker. */
190
+ const STRUCTURE_FILES = '.mol,.sdf,.sd,.smi,.smiles,.txt';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Read a structure dropped on the editor, or opened from disk.
3
+ *
4
+ * **Not exported from `ui/index.ts`**: it value-imports `openchemlib`. The
5
+ * editor loads it on the first drop, by which time the canvas has already
6
+ * brought openchemlib in.
7
+ */
8
+
9
+ import { Canonizer, Molecule } from 'openchemlib';
10
+
11
+ import { splitEditorValue } from '../core/editorValue.ts';
12
+
13
+ import type { StructureEditorMoleculeChange } from './editorChange.ts';
14
+
15
+ /**
16
+ * Turn dropped text into what the editor reports after an edit.
17
+ *
18
+ * A molfile is read whole, so an SDF gives its first record. Anything else is
19
+ * read from its first meaningful line, as a SMILES and then as an idCode — but
20
+ * an idCode only when it is the canonical one, because openchemlib decodes
21
+ * almost any word into some molecule: `ethanol` read as an idCode has 1106
22
+ * atoms. A word holding a character no idCode holds is never decoded, since
23
+ * openchemlib does not return from some of them — `O=Cc1cccc`, a SMILES with
24
+ * an unclosed ring, is one. A 3D structure is laid out flat, since the canvas
25
+ * draws in 2D.
26
+ * @param text - The file's content or the dragged text.
27
+ * @param fragment - Whether the editor draws a query fragment.
28
+ * @returns The change, or `null` when the text holds no structure.
29
+ */
30
+ export function readImportedStructure(
31
+ text: string,
32
+ fragment: boolean,
33
+ ): StructureEditorMoleculeChange | null {
34
+ const molecule = parseStructure(text);
35
+ if (molecule === null || molecule.getAllAtoms() === 0) return null;
36
+ if (hasDepth(molecule)) molecule.inventCoordinates();
37
+ molecule.setFragment(fragment);
38
+
39
+ const canonizer = new Canonizer(molecule);
40
+ return {
41
+ mode: 'molecule',
42
+ idCode: `${canonizer.getIDCode()} ${canonizer.getEncodedCoordinates(false)}`,
43
+ molfile: molecule.toMolfile(),
44
+ smiles: molecule.toIsomericSmiles(),
45
+ molecule: molecule.getCompactCopy(),
46
+ };
47
+ }
48
+
49
+ function parseStructure(text: string): Molecule | null {
50
+ const value = splitEditorValue(text);
51
+ if (value.kind === 'molfile') {
52
+ return attempt(() => Molecule.fromMolfile(value.molfile));
53
+ }
54
+ const notation = value.entries[0]?.structure;
55
+ if (notation === undefined) return null;
56
+ return (
57
+ attempt(() => Molecule.fromSmiles(notation)) ?? canonicalIdCode(notation)
58
+ );
59
+ }
60
+
61
+ function canonicalIdCode(text: string): Molecule | null {
62
+ if (!ID_CODE.test(text)) return null;
63
+ const molecule = attempt(() => Molecule.fromIDCode(text));
64
+ return molecule?.getIDCode() === text ? molecule : null;
65
+ }
66
+
67
+ function attempt(parse: () => Molecule): Molecule | null {
68
+ try {
69
+ return parse();
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+
75
+ function hasDepth(molecule: Molecule): boolean {
76
+ for (let atom = 0; atom < molecule.getAllAtoms(); atom++) {
77
+ if (molecule.getAtomZ(atom) !== 0) return true;
78
+ }
79
+ return false;
80
+ }
81
+
82
+ /** An idCode is written in six-bit groups offset to `@`, so in `@` to DEL. */
83
+ const ID_CODE = /^[\u0040-\u007F]+$/;
@@ -21,6 +21,8 @@ export type { StructureLabels, StructureProps } from './Structure.tsx';
21
21
  export { Structure } from './Structure.tsx';
22
22
  export type { StructureEditorProps } from './StructureEditor.tsx';
23
23
  export { StructureEditor } from './StructureEditor.tsx';
24
+ export type { StructureDropProps } from './StructureDrop.tsx';
25
+ export { StructureDrop } from './StructureDrop.tsx';
24
26
  export type { StructureEditorHelpProps } from './StructureEditorHelp.tsx';
25
27
  export { StructureEditorHelp } from './StructureEditorHelp.tsx';
26
28
  export type { StructureExportDialogProps } from './StructureExportDialog.tsx';