From a17c1e50133248874f9ae04b77d95fc41dae32da Mon Sep 17 00:00:00 2001
From: jobo322
Date: Fri, 5 Jun 2026 22:42:34 -0500
Subject: [PATCH 1/8] =?UTF-8?q?feat:=20enhance=20peak=20optimization=20pro?=
=?UTF-8?q?cess=20with=20additional=20iterations=20and=20parameters=20chor?=
=?UTF-8?q?e:=20increase=20the=20limit=20for=20peak=20optimization=20to=20?=
=?UTF-8?q?15=20=E2=80=A8fix:=20do=20not=20overwrite=20fwhm=20with=20defau?=
=?UTF-8?q?lt=20shape=20values?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
new version of ml-gsd contain the fix
chore: update ml-gsd to 14.1.0
---
src/component/1d/peaks/usePeakShapesPath.ts | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/src/component/1d/peaks/usePeakShapesPath.ts b/src/component/1d/peaks/usePeakShapesPath.ts
index 6c935f897..18e9f71f0 100644
--- a/src/component/1d/peaks/usePeakShapesPath.ts
+++ b/src/component/1d/peaks/usePeakShapesPath.ts
@@ -9,13 +9,13 @@ import { PathBuilder } from '../../utility/PathBuilder.js';
type PeaksShapesOptions =
| {
- target: 'peakShape';
- peak: Peak1D;
- }
+ target: 'peakShape';
+ peak: Peak1D;
+ }
| {
- target: 'peaksSum';
- peaks: Peak1D[];
- };
+ target: 'peaksSum';
+ peaks: Peak1D[];
+ };
export function usePeakShapesPath(spectrum: Spectrum1D) {
const { scaleX, scaleY } = useScaleChecked();
@@ -29,7 +29,6 @@ export function usePeakShapesPath(spectrum: Spectrum1D) {
const frequency = spectrum.info.originFrequency;
let pathSeries: DataXY | null = null;
-
switch (target) {
case 'peakShape': {
const { peak } = options;
From cca87ee252419323b28fe1070f6822de772fed7c Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Thu, 18 Jun 2026 16:01:51 +0200
Subject: [PATCH 2/8] refactor: ranges and peaks table preferences
---
src/component/1d/FloatingRanges.tsx | 12 +-
src/component/1d/peaks/Peaks.tsx | 7 +-
src/component/1d/ranges/Ranges.tsx | 4 +-
src/component/modal/EditPeakShapeModal.tsx | 4 +-
.../modal/editRange/EditRangeModal.tsx | 10 +-
.../forms/components/NewSignalTab.tsx | 6 +-
.../panels/PeaksPanel/PeaksPreferences.tsx | 36 +--
.../panels/PeaksPanel/PeaksTable.tsx | 22 +-
.../panels/RangesPanel/RangesPreferences.tsx | 44 ++--
.../panels/RangesPanel/RangesTable.tsx | 32 +--
.../panels/RangesPanel/RangesTableRow.tsx | 46 ++--
.../panelsPreferencesDefaultValues.ts | 65 +++---
src/demo/views/SnapshotView.tsx | 215 ++++++++++++------
13 files changed, 298 insertions(+), 205 deletions(-)
diff --git a/src/component/1d/FloatingRanges.tsx b/src/component/1d/FloatingRanges.tsx
index 601c651a1..f14ac92d9 100644
--- a/src/component/1d/FloatingRanges.tsx
+++ b/src/component/1d/FloatingRanges.tsx
@@ -52,21 +52,21 @@ interface RangeItem {
function useMapRanges(ranges: Ranges['values']) {
const output: RangeItem[] = [];
const activeTab = useActiveNucleusTab();
- const preferences = usePanelPreferences('ranges', activeTab);
+ const { tablePreferences } = usePanelPreferences('ranges', activeTab);
for (const range of ranges) {
const { id, from, to, integration, signals = [] } = range;
const relativeFlag = isSignalRange(range);
const formattedValue = formatNumber(
integration,
- preferences.relative.format,
+ tablePreferences.relative.format,
);
const integrationValue = relativeFlag
? formattedValue
: `[ ${formattedValue} ]`;
- const rangeText = `${formatNumber(from, preferences.from.format)} - ${formatNumber(
+ const rangeText = `${formatNumber(from, tablePreferences.from.format)} - ${formatNumber(
to,
- preferences.to.format,
+ tablePreferences.to.format,
)}`;
if (signals.length > 0) {
for (const signal of signals) {
@@ -74,13 +74,13 @@ function useMapRanges(ranges: Ranges['values']) {
const coupling = js
.map((jsItem) =>
!Number.isNaN(jsItem.coupling)
- ? formatNumber(jsItem.coupling, preferences.coupling.format)
+ ? formatNumber(jsItem.coupling, tablePreferences.coupling.format)
: '',
)
.join(',');
const signalDelta = !checkMultiplicity(multiplicity, ['m'])
? rangeText
- : formatNumber(delta, preferences.deltaPPM.format);
+ : formatNumber(delta, tablePreferences.deltaPPM.format);
output.push({
id,
delta: signalDelta,
diff --git a/src/component/1d/peaks/Peaks.tsx b/src/component/1d/peaks/Peaks.tsx
index 49300d002..64c89a9d9 100644
--- a/src/component/1d/peaks/Peaks.tsx
+++ b/src/component/1d/peaks/Peaks.tsx
@@ -188,9 +188,12 @@ export default function Peaks(props: PeaksProps) {
const spectrum = useSpectrum(emptyData) as Spectrum1D;
const peaksViewState = useActiveSpectrumPeaksViewState();
const rangesViewState = useActiveSpectrumRangesViewState();
+ const { tablePreferences } = usePanelPreferences(
+ peaksSource === 'peaks' ? 'peaks' : 'ranges',
+ nucleus,
+ );
const { deltaPPM: { format: peakFormat } = { format: '0.0' } } =
- usePanelPreferences(peaksSource === 'peaks' ? 'peaks' : 'ranges', nucleus);
-
+ tablePreferences;
const canDisplaySpectrumPeaks =
!spectrum.display.isVisible || spectrum.info?.isFid;
let mode: PeaksMode = 'spread';
diff --git a/src/component/1d/ranges/Ranges.tsx b/src/component/1d/ranges/Ranges.tsx
index 3f9258c68..6a7e2f8cf 100644
--- a/src/component/1d/ranges/Ranges.tsx
+++ b/src/component/1d/ranges/Ranges.tsx
@@ -100,7 +100,7 @@ export default function Ranges() {
toolOptions: { selectedTool },
} = useChartData();
const spectrum = useSpectrum(emptyData) as Spectrum1D;
- const rangesPreferences = usePanelPreferences('ranges', activeTab);
+ const { tablePreferences } = usePanelPreferences('ranges', activeTab);
if (
!spectrum.ranges?.values ||
@@ -114,7 +114,7 @@ export default function Ranges() {
);
}
diff --git a/src/component/modal/EditPeakShapeModal.tsx b/src/component/modal/EditPeakShapeModal.tsx
index d0fd7e9ab..7f8f31969 100644
--- a/src/component/modal/EditPeakShapeModal.tsx
+++ b/src/component/modal/EditPeakShapeModal.tsx
@@ -97,7 +97,7 @@ function InnerEditPeakShapeModal(props: Required) {
const { peak, onCloseDialog } = props;
const dispatch = useDispatch();
const activeTab = useActiveNucleusTab();
- const peaksPreferences = usePanelPreferences('peaks', activeTab);
+ const { tablePreferences } = usePanelPreferences('peaks', activeTab);
const [kind, setKind] = useState(peak.shape?.kind || 'gaussian');
const { handleSubmit, control, reset } = useForm({
@@ -125,7 +125,7 @@ function InnerEditPeakShapeModal(props: Required) {
setKind(value);
}
- const valuePPM = formatNumber(peak.x, peaksPreferences.deltaPPM.format);
+ const valuePPM = formatNumber(peak.x, tablePreferences.deltaPPM.format);
return (
diff --git a/src/component/modal/editRange/forms/components/NewSignalTab.tsx b/src/component/modal/editRange/forms/components/NewSignalTab.tsx
index acecf2746..3d728c32b 100644
--- a/src/component/modal/editRange/forms/components/NewSignalTab.tsx
+++ b/src/component/modal/editRange/forms/components/NewSignalTab.tsx
@@ -42,7 +42,7 @@ export function NewSignalTab(props: NewSignalTabProps) {
const { selectedTabId: signalIndex, selectTab } = useTabsController();
const { signals } = useWatch();
const activeTab = useActiveNucleusTab();
- const rangesPreferences = usePanelPreferences('ranges', activeTab);
+ const { tablePreferences } = usePanelPreferences('ranges', activeTab);
function saveHandler(val: any) {
const newSignal = {
@@ -95,8 +95,8 @@ export function NewSignalTab(props: NewSignalTabProps) {
Edit or select a delta value of new signal in range [
{`${formatNumber(
range.from,
- rangesPreferences.from.format,
- )} ppm - ${formatNumber(range.to, rangesPreferences.to.format)} ppm`}
+ tablePreferences.from.format,
+ )} ppm - ${formatNumber(range.to, tablePreferences.to.format)} ppm`}
]:
();
const deletePeakHandler = useCallback(
@@ -64,7 +64,7 @@ export function usePeaksTableColumns(activeTab: string) {
saveDeltaPPMRefsHandler(value, row.original)}
type="number"
@@ -78,7 +78,7 @@ export function usePeaksTableColumns(activeTab: string) {
Header: 'δ (Hz)',
accessor: 'xHz',
Cell: ({ row }: CellProps) =>
- formatNumber(row.original.xHz, peaksPreferences.deltaHz.format),
+ formatNumber(row.original.xHz, tablePreferences.deltaHz.format),
},
{
showWhen: 'intensity.show',
@@ -87,7 +87,7 @@ export function usePeaksTableColumns(activeTab: string) {
style: { maxWidth: '80px' },
accessor: 'y',
Cell: ({ row }: CellProps) =>
- formatNumber(row.original.y, peaksPreferences.intensity.format),
+ formatNumber(row.original.y, tablePreferences.intensity.format),
},
{
showWhen: 'peakWidth.show',
@@ -95,7 +95,7 @@ export function usePeaksTableColumns(activeTab: string) {
Header: 'Width (Hz)',
accessor: 'width',
Cell: ({ row }: CellProps) =>
- formatNumber(row.original.width, peaksPreferences.peakWidth.format),
+ formatNumber(row.original.width, tablePreferences.peakWidth.format),
},
{
showWhen: 'showKind',
@@ -111,7 +111,7 @@ export function usePeaksTableColumns(activeTab: string) {
Cell: ({ row }: CellProps) => {
const fwhm = row.original?.shape?.fwhm;
if (fwhm) {
- return formatNumber(fwhm, peaksPreferences.fwhm.format);
+ return formatNumber(fwhm, tablePreferences.fwhm.format);
}
return '';
},
@@ -127,7 +127,7 @@ export function usePeaksTableColumns(activeTab: string) {
row.original?.shape?.kind === 'pseudoVoigt' &&
row.original?.shape?.mu;
if (mu) {
- return formatNumber(mu, peaksPreferences.mu.format);
+ return formatNumber(mu, tablePreferences.mu.format);
}
return '';
},
@@ -144,7 +144,7 @@ export function usePeaksTableColumns(activeTab: string) {
row.original?.shape?.kind === 'generalizedLorentzian' &&
row.original?.shape?.gamma;
if (gamma) {
- return formatNumber(gamma, peaksPreferences.gamma.format);
+ return formatNumber(gamma, tablePreferences.gamma.format);
}
return '';
},
@@ -170,7 +170,7 @@ export function usePeaksTableColumns(activeTab: string) {
},
],
[
- peaksPreferences,
+ tablePreferences,
saveDeltaPPMRefsHandler,
deletePeakHandler,
editPeakHandler,
@@ -181,14 +181,14 @@ export function usePeaksTableColumns(activeTab: string) {
const columns: Array> = [];
for (const col of COLUMNS) {
const { showWhen, ...colParams } = col;
- if (dlv(peaksPreferences, showWhen)) {
+ if (dlv(tablePreferences, showWhen)) {
addCustomColumn(columns, colParams);
}
}
columns.sort((object1, object2) => object1.index - object2.index);
return columns;
- }, [COLUMNS, peaksPreferences]);
+ }, [COLUMNS, tablePreferences]);
return { tableColumns, peak, setEditedPeak };
}
diff --git a/src/component/panels/RangesPanel/RangesPreferences.tsx b/src/component/panels/RangesPanel/RangesPreferences.tsx
index 85e2c09a5..90f80dca1 100644
--- a/src/component/panels/RangesPanel/RangesPreferences.tsx
+++ b/src/component/panels/RangesPanel/RangesPreferences.tsx
@@ -18,91 +18,91 @@ const formatFields: NucleusPreferenceField[] = [
{
id: 1,
label: 'Serial number :',
- checkFieldName: 'showSerialNumber',
+ checkFieldName: 'tablePreferences.showSerialNumber',
hideFormatField: true,
},
{
id: 2,
label: 'Assignment label :',
- checkFieldName: 'showAssignmentLabel',
+ checkFieldName: 'tablePreferences.showAssignmentLabel',
hideFormatField: true,
},
{
id: 3,
label: 'From (ppm) :',
- checkFieldName: 'from.show',
- formatFieldName: 'from.format',
+ checkFieldName: 'tablePreferences.from.show',
+ formatFieldName: 'tablePreferences.from.format',
},
{
id: 4,
label: 'To (ppm) :',
- checkFieldName: 'to.show',
- formatFieldName: 'to.format',
+ checkFieldName: 'tablePreferences.to.show',
+ formatFieldName: 'tablePreferences.to.format',
},
{
id: 5,
label: 'Absolute integration :',
- checkFieldName: 'absolute.show',
- formatFieldName: 'absolute.format',
+ checkFieldName: 'tablePreferences.absolute.show',
+ formatFieldName: 'tablePreferences.absolute.format',
},
{
id: 6,
label: 'Relative integration :',
- checkFieldName: 'relative.show',
- formatFieldName: 'relative.format',
+ checkFieldName: 'tablePreferences.relative.show',
+ formatFieldName: 'tablePreferences.relative.format',
},
{
id: 7,
label: 'δ (ppm) :',
- checkFieldName: 'deltaPPM.show',
- formatFieldName: 'deltaPPM.format',
+ checkFieldName: 'tablePreferences.deltaPPM.show',
+ formatFieldName: 'tablePreferences.deltaPPM.format',
},
{
id: 8,
label: 'δ (Hz) :',
- checkFieldName: 'deltaHz.show',
- formatFieldName: 'deltaHz.format',
+ checkFieldName: 'tablePreferences.deltaHz.show',
+ formatFieldName: 'tablePreferences.deltaHz.format',
},
{
id: 9,
label: 'Coupling (Hz) :',
- checkFieldName: 'coupling.show',
- formatFieldName: 'coupling.format',
+ checkFieldName: 'tablePreferences.coupling.show',
+ formatFieldName: 'tablePreferences.coupling.format',
},
{
id: 10,
label: 'Kind :',
- checkFieldName: 'showKind',
+ checkFieldName: 'tablePreferences.showKind',
hideFormatField: true,
},
{
id: 11,
label: 'Multiplicity :',
- checkFieldName: 'showMultiplicity',
+ checkFieldName: 'tablePreferences.showMultiplicity',
hideFormatField: true,
},
{
id: 12,
label: 'Assignment links :',
- checkFieldName: 'showAssignment',
+ checkFieldName: 'tablePreferences.showAssignment',
hideFormatField: true,
},
{
id: 13,
label: 'Delete action :',
- checkFieldName: 'showDeleteAction',
+ checkFieldName: 'tablePreferences.showDeleteAction',
hideFormatField: true,
},
{
id: 14,
label: 'Zoom action :',
- checkFieldName: 'showZoomAction',
+ checkFieldName: 'tablePreferences.showZoomAction',
hideFormatField: true,
},
{
id: 15,
label: 'Edit action :',
- checkFieldName: 'showEditAction',
+ checkFieldName: 'tablePreferences.showEditAction',
hideFormatField: true,
},
];
diff --git a/src/component/panels/RangesPanel/RangesTable.tsx b/src/component/panels/RangesPanel/RangesTable.tsx
index 25a43bcc2..022ed517d 100644
--- a/src/component/panels/RangesPanel/RangesTable.tsx
+++ b/src/component/panels/RangesPanel/RangesTable.tsx
@@ -79,6 +79,8 @@ export default function RangesTable(props: RangesTableProps) {
info,
} = props;
+ const { tablePreferences } = preferences;
+
const element = extractChemicalElement(activeTab);
const { items: sortedData, isSortedDesc, onSort } = useTableSortBy(tableData);
const data = useMapRanges(sortedData);
@@ -92,9 +94,9 @@ export default function RangesTable(props: RangesTableProps) {
}
const showActions =
- preferences.showDeleteAction ||
- preferences.showEditAction ||
- preferences.showZoomAction;
+ tablePreferences.showDeleteAction ||
+ tablePreferences.showEditAction ||
+ tablePreferences.showZoomAction;
return (
<>
@@ -102,43 +104,43 @@ export default function RangesTable(props: RangesTableProps) {
- {preferences.showSerialNumber && | # | }
- {preferences.showAssignmentLabel && (
+ {tablePreferences.showSerialNumber && # | }
+ {tablePreferences.showAssignmentLabel && (
Assignment |
)}
- {preferences.from.show && (
+ {tablePreferences.from.show && (
From
{isSortedDesc('from').content}
|
)}
- {preferences.to.show && (
+ {tablePreferences.to.show && (
To {isSortedDesc('to').content}
|
)}
- {preferences.deltaPPM.show && (
+ {tablePreferences.deltaPPM.show && (
δ (ppm) {isSortedDesc('from').content}
|
)}
- {preferences.deltaHz.show && δ (Hz) | }
+ {tablePreferences.deltaHz.show && δ (Hz) | }
- {preferences.relative.show && (
+ {tablePreferences.relative.show && (
Rel. {element} {isSortedDesc('integration').content}
|
)}
- {preferences.absolute.show && Absolute | }
- {preferences.showMultiplicity && Mult. | }
- {preferences.coupling.show && J (Hz) | }
+ {tablePreferences.absolute.show && Absolute | }
+ {tablePreferences.showMultiplicity && Mult. | }
+ {tablePreferences.coupling.show && J (Hz) | }
- {preferences.showAssignment && (
+ {tablePreferences.showAssignment && (
|
)}
- {preferences.showKind && Kind | }
+ {tablePreferences.showKind && Kind | }
{showActions && {''} | }
diff --git a/src/component/panels/RangesPanel/RangesTableRow.tsx b/src/component/panels/RangesPanel/RangesTableRow.tsx
index f11ac95a5..01471d5a0 100644
--- a/src/component/panels/RangesPanel/RangesTableRow.tsx
+++ b/src/component/panels/RangesPanel/RangesTableRow.tsx
@@ -67,7 +67,7 @@ export default function RangesTableRow(props: RangesTableRowProps) {
rowData,
onContextMenuSelect,
contextMenu = [],
- preferences,
+ preferences: { tablePreferences },
info,
} = props;
const dispatch = useDispatch();
@@ -181,12 +181,12 @@ export default function RangesTableRow(props: RangesTableRowProps) {
as="tr"
style={trStyle}
>
- {preferences.showSerialNumber && (
+ {tablePreferences.showSerialNumber && (
{rowData.tableMetaInfo.rowIndex + 1}
|
)}
- {preferences.showAssignmentLabel && (
+ {tablePreferences.showAssignmentLabel && (
)}
- {preferences.from.show && (
+ {tablePreferences.from.show && (
)}
- {preferences.to.show && (
+ {tablePreferences.to.show && (
)}
- {preferences.deltaPPM.show && (
+ {tablePreferences.deltaPPM.show && (
)}
- {preferences.deltaHz.show && (
+ {tablePreferences.deltaHz.show && (
)}
- {preferences.relative.show && (
+ {tablePreferences.relative.show && (
)}
- {preferences.absolute.show && (
+ {tablePreferences.absolute.show && (
)}
- {preferences.showMultiplicity && (
+ {tablePreferences.showMultiplicity && (
{rowData.tableMetaInfo.signal?.multiplicity ?? 'm'}
|
)}
- {preferences.coupling.show && (
+ {tablePreferences.coupling.show && (
)}
- {preferences.showAssignment && (
+ {tablePreferences.showAssignment && (
);
diff --git a/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts b/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
index 4bb5f7d31..d42075251 100644
--- a/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
+++ b/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
@@ -1,10 +1,12 @@
import type {
BaseNucleus1DPreferences,
BaseNucleus2DPreferences,
+ BaseRangesTablePreferences,
MatrixGenerationOptions,
MultipleSpectraAnalysisPreferences,
PanelsPreferences,
PeaksNucleusPreferences,
+ RangesNucleusPreferences,
SpectraPreferences,
Zones1DNucleusPreferences,
Zones2DNucleusPreferences,
@@ -124,26 +126,33 @@ const getZoneDefaultValues = (nucleus?: string): PanelsPreferences['zones'] => {
}
};
+const createBaseRangesTablePreferences = (): BaseRangesTablePreferences => ({
+ showSerialNumber: true,
+ from: { show: false, format: '0.00' },
+ to: { show: false, format: '0.00' },
+ absolute: { show: false, format: '0.00' },
+ relative: { show: true, format: '0.00' },
+ deltaPPM: { show: true, format: '0.00' },
+ deltaHz: { show: false, format: '0.00' },
+ coupling: { show: true, format: '0.00' },
+ showKind: true,
+ showMultiplicity: true,
+ showAssignment: true,
+ showAssignmentLabel: true,
+});
+
const getRangeDefaultValues = (
nucleus?: string,
): PanelsPreferences['ranges'] => {
- const preferences = {
- showSerialNumber: true,
- from: { show: false, format: '0.00' },
- to: { show: false, format: '0.00' },
- absolute: { show: false, format: '0.00' },
- relative: { show: true, format: '0.00' },
- deltaPPM: { show: true, format: '0.00' },
- deltaHz: { show: false, format: '0.00' },
- coupling: { show: true, format: '0.00' },
+ const preferences: RangesNucleusPreferences = {
+ floatingTablePreferences: createBaseRangesTablePreferences(),
+ tablePreferences: {
+ ...createBaseRangesTablePreferences(),
+ showDeleteAction: true,
+ showZoomAction: true,
+ showEditAction: true,
+ },
jGraphTolerance: isProton(nucleus || '') ? 0.2 : nucleus === '13C' ? 2 : 0, //J Graph tolerance for: 1H: 0.2Hz 13C: 2Hz
- showKind: true,
- showMultiplicity: true,
- showAssignment: true,
- showDeleteAction: true,
- showZoomAction: true,
- showEditAction: true,
- showAssignmentLabel: true,
isSumConstant: true,
};
@@ -154,17 +163,19 @@ const getPeaksDefaultValues = (
nucleus?: string,
): PanelsPreferences['peaks'] => {
const preferences: PeaksNucleusPreferences = {
- showSerialNumber: true,
- deltaPPM: { show: true, format: '0.00' },
- deltaHz: { show: false, format: '0.00' },
- peakWidth: { show: false, format: '0.00' },
- intensity: { show: true, format: '0.00' },
- fwhm: { show: true, format: '0.00000' },
- mu: { show: false, format: '0.00000' },
- gamma: { show: false, format: '0.000' },
- showDeleteAction: true,
- showEditPeakShapeAction: true,
- showKind: true,
+ tablePreferences: {
+ showSerialNumber: true,
+ deltaPPM: { show: true, format: '0.00' },
+ deltaHz: { show: false, format: '0.00' },
+ peakWidth: { show: false, format: '0.00' },
+ intensity: { show: true, format: '0.00' },
+ fwhm: { show: true, format: '0.00000' },
+ mu: { show: false, format: '0.00000' },
+ gamma: { show: false, format: '0.000' },
+ showKind: true,
+ showDeleteAction: true,
+ showEditPeakShapeAction: true,
+ },
defaultPeakShape: DEFAULT_PEAK_SHAPE,
};
return getPreferences(preferences, nucleus);
diff --git a/src/demo/views/SnapshotView.tsx b/src/demo/views/SnapshotView.tsx
index 7bd5188fb..3a2619583 100644
--- a/src/demo/views/SnapshotView.tsx
+++ b/src/demo/views/SnapshotView.tsx
@@ -329,84 +329,159 @@ const customWorkspaces: CustomWorkspaces = {
ranges: {
nuclei: {
'1H': {
- isSumConstant: false,
- showAssignment: false,
- showAssignmentLabel: false,
- showSerialNumber: false,
- showDeleteAction: false,
- showEditAction: false,
- showMultiplicity: false,
- showZoomAction: false,
- from: {
- show: false,
- format: '0.00',
- },
- to: {
- show: false,
- format: '0.00',
- },
- absolute: {
- show: false,
- format: '0.00',
- },
- relative: {
- show: true,
- format: '0.00',
- },
- deltaPPM: {
- show: true,
- format: '0.00',
- },
- deltaHz: {
- show: false,
- format: '0.00',
+ tablePreferences: {
+ showAssignment: false,
+ showAssignmentLabel: false,
+ showSerialNumber: false,
+ showMultiplicity: false,
+ from: {
+ show: false,
+ format: '0.00',
+ },
+ to: {
+ show: false,
+ format: '0.00',
+ },
+ absolute: {
+ show: false,
+ format: '0.00',
+ },
+ relative: {
+ show: true,
+ format: '0.00',
+ },
+ deltaPPM: {
+ show: true,
+ format: '0.00',
+ },
+ deltaHz: {
+ show: false,
+ format: '0.00',
+ },
+ coupling: {
+ show: false,
+ format: '0.00',
+ },
+ showKind: false,
+ showDeleteAction: false,
+ showEditAction: false,
+ showZoomAction: false,
},
- coupling: {
- show: false,
- format: '0.00',
+ floatingTablePreferences: {
+ showAssignment: false,
+ showAssignmentLabel: false,
+ showSerialNumber: false,
+ showMultiplicity: false,
+ from: {
+ show: false,
+ format: '0.00',
+ },
+ to: {
+ show: false,
+ format: '0.00',
+ },
+ absolute: {
+ show: false,
+ format: '0.00',
+ },
+ relative: {
+ show: true,
+ format: '0.00',
+ },
+ deltaPPM: {
+ show: true,
+ format: '0.00',
+ },
+ deltaHz: {
+ show: false,
+ format: '0.00',
+ },
+ coupling: {
+ show: false,
+ format: '0.00',
+ },
+ showKind: false,
},
+ isSumConstant: false,
jGraphTolerance: 0.2,
- showKind: false,
},
'13C': {
- isSumConstant: false,
- showAssignment: false,
- showAssignmentLabel: false,
- showSerialNumber: false,
- showDeleteAction: false,
- showEditAction: false,
- showMultiplicity: false,
- showZoomAction: false,
- from: {
- show: false,
- format: '0.00',
- },
- to: {
- show: false,
- format: '0.00',
- },
- absolute: {
- show: false,
- format: '0.00',
- },
- relative: {
- show: true,
- format: '0.00',
- },
- deltaPPM: {
- show: true,
- format: '0.00',
- },
- deltaHz: {
- show: false,
- format: '0.00',
+ tablePreferences: {
+ showAssignment: false,
+ showAssignmentLabel: false,
+ showSerialNumber: false,
+ showMultiplicity: false,
+ from: {
+ show: false,
+ format: '0.00',
+ },
+ to: {
+ show: false,
+ format: '0.00',
+ },
+ absolute: {
+ show: false,
+ format: '0.00',
+ },
+ relative: {
+ show: true,
+ format: '0.00',
+ },
+ deltaPPM: {
+ show: true,
+ format: '0.00',
+ },
+ deltaHz: {
+ show: false,
+ format: '0.00',
+ },
+ coupling: {
+ show: true,
+ format: '0.00',
+ },
+ showKind: true,
+
+ showDeleteAction: false,
+ showEditAction: false,
+ showZoomAction: false,
},
- coupling: {
- show: true,
- format: '0.00',
+ floatingTablePreferences: {
+ showAssignment: false,
+ showAssignmentLabel: false,
+ showSerialNumber: false,
+ showMultiplicity: false,
+ from: {
+ show: false,
+ format: '0.00',
+ },
+ to: {
+ show: false,
+ format: '0.00',
+ },
+ absolute: {
+ show: false,
+ format: '0.00',
+ },
+ relative: {
+ show: true,
+ format: '0.00',
+ },
+ deltaPPM: {
+ show: true,
+ format: '0.00',
+ },
+ deltaHz: {
+ show: false,
+ format: '0.00',
+ },
+ coupling: {
+ show: true,
+ format: '0.00',
+ },
+ showKind: true,
},
+ isSumConstant: false,
jGraphTolerance: 2,
- showKind: true,
},
},
},
From 428b2f138ed98d77fbc9f13da18dec848b0a0309 Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Fri, 19 Jun 2026 12:49:14 +0200
Subject: [PATCH 3/8] feat: ranges table preferences
---
.../FloatingRangeTablePreferencesModal.tsx | 167 ++++++++++++++++++
.../1d/{ => ranges}/FloatingRanges.tsx | 128 ++++++++------
src/component/main/NMRiumViewer.tsx | 2 +-
3 files changed, 240 insertions(+), 57 deletions(-)
create mode 100644 src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
rename src/component/1d/{ => ranges}/FloatingRanges.tsx (73%)
diff --git a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
new file mode 100644
index 000000000..71f9b4559
--- /dev/null
+++ b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
@@ -0,0 +1,167 @@
+import { DialogBody, DialogFooter } from '@blueprintjs/core';
+import { useMemo } from 'react';
+import { useForm } from 'react-hook-form';
+import { Button } from 'react-science/ui';
+
+import { usePreferences } from '../../context/PreferencesContext.js';
+import { StandardDialog } from '../../elements/StandardDialog.tsx';
+import useNucleus from '../../hooks/useNucleus.js';
+import { usePanelPreferencesByNuclei } from '../../hooks/usePanelPreferences.js';
+import type { NucleusPreferenceField } from '../../panels/extra/preferences/NucleusPreferences.tsx';
+import { NucleusPreferences } from '../../panels/extra/preferences/NucleusPreferences.tsx';
+import { getUniqueNuclei } from '../../utility/getUniqueNuclei.js';
+
+
+
+
+const formatFields: NucleusPreferenceField[] = [
+ {
+ id: 1,
+ label: 'Serial number :',
+ checkFieldName: 'floatingTablePreferences.showSerialNumber',
+ hideFormatField: true,
+ },
+ {
+ id: 2,
+ label: 'Assignment label :',
+ checkFieldName: 'floatingTablePreferences.showAssignmentLabel',
+ hideFormatField: true,
+ },
+ {
+ id: 3,
+ label: 'From (ppm) :',
+ checkFieldName: 'floatingTablePreferences.from.show',
+ formatFieldName: 'floatingTablePreferences.from.format',
+ },
+ {
+ id: 4,
+ label: 'To (ppm) :',
+ checkFieldName: 'floatingTablePreferences.to.show',
+ formatFieldName: 'floatingTablePreferences.to.format',
+ },
+ {
+ id: 5,
+ label: 'Absolute integration :',
+ checkFieldName: 'floatingTablePreferences.absolute.show',
+ formatFieldName: 'floatingTablePreferences.absolute.format',
+ },
+ {
+ id: 6,
+ label: 'Relative integration :',
+ checkFieldName: 'floatingTablePreferences.relative.show',
+ formatFieldName: 'floatingTablePreferences.relative.format',
+ },
+ {
+ id: 7,
+ label: 'δ (ppm) :',
+ checkFieldName: 'floatingTablePreferences.deltaPPM.show',
+ formatFieldName: 'floatingTablePreferences.deltaPPM.format',
+ },
+ {
+ id: 8,
+ label: 'δ (Hz) :',
+ checkFieldName: 'floatingTablePreferences.deltaHz.show',
+ formatFieldName: 'floatingTablePreferences.deltaHz.format',
+ },
+ {
+ id: 9,
+ label: 'Coupling (Hz) :',
+ checkFieldName: 'floatingTablePreferences.coupling.show',
+ formatFieldName: 'floatingTablePreferences.coupling.format',
+ },
+ {
+ id: 10,
+ label: 'Kind :',
+ checkFieldName: 'floatingTablePreferences.showKind',
+ hideFormatField: true,
+ },
+ {
+ id: 11,
+ label: 'Multiplicity :',
+ checkFieldName: 'floatingTablePreferences.showMultiplicity',
+ hideFormatField: true,
+ },
+ {
+ id: 12,
+ label: 'Assignment links :',
+ checkFieldName: 'floatingTablePreferences.showAssignment',
+ hideFormatField: true,
+ },
+];
+
+interface InnerFloatingRangeTablePreferencesModalProps {
+ onCloseDialog: () => void;
+}
+
+interface FloatingRangeTablePreferencesModalProps extends InnerFloatingRangeTablePreferencesModalProps {
+ isOpen: boolean;
+}
+
+export function FloatingRangeTablePreferencesModal(props: FloatingRangeTablePreferencesModalProps) {
+ const { onCloseDialog, isOpen } = props;
+
+ if (!isOpen) return;
+
+
+
+ return
+
+
+}
+
+function InnerFloatingRangeTablePreferencesModal(props: InnerFloatingRangeTablePreferencesModalProps) {
+ const { onCloseDialog } = props;
+ const preferences = usePreferences();
+ const nucleus = useNucleus();
+ const nuclei = useMemo(() => getUniqueNuclei(nucleus), [nucleus]);
+ const preferencesByNuclei = usePanelPreferencesByNuclei('ranges', nuclei);
+
+
+
+ const { handleSubmit, control } = useForm({
+ defaultValues: preferencesByNuclei,
+ });
+ function saveHandler() {
+ void handleSubmit((values) => {
+ preferences.dispatch({
+ type: 'SET_PANELS_PREFERENCES',
+ payload: { key: 'ranges', value: values },
+ });
+ onCloseDialog();
+ })();
+
+ }
+
+
+ return (
+ <>
+
+ {nuclei?.map((n) => (
+
+ ))}
+
+
+
+
+
+
+
+ >
+ );
+}
+
diff --git a/src/component/1d/FloatingRanges.tsx b/src/component/1d/ranges/FloatingRanges.tsx
similarity index 73%
rename from src/component/1d/FloatingRanges.tsx
rename to src/component/1d/ranges/FloatingRanges.tsx
index f14ac92d9..5f6f7a934 100644
--- a/src/component/1d/FloatingRanges.tsx
+++ b/src/component/1d/ranges/FloatingRanges.tsx
@@ -4,25 +4,28 @@ import type { BoundingBox } from '@zakodium/nmrium-core';
import { checkMultiplicity } from 'nmr-processing';
import { memo, useEffect, useState } from 'react';
import { BsArrowsMove } from 'react-icons/bs';
-import { FaTimes } from 'react-icons/fa';
+import { FaCog, FaTimes } from 'react-icons/fa';
import { Rnd } from 'react-rnd';
-import { isSpectrum1D } from '../../data/data1d/Spectrum1D/index.js';
-import { isSignalRange } from '../../data/utilities/RangeUtilities.js';
-import type { SVGTableColumn } from '../SVGTable.js';
-import { SVGTable } from '../SVGTable.js';
-import { useChartData } from '../context/ChartContext.js';
-import { useDispatch } from '../context/DispatchContext.js';
-import { useGlobal } from '../context/GlobalContext.js';
-import type { ActionsButtonsPopoverProps } from '../elements/ActionsButtonsPopover.js';
-import { ActionsButtonsPopover } from '../elements/ActionsButtonsPopover.js';
-import { useActiveNucleusTab } from '../hooks/useActiveNucleusTab.js';
-import { usePanelPreferences } from '../hooks/usePanelPreferences.js';
-import { useSVGUnitConverter } from '../hooks/useSVGUnitConverter.js';
-import useSpectraByActiveNucleus from '../hooks/useSpectraPerNucleus.js';
-import { useCheckExportStatus } from '../hooks/useViewportSize.js';
-import { extractChemicalElement } from '../utility/extractChemicalElement.js';
-import { formatNumber } from '../utility/formatNumber.js';
+import { isSpectrum1D } from '../../../data/data1d/Spectrum1D/index.js';
+import { isSignalRange } from '../../../data/utilities/RangeUtilities.js';
+import type { SVGTableColumn } from '../../SVGTable.js';
+import { SVGTable } from '../../SVGTable.js';
+import { useChartData } from '../../context/ChartContext.js';
+import { useDispatch } from '../../context/DispatchContext.js';
+import { useGlobal } from '../../context/GlobalContext.js';
+import type { ActionsButtonsPopoverProps } from '../../elements/ActionsButtonsPopover.js';
+import { ActionsButtonsPopover } from '../../elements/ActionsButtonsPopover.js';
+import { useActiveNucleusTab } from '../../hooks/useActiveNucleusTab.js';
+import { useDialogToggle } from '../../hooks/useDialogToggle.ts';
+import { usePanelPreferences } from '../../hooks/usePanelPreferences.js';
+import { useSVGUnitConverter } from '../../hooks/useSVGUnitConverter.js';
+import useSpectraByActiveNucleus from '../../hooks/useSpectraPerNucleus.js';
+import { useCheckExportStatus } from '../../hooks/useViewportSize.js';
+import { extractChemicalElement } from '../../utility/extractChemicalElement.js';
+import { formatNumber } from '../../utility/formatNumber.js';
+
+import { FloatingRangeTablePreferencesModal } from './FloatingRangeTablePreferencesModal.tsx';
const ReactRnd = styled(Rnd)`
border: 1px solid transparent;
@@ -171,6 +174,7 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
const [isMoveActive, setIsMoveActive] = useState(false);
const { percentToPixel, pixelToPercent } = useSVGUnitConverter();
const isExportProcessStart = useCheckExportStatus();
+ const { dialog, closeDialog, openDialog } = useDialogToggle({ settingModal: false })
useEffect(() => {
setBounding({ ...externalBounding });
@@ -263,12 +267,20 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
const actionButtons: ActionsButtonsPopoverProps['buttons'] = [
{
icon: ,
-
intent: 'none',
title: 'Move ranges table',
style: { cursor: 'move' },
className: 'handle',
},
+ {
+ icon: ,
+ intent: 'none',
+ title: 'Table preferences',
+ onClick: () => {
+ openDialog('settingModal')
+ },
+
+ },
{
icon: ,
intent: 'danger',
@@ -292,45 +304,49 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
}
return (
- setIsMoveActive(true)}
- onResize={(e, dir, eRef, size, position) =>
- handleResize({ ...size, ...position })
- }
- onResizeStop={(e, dir, eRef, size, position) =>
- handleChangeInsetBounding({ ...size, ...position })
- }
- onDrag={(e, { x, y }) => {
- handleDrag({ x, y });
- }}
- onDragStop={(e, { x, y }) => {
- handleChangeInsetBounding({ x, y });
- setIsMoveActive(false);
- }}
- resizeHandleWrapperStyle={{ backgroundColor: 'white' }}
- >
-
+
+ setIsMoveActive(true)}
+ onResize={(e, dir, eRef, size, position) =>
+ handleResize({ ...size, ...position })
+ }
+ onResizeStop={(e, dir, eRef, size, position) =>
+ handleChangeInsetBounding({ ...size, ...position })
+ }
+ onDrag={(e, { x, y }) => {
+ handleDrag({ x, y });
+ }}
+ onDragStop={(e, { x, y }) => {
+ handleChangeInsetBounding({ x, y });
+ setIsMoveActive(false);
+ }}
+ resizeHandleWrapperStyle={{ backgroundColor: 'white' }}
>
-
-
-
+
+
+
+
+ >
+
);
}
diff --git a/src/component/main/NMRiumViewer.tsx b/src/component/main/NMRiumViewer.tsx
index 303ebfa8f..5795f34ad 100644
--- a/src/component/main/NMRiumViewer.tsx
+++ b/src/component/main/NMRiumViewer.tsx
@@ -2,9 +2,9 @@ import type { CSSProperties, RefObject } from 'react';
import { useDeferredValue, useEffect } from 'react';
import { FloatPublicationString } from '../1d/FloatPublicationString.js';
-import { FloatingRanges } from '../1d/FloatingRanges.js';
import { Viewer1D } from '../1d/Viewer1D.js';
import { SpectraInsets } from '../1d/inset/SpectraInsets.js';
+import { FloatingRanges } from '../1d/ranges/FloatingRanges.tsx';
import { FloatMolecules } from '../1d-2d/components/FloatMoleculeStructures/FloatMolecules.js';
import { SVGRootContainer } from '../1d-2d/components/SVGRootContainer.js';
import Viewer2D from '../2d/Viewer2D.js';
From c0427e74f4d19771009c45248b85be1f44ab8927 Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Mon, 22 Jun 2026 11:31:40 +0200
Subject: [PATCH 4/8] refactor: svg table
---
src/component/SVGTable.tsx | 68 ++++++++++++++++++++------------------
1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/src/component/SVGTable.tsx b/src/component/SVGTable.tsx
index 2d7af78e0..397eb850c 100644
--- a/src/component/SVGTable.tsx
+++ b/src/component/SVGTable.tsx
@@ -1,5 +1,5 @@
-import type { SVGAttributes } from 'react';
-import { createContext, useContext, useMemo } from 'react';
+import type { ReactElement, SVGAttributes } from 'react';
+import { createContext, isValidElement, useContext, useMemo } from 'react';
type CellTextProps = Omit<
SVGAttributes,
@@ -15,7 +15,7 @@ interface StyleCell {
cellBoxProps?: CellBoxProps;
}
interface BaseSVGTableColumn extends StyleCell {
- header: string;
+ header: string | ReactElement;
width: number;
minWidth?: number;
rowSpanGroupKey?: keyof T;
@@ -27,7 +27,7 @@ interface AccessorKeyColumn extends BaseSVGTableColumn {
}
interface AccessorFuncColumn extends BaseSVGTableColumn {
- accessorFun: (row: T) => number | string;
+ accessorFun: (row: T & { index: number }) => number | string;
}
export type SVGTableColumn = AccessorKeyColumn | AccessorFuncColumn;
@@ -69,14 +69,14 @@ function mapColumns(columns: Array>) {
}
interface FormatKeyOptions {
- rowIndex: number;
+ index: number;
columnKey: string;
groupKey: string;
}
function formatKey(options: FormatKeyOptions) {
- const { rowIndex, columnKey, groupKey } = options;
- return `GroupKey[${groupKey || null}]-ColumnKey[${columnKey}]-RowIndex[${rowIndex}]`;
+ const { index, columnKey, groupKey } = options;
+ return `GroupKey[${groupKey || null}]-ColumnKey[${columnKey}]-RowIndex[${index}]`;
}
function mapRowsSpan(data: T[], columns: Array>) {
@@ -89,14 +89,14 @@ function mapRowsSpan(data: T[], columns: Array>) {
let lastRowIndex = 0;
let lastGroupKey: string | null = null;
- for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
- const row = data[rowIndex];
+ for (let index = 0; index < data.length; index++) {
+ const row = data[index];
const groupKey = String(row?.[col.rowSpanGroupKey] || '');
const key = col._columnOptions.key;
const value = isAccessorKeyColumn(col)
? (row as any)[col.accessorKey]
- : col.accessorFun(row);
+ : col.accessorFun({ ...row, index });
if (
value === lastValue &&
@@ -107,16 +107,16 @@ function mapRowsSpan(data: T[], columns: Array>) {
const prevKey = formatKey({
groupKey,
columnKey: key,
- rowIndex: lastRowIndex,
+ index: lastRowIndex,
});
rowSpanMap.set(prevKey, (rowSpanMap.get(prevKey) || 1) + 1);
- skipColumns.add(formatKey({ groupKey, columnKey: key, rowIndex }));
+ skipColumns.add(formatKey({ groupKey, columnKey: key, index }));
} else {
// Start a new rowspan
lastValue = value;
- lastRowIndex = rowIndex;
+ lastRowIndex = index;
lastGroupKey = groupKey;
- rowSpanMap.set(formatKey({ groupKey, columnKey: key, rowIndex }), 1);
+ rowSpanMap.set(formatKey({ groupKey, columnKey: key, index }), 1);
}
}
}
@@ -170,11 +170,11 @@ export function SVGTable(props: SVGTableProps) {
);
})}
- {data.map((row, rowIndex) => {
+ {data.map((row, index) => {
return (
{columns.map((col) => {
const {
@@ -187,7 +187,7 @@ export function SVGTable(props: SVGTableProps) {
const cellKey = formatKey({
groupKey: String(groupKey),
columnKey,
- rowIndex,
+ index,
});
if (skipColumns.has(cellKey)) {
return null; // Skip merged row
@@ -199,7 +199,7 @@ export function SVGTable(props: SVGTableProps) {
extends StyleCell {
}
interface ColumnProps extends BaseColumnProps {
- value: string | number;
+ value: string | number | ReactElement;
}
interface ValueColumnProps extends BaseColumnProps {
- row: T;
+ row: T & { index: number };
}
function ValueColumn(props: ValueColumnProps) {
@@ -250,10 +250,8 @@ function Column(props: ColumnProps) {
const { rowHeight } = tableOptions;
return (
-
+
(props: ColumnProps) {
strokeWidth="1"
{...cellBoxProps}
/>
-
- {value}
-
+ {isValidElement(value) ? (
+ value
+ ) : (
+
+ {value}
+
+ )}
);
}
From 9626981f2c222e5033ebbc2efcecf3154b60d906 Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Mon, 22 Jun 2026 11:32:24 +0200
Subject: [PATCH 5/8] refactor: improve floating ranges table
---
src/component/1d/peaks/usePeakShapesPath.ts | 12 +-
.../FloatingRangeTablePreferencesModal.tsx | 48 +--
src/component/1d/ranges/FloatingRanges.tsx | 347 ++++++++++++------
3 files changed, 260 insertions(+), 147 deletions(-)
diff --git a/src/component/1d/peaks/usePeakShapesPath.ts b/src/component/1d/peaks/usePeakShapesPath.ts
index 18e9f71f0..544fd5dcd 100644
--- a/src/component/1d/peaks/usePeakShapesPath.ts
+++ b/src/component/1d/peaks/usePeakShapesPath.ts
@@ -9,13 +9,13 @@ import { PathBuilder } from '../../utility/PathBuilder.js';
type PeaksShapesOptions =
| {
- target: 'peakShape';
- peak: Peak1D;
- }
+ target: 'peakShape';
+ peak: Peak1D;
+ }
| {
- target: 'peaksSum';
- peaks: Peak1D[];
- };
+ target: 'peaksSum';
+ peaks: Peak1D[];
+ };
export function usePeakShapesPath(spectrum: Spectrum1D) {
const { scaleX, scaleY } = useScaleChecked();
diff --git a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
index 71f9b4559..68d8ac875 100644
--- a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
+++ b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
@@ -11,9 +11,6 @@ import type { NucleusPreferenceField } from '../../panels/extra/preferences/Nucl
import { NucleusPreferences } from '../../panels/extra/preferences/NucleusPreferences.tsx';
import { getUniqueNuclei } from '../../utility/getUniqueNuclei.js';
-
-
-
const formatFields: NucleusPreferenceField[] = [
{
id: 1,
@@ -81,12 +78,6 @@ const formatFields: NucleusPreferenceField[] = [
checkFieldName: 'floatingTablePreferences.showMultiplicity',
hideFormatField: true,
},
- {
- id: 12,
- label: 'Assignment links :',
- checkFieldName: 'floatingTablePreferences.showAssignment',
- hideFormatField: true,
- },
];
interface InnerFloatingRangeTablePreferencesModalProps {
@@ -97,32 +88,34 @@ interface FloatingRangeTablePreferencesModalProps extends InnerFloatingRangeTabl
isOpen: boolean;
}
-export function FloatingRangeTablePreferencesModal(props: FloatingRangeTablePreferencesModalProps) {
+export function FloatingRangeTablePreferencesModal(
+ props: FloatingRangeTablePreferencesModalProps,
+) {
const { onCloseDialog, isOpen } = props;
if (!isOpen) return;
-
-
- return
-
-
+ return (
+
+
+
+ );
}
-function InnerFloatingRangeTablePreferencesModal(props: InnerFloatingRangeTablePreferencesModalProps) {
+function InnerFloatingRangeTablePreferencesModal(
+ props: InnerFloatingRangeTablePreferencesModalProps,
+) {
const { onCloseDialog } = props;
const preferences = usePreferences();
const nucleus = useNucleus();
const nuclei = useMemo(() => getUniqueNuclei(nucleus), [nucleus]);
const preferencesByNuclei = usePanelPreferencesByNuclei('ranges', nuclei);
-
-
const { handleSubmit, control } = useForm({
defaultValues: preferencesByNuclei,
});
@@ -134,10 +127,8 @@ function InnerFloatingRangeTablePreferencesModal(props: InnerFloatingRangeTableP
});
onCloseDialog();
})();
-
}
-
return (
<>
@@ -152,16 +143,11 @@ function InnerFloatingRangeTablePreferencesModal(props: InnerFloatingRangeTableP
-
-
>
);
}
-
diff --git a/src/component/1d/ranges/FloatingRanges.tsx b/src/component/1d/ranges/FloatingRanges.tsx
index 5f6f7a934..d88e1406f 100644
--- a/src/component/1d/ranges/FloatingRanges.tsx
+++ b/src/component/1d/ranges/FloatingRanges.tsx
@@ -1,10 +1,13 @@
import styled from '@emotion/styled';
-import type { Ranges } from '@zakodium/nmr-types';
-import type { BoundingBox } from '@zakodium/nmrium-core';
+import type { Info1D, Range, Ranges, Signal1D } from '@zakodium/nmr-types';
+import type {
+ BaseRangesTablePreferences,
+ BoundingBox,
+} from '@zakodium/nmrium-core';
import { checkMultiplicity } from 'nmr-processing';
-import { memo, useEffect, useState } from 'react';
+import { memo, useEffect, useMemo, useState } from 'react';
import { BsArrowsMove } from 'react-icons/bs';
-import { FaCog, FaTimes } from 'react-icons/fa';
+import { FaCog, FaLink, FaTimes } from 'react-icons/fa';
import { Rnd } from 'react-rnd';
import { isSpectrum1D } from '../../../data/data1d/Spectrum1D/index.js';
@@ -39,142 +42,265 @@ const ReactRnd = styled(Rnd)`
}
}
`;
+interface SpectrumRangesInfo {
+ ranges: Ranges['values'];
+ info: Info1D;
+}
interface RangesTableProps {
- ranges: Ranges['values'];
+ data: SpectrumRangesInfo;
}
interface RangeItem {
id: string;
delta: string;
+ deltaHz: string;
multiplicity: string;
integration: string;
coupling: string;
+ from: string;
+ to: string;
+ absolute: string;
+ kind: string;
+ assignment: string;
+ nbAssignment: string;
+}
+
+function buildRangeBaseItem(
+ range: Range,
+ info: Info1D,
+ preferences: BaseRangesTablePreferences,
+) {
+ const { id, from, to, integration, absolute } = range;
+ const formatHz = preferences.deltaHz.format;
+ return {
+ id,
+ from: formatNumber(from, preferences.from.format),
+ to: formatNumber(to, preferences.to.format),
+ absolute: formatNumber(absolute, preferences.absolute.format),
+ integration: isSignalRange(range)
+ ? formatNumber(integration, preferences.relative.format)
+ : `[ ${formatNumber(integration, preferences.relative.format)} ]`,
+ deltaText: `${formatNumber(from, preferences.from.format)} - ${formatNumber(to, preferences.to.format)}`,
+ deltaHzText: `${formatNumber(from * info.originFrequency, formatHz)} - ${formatNumber(to * info.originFrequency, formatHz)}`,
+ formatHz,
+ };
}
-function useMapRanges(ranges: Ranges['values']) {
- const output: RangeItem[] = [];
+function buildSignalItem(
+ signal: Signal1D,
+ base: ReturnType,
+ info: Info1D,
+ preferences: BaseRangesTablePreferences,
+): RangeItem {
+ const {
+ multiplicity,
+ delta,
+ kind = '',
+ assignment = '',
+ js = [],
+ diaIDs,
+ } = signal;
+ const isNotMultiplet = !checkMultiplicity(multiplicity, ['m']);
+ return {
+ id: base.id,
+ from: base.from,
+ to: base.to,
+ absolute: base.absolute,
+ integration: base.integration,
+ multiplicity,
+ kind,
+ assignment,
+ coupling: js
+ .map((j) =>
+ !Number.isNaN(j.coupling)
+ ? formatNumber(j.coupling, preferences.coupling.format)
+ : '',
+ )
+ .join(','),
+ delta: isNotMultiplet
+ ? base.deltaText
+ : formatNumber(delta, preferences.deltaPPM.format),
+ deltaHz: isNotMultiplet
+ ? base.deltaHzText
+ : info?.originFrequency
+ ? formatNumber(delta * info.originFrequency, base.formatHz)
+ : '',
+ nbAssignment: diaIDs?.length ? String(diaIDs.length) : '',
+ };
+}
+
+function useMapRanges(data: SpectrumRangesInfo): RangeItem[] {
+ const { ranges, info } = data;
const activeTab = useActiveNucleusTab();
- const { tablePreferences } = usePanelPreferences('ranges', activeTab);
- for (const range of ranges) {
- const { id, from, to, integration, signals = [] } = range;
- const relativeFlag = isSignalRange(range);
- const formattedValue = formatNumber(
- integration,
- tablePreferences.relative.format,
- );
- const integrationValue = relativeFlag
- ? formattedValue
- : `[ ${formattedValue} ]`;
-
- const rangeText = `${formatNumber(from, tablePreferences.from.format)} - ${formatNumber(
- to,
- tablePreferences.to.format,
- )}`;
- if (signals.length > 0) {
- for (const signal of signals) {
- const { multiplicity, delta, js = [] } = signal;
- const coupling = js
- .map((jsItem) =>
- !Number.isNaN(jsItem.coupling)
- ? formatNumber(jsItem.coupling, tablePreferences.coupling.format)
- : '',
- )
- .join(',');
- const signalDelta = !checkMultiplicity(multiplicity, ['m'])
- ? rangeText
- : formatNumber(delta, tablePreferences.deltaPPM.format);
- output.push({
- id,
- delta: signalDelta,
- multiplicity,
- integration: integrationValue,
- coupling,
- });
- }
- } else {
- output.push({
- id,
- delta: rangeText,
- multiplicity: 'm',
- integration: integrationValue,
- coupling: '',
- });
+ const { floatingTablePreferences: preferences } = usePanelPreferences(
+ 'ranges',
+ activeTab,
+ );
+
+ return ranges.flatMap((range) => {
+ const base = buildRangeBaseItem(range, info, preferences);
+ const { signals = [] } = range;
+
+ if (signals.length === 0) {
+ return [
+ {
+ ...base,
+ delta: base.deltaText,
+ deltaHz: '',
+ multiplicity: 'm',
+ coupling: '',
+ kind: '',
+ assignment: '',
+ nbAssignment: '',
+ },
+ ];
}
- }
- return output;
+
+ return signals.map((signal) =>
+ buildSignalItem(signal, base, info, preferences),
+ );
+ });
+}
+
+function isColumnVisible(
+ pref: BaseRangesTablePreferences[keyof BaseRangesTablePreferences],
+): boolean {
+ if (typeof pref === 'boolean') return pref;
+ return pref?.show;
}
+
function InnerSVGRangesTable(props: RangesTableProps) {
- const { ranges } = props;
+ const { data } = props;
const {
view: {
spectra: { activeTab },
},
} = useChartData();
- const data = useMapRanges(ranges);
-
- if (!data) return null;
+ const rangesData = useMapRanges(data);
+ const { floatingTablePreferences } = usePanelPreferences('ranges', activeTab);
const element = extractChemicalElement(activeTab);
- const columns: Array> = [
- {
- accessorKey: 'delta',
- header: 'δ (ppm)',
- width: 100,
- rowSpanGroupKey: 'id',
- headerTextProps: { fontWeight: 'bold' },
- cellBoxProps: { stroke: '#dedede', fill: 'white', fillOpacity: 0.8 },
- headerBoxProps: { stroke: '#dedede', fill: '#E5E8EB' },
- },
- {
- accessorKey: 'integration',
- header: `Rel. ${element}`,
- width: 60,
- rowSpanGroupKey: 'id',
- headerTextProps: { fontWeight: 'bold' },
- cellBoxProps: { stroke: '#dedede', fill: 'white', fillOpacity: 0.8 },
- headerBoxProps: { stroke: '#dedede', fill: '#E5E8EB' },
- },
- {
- accessorKey: 'multiplicity',
- header: 'Mult.',
- width: 60,
- rowSpanGroupKey: 'id',
- headerTextProps: { fontWeight: 'bold' },
- cellBoxProps: { stroke: '#dedede', fill: 'white', fillOpacity: 0.8 },
- headerBoxProps: { stroke: '#dedede', fill: '#E5E8EB' },
- },
- {
- accessorKey: 'coupling',
- header: 'J (Hz)',
- width: 120,
- headerTextProps: { fontWeight: 'bold' },
- cellBoxProps: { stroke: '#dedede', fill: 'white', fillOpacity: 0.8 },
- headerBoxProps: { stroke: '#dedede', fill: '#E5E8EB' },
- },
- ];
+ const columns = useMemo((): Array> => {
+ const allColumns: Array<
+ { prefKey: keyof BaseRangesTablePreferences } & SVGTableColumn
+ > = [
+ {
+ prefKey: 'showSerialNumber',
+ accessorFun: (row) => row.index + 1,
+ header: '#',
+ width: 40,
+ },
+ {
+ prefKey: 'showAssignmentLabel',
+ accessorKey: 'assignment',
+ header: 'Assignment',
+ width: 120,
+ },
+ {
+ prefKey: 'deltaPPM',
+ accessorKey: 'delta',
+ header: 'δ (ppm)',
+ width: 100,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'deltaHz',
+ accessorKey: 'deltaHz',
+ header: 'δ (Hz)',
+ width: 110,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'from',
+ accessorKey: 'from',
+ header: `From`,
+ width: 60,
+ },
+ {
+ prefKey: 'to',
+ accessorKey: 'to',
+ header: `To`,
+ width: 60,
+ },
+ {
+ prefKey: 'relative',
+ accessorKey: 'integration',
+ header: `Rel. ${element}`,
+ width: 60,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'absolute',
+ accessorKey: 'absolute',
+ header: 'Absolute',
+ width: 80,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'showMultiplicity',
+ accessorKey: 'multiplicity',
+ header: 'Mult.',
+ width: 60,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'coupling',
+ accessorKey: 'coupling',
+ header: 'J (Hz)',
+ width: 120,
+ },
+
+ {
+ prefKey: 'showAssignment',
+ accessorKey: 'nbAssignment',
+ header: ,
+ width: 40,
+ },
+ {
+ prefKey: 'showKind',
+ accessorKey: 'kind',
+ header: 'Kind',
+ width: 120,
+ },
+ ];
+
+ return allColumns
+ .filter(({ prefKey }) =>
+ isColumnVisible(floatingTablePreferences[prefKey]),
+ )
+ .map(({ prefKey: _, ...col }) => ({
+ ...col,
+ headerTextProps: { fontWeight: 'bold' },
+ cellBoxProps: { stroke: '#dedede', fill: 'white', fillOpacity: 0.8 },
+ headerBoxProps: { stroke: '#dedede', fill: '#E5E8EB' },
+ }));
+ }, [floatingTablePreferences, element]);
+ if (!data) return null;
- return data={data} columns={columns} />;
+ return data={rangesData} columns={columns} />;
}
const SVGRangesTable = memo(InnerSVGRangesTable);
interface DraggablePublicationStringProps {
- ranges: Ranges['values'] | undefined;
+ data: SpectrumRangesInfo | undefined;
bonding: BoundingBox;
spectrumKey: string;
}
function DraggableRanges(props: DraggablePublicationStringProps) {
- const { ranges = [], bonding: externalBounding, spectrumKey } = props;
+ const { data, bonding: externalBounding, spectrumKey } = props;
const dispatch = useDispatch();
const { viewerRef } = useGlobal();
const [bounding, setBounding] = useState(externalBounding);
const [isMoveActive, setIsMoveActive] = useState(false);
const { percentToPixel, pixelToPercent } = useSVGUnitConverter();
const isExportProcessStart = useCheckExportStatus();
- const { dialog, closeDialog, openDialog } = useDialogToggle({ settingModal: false })
+ const { dialog, closeDialog, openDialog } = useDialogToggle({
+ settingModal: false,
+ });
useEffect(() => {
setBounding({ ...externalBounding });
@@ -277,9 +403,8 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
intent: 'none',
title: 'Table preferences',
onClick: () => {
- openDialog('settingModal')
+ openDialog('settingModal');
},
-
},
{
icon: ,
@@ -288,7 +413,7 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
onClick: handleRemove,
},
];
- if (!viewerRef || ranges.length === 0) return null;
+ if (!viewerRef || !data || data?.ranges?.length === 0) return null;
const { x: xInPercent, y: yInPercent } = bounding;
@@ -298,14 +423,17 @@ function DraggableRanges(props: DraggablePublicationStringProps) {
if (isExportProcessStart) {
return (
-
+
);
}
return (
<>
-
+
-
+
>
-
);
}
function useSpectraRanges() {
const spectra = useSpectraByActiveNucleus();
- const output: Record = {};
+ const output: Record = {};
for (const spectrum of spectra) {
if (!isSpectrum1D(spectrum)) {
continue;
}
- const { id: spectrumKey, ranges } = spectrum;
+ const { id: spectrumKey, ranges, info } = spectrum;
if (!Array.isArray(ranges?.values) || ranges.values.length === 0) {
continue;
}
- output[spectrumKey] = ranges.values;
+ output[spectrumKey] = { ranges: ranges.values, info };
}
return output;
@@ -387,7 +514,7 @@ export function FloatingRanges() {
key={spectrumKey}
spectrumKey={spectrumKey}
bonding={rangesBounding}
- ranges={spectraRanges[spectrumKey]}
+ data={spectraRanges[spectrumKey]}
/>
);
});
From aaf37ad6fb8fdf09a2d8b9901a6244036db411fc Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Tue, 23 Jun 2026 09:16:19 +0200
Subject: [PATCH 6/8] fix: show assignemnt
---
.../FloatingRangeTablePreferencesModal.tsx | 6 +
src/component/1d/ranges/FloatingRanges.tsx | 156 +++++++++---------
2 files changed, 84 insertions(+), 78 deletions(-)
diff --git a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
index 68d8ac875..95e8ba58d 100644
--- a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
+++ b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
@@ -78,6 +78,12 @@ const formatFields: NucleusPreferenceField[] = [
checkFieldName: 'floatingTablePreferences.showMultiplicity',
hideFormatField: true,
},
+ {
+ id: 12,
+ label: 'Assignment :',
+ checkFieldName: 'floatingTablePreferences.showAssignment',
+ hideFormatField: true,
+ },
];
interface InnerFloatingRangeTablePreferencesModalProps {
diff --git a/src/component/1d/ranges/FloatingRanges.tsx b/src/component/1d/ranges/FloatingRanges.tsx
index d88e1406f..9bba9be7b 100644
--- a/src/component/1d/ranges/FloatingRanges.tsx
+++ b/src/component/1d/ranges/FloatingRanges.tsx
@@ -186,85 +186,85 @@ function InnerSVGRangesTable(props: RangesTableProps) {
const allColumns: Array<
{ prefKey: keyof BaseRangesTablePreferences } & SVGTableColumn
> = [
- {
- prefKey: 'showSerialNumber',
- accessorFun: (row) => row.index + 1,
- header: '#',
- width: 40,
- },
- {
- prefKey: 'showAssignmentLabel',
- accessorKey: 'assignment',
- header: 'Assignment',
- width: 120,
- },
- {
- prefKey: 'deltaPPM',
- accessorKey: 'delta',
- header: 'δ (ppm)',
- width: 100,
- rowSpanGroupKey: 'id',
- },
- {
- prefKey: 'deltaHz',
- accessorKey: 'deltaHz',
- header: 'δ (Hz)',
- width: 110,
- rowSpanGroupKey: 'id',
- },
- {
- prefKey: 'from',
- accessorKey: 'from',
- header: `From`,
- width: 60,
- },
- {
- prefKey: 'to',
- accessorKey: 'to',
- header: `To`,
- width: 60,
- },
- {
- prefKey: 'relative',
- accessorKey: 'integration',
- header: `Rel. ${element}`,
- width: 60,
- rowSpanGroupKey: 'id',
- },
- {
- prefKey: 'absolute',
- accessorKey: 'absolute',
- header: 'Absolute',
- width: 80,
- rowSpanGroupKey: 'id',
- },
- {
- prefKey: 'showMultiplicity',
- accessorKey: 'multiplicity',
- header: 'Mult.',
- width: 60,
- rowSpanGroupKey: 'id',
- },
- {
- prefKey: 'coupling',
- accessorKey: 'coupling',
- header: 'J (Hz)',
- width: 120,
- },
+ {
+ prefKey: 'showSerialNumber',
+ accessorFun: (row) => row.index + 1,
+ header: '#',
+ width: 40,
+ },
+ {
+ prefKey: 'showAssignmentLabel',
+ accessorKey: 'assignment',
+ header: 'Assignment',
+ width: 120,
+ },
+ {
+ prefKey: 'deltaPPM',
+ accessorKey: 'delta',
+ header: 'δ (ppm)',
+ width: 100,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'deltaHz',
+ accessorKey: 'deltaHz',
+ header: 'δ (Hz)',
+ width: 110,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'from',
+ accessorKey: 'from',
+ header: `From`,
+ width: 60,
+ },
+ {
+ prefKey: 'to',
+ accessorKey: 'to',
+ header: `To`,
+ width: 60,
+ },
+ {
+ prefKey: 'relative',
+ accessorKey: 'integration',
+ header: `Rel. ${element}`,
+ width: 60,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'absolute',
+ accessorKey: 'absolute',
+ header: 'Absolute',
+ width: 80,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'showMultiplicity',
+ accessorKey: 'multiplicity',
+ header: 'Mult.',
+ width: 60,
+ rowSpanGroupKey: 'id',
+ },
+ {
+ prefKey: 'coupling',
+ accessorKey: 'coupling',
+ header: 'J (Hz)',
+ width: 120,
+ },
- {
- prefKey: 'showAssignment',
- accessorKey: 'nbAssignment',
- header: ,
- width: 40,
- },
- {
- prefKey: 'showKind',
- accessorKey: 'kind',
- header: 'Kind',
- width: 120,
- },
- ];
+ {
+ prefKey: 'showAssignment',
+ accessorKey: 'nbAssignment',
+ header: ,
+ width: 40,
+ },
+ {
+ prefKey: 'showKind',
+ accessorKey: 'kind',
+ header: 'Kind',
+ width: 120,
+ },
+ ];
return allColumns
.filter(({ prefKey }) =>
From 9b2e48bca76cb5c5711efd2aa813c6e968c131f2 Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Tue, 23 Jun 2026 10:23:21 +0200
Subject: [PATCH 7/8] feat: filter floating ranges table by signal kinds
---
.../FloatingRangeTablePreferencesModal.tsx | 85 ++++++++++++++++++-
src/component/1d/ranges/FloatingRanges.tsx | 14 ++-
.../panelsPreferencesDefaultValues.ts | 32 +++----
src/data/constants/signalsKinds.ts | 2 +-
src/demo/views/SnapshotView.tsx | 2 +
5 files changed, 113 insertions(+), 22 deletions(-)
diff --git a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
index 95e8ba58d..6bcf29de0 100644
--- a/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
+++ b/src/component/1d/ranges/FloatingRangeTablePreferencesModal.tsx
@@ -1,9 +1,16 @@
-import { DialogBody, DialogFooter } from '@blueprintjs/core';
+import { DialogBody, DialogFooter, MenuItem } from '@blueprintjs/core';
+import { MultiSelect } from '@blueprintjs/select';
+import type { SignalKind } from '@zakodium/nmr-types';
import { useMemo } from 'react';
-import { useForm } from 'react-hook-form';
+import type { Control } from 'react-hook-form';
+import { useController, useForm } from 'react-hook-form';
import { Button } from 'react-science/ui';
+import type { SignalKindItem } from '../../../data/constants/signalsKinds.ts';
+import { SIGNAL_KINDS } from '../../../data/constants/signalsKinds.ts';
import { usePreferences } from '../../context/PreferencesContext.js';
+import { fieldLabelStyle } from '../../elements/FormatField.tsx';
+import Label from '../../elements/Label.tsx';
import { StandardDialog } from '../../elements/StandardDialog.tsx';
import useNucleus from '../../hooks/useNucleus.js';
import { usePanelPreferencesByNuclei } from '../../hooks/usePanelPreferences.js';
@@ -121,7 +128,6 @@ function InnerFloatingRangeTablePreferencesModal(
const nucleus = useNucleus();
const nuclei = useMemo(() => getUniqueNuclei(nucleus), [nucleus]);
const preferencesByNuclei = usePanelPreferencesByNuclei('ranges', nuclei);
-
const { handleSubmit, control } = useForm({
defaultValues: preferencesByNuclei,
});
@@ -144,6 +150,9 @@ function InnerFloatingRangeTablePreferencesModal(
control={control}
nucleus={n}
fields={formatFields}
+ renderBottom={() => (
+
+ )}
/>
))}
@@ -157,3 +166,73 @@ function InnerFloatingRangeTablePreferencesModal(
>
);
}
+
+interface SignalKindFilterProps {
+ control: Control;
+ nucleus: string;
+}
+
+function SignalKindFilter({ control, nucleus }: SignalKindFilterProps) {
+ const { field } = useController({
+ control,
+ name: `nuclei.${nucleus}.floatingTablePreferences.signalKinds`,
+ defaultValue: [],
+ });
+
+ const selectedKinds: SignalKind[] = field.value ?? [];
+
+ function handleSelect(item: SignalKindItem) {
+ const already = selectedKinds.includes(item.value);
+ field.onChange(
+ already
+ ? selectedKinds.filter((k) => k !== item.value)
+ : [...selectedKinds, item.value],
+ );
+ }
+
+ function handleRemove(item: SignalKindItem, index: number) {
+ field.onChange(selectedKinds.filter((_, i) => i !== index));
+ }
+
+ function handleClear() {
+ field.onChange([]);
+ }
+
+ const selectedItems = SIGNAL_KINDS.filter((k) =>
+ selectedKinds.includes(k.value),
+ );
+
+ return (
+
+ );
+}
diff --git a/src/component/1d/ranges/FloatingRanges.tsx b/src/component/1d/ranges/FloatingRanges.tsx
index 9bba9be7b..620607455 100644
--- a/src/component/1d/ranges/FloatingRanges.tsx
+++ b/src/component/1d/ranges/FloatingRanges.tsx
@@ -3,6 +3,7 @@ import type { Info1D, Range, Ranges, Signal1D } from '@zakodium/nmr-types';
import type {
BaseRangesTablePreferences,
BoundingBox,
+ FloatingRangesTablePreferences,
} from '@zakodium/nmrium-core';
import { checkMultiplicity } from 'nmr-processing';
import { memo, useEffect, useMemo, useState } from 'react';
@@ -69,7 +70,7 @@ interface RangeItem {
function buildRangeBaseItem(
range: Range,
info: Info1D,
- preferences: BaseRangesTablePreferences,
+ preferences: FloatingRangesTablePreferences,
) {
const { id, from, to, integration, absolute } = range;
const formatHz = preferences.deltaHz.format;
@@ -91,7 +92,7 @@ function buildSignalItem(
signal: Signal1D,
base: ReturnType,
info: Info1D,
- preferences: BaseRangesTablePreferences,
+ preferences: FloatingRangesTablePreferences,
): RangeItem {
const {
multiplicity,
@@ -157,9 +158,16 @@ function useMapRanges(data: SpectrumRangesInfo): RangeItem[] {
];
}
- return signals.map((signal) =>
+ const result = signals.map((signal) =>
buildSignalItem(signal, base, info, preferences),
);
+ if (preferences.signalKinds.length === 0) {
+ return result;
+ }
+
+ return result.filter((signal) =>
+ preferences.signalKinds.includes(signal.kind || ''),
+ );
});
}
diff --git a/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts b/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
index d42075251..ae1a8e3ea 100644
--- a/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
+++ b/src/component/reducer/preferences/panelsPreferencesDefaultValues.ts
@@ -1,7 +1,7 @@
import type {
BaseNucleus1DPreferences,
BaseNucleus2DPreferences,
- BaseRangesTablePreferences,
+ FloatingRangesTablePreferences,
MatrixGenerationOptions,
MultipleSpectraAnalysisPreferences,
PanelsPreferences,
@@ -126,20 +126,22 @@ const getZoneDefaultValues = (nucleus?: string): PanelsPreferences['zones'] => {
}
};
-const createBaseRangesTablePreferences = (): BaseRangesTablePreferences => ({
- showSerialNumber: true,
- from: { show: false, format: '0.00' },
- to: { show: false, format: '0.00' },
- absolute: { show: false, format: '0.00' },
- relative: { show: true, format: '0.00' },
- deltaPPM: { show: true, format: '0.00' },
- deltaHz: { show: false, format: '0.00' },
- coupling: { show: true, format: '0.00' },
- showKind: true,
- showMultiplicity: true,
- showAssignment: true,
- showAssignmentLabel: true,
-});
+const createBaseRangesTablePreferences =
+ (): FloatingRangesTablePreferences => ({
+ showSerialNumber: true,
+ from: { show: false, format: '0.00' },
+ to: { show: false, format: '0.00' },
+ absolute: { show: false, format: '0.00' },
+ relative: { show: true, format: '0.00' },
+ deltaPPM: { show: true, format: '0.00' },
+ deltaHz: { show: false, format: '0.00' },
+ coupling: { show: true, format: '0.00' },
+ showKind: true,
+ showMultiplicity: true,
+ showAssignment: true,
+ showAssignmentLabel: true,
+ signalKinds: ['signal'],
+ });
const getRangeDefaultValues = (
nucleus?: string,
diff --git a/src/data/constants/signalsKinds.ts b/src/data/constants/signalsKinds.ts
index 9d17a6260..f509964b4 100644
--- a/src/data/constants/signalsKinds.ts
+++ b/src/data/constants/signalsKinds.ts
@@ -1,7 +1,7 @@
import type { SignalKind } from '@zakodium/nmr-types';
import { signalKindLabelMapping } from 'nmr-processing';
-interface SignalKindItem {
+export interface SignalKindItem {
value: SignalKind;
label: string;
}
diff --git a/src/demo/views/SnapshotView.tsx b/src/demo/views/SnapshotView.tsx
index 3a2619583..d86997233 100644
--- a/src/demo/views/SnapshotView.tsx
+++ b/src/demo/views/SnapshotView.tsx
@@ -368,6 +368,7 @@ const customWorkspaces: CustomWorkspaces = {
showZoomAction: false,
},
floatingTablePreferences: {
+ signalKinds: ['signal'],
showAssignment: false,
showAssignmentLabel: false,
showSerialNumber: false,
@@ -446,6 +447,7 @@ const customWorkspaces: CustomWorkspaces = {
showZoomAction: false,
},
floatingTablePreferences: {
+ signalKinds: ['signal'],
showAssignment: false,
showAssignmentLabel: false,
showSerialNumber: false,
From 21086758a4b2bc34e21b6757c2e016b66dd888c8 Mon Sep 17 00:00:00 2001
From: hamed musallam
Date: Thu, 25 Jun 2026 13:37:15 +0200
Subject: [PATCH 8/8] chore: update nmrium core packages
---
package-lock.json | 38 +++++++++++++++++++-------------------
package.json | 6 +++---
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 4ca238d67..c8beabc0d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,9 +17,9 @@
"@tanstack/react-form": "^1.33.0",
"@tanstack/react-store": "^0.11.0",
"@tanstack/react-table": "^8.21.3",
- "@zakodium/nmr-types": "^0.5.12",
- "@zakodium/nmrium-core": "^0.7.24",
- "@zakodium/nmrium-core-plugins": "^0.7.32",
+ "@zakodium/nmr-types": "^0.5.14",
+ "@zakodium/nmrium-core": "^0.7.31",
+ "@zakodium/nmrium-core-plugins": "^0.7.40",
"@zakodium/pdnd-esm": "^1.0.2",
"@zip.js/zip.js": "^2.8.26",
"cheminfo-font": "^1.27.0",
@@ -108,7 +108,7 @@
"stylelint": "^17.13.0",
"stylelint-config-standard": "^40.0.0",
"typescript": "~6.0.3",
- "vite": "^8.0.16",
+ "vite": "=8.0.16",
"vitest": "^4.1.9"
},
"peerDependencies": {
@@ -4016,9 +4016,9 @@
}
},
"node_modules/@zakodium/nmrium-core": {
- "version": "0.7.30",
- "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core/-/nmrium-core-0.7.30.tgz",
- "integrity": "sha512-uds3UysKrAgm38Yt2swNnt8nmf5SHqt1LuVnewwDTolztl3Lead0RtgOYsRjnL30k6gpvGrgaoENkIMxSY0/kQ==",
+ "version": "0.7.31",
+ "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core/-/nmrium-core-0.7.31.tgz",
+ "integrity": "sha512-DVhxwBTY5ftXGJ+HahdDwRJFXfRHipVijf8QLOduIYnru+f+c+axYalCFjmE0rvKTgo7vPekBVpRdcvg8u4lrQ==",
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"cheminfo-types": "^1.15.0",
@@ -4034,24 +4034,24 @@
}
},
"node_modules/@zakodium/nmrium-core-plugins": {
- "version": "0.7.39",
- "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core-plugins/-/nmrium-core-plugins-0.7.39.tgz",
- "integrity": "sha512-WFO8UmUB4ZGwO+eCTjC1RfUBeCtv+raQmsuVx6L7zf1/BuD0N3Lq0q+JpKkdn85sfFGckyejJr1yo2qd91EVMQ==",
+ "version": "0.7.40",
+ "resolved": "https://registry.npmjs.org/@zakodium/nmrium-core-plugins/-/nmrium-core-plugins-0.7.40.tgz",
+ "integrity": "sha512-ZepZd+0TPgwTpGbJPH99VSBFlNrhqDjtr4dcvYo5Gy+VDz0gf0DeSmjOCnHeFwkuPnTTG/YHWG8/6BSQHScyzw==",
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@date-fns/utc": "^2.1.1",
- "@zakodium/nmrium-core": "^0.7.30",
+ "@zakodium/nmrium-core": "^0.7.31",
"cheminfo-types": "^1.15.0",
"convert-to-jcamp": "^7.0.0",
"date-fns": "^4.1.0",
"file-collection": "^6.6.1",
"gyromagnetic-ratio": "^2.0.0",
"is-any-array": "^3.0.0",
- "jcampconverter": "^12.3.3",
+ "jcampconverter": "^12.4.0",
"linear-sum-assignment": "^1.0.9",
"lodash.merge": "^4.6.2",
"ml-spectra-processing": "^14.28.1",
- "nmr-processing": "^22.13.0",
+ "nmr-processing": "^22.14.0",
"openchemlib": "^9.22.0",
"openchemlib-utils": "^8.15.0",
"sdf-parser": "^8.0.0",
@@ -8482,9 +8482,9 @@
}
},
"node_modules/jcampconverter": {
- "version": "12.3.3",
- "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-12.3.3.tgz",
- "integrity": "sha512-Ayu6hbf5AM1eahyMp0EmnuDQnG2KRKYODq1SE6ITwcv3no2YCvbeQOvoRqdxwhV3t11PtESr57jvWvfttagvdw==",
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/jcampconverter/-/jcampconverter-12.4.0.tgz",
+ "integrity": "sha512-7sIYUsBW2ZWST702MbvUqoh5lkB2ud/5sexzshvSzpBIgHEw/rO4TIzMQit2WloJbl0jVFh9xH4D8o2kALAMtw==",
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"cheminfo-types": "^1.15.0",
@@ -9739,9 +9739,9 @@
}
},
"node_modules/nmr-processing": {
- "version": "22.13.0",
- "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-22.13.0.tgz",
- "integrity": "sha512-udS0fxLjJgojI382/6LZvBGLs+z+edoiULrqNjHYCQdFCgsEp6JYBNnHABY29myvXGN9ml17Clhc/qLaUJDe3w==",
+ "version": "22.14.0",
+ "resolved": "https://registry.npmjs.org/nmr-processing/-/nmr-processing-22.14.0.tgz",
+ "integrity": "sha512-MD5Y8aDqY5NRCAWf6cvnqpgVlVlIkbM1DZ5Zf+pyw411UolQ970mtRWxHTr0RUB8wsB57f+UXniZVKqtwANbiA==",
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"binary-search": "^1.3.6",
diff --git a/package.json b/package.json
index 0c92d8a4f..740bfea21 100644
--- a/package.json
+++ b/package.json
@@ -71,9 +71,9 @@
"@tanstack/react-form": "^1.33.0",
"@tanstack/react-store": "^0.11.0",
"@tanstack/react-table": "^8.21.3",
- "@zakodium/nmr-types": "^0.5.12",
- "@zakodium/nmrium-core": "^0.7.24",
- "@zakodium/nmrium-core-plugins": "^0.7.32",
+ "@zakodium/nmr-types": "^0.5.14",
+ "@zakodium/nmrium-core": "^0.7.31",
+ "@zakodium/nmrium-core-plugins": "^0.7.40",
"@zakodium/pdnd-esm": "^1.0.2",
"@zip.js/zip.js": "^2.8.26",
"cheminfo-font": "^1.27.0",