diff --git a/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx b/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx deleted file mode 100644 index 337ed3728..000000000 --- a/src/component/1d-2d/components/FloatMoleculeStructures/ActionsButton.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { BsArrowsMove } from 'react-icons/bs'; -import { FaTimes } from 'react-icons/fa'; - -import Button from '../../../elements/Button.js'; - -export default function ActionsButton({ onFloatBtnClick }) { - return ( -
- - - - - - -
- ); -} diff --git a/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx b/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx index 9c53c134c..9d79fa333 100644 --- a/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx +++ b/src/component/1d-2d/components/FloatMoleculeStructures/DraggableStructure.tsx @@ -1,7 +1,10 @@ import styled from '@emotion/styled'; import type { Ranges, Zones } from 'nmr-processing'; import OCL from 'openchemlib/full'; +import { useEffect, useState } from 'react'; import { ResponsiveChart } from 'react-d3-utils'; +import { BsArrowsMove } from 'react-icons/bs'; +import { FaTimes } from 'react-icons/fa'; import OCLnmr from 'react-ocl-nmr'; import { Rnd } from 'react-rnd'; @@ -12,14 +15,15 @@ import type { } from '../../../../data/molecules/Molecule.js'; import { useDispatch } from '../../../context/DispatchContext.js'; import { useGlobal } from '../../../context/GlobalContext.js'; +import { ActionsButtonsPopover } from '../../../elements/ActionsButtonsPopover.js'; +import type { ActionsButtonsPopoverProps } from '../../../elements/ActionsButtonsPopover.js'; import { useHighlightColor } from '../../../hooks/useHighlightColor.js'; +import { useSVGUnitConverter } from '../../../hooks/useSVGUnitConverter.js'; import { useCheckExportStatus } from '../../../hooks/useViewportSize.js'; import { useMoleculeEditor } from '../../../modal/MoleculeStructureEditorModal.js'; import useAtomAssignment from '../../../panels/MoleculesPanel/useAtomAssignment.js'; import type { DisplayerMode } from '../../../reducer/Reducer.js'; -import ActionsButton from './ActionsButton.js'; - interface DraggableMoleculeProps extends DraggableStructureProps { width: number; height: number; @@ -35,15 +39,9 @@ interface DraggableStructureProps { molecule: StateMoleculeExtended; } -const AUTO_CROP_MARGIN = 30; - const ReactRnd = styled(Rnd)` border: 1px solid transparent; - button { - visibility: hidden; - } - .content { width: 100%; height: 100%; @@ -52,10 +50,6 @@ const ReactRnd = styled(Rnd)` &:hover { border: 1px solid #ebecf1; background-color: white; - - button { - visibility: visible; - } } `; @@ -65,6 +59,15 @@ export function DraggableStructure(props: DraggableStructureProps) { const isExportProcessStart = useCheckExportStatus(); const dispatch = useDispatch(); const { modal, openMoleculeEditor } = useMoleculeEditor(); + const { percentToPixel, pixelToPercent } = useSVGUnitConverter(); + const [bounding, setBounding] = useState( + moleculeView.floating.bounding, + ); + const [isMoveActive, setIsMoveActive] = useState(false); + + useEffect(() => { + setBounding({ ...moleculeView.floating.bounding }); + }, [moleculeView.floating.bounding]); function floatMoleculeHandler() { dispatch({ @@ -88,42 +91,102 @@ export function DraggableStructure(props: DraggableStructureProps) { }); } + function handleDrag(internalBounding: Pick) { + setBounding((prevBounding) => ({ + ...prevBounding, + ...convertPositionToPercent(internalBounding), + })); + } + + function convertPositionToPercent({ + x, + y, + }: Pick) { + return { x: pixelToPercent(x, 'x'), y: pixelToPercent(y, 'y') }; + } + if (!viewerRef) return null; + const actionsButtons: ActionsButtonsPopoverProps['buttons'] = [ + { + icon: , + intent: 'none', + title: 'Move molecule', + style: { cursor: 'move' }, + className: 'handle', + }, + { + icon: , + intent: 'danger', + title: 'Hide molecule', + onClick: floatMoleculeHandler, + }, + ]; + + const { x: xInPercent, y: yInPercent, width, height } = bounding; + + const x = percentToPixel(xInPercent, 'x'); + const y = percentToPixel(yInPercent, 'y'); + if (isExportProcessStart) { - const { width, height } = moleculeView.floating.bounding; - return ; + return ( + + + + ); } return ( setIsMoveActive(true)} onResizeStop={(e, dir, eRef, { width, height }) => dragFloatMoleculeHandler({ width, height }) } + onDrag={(e, { x, y }) => { + handleDrag({ x, y }); + }} onDragStop={(e, { x, y }) => { - dragFloatMoleculeHandler({ x, y }); + dragFloatMoleculeHandler(convertPositionToPercent({ x, y })); + setIsMoveActive(false); }} resizeHandleWrapperStyle={{ backgroundColor: 'white' }} > -
openMoleculeEditor(molecule)} + - - - {({ width, height }) => { - return ; - }} - -
+
openMoleculeEditor(molecule)} + > + + {({ width, height }) => { + return ; + }} + +
+ + {modal}
); @@ -154,10 +217,8 @@ function DraggableMolecule(props: DraggableMoleculeProps) { >` padding: 5px; } `; - +interface ActionButtonProps + extends Pick< + ButtonProps, + | 'icon' + | 'onClick' + | 'intent' + | 'disabled' + | 'onPointerDown' + | 'style' + | 'className' + > { + title?: string; + visible?: boolean; + css?: Interpolation; +} export interface ActionsButtonsPopoverProps extends Omit { - buttons: Array< - Pick< - ButtonProps, - 'icon' | 'onClick' | 'intent' | 'disabled' | 'onPointerDown' | 'style' - > & { - title?: string; - visible?: boolean; - css?: Interpolation; - } - >; + buttons: ActionButtonProps[]; contentStyle?: CSSProperties; direction?: 'column' | 'row'; space?: number; } +function ActionButton(props: ButtonProps) { + return