react-cheminfo 0.66.0 → 0.68.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 +6 -6
- 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 +2 -2
- 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 +6 -3
- package/src/download/ui/FigureDownloadPanel.tsx +9 -2
- package/src/ecosystem/core/sites.ts +6 -6
- package/src/ecosystem/core/types.ts +2 -2
- package/src/ecosystem/ui/glyphs.tsx +2 -2
- 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
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frames of a trajectory: how many there are, which one is shown, and
|
|
3
|
+
* playing them in a loop.
|
|
4
|
+
*
|
|
5
|
+
* molstar keeps a trajectory as one data node and shows one of its frames
|
|
6
|
+
* through a `ModelFromTrajectory` node whose `modelIndex` says which. Playing
|
|
7
|
+
* is molstar's own model-index animation, which steps that index; showing one
|
|
8
|
+
* frame sets it.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PluginContext } from 'molstar/lib/mol-plugin/context.js';
|
|
12
|
+
import { AnimateModelIndex } from 'molstar/lib/mol-plugin-state/animation/built-in/model-index.js';
|
|
13
|
+
import { PluginStateObject } from 'molstar/lib/mol-plugin-state/objects.js';
|
|
14
|
+
import { ModelFromTrajectory } from 'molstar/lib/mol-plugin-state/transforms/model.js';
|
|
15
|
+
import { StateSelection } from 'molstar/lib/mol-state/index.js';
|
|
16
|
+
|
|
17
|
+
/** How fast molstar's model-index animation can step, frames per second. */
|
|
18
|
+
export const PLAYBACK_FPS_RANGE = { minimum: 5, maximum: 60 } as const;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* How many frames the trajectory on screen holds.
|
|
22
|
+
* @param plugin - The molstar context.
|
|
23
|
+
* @returns The most frames of any trajectory shown; 0 when none is.
|
|
24
|
+
*/
|
|
25
|
+
export function trajectoryFrameCount(plugin: PluginContext): number {
|
|
26
|
+
const state = plugin.state.data;
|
|
27
|
+
let count = 0;
|
|
28
|
+
for (const model of modelCells(plugin)) {
|
|
29
|
+
const trajectory = StateSelection.findAncestorOfType(
|
|
30
|
+
state.tree,
|
|
31
|
+
state.cells,
|
|
32
|
+
model.transform.ref,
|
|
33
|
+
PluginStateObject.Molecule.Trajectory,
|
|
34
|
+
);
|
|
35
|
+
count = Math.max(count, trajectory?.obj?.data.frameCount ?? 0);
|
|
36
|
+
}
|
|
37
|
+
return count;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Show one frame of every trajectory on screen, and everything built on it:
|
|
42
|
+
* the drawn model, its surface and the measurements over it.
|
|
43
|
+
* @param plugin - The molstar context.
|
|
44
|
+
* @param index - The frame, from 0.
|
|
45
|
+
* @returns Nothing; resolves once the state tree is updated.
|
|
46
|
+
*/
|
|
47
|
+
export async function showTrajectoryFrame(
|
|
48
|
+
plugin: PluginContext,
|
|
49
|
+
index: number,
|
|
50
|
+
): Promise<void> {
|
|
51
|
+
const update = plugin.build();
|
|
52
|
+
for (const model of modelCells(plugin)) {
|
|
53
|
+
update.to(model).update({ modelIndex: index });
|
|
54
|
+
}
|
|
55
|
+
await update.commit();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The frame on screen.
|
|
60
|
+
* @param plugin - The molstar context.
|
|
61
|
+
* @returns The index of the frame the first trajectory shows; 0 when none is.
|
|
62
|
+
*/
|
|
63
|
+
export function shownTrajectoryFrame(plugin: PluginContext): number {
|
|
64
|
+
return modelCells(plugin)[0]?.transform.params?.modelIndex ?? 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Play the frames in a loop, or stop them where they stand.
|
|
69
|
+
* @param plugin - The molstar context.
|
|
70
|
+
* @param playing - Whether to play. A trajectory of one frame never plays.
|
|
71
|
+
* @param framesPerSecond - How fast, clamped into {@link PLAYBACK_FPS_RANGE}.
|
|
72
|
+
* @returns Nothing; resolves once the animation is started or stopped.
|
|
73
|
+
*/
|
|
74
|
+
export async function setTrajectoryPlayback(
|
|
75
|
+
plugin: PluginContext,
|
|
76
|
+
playing: boolean,
|
|
77
|
+
framesPerSecond: number,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
if (!playing || trajectoryFrameCount(plugin) < 2) {
|
|
80
|
+
await stopTrajectory(plugin);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
await plugin.managers.animation.play(AnimateModelIndex, {
|
|
84
|
+
mode: { name: 'loop', params: { direction: 'forward' } },
|
|
85
|
+
duration: {
|
|
86
|
+
name: 'sequential',
|
|
87
|
+
params: { maxFps: clampFramesPerSecond(framesPerSecond) },
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Stop the frames where they stand.
|
|
94
|
+
* @param plugin - The molstar context.
|
|
95
|
+
* @returns Nothing; resolves once the animation is stopped.
|
|
96
|
+
*/
|
|
97
|
+
export async function stopTrajectory(plugin: PluginContext): Promise<void> {
|
|
98
|
+
const animation = plugin.managers.animation;
|
|
99
|
+
if (animation.isAnimating) await animation.stop();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A frame rate molstar's model-index animation accepts.
|
|
104
|
+
* @param framesPerSecond - Any rate.
|
|
105
|
+
* @returns The rate, rounded and clamped into {@link PLAYBACK_FPS_RANGE}.
|
|
106
|
+
*/
|
|
107
|
+
export function clampFramesPerSecond(framesPerSecond: number): number {
|
|
108
|
+
const { minimum, maximum } = PLAYBACK_FPS_RANGE;
|
|
109
|
+
if (!Number.isFinite(framesPerSecond)) return minimum;
|
|
110
|
+
return Math.min(maximum, Math.max(minimum, Math.round(framesPerSecond)));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function modelCells(plugin: PluginContext) {
|
|
114
|
+
return plugin.state.data.select(
|
|
115
|
+
StateSelection.Generators.ofTransformer(ModelFromTrajectory),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -55,6 +55,9 @@ export function PanelRail<TId extends string>(
|
|
|
55
55
|
id={panel.id}
|
|
56
56
|
icon={panel.icon}
|
|
57
57
|
tooltip={panel.title}
|
|
58
|
+
// A tooltip is not an accessible name: without this every toggle is
|
|
59
|
+
// an icon-only button with no name at all.
|
|
60
|
+
aria-label={panel.title}
|
|
58
61
|
active={openIds.includes(panel.id)}
|
|
59
62
|
onClick={() => onToggle(panel.id)}
|
|
60
63
|
/>
|
package/src/raman.ts
CHANGED
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export type { LoadedIrSpectrum } from './ir/core/analysisSpectra.ts';
|
|
12
|
-
export type { IrEditorHandle } from './ir/core/irEditorApi.ts';
|
|
12
|
+
export type { IrEditorHandle, IrPlotClick } from './ir/core/irEditorApi.ts';
|
|
13
13
|
export type { IrSpectrum } from './ir/core/irSpectrum.ts';
|
|
14
14
|
export { toIrSpectra } from './ir/core/toIrSpectrum.ts';
|
|
15
|
+
export type { IrHostPanel } from './ir/ui/irHostPanels.ts';
|
|
15
16
|
export type {
|
|
16
17
|
RamanEditorHandle,
|
|
17
18
|
RamanEditorProps,
|
|
@@ -4,8 +4,8 @@ import { trimTrailingSlash } from './address.ts';
|
|
|
4
4
|
* Where a site is mounted, read off the page rather than off the build.
|
|
5
5
|
*
|
|
6
6
|
* The build is mount-agnostic — vite is given a relative base, so the same
|
|
7
|
-
* `dist` serves `https://
|
|
8
|
-
* `https://www.cheminfo.org/
|
|
7
|
+
* `dist` serves `https://isomers.cheminfo.org/` and
|
|
8
|
+
* `https://www.cheminfo.org/isomers/`. What tells the two apart is the `<base>`
|
|
9
9
|
* the deployment stamps into the page it hands out, and `document.baseURI`
|
|
10
10
|
* resolves it against the address actually opened. So this answers correctly
|
|
11
11
|
* whether or not a slash closes the address, and on an address the SPA
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
*
|
|
17
17
|
* The mount is read off the page, not off the build: the build carries no
|
|
18
18
|
* mount, and the `<base>` a deployment stamps into its pages is what tells
|
|
19
|
-
* `https://
|
|
19
|
+
* `https://isomers.cheminfo.org/` from `https://www.cheminfo.org/isomers/`. Under
|
|
20
20
|
* Node there is no page, and the mount is the root.
|
|
21
21
|
* @param siteId - The site, as `ECOSYSTEM_SITES` names it.
|
|
22
22
|
* @param options - A mount path to use instead of the one read off the page.
|
|
@@ -130,7 +130,7 @@ export function originOf(options: SiteOrigin): string {
|
|
|
130
130
|
const origin = options.origin ?? `https://${resolveSite(options.site).host}`;
|
|
131
131
|
if (!HTTP_ORIGIN.test(origin) || !URL.canParse(origin)) {
|
|
132
132
|
throw new Error(
|
|
133
|
-
`an origin is an absolute address, e.g. https://
|
|
133
|
+
`an origin is an absolute address, e.g. https://isomers.cheminfo.org: ${JSON.stringify(origin)}`,
|
|
134
134
|
);
|
|
135
135
|
}
|
|
136
136
|
return trimTrailingSlash(origin);
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* The two are written however the deployment writes them — an origin, an
|
|
7
7
|
* origin and a mount, with or without a trailing slash — and a page is named
|
|
8
8
|
* from the site's own root, `/titration` and `titration` alike: every helper
|
|
9
|
-
* joins the two with exactly one slash, so `https://www.cheminfo.org/
|
|
10
|
-
* and `https://www.cheminfo.org/
|
|
11
|
-
* `https://www.cheminfo.org/
|
|
9
|
+
* joins the two with exactly one slash, so `https://www.cheminfo.org/isomers`
|
|
10
|
+
* and `https://www.cheminfo.org/isomers/` both put `/generator` at
|
|
11
|
+
* `https://www.cheminfo.org/isomers/generator`.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { trimTrailingSlash } from '../router/core/address.ts';
|
|
@@ -82,3 +82,11 @@ export type {
|
|
|
82
82
|
StructureSourceInput,
|
|
83
83
|
} from './structureSource.ts';
|
|
84
84
|
export { structureSource } from './structureSource.ts';
|
|
85
|
+
export type {
|
|
86
|
+
StructureTransfer,
|
|
87
|
+
StructureTransferSource,
|
|
88
|
+
} from './structureTransfer.ts';
|
|
89
|
+
export {
|
|
90
|
+
carriesStructure,
|
|
91
|
+
readStructureTransfer,
|
|
92
|
+
} from './structureTransfer.ts';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** What a paste or a drop carried that a structure can be read from. */
|
|
2
|
+
export type StructureTransfer =
|
|
3
|
+
{ kind: 'files'; files: File[] } | { kind: 'text'; text: string };
|
|
4
|
+
|
|
5
|
+
/** The part of a `DataTransfer` a structure is read from. */
|
|
6
|
+
export interface StructureTransferSource {
|
|
7
|
+
files: ArrayLike<File>;
|
|
8
|
+
getData: (format: string) => string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* What a paste or a drop holds: its files when it carries any, otherwise its
|
|
13
|
+
* text — a SMILES, an idCode, a molfile. A file copied in the file manager also
|
|
14
|
+
* carries its name as text, so the files win.
|
|
15
|
+
* @param transfer - The clipboard or drag data, `null` when the event has none.
|
|
16
|
+
* @returns The files or the trimmed text, or `null` when there is nothing.
|
|
17
|
+
*/
|
|
18
|
+
export function readStructureTransfer(
|
|
19
|
+
transfer: StructureTransferSource | null,
|
|
20
|
+
): StructureTransfer | null {
|
|
21
|
+
if (transfer === null) return null;
|
|
22
|
+
if (transfer.files.length > 0) {
|
|
23
|
+
return { kind: 'files', files: Array.from(transfer.files) };
|
|
24
|
+
}
|
|
25
|
+
const text = transfer.getData('text').trim();
|
|
26
|
+
return text === '' ? null : { kind: 'text', text };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether a drag in progress may carry a structure. Until the drop only the
|
|
31
|
+
* types are readable, never the content, so a file or plain text is enough.
|
|
32
|
+
* @param types - `DataTransfer.types` of the drag.
|
|
33
|
+
* @returns Whether it is worth offering to take the drop.
|
|
34
|
+
*/
|
|
35
|
+
export function carriesStructure(types: readonly string[]): boolean {
|
|
36
|
+
return types.includes('Files') || types.includes('text/plain');
|
|
37
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Button } from '@blueprintjs/core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
import { useRef } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
|
|
7
|
+
import type { StructureTransfer } from '../core/structureTransfer.ts';
|
|
8
|
+
|
|
9
|
+
/** What {@link EditorImportButton} needs. */
|
|
10
|
+
export interface EditorImportButtonProps {
|
|
11
|
+
/** Called with the files chosen. */
|
|
12
|
+
onImport: (transfer: StructureTransfer) => void;
|
|
13
|
+
/**
|
|
14
|
+
* The file types the picker offers, as an `accept` attribute.
|
|
15
|
+
* @default undefined
|
|
16
|
+
*/
|
|
17
|
+
accept?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The editor's open button, beside the export one, for a visitor who cannot
|
|
22
|
+
* drag a file onto the canvas — on a phone, or from a picker.
|
|
23
|
+
* @param props - See {@link EditorImportButtonProps}.
|
|
24
|
+
* @returns The button and its hidden file input.
|
|
25
|
+
*/
|
|
26
|
+
export function EditorImportButton(
|
|
27
|
+
props: EditorImportButtonProps,
|
|
28
|
+
): ReactElement {
|
|
29
|
+
const { onImport, accept } = props;
|
|
30
|
+
const t = useChromeT();
|
|
31
|
+
const input = useRef<HTMLInputElement>(null);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
<ActionTooltip content={t('structure.import.open')} placement="left">
|
|
36
|
+
<Button
|
|
37
|
+
variant="minimal"
|
|
38
|
+
size="small"
|
|
39
|
+
icon="import"
|
|
40
|
+
aria-label={t('structure.import.open')}
|
|
41
|
+
onClick={() => input.current?.click()}
|
|
42
|
+
/>
|
|
43
|
+
</ActionTooltip>
|
|
44
|
+
<input
|
|
45
|
+
ref={input}
|
|
46
|
+
type="file"
|
|
47
|
+
accept={accept}
|
|
48
|
+
hidden
|
|
49
|
+
data-testid="structure-editor-file"
|
|
50
|
+
onChange={(event) => {
|
|
51
|
+
const files = Array.from(event.currentTarget.files ?? []);
|
|
52
|
+
// Cleared, so choosing the same file again is a change.
|
|
53
|
+
event.currentTarget.value = '';
|
|
54
|
+
if (files.length > 0) onImport({ kind: 'files', files });
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Button, Callout } from '@blueprintjs/core';
|
|
2
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
5
|
+
|
|
6
|
+
import type { StructureImportProblem } from './useStructureImport.ts';
|
|
7
|
+
|
|
8
|
+
/** What {@link EditorImportProblem} needs. */
|
|
9
|
+
export interface EditorImportProblemProps {
|
|
10
|
+
/** What went wrong. */
|
|
11
|
+
problem: StructureImportProblem;
|
|
12
|
+
/** Forget it. */
|
|
13
|
+
onDismiss: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The line along the bottom of the canvas that says a drop loaded nothing,
|
|
18
|
+
* and that the drawing is still there.
|
|
19
|
+
* @param props - See {@link EditorImportProblemProps}.
|
|
20
|
+
* @returns The line.
|
|
21
|
+
*/
|
|
22
|
+
export function EditorImportProblem(
|
|
23
|
+
props: EditorImportProblemProps,
|
|
24
|
+
): ReactElement {
|
|
25
|
+
const { problem, onDismiss } = props;
|
|
26
|
+
const t = useChromeT();
|
|
27
|
+
return (
|
|
28
|
+
<div role="alert" style={PLACE}>
|
|
29
|
+
<Callout intent="danger" icon={null} compact style={LINE}>
|
|
30
|
+
<span style={TEXT}>
|
|
31
|
+
{problem.file === null
|
|
32
|
+
? t('structure.import.unreadableText')
|
|
33
|
+
: t('structure.import.unreadableFile', { name: problem.file })}
|
|
34
|
+
</span>
|
|
35
|
+
<Button
|
|
36
|
+
variant="minimal"
|
|
37
|
+
size="small"
|
|
38
|
+
icon="cross"
|
|
39
|
+
aria-label={t('overlay.dismiss')}
|
|
40
|
+
onClick={onDismiss}
|
|
41
|
+
/>
|
|
42
|
+
</Callout>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Clear of the tool palette, two 21px columns in a 2px border, at the left. */
|
|
48
|
+
const PLACE: CSSProperties = {
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
right: 4,
|
|
51
|
+
bottom: 4,
|
|
52
|
+
left: 52,
|
|
53
|
+
zIndex: 10,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const LINE: CSSProperties = {
|
|
57
|
+
display: 'flex',
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
gap: 6,
|
|
60
|
+
fontSize: 12,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const TEXT: CSSProperties = { flex: 1 };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { CSSProperties, ReactElement, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
4
|
+
import type { StructureTransfer } from '../core/structureTransfer.ts';
|
|
5
|
+
|
|
6
|
+
import { StructureDropOverlay } from './StructureDropOverlay.tsx';
|
|
7
|
+
import { useStructureDrop } from './useStructureDrop.ts';
|
|
8
|
+
|
|
9
|
+
/** What {@link StructureDrop} needs. */
|
|
10
|
+
export interface StructureDropProps {
|
|
11
|
+
/** Called with the files or the text dropped. */
|
|
12
|
+
onDrop: (transfer: StructureTransfer) => void;
|
|
13
|
+
/** What the drop lands on. */
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* What the overlay says while something is dragged over.
|
|
17
|
+
* @default 'Drop to load the structure', in the page's language
|
|
18
|
+
*/
|
|
19
|
+
label?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Take no drop, while a load is already running for instance.
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Class of the wrapping element.
|
|
27
|
+
* @default undefined
|
|
28
|
+
*/
|
|
29
|
+
className?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Extra style for the wrapping element, which is positioned so the overlay
|
|
32
|
+
* covers it.
|
|
33
|
+
* @default undefined
|
|
34
|
+
*/
|
|
35
|
+
style?: CSSProperties;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Make an area take a structure file, or structure text dragged from another
|
|
40
|
+
* page, with the same veil the structure editor raises over its canvas. What
|
|
41
|
+
* was dropped is handed over unread: the page knows which formats it takes.
|
|
42
|
+
* @param props - See {@link StructureDropProps}.
|
|
43
|
+
* @returns The area.
|
|
44
|
+
*/
|
|
45
|
+
export function StructureDrop(props: StructureDropProps): ReactElement {
|
|
46
|
+
const { onDrop, children, label, disabled = false } = props;
|
|
47
|
+
const { className, style } = props;
|
|
48
|
+
const t = useChromeT();
|
|
49
|
+
const drop = useStructureDrop(disabled ? undefined : onDrop);
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
className={className}
|
|
54
|
+
style={{ position: 'relative', ...style }}
|
|
55
|
+
{...drop.targetProps}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
{drop.over ? (
|
|
59
|
+
<StructureDropOverlay
|
|
60
|
+
label={label ?? t('structure.import.drop')}
|
|
61
|
+
handlers={drop.overlayProps}
|
|
62
|
+
/>
|
|
63
|
+
) : null}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Icon } from '@blueprintjs/core';
|
|
2
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { DropHandlers } from './useStructureDrop.ts';
|
|
5
|
+
|
|
6
|
+
/** What {@link StructureDropOverlay} needs. */
|
|
7
|
+
export interface StructureDropOverlayProps {
|
|
8
|
+
/** What the overlay says. */
|
|
9
|
+
label: string;
|
|
10
|
+
/** The overlay handlers of `useStructureDrop`. */
|
|
11
|
+
handlers: DropHandlers;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The veil a drop target raises while a file or text is dragged over it.
|
|
16
|
+
* @param props - See {@link StructureDropOverlayProps}.
|
|
17
|
+
* @returns The overlay.
|
|
18
|
+
*/
|
|
19
|
+
export function StructureDropOverlay(
|
|
20
|
+
props: StructureDropOverlayProps,
|
|
21
|
+
): ReactElement {
|
|
22
|
+
const { label, handlers } = props;
|
|
23
|
+
return (
|
|
24
|
+
<div data-testid="structure-drop-overlay" style={OVERLAY} {...handlers}>
|
|
25
|
+
{/* Nothing inside takes the pointer, so leaving the overlay is the only
|
|
26
|
+
dragleave it hears. */}
|
|
27
|
+
<Icon icon="import" size={28} style={PASSIVE} />
|
|
28
|
+
<span style={PASSIVE}>{label}</span>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const OVERLAY: CSSProperties = {
|
|
34
|
+
position: 'absolute',
|
|
35
|
+
inset: 0,
|
|
36
|
+
zIndex: 20,
|
|
37
|
+
display: 'flex',
|
|
38
|
+
flexDirection: 'column',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
justifyContent: 'center',
|
|
41
|
+
gap: 8,
|
|
42
|
+
border: '2px dashed var(--accent)',
|
|
43
|
+
borderRadius: 'inherit',
|
|
44
|
+
background: 'color-mix(in oklab, var(--accent) 10%, rgb(255 255 255 / 88%))',
|
|
45
|
+
color: 'var(--accent)',
|
|
46
|
+
fontSize: 14,
|
|
47
|
+
fontWeight: 600,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const PASSIVE: CSSProperties = { pointerEvents: 'none' };
|