Skip to content

Commit

Permalink
refactor: context menu
Browse files Browse the repository at this point in the history
  • Loading branch information
hamed-musallam committed Dec 7, 2023
1 parent 89c2806 commit 9dcbcf5
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 321 deletions.
613 changes: 349 additions & 264 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
},
"dependencies": {
"@blueprintjs/core": "^5.7.1",
"@blueprintjs/icons": "^5.4.1",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@lukeed/uuid": "^2.0.1",
Expand Down Expand Up @@ -103,7 +104,7 @@
"react-ocl-nmr": "^3.0.1",
"react-plot": "^1.4.2",
"react-rnd": "^10.4.1",
"react-science": "^0.27.0",
"react-science": "^0.29.0",
"react-slider": "^2.0.6",
"react-table": "^7.8.0",
"react-transition-group": "^4.4.5",
Expand Down
63 changes: 63 additions & 0 deletions src/component/elements/ContextMenuBluePrint.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
ContextMenuProps as BluePrintContextMenuProps,
Menu,
MenuItem,
MenuItemProps,
showContextMenu,
} from '@blueprintjs/core';
import React, { ComponentProps, ElementType, ReactNode } from 'react';

export interface ContextMenuItem extends MenuItemProps {
data?: object;
}

type ElementProps<E = 'div'> = E extends ElementType
? ComponentProps<E>
: never;

export interface BaseContextMenuProps {
options: ContextMenuItem[];
onSelect: (data?: object) => void;
}

export interface ContextMenuProps<E>
extends BaseContextMenuProps,
Omit<BluePrintContextMenuProps, 'onSelect' | 'content' | 'children'> {
as?: E;
children: ReactNode;
}

export function ContextMenu<E extends ElementType = 'div'>(
props: ContextMenuProps<E> & ElementProps<E>,
) {
const { options, onSelect, children, as: Wrapper = 'div', ...other } = props;

function handleContextMenu(event: React.MouseEvent<HTMLElement>) {
const content = (
<Menu>
{options.map((option) => (
<MenuItem
key={JSON.stringify(option)}
{...option}
onClick={() => onSelect(option?.data)}
/>
))}
</Menu>
);

event.preventDefault();
showContextMenu({
content,
targetOffset: {
left: event.clientX,
top: event.clientY,
},
});
}

return (
<Wrapper {...other} onContextMenu={handleContextMenu}>
{children}
</Wrapper>
);
}
12 changes: 6 additions & 6 deletions src/component/elements/ReactTable/Elements/ReactTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import { css, CSSObject } from '@emotion/react';
import { useMemo, useEffect, useCallback } from 'react';
import { DropdownMenu } from 'react-science/ui';

import { HighlightEventSource, useHighlight } from '../../../highlight/index';
import { BaseRowStyle, ContextMenuProps } from '../ReactTable';
import { ContextMenu } from '../../ContextMenuBluePrint';
import { BaseRowStyle, TableContextMenuProps } from '../ReactTable';

