react-cheminfo 0.76.0 → 0.77.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 +141 -31
- package/lib/card/core/cardAddress.d.ts +19 -2
- package/lib/card/core/cardAddress.d.ts.map +1 -1
- package/lib/card/core/cardAddress.js +35 -2
- package/lib/card/core/cardAddress.js.map +1 -1
- package/lib/card/core/cardPageUrl.d.ts +7 -1
- package/lib/card/core/cardPageUrl.d.ts.map +1 -1
- package/lib/card/core/cardPageUrl.js +4 -2
- package/lib/card/core/cardPageUrl.js.map +1 -1
- package/lib/card/core/index.d.ts +1 -1
- package/lib/card/core/index.d.ts.map +1 -1
- package/lib/card/core/index.js +1 -1
- package/lib/card/core/index.js.map +1 -1
- package/lib/credits/core/credits.d.ts +30 -0
- package/lib/credits/core/credits.d.ts.map +1 -1
- package/lib/credits/core/credits.js +35 -0
- package/lib/credits/core/credits.js.map +1 -1
- package/lib/download/core/downloadFigure.d.ts +12 -1
- package/lib/download/core/downloadFigure.d.ts.map +1 -1
- package/lib/download/core/downloadFigure.js +21 -0
- package/lib/download/core/downloadFigure.js.map +1 -1
- package/lib/download/core/figureDpi.d.ts +59 -0
- package/lib/download/core/figureDpi.d.ts.map +1 -0
- package/lib/download/core/figureDpi.js +75 -0
- package/lib/download/core/figureDpi.js.map +1 -0
- package/lib/download/core/figurePng.d.ts +4 -1
- package/lib/download/core/figurePng.d.ts.map +1 -1
- package/lib/download/core/figurePng.js +11 -2
- package/lib/download/core/figurePng.js.map +1 -1
- package/lib/download/core/index.d.ts +4 -1
- package/lib/download/core/index.d.ts.map +1 -1
- package/lib/download/core/index.js +3 -1
- package/lib/download/core/index.js.map +1 -1
- package/lib/download/core/pngDpi.d.ts +22 -0
- package/lib/download/core/pngDpi.d.ts.map +1 -0
- package/lib/download/core/pngDpi.js +79 -0
- package/lib/download/core/pngDpi.js.map +1 -0
- package/lib/download/ui/FigureDownloadPanel.d.ts +13 -0
- package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
- package/lib/download/ui/FigureDownloadPanel.js +18 -34
- package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
- package/lib/download/ui/figureDownloadHint.d.ts +5 -0
- package/lib/download/ui/figureDownloadHint.d.ts.map +1 -1
- package/lib/download/ui/figureDownloadHint.js +8 -0
- package/lib/download/ui/figureDownloadHint.js.map +1 -1
- package/lib/download/ui/figureDownloadOptions.d.ts +84 -0
- package/lib/download/ui/figureDownloadOptions.d.ts.map +1 -0
- package/lib/download/ui/figureDownloadOptions.js +2 -0
- package/lib/download/ui/figureDownloadOptions.js.map +1 -0
- package/lib/download/ui/resolutionChoices.d.ts +27 -0
- package/lib/download/ui/resolutionChoices.d.ts.map +1 -0
- package/lib/download/ui/resolutionChoices.js +48 -0
- package/lib/download/ui/resolutionChoices.js.map +1 -0
- package/lib/download/ui/useFigureActions.d.ts +4 -1
- package/lib/download/ui/useFigureActions.d.ts.map +1 -1
- package/lib/download/ui/useFigureActions.js +17 -8
- package/lib/download/ui/useFigureActions.js.map +1 -1
- package/lib/download/ui/useFigureDownload.d.ts +2 -55
- package/lib/download/ui/useFigureDownload.d.ts.map +1 -1
- package/lib/download/ui/useFigureDownload.js +45 -13
- package/lib/download/ui/useFigureDownload.js.map +1 -1
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +14 -0
- 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.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +3 -0
- 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/locales/de.json +30 -1
- package/lib/locales/en.json +30 -1
- package/lib/locales/es.json +30 -1
- package/lib/locales/fr.json +30 -1
- package/lib/locales/it.json +30 -1
- package/lib/molecule3d/ui/Molecule3DStage.d.ts +4 -33
- package/lib/molecule3d/ui/Molecule3DStage.d.ts.map +1 -1
- package/lib/molecule3d/ui/Molecule3DStage.js +3 -37
- package/lib/molecule3d/ui/Molecule3DStage.js.map +1 -1
- package/lib/osiris/core/barGeometry.d.ts +42 -0
- package/lib/osiris/core/barGeometry.d.ts.map +1 -0
- package/lib/osiris/core/barGeometry.js +46 -0
- package/lib/osiris/core/barGeometry.js.map +1 -0
- package/lib/osiris/core/computeProperties.d.ts +42 -0
- package/lib/osiris/core/computeProperties.d.ts.map +1 -0
- package/lib/osiris/core/computeProperties.js +115 -0
- package/lib/osiris/core/computeProperties.js.map +1 -0
- package/lib/osiris/core/constants.d.ts +70 -0
- package/lib/osiris/core/constants.d.ts.map +1 -0
- package/lib/osiris/core/constants.js +99 -0
- package/lib/osiris/core/constants.js.map +1 -0
- package/lib/osiris/core/fitness.d.ts +32 -0
- package/lib/osiris/core/fitness.d.ts.map +1 -0
- package/lib/osiris/core/fitness.js +48 -0
- package/lib/osiris/core/fitness.js.map +1 -0
- package/lib/osiris/core/index.d.ts +29 -0
- package/lib/osiris/core/index.d.ts.map +1 -0
- package/lib/osiris/core/index.js +19 -0
- package/lib/osiris/core/index.js.map +1 -0
- package/lib/osiris/core/poolSize.d.ts +17 -0
- package/lib/osiris/core/poolSize.d.ts.map +1 -0
- package/lib/osiris/core/poolSize.js +22 -0
- package/lib/osiris/core/poolSize.js.map +1 -0
- package/lib/osiris/core/poolTypes.d.ts +140 -0
- package/lib/osiris/core/poolTypes.d.ts.map +1 -0
- package/lib/osiris/core/poolTypes.js +12 -0
- package/lib/osiris/core/poolTypes.js.map +1 -0
- package/lib/osiris/core/predictIdCode.d.ts +39 -0
- package/lib/osiris/core/predictIdCode.d.ts.map +1 -0
- package/lib/osiris/core/predictIdCode.js +54 -0
- package/lib/osiris/core/predictIdCode.js.map +1 -0
- package/lib/osiris/core/predictProtocol.d.ts +67 -0
- package/lib/osiris/core/predictProtocol.d.ts.map +1 -0
- package/lib/osiris/core/predictProtocol.js +29 -0
- package/lib/osiris/core/predictProtocol.js.map +1 -0
- package/lib/osiris/core/predictionPool.d.ts +23 -0
- package/lib/osiris/core/predictionPool.d.ts.map +1 -0
- package/lib/osiris/core/predictionPool.js +186 -0
- package/lib/osiris/core/predictionPool.js.map +1 -0
- package/lib/osiris/core/predictionQueue.d.ts +46 -0
- package/lib/osiris/core/predictionQueue.d.ts.map +1 -0
- package/lib/osiris/core/predictionQueue.js +57 -0
- package/lib/osiris/core/predictionQueue.js.map +1 -0
- package/lib/osiris/core/predictors.d.ts +62 -0
- package/lib/osiris/core/predictors.d.ts.map +1 -0
- package/lib/osiris/core/predictors.js +100 -0
- package/lib/osiris/core/predictors.js.map +1 -0
- package/lib/osiris/core/propertyKeys.d.ts +32 -0
- package/lib/osiris/core/propertyKeys.d.ts.map +1 -0
- package/lib/osiris/core/propertyKeys.js +44 -0
- package/lib/osiris/core/propertyKeys.js.map +1 -0
- package/lib/osiris/core/riskAppearance.d.ts +60 -0
- package/lib/osiris/core/riskAppearance.d.ts.map +1 -0
- package/lib/osiris/core/riskAppearance.js +59 -0
- package/lib/osiris/core/riskAppearance.js.map +1 -0
- package/lib/osiris/core/riskDetail.d.ts +22 -0
- package/lib/osiris/core/riskDetail.d.ts.map +1 -0
- package/lib/osiris/core/riskDetail.js +86 -0
- package/lib/osiris/core/riskDetail.js.map +1 -0
- package/lib/osiris/core/riskDetailRequest.d.ts +31 -0
- package/lib/osiris/core/riskDetailRequest.d.ts.map +1 -0
- package/lib/osiris/core/riskDetailRequest.js +49 -0
- package/lib/osiris/core/riskDetailRequest.js.map +1 -0
- package/lib/osiris/core/riskFindings.d.ts +26 -0
- package/lib/osiris/core/riskFindings.d.ts.map +1 -0
- package/lib/osiris/core/riskFindings.js +79 -0
- package/lib/osiris/core/riskFindings.js.map +1 -0
- package/lib/osiris/core/runPredictionJob.d.ts +20 -0
- package/lib/osiris/core/runPredictionJob.d.ts.map +1 -0
- package/lib/osiris/core/runPredictionJob.js +43 -0
- package/lib/osiris/core/runPredictionJob.js.map +1 -0
- package/lib/osiris/core/scales.d.ts +70 -0
- package/lib/osiris/core/scales.d.ts.map +1 -0
- package/lib/osiris/core/scales.js +185 -0
- package/lib/osiris/core/scales.js.map +1 -0
- package/lib/osiris/core/types.d.ts +91 -0
- package/lib/osiris/core/types.d.ts.map +1 -0
- package/lib/osiris/core/types.js +19 -0
- package/lib/osiris/core/types.js.map +1 -0
- package/lib/osiris/core/valuation.d.ts +28 -0
- package/lib/osiris/core/valuation.d.ts.map +1 -0
- package/lib/osiris/core/valuation.js +39 -0
- package/lib/osiris/core/valuation.js.map +1 -0
- package/lib/osiris/ui/PropertyBar.d.ts +27 -0
- package/lib/osiris/ui/PropertyBar.d.ts.map +1 -0
- package/lib/osiris/ui/PropertyBar.js +27 -0
- package/lib/osiris/ui/PropertyBar.js.map +1 -0
- package/lib/osiris/ui/PropertyPanel.d.ts +91 -0
- package/lib/osiris/ui/PropertyPanel.d.ts.map +1 -0
- package/lib/osiris/ui/PropertyPanel.js +77 -0
- package/lib/osiris/ui/PropertyPanel.js.map +1 -0
- package/lib/osiris/ui/PropertyRows.d.ts +40 -0
- package/lib/osiris/ui/PropertyRows.d.ts.map +1 -0
- package/lib/osiris/ui/PropertyRows.js +23 -0
- package/lib/osiris/ui/PropertyRows.js.map +1 -0
- package/lib/osiris/ui/RiskFindings.d.ts +43 -0
- package/lib/osiris/ui/RiskFindings.d.ts.map +1 -0
- package/lib/osiris/ui/RiskFindings.js +51 -0
- package/lib/osiris/ui/RiskFindings.js.map +1 -0
- package/lib/osiris/ui/RiskPanel.d.ts +46 -0
- package/lib/osiris/ui/RiskPanel.d.ts.map +1 -0
- package/lib/osiris/ui/RiskPanel.js +32 -0
- package/lib/osiris/ui/RiskPanel.js.map +1 -0
- package/lib/osiris/ui/RiskSquare.d.ts +51 -0
- package/lib/osiris/ui/RiskSquare.d.ts.map +1 -0
- package/lib/osiris/ui/RiskSquare.js +23 -0
- package/lib/osiris/ui/RiskSquare.js.map +1 -0
- package/lib/osiris/ui/index.d.ts +15 -0
- package/lib/osiris/ui/index.d.ts.map +1 -0
- package/lib/osiris/ui/index.js +8 -0
- package/lib/osiris/ui/index.js.map +1 -0
- package/lib/osiris/ui/usePredictions.d.ts +81 -0
- package/lib/osiris/ui/usePredictions.d.ts.map +1 -0
- package/lib/osiris/ui/usePredictions.js +102 -0
- package/lib/osiris/ui/usePredictions.js.map +1 -0
- package/lib/osiris-ui.d.ts +11 -0
- package/lib/osiris-ui.d.ts.map +1 -0
- package/lib/osiris-ui.js +11 -0
- package/lib/osiris-ui.js.map +1 -0
- package/lib/osiris.d.ts +17 -0
- package/lib/osiris.d.ts.map +1 -0
- package/lib/osiris.js +17 -0
- package/lib/osiris.js.map +1 -0
- package/lib/panel/ui/FilterInput.d.ts.map +1 -1
- package/lib/panel/ui/FilterInput.js +3 -1
- package/lib/panel/ui/FilterInput.js.map +1 -1
- package/lib/panel/ui/SidePanelItem.d.ts +39 -0
- package/lib/panel/ui/SidePanelItem.d.ts.map +1 -0
- package/lib/panel/ui/SidePanelItem.js +63 -0
- package/lib/panel/ui/SidePanelItem.js.map +1 -0
- package/lib/panel/ui/SidePanelStack.d.ts +11 -10
- package/lib/panel/ui/SidePanelStack.d.ts.map +1 -1
- package/lib/panel/ui/SidePanelStack.js +22 -15
- package/lib/panel/ui/SidePanelStack.js.map +1 -1
- package/lib/panel/ui/SpectrumColorSwatch.d.ts.map +1 -1
- package/lib/panel/ui/SpectrumColorSwatch.js +4 -2
- package/lib/panel/ui/SpectrumColorSwatch.js.map +1 -1
- package/lib/panel/ui/usePanelFolds.d.ts +35 -0
- package/lib/panel/ui/usePanelFolds.d.ts.map +1 -0
- package/lib/panel/ui/usePanelFolds.js +73 -0
- package/lib/panel/ui/usePanelFolds.js.map +1 -0
- package/lib/shared/ui/FullscreenStage.d.ts +43 -0
- package/lib/shared/ui/FullscreenStage.d.ts.map +1 -0
- package/lib/shared/ui/FullscreenStage.js +38 -0
- package/lib/shared/ui/FullscreenStage.js.map +1 -0
- package/lib/shared/ui/canFillScreen.d.ts +7 -0
- package/lib/shared/ui/canFillScreen.d.ts.map +1 -0
- package/lib/shared/ui/canFillScreen.js +9 -0
- package/lib/shared/ui/canFillScreen.js.map +1 -0
- package/lib/shared/ui/index.d.ts +3 -0
- package/lib/shared/ui/index.d.ts.map +1 -1
- package/lib/shared/ui/index.js +2 -0
- package/lib/shared/ui/index.js.map +1 -1
- package/lib/split/ui/splitPanes.d.ts +3 -3
- package/lib/split/ui/splitPanes.js +1 -1
- package/lib/structure/core/structureNotations.d.ts +8 -1
- package/lib/structure/core/structureNotations.d.ts.map +1 -1
- package/lib/structure/core/structureNotations.js +14 -8
- package/lib/structure/core/structureNotations.js.map +1 -1
- package/lib/structure/ui/StructureExportPanel.d.ts +8 -0
- package/lib/structure/ui/StructureExportPanel.d.ts.map +1 -1
- package/lib/structure/ui/StructureExportPanel.js +9 -4
- package/lib/structure/ui/StructureExportPanel.js.map +1 -1
- package/lib/structure/ui/index.d.ts +1 -0
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js.map +1 -1
- package/package.json +4 -1
- package/src/card/core/cardAddress.ts +39 -3
- package/src/card/core/cardPageUrl.ts +10 -3
- package/src/card/core/index.ts +7 -1
- package/src/credits/core/credits.ts +40 -0
- package/src/download/core/downloadFigure.ts +26 -1
- package/src/download/core/figureDpi.ts +94 -0
- package/src/download/core/figurePng.ts +11 -2
- package/src/download/core/index.ts +13 -1
- package/src/download/core/pngDpi.ts +84 -0
- package/src/download/ui/FigureDownloadPanel.tsx +41 -51
- package/src/download/ui/figureDownloadHint.ts +13 -0
- package/src/download/ui/figureDownloadOptions.ts +85 -0
- package/src/download/ui/resolutionChoices.ts +67 -0
- package/src/download/ui/useFigureActions.ts +24 -9
- package/src/download/ui/useFigureDownload.tsx +57 -71
- package/src/ecosystem/core/sites.ts +14 -0
- package/src/ecosystem/core/types.ts +2 -1
- package/src/ecosystem/ui/glyphs.tsx +20 -0
- package/src/locales/de.json +30 -1
- package/src/locales/en.json +30 -1
- package/src/locales/es.json +30 -1
- package/src/locales/fr.json +30 -1
- package/src/locales/it.json +30 -1
- package/src/molecule3d/ui/Molecule3DStage.tsx +4 -88
- package/src/osiris/core/barGeometry.ts +74 -0
- package/src/osiris/core/computeProperties.ts +175 -0
- package/src/osiris/core/constants.ts +110 -0
- package/src/osiris/core/fitness.ts +59 -0
- package/src/osiris/core/index.ts +78 -0
- package/src/osiris/core/poolSize.ts +24 -0
- package/src/osiris/core/poolTypes.ts +140 -0
- package/src/osiris/core/predictIdCode.ts +69 -0
- package/src/osiris/core/predictProtocol.ts +78 -0
- package/src/osiris/core/predictionPool.ts +237 -0
- package/src/osiris/core/predictionQueue.ts +89 -0
- package/src/osiris/core/predictors.ts +142 -0
- package/src/osiris/core/propertyKeys.ts +54 -0
- package/src/osiris/core/riskAppearance.ts +86 -0
- package/src/osiris/core/riskDetail.ts +120 -0
- package/src/osiris/core/riskDetailRequest.ts +64 -0
- package/src/osiris/core/riskFindings.ts +92 -0
- package/src/osiris/core/runPredictionJob.ts +49 -0
- package/src/osiris/core/scales.ts +236 -0
- package/src/osiris/core/types.ts +103 -0
- package/src/osiris/core/valuation.ts +44 -0
- package/src/osiris/ui/PropertyBar.tsx +77 -0
- package/src/osiris/ui/PropertyPanel.tsx +227 -0
- package/src/osiris/ui/PropertyRows.tsx +92 -0
- package/src/osiris/ui/RiskFindings.tsx +137 -0
- package/src/osiris/ui/RiskPanel.tsx +81 -0
- package/src/osiris/ui/RiskSquare.tsx +108 -0
- package/src/osiris/ui/index.ts +17 -0
- package/src/osiris/ui/usePredictions.ts +194 -0
- package/src/osiris-ui.ts +11 -0
- package/src/osiris.ts +17 -0
- package/src/panel/ui/FilterInput.tsx +4 -1
- package/src/panel/ui/SidePanelItem.tsx +162 -0
- package/src/panel/ui/SidePanelStack.tsx +29 -36
- package/src/panel/ui/SpectrumColorSwatch.tsx +5 -3
- package/src/panel/ui/usePanelFolds.ts +103 -0
- package/src/shared/ui/FullscreenStage.tsx +96 -0
- package/src/shared/ui/canFillScreen.ts +8 -0
- package/src/shared/ui/index.ts +6 -0
- package/src/split/ui/splitPanes.tsx +4 -4
- package/src/structure/core/structureNotations.ts +25 -8
- package/src/structure/ui/StructureExportPanel.tsx +23 -4
- package/src/structure/ui/index.ts +4 -0
- package/styles/osiris.css +339 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { ActivityBarItemProps } from 'react-science/ui';
|
|
3
|
-
import { Accordion, AccordionProvider
|
|
3
|
+
import { Accordion, AccordionProvider } from 'react-science/ui';
|
|
4
|
+
|
|
5
|
+
import { SidePanelItem } from './SidePanelItem.tsx';
|
|
6
|
+
import { usePanelFolds } from './usePanelFolds.ts';
|
|
4
7
|
|
|
5
8
|
/** What a rail reads about one panel, wherever that rail is drawn. */
|
|
6
9
|
export interface PanelDescriptor {
|
|
@@ -44,21 +47,22 @@ export interface SidePanelStackProps<TPanel extends PanelDescriptor> {
|
|
|
44
47
|
* They are drawn in the order the rail stacks their icons rather than the order
|
|
45
48
|
* they were switched on, so a panel always comes back where it was.
|
|
46
49
|
*
|
|
47
|
-
* The header carries the shell's own
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* it
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
* The header carries the shell's own gestures and nothing about what the panel
|
|
51
|
+
* holds: focus, which folds every other panel away and unfolds them again;
|
|
52
|
+
* filling the screen with the panel, where the browser can; the chevron that
|
|
53
|
+
* folds it away; and the cross that closes it. What a panel switches on and off
|
|
54
|
+
* is a toolbar at the top of its own body, so it travels with the panel when it
|
|
55
|
+
* is folded, reordered or lent to another editor, and every header in every
|
|
56
|
+
* editor reads the same — which is the reason this is one component rather
|
|
57
|
+
* than one per editor.
|
|
53
58
|
*
|
|
54
59
|
* The chevron is there because nothing else says which panels are folded. The
|
|
55
60
|
* accordion draws every header identically and hides only the body, so a side
|
|
56
61
|
* of four closed panels and a side of four open ones differ by white space, and
|
|
57
62
|
* a reader looking for a panel that is already open reaches for its icon and
|
|
58
|
-
* closes it.
|
|
59
|
-
*
|
|
60
|
-
* does not
|
|
61
|
-
* would be an affordance that lies.
|
|
63
|
+
* closes it. Focus is a button as well as a shift-click because a modifier on a
|
|
64
|
+
* header is a gesture nobody finds, and it undoes itself, which a shift-click
|
|
65
|
+
* does not.
|
|
62
66
|
* @param props - Component props.
|
|
63
67
|
* @returns The stack.
|
|
64
68
|
*/
|
|
@@ -67,41 +71,30 @@ export function SidePanelStack<TPanel extends PanelDescriptor>(
|
|
|
67
71
|
) {
|
|
68
72
|
const { panels, openPanelIds, onClose, children } = props;
|
|
69
73
|
const open = panels.filter((panel) => openPanelIds.includes(panel.id));
|
|
74
|
+
const folds = usePanelFolds(open.map((panel) => panel.id));
|
|
70
75
|
|
|
71
76
|
return (
|
|
72
77
|
<AccordionProvider>
|
|
73
78
|
<Accordion>
|
|
74
79
|
{open.map((panel) => (
|
|
75
|
-
<
|
|
80
|
+
<SidePanelItem
|
|
76
81
|
key={panel.id}
|
|
77
82
|
id={panel.id}
|
|
78
83
|
title={panel.title}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}}
|
|
91
|
-
onClick={() => controls.toggle()}
|
|
92
|
-
/>
|
|
93
|
-
<Button
|
|
94
|
-
variant="minimal"
|
|
95
|
-
icon="cross"
|
|
96
|
-
tooltipProps={{ content: 'Close this panel' }}
|
|
97
|
-
aria-label={`Close the ${panel.title.toLowerCase()} panel`}
|
|
98
|
-
onClick={() => onClose(panel.id)}
|
|
99
|
-
/>
|
|
100
|
-
</>
|
|
101
|
-
)}
|
|
84
|
+
isOpen={folds.isOpen(panel.id)}
|
|
85
|
+
onOpenChange={(isOpen) => folds.setOpen(panel.id, isOpen)}
|
|
86
|
+
focus={
|
|
87
|
+
open.length > 1
|
|
88
|
+
? {
|
|
89
|
+
active: folds.focused === panel.id,
|
|
90
|
+
toggle: () => folds.toggleFocus(panel.id),
|
|
91
|
+
}
|
|
92
|
+
: undefined
|
|
93
|
+
}
|
|
94
|
+
onClose={() => onClose(panel.id)}
|
|
102
95
|
>
|
|
103
96
|
{children(panel)}
|
|
104
|
-
</
|
|
97
|
+
</SidePanelItem>
|
|
105
98
|
))}
|
|
106
99
|
</Accordion>
|
|
107
100
|
</AccordionProvider>
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
EXTRA_SPECTRUM_COLORS,
|
|
6
6
|
SPECTRUM_COLORS,
|
|
7
7
|
} from '../../chart/core/spectrumColor.ts';
|
|
8
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
8
9
|
|
|
9
10
|
export interface SpectrumColorSwatchProps {
|
|
10
11
|
/** The colour the spectrum is drawn in. */
|
|
@@ -41,6 +42,7 @@ export interface SpectrumColorSwatchProps {
|
|
|
41
42
|
export function SpectrumColorSwatch(props: SpectrumColorSwatchProps) {
|
|
42
43
|
const { color, name, onPick } = props;
|
|
43
44
|
const [isOpen, setIsOpen] = useState(false);
|
|
45
|
+
const t = useChromeT();
|
|
44
46
|
|
|
45
47
|
function offer(offered: string) {
|
|
46
48
|
return (
|
|
@@ -48,7 +50,7 @@ export function SpectrumColorSwatch(props: SpectrumColorSwatchProps) {
|
|
|
48
50
|
key={offered}
|
|
49
51
|
type="button"
|
|
50
52
|
title={offered}
|
|
51
|
-
aria-label={
|
|
53
|
+
aria-label={t('panel.drawIn', { name, color: offered })}
|
|
52
54
|
style={{
|
|
53
55
|
...(offered === color ? activeSwatchStyle : swatchStyle),
|
|
54
56
|
background: offered,
|
|
@@ -78,8 +80,8 @@ export function SpectrumColorSwatch(props: SpectrumColorSwatchProps) {
|
|
|
78
80
|
>
|
|
79
81
|
<button
|
|
80
82
|
type="button"
|
|
81
|
-
title=
|
|
82
|
-
aria-label={
|
|
83
|
+
title={t('panel.changeColour')}
|
|
84
|
+
aria-label={t('panel.colourOf', { name })}
|
|
83
85
|
style={{ ...swatchStyle, background: color }}
|
|
84
86
|
/>
|
|
85
87
|
</PopoverNext>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
/** Which panels of a stack are folded, and the gestures that change that. */
|
|
4
|
+
export interface PanelFolds {
|
|
5
|
+
/**
|
|
6
|
+
* Whether a panel shows its body.
|
|
7
|
+
* @param id - The panel.
|
|
8
|
+
* @returns False while it is folded away.
|
|
9
|
+
*/
|
|
10
|
+
isOpen: (id: string) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Fold a panel away, or unfold it.
|
|
13
|
+
* @param id - The panel.
|
|
14
|
+
* @param open - Whether it shows its body.
|
|
15
|
+
*/
|
|
16
|
+
setOpen: (id: string, open: boolean) => void;
|
|
17
|
+
/** The one panel left unfolded among several, or null. */
|
|
18
|
+
focused: string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Focus on a panel: unfold it and fold every other one, or, when it is
|
|
21
|
+
* already in focus, unfold them all again.
|
|
22
|
+
* @param id - The panel.
|
|
23
|
+
*/
|
|
24
|
+
toggleFocus: (id: string) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const NOTHING_FOLDED: ReadonlySet<string> = new Set();
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The folds of a stack of panels, kept by the stack rather than by each panel
|
|
31
|
+
* so that one panel can be focused — every other one folded — and the focus
|
|
32
|
+
* undone.
|
|
33
|
+
*
|
|
34
|
+
* A panel closed while folded comes back unfolded when it is opened again: a
|
|
35
|
+
* reader reopening a panel from the rail is asking to see it.
|
|
36
|
+
* @param openIds - The panels in the stack, in the order they are drawn.
|
|
37
|
+
* @returns The folds.
|
|
38
|
+
*/
|
|
39
|
+
export function usePanelFolds(openIds: readonly string[]): PanelFolds {
|
|
40
|
+
const [folded, setFolded] = useState(NOTHING_FOLDED);
|
|
41
|
+
|
|
42
|
+
const kept = keepOnly(folded, openIds);
|
|
43
|
+
if (kept !== folded) setFolded(kept);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
isOpen: (id) => !kept.has(id),
|
|
47
|
+
setOpen: (id, open) => {
|
|
48
|
+
setFolded((previous) => {
|
|
49
|
+
if (previous.has(id) !== open) return previous;
|
|
50
|
+
const next = new Set(previous);
|
|
51
|
+
if (open) next.delete(id);
|
|
52
|
+
else next.add(id);
|
|
53
|
+
return next;
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
focused: focusedPanel(openIds, kept),
|
|
57
|
+
toggleFocus: (id) => {
|
|
58
|
+
setFolded(
|
|
59
|
+
focusedPanel(openIds, kept) === id
|
|
60
|
+
? NOTHING_FOLDED
|
|
61
|
+
: new Set(openIds.filter((other) => other !== id)),
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The folds of the panels still in the stack.
|
|
69
|
+
* @param folded - The panels folded.
|
|
70
|
+
* @param openIds - The panels in the stack.
|
|
71
|
+
* @returns `folded` itself when every one of them is still in the stack.
|
|
72
|
+
*/
|
|
73
|
+
function keepOnly(
|
|
74
|
+
folded: ReadonlySet<string>,
|
|
75
|
+
openIds: readonly string[],
|
|
76
|
+
): ReadonlySet<string> {
|
|
77
|
+
for (const id of folded) {
|
|
78
|
+
if (!openIds.includes(id)) {
|
|
79
|
+
return new Set(openIds.filter((open) => folded.has(open)));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return folded;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The panel in focus: the only one unfolded, when there is another to fold.
|
|
87
|
+
* @param openIds - The panels in the stack.
|
|
88
|
+
* @param folded - The panels folded.
|
|
89
|
+
* @returns The panel, or null.
|
|
90
|
+
*/
|
|
91
|
+
function focusedPanel(
|
|
92
|
+
openIds: readonly string[],
|
|
93
|
+
folded: ReadonlySet<string>,
|
|
94
|
+
): string | null {
|
|
95
|
+
if (openIds.length < 2) return null;
|
|
96
|
+
let unfolded: string | null = null;
|
|
97
|
+
for (const id of openIds) {
|
|
98
|
+
if (folded.has(id)) continue;
|
|
99
|
+
if (unfolded !== null) return null;
|
|
100
|
+
unfolded = id;
|
|
101
|
+
}
|
|
102
|
+
return unfolded;
|
|
103
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A box that can fill the screen: the 3D canvas and its toolbars, a side panel.
|
|
3
|
+
*
|
|
4
|
+
* A box filling the screen hides everything outside it, and the popovers and
|
|
5
|
+
* tooltips of what it holds are portalled to `document.body`: while the box
|
|
6
|
+
* fills the screen they are portalled into it instead, the way react-science's
|
|
7
|
+
* `RootLayout` keeps its own menus visible. Otherwise the portal options of the
|
|
8
|
+
* page around the box are passed through untouched.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { PortalContext, PortalProvider } from '@blueprintjs/core';
|
|
12
|
+
import type { CSSProperties, ReactElement, ReactNode } from 'react';
|
|
13
|
+
import { useCallback, useContext, useState } from 'react';
|
|
14
|
+
import { FullScreenProvider, useFullscreen } from 'react-science/ui';
|
|
15
|
+
|
|
16
|
+
import { canFillScreen } from './canFillScreen.ts';
|
|
17
|
+
|
|
18
|
+
/** Whether a box fills the screen, and how to change that. */
|
|
19
|
+
export interface StageFullscreen {
|
|
20
|
+
/** Whether the box fills the screen. */
|
|
21
|
+
active: boolean;
|
|
22
|
+
/** Fill the screen, or leave it. */
|
|
23
|
+
toggle: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Props of {@link FullscreenStage}. */
|
|
27
|
+
export interface FullscreenStageProps {
|
|
28
|
+
/**
|
|
29
|
+
* Style of the box, or a function handed whether the box fills the screen,
|
|
30
|
+
* for a box shaped differently while it does.
|
|
31
|
+
*/
|
|
32
|
+
style: CSSProperties | ((fillsScreen: boolean) => CSSProperties);
|
|
33
|
+
/**
|
|
34
|
+
* Called with the box once it is mounted, and with `null` once it is gone.
|
|
35
|
+
* It must keep its identity across renders.
|
|
36
|
+
* @default undefined
|
|
37
|
+
*/
|
|
38
|
+
onStage?: (element: HTMLDivElement | null) => void;
|
|
39
|
+
/**
|
|
40
|
+
* What is drawn in the box, handed whether it fills the screen and the
|
|
41
|
+
* toggle, or `undefined` where the browser cannot fill the screen.
|
|
42
|
+
*/
|
|
43
|
+
children: (fullscreen: StageFullscreen | undefined) => ReactNode;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The box, able to fill the screen.
|
|
48
|
+
* @param props - See {@link FullscreenStageProps}.
|
|
49
|
+
* @returns The box.
|
|
50
|
+
*/
|
|
51
|
+
export function FullscreenStage(props: FullscreenStageProps): ReactElement {
|
|
52
|
+
return (
|
|
53
|
+
<FullScreenProvider>
|
|
54
|
+
{(fullscreenRef) => <Stage {...props} fullscreenRef={fullscreenRef} />}
|
|
55
|
+
</FullScreenProvider>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface StageProps extends FullscreenStageProps {
|
|
60
|
+
/** Where `FullScreenProvider` expects the element that fills the screen. */
|
|
61
|
+
fullscreenRef: { current: HTMLDivElement | null };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Stage(props: StageProps): ReactElement {
|
|
65
|
+
const { style, onStage, children, fullscreenRef } = props;
|
|
66
|
+
const { isFullScreen, toggle } = useFullscreen();
|
|
67
|
+
const portal = useContext(PortalContext);
|
|
68
|
+
const [canFill] = useState(canFillScreen);
|
|
69
|
+
const [stage, setStage] = useState<HTMLDivElement | null>(null);
|
|
70
|
+
const stageRef = useCallback(
|
|
71
|
+
(element: HTMLDivElement | null) => {
|
|
72
|
+
fullscreenRef.current = element;
|
|
73
|
+
setStage(element);
|
|
74
|
+
onStage?.(element);
|
|
75
|
+
},
|
|
76
|
+
[fullscreenRef, onStage],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// The provider is always there, so entering full screen changes a value
|
|
80
|
+
// rather than the tree, and what the box holds is never mounted again.
|
|
81
|
+
return (
|
|
82
|
+
<div
|
|
83
|
+
ref={stageRef}
|
|
84
|
+
style={typeof style === 'function' ? style(isFullScreen) : style}
|
|
85
|
+
>
|
|
86
|
+
<PortalProvider
|
|
87
|
+
portalClassName={portal.portalClassName}
|
|
88
|
+
portalContainer={
|
|
89
|
+
isFullScreen && stage !== null ? stage : portal.portalContainer
|
|
90
|
+
}
|
|
91
|
+
>
|
|
92
|
+
{children(canFill ? { active: isFullScreen, toggle } : undefined)}
|
|
93
|
+
</PortalProvider>
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether this browser lets a page fill the screen: neither an iPhone nor a
|
|
3
|
+
* frame without `allowfullscreen` does.
|
|
4
|
+
* @returns Whether `requestFullscreen` can succeed.
|
|
5
|
+
*/
|
|
6
|
+
export function canFillScreen(): boolean {
|
|
7
|
+
return typeof document !== 'undefined' && document.fullscreenEnabled;
|
|
8
|
+
}
|
package/src/shared/ui/index.ts
CHANGED
|
@@ -7,3 +7,9 @@ export type {
|
|
|
7
7
|
ActionTooltipTarget,
|
|
8
8
|
} from './useActionTooltip.ts';
|
|
9
9
|
export { ACTION_TOOLTIP_DELAY, useActionTooltip } from './useActionTooltip.ts';
|
|
10
|
+
export { canFillScreen } from './canFillScreen.ts';
|
|
11
|
+
export type {
|
|
12
|
+
FullscreenStageProps,
|
|
13
|
+
StageFullscreen,
|
|
14
|
+
} from './FullscreenStage.tsx';
|
|
15
|
+
export { FullscreenStage } from './FullscreenStage.tsx';
|
|
@@ -65,9 +65,9 @@ export interface SplitPanesProps extends SplitRange {
|
|
|
65
65
|
*/
|
|
66
66
|
stackBelow?: number;
|
|
67
67
|
/**
|
|
68
|
-
* The gutter each pane keeps beside the splitter, in pixels
|
|
69
|
-
*
|
|
70
|
-
* @default
|
|
68
|
+
* The gutter each pane keeps beside the splitter, in pixels. The bar is
|
|
69
|
+
* already the separation, so a gutter only widens it into a band of page.
|
|
70
|
+
* @default 0
|
|
71
71
|
*/
|
|
72
72
|
gutter?: number;
|
|
73
73
|
/**
|
|
@@ -234,7 +234,7 @@ const STACK_ACROSS = 860;
|
|
|
234
234
|
const STACK_DOWN = 420;
|
|
235
235
|
|
|
236
236
|
/** The gutter a pane keeps beside the splitter, in pixels. */
|
|
237
|
-
const GUTTER =
|
|
237
|
+
const GUTTER = 0;
|
|
238
238
|
|
|
239
239
|
/** The gap between the panes once they have stacked, in pixels. */
|
|
240
240
|
const STACKED_GAP = 16;
|
|
@@ -56,6 +56,13 @@ export interface StructureNotation {
|
|
|
56
56
|
block: boolean;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Notations the caller has already written, shown instead of the ones
|
|
61
|
+
* OpenChemLib would write. A drawing program's molfile keeps its
|
|
62
|
+
* abbreviations as superatoms, which a round trip through OpenChemLib drops.
|
|
63
|
+
*/
|
|
64
|
+
export type SuppliedNotations = Partial<Record<StructureNotationKind, string>>;
|
|
65
|
+
|
|
59
66
|
/** What a molfile is, for the application that opens one. */
|
|
60
67
|
const MOLFILE_TYPE = 'chemical/x-mdl-molfile';
|
|
61
68
|
|
|
@@ -66,35 +73,45 @@ const MOLFILE_TYPE = 'chemical/x-mdl-molfile';
|
|
|
66
73
|
* tautomer cannot always be canonized — comes back empty rather than taking
|
|
67
74
|
* the rest of the list down with it.
|
|
68
75
|
* @param molecule - The structure, as the editor handed it over. Not modified.
|
|
76
|
+
* @param supplied - Notations the caller wrote itself, used as they are.
|
|
69
77
|
* @returns One entry per notation, in the order they are shown.
|
|
70
78
|
*/
|
|
71
|
-
export function structureNotations(
|
|
72
|
-
|
|
79
|
+
export function structureNotations(
|
|
80
|
+
molecule: Molecule,
|
|
81
|
+
supplied: SuppliedNotations = {},
|
|
82
|
+
): StructureNotation[] {
|
|
83
|
+
const value = (kind: StructureNotationKind, write: () => string) =>
|
|
84
|
+
supplied[kind] ?? written(write);
|
|
73
85
|
return [
|
|
74
86
|
{
|
|
75
87
|
kind: 'smiles',
|
|
76
|
-
value:
|
|
88
|
+
value: value('smiles', () => molecule.toIsomericSmiles()),
|
|
77
89
|
canonical: false,
|
|
78
90
|
block: false,
|
|
79
91
|
},
|
|
80
92
|
{
|
|
81
93
|
kind: 'molfileV3000',
|
|
82
|
-
value:
|
|
94
|
+
value: value('molfileV3000', () => molecule.toMolfileV3()),
|
|
83
95
|
canonical: false,
|
|
84
96
|
file: { suffix: '-v3000', extension: 'mol', mimeType: MOLFILE_TYPE },
|
|
85
97
|
block: true,
|
|
86
98
|
},
|
|
87
99
|
{
|
|
88
100
|
kind: 'molfileV2000',
|
|
89
|
-
value:
|
|
101
|
+
value: value('molfileV2000', () => molecule.toMolfile()),
|
|
90
102
|
canonical: false,
|
|
91
103
|
file: { suffix: '-v2000', extension: 'mol', mimeType: MOLFILE_TYPE },
|
|
92
104
|
block: true,
|
|
93
105
|
},
|
|
94
|
-
{
|
|
106
|
+
{
|
|
107
|
+
kind: 'idCode',
|
|
108
|
+
value: value('idCode', () => molecule.getIDCode()),
|
|
109
|
+
canonical: true,
|
|
110
|
+
block: false,
|
|
111
|
+
},
|
|
95
112
|
{
|
|
96
113
|
kind: 'noStereoIdCode',
|
|
97
|
-
value:
|
|
114
|
+
value: value('noStereoIdCode', () =>
|
|
98
115
|
CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO),
|
|
99
116
|
),
|
|
100
117
|
canonical: true,
|
|
@@ -102,7 +119,7 @@ export function structureNotations(molecule: Molecule): StructureNotation[] {
|
|
|
102
119
|
},
|
|
103
120
|
{
|
|
104
121
|
kind: 'noStereoTautomerIdCode',
|
|
105
|
-
value:
|
|
122
|
+
value: value('noStereoTautomerIdCode', () =>
|
|
106
123
|
CanonizerUtil.getIDCode(molecule, CanonizerUtil.NOSTEREO_TAUTOMER),
|
|
107
124
|
),
|
|
108
125
|
canonical: true,
|
|
@@ -15,6 +15,7 @@ import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
|
15
15
|
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
16
16
|
import { sourceMolecule } from '../core/sourceMolecule.ts';
|
|
17
17
|
import { structureError } from '../core/structureError.ts';
|
|
18
|
+
import type { SuppliedNotations } from '../core/structureNotations.ts';
|
|
18
19
|
import { structureNotations } from '../core/structureNotations.ts';
|
|
19
20
|
import type { StructureSourceInput } from '../core/structureSource.ts';
|
|
20
21
|
import { structureSource } from '../core/structureSource.ts';
|
|
@@ -36,6 +37,13 @@ export interface StructureExportPanelProps extends StructureSourceInput {
|
|
|
36
37
|
* @default false
|
|
37
38
|
*/
|
|
38
39
|
fragment?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Notations the caller wrote itself, shown and saved as they are instead of
|
|
42
|
+
* the ones OpenChemLib would write from the structure — a drawing program
|
|
43
|
+
* whose molfile keeps superatoms that a round trip would drop.
|
|
44
|
+
* @default {}
|
|
45
|
+
*/
|
|
46
|
+
notations?: SuppliedNotations;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
/**
|
|
@@ -53,12 +61,17 @@ export function StructureExportPanel(
|
|
|
53
61
|
props: StructureExportPanelProps,
|
|
54
62
|
): ReactElement {
|
|
55
63
|
const { idCode, coordinates, molfile, smiles } = props;
|
|
56
|
-
const { name = 'structure', fragment = false } = props;
|
|
64
|
+
const { name = 'structure', fragment = false, notations: supplied } = props;
|
|
57
65
|
const t = useChromeT();
|
|
58
66
|
|
|
59
67
|
const read = useMemo(
|
|
60
|
-
() =>
|
|
61
|
-
|
|
68
|
+
() =>
|
|
69
|
+
readStructure(
|
|
70
|
+
{ idCode, coordinates, molfile, smiles },
|
|
71
|
+
fragment,
|
|
72
|
+
supplied,
|
|
73
|
+
),
|
|
74
|
+
[idCode, coordinates, molfile, smiles, fragment, supplied],
|
|
62
75
|
);
|
|
63
76
|
|
|
64
77
|
if (read.kind !== 'read') {
|
|
@@ -120,11 +133,13 @@ type ReadStructure =
|
|
|
120
133
|
* Read the notation the caller handed over, and write every other one from it.
|
|
121
134
|
* @param input - Whatever notations the caller has.
|
|
122
135
|
* @param fragment - Whether the structure is a query fragment.
|
|
136
|
+
* @param supplied - Notations the caller wrote itself.
|
|
123
137
|
* @returns The molecule and its notations, or why there are none.
|
|
124
138
|
*/
|
|
125
139
|
function readStructure(
|
|
126
140
|
input: StructureSourceInput,
|
|
127
141
|
fragment: boolean,
|
|
142
|
+
supplied: SuppliedNotations | undefined,
|
|
128
143
|
): ReadStructure {
|
|
129
144
|
const source = structureSource(input);
|
|
130
145
|
if (source.kind === 'empty') return { kind: 'empty' };
|
|
@@ -135,7 +150,11 @@ function readStructure(
|
|
|
135
150
|
// structure from the one that was drawn.
|
|
136
151
|
if (fragment) molecule.setFragment(true);
|
|
137
152
|
if (molecule.getAllAtoms() === 0) return { kind: 'empty' };
|
|
138
|
-
return {
|
|
153
|
+
return {
|
|
154
|
+
kind: 'read',
|
|
155
|
+
molecule,
|
|
156
|
+
notations: structureNotations(molecule, supplied),
|
|
157
|
+
};
|
|
139
158
|
} catch (error) {
|
|
140
159
|
return { kind: 'error', message: structureError(error).message };
|
|
141
160
|
}
|
|
@@ -36,6 +36,10 @@ export { StructureExportButton } from './StructureExportButton.tsx';
|
|
|
36
36
|
export type { CardStructureProps } from './CardStructure.tsx';
|
|
37
37
|
export { CardStructure } from './CardStructure.tsx';
|
|
38
38
|
export type { StructureExportPanelProps } from './StructureExportPanel.tsx';
|
|
39
|
+
export type {
|
|
40
|
+
StructureNotationKind,
|
|
41
|
+
SuppliedNotations,
|
|
42
|
+
} from '../core/structureNotations.ts';
|
|
39
43
|
export type { ToolbarFloorOptions } from './useToolbarFloor.ts';
|
|
40
44
|
export { useToolbarFloor } from './useToolbarFloor.ts';
|
|
41
45
|
export type { StructureDraft } from './useStructureDraft.ts';
|