import type { Spectrum } from '@zakodium/nmrium-core';
import dlv from 'dlv';
import { useState } from 'react';
import { useResizeObserver } from 'react-d3-utils';
import { BsArrowsMove } from 'react-icons/bs';
import { FaTimes } from 'react-icons/fa';
import { SVGStyledText } from 'react-science/ui';
import { useIsInset } from '../../1d/inset/InsetProvider.js';
import { useChartData } from '../../context/ChartContext.js';
import { useGlobal } from '../../context/GlobalContext.js';
import { usePreferences } from '../../context/PreferencesContext.js';
import type { ActionsButtonsPopoverProps } from '../../elements/ActionsButtonsPopover.js';
import { ActionsButtonsPopover } from '../../elements/ActionsButtonsPopover.js';
import { SVGGroup } from '../../elements/SVGGroup.js';
import useDraggable from '../../elements/draggable/useDraggable.js';
import useSpectrum from '../../hooks/useSpectrum.js';
import type { Margin } from '../../reducer/Reducer.js';
import { formatNumber } from '../../utility/formatNumber.js';
const verticalSpace = 5;
const boxPadding = 0;
const dragShiftY = 24;
function getInfoValue(
spectrum: Spectrum,
field: { jpath: string[]; format: string },
) {
const { jpath, format } = field;
const value = dlv(spectrum, jpath, '');
switch (typeof value) {
case 'number':
return formatNumber(value, format);
case 'string':
return value;
case 'boolean':
return value ? 'Yes' : 'No';
default:
return JSON.stringify(value);
}
}
function useInfoPosition(margin: Margin) {
const { left, top } = margin;
const {
current: { infoBlock },
} = usePreferences();
const { x, y } = infoBlock?.position || { x: left, y: top };
return { x, y };
}
function SpectrumInfoBlock() {
const { height, width, margin } = useChartData();
const spectrum = useSpectrum();
const { viewerRef } = useGlobal();
const coordinate = useInfoPosition(margin);
const { dispatch } = usePreferences();
const [isMoveActive, setIsMoveActive] = useState(false);
const isInset = useIsInset();
const [currentPosition, setCurrentPosition] = useState<{
x: number;
y: number;
}>(coordinate);
const {
current: {
infoBlock: { visible, fields, nameStyle, valueStyle },
},
} = usePreferences();
const infoFields = fields.filter((field) => field.visible);
const totalSpace =
verticalSpace *
((infoFields?.length < 2
? 2
: infoFields?.length - (infoFields?.length % 2)
? 2
: 1) || 0);
const [
ref,
{ width: boxWidth, height: boxHeight } = { width: 0, height: 0 },
] = useResizeObserver();
const { onPointerDown } = useDraggable({
position: coordinate,
onChange: (dragEvent) => {
const { action, position } = dragEvent;
switch (action) {
case 'start': {
setCurrentPosition({ x: position.x, y: position.y + dragShiftY });
setIsMoveActive(true);
break;
}
case 'move': {
setCurrentPosition({
x: position.x,
y: position.y + dragShiftY,
});
break;
}
case 'end':
dispatch({
type: 'CHANGE_INFORMATION_BLOCK_POSITION',
payload: {
coordination: {
x: position.x,
y: position.y,
},
},
});
setIsMoveActive(false);
break;
default:
break;
}
},
parentElement: viewerRef,
});
if (!visible || !spectrum || isInset) return null;
const bothSidePadding = boxPadding * 2;
const shift = dragShiftY / 2;
let { x, y } = currentPosition;
if (x + boxWidth + boxPadding > width - margin.right) {
x = width - margin.right - boxWidth - boxPadding;
}
if (x - boxPadding < margin.left) {
x = margin.left + boxPadding;
}
if (y + boxHeight + bothSidePadding + shift > height - margin.bottom) {
y = height - margin.bottom - boxHeight - bothSidePadding - shift;
}
if (y + shift < margin.top) {
y = margin.top - shift;
}
const finalBoxWidth = boxWidth + bothSidePadding;
const finalBoxHeight = boxHeight + bothSidePadding;
const actionsButtons: ActionsButtonsPopoverProps['buttons'] = [
{
icon: ,
onPointerDown: (event) => {
event.stopPropagation();
onPointerDown(event);
},
intent: 'none',
title: 'Move information block',
style: { cursor: 'move' },
},
{
icon: ,
onClick: () => {
dispatch({
type: 'TOGGLE_INFORMATION_BLOCK',
payload: { visible: false },
});
},
intent: 'danger',
title: 'Hide information block',
},
];
return (
{infoFields.map((field, index) => {
return (
{field.label} :
{getInfoValue(spectrum, field)}
);
})}
);
}
export default SpectrumInfoBlock;