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
@@ -48,6 +48,13 @@ export interface FigureSvg {
48
48
  /** What a saved SVG figure is, for the file and for the renderer reading it. */
49
49
  export const FIGURE_SVG_TYPE = 'image/svg+xml;charset=utf-8';
50
50
 
51
+ /** A run of words inside a card, with where it sits and how it is set. */
52
+ interface TextRun {
53
+ text: string;
54
+ box: DOMRect;
55
+ type: CSSStyleDeclaration;
56
+ }
57
+
51
58
  /** The token a figure's own ground is named by. */
52
59
  const SURFACE_TOKEN = '--surface';
53
60
 
@@ -138,19 +145,15 @@ function legendMarkup(legend: Element, box: DOMRect): string {
138
145
  }
139
146
 
140
147
  const texts: FigureLegendText[] = [];
141
- for (const run of legend.querySelectorAll('*')) {
142
- if (run.firstElementChild !== null) continue;
143
- const words = run.textContent?.trim() ?? '';
144
- if (words === '') continue;
145
- const at = run.getBoundingClientRect();
146
- const type = window.getComputedStyle(run);
148
+ for (const run of textRuns(legend)) {
149
+ const at = run.box;
147
150
  texts.push({
148
- text: words,
151
+ text: run.text,
149
152
  x: at.left - box.left,
150
153
  y: at.top - box.top + at.height / 2,
151
- color: type.color,
152
- fontSize: Number.parseFloat(type.fontSize),
153
- fontWeight: type.fontWeight,
154
+ color: run.type.color,
155
+ fontSize: Number.parseFloat(run.type.fontSize),
156
+ fontWeight: run.type.fontWeight,
154
157
  });
155
158
  }
156
159
 
@@ -172,6 +175,35 @@ function legendMarkup(legend: Element, box: DOMRect): string {
172
175
  });
173
176
  }
174
177
 
