react-cheminfo 0.66.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -11
- package/lib/download/ui/FigureDownloadPanel.d.ts +7 -1
- package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
- package/lib/download/ui/FigureDownloadPanel.js +2 -2
- package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
- package/lib/ecosystem/core/sites.js +3 -3
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/core/types.d.ts +1 -1
- package/lib/ecosystem/core/types.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +1 -1
- package/lib/ecosystem/ui/glyphs.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/i18n/core/messageCatalog.d.ts +2 -2
- package/lib/i18n/vite/localeCatalog.d.ts +1 -1
- package/lib/ir/core/index.d.ts +2 -2
- package/lib/ir/core/index.d.ts.map +1 -1
- package/lib/ir/core/index.js.map +1 -1
- package/lib/ir/core/irEditorApi.d.ts +12 -0
- package/lib/ir/core/irEditorApi.d.ts.map +1 -1
- package/lib/ir/core/irReducer.d.ts +2 -2
- package/lib/ir/core/irReducer.d.ts.map +1 -1
- package/lib/ir/core/irSidePanels.d.ts +7 -1
- package/lib/ir/core/irSidePanels.d.ts.map +1 -1
- package/lib/ir/core/irState.d.ts +8 -5
- package/lib/ir/core/irState.d.ts.map +1 -1
- package/lib/ir/core/irState.js.map +1 -1
- package/lib/ir/ui/IrCanvas.d.ts +7 -0
- package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
- package/lib/ir/ui/IrCanvas.js +8 -3
- package/lib/ir/ui/IrCanvas.js.map +1 -1
- package/lib/ir/ui/IrChart.d.ts.map +1 -1
- package/lib/ir/ui/IrChart.js +5 -1
- package/lib/ir/ui/IrChart.js.map +1 -1
- package/lib/ir/ui/IrEditor.d.ts +22 -4
- package/lib/ir/ui/IrEditor.d.ts.map +1 -1
- package/lib/ir/ui/IrEditor.js.map +1 -1
- package/lib/ir/ui/IrShell.d.ts +9 -1
- package/lib/ir/ui/IrShell.d.ts.map +1 -1
- package/lib/ir/ui/IrShell.js +4 -19
- package/lib/ir/ui/IrShell.js.map +1 -1
- package/lib/ir/ui/IrSidePanel.d.ts +11 -0
- package/lib/ir/ui/IrSidePanel.d.ts.map +1 -1
- package/lib/ir/ui/IrSidePanel.js +12 -3
- package/lib/ir/ui/IrSidePanel.js.map +1 -1
- package/lib/ir/ui/RamanEditor.d.ts +22 -4
- package/lib/ir/ui/RamanEditor.d.ts.map +1 -1
- package/lib/ir/ui/RamanEditor.js.map +1 -1
- package/lib/ir/ui/VibrationalEditor.d.ts +18 -4
- package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -1
- package/lib/ir/ui/VibrationalEditor.js +4 -2
- package/lib/ir/ui/VibrationalEditor.js.map +1 -1
- package/lib/ir/ui/index.d.ts +1 -0
- package/lib/ir/ui/index.d.ts.map +1 -1
- package/lib/ir/ui/index.js.map +1 -1
- package/lib/ir/ui/irActions.d.ts +3 -3
- package/lib/ir/ui/irActions.d.ts.map +1 -1
- package/lib/ir/ui/irChartProps.d.ts +7 -0
- package/lib/ir/ui/irChartProps.d.ts.map +1 -1
- package/lib/ir/ui/irHostPanels.d.ts +53 -0
- package/lib/ir/ui/irHostPanels.d.ts.map +1 -0
- package/lib/ir/ui/irHostPanels.js +41 -0
- package/lib/ir/ui/irHostPanels.js.map +1 -0
- package/lib/ir/ui/useIrSide.d.ts +27 -0
- package/lib/ir/ui/useIrSide.d.ts.map +1 -0
- package/lib/ir/ui/useIrSide.js +42 -0
- package/lib/ir/ui/useIrSide.js.map +1 -0
- package/lib/ir/ui/useIrZoom.d.ts +8 -0
- package/lib/ir/ui/useIrZoom.d.ts.map +1 -1
- package/lib/ir/ui/useIrZoom.js +2 -1
- package/lib/ir/ui/useIrZoom.js.map +1 -1
- package/lib/locales/de.json +9 -1
- package/lib/locales/en.json +9 -1
- package/lib/locales/es.json +9 -1
- package/lib/locales/fr.json +9 -1
- package/lib/locales/it.json +9 -1
- package/lib/molecule3d/core/animatedPng.d.ts +25 -0
- package/lib/molecule3d/core/animatedPng.d.ts.map +1 -0
- package/lib/molecule3d/core/animatedPng.js +59 -0
- package/lib/molecule3d/core/animatedPng.js.map +1 -0
- package/lib/molecule3d/core/file.d.ts +24 -0
- package/lib/molecule3d/core/file.d.ts.map +1 -0
- package/lib/molecule3d/core/file.js +2 -0
- package/lib/molecule3d/core/file.js.map +1 -0
- package/lib/molecule3d/core/index.d.ts +4 -1
- package/lib/molecule3d/core/index.d.ts.map +1 -1
- package/lib/molecule3d/core/index.js +1 -0
- package/lib/molecule3d/core/index.js.map +1 -1
- package/lib/molecule3d/core/settings.d.ts +0 -7
- package/lib/molecule3d/core/settings.d.ts.map +1 -1
- package/lib/molecule3d/core/settings.js.map +1 -1
- package/lib/molecule3d/ui/Molecule3DExport.d.ts +10 -2
- package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
- package/lib/molecule3d/ui/Molecule3DExport.js +15 -2
- package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
- package/lib/molecule3d/ui/Molecule3DToolbar.js +9 -2
- package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.js +23 -41
- package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
- package/lib/molecule3d/ui/drawScene.d.ts +2 -1
- package/lib/molecule3d/ui/drawScene.d.ts.map +1 -1
- package/lib/molecule3d/ui/drawScene.js.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts +15 -1
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.js +14 -2
- package/lib/molecule3d/ui/exportMoleculeImage.js.map +1 -1
- package/lib/molecule3d/ui/moleculeFrames.d.ts +47 -0
- package/lib/molecule3d/ui/moleculeFrames.d.ts.map +1 -0
- package/lib/molecule3d/ui/moleculeFrames.js +65 -0
- package/lib/molecule3d/ui/moleculeFrames.js.map +1 -0
- package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +14 -1
- package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
- package/lib/molecule3d/ui/renderMolecule.d.ts +3 -3
- package/lib/molecule3d/ui/renderMolecule.d.ts.map +1 -1
- package/lib/molecule3d/ui/renderMolecule.js +2 -1
- package/lib/molecule3d/ui/renderMolecule.js.map +1 -1
- package/lib/molecule3d/ui/sceneDrawer.d.ts +2 -1
- package/lib/molecule3d/ui/sceneDrawer.d.ts.map +1 -1
- package/lib/molecule3d/ui/sceneDrawer.js +9 -1
- package/lib/molecule3d/ui/sceneDrawer.js.map +1 -1
- package/lib/molecule3d/ui/useImageExport.d.ts +8 -3
- package/lib/molecule3d/ui/useImageExport.d.ts.map +1 -1
- package/lib/molecule3d/ui/useImageExport.js +13 -4
- package/lib/molecule3d/ui/useImageExport.js.map +1 -1
- package/lib/molecule3d/ui/useMoleculeScene.d.ts +2 -1
- package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -1
- package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -1
- package/lib/molecule3d/ui/useMoleculeViewer.d.ts +16 -0
- package/lib/molecule3d/ui/useMoleculeViewer.d.ts.map +1 -0
- package/lib/molecule3d/ui/useMoleculeViewer.js +37 -0
- package/lib/molecule3d/ui/useMoleculeViewer.js.map +1 -0
- package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts +3 -3
- package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts.map +1 -1
- package/lib/molecule3d/ui/usePolarSurfaceArea.js +4 -3
- package/lib/molecule3d/ui/usePolarSurfaceArea.js.map +1 -1
- package/lib/molecule3d/ui/viewer.d.ts +4 -1
- package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
- package/lib/molecule3d/ui/viewer.js +21 -19
- package/lib/molecule3d/ui/viewer.js.map +1 -1
- package/lib/molecule3d/ui/viewerTypes.d.ts +6 -0
- package/lib/molecule3d/ui/viewerTypes.d.ts.map +1 -1
- package/lib/molstar/core/captureScene.d.ts +19 -1
- package/lib/molstar/core/captureScene.d.ts.map +1 -1
- package/lib/molstar/core/captureScene.js +57 -2
- package/lib/molstar/core/captureScene.js.map +1 -1
- package/lib/molstar/core/index.d.ts +5 -2
- package/lib/molstar/core/index.d.ts.map +1 -1
- package/lib/molstar/core/index.js +4 -2
- package/lib/molstar/core/index.js.map +1 -1
- package/lib/molstar/core/trajectory.d.ts +56 -0
- package/lib/molstar/core/trajectory.d.ts.map +1 -0
- package/lib/molstar/core/trajectory.js +96 -0
- package/lib/molstar/core/trajectory.js.map +1 -0
- package/lib/panel/ui/PanelRail.d.ts.map +1 -1
- package/lib/panel/ui/PanelRail.js +1 -1
- package/lib/panel/ui/PanelRail.js.map +1 -1
- package/lib/raman.d.ts +2 -1
- package/lib/raman.d.ts.map +1 -1
- package/lib/raman.js.map +1 -1
- package/lib/router/core/basePath.d.ts +2 -2
- package/lib/router/core/basePath.js +2 -2
- package/lib/router/core/siteAddresses.d.ts +1 -1
- package/lib/router/core/siteAddresses.js +1 -1
- package/lib/seo/core/siteFiles.js +1 -1
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/server/answerAddresses.d.ts +3 -3
- package/lib/server/answerAddresses.js +3 -3
- 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/structureTransfer.d.ts +29 -0
- package/lib/structure/core/structureTransfer.d.ts.map +1 -0
- package/lib/structure/core/structureTransfer.js +26 -0
- package/lib/structure/core/structureTransfer.js.map +1 -0
- package/lib/structure/ui/EditorImportButton.d.ts +20 -0
- package/lib/structure/ui/EditorImportButton.d.ts.map +1 -0
- package/lib/structure/ui/EditorImportButton.js +24 -0
- package/lib/structure/ui/EditorImportButton.js.map +1 -0
- package/lib/structure/ui/EditorImportProblem.d.ts +17 -0
- package/lib/structure/ui/EditorImportProblem.d.ts.map +1 -0
- package/lib/structure/ui/EditorImportProblem.js +32 -0
- package/lib/structure/ui/EditorImportProblem.js.map +1 -0
- package/lib/structure/ui/StructureDrop.d.ts +39 -0
- package/lib/structure/ui/StructureDrop.d.ts.map +1 -0
- package/lib/structure/ui/StructureDrop.js +19 -0
- package/lib/structure/ui/StructureDrop.js.map +1 -0
- package/lib/structure/ui/StructureDropOverlay.d.ts +16 -0
- package/lib/structure/ui/StructureDropOverlay.d.ts.map +1 -0
- package/lib/structure/ui/StructureDropOverlay.js +29 -0
- package/lib/structure/ui/StructureDropOverlay.js.map +1 -0
- package/lib/structure/ui/StructureEditor.d.ts +3 -80
- package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
- package/lib/structure/ui/StructureEditor.js +21 -33
- package/lib/structure/ui/StructureEditor.js.map +1 -1
- package/lib/structure/ui/importedStructure.d.ts +25 -0
- package/lib/structure/ui/importedStructure.d.ts.map +1 -0
- package/lib/structure/ui/importedStructure.js +74 -0
- package/lib/structure/ui/importedStructure.js.map +1 -0
- package/lib/structure/ui/index.d.ts +2 -0
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js +1 -0
- package/lib/structure/ui/index.js.map +1 -1
- package/lib/structure/ui/structureEditorProps.d.ts +98 -0
- package/lib/structure/ui/structureEditorProps.d.ts.map +1 -0
- package/lib/structure/ui/structureEditorProps.js +2 -0
- package/lib/structure/ui/structureEditorProps.js.map +1 -0
- package/lib/structure/ui/useDebouncedChange.d.ts +16 -0
- package/lib/structure/ui/useDebouncedChange.d.ts.map +1 -0
- package/lib/structure/ui/useDebouncedChange.js +30 -0
- package/lib/structure/ui/useDebouncedChange.js.map +1 -0
- package/lib/structure/ui/useStructureDrop.d.ts +30 -0
- package/lib/structure/ui/useStructureDrop.d.ts.map +1 -0
- package/lib/structure/ui/useStructureDrop.js +49 -0
- package/lib/structure/ui/useStructureDrop.js.map +1 -0
- package/lib/structure/ui/useStructureImport.d.ts +45 -0
- package/lib/structure/ui/useStructureImport.d.ts.map +1 -0
- package/lib/structure/ui/useStructureImport.js +62 -0
- package/lib/structure/ui/useStructureImport.js.map +1 -0
- package/package.json +4 -1
- package/src/download/ui/FigureDownloadPanel.tsx +9 -2
- package/src/ecosystem/core/sites.ts +3 -3
- package/src/ecosystem/core/types.ts +1 -1
- package/src/ecosystem/ui/glyphs.tsx +1 -1
- package/src/i18n/core/messageCatalog.ts +2 -2
- package/src/i18n/vite/localeCatalog.ts +1 -1
- package/src/ir/core/index.ts +6 -2
- package/src/ir/core/irEditorApi.ts +13 -0
- package/src/ir/core/irReducer.ts +2 -2
- package/src/ir/core/irSidePanels.ts +8 -1
- package/src/ir/core/irState.ts +8 -5
- package/src/ir/ui/IrCanvas.tsx +27 -2
- package/src/ir/ui/IrChart.tsx +11 -0
- package/src/ir/ui/IrEditor.tsx +22 -4
- package/src/ir/ui/IrShell.tsx +21 -22
- package/src/ir/ui/IrSidePanel.tsx +36 -10
- package/src/ir/ui/RamanEditor.tsx +22 -4
- package/src/ir/ui/VibrationalEditor.tsx +24 -5
- package/src/ir/ui/index.ts +1 -0
- package/src/ir/ui/irActions.ts +3 -3
- package/src/ir/ui/irChartProps.ts +7 -0
- package/src/ir/ui/irHostPanels.ts +76 -0
- package/src/ir/ui/useIrSide.ts +60 -0
- package/src/ir/ui/useIrZoom.ts +10 -0
- package/src/locales/de.json +9 -1
- package/src/locales/en.json +9 -1
- package/src/locales/es.json +9 -1
- package/src/locales/fr.json +9 -1
- package/src/locales/it.json +9 -1
- package/src/molecule3d/core/animatedPng.ts +79 -0
- package/src/molecule3d/core/file.ts +23 -0
- package/src/molecule3d/core/index.ts +3 -1
- package/src/molecule3d/core/settings.ts +0 -8
- package/src/molecule3d/ui/Molecule3DExport.tsx +43 -5
- package/src/molecule3d/ui/Molecule3DToolbar.tsx +9 -2
- package/src/molecule3d/ui/MoleculeCanvas3D.tsx +24 -38
- package/src/molecule3d/ui/drawScene.ts +2 -1
- package/src/molecule3d/ui/exportMoleculeImage.ts +28 -3
- package/src/molecule3d/ui/moleculeFrames.ts +88 -0
- package/src/molecule3d/ui/moleculeViewer3DProps.ts +14 -5
- package/src/molecule3d/ui/renderMolecule.ts +5 -3
- package/src/molecule3d/ui/sceneDrawer.ts +14 -2
- package/src/molecule3d/ui/useImageExport.ts +22 -5
- package/src/molecule3d/ui/useMoleculeScene.ts +2 -1
- package/src/molecule3d/ui/useMoleculeViewer.ts +46 -0
- package/src/molecule3d/ui/usePolarSurfaceArea.ts +6 -4
- package/src/molecule3d/ui/viewer.ts +34 -27
- package/src/molecule3d/ui/viewerTypes.ts +6 -0
- package/src/molstar/core/captureScene.ts +85 -2
- package/src/molstar/core/index.ts +13 -2
- package/src/molstar/core/trajectory.ts +117 -0
- package/src/panel/ui/PanelRail.tsx +3 -0
- package/src/raman.ts +2 -1
- package/src/router/core/basePath.ts +2 -2
- package/src/router/core/siteAddresses.ts +1 -1
- package/src/seo/core/siteFiles.ts +1 -1
- package/src/server/answerAddresses.ts +3 -3
- package/src/structure/core/index.ts +8 -0
- package/src/structure/core/structureTransfer.ts +37 -0
- package/src/structure/ui/EditorImportButton.tsx +59 -0
- package/src/structure/ui/EditorImportProblem.tsx +63 -0
- package/src/structure/ui/StructureDrop.tsx +66 -0
- package/src/structure/ui/StructureDropOverlay.tsx +50 -0
- package/src/structure/ui/StructureEditor.tsx +49 -134
- package/src/structure/ui/importedStructure.ts +83 -0
- package/src/structure/ui/index.ts +2 -0
- package/src/structure/ui/structureEditorProps.ts +103 -0
- package/src/structure/ui/useDebouncedChange.ts +41 -0
- package/src/structure/ui/useStructureDrop.ts +76 -0
- package/src/structure/ui/useStructureImport.ts +122 -0
|
@@ -8,29 +8,26 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { CSSProperties, ReactElement } from 'react';
|
|
11
|
-
import {
|
|
12
|
-
Suspense,
|
|
13
|
-
lazy,
|
|
14
|
-
useCallback,
|
|
15
|
-
useEffect,
|
|
16
|
-
useRef,
|
|
17
|
-
useState,
|
|
18
|
-
} from 'react';
|
|
19
|
-
import type { CanvasEditorInputFormat } from 'react-ocl';
|
|
11
|
+
import { Suspense, lazy, useCallback } from 'react';
|
|
20
12
|
|
|
21
13
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
22
14
|
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
23
|
-
import { createPendingCall } from '../core/pendingCall.ts';
|
|
24
15
|
|
|
25
16
|
import { EditorHelpButton } from './EditorHelpButton.tsx';
|
|
17
|
+
import { EditorImportButton } from './EditorImportButton.tsx';
|
|
18
|
+
import { EditorImportProblem } from './EditorImportProblem.tsx';
|
|
19
|
+
import { StructureDropOverlay } from './StructureDropOverlay.tsx';
|
|
26
20
|
import { ToolbarTooltip } from './ToolbarTooltip.tsx';
|
|
27
|
-
import type {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} from './editorChange.ts';
|
|
21
|
+
import type { StructureEditorChange } from './editorChange.ts';
|
|
22
|
+
import type { StructureEditorProps } from './structureEditorProps.ts';
|
|
23
|
+
import { useDebouncedChange } from './useDebouncedChange.ts';
|
|
31
24
|
import { useEditorStructure } from './useEditorStructure.ts';
|
|
25
|
+
import { useStructureDrop } from './useStructureDrop.ts';
|
|
26
|
+
import { useStructureImport } from './useStructureImport.ts';
|
|
32
27
|
import { useToolbarFloor } from './useToolbarFloor.ts';
|
|
33
28
|
|
|
29
|
+
export type { StructureEditorProps } from './structureEditorProps.ts';
|
|
30
|
+
|
|
34
31
|
const EditorExportButton = lazy(async () => {
|
|
35
32
|
const module = await import('./EditorExportButton.tsx');
|
|
36
33
|
return { default: module.EditorExportButton };
|
|
@@ -41,84 +38,6 @@ const EditorCanvas = lazy(async () => {
|
|
|
41
38
|
return { default: module.EditorCanvas };
|
|
42
39
|
});
|
|
43
40
|
|
|
44
|
-
/** What {@link StructureEditor} needs. */
|
|
45
|
-
export interface StructureEditorProps {
|
|
46
|
-
/**
|
|
47
|
-
* Called after every edit, once the drawing has been still for `debounce`
|
|
48
|
-
* milliseconds, with every notation read out of the editor.
|
|
49
|
-
*/
|
|
50
|
-
onChange: (change: StructureEditorChange) => void;
|
|
51
|
-
/**
|
|
52
|
-
* Draw a query fragment rather than a whole structure, which is what a
|
|
53
|
-
* substructure filter needs.
|
|
54
|
-
* @default false
|
|
55
|
-
*/
|
|
56
|
-
fragment?: boolean;
|
|
57
|
-
/**
|
|
58
|
-
* How `value` is written.
|
|
59
|
-
* @default 'idcode'
|
|
60
|
-
*/
|
|
61
|
-
inputFormat?: CanvasEditorInputFormat;
|
|
62
|
-
/**
|
|
63
|
-
* What the canvas holds. Read once, when the editor appears and again on
|
|
64
|
-
* every change of `revision`: the editor is uncontrolled, so feeding the
|
|
65
|
-
* drawing back into it would replace the structure and reset every
|
|
66
|
-
* coordinate under the pen.
|
|
67
|
-
* @default ''
|
|
68
|
-
*/
|
|
69
|
-
value?: string;
|
|
70
|
-
/**
|
|
71
|
-
* Bumped by the caller to load `value` into the canvas again, which is what
|
|
72
|
-
* an example, a share link or a Clear button does. Changing it discards
|
|
73
|
-
* whatever was being drawn.
|
|
74
|
-
* @default 0
|
|
75
|
-
*/
|
|
76
|
-
revision?: number;
|
|
77
|
-
/**
|
|
78
|
-
* How long the drawing has to be still before `onChange` is called, in
|
|
79
|
-
* milliseconds. Long enough that drawing a ring does not publish six
|
|
80
|
-
* structures; `0` reports every stroke.
|
|
81
|
-
* @default 300
|
|
82
|
-
*/
|
|
83
|
-
debounce?: number;
|
|
84
|
-
/**
|
|
85
|
-
* Smallest height of the drawing area, in pixels. Raised to whatever the
|
|
86
|
-
* toolbar needs, which is usually more.
|
|
87
|
-
* @default 320
|
|
88
|
-
*/
|
|
89
|
-
minHeight?: number;
|
|
90
|
-
/**
|
|
91
|
-
* Whether the editor draws one structure or a reaction. A reaction canvas
|
|
92
|
-
* has its own toolbar and its own arrow.
|
|
93
|
-
* @default 'molecule'
|
|
94
|
-
*/
|
|
95
|
-
mode?: StructureEditorMode;
|
|
96
|
-
/**
|
|
97
|
-
* Explain each toolbar button in a tooltip, and put a button in the corner
|
|
98
|
-
* that opens a guide to the mouse and the keyboard, which F1 opens too.
|
|
99
|
-
* @default true
|
|
100
|
-
*/
|
|
101
|
-
help?: boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Put a button in the corner that opens every notation of the drawing — its
|
|
104
|
-
* SMILES, its molfiles, its canonical identifiers — and the picture of it,
|
|
105
|
-
* ready to copy or to save. A reaction has none of those, so it is never
|
|
106
|
-
* offered one.
|
|
107
|
-
* @default true
|
|
108
|
-
*/
|
|
109
|
-
exportable?: boolean;
|
|
110
|
-
/**
|
|
111
|
-
* Class the container carries, so a site can reach it from its stylesheet.
|
|
112
|
-
* @default undefined
|
|
113
|
-
*/
|
|
114
|
-
className?: string;
|
|
115
|
-
/**
|
|
116
|
-
* Extra style for the container, merged over the packaged one.
|
|
117
|
-
* @default undefined
|
|
118
|
-
*/
|
|
119
|
-
style?: CSSProperties;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
41
|
/**
|
|
123
42
|
* The canvas structure editor, sized to fill its container and never to hide
|
|
124
43
|
* part of its toolbar, with a tooltip on every toolbar button and a guide to
|
|
@@ -138,13 +57,15 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
138
57
|
mode = 'molecule',
|
|
139
58
|
help = true,
|
|
140
59
|
exportable = true,
|
|
60
|
+
importable = true,
|
|
61
|
+
onImport,
|
|
141
62
|
className,
|
|
142
63
|
style,
|
|
143
64
|
} = props;
|
|
144
65
|
|
|
145
66
|
const t = useChromeT();
|
|
146
67
|
const containerRef = useToolbarFloor({ minHeight, revision });
|
|
147
|
-
const handleChange =
|
|
68
|
+
const handleChange = useDebouncedChange(onChange, debounce, revision);
|
|
148
69
|
const drawing = useEditorStructure({ value, inputFormat, revision });
|
|
149
70
|
const handleEdit = useCallback(
|
|
150
71
|
(change: StructureEditorChange) => {
|
|
@@ -155,12 +76,21 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
155
76
|
},
|
|
156
77
|
[drawing, handleChange],
|
|
157
78
|
);
|
|
79
|
+
const imports = useStructureImport({
|
|
80
|
+
revision,
|
|
81
|
+
fragment,
|
|
82
|
+
onImport,
|
|
83
|
+
onRead: handleEdit,
|
|
84
|
+
});
|
|
85
|
+
const takesImports = importable && mode === 'molecule';
|
|
86
|
+
const drop = useStructureDrop(takesImports ? imports.load : undefined);
|
|
158
87
|
|
|
159
88
|
return (
|
|
160
89
|
<div
|
|
161
90
|
ref={containerRef}
|
|
162
91
|
className={className}
|
|
163
92
|
style={{ ...ROOT_STYLE, minHeight, ...style }}
|
|
93
|
+
{...drop.targetProps}
|
|
164
94
|
>
|
|
165
95
|
<Suspense
|
|
166
96
|
fallback={
|
|
@@ -168,17 +98,23 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
168
98
|
}
|
|
169
99
|
>
|
|
170
100
|
<EditorCanvas
|
|
171
|
-
key={
|
|
101
|
+
key={imports.canvasKey}
|
|
172
102
|
onChange={handleEdit}
|
|
173
103
|
fragment={fragment}
|
|
174
|
-
inputFormat={inputFormat}
|
|
175
|
-
value={value}
|
|
104
|
+
inputFormat={imports.idCode === null ? inputFormat : 'idcode'}
|
|
105
|
+
value={imports.idCode ?? value}
|
|
176
106
|
mode={mode}
|
|
177
107
|
/>
|
|
178
108
|
{help ? (
|
|
179
109
|
<ToolbarTooltip containerRef={containerRef} mode={mode} />
|
|
180
110
|
) : null}
|
|
181
111
|
<div style={CORNER_STYLE}>
|
|
112
|
+
{takesImports ? (
|
|
113
|
+
<EditorImportButton
|
|
114
|
+
onImport={imports.load}
|
|
115
|
+
accept={onImport === undefined ? STRUCTURE_FILES : undefined}
|
|
116
|
+
/>
|
|
117
|
+
) : null}
|
|
182
118
|
{exportable && mode === 'molecule' ? (
|
|
183
119
|
<EditorExportButton
|
|
184
120
|
source={drawing.source}
|
|
@@ -194,47 +130,23 @@ export function StructureEditor(props: StructureEditorProps): ReactElement {
|
|
|
194
130
|
/>
|
|
195
131
|
) : null}
|
|
196
132
|
</div>
|
|
133
|
+
{imports.problem === null ? null : (
|
|
134
|
+
<EditorImportProblem
|
|
135
|
+
problem={imports.problem}
|
|
136
|
+
onDismiss={imports.dismiss}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
197
139
|
</Suspense>
|
|
140
|
+
{drop.over ? (
|
|
141
|
+
<StructureDropOverlay
|
|
142
|
+
label={t('structure.import.drop')}
|
|
143
|
+
handlers={drop.overlayProps}
|
|
144
|
+
/>
|
|
145
|
+
) : null}
|
|
198
146
|
</div>
|
|
199
147
|
);
|
|
200
148
|
}
|
|
201
149
|
|
|
202
|
-
/**
|
|
203
|
-
* Report the last edit of a burst rather than every one of them.
|
|
204
|
-
*
|
|
205
|
-
* The editor's own event is read out before the wait starts, so what arrives
|
|
206
|
-
* late is a plain object rather than a handle on an editor that has moved on.
|
|
207
|
-
* An editor removed mid-burst — a tab switched, a card folded — still reports
|
|
208
|
-
* its last edit, which would otherwise be lost with the timer.
|
|
209
|
-
* @param onChange - What the caller wants told.
|
|
210
|
-
* @param delay - How long the drawing has to be still, in milliseconds.
|
|
211
|
-
* @param resetKey - Dropped edits: a burst still waiting when the caller
|
|
212
|
-
* replaces the structure describes a canvas that no longer exists.
|
|
213
|
-
* @returns The handler to give the canvas.
|
|
214
|
-
*/
|
|
215
|
-
function useDebounced(
|
|
216
|
-
onChange: (change: StructureEditorChange) => void,
|
|
217
|
-
delay: number,
|
|
218
|
-
resetKey: number,
|
|
219
|
-
): (change: StructureEditorChange) => void {
|
|
220
|
-
const [pending] = useState(createPendingCall<StructureEditorChange>);
|
|
221
|
-
const onChangeRef = useRef(onChange);
|
|
222
|
-
useEffect(() => {
|
|
223
|
-
onChangeRef.current = onChange;
|
|
224
|
-
});
|
|
225
|
-
useEffect(() => {
|
|
226
|
-
pending.drop();
|
|
227
|
-
}, [pending, resetKey]);
|
|
228
|
-
useEffect(() => () => pending.flush(), [pending]);
|
|
229
|
-
|
|
230
|
-
return useCallback(
|
|
231
|
-
(change: StructureEditorChange) => {
|
|
232
|
-
pending.push(change, delay, (value) => onChangeRef.current(value));
|
|
233
|
-
},
|
|
234
|
-
[pending, delay],
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
150
|
/**
|
|
239
151
|
* The canvas is positioned out of the height computation, so the container's
|
|
240
152
|
* own height is what the measured toolbar floor writes on it. The `minHeight`
|
|
@@ -252,8 +164,8 @@ const ROOT_STYLE: CSSProperties = {
|
|
|
252
164
|
};
|
|
253
165
|
|
|
254
166
|
/**
|
|
255
|
-
* The corner the editor's own buttons sit in: export
|
|
256
|
-
*
|
|
167
|
+
* The corner the editor's own buttons sit in: open, export, then help — the
|
|
168
|
+
* drawing in, the drawing out, and the guide last.
|
|
257
169
|
*/
|
|
258
170
|
const CORNER_STYLE: CSSProperties = {
|
|
259
171
|
position: 'absolute',
|
|
@@ -273,3 +185,6 @@ const LOADING_STYLE: CSSProperties = {
|
|
|
273
185
|
color: TOKEN.textFaint,
|
|
274
186
|
fontSize: 13,
|
|
275
187
|
};
|
|
188
|
+
|
|
189
|
+
/** What the editor reads itself, offered first by the file picker. */
|
|
190
|
+
const STRUCTURE_FILES = '.mol,.sdf,.sd,.smi,.smiles,.txt';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a structure dropped on the editor, or opened from disk.
|
|
3
|
+
*
|
|
4
|
+
* **Not exported from `ui/index.ts`**: it value-imports `openchemlib`. The
|
|
5
|
+
* editor loads it on the first drop, by which time the canvas has already
|
|
6
|
+
* brought openchemlib in.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Canonizer, Molecule } from 'openchemlib';
|
|
10
|
+
|
|
11
|
+
import { splitEditorValue } from '../core/editorValue.ts';
|
|
12
|
+
|
|
13
|
+
import type { StructureEditorMoleculeChange } from './editorChange.ts';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Turn dropped text into what the editor reports after an edit.
|
|
17
|
+
*
|
|
18
|
+
* A molfile is read whole, so an SDF gives its first record. Anything else is
|
|
19
|
+
* read from its first meaningful line, as a SMILES and then as an idCode — but
|
|
20
|
+
* an idCode only when it is the canonical one, because openchemlib decodes
|
|
21
|
+
* almost any word into some molecule: `ethanol` read as an idCode has 1106
|
|
22
|
+
* atoms. A word holding a character no idCode holds is never decoded, since
|
|
23
|
+
* openchemlib does not return from some of them — `O=Cc1cccc`, a SMILES with
|
|
24
|
+
* an unclosed ring, is one. A 3D structure is laid out flat, since the canvas
|
|
25
|
+
* draws in 2D.
|
|
26
|
+
* @param text - The file's content or the dragged text.
|
|
27
|
+
* @param fragment - Whether the editor draws a query fragment.
|
|
28
|
+
* @returns The change, or `null` when the text holds no structure.
|
|
29
|
+
*/
|
|
30
|
+
export function readImportedStructure(
|
|
31
|
+
text: string,
|
|
32
|
+
fragment: boolean,
|
|
33
|
+
): StructureEditorMoleculeChange | null {
|
|
34
|
+
const molecule = parseStructure(text);
|
|
35
|
+
if (molecule === null || molecule.getAllAtoms() === 0) return null;
|
|
36
|
+
if (hasDepth(molecule)) molecule.inventCoordinates();
|
|
37
|
+
molecule.setFragment(fragment);
|
|
38
|
+
|
|
39
|
+
const canonizer = new Canonizer(molecule);
|
|
40
|
+
return {
|
|
41
|
+
mode: 'molecule',
|
|
42
|
+
idCode: `${canonizer.getIDCode()} ${canonizer.getEncodedCoordinates(false)}`,
|
|
43
|
+
molfile: molecule.toMolfile(),
|
|
44
|
+
smiles: molecule.toIsomericSmiles(),
|
|
45
|
+
molecule: molecule.getCompactCopy(),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function parseStructure(text: string): Molecule | null {
|
|
50
|
+
const value = splitEditorValue(text);
|
|
51
|
+
if (value.kind === 'molfile') {
|
|
52
|
+
return attempt(() => Molecule.fromMolfile(value.molfile));
|
|
53
|
+
}
|
|
54
|
+
const notation = value.entries[0]?.structure;
|
|
55
|
+
if (notation === undefined) return null;
|
|
56
|
+
return (
|
|
57
|
+
attempt(() => Molecule.fromSmiles(notation)) ?? canonicalIdCode(notation)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function canonicalIdCode(text: string): Molecule | null {
|
|
62
|
+
if (!ID_CODE.test(text)) return null;
|
|
63
|
+
const molecule = attempt(() => Molecule.fromIDCode(text));
|
|
64
|
+
return molecule?.getIDCode() === text ? molecule : null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function attempt(parse: () => Molecule): Molecule | null {
|
|
68
|
+
try {
|
|
69
|
+
return parse();
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function hasDepth(molecule: Molecule): boolean {
|
|
76
|
+
for (let atom = 0; atom < molecule.getAllAtoms(); atom++) {
|
|
77
|
+
if (molecule.getAtomZ(atom) !== 0) return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** An idCode is written in six-bit groups offset to `@`, so in `@` to DEL. */
|
|
83
|
+
const ID_CODE = /^[\u0040-\u007F]+$/;
|
|
@@ -21,6 +21,8 @@ export type { StructureLabels, StructureProps } from './Structure.tsx';
|
|
|
21
21
|
export { Structure } from './Structure.tsx';
|
|
22
22
|
export type { StructureEditorProps } from './StructureEditor.tsx';
|
|
23
23
|
export { StructureEditor } from './StructureEditor.tsx';
|
|
24
|
+
export type { StructureDropProps } from './StructureDrop.tsx';
|
|
25
|
+
export { StructureDrop } from './StructureDrop.tsx';
|
|
24
26
|
export type { StructureEditorHelpProps } from './StructureEditorHelp.tsx';
|
|
25
27
|
export { StructureEditorHelp } from './StructureEditorHelp.tsx';
|
|
26
28
|
export type { StructureExportDialogProps } from './StructureExportDialog.tsx';
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
import type { CanvasEditorInputFormat } from 'react-ocl';
|
|
3
|
+
|
|
4
|
+
import type { StructureTransfer } from '../core/structureTransfer.ts';
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
StructureEditorChange,
|
|
8
|
+
StructureEditorMode,
|
|
9
|
+
} from './editorChange.ts';
|
|
10
|
+
|
|
11
|
+
/** What `StructureEditor` needs. */
|
|
12
|
+
export interface StructureEditorProps {
|
|
13
|
+
/**
|
|
14
|
+
* Called after every edit, once the drawing has been still for `debounce`
|
|
15
|
+
* milliseconds, with every notation read out of the editor.
|
|
16
|
+
*/
|
|
17
|
+
onChange: (change: StructureEditorChange) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Draw a query fragment rather than a whole structure, which is what a
|
|
20
|
+
* substructure filter needs.
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
fragment?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* How `value` is written.
|
|
26
|
+
* @default 'idcode'
|
|
27
|
+
*/
|
|
28
|
+
inputFormat?: CanvasEditorInputFormat;
|
|
29
|
+
/**
|
|
30
|
+
* What the canvas holds. Read once, when the editor appears and again on
|
|
31
|
+
* every change of `revision`: the editor is uncontrolled, so feeding the
|
|
32
|
+
* drawing back into it would replace the structure and reset every
|
|
33
|
+
* coordinate under the pen.
|
|
34
|
+
* @default ''
|
|
35
|
+
*/
|
|
36
|
+
value?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Bumped by the caller to load `value` into the canvas again, which is what
|
|
39
|
+
* an example, a share link or a Clear button does. Changing it discards
|
|
40
|
+
* whatever was being drawn.
|
|
41
|
+
* @default 0
|
|
42
|
+
*/
|
|
43
|
+
revision?: number;
|
|
44
|
+
/**
|
|
45
|
+
* How long the drawing has to be still before `onChange` is called, in
|
|
46
|
+
* milliseconds. Long enough that drawing a ring does not publish six
|
|
47
|
+
* structures; `0` reports every stroke.
|
|
48
|
+
* @default 300
|
|
49
|
+
*/
|
|
50
|
+
debounce?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Smallest height of the drawing area, in pixels. Raised to whatever the
|
|
53
|
+
* toolbar needs, which is usually more.
|
|
54
|
+
* @default 320
|
|
55
|
+
*/
|
|
56
|
+
minHeight?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the editor draws one structure or a reaction. A reaction canvas
|
|
59
|
+
* has its own toolbar and its own arrow.
|
|
60
|
+
* @default 'molecule'
|
|
61
|
+
*/
|
|
62
|
+
mode?: StructureEditorMode;
|
|
63
|
+
/**
|
|
64
|
+
* Explain each toolbar button in a tooltip, and put a button in the corner
|
|
65
|
+
* that opens a guide to the mouse and the keyboard, which F1 opens too.
|
|
66
|
+
* @default true
|
|
67
|
+
*/
|
|
68
|
+
help?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Put a button in the corner that opens every notation of the drawing — its
|
|
71
|
+
* SMILES, its molfiles, its canonical identifiers — and the picture of it,
|
|
72
|
+
* ready to copy or to save. A reaction has none of those, so it is never
|
|
73
|
+
* offered one.
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
exportable?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Take a structure dropped on the canvas — a molfile, an SDF, a SMILES or
|
|
79
|
+
* an idCode, as a file or as text dragged from another page — and put a
|
|
80
|
+
* button in the corner that opens one from disk. A reaction canvas takes
|
|
81
|
+
* none.
|
|
82
|
+
* @default true
|
|
83
|
+
*/
|
|
84
|
+
importable?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Take what is dropped or opened yourself instead of letting the editor read
|
|
87
|
+
* it, for a page that reads more than the canvas does — an XYZ, a PDB, a 3D
|
|
88
|
+
* geometry the canvas would flatten. The page then loads the structure back
|
|
89
|
+
* through `value` and `revision`, like any other.
|
|
90
|
+
* @default undefined
|
|
91
|
+
*/
|
|
92
|
+
onImport?: (transfer: StructureTransfer) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Class the container carries, so a site can reach it from its stylesheet.
|
|
95
|
+
* @default undefined
|
|
96
|
+
*/
|
|
97
|
+
className?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Extra style for the container, merged over the packaged one.
|
|
100
|
+
* @default undefined
|
|
101
|
+
*/
|
|
102
|
+
style?: CSSProperties;
|
|
103
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { createPendingCall } from '../core/pendingCall.ts';
|
|
4
|
+
|
|
5
|
+
import type { StructureEditorChange } from './editorChange.ts';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Report the last edit of a burst rather than every one of them.
|
|
9
|
+
*
|
|
10
|
+
* The editor's own event is read out before the wait starts, so what arrives
|
|
11
|
+
* late is a plain object rather than a handle on an editor that has moved on.
|
|
12
|
+
* An editor removed mid-burst — a tab switched, a card folded — still reports
|
|
13
|
+
* its last edit, which would otherwise be lost with the timer.
|
|
14
|
+
* @param onChange - What the caller wants told.
|
|
15
|
+
* @param delay - How long the drawing has to be still, in milliseconds.
|
|
16
|
+
* @param resetKey - Dropped edits: a burst still waiting when the caller
|
|
17
|
+
* replaces the structure describes a canvas that no longer exists.
|
|
18
|
+
* @returns The handler to give the canvas.
|
|
19
|
+
*/
|
|
20
|
+
export function useDebouncedChange(
|
|
21
|
+
onChange: (change: StructureEditorChange) => void,
|
|
22
|
+
delay: number,
|
|
23
|
+
resetKey: number,
|
|
24
|
+
): (change: StructureEditorChange) => void {
|
|
25
|
+
const [pending] = useState(createPendingCall<StructureEditorChange>);
|
|
26
|
+
const onChangeRef = useRef(onChange);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
onChangeRef.current = onChange;
|
|
29
|
+
});
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
pending.drop();
|
|
32
|
+
}, [pending, resetKey]);
|
|
33
|
+
useEffect(() => () => pending.flush(), [pending]);
|
|
34
|
+
|
|
35
|
+
return useCallback(
|
|
36
|
+
(change: StructureEditorChange) => {
|
|
37
|
+
pending.push(change, delay, (value) => onChangeRef.current(value));
|
|
38
|
+
},
|
|
39
|
+
[pending, delay],
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { DragEvent } from 'react';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { StructureTransfer } from '../core/structureTransfer.ts';
|
|
5
|
+
import {
|
|
6
|
+
carriesStructure,
|
|
7
|
+
readStructureTransfer,
|
|
8
|
+
} from '../core/structureTransfer.ts';
|
|
9
|
+
|
|
10
|
+
/** The drag handlers of one element. */
|
|
11
|
+
export interface DropHandlers {
|
|
12
|
+
onDragEnter?: (event: DragEvent<HTMLElement>) => void;
|
|
13
|
+
onDragOver?: (event: DragEvent<HTMLElement>) => void;
|
|
14
|
+
onDragLeave?: (event: DragEvent<HTMLElement>) => void;
|
|
15
|
+
onDrop?: (event: DragEvent<HTMLElement>) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A drop target, in two parts: the element and the overlay it raises. */
|
|
19
|
+
export interface StructureDropTarget {
|
|
20
|
+
/** Whether a file or text is being dragged over the target. */
|
|
21
|
+
over: boolean;
|
|
22
|
+
/** Put on the element that takes the drop. */
|
|
23
|
+
targetProps: DropHandlers;
|
|
24
|
+
/**
|
|
25
|
+
* Put on the overlay drawn while `over`. It covers the target and takes
|
|
26
|
+
* every drag event from then on, so moving across the canvas and the buttons
|
|
27
|
+
* underneath never reads as leaving, and leaving the overlay is leaving.
|
|
28
|
+
*/
|
|
29
|
+
overlayProps: DropHandlers;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Take a file or text dropped on an element.
|
|
34
|
+
* @param onDrop - Where the drop goes; `undefined` takes none.
|
|
35
|
+
* @returns Whether a drag is over the element, and the handlers to put on it
|
|
36
|
+
* and on its overlay.
|
|
37
|
+
*/
|
|
38
|
+
export function useStructureDrop(
|
|
39
|
+
onDrop: ((transfer: StructureTransfer) => void) | undefined,
|
|
40
|
+
): StructureDropTarget {
|
|
41
|
+
const [over, setOver] = useState(false);
|
|
42
|
+
|
|
43
|
+
return useMemo(() => {
|
|
44
|
+
if (onDrop === undefined) {
|
|
45
|
+
return { over: false, targetProps: {}, overlayProps: {} };
|
|
46
|
+
}
|
|
47
|
+
const accept = (event: DragEvent<HTMLElement>): boolean => {
|
|
48
|
+
if (!carriesStructure(event.dataTransfer.types)) return false;
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
event.dataTransfer.dropEffect = 'copy';
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
over,
|
|
55
|
+
targetProps: {
|
|
56
|
+
onDragEnter: (event) => {
|
|
57
|
+
if (accept(event)) setOver(true);
|
|
58
|
+
},
|
|
59
|
+
onDragOver: accept,
|
|
60
|
+
},
|
|
61
|
+
overlayProps: {
|
|
62
|
+
onDragOver: accept,
|
|
63
|
+
onDragLeave: (event) => {
|
|
64
|
+
if (event.target === event.currentTarget) setOver(false);
|
|
65
|
+
},
|
|
66
|
+
onDrop: (event) => {
|
|
67
|
+
setOver(false);
|
|
68
|
+
const transfer = readStructureTransfer(event.dataTransfer);
|
|
69
|
+
if (transfer === null) return;
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
onDrop(transfer);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}, [onDrop, over]);
|
|
76
|
+
}
|