function getRowStyle(
isActive: boolean,
Expand Down Expand Up @@ -36,7 +36,7 @@ function getRowStyle(
export interface ClickEvent {
onClick?: (event: Event, data: unknown) => void;
}
interface ReactTableRowProps extends ClickEvent, ContextMenuProps {
interface ReactTableRowProps extends ClickEvent, TableContextMenuProps {
row: any;
highlightedSource?: HighlightEventSource;
isRowActive: boolean;
Expand Down Expand Up @@ -89,11 +89,11 @@ function ReactTableRow(props: ReactTableRowProps) {
[onClick, row],
);
return (
<DropdownMenu
trigger="contextMenu"
<ContextMenu
options={contextMenu}
onSelect={(selected) => onContextMenuSelect?.(selected, row.original)}
as="tr"
style={{ position: 'static' }}
key={row.getRowProps().key}
css={getRowStyle(
highlight.isActive || isRowActive,
Expand Down Expand Up @@ -127,7 +127,7 @@ function ReactTableRow(props: ReactTableRowProps) {
);
}
})}
</DropdownMenu>
</ContextMenu>
);
}

Expand Down
10 changes: 5 additions & 5 deletions src/component/elements/ReactTable/ReactTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
useEffect,
useMemo,
} from 'react';
import { DropdownMenuProps } from 'react-science/ui';
import {
useTable,
useSortBy,
Expand All @@ -28,6 +27,7 @@ import {
import { useMeasure } from 'react-use';

import { HighlightEventSource } from '../../highlight';
import { BaseContextMenuProps } from '../ContextMenuBluePrint';

import { EmptyDataRow } from './Elements/EmptyDataRow';
import ReactTableHeader from './Elements/ReactTableHeader';
Expand Down Expand Up @@ -69,14 +69,14 @@ export interface BaseRowStyle {
base?: CSSProperties;
}

export interface ContextMenuProps {
export interface TableContextMenuProps {
onContextMenuSelect?: (
selected: Parameters<DropdownMenuProps<any, any>['onSelect']>[0],
selected: Parameters<BaseContextMenuProps['onSelect']>[0],
data: any,
) => void;
contextMenu?: DropdownMenuProps<any, any>['options'];
contextMenu?: BaseContextMenuProps['options'];
}
interface ReactTableProps extends ContextMenuProps, ClickEvent, SortEvent {
interface ReactTableProps extends TableContextMenuProps, ClickEvent, SortEvent {
data: any;
columns: any;
highlightedSource?: HighlightEventSource;
Expand Down
7 changes: 3 additions & 4 deletions src/component/panels/RangesPanel/RangesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ import { Spectrum1D, WorkSpacePanelPreferences } from 'nmr-load-save';
import { Info1D, Ranges } from 'nmr-processing';
import { useCallback, useMemo, memo, useState, useRef } from 'react';
import { FaCopy } from 'react-icons/fa';
import { DropdownMenuProps } from 'react-science/ui';

import { StateMoleculeExtended } from '../../../data/molecules/Molecule';
import { ClipboardFallbackModal } from '../../../utils/clipboard/clipboardComponents';
import { useClipboard } from '../../../utils/clipboard/clipboardHooks';
import { useAssignmentData } from '../../assignment/AssignmentsContext';
import { useChartData } from '../../context/ChartContext';
import { useDispatch } from '../../context/DispatchContext';
import { BaseContextMenuProps } from '../../elements/ContextMenuBluePrint';
import { useAlert } from '../../elements/popup/Alert';
import { usePanelPreferences } from '../../hooks/usePanelPreferences';
import useSpectrum from '../../hooks/useSpectrum';
Expand All @@ -24,10 +24,9 @@ import RangesHeader from './RangesHeader';
import RangesPreferences from './RangesPreferences';
import RangesTable from './RangesTable';

const rangesContextMenuOptions: DropdownMenuProps<any, any>['options'] = [
const rangesContextMenuOptions: BaseContextMenuProps['options'] = [
{
label: 'Copy to Clipboard',
type: 'option',
text: 'Copy to Clipboard',
icon: <FaCopy />,
},
];
Expand Down
4 changes: 2 additions & 2 deletions src/component/panels/RangesPanel/RangesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { WorkSpacePanelPreferences } from 'nmr-load-save';
import { Info1D } from 'nmr-processing';
import { FaLink } from 'react-icons/fa';

import { ContextMenuProps } from '../../elements/ReactTable/ReactTable';
import { TableContextMenuProps } from '../../elements/ReactTable/ReactTable';
import useTableSortBy from '../../hooks/useTableSortBy';
import NoDataForFid from '../extra/placeholder/NoDataForFid';
import NoTableData from '../extra/placeholder/NoTableData';
Expand Down Expand Up @@ -56,7 +56,7 @@ const tableStyle = css`
}
}
`;
interface RangesTableProps extends ContextMenuProps {
interface RangesTableProps extends TableContextMenuProps {
onUnlink: (a: any, b?: any) => void;
preferences: WorkSpacePanelPreferences['ranges'];
tableData: any;
Expand Down
11 changes: 5 additions & 6 deletions src/component/panels/RangesPanel/RangesTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import lodashGet from 'lodash/get';
import { WorkSpacePanelPreferences } from 'nmr-load-save';
import { Info1D } from 'nmr-processing';
import { useMemo, useCallback, MouseEvent, CSSProperties } from 'react';
import { DropdownMenu } from 'react-science/ui';

import {
AssignmentsData,
useAssignment,
useAssignmentData,
} from '../../assignment/AssignmentsContext';
import { filterForIDsWithAssignment } from '../../assignment/utilities/filterForIDsWithAssignment';
import { ContextMenuProps } from '../../elements/ReactTable/ReactTable';
import { ContextMenu } from '../../elements/ContextMenuBluePrint';
import { TableContextMenuProps } from '../../elements/ReactTable/ReactTable';
import {
HighlightEventSource,
useHighlight,
Expand All @@ -38,7 +38,7 @@ const ConstantlyHighlightedRowStyle = css`
background-color: #f5f5dc;
`;

interface RangesTableRowProps extends ContextMenuProps {
interface RangesTableRowProps extends TableContextMenuProps {
rowData: any;
onUnlink: (a: any, b?: any) => void;
preferences: WorkSpacePanelPreferences['ranges'];
Expand Down Expand Up @@ -189,8 +189,7 @@ function RangesTableRow({
}, [assignmentRange.isActive, highlightRange.isActive, rowData]);

return (
<DropdownMenu
trigger="contextMenu"
<ContextMenu
options={contextMenu}
onSelect={(selected) => onContextMenuSelect?.(selected, rowData)}
as="tr"
Expand Down Expand Up @@ -302,7 +301,7 @@ function RangesTableRow({
showEditAction={preferences.showEditAction}
showZoomAction={preferences.showZoomAction}
/>
</DropdownMenu>
</ContextMenu>
);
}

Expand Down
48 changes: 21 additions & 27 deletions src/component/panels/SpectrumsPanel/SpectraTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ import {
import { useMemo, CSSProperties, useCallback, useState } from 'react';
import { FaCopy, FaRegTrashAlt, FaFileExport } from 'react-icons/fa';
import { IoColorPaletteOutline } from 'react-icons/io5';
import { DropdownMenu, DropdownMenuProps } from 'react-science/ui';

import { ClipboardFallbackModal } from '../../../utils/clipboard/clipboardComponents';
import { useClipboard } from '../../../utils/clipboard/clipboardHooks';
import { useDispatch } from '../../context/DispatchContext';
import {
ContextMenu,
ContextMenuItem,
} from '../../elements/ContextMenuBluePrint';
import ReactTable, { Column } from '../../elements/ReactTable/ReactTable';
import { useAlert } from '../../elements/popup/Alert';
import { usePanelPreferences } from '../../hooks/usePanelPreferences';
Expand Down Expand Up @@ -58,10 +61,9 @@ interface SpectraTableProps extends OnChangeVisibilityEvent {
nucleus: string;
}

const options: DropdownMenuProps<string, any>['options'] = [
const options: ContextMenuItem[] = [
{
label: 'Recolor based on distinct value',
type: 'option',
text: 'Recolor based on distinct value',
icon: <IoColorPaletteOutline />,
},
];
Expand All @@ -72,32 +74,28 @@ enum SpectraContextMenuOptionsKeys {
ExportAsJcamp = 'ExportAsJcamp',
}

const Spectra2DContextMenuOptions: DropdownMenuProps<any, any>['options'] = [
const Spectra2DContextMenuOptions: ContextMenuItem[] = [
{
label: 'Copy to Clipboard',
type: 'option',
text: 'Copy to Clipboard',
icon: <FaCopy />,
data: { id: SpectraContextMenuOptionsKeys.CopyToClipboard },
},
{
label: 'Delete',
type: 'option',
text: 'Delete',
icon: <FaRegTrashAlt />,
data: { id: SpectraContextMenuOptionsKeys.Delete },
},
{
label: 'Export as jcamp',
type: 'option',
text: 'Export as jcamp',
icon: <FaFileExport />,
data: { id: SpectraContextMenuOptionsKeys.ExportAsJcamp },
},
];

const Spectra1DContextMenuOptions: DropdownMenuProps<any, any>['options'] = [
const Spectra1DContextMenuOptions: ContextMenuItem[] = [
...Spectra2DContextMenuOptions,
{
label: 'Export as jcamp',
type: 'option',
text: 'Export as jcamp',
icon: <FaFileExport />,
data: { id: SpectraContextMenuOptionsKeys.ExportAsJcamp },
},
Expand Down Expand Up @@ -200,7 +198,7 @@ export function SpectraTable(props: SpectraTableProps) {

const selectContextMenuHandler = useCallback(
(option, spectrum) => {
const { id } = option.data;
const { id } = option;
switch (id) {
case SpectraContextMenuOptionsKeys.CopyToClipboard: {
void (async () => {
Expand Down Expand Up @@ -349,20 +347,16 @@ const ColumnHeader = ({
}

return (
<DropdownMenu
trigger="contextMenu"
<ContextMenu
options={options}
onSelect={selectHandler}
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
<div
style={{
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{label}
</div>
</DropdownMenu>
{label}
</ContextMenu>
);
};
Loading

0 comments on commit 9dcbcf5

Please sign in to comment.