react-cheminfo 0.38.0 → 0.39.1
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.
- package/lib/chart/ui/Axes.d.ts +19 -0
- package/lib/chart/ui/Axes.d.ts.map +1 -1
- package/lib/chart/ui/Axes.js +25 -5
- package/lib/chart/ui/Axes.js.map +1 -1
- package/lib/chrome/ui/NavMenuButton.d.ts.map +1 -1
- package/lib/chrome/ui/NavMenuButton.js +41 -11
- package/lib/chrome/ui/NavMenuButton.js.map +1 -1
- package/lib/chrome/ui/SiteHeader.js +24 -1
- package/lib/chrome/ui/SiteHeader.js.map +1 -1
- package/lib/chrome/ui/navItem.d.ts +7 -0
- package/lib/chrome/ui/navItem.d.ts.map +1 -1
- package/lib/chrome/ui/navItem.js.map +1 -1
- package/lib/citation/ui/entries.d.ts.map +1 -1
- package/lib/citation/ui/entries.js +6 -1
- package/lib/citation/ui/entries.js.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.d.ts +11 -0
- package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.js +28 -10
- package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
- package/lib/clipboard/ui/CopyButton.d.ts +2 -1
- package/lib/clipboard/ui/CopyButton.d.ts.map +1 -1
- package/lib/clipboard/ui/CopyButton.js +2 -1
- package/lib/clipboard/ui/CopyButton.js.map +1 -1
- package/lib/clipboard/ui/CopyableValue.d.ts +24 -4
- package/lib/clipboard/ui/CopyableValue.d.ts.map +1 -1
- package/lib/clipboard/ui/CopyableValue.js +35 -3
- package/lib/clipboard/ui/CopyableValue.js.map +1 -1
- package/lib/clipboard/ui/index.d.ts +1 -1
- package/lib/clipboard/ui/index.d.ts.map +1 -1
- package/lib/clipboard/ui/index.js.map +1 -1
- package/lib/confirm/ui/ConfirmButton.d.ts.map +1 -1
- package/lib/confirm/ui/ConfirmButton.js +2 -1
- package/lib/confirm/ui/ConfirmButton.js.map +1 -1
- package/lib/delimited/ui/TableDataButton.d.ts.map +1 -1
- package/lib/delimited/ui/TableDataButton.js +2 -1
- package/lib/delimited/ui/TableDataButton.js.map +1 -1
- package/lib/download/core/figureSvg.d.ts.map +1 -1
- package/lib/download/core/figureSvg.js +37 -12
- package/lib/download/core/figureSvg.js.map +1 -1
- package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
- package/lib/help/ui/HelpToolbarButton.js +2 -1
- package/lib/help/ui/HelpToolbarButton.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/locales/de.json +39 -4
- package/lib/locales/en.json +39 -4
- package/lib/locales/es.json +39 -4
- package/lib/locales/fr.json +39 -4
- package/lib/locales/it.json +39 -4
- package/lib/number/ui/NumberInput.js +1 -1
- package/lib/number/ui/NumberInput.js.map +1 -1
- package/lib/overlay/ui/OverlayIconButton.d.ts.map +1 -1
- package/lib/overlay/ui/OverlayIconButton.js +1 -1
- package/lib/overlay/ui/OverlayIconButton.js.map +1 -1
- package/lib/panel/ui/ClearButton.d.ts.map +1 -1
- package/lib/panel/ui/ClearButton.js +1 -1
- package/lib/panel/ui/ClearButton.js.map +1 -1
- package/lib/pedagogy/core/inlineMarks.d.ts +9 -5
- package/lib/pedagogy/core/inlineMarks.d.ts.map +1 -1
- package/lib/pedagogy/core/inlineMarks.js +14 -6
- package/lib/pedagogy/core/inlineMarks.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryDefinition.d.ts +4 -10
- package/lib/pedagogy/ui/GlossaryDefinition.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryDefinition.js +7 -7
- package/lib/pedagogy/ui/GlossaryDefinition.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.js +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryProvider.d.ts +7 -0
- package/lib/pedagogy/ui/GlossaryProvider.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryProvider.js +3 -2
- package/lib/pedagogy/ui/GlossaryProvider.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryText.d.ts +7 -2
- package/lib/pedagogy/ui/GlossaryText.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryText.js +3 -2
- package/lib/pedagogy/ui/GlossaryText.js.map +1 -1
- package/lib/pedagogy/ui/InlineText.d.ts +8 -2
- package/lib/pedagogy/ui/InlineText.d.ts.map +1 -1
- package/lib/pedagogy/ui/InlineText.js +7 -2
- package/lib/pedagogy/ui/InlineText.js.map +1 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts +4 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts.map +1 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.js +2 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.js.map +1 -1
- package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
- package/lib/pedagogy/ui/SyntaxTooltip.js +11 -10
- package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
- package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
- package/lib/pedagogy/ui/TutorialStepStrip.js +18 -4
- package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
- package/lib/pedagogy/ui/glossaryContext.d.ts +7 -0
- package/lib/pedagogy/ui/glossaryContext.d.ts.map +1 -1
- package/lib/pedagogy/ui/glossaryContext.js.map +1 -1
- package/lib/pedagogy/ui/index.d.ts +1 -1
- package/lib/pedagogy/ui/index.d.ts.map +1 -1
- package/lib/pedagogy/ui/inlineSegments.d.ts +5 -0
- package/lib/pedagogy/ui/inlineSegments.d.ts.map +1 -1
- package/lib/pedagogy/ui/inlineSegments.js +2 -0
- package/lib/pedagogy/ui/inlineSegments.js.map +1 -1
- package/lib/pedagogy/ui/pedagogyStyle.d.ts +8 -9
- package/lib/pedagogy/ui/pedagogyStyle.d.ts.map +1 -1
- package/lib/pedagogy/ui/pedagogyStyle.js +10 -18
- package/lib/pedagogy/ui/pedagogyStyle.js.map +1 -1
- package/lib/seo/core/plainDescription.d.ts +2 -2
- package/lib/seo/core/plainDescription.js +5 -2
- package/lib/seo/core/plainDescription.js.map +1 -1
- package/lib/share/core/devices.d.ts +41 -0
- package/lib/share/core/devices.d.ts.map +1 -0
- package/lib/share/core/devices.js +58 -0
- package/lib/share/core/devices.js.map +1 -0
- package/lib/share/core/index.d.ts +4 -0
- package/lib/share/core/index.d.ts.map +1 -1
- package/lib/share/core/index.js +2 -0
- package/lib/share/core/index.js.map +1 -1
- package/lib/share/core/regions.d.ts +43 -0
- package/lib/share/core/regions.d.ts.map +1 -0
- package/lib/share/core/regions.js +71 -0
- package/lib/share/core/regions.js.map +1 -0
- package/lib/share/ui/HiddenPartsProvider.d.ts.map +1 -1
- package/lib/share/ui/HiddenPartsProvider.js +4 -1
- package/lib/share/ui/HiddenPartsProvider.js.map +1 -1
- package/lib/share/ui/PagePart.d.ts.map +1 -1
- package/lib/share/ui/PagePart.js +10 -1
- package/lib/share/ui/PagePart.js.map +1 -1
- package/lib/share/ui/ShareButton.d.ts.map +1 -1
- package/lib/share/ui/ShareButton.js +3 -4
- package/lib/share/ui/ShareButton.js.map +1 -1
- package/lib/share/ui/ShareConfigOptions.d.ts +6 -1
- package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
- package/lib/share/ui/ShareConfigOptions.js +6 -13
- package/lib/share/ui/ShareConfigOptions.js.map +1 -1
- package/lib/share/ui/ShareDialog.d.ts +14 -0
- package/lib/share/ui/ShareDialog.d.ts.map +1 -1
- package/lib/share/ui/ShareDialog.js +3 -3
- package/lib/share/ui/ShareDialog.js.map +1 -1
- package/lib/share/ui/ShareDialogContent.d.ts +2 -2
- package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
- package/lib/share/ui/ShareDialogContent.js +36 -30
- package/lib/share/ui/ShareDialogContent.js.map +1 -1
- package/lib/share/ui/ShareLinkBar.d.ts +21 -0
- package/lib/share/ui/ShareLinkBar.d.ts.map +1 -0
- package/lib/share/ui/ShareLinkBar.js +32 -0
- package/lib/share/ui/ShareLinkBar.js.map +1 -0
- package/lib/share/ui/SharePanes.d.ts +17 -0
- package/lib/share/ui/SharePanes.d.ts.map +1 -0
- package/lib/share/ui/SharePanes.js +27 -0
- package/lib/share/ui/SharePanes.js.map +1 -0
- package/lib/share/ui/SharePartOptions.d.ts +9 -3
- package/lib/share/ui/SharePartOptions.d.ts.map +1 -1
- package/lib/share/ui/SharePartOptions.js +12 -16
- package/lib/share/ui/SharePartOptions.js.map +1 -1
- package/lib/share/ui/SharePartRow.d.ts +37 -0
- package/lib/share/ui/SharePartRow.d.ts.map +1 -0
- package/lib/share/ui/SharePartRow.js +25 -0
- package/lib/share/ui/SharePartRow.js.map +1 -0
- package/lib/share/ui/SharePresetTabs.d.ts +10 -7
- package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
- package/lib/share/ui/SharePresetTabs.js +17 -17
- package/lib/share/ui/SharePresetTabs.js.map +1 -1
- package/lib/share/ui/SharePreview.d.ts +32 -0
- package/lib/share/ui/SharePreview.d.ts.map +1 -0
- package/lib/share/ui/SharePreview.js +129 -0
- package/lib/share/ui/SharePreview.js.map +1 -0
- package/lib/share/ui/SharePreviewDevices.d.ts +20 -0
- package/lib/share/ui/SharePreviewDevices.d.ts.map +1 -0
- package/lib/share/ui/SharePreviewDevices.js +40 -0
- package/lib/share/ui/SharePreviewDevices.js.map +1 -0
- package/lib/share/ui/index.d.ts +1 -0
- package/lib/share/ui/index.d.ts.map +1 -1
- package/lib/share/ui/index.js.map +1 -1
- package/lib/share/ui/shareMarking.d.ts +14 -0
- package/lib/share/ui/shareMarking.d.ts.map +1 -0
- package/lib/share/ui/shareMarking.js +17 -0
- package/lib/share/ui/shareMarking.js.map +1 -0
- package/lib/share/ui/useShareRegionReports.d.ts +12 -0
- package/lib/share/ui/useShareRegionReports.d.ts.map +1 -0
- package/lib/share/ui/useShareRegionReports.js +102 -0
- package/lib/share/ui/useShareRegionReports.js.map +1 -0
- package/lib/shared/ui/ActionTooltip.d.ts +42 -0
- package/lib/shared/ui/ActionTooltip.d.ts.map +1 -0
- package/lib/shared/ui/ActionTooltip.js +21 -0
- package/lib/shared/ui/ActionTooltip.js.map +1 -0
- package/lib/shared/ui/index.d.ts +4 -0
- package/lib/shared/ui/index.d.ts.map +1 -1
- package/lib/shared/ui/index.js +2 -0
- package/lib/shared/ui/index.js.map +1 -1
- package/lib/shared/ui/useActionTooltip.d.ts +48 -0
- package/lib/shared/ui/useActionTooltip.d.ts.map +1 -0
- package/lib/shared/ui/useActionTooltip.js +78 -0
- package/lib/shared/ui/useActionTooltip.js.map +1 -0
- package/lib/structure/core/index.d.ts +2 -0
- package/lib/structure/core/index.d.ts.map +1 -1
- package/lib/structure/core/index.js +1 -0
- package/lib/structure/core/index.js.map +1 -1
- package/lib/structure/core/sourceMolecule.d.ts +18 -0
- package/lib/structure/core/sourceMolecule.d.ts.map +1 -0
- package/lib/structure/core/sourceMolecule.js +26 -0
- package/lib/structure/core/sourceMolecule.js.map +1 -0
- package/lib/structure/core/structureNotations.d.ts +57 -0
- package/lib/structure/core/structureNotations.d.ts.map +1 -0
- package/lib/structure/core/structureNotations.js +74 -0
- package/lib/structure/core/structureNotations.js.map +1 -0
- package/lib/structure/core/structurePicture.d.ts +49 -0
- package/lib/structure/core/structurePicture.d.ts.map +1 -0
- package/lib/structure/core/structurePicture.js +83 -0
- package/lib/structure/core/structurePicture.js.map +1 -0
- package/lib/structure/ui/EditorExportButton.d.ts +23 -0
- package/lib/structure/ui/EditorExportButton.d.ts.map +1 -0
- package/lib/structure/ui/EditorExportButton.js +23 -0
- package/lib/structure/ui/EditorExportButton.js.map +1 -0
- package/lib/structure/ui/EditorHelpButton.d.ts +5 -2
- package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
- package/lib/structure/ui/EditorHelpButton.js +8 -9
- package/lib/structure/ui/EditorHelpButton.js.map +1 -1
- package/lib/structure/ui/StructureEditor.d.ts +8 -0
- package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
- package/lib/structure/ui/StructureEditor.js +26 -3
- package/lib/structure/ui/StructureEditor.js.map +1 -1
- package/lib/structure/ui/StructureExportDialog.d.ts +34 -0
- package/lib/structure/ui/StructureExportDialog.d.ts.map +1 -0
- package/lib/structure/ui/StructureExportDialog.js +43 -0
- package/lib/structure/ui/StructureExportDialog.js.map +1 -0
- package/lib/structure/ui/StructureExportPanel.d.ts +37 -0
- package/lib/structure/ui/StructureExportPanel.d.ts.map +1 -0
- package/lib/structure/ui/StructureExportPanel.js +75 -0
- package/lib/structure/ui/StructureExportPanel.js.map +1 -0
- package/lib/structure/ui/StructureNotationRow.d.ts +22 -0
- package/lib/structure/ui/StructureNotationRow.d.ts.map +1 -0
- package/lib/structure/ui/StructureNotationRow.js +34 -0
- package/lib/structure/ui/StructureNotationRow.js.map +1 -0
- package/lib/structure/ui/StructurePicturePane.d.ts +23 -0
- package/lib/structure/ui/StructurePicturePane.d.ts.map +1 -0
- package/lib/structure/ui/StructurePicturePane.js +113 -0
- package/lib/structure/ui/StructurePicturePane.js.map +1 -0
- package/lib/structure/ui/StructureSvg.d.ts.map +1 -1
- package/lib/structure/ui/StructureSvg.js +2 -18
- package/lib/structure/ui/StructureSvg.js.map +1 -1
- package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
- package/lib/structure/ui/ToolbarTooltip.js +1 -2
- package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
- package/lib/structure/ui/index.d.ts +7 -3
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js +5 -3
- package/lib/structure/ui/index.js.map +1 -1
- package/lib/structure/ui/structureNotationText.d.ts +23 -0
- package/lib/structure/ui/structureNotationText.d.ts.map +1 -0
- package/lib/structure/ui/structureNotationText.js +42 -0
- package/lib/structure/ui/structureNotationText.js.map +1 -0
- package/lib/structure/ui/useEditorStructure.d.ts +37 -0
- package/lib/structure/ui/useEditorStructure.d.ts.map +1 -0
- package/lib/structure/ui/useEditorStructure.js +70 -0
- package/lib/structure/ui/useEditorStructure.js.map +1 -0
- package/package.json +1 -1
- package/src/chart/ui/Axes.tsx +53 -5
- package/src/chrome/ui/NavMenuButton.tsx +61 -18
- package/src/chrome/ui/SiteHeader.tsx +37 -1
- package/src/chrome/ui/navItem.ts +7 -0
- package/src/citation/ui/entries.tsx +10 -2
- package/src/clipboard/ui/ClickToCopy.tsx +47 -13
- package/src/clipboard/ui/CopyButton.tsx +4 -2
- package/src/clipboard/ui/CopyableValue.tsx +88 -13
- package/src/clipboard/ui/index.ts +5 -1
- package/src/confirm/ui/ConfirmButton.tsx +2 -0
- package/src/delimited/ui/TableDataButton.tsx +2 -1
- package/src/download/core/figureSvg.ts +42 -10
- package/src/help/ui/HelpToolbarButton.tsx +2 -1
- package/src/locales/de.json +39 -4
- package/src/locales/en.json +39 -4
- package/src/locales/es.json +39 -4
- package/src/locales/fr.json +39 -4
- package/src/locales/it.json +39 -4
- package/src/number/ui/NumberInput.tsx +1 -1
- package/src/overlay/ui/OverlayIconButton.tsx +1 -0
- package/src/panel/ui/ClearButton.tsx +1 -0
- package/src/pedagogy/core/inlineMarks.ts +15 -7
- package/src/pedagogy/ui/GlossaryDefinition.tsx +8 -18
- package/src/pedagogy/ui/GlossaryIndex.tsx +0 -1
- package/src/pedagogy/ui/GlossaryProvider.tsx +10 -2
- package/src/pedagogy/ui/GlossaryText.tsx +10 -2
- package/src/pedagogy/ui/InlineText.tsx +21 -4
- package/src/pedagogy/ui/ReferenceSectionBlock.tsx +8 -2
- package/src/pedagogy/ui/SyntaxTooltip.tsx +11 -9
- package/src/pedagogy/ui/TutorialStepStrip.tsx +50 -18
- package/src/pedagogy/ui/glossaryContext.ts +7 -0
- package/src/pedagogy/ui/index.ts +1 -1
- package/src/pedagogy/ui/inlineSegments.tsx +7 -0
- package/src/pedagogy/ui/pedagogyStyle.ts +12 -24
- package/src/seo/core/plainDescription.ts +4 -2
- package/src/share/core/devices.ts +80 -0
- package/src/share/core/index.ts +14 -0
- package/src/share/core/regions.ts +87 -0
- package/src/share/ui/HiddenPartsProvider.tsx +6 -1
- package/src/share/ui/PagePart.tsx +12 -1
- package/src/share/ui/ShareButton.tsx +3 -6
- package/src/share/ui/ShareConfigOptions.tsx +25 -16
- package/src/share/ui/ShareDialog.tsx +17 -3
- package/src/share/ui/ShareDialogContent.tsx +80 -77
- package/src/share/ui/ShareLinkBar.tsx +70 -0
- package/src/share/ui/SharePanes.tsx +62 -0
- package/src/share/ui/SharePartOptions.tsx +25 -26
- package/src/share/ui/SharePartRow.tsx +78 -0
- package/src/share/ui/SharePresetTabs.tsx +36 -43
- package/src/share/ui/SharePreview.tsx +235 -0
- package/src/share/ui/SharePreviewDevices.tsx +70 -0
- package/src/share/ui/index.ts +1 -0
- package/src/share/ui/shareMarking.ts +18 -0
- package/src/share/ui/useShareRegionReports.ts +108 -0
- package/src/shared/ui/ActionTooltip.tsx +70 -0
- package/src/shared/ui/index.ts +7 -0
- package/src/shared/ui/useActionTooltip.ts +103 -0
- package/src/structure/core/index.ts +5 -0
- package/src/structure/core/sourceMolecule.ts +26 -0
- package/src/structure/core/structureNotations.ts +125 -0
- package/src/structure/core/structurePicture.ts +119 -0
- package/src/structure/ui/EditorExportButton.tsx +62 -0
- package/src/structure/ui/EditorHelpButton.tsx +26 -30
- package/src/structure/ui/StructureEditor.tsx +51 -5
- package/src/structure/ui/StructureExportDialog.tsx +90 -0
- package/src/structure/ui/StructureExportPanel.tsx +156 -0
- package/src/structure/ui/StructureNotationRow.tsx +74 -0
- package/src/structure/ui/StructurePicturePane.tsx +208 -0
- package/src/structure/ui/StructureSvg.tsx +3 -12
- package/src/structure/ui/ToolbarTooltip.tsx +1 -1
- package/src/structure/ui/index.ts +7 -3
- package/src/structure/ui/structureNotationText.ts +56 -0
- package/src/structure/ui/useEditorStructure.ts +119 -0
- package/styles/chrome.css +414 -14
|
@@ -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;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The body of the export dialog, which is the half that reads the structure.
|
|
3
|
+
*
|
|
4
|
+
* It value-imports `openchemlib`, through the notations and the parser, so the
|
|
5
|
+
* dialog holds it behind `React.lazy`: a page carrying an editor downloads
|
|
6
|
+
* this only when somebody asks to export something.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
10
|
+
import { useMemo } from 'react';
|
|
11
|
+
|
|
12
|
+
import { CollapsibleSection } from '../../disclosure/ui/CollapsibleSection.tsx';
|
|
13
|
+
import { sanitizeFileName } from '../../download/core/sanitizeFileName.ts';
|
|
14
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
15
|
+
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
16
|
+
import { sourceMolecule } from '../core/sourceMolecule.ts';
|
|
17
|
+
import { structureError } from '../core/structureError.ts';
|
|
18
|
+
import { structureNotations } from '../core/structureNotations.ts';
|
|
19
|
+
import type { StructureSourceInput } from '../core/structureSource.ts';
|
|
20
|
+
import { structureSource } from '../core/structureSource.ts';
|
|
21
|
+
|
|
22
|
+
import { StructureNotationRow } from './StructureNotationRow.tsx';
|
|
23
|
+
import { StructurePicturePane } from './StructurePicturePane.tsx';
|
|
24
|
+
|
|
25
|
+
/** What {@link StructureExportPanel} is handed. */
|
|
26
|
+
export interface StructureExportPanelProps extends StructureSourceInput {
|
|
27
|
+
/**
|
|
28
|
+
* Base name of every file saved from here, extension excluded.
|
|
29
|
+
* @default 'structure'
|
|
30
|
+
*/
|
|
31
|
+
name?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the structure is a query fragment, which is what a substructure
|
|
34
|
+
* filter draws. A fragment's idCode is not a molecule's, so this has to be
|
|
35
|
+
* said when the notation handed over does not already carry it.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
fragment?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Every notation of a drawn structure, and the picture of it.
|
|
43
|
+
*
|
|
44
|
+
* The notations come first and in the order a chemist reaches for them — the
|
|
45
|
+
* SMILES, then the two molfiles — with the canonical identifiers folded away
|
|
46
|
+
* underneath: they answer a database question rather than a drawing one, so
|
|
47
|
+
* they are there for whoever came for them and out of the way of everyone
|
|
48
|
+
* else.
|
|
49
|
+
* @param props - See {@link StructureExportPanelProps}.
|
|
50
|
+
* @returns The panel.
|
|
51
|
+
*/
|
|
52
|
+
export function StructureExportPanel(
|
|
53
|
+
props: StructureExportPanelProps,
|
|
54
|
+
): ReactElement {
|
|
55
|
+
const { idCode, coordinates, molfile, smiles } = props;
|
|
56
|
+
const { name = 'structure', fragment = false } = props;
|
|
57
|
+
const t = useChromeT();
|
|
58
|
+
|
|
59
|
+
const read = useMemo(
|
|
60
|
+
() => readStructure({ idCode, coordinates, molfile, smiles }, fragment),
|
|
61
|
+
[idCode, coordinates, molfile, smiles, fragment],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (read.kind !== 'read') {
|
|
65
|
+
return (
|
|
66
|
+
<p style={EMPTY_STYLE}>
|
|
67
|
+
{read.kind === 'empty' ? t('structure.export.nothing') : read.message}
|
|
68
|
+
</p>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const fileName = sanitizeFileName(name, 'structure');
|
|
73
|
+
const notations = read.notations;
|
|
74
|
+
const common = notations.filter((notation) => !notation.canonical);
|
|
75
|
+
const identifiers = notations.filter((notation) => notation.canonical);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="structure-export__panes">
|
|
79
|
+
<StructurePicturePane molecule={read.molecule} fileName={fileName} />
|
|
80
|
+
<div className="structure-export__notations">
|
|
81
|
+
{common.map((notation) => (
|
|
82
|
+
<StructureNotationRow
|
|
83
|
+
key={notation.kind}
|
|
84
|
+
notation={notation}
|
|
85
|
+
fileName={fileName}
|
|
86
|
+
/>
|
|
87
|
+
))}
|
|
88
|
+
<CollapsibleSection
|
|
89
|
+
className="structure-export__identifiers"
|
|
90
|
+
title={t('structure.export.identifiers')}
|
|
91
|
+
defaultOpen={false}
|
|
92
|
+
>
|
|
93
|
+
{identifiers.map((notation) => (
|
|
94
|
+
<StructureNotationRow
|
|
95
|
+
key={notation.kind}
|
|
96
|
+
notation={notation}
|
|
97
|
+
fileName={fileName}
|
|
98
|
+
/>
|
|
99
|
+
))}
|
|
100
|
+
</CollapsibleSection>
|
|
101
|
+
{/* The convention is taught once here rather than with a glyph per
|
|
102
|
+
row — see the dotted underlines above. */}
|
|
103
|
+
<p style={FOOT_STYLE}>{t('overlay.hoverAName')}</p>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The structure the panel is showing, or the reason there is none. */
|
|
110
|
+
type ReadStructure =
|
|
111
|
+
| {
|
|
112
|
+
kind: 'read';
|
|
113
|
+
molecule: ReturnType<typeof sourceMolecule>;
|
|
114
|
+
notations: ReturnType<typeof structureNotations>;
|
|
115
|
+
}
|
|
116
|
+
| { kind: 'empty' }
|
|
117
|
+
| { kind: 'error'; message: string };
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read the notation the caller handed over, and write every other one from it.
|
|
121
|
+
* @param input - Whatever notations the caller has.
|
|
122
|
+
* @param fragment - Whether the structure is a query fragment.
|
|
123
|
+
* @returns The molecule and its notations, or why there are none.
|
|
124
|
+
*/
|
|
125
|
+
function readStructure(
|
|
126
|
+
input: StructureSourceInput,
|
|
127
|
+
fragment: boolean,
|
|
128
|
+
): ReadStructure {
|
|
129
|
+
const source = structureSource(input);
|
|
130
|
+
if (source.kind === 'empty') return { kind: 'empty' };
|
|
131
|
+
try {
|
|
132
|
+
const molecule = sourceMolecule(source);
|
|
133
|
+
// Only ever set, never cleared: an idCode written by a query editor
|
|
134
|
+
// already carries the flag, and clearing it would export a different
|
|
135
|
+
// structure from the one that was drawn.
|
|
136
|
+
if (fragment) molecule.setFragment(true);
|
|
137
|
+
if (molecule.getAllAtoms() === 0) return { kind: 'empty' };
|
|
138
|
+
return { kind: 'read', molecule, notations: structureNotations(molecule) };
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return { kind: 'error', message: structureError(error).message };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const EMPTY_STYLE = {
|
|
145
|
+
margin: 0,
|
|
146
|
+
padding: '2rem 0',
|
|
147
|
+
color: TOKEN.textMuted,
|
|
148
|
+
fontSize: 13,
|
|
149
|
+
textAlign: 'center',
|
|
150
|
+
} as const satisfies CSSProperties;
|
|
151
|
+
|
|
152
|
+
const FOOT_STYLE = {
|
|
153
|
+
margin: 0,
|
|
154
|
+
color: TOKEN.textFaint,
|
|
155
|
+
fontSize: 11,
|
|
156
|
+
} as const satisfies CSSProperties;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Button } from '@blueprintjs/core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
import { CopyableValue } from '../../clipboard/ui/CopyableValue.tsx';
|
|
5
|
+
import { downloadText } from '../../download/core/downloadText.ts';
|
|
6
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
7
|
+
import type { StructureNotation } from '../core/structureNotations.ts';
|
|
8
|
+
|
|
9
|
+
import { notationText } from './structureNotationText.ts';
|
|
10
|
+
|
|
11
|
+
/** What {@link StructureNotationRow} shows. */
|
|
12
|
+
export interface StructureNotationRowProps {
|
|
13
|
+
/** The notation, as `structureNotations` wrote it. */
|
|
14
|
+
notation: StructureNotation;
|
|
15
|
+
/** Base name of the file this notation is saved as, extension excluded. */
|
|
16
|
+
fileName: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* One notation: its name, the text, and the two ways of taking it away.
|
|
21
|
+
*
|
|
22
|
+
* The text is the button that copies it — a notation is only ever wanted
|
|
23
|
+
* somewhere else — and a notation that is also a file carries a save button on
|
|
24
|
+
* its name's line, where it cannot be hit while reaching for the text. The
|
|
25
|
+
* name explains itself on hover, dotted-underlined to say so, so the row needs
|
|
26
|
+
* no glyph of its own.
|
|
27
|
+
* @param props - See {@link StructureNotationRowProps}.
|
|
28
|
+
* @returns The row.
|
|
29
|
+
*/
|
|
30
|
+
export function StructureNotationRow(
|
|
31
|
+
props: StructureNotationRowProps,
|
|
32
|
+
): ReactElement {
|
|
33
|
+
const { notation, fileName } = props;
|
|
34
|
+
const { kind, value, file, block } = notation;
|
|
35
|
+
const t = useChromeT();
|
|
36
|
+
const text = notationText(kind);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<CopyableValue
|
|
40
|
+
className="structure-export__notation"
|
|
41
|
+
label={t(text.label)}
|
|
42
|
+
hint={t(text.hint)}
|
|
43
|
+
value={value}
|
|
44
|
+
block={block}
|
|
45
|
+
clip={block}
|
|
46
|
+
maxHeight={block ? BLOCK_HEIGHT : undefined}
|
|
47
|
+
action={
|
|
48
|
+
file === undefined || value === '' ? undefined : (
|
|
49
|
+
<Button
|
|
50
|
+
variant="minimal"
|
|
51
|
+
size="small"
|
|
52
|
+
icon="download"
|
|
53
|
+
text={t('download.save')}
|
|
54
|
+
onClick={() => {
|
|
55
|
+
downloadText(
|
|
56
|
+
value,
|
|
57
|
+
`${fileName}${file.suffix}.${file.extension}`,
|
|
58
|
+
`${file.mimeType};charset=utf-8`,
|
|
59
|
+
);
|
|
60
|
+
}}
|
|
61
|
+
/>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* How much of a molfile is shown: its header and the first lines of its
|
|
70
|
+
* connection table, which is enough to see which dialect and which molecule it
|
|
71
|
+
* is. The rest is faded out rather than scrolled — the whole file is what a
|
|
72
|
+
* click copies and what the save button writes.
|
|
73
|
+
*/
|
|
74
|
+
const BLOCK_HEIGHT = 92;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Button, SegmentedControl } from '@blueprintjs/core';
|
|
2
|
+
import type { Molecule } from 'openchemlib';
|
|
3
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
import { writeImageToClipboard } from '../../clipboard/core/copyPng.ts';
|
|
7
|
+
import { downloadBlob } from '../../download/core/downloadBlob.ts';
|
|
8
|
+
import { downloadText } from '../../download/core/downloadText.ts';
|
|
9
|
+
import { figurePng } from '../../download/core/figurePng.ts';
|
|
10
|
+
import {
|
|
11
|
+
FIGURE_SCALES,
|
|
12
|
+
figureScaleFits,
|
|
13
|
+
figureScaleLabel,
|
|
14
|
+
formatFigurePixels,
|
|
15
|
+
} from '../../download/core/figureScale.ts';
|
|
16
|
+
import { FIGURE_SVG_TYPE } from '../../download/core/figureSvg.ts';
|
|
17
|
+
import { HelpTooltip } from '../../help/ui/HelpTooltip.tsx';
|
|
18
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
19
|
+
import { OVERLAY_HELP_NAME_STYLE } from '../../overlay/ui/overlayRowStyles.ts';
|
|
20
|
+
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
21
|
+
import type { StructurePicture } from '../core/structurePicture.ts';
|
|
22
|
+
import {
|
|
23
|
+
STRUCTURE_BOND_LENGTH,
|
|
24
|
+
structurePicture,
|
|
25
|
+
} from '../core/structurePicture.ts';
|
|
26
|
+
|
|
27
|
+
/** What {@link StructurePicturePane} draws and saves. */
|
|
28
|
+
export interface StructurePicturePaneProps {
|
|
29
|
+
/** The structure. Not modified. */
|
|
30
|
+
molecule: Molecule;
|
|
31
|
+
/** Base name of the saved files, extension excluded. */
|
|
32
|
+
fileName: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The multiple the pictures are offered at first. */
|
|
36
|
+
const DEFAULT_SCALE = 2;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The structure as a picture: what it looks like, how big it leaves, and the
|
|
40
|
+
* three ways it leaves.
|
|
41
|
+
*
|
|
42
|
+
* What is shown is the file: the preview is the very SVG the save button
|
|
43
|
+
* writes, laid out smaller, so nobody saves a picture they have not seen. The
|
|
44
|
+
* resolution is a multiple rather than a pixel width because the multiple is
|
|
45
|
+
* the part a reader has an opinion about — one for a note, two for a slide,
|
|
46
|
+
* three or four for print — and the pixels it comes to are written under it.
|
|
47
|
+
* @param props - See {@link StructurePicturePaneProps}.
|
|
48
|
+
* @returns The pane.
|
|
49
|
+
*/
|
|
50
|
+
export function StructurePicturePane(
|
|
51
|
+
props: StructurePicturePaneProps,
|
|
52
|
+
): ReactElement {
|
|
53
|
+
const { molecule, fileName } = props;
|
|
54
|
+
const t = useChromeT();
|
|
55
|
+
const [scale, setScale] = useState(DEFAULT_SCALE);
|
|
56
|
+
const [notice, setNotice] = useState<string | null>(null);
|
|
57
|
+
|
|
58
|
+
// Drawn once per resolution, so what is previewed, measured and saved is one
|
|
59
|
+
// picture rather than three that have to be kept in step.
|
|
60
|
+
const picture = useMemo(
|
|
61
|
+
() =>
|
|
62
|
+
structurePicture(molecule, { bondLength: STRUCTURE_BOND_LENGTH * scale }),
|
|
63
|
+
[molecule, scale],
|
|
64
|
+
);
|
|
65
|
+
// Shown as the document itself rather than as markup put into the page: the
|
|
66
|
+
// dialog never writes HTML it did not author, and the preview is the file.
|
|
67
|
+
const preview = `data:${FIGURE_SVG_TYPE},${encodeURIComponent(picture.markup)}`;
|
|
68
|
+
// The crop is the structure's own shape, so the size at one resolution is
|
|
69
|
+
// what every other one scales from: measured rather than assumed.
|
|
70
|
+
const base = useMemo(() => structurePicture(molecule), [molecule]);
|
|
71
|
+
|
|
72
|
+
async function png(): Promise<Blob> {
|
|
73
|
+
return figurePng(picture, 1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function run(write: () => Promise<string | null>): Promise<void> {
|
|
77
|
+
try {
|
|
78
|
+
setNotice(await write());
|
|
79
|
+
} catch (error) {
|
|
80
|
+
setNotice(error instanceof Error ? error.message : String(error));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className="structure-export__picture">
|
|
86
|
+
<img
|
|
87
|
+
className="structure-export__stage"
|
|
88
|
+
src={preview}
|
|
89
|
+
alt={t('structure.export.picture')}
|
|
90
|
+
/>
|
|
91
|
+
<div className="structure-export__row">
|
|
92
|
+
<HelpTooltip
|
|
93
|
+
content={{
|
|
94
|
+
title: t('download.resolution'),
|
|
95
|
+
body: t('download.resolutionHelp'),
|
|
96
|
+
example: { code: '2×', note: t('download.resolutionExample') },
|
|
97
|
+
}}
|
|
98
|
+
placement="top-start"
|
|
99
|
+
>
|
|
100
|
+
<span style={NAME_STYLE}>{t('download.resolution')}</span>
|
|
101
|
+
</HelpTooltip>
|
|
102
|
+
<SegmentedControl
|
|
103
|
+
size="small"
|
|
104
|
+
options={scaleOptions(base)}
|
|
105
|
+
value={String(scale)}
|
|
106
|
+
onValueChange={(picked) => {
|
|
107
|
+
setNotice(null);
|
|
108
|
+
setScale(Number(picked));
|
|
109
|
+
}}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
<p className="structure-export__pixels" style={PIXELS_STYLE}>
|
|
113
|
+
{formatFigurePixels(picture)}
|
|
114
|
+
</p>
|
|
115
|
+
<div className="structure-export__actions">
|
|
116
|
+
<Button
|
|
117
|
+
icon="download"
|
|
118
|
+
size="small"
|
|
119
|
+
text={t('structure.export.saveSvg')}
|
|
120
|
+
onClick={() =>
|
|
121
|
+
void run(async () => {
|
|
122
|
+
downloadText(picture.markup, `${fileName}.svg`, FIGURE_SVG_TYPE);
|
|
123
|
+
return null;
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
/>
|
|
127
|
+
<Button
|
|
128
|
+
icon="download"
|
|
129
|
+
size="small"
|
|
130
|
+
intent="primary"
|
|
131
|
+
text={t('structure.export.savePng')}
|
|
132
|
+
onClick={() =>
|
|
133
|
+
void run(async () => {
|
|
134
|
+
downloadBlob(await png(), `${fileName}.png`);
|
|
135
|
+
return null;
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
/>
|
|
139
|
+
<Button
|
|
140
|
+
icon="clipboard"
|
|
141
|
+
size="small"
|
|
142
|
+
text={t('structure.export.copyPng')}
|
|
143
|
+
onClick={() =>
|
|
144
|
+
// Safari only allows a clipboard write the click itself started,
|
|
145
|
+
// so the image is handed over as a promise rather than awaited
|
|
146
|
+
// first — see `writeImageToClipboard`.
|
|
147
|
+
void run(async () =>
|
|
148
|
+
(await writeImageToClipboard(png()))
|
|
149
|
+
? t('download.hintCopied', {
|
|
150
|
+
pixels: formatFigurePixels(picture),
|
|
151
|
+
})
|
|
152
|
+
: t('download.copyUnsupported'),
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
/>
|
|
156
|
+
</div>
|
|
157
|
+
{notice === null ? null : (
|
|
158
|
+
<p className="structure-export__notice" style={NOTICE_STYLE}>
|
|
159
|
+
{notice}
|
|
160
|
+
</p>
|
|
161
|
+
)}
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The multiples offered, each greyed when the picture it would produce is past
|
|
168
|
+
* what a browser will paint — the ceiling is met here rather than as a blank
|
|
169
|
+
* file, which is the rule the figure panel follows.
|
|
170
|
+
* @param base - The picture at the smallest resolution, which the others are
|
|
171
|
+
* multiples of.
|
|
172
|
+
* @returns The choices, in the order offered.
|
|
173
|
+
*/
|
|
174
|
+
function scaleOptions(base: StructurePicture): Array<{
|
|
175
|
+
label: string;
|
|
176
|
+
value: string;
|
|
177
|
+
disabled?: boolean;
|
|
178
|
+
}> {
|
|
179
|
+
const options = [];
|
|
180
|
+
for (const scale of FIGURE_SCALES) {
|
|
181
|
+
options.push({
|
|
182
|
+
label: figureScaleLabel(scale),
|
|
183
|
+
value: String(scale),
|
|
184
|
+
disabled: !figureScaleFits(base, scale),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return options;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const NAME_STYLE = {
|
|
191
|
+
...OVERLAY_HELP_NAME_STYLE,
|
|
192
|
+
color: TOKEN.textMuted,
|
|
193
|
+
fontSize: 12,
|
|
194
|
+
fontWeight: 600,
|
|
195
|
+
} as const satisfies CSSProperties;
|
|
196
|
+
|
|
197
|
+
const PIXELS_STYLE = {
|
|
198
|
+
margin: 0,
|
|
199
|
+
color: TOKEN.textFaint,
|
|
200
|
+
fontSize: 11,
|
|
201
|
+
fontVariantNumeric: 'tabular-nums',
|
|
202
|
+
} as const satisfies CSSProperties;
|
|
203
|
+
|
|
204
|
+
const NOTICE_STYLE = {
|
|
205
|
+
margin: 0,
|
|
206
|
+
color: TOKEN.textMuted,
|
|
207
|
+
fontSize: 11,
|
|
208
|
+
} as const satisfies CSSProperties;
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
* every bundle, including the ones that only ever wanted the Tools menu.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { Molecule } from 'openchemlib';
|
|
11
|
+
import type { Molecule } from 'openchemlib';
|
|
12
12
|
import type { ReactElement, ReactNode } from 'react';
|
|
13
13
|
import { useMemo } from 'react';
|
|
14
14
|
import { SvgRenderer } from 'react-ocl';
|
|
15
15
|
|
|
16
16
|
import type { AtomLabelPlacement } from '../core/atomLabels.ts';
|
|
17
17
|
import { applyAtomLabels } from '../core/atomLabels.ts';
|
|
18
|
+
import { sourceMolecule } from '../core/sourceMolecule.ts';
|
|
18
19
|
import type { StructureSource } from '../core/structureSource.ts';
|
|
19
20
|
|
|
20
21
|
import { StructurePlaceholder } from './StructurePlaceholder.tsx';
|
|
@@ -163,7 +164,7 @@ function readDrawing(
|
|
|
163
164
|
): Drawing | null {
|
|
164
165
|
let molecule: Molecule;
|
|
165
166
|
try {
|
|
166
|
-
molecule =
|
|
167
|
+
molecule = sourceMolecule({ kind, value, coordinates });
|
|
167
168
|
} catch {
|
|
168
169
|
return null;
|
|
169
170
|
}
|
|
@@ -174,13 +175,3 @@ function readDrawing(
|
|
|
174
175
|
const written = applyAtomLabels(molecule, labels, placement);
|
|
175
176
|
return { molecule, labelled: written > 0 };
|
|
176
177
|
}
|
|
177
|
-
|
|
178
|
-
function parseMolecule(
|
|
179
|
-
kind: StructureSource['kind'],
|
|
180
|
-
value: string,
|
|
181
|
-
coordinates: string | undefined,
|
|
182
|
-
): Molecule {
|
|
183
|
-
if (kind === 'idcode') return Molecule.fromIDCode(value, coordinates);
|
|
184
|
-
if (kind === 'molfile') return Molecule.fromMolfile(value);
|
|
185
|
-
return Molecule.fromSmiles(value);
|
|
186
|
-
}
|
|
@@ -43,6 +43,7 @@ export function ToolbarTooltip(
|
|
|
43
43
|
isOpen={hover.open}
|
|
44
44
|
placement="right"
|
|
45
45
|
content={<ButtonTip button={button} mode={mode} />}
|
|
46
|
+
popoverClassName="help-tooltip"
|
|
46
47
|
renderTarget={({ ref }) => (
|
|
47
48
|
<span ref={ref} aria-hidden style={{ ...TARGET_STYLE, ...hover.box }} />
|
|
48
49
|
)}
|
|
@@ -87,7 +88,6 @@ const TIP_STYLE: CSSProperties = {
|
|
|
87
88
|
display: 'flex',
|
|
88
89
|
flexDirection: 'column',
|
|
89
90
|
gap: 4,
|
|
90
|
-
maxWidth: 260,
|
|
91
91
|
lineHeight: 1.4,
|
|
92
92
|
};
|
|
93
93
|
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* What a site imports to show or to draw a structure.
|
|
3
3
|
*
|
|
4
4
|
* **Nothing exported here may pull react-ocl or openchemlib in statically.**
|
|
5
|
-
* `StructureSvg` and `
|
|
6
|
-
*
|
|
7
|
-
* boundaries inside `Structure
|
|
5
|
+
* `StructureSvg`, `EditorCanvas` and `StructureExportPanel` are deliberately
|
|
6
|
+
* absent: re-exporting any of them would make react-ocl reachable from this
|
|
7
|
+
* barrel, the `React.lazy` boundaries inside `Structure`, `StructureEditor`
|
|
8
|
+
* and `StructureExportDialog` would be defeated, and
|
|
8
9
|
* `react-cheminfo/structure` would stop being importable at all when those
|
|
9
10
|
* optional peers are not installed — which is what a site wanting only the
|
|
10
11
|
* Tools menu does. Type-only re-exports are erased and so are safe.
|
|
@@ -22,5 +23,8 @@ export type { StructureEditorProps } from './StructureEditor.tsx';
|
|
|
22
23
|
export { StructureEditor } from './StructureEditor.tsx';
|
|
23
24
|
export type { StructureEditorHelpProps } from './StructureEditorHelp.tsx';
|
|
24
25
|
export { StructureEditorHelp } from './StructureEditorHelp.tsx';
|
|
26
|
+
export type { StructureExportDialogProps } from './StructureExportDialog.tsx';
|
|
27
|
+
export { StructureExportDialog } from './StructureExportDialog.tsx';
|
|
28
|
+
export type { StructureExportPanelProps } from './StructureExportPanel.tsx';
|
|
25
29
|
export type { ToolbarFloorOptions } from './useToolbarFloor.ts';
|
|
26
30
|
export { useToolbarFloor } from './useToolbarFloor.ts';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each notation is called, and the line that explains it.
|
|
3
|
+
*
|
|
4
|
+
* The core module writing the notations stays language-free, so the words live
|
|
5
|
+
* here: one record, so a notation added there is a compile error until it is
|
|
6
|
+
* named.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ChromeKey } from '../../i18n/core/chromeCatalog.ts';
|
|
10
|
+
import type { StructureNotationKind } from '../core/structureNotations.ts';
|
|
11
|
+
|
|
12
|
+
/** The two lines a notation needs: its name, and what it is. */
|
|
13
|
+
export interface StructureNotationText {
|
|
14
|
+
/** Its name, on the row. */
|
|
15
|
+
label: ChromeKey;
|
|
16
|
+
/** What it is, read by hovering the name. */
|
|
17
|
+
hint: ChromeKey;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const TEXT = {
|
|
21
|
+
smiles: {
|
|
22
|
+
label: 'structure.export.smiles',
|
|
23
|
+
hint: 'structure.export.smilesHelp',
|
|
24
|
+
},
|
|
25
|
+
molfileV3000: {
|
|
26
|
+
label: 'structure.export.molfileV3000',
|
|
27
|
+
hint: 'structure.export.molfileV3000Help',
|
|
28
|
+
},
|
|
29
|
+
molfileV2000: {
|
|
30
|
+
label: 'structure.export.molfileV2000',
|
|
31
|
+
hint: 'structure.export.molfileV2000Help',
|
|
32
|
+
},
|
|
33
|
+
idCode: {
|
|
34
|
+
label: 'structure.export.idCode',
|
|
35
|
+
hint: 'structure.export.idCodeHelp',
|
|
36
|
+
},
|
|
37
|
+
noStereoIdCode: {
|
|
38
|
+
label: 'structure.export.noStereoIdCode',
|
|
39
|
+
hint: 'structure.export.noStereoIdCodeHelp',
|
|
40
|
+
},
|
|
41
|
+
noStereoTautomerIdCode: {
|
|
42
|
+
label: 'structure.export.noStereoTautomerIdCode',
|
|
43
|
+
hint: 'structure.export.noStereoTautomerIdCodeHelp',
|
|
44
|
+
},
|
|
45
|
+
} as const satisfies Record<StructureNotationKind, StructureNotationText>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* How a notation is named and explained.
|
|
49
|
+
* @param kind - Which notation it is.
|
|
50
|
+
* @returns The two keys to format.
|
|
51
|
+
*/
|
|
52
|
+
export function notationText(
|
|
53
|
+
kind: StructureNotationKind,
|
|
54
|
+
): StructureNotationText {
|
|
55
|
+
return TEXT[kind];
|
|
56
|
+
}
|