react-cheminfo 0.38.0 → 0.39.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 (327) hide show
  1. package/lib/chart/ui/Axes.d.ts +19 -0
  2. package/lib/chart/ui/Axes.d.ts.map +1 -1
  3. package/lib/chart/ui/Axes.js +25 -5
  4. package/lib/chart/ui/Axes.js.map +1 -1
  5. package/lib/chrome/ui/NavMenuButton.d.ts.map +1 -1
  6. package/lib/chrome/ui/NavMenuButton.js +41 -11
  7. package/lib/chrome/ui/NavMenuButton.js.map +1 -1
  8. package/lib/chrome/ui/SiteHeader.js +24 -1
  9. package/lib/chrome/ui/SiteHeader.js.map +1 -1
  10. package/lib/chrome/ui/navItem.d.ts +7 -0
  11. package/lib/chrome/ui/navItem.d.ts.map +1 -1
  12. package/lib/chrome/ui/navItem.js.map +1 -1
  13. package/lib/citation/ui/entries.d.ts.map +1 -1
  14. package/lib/citation/ui/entries.js +6 -1
  15. package/lib/citation/ui/entries.js.map +1 -1
  16. package/lib/clipboard/ui/ClickToCopy.d.ts +11 -0
  17. package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
  18. package/lib/clipboard/ui/ClickToCopy.js +28 -10
  19. package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
  20. package/lib/clipboard/ui/CopyButton.d.ts +2 -1
  21. package/lib/clipboard/ui/CopyButton.d.ts.map +1 -1
  22. package/lib/clipboard/ui/CopyButton.js +2 -1
  23. package/lib/clipboard/ui/CopyButton.js.map +1 -1
  24. package/lib/clipboard/ui/CopyableValue.d.ts +24 -4
  25. package/lib/clipboard/ui/CopyableValue.d.ts.map +1 -1
  26. package/lib/clipboard/ui/CopyableValue.js +35 -3
  27. package/lib/clipboard/ui/CopyableValue.js.map +1 -1
  28. package/lib/clipboard/ui/index.d.ts +1 -1
  29. package/lib/clipboard/ui/index.d.ts.map +1 -1
  30. package/lib/clipboard/ui/index.js.map +1 -1
  31. package/lib/confirm/ui/ConfirmButton.d.ts.map +1 -1
  32. package/lib/confirm/ui/ConfirmButton.js +2 -1
  33. package/lib/confirm/ui/ConfirmButton.js.map +1 -1
  34. package/lib/delimited/ui/TableDataButton.d.ts.map +1 -1
  35. package/lib/delimited/ui/TableDataButton.js +2 -1
  36. package/lib/delimited/ui/TableDataButton.js.map +1 -1
  37. package/lib/download/core/figureSvg.d.ts.map +1 -1
  38. package/lib/download/core/figureSvg.js +37 -12
  39. package/lib/download/core/figureSvg.js.map +1 -1
  40. package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
  41. package/lib/help/ui/HelpToolbarButton.js +2 -1
  42. package/lib/help/ui/HelpToolbarButton.js.map +1 -1
  43. package/lib/i18n/core/chromeCatalog.d.ts +1 -1
  44. package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
  45. package/lib/locales/de.json +39 -4
  46. package/lib/locales/en.json +39 -4
  47. package/lib/locales/es.json +39 -4
  48. package/lib/locales/fr.json +39 -4
  49. package/lib/locales/it.json +39 -4
  50. package/lib/number/ui/NumberInput.js +1 -1
  51. package/lib/number/ui/NumberInput.js.map +1 -1
  52. package/lib/overlay/ui/OverlayIconButton.d.ts.map +1 -1
  53. package/lib/overlay/ui/OverlayIconButton.js +1 -1
  54. package/lib/overlay/ui/OverlayIconButton.js.map +1 -1
  55. package/lib/panel/ui/ClearButton.d.ts.map +1 -1
  56. package/lib/panel/ui/ClearButton.js +1 -1
  57. package/lib/panel/ui/ClearButton.js.map +1 -1
  58. package/lib/pedagogy/core/inlineMarks.d.ts +9 -5
  59. package/lib/pedagogy/core/inlineMarks.d.ts.map +1 -1
  60. package/lib/pedagogy/core/inlineMarks.js +14 -6
  61. package/lib/pedagogy/core/inlineMarks.js.map +1 -1
  62. package/lib/pedagogy/ui/GlossaryDefinition.d.ts +4 -10
  63. package/lib/pedagogy/ui/GlossaryDefinition.d.ts.map +1 -1
  64. package/lib/pedagogy/ui/GlossaryDefinition.js +7 -7
  65. package/lib/pedagogy/ui/GlossaryDefinition.js.map +1 -1
  66. package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
  67. package/lib/pedagogy/ui/GlossaryIndex.js +1 -1
  68. package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
  69. package/lib/pedagogy/ui/GlossaryProvider.d.ts +7 -0
  70. package/lib/pedagogy/ui/GlossaryProvider.d.ts.map +1 -1
  71. package/lib/pedagogy/ui/GlossaryProvider.js +3 -2
  72. package/lib/pedagogy/ui/GlossaryProvider.js.map +1 -1
  73. package/lib/pedagogy/ui/GlossaryText.d.ts +7 -2
  74. package/lib/pedagogy/ui/GlossaryText.d.ts.map +1 -1
  75. package/lib/pedagogy/ui/GlossaryText.js +3 -2
  76. package/lib/pedagogy/ui/GlossaryText.js.map +1 -1
  77. package/lib/pedagogy/ui/InlineText.d.ts +8 -2
  78. package/lib/pedagogy/ui/InlineText.d.ts.map +1 -1
  79. package/lib/pedagogy/ui/InlineText.js +7 -2
  80. package/lib/pedagogy/ui/InlineText.js.map +1 -1
  81. package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts +4 -1
  82. package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts.map +1 -1
  83. package/lib/pedagogy/ui/ReferenceSectionBlock.js +2 -1
  84. package/lib/pedagogy/ui/ReferenceSectionBlock.js.map +1 -1
  85. package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
  86. package/lib/pedagogy/ui/SyntaxTooltip.js +11 -10
  87. package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
  88. package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
  89. package/lib/pedagogy/ui/TutorialStepStrip.js +18 -4
  90. package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
  91. package/lib/pedagogy/ui/glossaryContext.d.ts +7 -0
  92. package/lib/pedagogy/ui/glossaryContext.d.ts.map +1 -1
  93. package/lib/pedagogy/ui/glossaryContext.js.map +1 -1
  94. package/lib/pedagogy/ui/index.d.ts +1 -1
  95. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  96. package/lib/pedagogy/ui/inlineSegments.d.ts +5 -0
  97. package/lib/pedagogy/ui/inlineSegments.d.ts.map +1 -1
  98. package/lib/pedagogy/ui/inlineSegments.js +2 -0
  99. package/lib/pedagogy/ui/inlineSegments.js.map +1 -1
  100. package/lib/pedagogy/ui/pedagogyStyle.d.ts +8 -9
  101. package/lib/pedagogy/ui/pedagogyStyle.d.ts.map +1 -1
  102. package/lib/pedagogy/ui/pedagogyStyle.js +10 -18
  103. package/lib/pedagogy/ui/pedagogyStyle.js.map +1 -1
  104. package/lib/seo/core/plainDescription.d.ts +2 -2
  105. package/lib/seo/core/plainDescription.js +5 -2
  106. package/lib/seo/core/plainDescription.js.map +1 -1
  107. package/lib/share/core/devices.d.ts +41 -0
  108. package/lib/share/core/devices.d.ts.map +1 -0
  109. package/lib/share/core/devices.js +58 -0
  110. package/lib/share/core/devices.js.map +1 -0
  111. package/lib/share/core/index.d.ts +4 -0
  112. package/lib/share/core/index.d.ts.map +1 -1
  113. package/lib/share/core/index.js +2 -0
  114. package/lib/share/core/index.js.map +1 -1
  115. package/lib/share/core/regions.d.ts +43 -0
  116. package/lib/share/core/regions.d.ts.map +1 -0
  117. package/lib/share/core/regions.js +71 -0
  118. package/lib/share/core/regions.js.map +1 -0
  119. package/lib/share/ui/HiddenPartsProvider.d.ts.map +1 -1
  120. package/lib/share/ui/HiddenPartsProvider.js +4 -1
  121. package/lib/share/ui/HiddenPartsProvider.js.map +1 -1
  122. package/lib/share/ui/PagePart.d.ts.map +1 -1
  123. package/lib/share/ui/PagePart.js +10 -1
  124. package/lib/share/ui/PagePart.js.map +1 -1
  125. package/lib/share/ui/ShareButton.d.ts.map +1 -1
  126. package/lib/share/ui/ShareButton.js +3 -4
  127. package/lib/share/ui/ShareButton.js.map +1 -1
  128. package/lib/share/ui/ShareConfigOptions.d.ts +6 -1
  129. package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
  130. package/lib/share/ui/ShareConfigOptions.js +6 -13
  131. package/lib/share/ui/ShareConfigOptions.js.map +1 -1
  132. package/lib/share/ui/ShareDialog.d.ts +14 -0
  133. package/lib/share/ui/ShareDialog.d.ts.map +1 -1
  134. package/lib/share/ui/ShareDialog.js +3 -3
  135. package/lib/share/ui/ShareDialog.js.map +1 -1
  136. package/lib/share/ui/ShareDialogContent.d.ts +2 -2
  137. package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
  138. package/lib/share/ui/ShareDialogContent.js +36 -30
  139. package/lib/share/ui/ShareDialogContent.js.map +1 -1
  140. package/lib/share/ui/ShareLinkBar.d.ts +21 -0
  141. package/lib/share/ui/ShareLinkBar.d.ts.map +1 -0
  142. package/lib/share/ui/ShareLinkBar.js +32 -0
  143. package/lib/share/ui/ShareLinkBar.js.map +1 -0
  144. package/lib/share/ui/SharePanes.d.ts +17 -0
  145. package/lib/share/ui/SharePanes.d.ts.map +1 -0
  146. package/lib/share/ui/SharePanes.js +27 -0
  147. package/lib/share/ui/SharePanes.js.map +1 -0
  148. package/lib/share/ui/SharePartOptions.d.ts +9 -3
  149. package/lib/share/ui/SharePartOptions.d.ts.map +1 -1
  150. package/lib/share/ui/SharePartOptions.js +12 -16
  151. package/lib/share/ui/SharePartOptions.js.map +1 -1
  152. package/lib/share/ui/SharePartRow.d.ts +37 -0
  153. package/lib/share/ui/SharePartRow.d.ts.map +1 -0
  154. package/lib/share/ui/SharePartRow.js +25 -0
  155. package/lib/share/ui/SharePartRow.js.map +1 -0
  156. package/lib/share/ui/SharePresetTabs.d.ts +10 -7
  157. package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
  158. package/lib/share/ui/SharePresetTabs.js +17 -17
  159. package/lib/share/ui/SharePresetTabs.js.map +1 -1
  160. package/lib/share/ui/SharePreview.d.ts +32 -0
  161. package/lib/share/ui/SharePreview.d.ts.map +1 -0
  162. package/lib/share/ui/SharePreview.js +104 -0
  163. package/lib/share/ui/SharePreview.js.map +1 -0
  164. package/lib/share/ui/SharePreviewDevices.d.ts +20 -0
  165. package/lib/share/ui/SharePreviewDevices.d.ts.map +1 -0
  166. package/lib/share/ui/SharePreviewDevices.js +40 -0
  167. package/lib/share/ui/SharePreviewDevices.js.map +1 -0
  168. package/lib/share/ui/index.d.ts +1 -0
  169. package/lib/share/ui/index.d.ts.map +1 -1
  170. package/lib/share/ui/index.js.map +1 -1
  171. package/lib/share/ui/shareMarking.d.ts +14 -0
  172. package/lib/share/ui/shareMarking.d.ts.map +1 -0
  173. package/lib/share/ui/shareMarking.js +17 -0
  174. package/lib/share/ui/shareMarking.js.map +1 -0
  175. package/lib/share/ui/useShareRegionReports.d.ts +12 -0
  176. package/lib/share/ui/useShareRegionReports.d.ts.map +1 -0
  177. package/lib/share/ui/useShareRegionReports.js +73 -0
  178. package/lib/share/ui/useShareRegionReports.js.map +1 -0
  179. package/lib/shared/ui/ActionTooltip.d.ts +42 -0
  180. package/lib/shared/ui/ActionTooltip.d.ts.map +1 -0
  181. package/lib/shared/ui/ActionTooltip.js +21 -0
  182. package/lib/shared/ui/ActionTooltip.js.map +1 -0
  183. package/lib/shared/ui/index.d.ts +4 -0
  184. package/lib/shared/ui/index.d.ts.map +1 -1
  185. package/lib/shared/ui/index.js +2 -0
  186. package/lib/shared/ui/index.js.map +1 -1
  187. package/lib/shared/ui/useActionTooltip.d.ts +48 -0
  188. package/lib/shared/ui/useActionTooltip.d.ts.map +1 -0
  189. package/lib/shared/ui/useActionTooltip.js +78 -0
  190. package/lib/shared/ui/useActionTooltip.js.map +1 -0
  191. package/lib/structure/core/index.d.ts +2 -0
  192. package/lib/structure/core/index.d.ts.map +1 -1
  193. package/lib/structure/core/index.js +1 -0
  194. package/lib/structure/core/index.js.map +1 -1
  195. package/lib/structure/core/sourceMolecule.d.ts +18 -0
  196. package/lib/structure/core/sourceMolecule.d.ts.map +1 -0
  197. package/lib/structure/core/sourceMolecule.js +26 -0
  198. package/lib/structure/core/sourceMolecule.js.map +1 -0
  199. package/lib/structure/core/structureNotations.d.ts +57 -0
  200. package/lib/structure/core/structureNotations.d.ts.map +1 -0
  201. package/lib/structure/core/structureNotations.js +74 -0
  202. package/lib/structure/core/structureNotations.js.map +1 -0
  203. package/lib/structure/core/structurePicture.d.ts +49 -0
  204. package/lib/structure/core/structurePicture.d.ts.map +1 -0
  205. package/lib/structure/core/structurePicture.js +83 -0
  206. package/lib/structure/core/structurePicture.js.map +1 -0
  207. package/lib/structure/ui/EditorExportButton.d.ts +23 -0
  208. package/lib/structure/ui/EditorExportButton.d.ts.map +1 -0
  209. package/lib/structure/ui/EditorExportButton.js +23 -0
  210. package/lib/structure/ui/EditorExportButton.js.map +1 -0
  211. package/lib/structure/ui/EditorHelpButton.d.ts +5 -2
  212. package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
  213. package/lib/structure/ui/EditorHelpButton.js +8 -9
  214. package/lib/structure/ui/EditorHelpButton.js.map +1 -1
  215. package/lib/structure/ui/StructureEditor.d.ts +8 -0
  216. package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
  217. package/lib/structure/ui/StructureEditor.js +26 -3
  218. package/lib/structure/ui/StructureEditor.js.map +1 -1
  219. package/lib/structure/ui/StructureExportDialog.d.ts +34 -0
  220. package/lib/structure/ui/StructureExportDialog.d.ts.map +1 -0
  221. package/lib/structure/ui/StructureExportDialog.js +43 -0
  222. package/lib/structure/ui/StructureExportDialog.js.map +1 -0
  223. package/lib/structure/ui/StructureExportPanel.d.ts +37 -0
  224. package/lib/structure/ui/StructureExportPanel.d.ts.map +1 -0
  225. package/lib/structure/ui/StructureExportPanel.js +75 -0
  226. package/lib/structure/ui/StructureExportPanel.js.map +1 -0
  227. package/lib/structure/ui/StructureNotationRow.d.ts +22 -0
  228. package/lib/structure/ui/StructureNotationRow.d.ts.map +1 -0
  229. package/lib/structure/ui/StructureNotationRow.js +34 -0
  230. package/lib/structure/ui/StructureNotationRow.js.map +1 -0
  231. package/lib/structure/ui/StructurePicturePane.d.ts +23 -0
  232. package/lib/structure/ui/StructurePicturePane.d.ts.map +1 -0
  233. package/lib/structure/ui/StructurePicturePane.js +113 -0
  234. package/lib/structure/ui/StructurePicturePane.js.map +1 -0
  235. package/lib/structure/ui/StructureSvg.d.ts.map +1 -1
  236. package/lib/structure/ui/StructureSvg.js +2 -18
  237. package/lib/structure/ui/StructureSvg.js.map +1 -1
  238. package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
  239. package/lib/structure/ui/ToolbarTooltip.js +1 -2
  240. package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
  241. package/lib/structure/ui/index.d.ts +7 -3
  242. package/lib/structure/ui/index.d.ts.map +1 -1
  243. package/lib/structure/ui/index.js +5 -3
  244. package/lib/structure/ui/index.js.map +1 -1
  245. package/lib/structure/ui/structureNotationText.d.ts +23 -0
  246. package/lib/structure/ui/structureNotationText.d.ts.map +1 -0
  247. package/lib/structure/ui/structureNotationText.js +42 -0
  248. package/lib/structure/ui/structureNotationText.js.map +1 -0
  249. package/lib/structure/ui/useEditorStructure.d.ts +37 -0
  250. package/lib/structure/ui/useEditorStructure.d.ts.map +1 -0
  251. package/lib/structure/ui/useEditorStructure.js +70 -0
  252. package/lib/structure/ui/useEditorStructure.js.map +1 -0
  253. package/package.json +1 -1
  254. package/src/chart/ui/Axes.tsx +53 -5
  255. package/src/chrome/ui/NavMenuButton.tsx +61 -18
  256. package/src/chrome/ui/SiteHeader.tsx +37 -1
  257. package/src/chrome/ui/navItem.ts +7 -0
  258. package/src/citation/ui/entries.tsx +10 -2
  259. package/src/clipboard/ui/ClickToCopy.tsx +47 -13
  260. package/src/clipboard/ui/CopyButton.tsx +4 -2
  261. package/src/clipboard/ui/CopyableValue.tsx +88 -13
  262. package/src/clipboard/ui/index.ts +5 -1
  263. package/src/confirm/ui/ConfirmButton.tsx +2 -0
  264. package/src/delimited/ui/TableDataButton.tsx +2 -1
  265. package/src/download/core/figureSvg.ts +42 -10
  266. package/src/help/ui/HelpToolbarButton.tsx +2 -1
  267. package/src/locales/de.json +39 -4
  268. package/src/locales/en.json +39 -4
  269. package/src/locales/es.json +39 -4
  270. package/src/locales/fr.json +39 -4
  271. package/src/locales/it.json +39 -4
  272. package/src/number/ui/NumberInput.tsx +1 -1
  273. package/src/overlay/ui/OverlayIconButton.tsx +1 -0
  274. package/src/panel/ui/ClearButton.tsx +1 -0
  275. package/src/pedagogy/core/inlineMarks.ts +15 -7
  276. package/src/pedagogy/ui/GlossaryDefinition.tsx +8 -18
  277. package/src/pedagogy/ui/GlossaryIndex.tsx +0 -1
  278. package/src/pedagogy/ui/GlossaryProvider.tsx +10 -2
  279. package/src/pedagogy/ui/GlossaryText.tsx +10 -2
  280. package/src/pedagogy/ui/InlineText.tsx +21 -4
  281. package/src/pedagogy/ui/ReferenceSectionBlock.tsx +8 -2
  282. package/src/pedagogy/ui/SyntaxTooltip.tsx +11 -9
  283. package/src/pedagogy/ui/TutorialStepStrip.tsx +50 -18
  284. package/src/pedagogy/ui/glossaryContext.ts +7 -0
  285. package/src/pedagogy/ui/index.ts +1 -1
  286. package/src/pedagogy/ui/inlineSegments.tsx +7 -0
  287. package/src/pedagogy/ui/pedagogyStyle.ts +12 -24
  288. package/src/seo/core/plainDescription.ts +4 -2
  289. package/src/share/core/devices.ts +80 -0
  290. package/src/share/core/index.ts +14 -0
  291. package/src/share/core/regions.ts +87 -0
  292. package/src/share/ui/HiddenPartsProvider.tsx +6 -1
  293. package/src/share/ui/PagePart.tsx +12 -1
  294. package/src/share/ui/ShareButton.tsx +3 -6
  295. package/src/share/ui/ShareConfigOptions.tsx +25 -16
  296. package/src/share/ui/ShareDialog.tsx +17 -3
  297. package/src/share/ui/ShareDialogContent.tsx +80 -77
  298. package/src/share/ui/ShareLinkBar.tsx +70 -0
  299. package/src/share/ui/SharePanes.tsx +62 -0
  300. package/src/share/ui/SharePartOptions.tsx +25 -26
  301. package/src/share/ui/SharePartRow.tsx +78 -0
  302. package/src/share/ui/SharePresetTabs.tsx +36 -43
  303. package/src/share/ui/SharePreview.tsx +204 -0
  304. package/src/share/ui/SharePreviewDevices.tsx +70 -0
  305. package/src/share/ui/index.ts +1 -0
  306. package/src/share/ui/shareMarking.ts +18 -0
  307. package/src/share/ui/useShareRegionReports.ts +84 -0
  308. package/src/shared/ui/ActionTooltip.tsx +70 -0
  309. package/src/shared/ui/index.ts +7 -0
  310. package/src/shared/ui/useActionTooltip.ts +103 -0
  311. package/src/structure/core/index.ts +5 -0
  312. package/src/structure/core/sourceMolecule.ts +26 -0
  313. package/src/structure/core/structureNotations.ts +125 -0
  314. package/src/structure/core/structurePicture.ts +119 -0
  315. package/src/structure/ui/EditorExportButton.tsx +62 -0
  316. package/src/structure/ui/EditorHelpButton.tsx +26 -30
  317. package/src/structure/ui/StructureEditor.tsx +51 -5
  318. package/src/structure/ui/StructureExportDialog.tsx +90 -0
  319. package/src/structure/ui/StructureExportPanel.tsx +156 -0
  320. package/src/structure/ui/StructureNotationRow.tsx +74 -0
  321. package/src/structure/ui/StructurePicturePane.tsx +208 -0
  322. package/src/structure/ui/StructureSvg.tsx +3 -12
  323. package/src/structure/ui/ToolbarTooltip.tsx +1 -1
  324. package/src/structure/ui/index.ts +7 -3
  325. package/src/structure/ui/structureNotationText.ts +56 -0
  326. package/src/structure/ui/useEditorStructure.ts +119 -0
  327. package/styles/chrome.css +414 -14
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Read the notation a depiction was handed into the molecule it draws.
3
+ *
4
+ * **Not exported from `core/index.ts`**: it value-imports `openchemlib`, so a
5
+ * barrel carrying it would pull the whole library into every site that imports
6
+ * `react-cheminfo/core`. The depiction and the export dialog both load it
7
+ * lazily, which is where openchemlib already is.
8
+ */
9
+
10
+ import { Molecule } from 'openchemlib';
11
+
12
+ import type { StructureSource } from './structureSource.ts';
13
+
14
+ /**
15
+ * Parse one picked notation.
16
+ * @param source - The notation, as `structureSource` picked it.
17
+ * @returns The molecule, which holds no atom for an empty source.
18
+ * @throws {Error} Whatever OpenChemLib throws on a notation it cannot read.
19
+ */
20
+ export function sourceMolecule(source: StructureSource): Molecule {
21
+ const { kind, value, coordinates } = source;
22
+ if (kind === 'idcode') return Molecule.fromIDCode(value, coordinates);
23
+ if (kind === 'molfile') return Molecule.fromMolfile(value);
24
+ if (kind === 'smiles') return Molecule.fromSmiles(value);
25
+ return new Molecule(0, 0);
26
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Every way this package writes a drawn structure out.
3
+ *
4
+ * **Not exported from `core/index.ts`, and it must not be.** It is the one
5
+ * structure module that value-imports `openchemlib`, because the canonical
6
+ * forms below are `CanonizerUtil`'s and nothing on `Molecule` reaches them, so
7
+ * a barrel carrying it would pull openchemlib into every site that imports
8
+ * `react-cheminfo/core` for a formatter. The export dialog loads it lazily
9
+ * instead, next to the editor that already has openchemlib.
10
+ */
11
+
12
+ import type { Molecule } from 'openchemlib';
13
+ import { CanonizerUtil } from 'openchemlib';
14
+
15
+ /** The notations offered, in the order they are offered in. */
16
+ export type StructureNotationKind =
17
+ | 'smiles'
18
+ | 'molfileV3000'
19
+ | 'molfileV2000'
20
+ | 'idCode'
21
+ | 'noStereoIdCode'
22
+ | 'noStereoTautomerIdCode';
23
+
24
+ /** How a notation leaves the page as a file. */
25
+ export interface StructureNotationFile {
26
+ /** Added to the structure's own name, so two molfiles do not collide. */
27
+ suffix: string;
28
+ /** The extension, without its dot. */
29
+ extension: string;
30
+ /** What the file holds, so the system opens it with the right application. */
31
+ mimeType: string;
32
+ }
33
+
34
+ /** One way of writing a structure. */
35
+ export interface StructureNotation {
36
+ /** Which notation it is. */
37
+ kind: StructureNotationKind;
38
+ /** The notation itself, empty when OpenChemLib would not write it. */
39
+ value: string;
40
+ /**
41
+ * Whether it is one of the canonical identifiers — a string that names the
42
+ * molecule rather than describes the drawing, and that a record is looked up
43
+ * by. They answer a database question rather than a drawing one, so they are
44
+ * shown apart from the rest.
45
+ */
46
+ canonical: boolean;
47
+ /**
48
+ * The file it is saved as. Absent for a notation that is only ever copied.
49
+ * @default undefined
50
+ */
51
+ file?: StructureNotationFile;
52
+ /**
53
+ * Whether it runs over several lines, so it is shown as a block rather than
54
+ * on the label's own line.
55
+ */
56
+ block: boolean;
57
+ }
58
+
59
+ /** What a molfile is, for the application that opens one. */
60
+ const MOLFILE_TYPE = 'chemical/x-mdl-molfile';
61
+
62
+ /**
63
+ * Write a structure every way the export dialog offers.
64
+ *
65
+ * A notation OpenChemLib refuses — a query fragment has no SMILES, a generic
66
+ * tautomer cannot always be canonized — comes back empty rather than taking
67
+ * the rest of the list down with it.
68
+ * @param molecule - The structure, as the editor handed it over. Not modified.
69
+ * @returns One entry per notation, in the order they are shown.
70
+ */
71
+ export function structureNotations(molecule: Molecule): StructureNotation[] {
72
+ const idCode = written(() => molecule.getIDCode());
73
+ return [
74
+ {
75
+ kind: 'smiles',
76
+ value: written(() => molecule.toIsomericSmiles()),
77
+ canonical: false,
78
+ block: false,
79
+ },
80
+ {
81
+ kind: 'molfileV3000',
82
+ value: written(() => molecule.toMolfileV3()),
83
+ canonical: false,
84
+ file: { suffix: '-v3000', extension: 'mol', mimeType: MOLFILE_TYPE },
85
+ block: true,
86
+ },
87
+ {
88
+ kind: 'molfileV2000',
89
+ value: written(() => molecule.toMolfile()),
90
+ canonical: false,
91
+ file: { suffix: '-v2000', extension: 'mol', mimeType: MOLFILE_TYPE },
92
+ block: true,
93
+ },
94
+ { kind: 'idCode', value: idCode, canonical: true, block: false },
95
+ {
96
+ kind: 'noStereoIdCode',
97
+ value: written(() =>
98
+ CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO),
99
+ ),
100
+ canonical: true,
101
+ block: false,
102
+ },
103
+ {
104
+ kind: 'noStereoTautomerIdCode',
105
+ value: written(() =>
106
+ CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO_TAUTOMER),
107
+ ),
108
+ canonical: true,
109
+ block: false,
110
+ },
111
+ ];
112
+ }
113
+
114
+ /**
115
+ * One notation, or nothing when OpenChemLib will not write it.
116
+ * @param write - What writes it.
117
+ * @returns The notation, empty on a refusal.
118
+ */
119
+ function written(write: () => string): string {
120
+ try {
121
+ return write();
122
+ } catch {
123
+ return '';
124
+ }
125
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * A structure as a picture, drawn at the size it is saved at.
3
+ *
4
+ * The resolution is a bond length rather than a canvas: OpenChemLib caps the
5
+ * bond it draws at 24 pixels whatever box it is given, so asking for a canvas
6
+ * four times larger produces the same small drawing with more white around it
7
+ * — a resolution control that changes the file and not the picture. Lifting
8
+ * the cap and cropping to the structure is what makes `4×` genuinely four
9
+ * times the drawing.
10
+ */
11
+
12
+ import type { Molecule } from 'openchemlib';
13
+
14
+ import type { FigurePixels } from '../../download/core/figureScale.ts';
15
+
16
+ /** How the picture is drawn. */
17
+ export interface StructurePictureOptions {
18
+ /**
19
+ * The longest bond drawn, in pixels, which is what sets the size of
20
+ * everything else — the picture is cropped to the structure afterwards.
21
+ * @default 60
22
+ */
23
+ bondLength?: number;
24
+ /**
25
+ * What is painted behind the structure. An SVG left unpainted opens
26
+ * transparent, and a structure is drawn in black, so it disappears in
27
+ * anything with a dark background — a slide, a reader in dark mode.
28
+ * @default '#ffffff'
29
+ */
30
+ background?: string;
31
+ }
32
+
33
+ /** A structure drawn, and how big it came out. */
34
+ export interface StructurePicture extends FigurePixels {
35
+ /** The SVG document, ready to be saved or rasterized. */
36
+ markup: string;
37
+ }
38
+
39
+ /**
40
+ * The bond length a picture is drawn at before the resolution multiplies it.
41
+ *
42
+ * Chosen so a drug-sized molecule comes out around 300 pixels wide, which is
43
+ * what a note or a chat window wants; two or three times that is a slide, and
44
+ * four is print.
45
+ */
46
+ export const STRUCTURE_BOND_LENGTH = 60;
47
+
48
+ /**
49
+ * The canvas the structure is laid out in before it is cropped out of it.
50
+ *
51
+ * Only a ceiling: past it the box, rather than the bond length, would decide
52
+ * the size, and it is far beyond what a browser will paint anyway.
53
+ */
54
+ const CANVAS = 20_000;
55
+
56
+ /** Where the opening `<svg …>` tag ends, so the background goes after it. */
57
+ const OPEN_TAG = /<svg\b[^>]*>/u;
58
+
59
+ /** The size OpenChemLib wrote on the document it produced. */
60
+ const SIDE = /\b(?<side>width|height)="(?<pixels>\d+)px"/gu;
61
+
62
+ /**
63
+ * Draw a structure as a standalone SVG document, cropped to the structure.
64
+ * @param molecule - The structure. Not modified.
65
+ * @param options - How large to draw it, and what to paint behind it.
66
+ * @returns The document and the size it came out at.
67
+ */
68
+ export function structurePicture(
69
+ molecule: Molecule,
70
+ options: StructurePictureOptions = {},
71
+ ): StructurePicture {
72
+ const { bondLength = STRUCTURE_BOND_LENGTH, background = '#ffffff' } =
73
+ options;
74
+ const markup = molecule.toSVG(CANVAS, CANVAS, undefined, {
75
+ autoCrop: true,
76
+ autoCropMargin: Math.max(2, Math.round(bondLength / 6)),
77
+ maxAVBL: Math.max(1, Math.round(bondLength)),
78
+ });
79
+
80
+ return { markup: painted(markup, background), ...sizeOf(markup) };
81
+ }
82
+
83
+ /**
84
+ * Paint a background into the document, so the file does not open
85
+ * transparent.
86
+ * @param markup - The document as OpenChemLib wrote it.
87
+ * @param background - What to paint, or `transparent` to paint nothing.
88
+ * @returns The document.
89
+ */
90
+ function painted(markup: string, background: string): string {
91
+ if (background === 'transparent') return markup;
92
+ const open = OPEN_TAG.exec(markup);
93
+ // A document whose opening tag cannot be found is handed back unpainted
94
+ // rather than corrupted by an insertion at a guessed offset.
95
+ if (open === null) return markup;
96
+ const end = open.index + open[0].length;
97
+ return `${markup.slice(0, end)}<rect width="100%" height="100%" fill="${background}" />${markup.slice(end)}`;
98
+ }
99
+
100
+ /**
101
+ * How big the cropped document came out.
102
+ *
103
+ * Read off the document rather than computed, because the crop is the
104
+ * structure's own shape: two molecules asked for at the same bond length come
105
+ * out at different sizes, and the size is what the reader is shown.
106
+ * @param markup - The document as OpenChemLib wrote it.
107
+ * @returns Its size in pixels.
108
+ */
109
+ function sizeOf(markup: string): FigurePixels {
110
+ const sides: Record<string, number> = {};
111
+ SIDE.lastIndex = 0;
112
+ for (const match of markup.matchAll(SIDE)) {
113
+ const { side, pixels } = match.groups ?? {};
114
+ if (side !== undefined && pixels !== undefined && !(side in sides)) {
115
+ sides[side] = Number(pixels);
116
+ }
117
+ }
118
+ return { width: sides.width ?? CANVAS, height: sides.height ?? CANVAS };
119
+ }
@@ -0,0 +1,62 @@
1
+ import { Button } from '@blueprintjs/core';
2
+ import type { ReactElement } from 'react';
3
+ import { useState } from 'react';
4
+
5
+ import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
7
+ import type { StructureSourceInput } from '../core/structureSource.ts';
8
+
9
+ import { StructureExportDialog } from './StructureExportDialog.tsx';
10
+
11
+ /** What {@link EditorExportButton} needs. */
12
+ export interface EditorExportButtonProps {
13
+ /** Reads what is drawn, called the moment the dialog is opened. */
14
+ source: () => StructureSourceInput;
15
+ /** Whether the editor draws a query fragment. */
16
+ fragment: boolean;
17
+ /** Whether the canvas holds nothing to export. */
18
+ empty: boolean;
19
+ }
20
+
21
+ /**
22
+ * The editor's export button, beside the help one, opening every notation of
23
+ * the drawing and the picture of it.
24
+ *
25
+ * The structure is read when the button is pressed rather than kept beside the
26
+ * canvas, so the dialog opens on what is drawn now and the editor is not
27
+ * re-rendered on every stroke to keep a copy in step.
28
+ * @param props - See {@link EditorExportButtonProps}.
29
+ * @returns The button and its dialog.
30
+ */
31
+ export function EditorExportButton(
32
+ props: EditorExportButtonProps,
33
+ ): ReactElement {
34
+ const { source, fragment, empty } = props;
35
+ const t = useChromeT();
36
+ const [opened, setOpened] = useState<StructureSourceInput | null>(null);
37
+
38
+ return (
39
+ <>
40
+ <ActionTooltip
41
+ content={t('structure.export.open')}
42
+ placement="left"
43
+ opened={opened !== null}
44
+ >
45
+ <Button
46
+ variant="minimal"
47
+ size="small"
48
+ icon="export"
49
+ disabled={empty}
50
+ aria-label={t('structure.export.open')}
51
+ onClick={() => setOpened(source())}
52
+ />
53
+ </ActionTooltip>
54
+ <StructureExportDialog
55
+ {...opened}
56
+ isOpen={opened !== null}
57
+ fragment={fragment}
58
+ onClose={() => setOpened(null)}
59
+ />
60
+ </>
61
+ );
62
+ }
@@ -1,8 +1,9 @@
1
- import { Button, PopoverNext, Tooltip } from '@blueprintjs/core';
2
- import type { CSSProperties, ReactElement, RefObject } from 'react';
1
+ import { Button, PopoverNext } from '@blueprintjs/core';
2
+ import type { ReactElement, RefObject } from 'react';
3
3
  import { useEffect, useState } from 'react';
4
4
 
5
5
  import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
6
7
 
7
8
  import { StructureEditorHelp } from './StructureEditorHelp.tsx';
8
9
  import type { StructureEditorMode } from './editorChange.ts';
@@ -18,8 +19,11 @@ export interface EditorHelpButtonProps {
18
19
  }
19
20
 
20
21
  /**
21
- * The editor's help button, in the corner of the drawing, opening the guide to
22
- * the mouse and the keyboard.
22
+ * The editor's help button, opening the guide to the mouse and the keyboard.
23
+ *
24
+ * It is placed by whoever renders it — the editor puts it in the corner of the
25
+ * drawing, next to the export button — so the two read as one group rather
26
+ * than as two controls that happen to overlap.
23
27
  *
24
28
  * F1 opens it too: openchemlib binds that key to a help dialog it does not
25
29
  * implement on the web.
@@ -44,32 +48,24 @@ export function EditorHelpButton(props: EditorHelpButtonProps): ReactElement {
44
48
  }, [containerRef]);
45
49
 
46
50
  return (
47
- <div style={CORNER_STYLE}>
48
- <PopoverNext
49
- isOpen={isOpen}
50
- onInteraction={setIsOpen}
51
- placement="left-start"
52
- content={<StructureEditorHelp mode={mode} fragment={fragment} />}
51
+ <PopoverNext
52
+ isOpen={isOpen}
53
+ onInteraction={setIsOpen}
54
+ placement="left-start"
55
+ content={<StructureEditorHelp mode={mode} fragment={fragment} />}
56
+ >
57
+ <ActionTooltip
58
+ content={t('structure.mouseAndKeyboard')}
59
+ placement="left"
60
+ opened={isOpen}
53
61
  >
54
- <Tooltip
55
- content={t('structure.mouseAndKeyboard')}
56
- placement="left"
57
- disabled={isOpen}
58
- >
59
- <Button
60
- variant="minimal"
61
- size="small"
62
- icon="help"
63
- aria-label={t('structure.mouseAndKeyboard')}
64
- />
65
- </Tooltip>
66
- </PopoverNext>
67
- </div>
62
+ <Button
63
+ variant="minimal"
64
+ size="small"
65
+ icon="help"
66
+ aria-label={t('structure.mouseAndKeyboard')}
67
+ />
68
+ </ActionTooltip>
69
+ </PopoverNext>
68
70
  );
69
71
  }
70
-
71
- const CORNER_STYLE: CSSProperties = {
72
- position: 'absolute',
73
- top: 4,
74
- right: 4,
75
- };
@@ -28,8 +28,14 @@ import type {
28
28
  StructureEditorChange,
29
29
  StructureEditorMode,
30
30
  } from './editorChange.ts';
31
+ import { useEditorStructure } from './useEditorStructure.ts';
31
32
  import { useToolbarFloor } from './useToolbarFloor.ts';
32
33
 
34
+ const EditorExportButton = lazy(async () => {
35
+ const module = await import('./EditorExportButton.tsx');
36
+ return { default: module.EditorExportButton };
37
+ });
38
+
33
39
  const EditorCanvas = lazy(async () => {
34
40
  const module = await import('./EditorCanvas.tsx');
35
41
  return { default: module.EditorCanvas };
@@ -93,6 +99,14 @@ export interface StructureEditorProps {
93
99
  * @default true
94
100
  */
95
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;
96
110
  /**
97
111
  * Class the container carries, so a site can reach it from its stylesheet.
98
112
  * @default undefined
@@ -123,6 +137,7 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
123
137
  minHeight = 320,
124
138
  mode = 'molecule',
125
139
  help = true,
140
+ exportable = true,
126
141
  className,
127
142
  style,
128
143
  } = props;
@@ -130,6 +145,16 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
130
145
  const t = useChromeT();
131
146
  const containerRef = useToolbarFloor({ minHeight, revision });
132
147
  const handleChange = useDebounced(onChange, debounce, revision);
148
+ const drawing = useEditorStructure({ value, inputFormat, revision });
149
+ const handleEdit = useCallback(
150
+ (change: StructureEditorChange) => {
151
+ // Tapped undebounced, so a button beside the canvas reads the structure
152
+ // as it stands rather than as it stood before the last burst.
153
+ drawing.track(change);
154
+ handleChange(change);
155
+ },
156
+ [drawing, handleChange],
157
+ );
133
158
 
134
159
  return (
135
160
  <div
@@ -144,22 +169,31 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
144
169
  >
145
170
  <EditorCanvas
146
171
  key={revision}
147
- onChange={handleChange}
172
+ onChange={handleEdit}
148
173
  fragment={fragment}
149
174
  inputFormat={inputFormat}
150
175
  value={value}
151
176
  mode={mode}
152
177
  />
153
178
  {help ? (
154
- <>
155
- <ToolbarTooltip containerRef={containerRef} mode={mode} />
179
+ <ToolbarTooltip containerRef={containerRef} mode={mode} />
180
+ ) : null}
181
+ <div style={CORNER_STYLE}>
182
+ {exportable && mode === 'molecule' ? (
183
+ <EditorExportButton
184
+ source={drawing.source}
185
+ fragment={fragment}
186
+ empty={drawing.empty}
187
+ />
188
+ ) : null}
189
+ {help ? (
156
190
  <EditorHelpButton
157
191
  containerRef={containerRef}
158
192
  mode={mode}
159
193
  fragment={fragment}
160
194
  />
161
- </>
162
- ) : null}
195
+ ) : null}
196
+ </div>
163
197
  </Suspense>
164
198
  </div>
165
199
  );
@@ -217,6 +251,18 @@ const ROOT_STYLE: CSSProperties = {
217
251
  background: '#fff',
218
252
  };
219
253
 
254
+ /**
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.
257
+ */
258
+ const CORNER_STYLE: CSSProperties = {
259
+ position: 'absolute',
260
+ top: 4,
261
+ right: 4,
262
+ display: 'flex',
263
+ gap: 2,
264
+ };
265
+
220
266
  /** The box the canvas will fill, so its arrival moves nothing. */
221
267
  const LOADING_STYLE: CSSProperties = {
222
268
  position: 'absolute',
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The dialog that hands a drawn structure over.
3
+ *
4
+ * The shell is here and the body is behind `React.lazy`, for the same reason
5
+ * `Structure` keeps its depiction there: this file must stay free of
6
+ * `openchemlib` so a site importing `react-cheminfo/structure` for the editor
7
+ * does not also download the notations nobody has asked for yet.
8
+ */
9
+
10
+ import { Dialog, DialogBody } from '@blueprintjs/core';
11
+ import type { CSSProperties, ReactElement } from 'react';
12
+ import { Suspense, lazy } from 'react';
13
+
14
+ import { useChromeT } from '../../i18n/ui/useT.ts';
15
+ import { TOKEN } from '../../tokens/core/familyTokens.ts';
16
+
17
+ import type { StructureExportPanelProps } from './StructureExportPanel.tsx';
18
+
19
+ const StructureExportPanel = lazy(async () => {
20
+ const module = await import('./StructureExportPanel.tsx');
21
+ return { default: module.StructureExportPanel };
22
+ });
23
+
24
+ /** What {@link StructureExportDialog} needs. */
25
+ export interface StructureExportDialogProps extends StructureExportPanelProps {
26
+ /** Whether the dialog is on screen. */
27
+ isOpen: boolean;
28
+ /** Called when the dialog is dismissed. */
29
+ onClose: () => void;
30
+ /**
31
+ * Whether the dialog is rendered through a portal on `document.body`.
32
+ * @default true
33
+ */
34
+ usePortal?: boolean;
35
+ }
36
+
37
+ /**
38
+ * Take a structure off the page: as a notation, or as a picture.
39
+ *
40
+ * One dialog rather than a menu of downloads, because the question is never
41
+ * only "which format" — a reader comparing a SMILES against an idCode, or
42
+ * checking that the hash they are about to paste belongs to the molecule in
43
+ * front of them, needs to see the structure and the strings together.
44
+ * @param props - See {@link StructureExportDialogProps}.
45
+ * @returns The dialog.
46
+ */
47
+ export function StructureExportDialog(
48
+ props: StructureExportDialogProps,
49
+ ): ReactElement {
50
+ const { isOpen, onClose, usePortal = true, ...panel } = props;
51
+ const t = useChromeT();
52
+
53
+ return (
54
+ <Dialog
55
+ isOpen={isOpen}
56
+ onClose={onClose}
57
+ usePortal={usePortal}
58
+ title={t('structure.export.title')}
59
+ icon="export"
60
+ className="structure-export"
61
+ style={DIALOG_STYLE}
62
+ >
63
+ <DialogBody className="structure-export__body">
64
+ {/* Mounted with the body, so the notations are written from the
65
+ structure as it stands each time the dialog is opened. */}
66
+ {isOpen ? (
67
+ <Suspense
68
+ fallback={
69
+ <p style={LOADING_STYLE}>{t('structure.export.loading')}</p>
70
+ }
71
+ >
72
+ <StructureExportPanel {...panel} />
73
+ </Suspense>
74
+ ) : null}
75
+ </DialogBody>
76
+ </Dialog>
77
+ );
78
+ }
79
+
80
+ const DIALOG_STYLE = {
81
+ width: 'min(980px, 94vw)',
82
+ } as const satisfies CSSProperties;
83
+
84
+ const LOADING_STYLE = {
85
+ margin: 0,
86
+ padding: '2rem 0',
87
+ color: TOKEN.textFaint,
88
+ fontSize: 13,
89
+ textAlign: 'center',
90
+ } as const satisfies CSSProperties;