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
package/src/ir/core/irState.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* a stale band is then impossible rather than merely unlikely.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import type { IrSidePanelId } from './irSidePanels.ts';
|
|
16
|
+
import type { IrPanelId, IrSidePanelId } from './irSidePanels.ts';
|
|
17
17
|
import type { IrDomain, IrMode, IrSpectrum } from './irSpectrum.ts';
|
|
18
18
|
import type { IrTechnique } from './irTechnique.ts';
|
|
19
19
|
import { defaultIrMode, irModeFor, offersIrMode } from './irTechnique.ts';
|
|
@@ -42,8 +42,11 @@ export interface IrView {
|
|
|
42
42
|
domain: IrDomain | null;
|
|
43
43
|
/** Which tool a drag across the chart is running. */
|
|
44
44
|
tool: IrTool;
|
|
45
|
-
/**
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The side panels that are open: the viewer's own and any a host added. An id
|
|
47
|
+
* no panel on offer answers to opens nothing.
|
|
48
|
+
*/
|
|
49
|
+
openPanelIds: IrPanelId[];
|
|
47
50
|
/** Why the last action was refused, `null` as soon as one succeeds. */
|
|
48
51
|
error: string | null;
|
|
49
52
|
}
|
|
@@ -139,10 +142,10 @@ export interface CreateIrStateOptions {
|
|
|
139
142
|
*/
|
|
140
143
|
settings?: Partial<IrSettings>;
|
|
141
144
|
/**
|
|
142
|
-
* The panels open to begin with.
|
|
145
|
+
* The panels open to begin with, the viewer's own or a host's.
|
|
143
146
|
* @default DEFAULT_SIDE_PANELS
|
|
144
147
|
*/
|
|
145
|
-
panelIds?:
|
|
148
|
+
panelIds?: readonly IrPanelId[];
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
/**
|
package/src/ir/ui/IrCanvas.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
2
|
|
|
3
3
|
import type { IrBand } from '../core/irBand.ts';
|
|
4
|
+
import type { IrPlotClick } from '../core/irEditorApi.ts';
|
|
4
5
|
import type { IrDomain } from '../core/irSpectrum.ts';
|
|
5
6
|
|
|
6
7
|
import { IrChart } from './IrChart.tsx';
|
|
@@ -32,6 +33,12 @@ export interface IrCanvasProps {
|
|
|
32
33
|
* @default undefined
|
|
33
34
|
*/
|
|
34
35
|
chartId?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Told of a click on the plot — a press let go without travelling, never the
|
|
38
|
+
* end of a drag — with the spectrum selected at that moment.
|
|
39
|
+
* @default undefined
|
|
40
|
+
*/
|
|
41
|
+
onPlotClick?: (click: IrPlotClick) => void;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
/**
|
|
@@ -50,7 +57,13 @@ export interface IrCanvasProps {
|
|
|
50
57
|
* @returns The canvas.
|
|
51
58
|
*/
|
|
52
59
|
export function IrCanvas(props: IrCanvasProps) {
|
|
53
|
-
const {
|
|
60
|
+
const {
|
|
61
|
+
highlight = null,
|
|
62
|
+
onHighlight,
|
|
63
|
+
attachChart,
|
|
64
|
+
chartId,
|
|
65
|
+
onPlotClick,
|
|
66
|
+
} = props;
|
|
54
67
|
const { state, visibleSpectra, assigned } = useIrEditorState();
|
|
55
68
|
const actions = useIrActions();
|
|
56
69
|
const { domain, tool, selectedId } = state.view;
|
|
@@ -63,6 +76,17 @@ export function IrCanvas(props: IrCanvasProps) {
|
|
|
63
76
|
[actions],
|
|
64
77
|
);
|
|
65
78
|
|
|
79
|
+
// Which spectrum was selected is the viewer's to say, not the chart's: the
|
|
80
|
+
// chart only knows where the press landed.
|
|
81
|
+
const onClickAt = useMemo(
|
|
82
|
+
() =>
|
|
83
|
+
onPlotClick === undefined
|
|
84
|
+
? undefined
|
|
85
|
+
: (wavenumber: number) =>
|
|
86
|
+
onPlotClick({ wavenumber, spectrumId: selectedId }),
|
|
87
|
+
[onPlotClick, selectedId],
|
|
88
|
+
);
|
|
89
|
+
|
|
66
90
|
return (
|
|
67
91
|
<div style={rootStyle}>
|
|
68
92
|
<div ref={attachChart} id={chartId} style={chartStyle}>
|
|
@@ -79,6 +103,7 @@ export function IrCanvas(props: IrCanvasProps) {
|
|
|
79
103
|
onDomainChange={onDomainChange}
|
|
80
104
|
drag={tool === 'box' ? 'box' : 'xAxis'}
|
|
81
105
|
emphasisedId={selectedId}
|
|
106
|
+
onPlotClick={onClickAt}
|
|
82
107
|
/>
|
|
83
108
|
</div>
|
|
84
109
|
<IrStatusBar />
|
package/src/ir/ui/IrChart.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { useCallback, useId, useLayoutEffect, useMemo, useRef } from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { sameChartDomain } from '../../chart/core/chartDomain.ts';
|
|
5
5
|
import { MARGIN, plotRect } from '../../chart/core/chartGeometry.ts';
|
|
6
|
+
import type { ChartPoint } from '../../chart/core/svgPoint.ts';
|
|
6
7
|
import { Axes } from '../../chart/ui/Axes.tsx';
|
|
7
8
|
import { SelectionRect } from '../../chart/ui/SelectionRect.tsx';
|
|
8
9
|
import { chartSurfaceStyle } from '../../chart/ui/chartSurface.ts';
|
|
@@ -56,6 +57,7 @@ export function IrChart(props: IrChartProps): ReactElement {
|
|
|
56
57
|
onHighlight,
|
|
57
58
|
domain = null,
|
|
58
59
|
onDomainChange,
|
|
60
|
+
onPlotClick,
|
|
59
61
|
drag = 'xAxis',
|
|
60
62
|
emphasisedId = null,
|
|
61
63
|
width,
|
|
@@ -81,6 +83,14 @@ export function IrChart(props: IrChartProps): ReactElement {
|
|
|
81
83
|
const frameWidth = plot.right + MARGIN.right;
|
|
82
84
|
const frameHeight = plot.bottom + MARGIN.bottom;
|
|
83
85
|
|
|
86
|
+
const onClick = useMemo(
|
|
87
|
+
() =>
|
|
88
|
+
onPlotClick === undefined
|
|
89
|
+
? undefined
|
|
90
|
+
: (point: ChartPoint) => onPlotClick(point.x),
|
|
91
|
+
[onPlotClick],
|
|
92
|
+
);
|
|
93
|
+
|
|
84
94
|
// The host's window goes *into* the zoom rather than over it, so a drag is
|
|
85
95
|
// always measured against what is on screen.
|
|
86
96
|
const zoom = useIrZoom({
|
|
@@ -91,6 +101,7 @@ export function IrChart(props: IrChartProps): ReactElement {
|
|
|
91
101
|
plot,
|
|
92
102
|
domain,
|
|
93
103
|
drag,
|
|
104
|
+
onClick,
|
|
94
105
|
});
|
|
95
106
|
|
|
96
107
|
// The scales the zoom measured its gestures against — the x one running right
|
package/src/ir/ui/IrEditor.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Ref } from 'react';
|
|
2
2
|
|
|
3
|
-
import type { IrEditorHandle } from '../core/irEditorApi.ts';
|
|
4
|
-
import type {
|
|
3
|
+
import type { IrEditorHandle, IrPlotClick } from '../core/irEditorApi.ts';
|
|
4
|
+
import type { IrPanelId } from '../core/irSidePanels.ts';
|
|
5
5
|
import type { IrMode, IrSpectrum } from '../core/irSpectrum.ts';
|
|
6
6
|
|
|
7
7
|
import { VibrationalEditor } from './VibrationalEditor.tsx';
|
|
8
|
+
import type { IrHostPanel } from './irHostPanels.ts';
|
|
8
9
|
|
|
9
10
|
export interface IrEditorProps {
|
|
10
11
|
/**
|
|
@@ -32,10 +33,27 @@ export interface IrEditorProps {
|
|
|
32
33
|
*/
|
|
33
34
|
mode?: IrMode;
|
|
34
35
|
/**
|
|
35
|
-
* The side panels open to begin with
|
|
36
|
+
* The side panels open to begin with: the viewer's own — `'spectra'`,
|
|
37
|
+
* `'bands'`, `'metadata'` — or the id of one of `panels`. An id no panel
|
|
38
|
+
* answers to is ignored.
|
|
36
39
|
* @default DEFAULT_SIDE_PANELS
|
|
37
40
|
*/
|
|
38
|
-
defaultPanelIds?:
|
|
41
|
+
defaultPanelIds?: readonly IrPanelId[];
|
|
42
|
+
/**
|
|
43
|
+
* Panels the host adds to the viewer's own — a structure to predict a
|
|
44
|
+
* spectrum from, say. Their icons come first in the activity bar, in the
|
|
45
|
+
* order given, and each then behaves as a built-in panel does: toggled on its
|
|
46
|
+
* own, stacked in the same column with a share of its height, folded and
|
|
47
|
+
* closed from its header.
|
|
48
|
+
* @default []
|
|
49
|
+
*/
|
|
50
|
+
panels?: readonly IrHostPanel[];
|
|
51
|
+
/**
|
|
52
|
+
* The plot was clicked at this wavenumber (a press that did not travel, i.e.
|
|
53
|
+
* not a zoom drag), with the spectrum selected at that moment.
|
|
54
|
+
* @default undefined
|
|
55
|
+
*/
|
|
56
|
+
onPlotClick?: (click: IrPlotClick) => void;
|
|
39
57
|
/**
|
|
40
58
|
* The handle a host drives the viewer through: take these spectra, frame this
|
|
41
59
|
* wavenumber, select that one.
|
package/src/ir/ui/IrShell.tsx
CHANGED
|
@@ -7,11 +7,9 @@ import { useFigureDownload } from '../../download/ui/useFigureDownload.tsx';
|
|
|
7
7
|
import { PanelRail } from '../../panel/ui/PanelRail.tsx';
|
|
8
8
|
import type { IrBand } from '../core/irBand.ts';
|
|
9
9
|
import type { IrCommandHandlers } from '../core/irCommands.ts';
|
|
10
|
-
import type { IrEditorHandle } from '../core/irEditorApi.ts';
|
|
10
|
+
import type { IrEditorHandle, IrPlotClick } from '../core/irEditorApi.ts';
|
|
11
11
|
import { otherIrMode } from '../core/irMode.ts';
|
|
12
|
-
import { irSidePanels } from '../core/irSidePanels.ts';
|
|
13
12
|
import type { IrSpectrum } from '../core/irSpectrum.ts';
|
|
14
|
-
import { DEFAULT_SIDE_PANEL } from '../core/irState.ts';
|
|
15
13
|
import { irCommandOffered } from '../core/irTechniqueCommands.ts';
|
|
16
14
|
|
|
17
15
|
import { IrAboutDialog } from './IrAboutDialog.tsx';
|
|
@@ -21,9 +19,11 @@ import { IrDocumentationDialog } from './IrDocumentationDialog.tsx';
|
|
|
21
19
|
import { IrHeader } from './IrHeader.tsx';
|
|
22
20
|
import { IrSidePanel } from './IrSidePanel.tsx';
|
|
23
21
|
import { IrToolbar } from './IrToolbar.tsx';
|
|
22
|
+
import type { IrHostPanel } from './irHostPanels.ts';
|
|
24
23
|
import { useIrActions, useIrEditorState } from './irStateContext.ts';
|
|
25
24
|
import { useIrHandle } from './useIrHandle.ts';
|
|
26
25
|
import { useIrShortcuts } from './useIrShortcuts.ts';
|
|
26
|
+
import { useIrSide } from './useIrSide.ts';
|
|
27
27
|
import { useValueAxisZoom } from './useValueAxisZoom.ts';
|
|
28
28
|
|
|
29
29
|
export interface IrShellProps {
|
|
@@ -32,6 +32,13 @@ export interface IrShellProps {
|
|
|
32
32
|
* @default undefined
|
|
33
33
|
*/
|
|
34
34
|
handle?: Ref<IrEditorHandle>;
|
|
35
|
+
/** The panels the host adds to the viewer's own, ahead of them. */
|
|
36
|
+
panels: readonly IrHostPanel[];
|
|
37
|
+
/**
|
|
38
|
+
* Told of a click on the plot, with the spectrum selected at that moment.
|
|
39
|
+
* @default undefined
|
|
40
|
+
*/
|
|
41
|
+
onPlotClick?: (click: IrPlotClick) => void;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
/**
|
|
@@ -49,12 +56,13 @@ export interface IrShellProps {
|
|
|
49
56
|
* @returns The screen.
|
|
50
57
|
*/
|
|
51
58
|
export function IrShell(props: IrShellProps) {
|
|
52
|
-
const { handle } = props;
|
|
59
|
+
const { handle, panels, onPlotClick } = props;
|
|
53
60
|
|
|
54
61
|
const { state, visibleSpectra, selectedSpectrum } = useIrEditorState();
|
|
55
62
|
const actions = useIrActions();
|
|
56
63
|
const { toggle: toggleFullScreen } = useFullscreen();
|
|
57
64
|
const { openPanelIds, tool } = state.view;
|
|
65
|
+
const side = useIrSide(panels);
|
|
58
66
|
const { mode, pickBands, showAssignments, technique } = state.settings;
|
|
59
67
|
|
|
60
68
|
const [isAboutOpen, setIsAboutOpen] = useState(false);
|
|
@@ -122,20 +130,6 @@ export function IrShell(props: IrShellProps) {
|
|
|
122
130
|
useIrShortcuts(root, commands);
|
|
123
131
|
useIrHandle(handle);
|
|
124
132
|
|
|
125
|
-
/**
|
|
126
|
-
* Open or close the side, as the splitter is dragged shut and back open.
|
|
127
|
-
* @param open - Whether the side is now open.
|
|
128
|
-
*/
|
|
129
|
-
function setSideOpen(open: boolean): void {
|
|
130
|
-
if (!open) {
|
|
131
|
-
for (const panelId of openPanelIds) actions.togglePanel(panelId);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
// Dragging the splitter back open must land on something, or it opens on an
|
|
135
|
-
// empty column and reads as broken.
|
|
136
|
-
if (openPanelIds.length === 0) actions.togglePanel(DEFAULT_SIDE_PANEL);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
133
|
return (
|
|
140
134
|
<IrCommandProvider handlers={commands} technique={technique}>
|
|
141
135
|
{/* `tabIndex` so a click anywhere in the viewer makes this the target the
|
|
@@ -156,23 +150,28 @@ export function IrShell(props: IrShellProps) {
|
|
|
156
150
|
direction="horizontal"
|
|
157
151
|
controlledSide="end"
|
|
158
152
|
defaultSize="360px"
|
|
159
|
-
open={
|
|
160
|
-
onOpenChange={
|
|
153
|
+
open={side.isOpen}
|
|
154
|
+
onOpenChange={side.setOpen}
|
|
161
155
|
>
|
|
162
156
|
<IrCanvas
|
|
163
157
|
highlight={highlight}
|
|
164
158
|
onHighlight={setHighlight}
|
|
165
159
|
chartId={chartId}
|
|
160
|
+
onPlotClick={onPlotClick}
|
|
166
161
|
/>
|
|
167
162
|
|
|
168
|
-
<IrSidePanel
|
|
163
|
+
<IrSidePanel
|
|
164
|
+
panels={panels}
|
|
165
|
+
highlight={highlight}
|
|
166
|
+
onHighlight={setHighlight}
|
|
167
|
+
/>
|
|
169
168
|
</SplitPane>
|
|
170
169
|
|
|
171
170
|
{/* Outside the split, so the icons stay put against the right edge
|
|
172
171
|
while the panel beside them is resized or closed. */}
|
|
173
172
|
<div style={railStyle}>
|
|
174
173
|
<PanelRail
|
|
175
|
-
panels={
|
|
174
|
+
panels={side.panels}
|
|
176
175
|
openIds={openPanelIds}
|
|
177
176
|
onToggle={actions.togglePanel}
|
|
178
177
|
/>
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { panelStyle } from '../../panel/core/panelStyles.ts';
|
|
1
4
|
import { SidePanelStack } from '../../panel/ui/SidePanelStack.tsx';
|
|
2
5
|
import type { IrBand } from '../core/irBand.ts';
|
|
3
6
|
import type { IrSidePanelId } from '../core/irSidePanels.ts';
|
|
4
|
-
import { irSidePanels } from '../core/irSidePanels.ts';
|
|
5
7
|
|
|
6
8
|
import { BandsPanel } from './BandsPanel.tsx';
|
|
7
9
|
import { MetadataPanel } from './MetadataPanel.tsx';
|
|
8
10
|
import { SpectraPanel } from './SpectraPanel.tsx';
|
|
11
|
+
import type { IrHostPanel } from './irHostPanels.ts';
|
|
12
|
+
import { irStackPanels, isIrHostPanel } from './irHostPanels.ts';
|
|
9
13
|
import { useIrActions, useIrEditorState } from './irStateContext.ts';
|
|
10
14
|
|
|
11
15
|
export interface IrSidePanelProps {
|
|
16
|
+
/**
|
|
17
|
+
* The panels the host adds to the viewer's own, stacked above them in the
|
|
18
|
+
* order given.
|
|
19
|
+
* @default []
|
|
20
|
+
*/
|
|
21
|
+
panels?: readonly IrHostPanel[];
|
|
12
22
|
/**
|
|
13
23
|
* The band the pointer is resting on.
|
|
14
24
|
* @default null
|
|
@@ -29,28 +39,41 @@ export interface IrSidePanelProps {
|
|
|
29
39
|
* bands are is one question asked of two panels. The header carries the close
|
|
30
40
|
* button and nothing else — a panel's own actions are a toolbar inside its body,
|
|
31
41
|
* so they travel with it.
|
|
42
|
+
*
|
|
43
|
+
* A host's panel is stacked like the viewer's own, and its body is laid out in
|
|
44
|
+
* the same column a built-in panel fills, so it takes its share of the height
|
|
45
|
+
* and scrolls within it rather than pushing the stack.
|
|
32
46
|
* @param props - Component props.
|
|
33
47
|
* @returns The panel stack.
|
|
34
48
|
*/
|
|
35
49
|
export function IrSidePanel(props: IrSidePanelProps) {
|
|
36
|
-
const {
|
|
50
|
+
const {
|
|
51
|
+
panels: hostPanels = NO_PANELS,
|
|
52
|
+
highlight = null,
|
|
53
|
+
onHighlight,
|
|
54
|
+
} = props;
|
|
37
55
|
const { state } = useIrEditorState();
|
|
38
56
|
const actions = useIrActions();
|
|
39
57
|
const { openPanelIds } = state.view;
|
|
58
|
+
const panels = useMemo(() => irStackPanels(hostPanels), [hostPanels]);
|
|
40
59
|
|
|
41
60
|
return (
|
|
42
61
|
<SidePanelStack
|
|
43
|
-
panels={
|
|
62
|
+
panels={panels}
|
|
44
63
|
openPanelIds={openPanelIds}
|
|
45
64
|
onClose={actions.togglePanel}
|
|
46
65
|
>
|
|
47
|
-
{(panel) =>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
{(panel) =>
|
|
67
|
+
isIrHostPanel(panel) ? (
|
|
68
|
+
<div style={panelStyle}>{panel.content}</div>
|
|
69
|
+
) : (
|
|
70
|
+
<PanelBody
|
|
71
|
+
panelId={panel.id}
|
|
72
|
+
highlight={highlight}
|
|
73
|
+
onHighlight={onHighlight}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
54
77
|
</SidePanelStack>
|
|
55
78
|
);
|
|
56
79
|
}
|
|
@@ -76,3 +99,6 @@ function PanelBody(props: PanelBodyProps) {
|
|
|
76
99
|
if (panelId === 'metadata') return <MetadataPanel />;
|
|
77
100
|
return <BandsPanel highlight={highlight} onHighlight={onHighlight} />;
|
|
78
101
|
}
|
|
102
|
+
|
|
103
|
+
/** What a stack the host adds nothing to holds, kept stable for the memo. */
|
|
104
|
+
const NO_PANELS: readonly IrHostPanel[] = [];
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Ref } from 'react';
|
|
2
2
|
|
|
3
|
-
import type { IrEditorHandle } from '../core/irEditorApi.ts';
|
|
4
|
-
import type {
|
|
3
|
+
import type { IrEditorHandle, IrPlotClick } from '../core/irEditorApi.ts';
|
|
4
|
+
import type { IrPanelId } from '../core/irSidePanels.ts';
|
|
5
5
|
import type { IrSpectrum } from '../core/irSpectrum.ts';
|
|
6
6
|
|
|
7
7
|
import { VibrationalEditor } from './VibrationalEditor.tsx';
|
|
8
|
+
import type { IrHostPanel } from './irHostPanels.ts';
|
|
8
9
|
|
|
9
10
|
/** The handle a host drives a Raman viewer through: the infrared one's. */
|
|
10
11
|
export type RamanEditorHandle = IrEditorHandle;
|
|
@@ -25,10 +26,27 @@ export interface RamanEditorProps {
|
|
|
25
26
|
*/
|
|
26
27
|
onChange?: (spectra: IrSpectrum[]) => void;
|
|
27
28
|
/**
|
|
28
|
-
* The side panels open to begin with
|
|
29
|
+
* The side panels open to begin with: the viewer's own — `'spectra'`,
|
|
30
|
+
* `'bands'`, `'metadata'` — or the id of one of `panels`. An id no panel
|
|
31
|
+
* answers to is ignored.
|
|
29
32
|
* @default DEFAULT_SIDE_PANELS
|
|
30
33
|
*/
|
|
31
|
-
defaultPanelIds?:
|
|
34
|
+
defaultPanelIds?: readonly IrPanelId[];
|
|
35
|
+
/**
|
|
36
|
+
* Panels the host adds to the viewer's own. Their icons come first in the
|
|
37
|
+
* activity bar, in the order given, and each then behaves as a built-in panel
|
|
38
|
+
* does: toggled on its own, stacked in the same column with a share of its
|
|
39
|
+
* height, folded and closed from its header.
|
|
40
|
+
* @default []
|
|
41
|
+
*/
|
|
42
|
+
panels?: readonly IrHostPanel[];
|
|
43
|
+
/**
|
|
44
|
+
* The plot was clicked at this Raman shift (a press that did not travel, i.e.
|
|
45
|
+
* not a zoom drag), with the spectrum selected at that moment. The shift is
|
|
46
|
+
* reported as `wavenumber`, the name both techniques share.
|
|
47
|
+
* @default undefined
|
|
48
|
+
*/
|
|
49
|
+
onPlotClick?: (click: IrPlotClick) => void;
|
|
32
50
|
/**
|
|
33
51
|
* The handle a host drives the viewer through: take these spectra, frame this
|
|
34
52
|
* Raman shift, select that one.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { Ref } from 'react';
|
|
2
2
|
import { RootLayout } from 'react-science/ui';
|
|
3
3
|
|
|
4
|
-
import type { IrEditorHandle } from '../core/irEditorApi.ts';
|
|
5
|
-
import type {
|
|
4
|
+
import type { IrEditorHandle, IrPlotClick } from '../core/irEditorApi.ts';
|
|
5
|
+
import type { IrPanelId } from '../core/irSidePanels.ts';
|
|
6
6
|
import type { IrMode, IrSpectrum } from '../core/irSpectrum.ts';
|
|
7
7
|
import type { IrTechnique } from '../core/irTechnique.ts';
|
|
8
8
|
|
|
9
9
|
import { IrShell } from './IrShell.tsx';
|
|
10
10
|
import { IrStateProvider } from './IrStateProvider.tsx';
|
|
11
|
+
import type { IrHostPanel } from './irHostPanels.ts';
|
|
11
12
|
import { useIrEditor } from './useIrEditor.ts';
|
|
12
13
|
|
|
13
14
|
export interface VibrationalEditorProps {
|
|
@@ -34,10 +35,23 @@ export interface VibrationalEditorProps {
|
|
|
34
35
|
*/
|
|
35
36
|
mode?: IrMode;
|
|
36
37
|
/**
|
|
37
|
-
* The side panels open to begin with.
|
|
38
|
+
* The side panels open to begin with, the viewer's own or the host's. An id
|
|
39
|
+
* no panel answers to is ignored.
|
|
38
40
|
* @default DEFAULT_SIDE_PANELS
|
|
39
41
|
*/
|
|
40
|
-
defaultPanelIds?:
|
|
42
|
+
defaultPanelIds?: readonly IrPanelId[];
|
|
43
|
+
/**
|
|
44
|
+
* Panels the host adds to the viewer's own: their icons come first in the
|
|
45
|
+
* activity bar, in the order given, and each behaves as a built-in panel does.
|
|
46
|
+
* @default []
|
|
47
|
+
*/
|
|
48
|
+
panels?: readonly IrHostPanel[];
|
|
49
|
+
/**
|
|
50
|
+
* The plot was clicked at this wavenumber (a press that did not travel, i.e.
|
|
51
|
+
* not a zoom drag), with the spectrum selected at that moment.
|
|
52
|
+
* @default undefined
|
|
53
|
+
*/
|
|
54
|
+
onPlotClick?: (click: IrPlotClick) => void;
|
|
41
55
|
/**
|
|
42
56
|
* The handle a host drives the viewer through.
|
|
43
57
|
* @default undefined
|
|
@@ -59,6 +73,8 @@ export function VibrationalEditor(props: VibrationalEditorProps) {
|
|
|
59
73
|
onChange,
|
|
60
74
|
mode,
|
|
61
75
|
defaultPanelIds,
|
|
76
|
+
panels = NO_PANELS,
|
|
77
|
+
onPlotClick,
|
|
62
78
|
ref,
|
|
63
79
|
} = props;
|
|
64
80
|
|
|
@@ -77,7 +93,7 @@ export function VibrationalEditor(props: VibrationalEditorProps) {
|
|
|
77
93
|
the backdrop white. Above the shell rather than inside it, so the shell
|
|
78
94
|
can ask whether it is full screen and offer the way out. */}
|
|
79
95
|
<RootLayout style={rootLayoutStyle}>
|
|
80
|
-
<IrShell handle={ref} />
|
|
96
|
+
<IrShell handle={ref} panels={panels} onPlotClick={onPlotClick} />
|
|
81
97
|
</RootLayout>
|
|
82
98
|
</IrStateProvider>
|
|
83
99
|
);
|
|
@@ -92,3 +108,6 @@ const rootLayoutStyle = { minHeight: 0 } as const;
|
|
|
92
108
|
|
|
93
109
|
/** What a viewer opens on when it is handed nothing, kept stable for the memo. */
|
|
94
110
|
const NO_SPECTRA: IrSpectrum[] = [];
|
|
111
|
+
|
|
112
|
+
/** What a viewer the host adds no panel to offers, kept stable for the memo. */
|
|
113
|
+
const NO_PANELS: readonly IrHostPanel[] = [];
|
package/src/ir/ui/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ export { createIrActions } from './irActions.ts';
|
|
|
47
47
|
export type { IrChartProps } from './irChartProps.ts';
|
|
48
48
|
export type { IrCommandContextValue } from './irCommandContext.tsx';
|
|
49
49
|
export { useIrCommand, useIrCommandProps } from './irCommandContext.tsx';
|
|
50
|
+
export type { IrHostPanel } from './irHostPanels.ts';
|
|
50
51
|
export { useIrActions, useIrEditorState } from './irStateContext.ts';
|
|
51
52
|
export type { IrEditorApi, UseIrEditorOptions } from './useIrEditor.ts';
|
|
52
53
|
export { useIrEditor } from './useIrEditor.ts';
|
package/src/ir/ui/irActions.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { Dispatch } from 'react';
|
|
10
10
|
|
|
11
11
|
import type { IrAction } from '../core/irReducer.ts';
|
|
12
|
-
import type {
|
|
12
|
+
import type { IrPanelId } from '../core/irSidePanels.ts';
|
|
13
13
|
import type { IrDomain, IrSpectrum } from '../core/irSpectrum.ts';
|
|
14
14
|
import type { IrSettings, IrTool, PartialIrState } from '../core/irState.ts';
|
|
15
15
|
|
|
@@ -35,8 +35,8 @@ export interface IrEditorActions {
|
|
|
35
35
|
resetDomain: () => void;
|
|
36
36
|
/** Run this tool on the next drag. */
|
|
37
37
|
setTool: (tool: IrTool) => void;
|
|
38
|
-
/** Open or close a side panel. */
|
|
39
|
-
togglePanel: (panelId:
|
|
38
|
+
/** Open or close a side panel, the viewer's own or one a host added. */
|
|
39
|
+
togglePanel: (panelId: IrPanelId) => void;
|
|
40
40
|
/** Say why something was refused, or that nothing is wrong any more. */
|
|
41
41
|
setError: (error: string | null) => void;
|
|
42
42
|
/** Change how the spectra are drawn and read. */
|
|
@@ -94,6 +94,13 @@ export interface IrChartProps {
|
|
|
94
94
|
* @default undefined
|
|
95
95
|
*/
|
|
96
96
|
onDomainChange?: (domain: IrDomain) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Told the wavenumber a click on the plot landed at: a press let go over the
|
|
99
|
+
* plot without travelling. The end of a drag is never one, nor is a press let
|
|
100
|
+
* go over the axis labels, which inverts to a value the chart is not drawing.
|
|
101
|
+
* @default undefined
|
|
102
|
+
*/
|
|
103
|
+
onPlotClick?: (wavenumber: number) => void;
|
|
97
104
|
/**
|
|
98
105
|
* What a drag across the plot asks for: the wavenumber axis alone, or exactly
|
|
99
106
|
* the rectangle it sweeps out. A viewer offering a square-zoom tool switches
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The panels a host adds to the viewer's own, and the one list both make.
|
|
3
|
+
*
|
|
4
|
+
* A host panel is a panel like any other once it is in the list: the activity
|
|
5
|
+
* bar and the stack read the same list, so it toggles, folds and closes
|
|
6
|
+
* exactly as the spectra or the bands do. The host brings the body and nothing
|
|
7
|
+
* else — the header, its close button and the place in the column are the
|
|
8
|
+
* viewer's, which is what keeps every header reading the same.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { IconName } from '@blueprintjs/core';
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
|
|
14
|
+
import { irSidePanels } from '../core/irSidePanels.ts';
|
|
15
|
+
|
|
16
|
+
/** A panel the host adds to the editor's own stack. */
|
|
17
|
+
export interface IrHostPanel {
|
|
18
|
+
/**
|
|
19
|
+
* Its identity in the activity bar and in `defaultPanelIds`; never a
|
|
20
|
+
* built-in id. One that is, or that an earlier host panel already took, is
|
|
21
|
+
* left out: one icon cannot open two panels.
|
|
22
|
+
*/
|
|
23
|
+
id: string;
|
|
24
|
+
/** What its header and its activity-bar item say. */
|
|
25
|
+
title: string;
|
|
26
|
+
/** Its glyph in the activity bar (a Blueprint IconName). */
|
|
27
|
+
icon: IconName;
|
|
28
|
+
/**
|
|
29
|
+
* Its body. It brings its own toolbar as first row: the header carries the
|
|
30
|
+
* close button only.
|
|
31
|
+
*
|
|
32
|
+
* It is laid out in a column filling the panel's share of the height, so a
|
|
33
|
+
* toolbar row in `panelToolbarStyle` followed by a body in `panelBodyStyle`,
|
|
34
|
+
* both from `react-cheminfo/core`, keeps the toolbar in place while a tall
|
|
35
|
+
* body scrolls under it. It is rendered inside the viewer, so a component in
|
|
36
|
+
* it reaches the viewer it stands in through `useIrEditorState` and
|
|
37
|
+
* `useIrActions` — to overlay a predicted spectrum, say.
|
|
38
|
+
*/
|
|
39
|
+
content: ReactNode;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** One panel of the side: one of the viewer's own, or one a host added. */
|
|
43
|
+
export type IrStackPanel = (typeof irSidePanels)[number] | IrHostPanel;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Every panel the side offers, in the order the activity bar stacks them: the
|
|
47
|
+
* host's first, in the order given, then the viewer's own.
|
|
48
|
+
* @param hostPanels - What the host adds.
|
|
49
|
+
* @returns The panels; the viewer's own list itself when the host adds none.
|
|
50
|
+
*/
|
|
51
|
+
export function irStackPanels(
|
|
52
|
+
hostPanels: readonly IrHostPanel[],
|
|
53
|
+
): readonly IrStackPanel[] {
|
|
54
|
+
if (hostPanels.length === 0) return irSidePanels;
|
|
55
|
+
const taken = new Set<string>(BUILT_IN_IDS);
|
|
56
|
+
const panels: IrStackPanel[] = [];
|
|
57
|
+
for (const panel of hostPanels) {
|
|
58
|
+
if (taken.has(panel.id)) continue;
|
|
59
|
+
taken.add(panel.id);
|
|
60
|
+
panels.push(panel);
|
|
61
|
+
}
|
|
62
|
+
panels.push(...irSidePanels);
|
|
63
|
+
return panels;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether a panel of the side is one a host added, whose body it brings.
|
|
68
|
+
* @param panel - The panel.
|
|
69
|
+
* @returns True for a host's panel.
|
|
70
|
+
*/
|
|
71
|
+
export function isIrHostPanel(panel: IrStackPanel): panel is IrHostPanel {
|
|
72
|
+
return 'content' in panel;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The ids no host panel may take. */
|
|
76
|
+
const BUILT_IN_IDS: readonly string[] = irSidePanels.map((panel) => panel.id);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The side of the viewer: the panels it offers, whether any of them is open,
|
|
3
|
+
* and what dragging the splitter shut and back open does to them.
|
|
4
|
+
*
|
|
5
|
+
* A hook of its own beside the shell, because the shell lays the side out and
|
|
6
|
+
* this decides what is on it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
|
|
11
|
+
import { DEFAULT_SIDE_PANEL } from '../core/irState.ts';
|
|
12
|
+
|
|
13
|
+
import type { IrHostPanel, IrStackPanel } from './irHostPanels.ts';
|
|
14
|
+
import { irStackPanels } from './irHostPanels.ts';
|
|
15
|
+
import { useIrActions, useIrEditorState } from './irStateContext.ts';
|
|
16
|
+
|
|
17
|
+
/** The side, as the shell lays it out. */
|
|
18
|
+
export interface IrSide {
|
|
19
|
+
/** Every panel on offer, in the order their icons are stacked. */
|
|
20
|
+
panels: readonly IrStackPanel[];
|
|
21
|
+
/** Whether a panel on offer is open, which is whether the side is. */
|
|
22
|
+
isOpen: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Open or close the side, as the splitter is dragged shut and back open.
|
|
25
|
+
* @param open - Whether the side is now open.
|
|
26
|
+
*/
|
|
27
|
+
setOpen: (open: boolean) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The side of the viewer this is called inside.
|
|
32
|
+
* @param hostPanels - The panels the host adds to the viewer's own.
|
|
33
|
+
* @returns The panels on offer, whether the side is open, and how to open it.
|
|
34
|
+
*/
|
|
35
|
+
export function useIrSide(hostPanels: readonly IrHostPanel[]): IrSide {
|
|
36
|
+
const { state } = useIrEditorState();
|
|
37
|
+
const actions = useIrActions();
|
|
38
|
+
const { openPanelIds } = state.view;
|
|
39
|
+
|
|
40
|
+
const panels = useMemo(() => irStackPanels(hostPanels), [hostPanels]);
|
|
41
|
+
// Read off the panels on offer rather than off the ids: an id no panel
|
|
42
|
+
// answers to opens nothing, and a side open on it alone is an empty column.
|
|
43
|
+
const isOpen = panels.some((panel) => openPanelIds.includes(panel.id));
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Open or close the side.
|
|
47
|
+
* @param open - Whether the side is now open.
|
|
48
|
+
*/
|
|
49
|
+
function setOpen(open: boolean): void {
|
|
50
|
+
if (!open) {
|
|
51
|
+
for (const panelId of openPanelIds) actions.togglePanel(panelId);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Dragging the splitter back open must land on something, or it opens on an
|
|
55
|
+
// empty column and reads as broken.
|
|
56
|
+
if (!isOpen) actions.togglePanel(DEFAULT_SIDE_PANEL);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { panels, isOpen, setOpen };
|
|
60
|
+
}
|