react-cheminfo 0.37.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.
- package/README.md +77 -1
- package/bin/check-seo.mjs +43 -1
- 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/core.d.ts +1 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +1 -0
- package/lib/core.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 +48 -5
- package/lib/locales/en.json +48 -5
- package/lib/locales/es.json +48 -5
- package/lib/locales/fr.json +48 -5
- package/lib/locales/it.json +48 -5
- package/lib/number/core/index.d.ts +1 -1
- package/lib/number/core/index.d.ts.map +1 -1
- package/lib/number/core/index.js +1 -1
- package/lib/number/core/index.js.map +1 -1
- package/lib/number/core/numberText.d.ts +13 -0
- package/lib/number/core/numberText.d.ts.map +1 -1
- package/lib/number/core/numberText.js +20 -0
- package/lib/number/core/numberText.js.map +1 -1
- 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/range/core/index.d.ts +4 -0
- package/lib/range/core/index.d.ts.map +1 -0
- package/lib/range/core/index.js +3 -0
- package/lib/range/core/index.js.map +1 -0
- package/lib/range/core/rangeBounds.d.ts +79 -0
- package/lib/range/core/rangeBounds.d.ts.map +1 -0
- package/lib/range/core/rangeBounds.js +110 -0
- package/lib/range/core/rangeBounds.js.map +1 -0
- package/lib/range/core/rangeHistogram.d.ts +13 -0
- package/lib/range/core/rangeHistogram.d.ts.map +1 -0
- package/lib/range/core/rangeHistogram.js +39 -0
- package/lib/range/core/rangeHistogram.js.map +1 -0
- package/lib/range/ui/RangeHistogram.d.ts +20 -0
- package/lib/range/ui/RangeHistogram.d.ts.map +1 -0
- package/lib/range/ui/RangeHistogram.js +18 -0
- package/lib/range/ui/RangeHistogram.js.map +1 -0
- package/lib/range/ui/RangeSlider.d.ts +77 -0
- package/lib/range/ui/RangeSlider.d.ts.map +1 -0
- package/lib/range/ui/RangeSlider.js +60 -0
- package/lib/range/ui/RangeSlider.js.map +1 -0
- package/lib/range/ui/RangeValue.d.ts +41 -0
- package/lib/range/ui/RangeValue.d.ts.map +1 -0
- package/lib/range/ui/RangeValue.js +73 -0
- package/lib/range/ui/RangeValue.js.map +1 -0
- package/lib/range/ui/index.d.ts +3 -0
- package/lib/range/ui/index.d.ts.map +1 -0
- package/lib/range/ui/index.js +2 -0
- package/lib/range/ui/index.js.map +1 -0
- package/lib/seo/core/documentMeta.d.ts +16 -0
- package/lib/seo/core/documentMeta.d.ts.map +1 -1
- package/lib/seo/core/documentMeta.js +18 -0
- package/lib/seo/core/documentMeta.js.map +1 -1
- package/lib/seo/core/index.d.ts +3 -1
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +2 -1
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/noscript.d.ts +8 -0
- package/lib/seo/core/noscript.d.ts.map +1 -1
- package/lib/seo/core/noscript.js +10 -3
- package/lib/seo/core/noscript.js.map +1 -1
- package/lib/seo/core/pageMeta.d.ts +10 -2
- package/lib/seo/core/pageMeta.d.ts.map +1 -1
- package/lib/seo/core/pageMeta.js +12 -3
- package/lib/seo/core/pageMeta.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/seo/core/siteFiles.d.ts +32 -3
- package/lib/seo/core/siteFiles.d.ts.map +1 -1
- package/lib/seo/core/siteFiles.js +13 -4
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/seo/core/startDocumentMeta.js +8 -7
- package/lib/seo/core/startDocumentMeta.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +26 -4
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +100 -30
- package/lib/seo/vite/prerender.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 +104 -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 +73 -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/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- 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/core.ts +1 -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 +48 -5
- package/src/locales/en.json +48 -5
- package/src/locales/es.json +48 -5
- package/src/locales/fr.json +48 -5
- package/src/locales/it.json +48 -5
- package/src/number/core/index.ts +1 -0
- package/src/number/core/numberText.ts +20 -0
- 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/range/core/index.ts +11 -0
- package/src/range/core/rangeBounds.ts +143 -0
- package/src/range/core/rangeHistogram.ts +38 -0
- package/src/range/ui/RangeHistogram.tsx +49 -0
- package/src/range/ui/RangeSlider.tsx +209 -0
- package/src/range/ui/RangeValue.tsx +166 -0
- package/src/range/ui/index.ts +2 -0
- package/src/seo/core/documentMeta.ts +22 -0
- package/src/seo/core/index.ts +8 -1
- package/src/seo/core/noscript.ts +20 -2
- package/src/seo/core/pageMeta.ts +29 -5
- package/src/seo/core/plainDescription.ts +4 -2
- package/src/seo/core/siteFiles.ts +45 -10
- package/src/seo/core/startDocumentMeta.ts +9 -9
- package/src/seo/vite/prerender.ts +160 -36
- 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 +204 -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 +84 -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/src/ui.ts +1 -0
- package/styles/chrome.css +546 -11
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every way this package writes a drawn structure out.
|
|
3
|
+
*
|
|
4
|
+
* **Not exported from `core/index.ts`, and it must not be.** It is the one
|
|
5
|
+
* structure module that value-imports `openchemlib`, because the canonical
|
|
6
|
+
* forms below are `CanonizerUtil`'s and nothing on `Molecule` reaches them, so
|
|
7
|
+
* a barrel carrying it would pull openchemlib into every site that imports
|
|
8
|
+
* `react-cheminfo/core` for a formatter. The export dialog loads it lazily
|
|
9
|
+
* instead, next to the editor that already has openchemlib.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Molecule } from 'openchemlib';
|
|
13
|
+
import { CanonizerUtil } from 'openchemlib';
|
|
14
|
+
|
|
15
|
+
/** The notations offered, in the order they are offered in. */
|
|
16
|
+
export type StructureNotationKind =
|
|
17
|
+
| 'smiles'
|
|
18
|
+
| 'molfileV3000'
|
|
19
|
+
| 'molfileV2000'
|
|
20
|
+
| 'idCode'
|
|
21
|
+
| 'noStereoIdCode'
|
|
22
|
+
| 'noStereoTautomerIdCode';
|
|
23
|
+
|
|
24
|
+
/** How a notation leaves the page as a file. */
|
|
25
|
+
export interface StructureNotationFile {
|
|
26
|
+
/** Added to the structure's own name, so two molfiles do not collide. */
|
|
27
|
+
suffix: string;
|
|
28
|
+
/** The extension, without its dot. */
|
|
29
|
+
extension: string;
|
|
30
|
+
/** What the file holds, so the system opens it with the right application. */
|
|
31
|
+
mimeType: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** One way of writing a structure. */
|
|
35
|
+
export interface StructureNotation {
|
|
36
|
+
/** Which notation it is. */
|
|
37
|
+
kind: StructureNotationKind;
|
|
38
|
+
/** The notation itself, empty when OpenChemLib would not write it. */
|
|
39
|
+
value: string;
|
|
40
|
+
/**
|
|
41
|
+
* Whether it is one of the canonical identifiers — a string that names the
|
|
42
|
+
* molecule rather than describes the drawing, and that a record is looked up
|
|
43
|
+
* by. They answer a database question rather than a drawing one, so they are
|
|
44
|
+
* shown apart from the rest.
|
|
45
|
+
*/
|
|
46
|
+
canonical: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The file it is saved as. Absent for a notation that is only ever copied.
|
|
49
|
+
* @default undefined
|
|
50
|
+
*/
|
|
51
|
+
file?: StructureNotationFile;
|
|
52
|
+
/**
|
|
53
|
+
* Whether it runs over several lines, so it is shown as a block rather than
|
|
54
|
+
* on the label's own line.
|
|
55
|
+
*/
|
|
56
|
+
block: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** What a molfile is, for the application that opens one. */
|
|
60
|
+
const MOLFILE_TYPE = 'chemical/x-mdl-molfile';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Write a structure every way the export dialog offers.
|
|
64
|
+
*
|
|
65
|
+
* A notation OpenChemLib refuses — a query fragment has no SMILES, a generic
|
|
66
|
+
* tautomer cannot always be canonized — comes back empty rather than taking
|
|
67
|
+
* the rest of the list down with it.
|
|
68
|
+
* @param molecule - The structure, as the editor handed it over. Not modified.
|
|
69
|
+
* @returns One entry per notation, in the order they are shown.
|
|
70
|
+
*/
|
|
71
|
+
export function structureNotations(molecule: Molecule): StructureNotation[] {
|
|
72
|
+
const idCode = written(() => molecule.getIDCode());
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
kind: 'smiles',
|
|
76
|
+
value: written(() => molecule.toIsomericSmiles()),
|
|
77
|
+
canonical: false,
|
|
78
|
+
block: false,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
kind: 'molfileV3000',
|
|
82
|
+
value: written(() => molecule.toMolfileV3()),
|
|
83
|
+
canonical: false,
|
|
84
|
+
file: { suffix: '-v3000', extension: 'mol', mimeType: MOLFILE_TYPE },
|
|
85
|
+
block: true,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
kind: 'molfileV2000',
|
|
89
|
+
value: written(() => molecule.toMolfile()),
|
|
90
|
+
canonical: false,
|
|
91
|
+
file: { suffix: '-v2000', extension: 'mol', mimeType: MOLFILE_TYPE },
|
|
92
|
+
block: true,
|
|
93
|
+
},
|
|
94
|
+
{ kind: 'idCode', value: idCode, canonical: true, block: false },
|
|
95
|
+
{
|
|
96
|
+
kind: 'noStereoIdCode',
|
|
97
|
+
value: written(() =>
|
|
98
|
+
CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO),
|
|
99
|
+
),
|
|
100
|
+
canonical: true,
|
|
101
|
+
block: false,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
kind: 'noStereoTautomerIdCode',
|
|
105
|
+
value: written(() =>
|
|
106
|
+
CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO_TAUTOMER),
|
|
107
|
+
),
|
|
108
|
+
canonical: true,
|
|
109
|
+
block: false,
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* One notation, or nothing when OpenChemLib will not write it.
|
|
116
|
+
* @param write - What writes it.
|
|
117
|
+
* @returns The notation, empty on a refusal.
|
|
118
|
+
*/
|
|
119
|
+
function written(write: () => string): string {
|
|
120
|
+
try {
|
|
121
|
+
return write();
|
|
122
|
+
} catch {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A structure as a picture, drawn at the size it is saved at.
|
|
3
|
+
*
|
|
4
|
+
* The resolution is a bond length rather than a canvas: OpenChemLib caps the
|
|
5
|
+
* bond it draws at 24 pixels whatever box it is given, so asking for a canvas
|
|
6
|
+
* four times larger produces the same small drawing with more white around it
|
|
7
|
+
* — a resolution control that changes the file and not the picture. Lifting
|
|
8
|
+
* the cap and cropping to the structure is what makes `4×` genuinely four
|
|
9
|
+
* times the drawing.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { Molecule } from 'openchemlib';
|
|
13
|
+
|
|
14
|
+
import type { FigurePixels } from '../../download/core/figureScale.ts';
|
|
15
|
+
|
|
16
|
+
/** How the picture is drawn. */
|
|
17
|
+
export interface StructurePictureOptions {
|
|
18
|
+
/**
|
|
19
|
+
* The longest bond drawn, in pixels, which is what sets the size of
|
|
20
|
+
* everything else — the picture is cropped to the structure afterwards.
|
|
21
|
+
* @default 60
|
|
22
|
+
*/
|
|
23
|
+
bondLength?: number;
|
|
24
|
+
/**
|
|
25
|
+
* What is painted behind the structure. An SVG left unpainted opens
|
|
26
|
+
* transparent, and a structure is drawn in black, so it disappears in
|
|
27
|
+
* anything with a dark background — a slide, a reader in dark mode.
|
|
28
|
+
* @default '#ffffff'
|
|
29
|
+
*/
|
|
30
|
+
background?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A structure drawn, and how big it came out. */
|
|
34
|
+
export interface StructurePicture extends FigurePixels {
|
|
35
|
+
/** The SVG document, ready to be saved or rasterized. */
|
|
36
|
+
markup: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The bond length a picture is drawn at before the resolution multiplies it.
|
|
41
|
+
*
|
|
42
|
+
* Chosen so a drug-sized molecule comes out around 300 pixels wide, which is
|
|
43
|
+
* what a note or a chat window wants; two or three times that is a slide, and
|
|
44
|
+
* four is print.
|
|
45
|
+
*/
|
|
46
|
+
export const STRUCTURE_BOND_LENGTH = 60;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The canvas the structure is laid out in before it is cropped out of it.
|
|
50
|
+
*
|
|
51
|
+
* Only a ceiling: past it the box, rather than the bond length, would decide
|
|
52
|
+
* the size, and it is far beyond what a browser will paint anyway.
|
|
53
|
+
*/
|
|
54
|
+
const CANVAS = 20_000;
|
|
55
|
+
|
|
56
|
+
/** Where the opening `<svg …>` tag ends, so the background goes after it. */
|
|
57
|
+
const OPEN_TAG = /<svg\b[^>]*>/u;
|
|
58
|
+
|
|
59
|
+
/** The size OpenChemLib wrote on the document it produced. */
|
|
60
|
+
const SIDE = /\b(?<side>width|height)="(?<pixels>\d+)px"/gu;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Draw a structure as a standalone SVG document, cropped to the structure.
|
|
64
|
+
* @param molecule - The structure. Not modified.
|
|
65
|
+
* @param options - How large to draw it, and what to paint behind it.
|
|
66
|
+
* @returns The document and the size it came out at.
|
|
67
|
+
*/
|
|
68
|
+
export function structurePicture(
|
|
69
|
+
molecule: Molecule,
|
|
70
|
+
options: StructurePictureOptions = {},
|
|
71
|
+
): StructurePicture {
|
|
72
|
+
const { bondLength = STRUCTURE_BOND_LENGTH, background = '#ffffff' } =
|
|
73
|
+
options;
|
|
74
|
+
const markup = molecule.toSVG(CANVAS, CANVAS, undefined, {
|
|
75
|
+
autoCrop: true,
|
|
76
|
+
autoCropMargin: Math.max(2, Math.round(bondLength / 6)),
|
|
77
|
+
maxAVBL: Math.max(1, Math.round(bondLength)),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return { markup: painted(markup, background), ...sizeOf(markup) };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Paint a background into the document, so the file does not open
|
|
85
|
+
* transparent.
|
|
86
|
+
* @param markup - The document as OpenChemLib wrote it.
|
|
87
|
+
* @param background - What to paint, or `transparent` to paint nothing.
|
|
88
|
+
* @returns The document.
|
|
89
|
+
*/
|
|
90
|
+
function painted(markup: string, background: string): string {
|
|
91
|
+
if (background === 'transparent') return markup;
|
|
92
|
+
const open = OPEN_TAG.exec(markup);
|
|
93
|
+
// A document whose opening tag cannot be found is handed back unpainted
|
|
94
|
+
// rather than corrupted by an insertion at a guessed offset.
|
|
95
|
+
if (open === null) return markup;
|
|
96
|
+
const end = open.index + open[0].length;
|
|
97
|
+
return `${markup.slice(0, end)}<rect width="100%" height="100%" fill="${background}" />${markup.slice(end)}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* How big the cropped document came out.
|
|
102
|
+
*
|
|
103
|
+
* Read off the document rather than computed, because the crop is the
|
|
104
|
+
* structure's own shape: two molecules asked for at the same bond length come
|
|
105
|
+
* out at different sizes, and the size is what the reader is shown.
|
|
106
|
+
* @param markup - The document as OpenChemLib wrote it.
|
|
107
|
+
* @returns Its size in pixels.
|
|
108
|
+
*/
|
|
109
|
+
function sizeOf(markup: string): FigurePixels {
|
|
110
|
+
const sides: Record<string, number> = {};
|
|
111
|
+
SIDE.lastIndex = 0;
|
|
112
|
+
for (const match of markup.matchAll(SIDE)) {
|
|
113
|
+
const { side, pixels } = match.groups ?? {};
|
|
114
|
+
if (side !== undefined && pixels !== undefined && !(side in sides)) {
|
|
115
|
+
sides[side] = Number(pixels);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { width: sides.width ?? CANVAS, height: sides.height ?? CANVAS };
|
|
119
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Button } from '@blueprintjs/core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
|
|
7
|
+
import type { StructureSourceInput } from '../core/structureSource.ts';
|
|
8
|
+
|
|
9
|
+
import { StructureExportDialog } from './StructureExportDialog.tsx';
|
|
10
|
+
|
|
11
|
+
/** What {@link EditorExportButton} needs. */
|
|
12
|
+
export interface EditorExportButtonProps {
|
|
13
|
+
/** Reads what is drawn, called the moment the dialog is opened. */
|
|
14
|
+
source: () => StructureSourceInput;
|
|
15
|
+
/** Whether the editor draws a query fragment. */
|
|
16
|
+
fragment: boolean;
|
|
17
|
+
/** Whether the canvas holds nothing to export. */
|
|
18
|
+
empty: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The editor's export button, beside the help one, opening every notation of
|
|
23
|
+
* the drawing and the picture of it.
|
|
24
|
+
*
|
|
25
|
+
* The structure is read when the button is pressed rather than kept beside the
|
|
26
|
+
* canvas, so the dialog opens on what is drawn now and the editor is not
|
|
27
|
+
* re-rendered on every stroke to keep a copy in step.
|
|
28
|
+
* @param props - See {@link EditorExportButtonProps}.
|
|
29
|
+
* @returns The button and its dialog.
|
|
30
|
+
*/
|
|
31
|
+
export function EditorExportButton(
|
|
32
|
+
props: EditorExportButtonProps,
|
|
33
|
+
): ReactElement {
|
|
34
|
+
const { source, fragment, empty } = props;
|
|
35
|
+
const t = useChromeT();
|
|
36
|
+
const [opened, setOpened] = useState<StructureSourceInput | null>(null);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<ActionTooltip
|
|
41
|
+
content={t('structure.export.open')}
|
|
42
|
+
placement="left"
|
|
43
|
+
opened={opened !== null}
|
|
44
|
+
>
|
|
45
|
+
<Button
|
|
46
|
+
variant="minimal"
|
|
47
|
+
size="small"
|
|
48
|
+
icon="export"
|
|
49
|
+
disabled={empty}
|
|
50
|
+
aria-label={t('structure.export.open')}
|
|
51
|
+
onClick={() => setOpened(source())}
|
|
52
|
+
/>
|
|
53
|
+
</ActionTooltip>
|
|
54
|
+
<StructureExportDialog
|
|
55
|
+
{...opened}
|
|
56
|
+
isOpen={opened !== null}
|
|
57
|
+
fragment={fragment}
|
|
58
|
+
onClose={() => setOpened(null)}
|
|
59
|
+
/>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Button, PopoverNext
|
|
2
|
-
import type {
|
|
1
|
+
import { Button, PopoverNext } from '@blueprintjs/core';
|
|
2
|
+
import type { ReactElement, RefObject } from 'react';
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
|
|
6
7
|
|
|
7
8
|
import { StructureEditorHelp } from './StructureEditorHelp.tsx';
|
|
8
9
|
import type { StructureEditorMode } from './editorChange.ts';
|
|
@@ -18,8 +19,11 @@ export interface EditorHelpButtonProps {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
|
-
* The editor's help button,
|
|
22
|
-
*
|
|
22
|
+
* The editor's help button, opening the guide to the mouse and the keyboard.
|
|
23
|
+
*
|
|
24
|
+
* It is placed by whoever renders it — the editor puts it in the corner of the
|
|
25
|
+
* drawing, next to the export button — so the two read as one group rather
|
|
26
|
+
* than as two controls that happen to overlap.
|
|
23
27
|
*
|
|
24
28
|
* F1 opens it too: openchemlib binds that key to a help dialog it does not
|
|
25
29
|
* implement on the web.
|
|
@@ -44,32 +48,24 @@ export function EditorHelpButton(props: EditorHelpButtonProps): ReactElement {
|
|
|
44
48
|
}, [containerRef]);
|
|
45
49
|
|
|
46
50
|
return (
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
<PopoverNext
|
|
52
|
+
isOpen={isOpen}
|
|
53
|
+
onInteraction={setIsOpen}
|
|
54
|
+
placement="left-start"
|
|
55
|
+
content={<StructureEditorHelp mode={mode} fragment={fragment} />}
|
|
56
|
+
>
|
|
57
|
+
<ActionTooltip
|
|
58
|
+
content={t('structure.mouseAndKeyboard')}
|
|
59
|
+
placement="left"
|
|
60
|
+
opened={isOpen}
|
|
53
61
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
icon="help"
|
|
63
|
-
aria-label={t('structure.mouseAndKeyboard')}
|
|
64
|
-
/>
|
|
65
|
-
</Tooltip>
|
|
66
|
-
</PopoverNext>
|
|
67
|
-
</div>
|
|
62
|
+
<Button
|
|
63
|
+
variant="minimal"
|
|
64
|
+
size="small"
|
|
65
|
+
icon="help"
|
|
66
|
+
aria-label={t('structure.mouseAndKeyboard')}
|
|
67
|
+
/>
|
|
68
|
+
</ActionTooltip>
|
|
69
|
+
</PopoverNext>
|
|
68
70
|
);
|
|
69
71
|
}
|
|
70
|
-
|
|
71
|
-
const CORNER_STYLE: CSSProperties = {
|
|
72
|
-
position: 'absolute',
|
|
73
|
-
top: 4,
|
|
74
|
-
right: 4,
|
|
75
|
-
};
|
|
@@ -28,8 +28,14 @@ import type {
|
|
|
28
28
|
StructureEditorChange,
|
|
29
29
|
StructureEditorMode,
|
|
30
30
|
} from './editorChange.ts';
|
|
31
|
+
import { useEditorStructure } from './useEditorStructure.ts';
|
|
31
32
|
import { useToolbarFloor } from './useToolbarFloor.ts';
|
|
32
33
|
|
|
34
|
+
const EditorExportButton = lazy(async () => {
|
|
35
|
+
const module = await import('./EditorExportButton.tsx');
|
|
36
|
+
return { default: module.EditorExportButton };
|
|
37
|
+
});
|
|
38
|
+
|
|
33
39
|
const EditorCanvas = lazy(async () => {
|
|
34
40
|
const module = await import('./EditorCanvas.tsx');
|
|
35
41
|
return { default: module.EditorCanvas };
|
|
@@ -93,6 +99,14 @@ export interface StructureEditorProps {
|
|
|
93
99
|
* @default true
|
|
94
100
|
*/
|
|
95
101
|
help?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Put a button in the corner that opens every notation of the drawing — its
|
|
104
|
+
* SMILES, its molfiles, its canonical identifiers — and the picture of it,
|
|
105
|
+
* ready to copy or to save. A reaction has none of those, so it is never
|
|
106
|
+
* offered one.
|
|
107
|
+
* @default true
|
|
108
|
+
*/
|
|
109
|
+
exportable?: boolean;
|
|
96
110
|
/**
|
|
97
111
|
* Class the container carries, so a site can reach it from its stylesheet.
|
|
98
112
|
* @default undefined
|
|
@@ -123,6 +137,7 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
123
137
|
minHeight = 320,
|
|
124
138
|
mode = 'molecule',
|
|
125
139
|
help = true,
|
|
140
|
+
exportable = true,
|
|
126
141
|
className,
|
|
127
142
|
style,
|
|
128
143
|
} = props;
|
|
@@ -130,6 +145,16 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
130
145
|
const t = useChromeT();
|
|
131
146
|
const containerRef = useToolbarFloor({ minHeight, revision });
|
|
132
147
|
const handleChange = useDebounced(onChange, debounce, revision);
|
|
148
|
+
const drawing = useEditorStructure({ value, inputFormat, revision });
|
|
149
|
+
const handleEdit = useCallback(
|
|
150
|
+
(change: StructureEditorChange) => {
|
|
151
|
+
// Tapped undebounced, so a button beside the canvas reads the structure
|
|
152
|
+
// as it stands rather than as it stood before the last burst.
|
|
153
|
+
drawing.track(change);
|
|
154
|
+
handleChange(change);
|
|
155
|
+
},
|
|
156
|
+
[drawing, handleChange],
|
|
157
|
+
);
|
|
133
158
|
|
|
134
159
|
return (
|
|
135
160
|
<div
|
|
@@ -144,22 +169,31 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
144
169
|
>
|
|
145
170
|
<EditorCanvas
|
|
146
171
|
key={revision}
|
|
147
|
-
onChange={
|
|
172
|
+
onChange={handleEdit}
|
|
148
173
|
fragment={fragment}
|
|
149
174
|
inputFormat={inputFormat}
|
|
150
175
|
value={value}
|
|
151
176
|
mode={mode}
|
|
152
177
|
/>
|
|
153
178
|
{help ? (
|
|
154
|
-
|
|
155
|
-
|
|
179
|
+
<ToolbarTooltip containerRef={containerRef} mode={mode} />
|
|
180
|
+
) : null}
|
|
181
|
+
<div style={CORNER_STYLE}>
|
|
182
|
+
{exportable && mode === 'molecule' ? (
|
|
183
|
+
<EditorExportButton
|
|
184
|
+
source={drawing.source}
|
|
185
|
+
fragment={fragment}
|
|
186
|
+
empty={drawing.empty}
|
|
187
|
+
/>
|
|
188
|
+
) : null}
|
|
189
|
+
{help ? (
|
|
156
190
|
<EditorHelpButton
|
|
157
191
|
containerRef={containerRef}
|
|
158
192
|
mode={mode}
|
|
159
193
|
fragment={fragment}
|
|
160
194
|
/>
|
|
161
|
-
|
|
162
|
-
|
|
195
|
+
) : null}
|
|
196
|
+
</div>
|
|
163
197
|
</Suspense>
|
|
164
198
|
</div>
|
|
165
199
|
);
|
|
@@ -217,6 +251,18 @@ const ROOT_STYLE: CSSProperties = {
|
|
|
217
251
|
background: '#fff',
|
|
218
252
|
};
|
|
219
253
|
|
|
254
|
+
/**
|
|
255
|
+
* The corner the editor's own buttons sit in: export first, then help, so the
|
|
256
|
+
* one that does something to the drawing is the nearer of the two to it.
|
|
257
|
+
*/
|
|
258
|
+
const CORNER_STYLE: CSSProperties = {
|
|
259
|
+
position: 'absolute',
|
|
260
|
+
top: 4,
|
|
261
|
+
right: 4,
|
|
262
|
+
display: 'flex',
|
|
263
|
+
gap: 2,
|
|
264
|
+
};
|
|
265
|
+
|
|
220
266
|
/** The box the canvas will fill, so its arrival moves nothing. */
|
|
221
267
|
const LOADING_STYLE: CSSProperties = {
|
|
222
268
|
position: 'absolute',
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The dialog that hands a drawn structure over.
|
|
3
|
+
*
|
|
4
|
+
* The shell is here and the body is behind `React.lazy`, for the same reason
|
|
5
|
+
* `Structure` keeps its depiction there: this file must stay free of
|
|
6
|
+
* `openchemlib` so a site importing `react-cheminfo/structure` for the editor
|
|
7
|
+
* does not also download the notations nobody has asked for yet.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Dialog, DialogBody } from '@blueprintjs/core';
|
|
11
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
12
|
+
import { Suspense, lazy } from 'react';
|
|
13
|
+
|
|
14
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
15
|
+
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
16
|
+
|
|
17
|
+
import type { StructureExportPanelProps } from './StructureExportPanel.tsx';
|
|
18
|
+
|
|
19
|
+
const StructureExportPanel = lazy(async () => {
|
|
20
|
+
const module = await import('./StructureExportPanel.tsx');
|
|
21
|
+
return { default: module.StructureExportPanel };
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** What {@link StructureExportDialog} needs. */
|
|
25
|
+
export interface StructureExportDialogProps extends StructureExportPanelProps {
|
|
26
|
+
/** Whether the dialog is on screen. */
|
|
27
|
+
isOpen: boolean;
|
|
28
|
+
/** Called when the dialog is dismissed. */
|
|
29
|
+
onClose: () => void;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the dialog is rendered through a portal on `document.body`.
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
usePortal?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Take a structure off the page: as a notation, or as a picture.
|
|
39
|
+
*
|
|
40
|
+
* One dialog rather than a menu of downloads, because the question is never
|
|
41
|
+
* only "which format" — a reader comparing a SMILES against an idCode, or
|
|
42
|
+
* checking that the hash they are about to paste belongs to the molecule in
|
|
43
|
+
* front of them, needs to see the structure and the strings together.
|
|
44
|
+
* @param props - See {@link StructureExportDialogProps}.
|
|
45
|
+
* @returns The dialog.
|
|
46
|
+
*/
|
|
47
|
+
export function StructureExportDialog(
|
|
48
|
+
props: StructureExportDialogProps,
|
|
49
|
+
): ReactElement {
|
|
50
|
+
const { isOpen, onClose, usePortal = true, ...panel } = props;
|
|
51
|
+
const t = useChromeT();
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Dialog
|
|
55
|
+
isOpen={isOpen}
|
|
56
|
+
onClose={onClose}
|
|
57
|
+
usePortal={usePortal}
|
|
58
|
+
title={t('structure.export.title')}
|
|
59
|
+
icon="export"
|
|
60
|
+
className="structure-export"
|
|
61
|
+
style={DIALOG_STYLE}
|
|
62
|
+
>
|
|
63
|
+
<DialogBody className="structure-export__body">
|
|
64
|
+
{/* Mounted with the body, so the notations are written from the
|
|
65
|
+
structure as it stands each time the dialog is opened. */}
|
|
66
|
+
{isOpen ? (
|
|
67
|
+
<Suspense
|
|
68
|
+
fallback={
|
|
69
|
+
<p style={LOADING_STYLE}>{t('structure.export.loading')}</p>
|
|
70
|
+
}
|
|
71
|
+
>
|
|
72
|
+
<StructureExportPanel {...panel} />
|
|
73
|
+
</Suspense>
|
|
74
|
+
) : null}
|
|
75
|
+
</DialogBody>
|
|
76
|
+
</Dialog>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const DIALOG_STYLE = {
|
|
81
|
+
width: 'min(980px, 94vw)',
|
|
82
|
+
} as const satisfies CSSProperties;
|
|
83
|
+
|
|
84
|
+
const LOADING_STYLE = {
|
|
85
|
+
margin: 0,
|
|
86
|
+
padding: '2rem 0',
|
|
87
|
+
color: TOKEN.textFaint,
|
|
88
|
+
fontSize: 13,
|
|
89
|
+
textAlign: 'center',
|
|
90
|
+
} as const satisfies CSSProperties;
|