From 02ee2f8107f4af15dbd186c12ab7b2518c825089 Mon Sep 17 00:00:00 2001
From: hamed-musallam <35760236+hamed-musallam@users.noreply.github.com>
Date: Fri, 17 Jan 2025 12:43:25 +0100
Subject: [PATCH] feat: fill chemical shift input by using the cursor on the
spectrum (#3334)
---
.../editRange/forms/components/DeltaInput.tsx | 30 +++++++++-
.../forms/components/SignalsContent.tsx | 60 ++++++++++++++++---
.../signal-tabs/SignalJCouplingsTable.tsx | 10 +++-
.../signal-tabs/SignalPeaksTable.tsx | 10 +++-
4 files changed, 96 insertions(+), 14 deletions(-)
diff --git a/src/component/modal/editRange/forms/components/DeltaInput.tsx b/src/component/modal/editRange/forms/components/DeltaInput.tsx
index 618102e6f..cc5de6e75 100644
--- a/src/component/modal/editRange/forms/components/DeltaInput.tsx
+++ b/src/component/modal/editRange/forms/components/DeltaInput.tsx
@@ -1,7 +1,10 @@
import { translateMultiplet } from 'nmr-processing';
-import { useFormContext } from 'react-hook-form';
+import { useFormContext, useWatch } from 'react-hook-form';
import { NumberInput2Controller } from '../../../../elements/NumberInput2Controller.js';
+import { useEvent } from '../../../../utility/Events.js';
+
+import { useEventFocusInput } from './SignalsContent.js';
interface DeltaInputProps {
signal: any;
@@ -16,8 +19,30 @@ export function DeltaInput({ signal, index }: DeltaInputProps) {
const {
control,
formState: { errors },
+ setValue,
} = useFormContext();
const isNotValid = hasError(errors, index);
+ const { signalIndex } = useWatch();
+ const { focusSource, setFocusSource } = useEventFocusInput();
+
+ useEvent({
+ onClick: ({ xPPM, shiftKey }) => {
+ if (index === signalIndex && shiftKey && focusSource === 'delta') {
+ setValue(`signals.${index}.delta`, xPPM);
+ }
+ },
+ onBrushEnd: (options) => {
+ const {
+ range: [from, to],
+ shiftKey,
+ } = options;
+ if (index === signalIndex && shiftKey && focusSource === 'delta') {
+ const delta = (to - from) / 2 + from;
+ setValue(`signals.${index}.delta`, delta);
+ }
+ },
+ });
+
return (
{
+ setFocusSource('delta');
+ }}
/>
{signal.js
diff --git a/src/component/modal/editRange/forms/components/SignalsContent.tsx b/src/component/modal/editRange/forms/components/SignalsContent.tsx
index 28d66a630..e5f875ab8 100644
--- a/src/component/modal/editRange/forms/components/SignalsContent.tsx
+++ b/src/component/modal/editRange/forms/components/SignalsContent.tsx
@@ -1,7 +1,15 @@
/** @jsxImportSource @emotion/react */
import { Tab, Tabs } from '@blueprintjs/core';
import type { Range } from 'nmr-processing';
-import { memo, useCallback, useEffect, useMemo } from 'react';
+import {
+ createContext,
+ memo,
+ useCallback,
+ useContext,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
import { useFormContext, useWatch } from 'react-hook-form';
import { FaPlus } from 'react-icons/fa';
@@ -16,6 +24,38 @@ interface SignalsFormProps {
range: Range;
}
+type FocusSource = 'peak' | 'coupling' | 'delta' | null;
+interface FocusInputContextState {
+ focusSource: 'peak' | 'coupling' | 'delta' | null;
+ setFocusSource: (source: FocusSource) => void;
+}
+
+const FocusInputContext = createContext(null);
+
+export function useEventFocusInput() {
+ const context = useContext(FocusInputContext);
+
+ if (!context) {
+ throw new Error('FocusInputContext was not found.');
+ }
+
+ return context;
+}
+
+function FocusInputProvider({ children }) {
+ const [focusSource, setFocusSource] = useState(null);
+
+ const state = useMemo(() => {
+ return { focusSource, setFocusSource };
+ }, [focusSource]);
+
+ return (
+
+ {children}
+
+ );
+}
+
function SignalsContent({ range }: SignalsFormProps) {
const { setValue } = useFormContext();
const { signals, signalIndex } = useWatch();
@@ -78,14 +118,16 @@ function SignalsContent({ range }: SignalsFormProps) {
return (
- tapClickHandler(id)}
- animate={false}
- >
- {signalFormTabs}
-
+
+ tapClickHandler(id)}
+ animate={false}
+ >
+ {signalFormTabs}
+
+
);
}
diff --git a/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx b/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx
index de3dc6eeb..6b0da60bb 100644
--- a/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx
+++ b/src/component/modal/editRange/forms/components/signal-tabs/SignalJCouplingsTable.tsx
@@ -17,6 +17,7 @@ import { Select2Controller } from '../../../../../elements/Select2Controller.js'
import useSpectrum from '../../../../../hooks/useSpectrum.js';
import { hasCouplingConstant } from '../../../../../panels/extra/utilities/MultiplicityUtilities.js';
import { useEvent } from '../../../../../utility/Events.js';
+import { useEventFocusInput } from '../SignalsContent.js';
const styles: Record<'input' | 'select' | 'column', CSSProperties> = {
input: {
@@ -49,6 +50,8 @@ function getCouplingMinErrorMessage(errors, index) {
}
export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) {
+ const { focusSource, setFocusSource } = useEventFocusInput();
+
const {
setValue,
control,
@@ -67,7 +70,8 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) {
if (
props.index === signalIndex &&
typeof lastSelectedCouplingIndexRef.current === 'number' &&
- shiftKey
+ shiftKey &&
+ focusSource === 'coupling'
) {
setValue(
getJCouplingKey(
@@ -89,7 +93,8 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) {
props.index === signalIndex &&
typeof lastSelectedCouplingIndexRef.current === 'number' &&
shiftKey &&
- isSpectrum1D(spectrum)
+ isSpectrum1D(spectrum) &&
+ focusSource === 'coupling'
) {
const value = Math.abs(to - from) * spectrum.info.originFrequency;
@@ -218,6 +223,7 @@ export function SignalJCouplingsTable(props: SignalJCouplingsTableProps) {
);
function selectRowHandler(index) {
+ setFocusSource('coupling');
lastSelectedCouplingIndexRef.current = index;
}
diff --git a/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx b/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx
index f6a8e6def..9652b3563 100644
--- a/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx
+++ b/src/component/modal/editRange/forms/components/signal-tabs/SignalPeaksTable.tsx
@@ -15,6 +15,7 @@ import type { Column } from '../../../../../elements/ReactTable/ReactTable.js';
import ReactTable from '../../../../../elements/ReactTable/ReactTable.js';
import useSpectrum from '../../../../../hooks/useSpectrum.js';
import { useEvent } from '../../../../../utility/Events.js';
+import { useEventFocusInput } from '../SignalsContent.js';
const styles: Record<'input' | 'column', CSSProperties> = {
input: {
@@ -41,6 +42,8 @@ function getPeakKey(signalIndex: number, peakIndex, key?: keyof Peak1D) {
}
export function SignalPeaksTable(props: SignalPeaksTableProps) {
+ const { focusSource, setFocusSource } = useEventFocusInput();
+
const { setValue, control, setFocus } = useFormContext();
const { signals, signalIndex } = useWatch();
const signal = signals?.[signalIndex] || {};
@@ -57,7 +60,8 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) {
if (
props.index === signalIndex &&
typeof lastSelectedPeakIndexRef.current === 'number' &&
- shiftKey
+ shiftKey &&
+ focusSource === 'peak'
) {
const delta = xPPM;
const xIndex = xFindClosestIndex(xArray, delta, { sorted: false });
@@ -77,7 +81,8 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) {
if (
props.index === signalIndex &&
typeof lastSelectedPeakIndexRef.current === 'number' &&
- shiftKey
+ shiftKey &&
+ focusSource === 'peak'
) {
const delta = (to - from) / 2 + from;
@@ -206,6 +211,7 @@ export function SignalPeaksTable(props: SignalPeaksTableProps) {
);
function selectRowHandler(index) {
+ setFocusSource('peak');
lastSelectedPeakIndexRef.current = index;
setFocus(`signals.${signalIndex}.peaks.${index}.x`, { shouldSelect: true });
}