178
+ /**
179
+ * Every run of words inside a card, with the box the browser gave it.
180
+ *
181
+ * Collected as text nodes rather than as elements, because an element is only
182
+ * the smallest box around a run when it holds nothing else: a formula drawn as
183
+ * `HCO<sub>3</sub><sup>-</sup>` keeps `HCO` on the element itself, and a card
184
+ * read element by element loses exactly the letters that name the species. The
185
+ * box is measured over the characters with a `Range`, which is also tighter
186
+ * than the element's own box wherever that element is padded.
187
+ * @param legend - The card, as it sits on the page.
188
+ * @returns The runs, in the order they are written.
189
+ */
190
+ function textRuns(legend: Element): TextRun[] {
191
+ const runs: TextRun[] = [];
192
+ const walker = document.createTreeWalker(legend, NodeFilter.SHOW_TEXT);
193
+ const range = document.createRange();
194
+ for (let node = walker.nextNode(); node !== null; node = walker.nextNode()) {
195
+ const words = node.textContent?.trim() ?? '';
196
+ if (words === '') continue;
197
+ const parent = node.parentElement;
198
+ if (parent === null) continue;
199
+ range.selectNodeContents(node);
200
+ const box = range.getBoundingClientRect();
201
+ if (box.width <= 0 || box.height <= 0) continue;
202
+ runs.push({ text: words, box, type: window.getComputedStyle(parent) });
203
+ }
204
+ return runs;
205
+ }
206
+
175
207
  /**
176
208
  * One drawing, serialized with every token it names written out.
177
209
  *
@@ -3,6 +3,7 @@ import { Button } from '@blueprintjs/core';
3
3
  import type { ReactElement } from 'react';
4
4
 
5
5
  import { useChromeT } from '../../i18n/ui/useT.ts';
6
+ import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
6
7
 
7
8
  import type { HelpContent } from './HelpBody.tsx';
8
9
  import { HelpTooltip } from './HelpTooltip.tsx';
@@ -68,7 +69,7 @@ export function HelpToolbarButton(props: HelpToolbarButtonProps): ReactElement {
68
69
  icon={icon}
69
70
  text={label}
70
71
  aria-label={label ?? helpName(content, t)}
71
- className={className}
72
+ className={joinClassNames('no-print', className)}
72
73
  onClick={onClick}
73
74
  />
74
75
  </HelpTooltip>
@@ -48,18 +48,32 @@
48
48
  "site.inorganic.tagline": "Eine anorganische Verbindung benennen und ihre Formel schreiben.",
49
49
  "share.button": "Teilen",
50
50
  "share.buttonTitle": "Einen Link zu dieser Seite teilen oder sie in Ihre eigene Website einbetten",
51
- "share.dialogTitle": "Teilen oder einbetten",
52
- "share.lead": "Ein Link auf {title}, so wie Sie es eingestellt haben.",
51
+ "share.dialogTitleFor": "{title} teilen oder einbetten",
53
52
  "share.layout": "Darstellung",
54
53
  "share.embed": "In eine andere Seite einbetten",
55
54
  "share.embedHint": "Lässt Kopfzeile und Navigation der Website weg, damit die Seite in einer Seite von Ihnen sitzt.",
55
+ "share.on": "Ein",
56
+ "share.off": "Aus",
56
57
  "share.showOnPage": "Auf der Seite zeigen",
57
58
  "share.custom": "Eigene",
58
- "share.link": "Link",
59
+ "share.options": "Optionen",
60
+ "share.preview": "Vorschau",
61
+ "share.device.window": "Dieses Fenster",
62
+ "share.device.mobile": "Handy",
63
+ "share.device.laptop": "Laptop",
64
+ "share.device.hd": "HD",
65
+ "share.deviceSize": "{name} · {width} × {height}",
66
+ "share.previewWhat": "Die Seite, wie dieser Link sie öffnet, auf dem gewählten Bildschirm.",
67
+ "share.previewLive": "Es ist die Seite selbst: Was Sie darin ändern, ändert den Link nicht.",
59
68
  "share.copyLink": "Link kopieren",
69
+ "share.copyLinkHelpTitle": "Die Seite so weitergeben",
70
+ "share.copyLinkHelp": "Fügen Sie die Adresse in eine Mail, einen Chat oder eine Kursseite ein: Sie öffnet diese Seite genau so eingestellt, wie Sie sie jetzt haben.",
60
71
  "share.openInNewTab": "In einem neuen Tab öffnen",
61
- "share.iframe": "Iframe",
72
+ "share.openInNewTabHelpTitle": "Vor dem Senden ansehen",
73
+ "share.openInNewTabHelp": "Öffnet den Link in einem neuen Tab, damit Sie sehen, was die Klasse bekommt.",
62
74
  "share.copyIframe": "Iframe kopieren",
75
+ "share.copyIframeHelpTitle": "Die Seite in Ihre einbauen",
76
+ "share.copyIframeHelp": "Ein HTML-Schnipsel, das dort eingefügt wird, wo das HTML Ihrer Seite bearbeitet wird: das Werkzeug läuft dann darin.",
63
77
  "share.done": "Fertig",
64
78
  "cite.button": "Zitieren",
65
79
  "cite.copyReferenceAs": "Literaturangabe kopieren als",
@@ -410,6 +424,27 @@
410
424
  "structure.tool.reactionOnly": "Nur beim Zeichnen einer Reaktion.",
411
425
  "structure.tool.unavailable": "In diesem Editor nicht verfügbar.",
412
426
  "structure.loadingEditor": "Der Editor wird geladen…",
427
+ "structure.export.open": "Struktur exportieren",
428
+ "structure.export.title": "Struktur exportieren",
429
+ "structure.export.loading": "Die Struktur wird gelesen…",
430
+ "structure.export.nothing": "Noch nichts gezeichnet.",
431
+ "structure.export.picture": "Die Struktur, so wie das gespeicherte Bild sie zeichnet",
432
+ "structure.export.identifiers": "Kanonische Kennungen",
433
+ "structure.export.saveSvg": "Als SVG speichern",
434
+ "structure.export.savePng": "Als PNG speichern",
435
+ "structure.export.copyPng": "PNG kopieren",
436
+ "structure.export.smiles": "SMILES",
437
+ "structure.export.smilesHelp": "Die Struktur in einer Zeile, Stereochemie eingeschlossen. Jedes Programm liest sie.",
438
+ "structure.export.molfileV3000": "Molfile V3000",
439
+ "structure.export.molfileV3000Help": "Die Verbindungstabelle, mit den Atomen so angeordnet wie gezeichnet. Trägt mehr als 999 Atome und erweiterte Stereochemie.",
440
+ "structure.export.molfileV2000": "Molfile V2000",
441
+ "structure.export.molfileV2000Help": "Die Verbindungstabelle, mit den Atomen so angeordnet wie gezeichnet. Der ältere Dialekt, den jedes Programm öffnet.",
442
+ "structure.export.idCode": "idCode",
443
+ "structure.export.idCodeHelp": "Die kanonische Kennung von OpenChemLib: eine Zeichenkette je Molekül, unabhängig von der Zeichnung.",
444
+ "structure.export.noStereoIdCode": "idCode ohne Stereochemie",
445
+ "structure.export.noStereoIdCodeHelp": "Jedes Stereoisomer ergibt diese, womit ein ohne Stereozentren gezeichneter Eintrag gefunden wird.",
446
+ "structure.export.noStereoTautomerIdCode": "idCode ohne Stereochemie und Tautomerie",
447
+ "structure.export.noStereoTautomerIdCodeHelp": "Jedes Tautomer und jedes Stereoisomer ergibt diese: Keto- und Enolform haben denselben Schlüssel.",
413
448
  "molecule3d.view": "Ansicht",
414
449
  "molecule3d.resetView": "Ansicht zurücksetzen",
415
450
  "molecule3d.spin": "Drehen lassen",
@@ -48,18 +48,32 @@
48
48
  "site.inorganic.tagline": "Name an inorganic compound, and write its formula.",
49
49
  "share.button": "Share",
50
50
  "share.buttonTitle": "Share a link to this page, or embed it in your own site",
51
- "share.dialogTitle": "Share or embed",
52
- "share.lead": "A link to {title} as you have it set up now.",
51
+ "share.dialogTitleFor": "Share or embed — {title}",
53
52
  "share.layout": "Layout",
54
53
  "share.embed": "Embed in another page",
55
54
  "share.embedHint": "Drops the site header and its navigation, so the page sits inside a page of your own.",
55
+ "share.on": "On",
56
+ "share.off": "Off",
56
57
  "share.showOnPage": "Show on the page",
57
58
  "share.custom": "Custom",
58
- "share.link": "Link",
59
+ "share.options": "Options",
60
+ "share.preview": "Preview",
61
+ "share.device.window": "This window",
62
+ "share.device.mobile": "Mobile",
63
+ "share.device.laptop": "Laptop",
64
+ "share.device.hd": "HD",
65
+ "share.deviceSize": "{name} · {width} × {height}",
66
+ "share.previewWhat": "The page as this link opens it, at the screen you pick.",
67
+ "share.previewLive": "It is the live page: what you change inside it does not change the link.",
59
68
  "share.copyLink": "Copy the link",
69
+ "share.copyLinkHelpTitle": "Hand the page out as it is",
70
+ "share.copyLinkHelp": "Paste the address in a mail, a chat or a course page: it opens this page set up exactly as you have it now.",
60
71
  "share.openInNewTab": "Open in a new tab",
61
- "share.iframe": "Iframe",
72
+ "share.openInNewTabHelpTitle": "See it before you send it",
73
+ "share.openInNewTabHelp": "Opens the link in a new tab, so you check what the class will get.",
62
74
  "share.copyIframe": "Copy the iframe",
75
+ "share.copyIframeHelpTitle": "Put the page inside yours",
76
+ "share.copyIframeHelp": "A snippet of HTML to paste where your own page's HTML is edited: the tool then runs inside it.",
63
77
  "share.done": "Done",
64
78
  "cite.button": "Cite",
65
79
  "cite.copyReferenceAs": "Copy the reference as",
@@ -372,6 +386,27 @@
372
386
  "structure.tool.reactionOnly": "Only when drawing a reaction.",
373
387
  "structure.tool.unavailable": "Not available in this editor.",
374
388
  "structure.loadingEditor": "Loading the editor…",
389
+ "structure.export.open": "Export the structure",
390
+ "structure.export.title": "Export the structure",
391
+ "structure.export.loading": "Reading the structure…",
392
+ "structure.export.nothing": "Nothing is drawn yet.",
393
+ "structure.export.picture": "The structure, as the saved picture draws it",
394
+ "structure.export.identifiers": "Canonical identifiers",
395
+ "structure.export.saveSvg": "Save SVG",
396
+ "structure.export.savePng": "Save PNG",
397
+ "structure.export.copyPng": "Copy PNG",
398
+ "structure.export.smiles": "SMILES",
399
+ "structure.export.smilesHelp": "The structure on one line, stereochemistry included. Every tool reads it.",
400
+ "structure.export.molfileV3000": "Molfile V3000",
401
+ "structure.export.molfileV3000Help": "The connection table, with the atoms laid out as they are drawn. Carries more than 999 atoms, and enhanced stereo.",
402
+ "structure.export.molfileV2000": "Molfile V2000",
403
+ "structure.export.molfileV2000Help": "The connection table, with the atoms laid out as they are drawn. The older dialect, and the one every tool opens.",
404
+ "structure.export.idCode": "idCode",
405
+ "structure.export.idCodeHelp": "OpenChemLib's canonical identifier: one string per molecule, whichever way it was drawn.",
406
+ "structure.export.noStereoIdCode": "idCode without stereochemistry",
407
+ "structure.export.noStereoIdCodeHelp": "Every stereoisomer of this structure gives this one, so it finds a record drawn without its stereocentres.",
408
+ "structure.export.noStereoTautomerIdCode": "idCode without stereochemistry or tautomer",
409
+ "structure.export.noStereoTautomerIdCodeHelp": "Every tautomer and every stereoisomer gives this one, so the keto and the enol form key together.",
375
410
  "periodic.table": "Periodic table",
376
411
  "periodic.group": "Group {group}",
377
412
  "periodic.period": "Period {period}",
@@ -48,18 +48,32 @@
48
48
  "site.inorganic.tagline": "Nombrar un compuesto inorgánico y escribir su fórmula.",
49
49
  "share.button": "Compartir",
50
50
  "share.buttonTitle": "Compartir un enlace a esta página, o incrustarla en su propio sitio",
51
- "share.dialogTitle": "Compartir o incrustar",
52
- "share.lead": "Un enlace a {title} tal como lo tiene configurado ahora.",
51
+ "share.dialogTitleFor": "Compartir o incrustar — {title}",
53
52
  "share.layout": "Disposición",
54
53
  "share.embed": "Incrustar en otra página",
55
54
  "share.embedHint": "Quita la cabecera del sitio y su navegación, para que la página quede dentro de una página suya.",
55
+ "share.on": "Sí",
56
+ "share.off": "No",
56
57
  "share.showOnPage": "Mostrar en la página",
57
58
  "share.custom": "A medida",
58
- "share.link": "Enlace",
59
+ "share.options": "Opciones",
60
+ "share.preview": "Vista previa",
61
+ "share.device.window": "Esta ventana",
62
+ "share.device.mobile": "Móvil",
63
+ "share.device.laptop": "Portátil",
64
+ "share.device.hd": "HD",
65
+ "share.deviceSize": "{name} · {width} × {height}",
66
+ "share.previewWhat": "La página tal como la abre este enlace, en la pantalla que elijas.",
67
+ "share.previewLive": "Es la página en vivo: lo que cambies dentro no cambia el enlace.",
59
68
  "share.copyLink": "Copiar el enlace",
69
+ "share.copyLinkHelpTitle": "Entregar la página tal cual",
70
+ "share.copyLinkHelp": "Pega la dirección en un correo, un chat o una página de curso: abre esta página configurada exactamente como la tienes ahora.",
60
71
  "share.openInNewTab": "Abrir en una pestaña nueva",
61
- "share.iframe": "Iframe",
72
+ "share.openInNewTabHelpTitle": "Verla antes de enviarla",
73
+ "share.openInNewTabHelp": "Abre el enlace en una pestaña nueva, para comprobar lo que recibirá la clase.",
62
74
  "share.copyIframe": "Copiar el iframe",
75
+ "share.copyIframeHelpTitle": "Poner la página dentro de la tuya",
76
+ "share.copyIframeHelp": "Un fragmento de HTML para pegar donde se edita el HTML de tu página: la herramienta funciona dentro de él.",
63
77
  "share.done": "Listo",
64
78
  "cite.button": "Citar",
65
79
  "cite.copyReferenceAs": "Copiar la referencia como",
@@ -410,6 +424,27 @@
410
424
  "structure.tool.reactionOnly": "Solo al dibujar una reacción.",
411
425
  "structure.tool.unavailable": "No disponible en este editor.",
412
426
  "structure.loadingEditor": "Cargando el editor…",
427
+ "structure.export.open": "Exportar la estructura",
428
+ "structure.export.title": "Exportar la estructura",
429
+ "structure.export.loading": "Leyendo la estructura…",
430
+ "structure.export.nothing": "Todavía no hay nada dibujado.",
431
+ "structure.export.picture": "La estructura, tal como la dibuja la imagen guardada",
432
+ "structure.export.identifiers": "Identificadores canónicos",
433
+ "structure.export.saveSvg": "Guardar en SVG",
434
+ "structure.export.savePng": "Guardar en PNG",
435
+ "structure.export.copyPng": "Copiar el PNG",
436
+ "structure.export.smiles": "SMILES",
437
+ "structure.export.smilesHelp": "La estructura en una línea, con su estereoquímica. Todas las herramientas la leen.",
438
+ "structure.export.molfileV3000": "Molfile V3000",
439
+ "structure.export.molfileV3000Help": "La tabla de conexiones, con los átomos colocados como se dibujan. Admite más de 999 átomos y la estereoquímica ampliada.",
440
+ "structure.export.molfileV2000": "Molfile V2000",
441
+ "structure.export.molfileV2000Help": "La tabla de conexiones, con los átomos colocados como se dibujan. El dialecto antiguo, el que abre cualquier herramienta.",
442
+ "structure.export.idCode": "idCode",
443
+ "structure.export.idCodeHelp": "El identificador canónico de OpenChemLib: una cadena por molécula, se dibuje como se dibuje.",
444
+ "structure.export.noStereoIdCode": "idCode sin estereoquímica",
445
+ "structure.export.noStereoIdCodeHelp": "Todos los estereoisómeros dan este, así que encuentra un registro dibujado sin sus centros estereogénicos.",
446
+ "structure.export.noStereoTautomerIdCode": "idCode sin estereoquímica ni tautomería",
447
+ "structure.export.noStereoTautomerIdCodeHelp": "Todos los tautómeros y estereoisómeros dan este: la forma cetónica y la enólica comparten clave.",
413
448
  "molecule3d.view": "Vista",
414
449
  "molecule3d.resetView": "Reiniciar la vista",
415
450
  "molecule3d.spin": "Giro continuo",
@@ -48,18 +48,32 @@
48
48
  "site.inorganic.tagline": "Nommer un composé inorganique, et en écrire la formule.",
49
49
  "share.button": "Partager",
50
50
  "share.buttonTitle": "Partager un lien vers cette page, ou l'intégrer à votre propre site",
51
- "share.dialogTitle": "Partager ou intégrer",
52
- "share.lead": "Un lien vers {title} tel que vous l'avez réglé.",
51
+ "share.dialogTitleFor": "Partager ou intégrer — {title}",
53
52
  "share.layout": "Disposition",
54
53
  "share.embed": "Intégrer dans une autre page",
55
54
  "share.embedHint": "Retire l'en-tête du site et sa navigation, pour que la page prenne place dans une page à vous.",
55
+ "share.on": "Oui",
56
+ "share.off": "Non",
56
57
  "share.showOnPage": "Afficher sur la page",
57
58
  "share.custom": "Sur mesure",
58
- "share.link": "Lien",
59
+ "share.options": "Options",
60
+ "share.preview": "Aperçu",
61
+ "share.device.window": "Cette fenêtre",
62
+ "share.device.mobile": "Mobile",
63
+ "share.device.laptop": "Portable",
64
+ "share.device.hd": "HD",
65
+ "share.deviceSize": "{name} · {width} × {height}",
66
+ "share.previewWhat": "La page telle que ce lien l'ouvre, à l'écran que vous choisissez.",
67
+ "share.previewLive": "C'est la page elle-même : ce que vous y modifiez ne modifie pas le lien.",
59
68
  "share.copyLink": "Copier le lien",
69
+ "share.copyLinkHelpTitle": "Transmettre la page telle quelle",
70
+ "share.copyLinkHelp": "Collez l'adresse dans un courriel, une discussion ou une page de cours : elle ouvre cette page réglée exactement comme vous l'avez.",
60
71
  "share.openInNewTab": "Ouvrir dans un nouvel onglet",
61
- "share.iframe": "Iframe",
72
+ "share.openInNewTabHelpTitle": "Voir avant d'envoyer",
73
+ "share.openInNewTabHelp": "Ouvre le lien dans un nouvel onglet, pour vérifier ce que la classe recevra.",
62
74
  "share.copyIframe": "Copier l'iframe",
75
+ "share.copyIframeHelpTitle": "Mettre la page dans la vôtre",
76
+ "share.copyIframeHelp": "Un extrait de HTML à coller là où le HTML de votre page s'édite : l'outil s'exécute alors à l'intérieur.",
63
77
  "share.done": "Terminé",
64
78
  "cite.button": "Citer",
65
79
  "cite.copyReferenceAs": "Copier la référence en",
@@ -410,6 +424,27 @@
410
424
  "structure.tool.reactionOnly": "Seulement lors du dessin d'une réaction.",
411
425
  "structure.tool.unavailable": "Indisponible dans cet éditeur.",
412
426
  "structure.loadingEditor": "Chargement de l'éditeur…",
427
+ "structure.export.open": "Exporter la structure",
428
+ "structure.export.title": "Exporter la structure",
429
+ "structure.export.loading": "Lecture de la structure…",
430
+ "structure.export.nothing": "Rien n'est encore dessiné.",
431
+ "structure.export.picture": "La structure, telle que l'image enregistrée la dessine",
432
+ "structure.export.identifiers": "Identifiants canoniques",
433
+ "structure.export.saveSvg": "Enregistrer en SVG",
434
+ "structure.export.savePng": "Enregistrer en PNG",
435
+ "structure.export.copyPng": "Copier le PNG",
436
+ "structure.export.smiles": "SMILES",
437
+ "structure.export.smilesHelp": "La structure sur une ligne, stéréochimie comprise. Tous les logiciels le lisent.",
438
+ "structure.export.molfileV3000": "Molfile V3000",
439
+ "structure.export.molfileV3000Help": "La table de connexion, avec les atomes placés comme ils sont dessinés. Accepte plus de 999 atomes et la stéréochimie étendue.",
440
+ "structure.export.molfileV2000": "Molfile V2000",
441
+ "structure.export.molfileV2000Help": "La table de connexion, avec les atomes placés comme ils sont dessinés. Le dialecte le plus ancien, et celui que tout logiciel ouvre.",
442
+ "structure.export.idCode": "idCode",
443
+ "structure.export.idCodeHelp": "L'identifiant canonique d'OpenChemLib : une chaîne par molécule, quel que soit le dessin.",
444
+ "structure.export.noStereoIdCode": "idCode sans stéréochimie",
445
+ "structure.export.noStereoIdCodeHelp": "Tous les stéréoisomères donnent celui-ci, ce qui retrouve un enregistrement dessiné sans ses centres stéréogènes.",
446
+ "structure.export.noStereoTautomerIdCode": "idCode sans stéréochimie ni tautomérie",
447
+ "structure.export.noStereoTautomerIdCodeHelp": "Tous les tautomères et tous les stéréoisomères donnent celui-ci : la forme cétone et la forme énol ont la même clé.",
413
448
  "molecule3d.view": "Vue",
414
449
  "molecule3d.resetView": "Réinitialiser la vue",
415
450
  "molecule3d.spin": "Rotation continue",
@@ -48,18 +48,32 @@
48
48
  "site.inorganic.tagline": "Nominare un composto inorganico e scriverne la formula.",
49
49
  "share.button": "Condividi",
50
50
  "share.buttonTitle": "Condividere un link a questa pagina, o incorporarla nel proprio sito",
51
- "share.dialogTitle": "Condividere o incorporare",
52
- "share.lead": "Un link a {title} così come è configurato ora.",
51
+ "share.dialogTitleFor": "Condividere o incorporare — {title}",
53
52
  "share.layout": "Disposizione",
54
53
  "share.embed": "Incorporare in un'altra pagina",
55
54
  "share.embedHint": "Toglie l'intestazione del sito e la sua navigazione, così la pagina sta dentro una pagina propria.",
55
+ "share.on": "Sì",
56
+ "share.off": "No",
56
57
  "share.showOnPage": "Mostra nella pagina",
57
58
  "share.custom": "Personalizzato",
58
- "share.link": "Link",
59
+ "share.options": "Opzioni",
60
+ "share.preview": "Anteprima",
61
+ "share.device.window": "Questa finestra",
62
+ "share.device.mobile": "Cellulare",
63
+ "share.device.laptop": "Portatile",
64
+ "share.device.hd": "HD",
65
+ "share.deviceSize": "{name} · {width} × {height}",
66
+ "share.previewWhat": "La pagina come la apre questo link, sullo schermo che scegli.",
67
+ "share.previewLive": "È la pagina stessa: quello che cambi al suo interno non cambia il link.",
59
68
  "share.copyLink": "Copia il link",
69
+ "share.copyLinkHelpTitle": "Consegnare la pagina com'è",
70
+ "share.copyLinkHelp": "Incolla l'indirizzo in una mail, una chat o una pagina di corso: apre questa pagina impostata esattamente come ce l'hai ora.",
60
71
  "share.openInNewTab": "Apri in una nuova scheda",
61
- "share.iframe": "Iframe",
72
+ "share.openInNewTabHelpTitle": "Vederla prima di inviarla",
73
+ "share.openInNewTabHelp": "Apre il link in una nuova scheda, per controllare che cosa riceverà la classe.",
62
74
  "share.copyIframe": "Copia l'iframe",
75
+ "share.copyIframeHelpTitle": "Mettere la pagina dentro la tua",
76
+ "share.copyIframeHelp": "Un frammento di HTML da incollare dove si modifica l'HTML della tua pagina: lo strumento funziona al suo interno.",
63
77
  "share.done": "Fatto",
64
78
  "cite.button": "Cita",
65
79
  "cite.copyReferenceAs": "Copia il riferimento come",
@@ -372,6 +386,27 @@
372
386
  "structure.tool.reactionOnly": "Solo quando si disegna una reazione.",
373
387
  "structure.tool.unavailable": "Non disponibile in questo editor.",
374
388
  "structure.loadingEditor": "Caricamento dell'editor…",
389
+ "structure.export.open": "Esporta la struttura",
390
+ "structure.export.title": "Esporta la struttura",
391
+ "structure.export.loading": "Lettura della struttura…",
392
+ "structure.export.nothing": "Non c'è ancora nulla di disegnato.",
393
+ "structure.export.picture": "La struttura, come la disegna l'immagine salvata",
394
+ "structure.export.identifiers": "Identificatori canonici",
395
+ "structure.export.saveSvg": "Salva in SVG",
396
+ "structure.export.savePng": "Salva in PNG",
397
+ "structure.export.copyPng": "Copia il PNG",
398
+ "structure.export.smiles": "SMILES",
399
+ "structure.export.smilesHelp": "La struttura su una riga, stereochimica compresa. Ogni strumento la legge.",
400
+ "structure.export.molfileV3000": "Molfile V3000",
401
+ "structure.export.molfileV3000Help": "La tabella delle connessioni, con gli atomi disposti come sono disegnati. Regge più di 999 atomi e la stereochimica estesa.",
402
+ "structure.export.molfileV2000": "Molfile V2000",
403
+ "structure.export.molfileV2000Help": "La tabella delle connessioni, con gli atomi disposti come sono disegnati. Il dialetto più vecchio, quello che ogni strumento apre.",
404
+ "structure.export.idCode": "idCode",
405
+ "structure.export.idCodeHelp": "L'identificatore canonico di OpenChemLib: una stringa per molecola, come che sia disegnata.",
406
+ "structure.export.noStereoIdCode": "idCode senza stereochimica",
407
+ "structure.export.noStereoIdCodeHelp": "Ogni stereoisomero dà questo, così trova una voce disegnata senza i suoi centri stereogenici.",
408
+ "structure.export.noStereoTautomerIdCode": "idCode senza stereochimica né tautomeria",
409
+ "structure.export.noStereoTautomerIdCodeHelp": "Ogni tautomero e ogni stereoisomero dà questo: la forma chetonica e quella enolica hanno la stessa chiave.",
375
410
  "periodic.table": "Tavola periodica",
376
411
  "periodic.group": "Gruppo {group}",
377
412
  "periodic.period": "Periodo {period}",
@@ -250,7 +250,7 @@ export function NumberInput(props: NumberInputProps): ReactElement {
250
250
  className={[Classes.NUMERIC_INPUT, className].filter(Boolean).join(' ')}
251
251
  >
252
252
  {box}
253
- <ButtonGroup className={Classes.FIXED} vertical>
253
+ <ButtonGroup className={`${Classes.FIXED} no-print`} vertical>
254
254
  <Button
255
255
  icon="chevron-up"
256
256
  size={size}
@@ -90,6 +90,7 @@ export function OverlayIconButton(props: OverlayIconButtonProps): ReactElement {
90
90
  return (
91
91
  <button
92
92
  type="button"
93
+ className="no-print"
93
94
  title={told}
94
95
  aria-label={name}
95
96
  aria-haspopup={opensMenu ? 'menu' : undefined}
@@ -32,6 +32,7 @@ export function ClearButton(props: ClearButtonProps) {
32
32
 
33
33
  return (
34
34
  <Button
35
+ className="no-print"
35
36
  variant="minimal"
36
37
  icon="cross"
37
38
  aria-label={label}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The light inline markup authored prose is written in: `` `code` ``,
3
- * `**strong**` and `*emphasis*`, plus — for prose that links its jargon — the
4
- * `[[term]]` markers of the glossary.
3
+ * `**strong**`, `*emphasis*` and `{{C6H6O}}` for a molecular formula, plus —
4
+ * for prose that links its jargon — the `[[term]]` markers of the glossary.
5
5
  *
6
6
  * One left-to-right pass, without a DOM. Whatever opens first is read whole
7
7
  * before anything inside it is looked at, so `` `[*+]` `` and `` `*!@*` `` stay
@@ -22,10 +22,11 @@ import { GLOSSARY_MARKER_SOURCE, readMarker } from './glossary.ts';
22
22
  export type InlineSegment =
23
23
  | { kind: 'text'; start: number; text: string }
24
24
  | { kind: 'code'; start: number; text: string }
25
+ | { kind: 'mf'; start: number; mf: string }
25
26
  | { kind: 'term'; start: number; term: string; text: string }
26
27
  | { kind: 'strong' | 'emphasis'; start: number; children: InlineSegment[] };
27
28
 
28
- /** What {@link parseInlineMarks} reads besides the three marks. */
29
+ /** What {@link parseInlineMarks} reads besides the four marks. */
29
30
  export interface ParseInlineMarksOptions {
30
31
  /**
31
32
  * Whether `[[term]]` and `[[term|displayed text]]` markers are read too, as
@@ -36,8 +37,8 @@ export interface ParseInlineMarksOptions {
36
37
  }
37
38
 
38
39
  /**
39
- * Split authored prose into runs of text, code spans, strong and emphasised
40
- * runs, and — when asked — glossary markers.
40
+ * Split authored prose into runs of text, code spans, molecular formulas,
41
+ * strong and emphasised runs, and — when asked — glossary markers.
41
42
  *
42
43
  * Anything that does not close is not markup and comes back verbatim inside a
43
44
  * `text` segment: a lone backtick, `**bold` with no closing pair, `[[term`.
@@ -52,10 +53,16 @@ export function parseInlineMarks(
52
53
  return parseFrom(text, 0, options.glossaryMarkers === true);
53
54
  }
54
55
 
56
+ const MF_SOURCE = String.raw`\{\{(?<mf>[^{}]+)\}\}`;
55
57
  const CODE_SOURCE = '`(?<code>[^`]+)`';
56
58
  const STRONG_SOURCE = String.raw`\*\*(?<strong>[^*]+)\*\*`;
57
59
  const EMPHASIS_SOURCE = String.raw`\*(?<emphasis>[^\s*](?:[^*]*[^\s*])?)\*`;
58
- const MARKS_SOURCE = [CODE_SOURCE, STRONG_SOURCE, EMPHASIS_SOURCE].join('|');
60
+ const MARKS_SOURCE = [
61
+ MF_SOURCE,
62
+ CODE_SOURCE,
63
+ STRONG_SOURCE,
64
+ EMPHASIS_SOURCE,
65
+ ].join('|');
59
66
  const MARKS_AND_MARKERS_SOURCE = `${GLOSSARY_MARKER_SOURCE}|${MARKS_SOURCE}`;
60
67
 
61
68
  function parseFrom(
@@ -99,8 +106,9 @@ function toSegment(
99
106
  markers: boolean,
100
107
  ): InlineSegment {
101
108
  const start = offset + match.index;
102
- const { term, code, strong, emphasis } = match.groups ?? {};
109
+ const { term, mf, code, strong, emphasis } = match.groups ?? {};
103
110
  if (term !== undefined) return readMarker(term, start);
111
+ if (mf !== undefined) return { kind: 'mf', start, mf: mf.trim() };
104
112
  if (code !== undefined) return { kind: 'code', start, text: code };
105
113
  if (strong !== undefined) {
106
114
  return {
@@ -5,19 +5,13 @@ import type { GlossaryEntry, GlossaryExample } from '../core/glossary.ts';
5
5
  import { InlineText } from './InlineText.tsx';
6
6
  import { exampleText } from './exampleText.ts';
7
7
  import { useGlossary } from './glossaryContext.ts';
8
- import type { ProseInk, ProseTone } from './pedagogyStyle.ts';
8
+ import type { ProseInk } from './pedagogyStyle.ts';
9
9
  import { MONOSPACE, PROSE_INK } from './pedagogyStyle.ts';
10
10
 
11
11
  /** Props of {@link GlossaryDefinition}. */
12
12
  export interface GlossaryDefinitionProps<TExample = GlossaryExample> {
13
13
  /** The term to explain, already resolved from a marker. */
14
14
  entry: GlossaryEntry<TExample>;
15
- /**
16
- * The ground it is drawn on: the dark plate of a tooltip, or the page, where
17
- * a glossary lists every term.
18
- * @default 'tooltip'
19
- */
20
- tone?: ProseTone;
21
15
  /**
22
16
  * Draws the illustration of one example; its note is still written under it.
23
17
  * @default the surrounding provider's, and otherwise the code and the input
@@ -38,17 +32,18 @@ export interface GlossaryDefinitionProps<TExample = GlossaryExample> {
38
32
  /**
39
33
  * One definition: the term, one paragraph, then the worked examples.
40
34
  *
41
- * The tooltip a marker opens and the entry a glossary page lists are this one
42
- * body on two grounds, so a term reads the same wherever it is looked up.
43
- * @param props - The entry, and the ground it is drawn on.
35
+ * The tooltip a marker opens and the entry a glossary page lists are the same
36
+ * body on the same ground — the family's light card — so a term reads the same
37
+ * wherever it is looked up.
38
+ * @param props - The entry, and how its examples and code spans are drawn.
44
39
  * @returns The definition.
45
40
  */
46
41
  export function GlossaryDefinition<TExample = GlossaryExample>(
47
42
  props: GlossaryDefinitionProps<TExample>,
48
43
  ): ReactElement {
49
- const { className, entry, tone = 'tooltip' } = props;
44
+ const { className, entry } = props;
50
45
  const context = useGlossary();
51
- const ink = PROSE_INK[tone];
46
+ const ink = PROSE_INK;
52
47
  const renderCode =
53
48
  props.renderCode ??
54
49
  context.renderCode ??
@@ -77,10 +72,7 @@ export function GlossaryDefinition<TExample = GlossaryExample>(
77
72
  }
78
73
 
79
74
  return (
80
- <div
81
- className={className}
82
- style={tone === 'tooltip' ? TOOLTIP_BODY_STYLE : BODY_STYLE}
83
- >
75
+ <div className={className} style={BODY_STYLE}>
84
76
  <div style={TITLE_STYLE}>{entry.title}</div>
85
77
  <div style={{ ...SUMMARY_STYLE, color: ink.text }}>
86
78
  <InlineText text={entry.summary} renderCode={renderCode} />
@@ -117,8 +109,6 @@ const BODY_STYLE: CSSProperties = {
117
109
  gap: 6,
118
110
  };
119
111
 
120
- const TOOLTIP_BODY_STYLE: CSSProperties = { ...BODY_STYLE, maxWidth: 340 };
121
-
122
112
  const TITLE_STYLE: CSSProperties = { fontWeight: 600, fontSize: 13 };
123
113
 
124
114
  const SUMMARY_STYLE: CSSProperties = { fontSize: 12, lineHeight: 1.45 };
@@ -122,7 +122,6 @@ export function GlossaryIndex<TExample = GlossaryExample>(
122
122
  >
123
123
  <GlossaryDefinition
124
124
  entry={entry}
125
- tone="page"
126
125
  renderExample={renderExample}
127
126
  renderCode={renderCode}
128
127
  />
@@ -23,6 +23,13 @@ export interface GlossaryProviderProps<TExample = GlossaryExample> {
23
23
  * @default undefined — a plain `<code>`
24
24
  */
25
25
  renderCode?: (code: string) => ReactNode;
26
+ /**
27
+ * Draws the `{{C6H6O}}` formulas of the prose below. A chemistry site passes
28
+ * `(mf) => <MF mf={mf} />` from `react-mf` here and every formula under the
29
+ * provider — a step, a question, a hint, a definition — is then drawn by it.
30
+ * @default undefined — the formula as typed
31
+ */
32
+ renderMf?: (mf: string) => ReactNode;
26
33
  /** The part of the page whose prose resolves its markers against it. */
27
34
  children: ReactNode;
28
35
  }
@@ -41,14 +48,15 @@ export interface GlossaryProviderProps<TExample = GlossaryExample> {
41
48
  export function GlossaryProvider<TExample = GlossaryExample>(
42
49
  props: GlossaryProviderProps<TExample>,
43
50
  ): ReactElement {
44
- const { glossary, renderExample, renderCode, children } = props;
51
+ const { glossary, renderExample, renderCode, renderMf, children } = props;
45
52
  const value = useMemo<GlossaryContextValue>(
46
53
  () => ({
47
54
  glossary,
48
55
  renderExample: renderExample as GlossaryContextValue['renderExample'],
49
56
  renderCode,
57
+ renderMf,
50
58
  }),
51
- [glossary, renderExample, renderCode],
59
+ [glossary, renderExample, renderCode, renderMf],
52
60
  );
53
61
 
54
62
  return (