Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Right click menu #630

Merged
merged 4 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/assets/icons/Cut.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon";
import { mdiContentCut } from "@mdi/js";

export default function Cut(props: SvgIconProps) {
return (
<SvgIcon {...props}>
<path d={mdiContentCut} />
</SvgIcon>
);
}
10 changes: 10 additions & 0 deletions src/assets/icons/Paste.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import SvgIcon, { SvgIconProps } from "@mui/material/SvgIcon";
import { mdiContentPaste } from "@mdi/js";

export default function Paste(props: SvgIconProps) {
return (
<SvgIcon {...props}>
<path d={mdiContentPaste} />
</SvgIcon>
);
}
1 change: 1 addition & 0 deletions src/components/Table/ColumnMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type SelectedColumnHeader = {
column: Column<any> & { [key: string]: any };
anchorEl: PopoverProps["anchorEl"];
};

export type ColumnMenuRef = {
selectedColumnHeader: SelectedColumnHeader | null;
setSelectedColumnHeader: React.Dispatch<
Expand Down
42 changes: 42 additions & 0 deletions src/components/Table/ContextMenu/MenuContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Menu } from "@mui/material";
import MenuRow, { IMenuRow } from "./MenuRow";

interface IMenuContents {
anchorEl: HTMLElement;
open: boolean;
handleClose: () => void;
items: IMenuRow[];
}

export function MenuContents({
anchorEl,
open,
handleClose,
items,
}: IMenuContents) {
const handleContext = (e: React.MouseEvent) => e.preventDefault();
return (
<Menu
id="cell-context-menu"
aria-labelledby="cell-context-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
sx={{ "& .MuiMenu-paper": { backgroundColor: "background.default" } }}
MenuListProps={{ disablePadding: true }}
onContextMenu={handleContext}
>
{items.map((item, indx: number) => (
<MenuRow key={indx} {...item} />
))}
</Menu>
);
}
17 changes: 17 additions & 0 deletions src/components/Table/ContextMenu/MenuRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ListItemIcon, ListItemText, MenuItem } from "@mui/material";

export interface IMenuRow {
onClick: () => void;
icon: JSX.Element;
label: string;
disabled?: boolean;
}

export default function MenuRow({ onClick, icon, label, disabled }: IMenuRow) {
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
return (
<MenuItem disabled={disabled} onClick={onClick}>
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
<ListItemIcon>{icon} </ListItemIcon>
<ListItemText> {label} </ListItemText>
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
</MenuItem>
);
}
56 changes: 56 additions & 0 deletions src/components/Table/ContextMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from "react";
import _find from "lodash/find";
import { PopoverProps } from "@mui/material";

import { getFieldProp } from "@src/components/fields";
import { useProjectContext } from "@src/contexts/ProjectContext";

import { MenuContents } from "./MenuContent";

export type SelectedCell = {
rowIndex: number;
colIndex: number;
};

export type ContextMenuRef = {
selectedCell: SelectedCell;
setSelectedCell: React.Dispatch<React.SetStateAction<SelectedCell | null>>;
anchorEl: HTMLElement | null;
setAnchorEl: React.Dispatch<
React.SetStateAction<PopoverProps["anchorEl"] | null>
>;
};
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved

export default function ContextMenu() {
const { contextMenuRef, tableState }: any = useProjectContext();
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
const [anchorEl, setAnchorEl] = React.useState<any | null>(null);
const [selectedCell, setSelectedCell] = React.useState<any | null>();
const open = Boolean(anchorEl);
const handleClose = () => setAnchorEl(null);

if (contextMenuRef)
contextMenuRef.current = {
anchorEl,
setAnchorEl,
selectedCell,
setSelectedCell,
} as {};

const selectedColIndex = selectedCell?.colIndex;
const selectedCol = _find(tableState?.columns, { index: selectedColIndex });
const getActions =
getFieldProp("contextMenuActions", selectedCol?.type) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add support for derivatives

function empty() {};
const actions = getActions() || [];
const hasNoActions = Boolean(actions.length === 0);

if (!contextMenuRef.current || !open || hasNoActions) return <></>;
return (
<MenuContents
anchorEl={anchorEl}
open={open}
handleClose={handleClose}
items={actions}
/>
);
}
23 changes: 21 additions & 2 deletions src/components/Table/TableRow.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useProjectContext } from "@src/contexts/ProjectContext";
import { Fragment } from "react";
import { Row, RowRendererProps } from "react-data-grid";

Expand All @@ -8,9 +9,27 @@ export default function TableRow(props: RowRendererProps<any>) {
return (
<Fragment key={props.row.id}>
<OutOfOrderIndicator top={props.top} height={props.height} />
<Row {...props} />
<ContextMenu>
<Row {...props} />
</ContextMenu>
</Fragment>
);

return <Row {...props} />;
return (
<ContextMenu>
<Row {...props} />
</ContextMenu>
);
}

const ContextMenu = (props: any) => {
const { contextMenuRef }: any = useProjectContext();
function handleClick(e: any) {
e.preventDefault();
const input = e?.target as HTMLElement;
if (contextMenuRef?.current) {
contextMenuRef?.current?.setAnchorEl(input);
}
}
return <span onContextMenu={(e) => handleClick(e)}>{props.children}</span>;
};
Comment on lines +12 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think ContextMenu needs to be a separate component. I just set the onContextMenu prop on Row and the e.target is the cell div, which is the same in both methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, my dude! The less code the better. I will update the changes

10 changes: 10 additions & 0 deletions src/components/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import TableContainer, { OUT_OF_ORDER_MARGIN } from "./TableContainer";
import TableHeader from "../TableHeader";
import ColumnHeader from "./ColumnHeader";
import ColumnMenu from "./ColumnMenu";
import ContextMenu from "./ContextMenu";
import FinalColumnHeader from "./FinalColumnHeader";
import FinalColumn from "./formatters/FinalColumn";
import TableRow from "./TableRow";
Expand Down Expand Up @@ -48,6 +49,7 @@ export default function Table() {
tableState,
tableActions,
dataGridRef,
contextMenuRef,
sideDrawerRef,
updateCell,
} = useProjectContext();
Expand Down Expand Up @@ -262,6 +264,13 @@ export default function Table() {
});
}
}}
onSelectedCellChange={({ rowIdx, idx }) => {
console.log("firing");
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
gibsonliketheguitar marked this conversation as resolved.
Show resolved Hide resolved
contextMenuRef?.current?.setSelectedCell({
rowIndex: rowIdx,
colIndex: idx,
});
}}
/>
</DndProvider>
) : (
Expand All @@ -270,6 +279,7 @@ export default function Table() {
</TableContainer>

<ColumnMenu />
<ContextMenu />
<BulkActions
selectedRows={selectedRows}
columns={columns}
Expand Down
3 changes: 3 additions & 0 deletions src/components/fields/Email/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import EmailIcon from "@mui/icons-material/MailOutlined";
import BasicCell from "../_BasicCell/BasicCellValue";
import TextEditor from "@src/components/Table/editors/TextEditor";
import { filterOperators } from "../ShortText/Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";

const SideDrawerField = lazy(
() =>
import("./SideDrawerField" /* webpackChunkName: "SideDrawerField-Email" */)
Expand All @@ -20,6 +22,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <EmailIcon />,
description: "Email address. Not validated.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(BasicCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/LongText/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import LongTextIcon from "@mui/icons-material/Notes";
import BasicCell from "./BasicCell";
import TextEditor from "@src/components/Table/editors/TextEditor";
import { filterOperators } from "../ShortText/Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";

const SideDrawerField = lazy(
() =>
Expand All @@ -23,6 +24,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <LongTextIcon />,
description: "Text displayed on multiple lines.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(BasicCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/Number/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import NumberIcon from "@src/assets/icons/Number";
import BasicCell from "./BasicCell";
import TextEditor from "@src/components/Table/editors/TextEditor";
import { filterOperators } from "./Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";
const SideDrawerField = lazy(
() =>
import("./SideDrawerField" /* webpackChunkName: "SideDrawerField-Number" */)
Expand All @@ -20,6 +21,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <NumberIcon />,
description: "Numeric value.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(BasicCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/Phone/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import PhoneIcon from "@mui/icons-material/PhoneOutlined";
import BasicCell from "../_BasicCell/BasicCellValue";
import TextEditor from "@src/components/Table/editors/TextEditor";
import { filterOperators } from "../ShortText/Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";

const SideDrawerField = lazy(
() =>
Expand All @@ -21,6 +22,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <PhoneIcon />,
description: "Phone number stored as text. Not validated.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(BasicCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/RichText/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import withHeavyCell from "../_withTableCell/withHeavyCell";
import RichTextIcon from "@mui/icons-material/TextFormat";
import BasicCell from "../_BasicCell/BasicCellNull";
import withSideDrawerEditor from "@src/components/Table/editors/withSideDrawerEditor";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";

const TableCell = lazy(
() => import("./TableCell" /* webpackChunkName: "TableCell-RichText" */)
Expand All @@ -25,6 +26,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <RichTextIcon />,
description: "HTML edited with a rich text editor.",
contextMenuActions: BasicContextMenuActions,
TableCell: withHeavyCell(BasicCell, TableCell),
TableEditor: withSideDrawerEditor(TableCell),
SideDrawerField,
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/ShortText/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import BasicCell from "../_BasicCell/BasicCellValue";
import TextEditor from "@src/components/Table/editors/TextEditor";

import { filterOperators } from "./Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";
const SideDrawerField = lazy(
() =>
import(
Expand All @@ -26,6 +27,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <ShortTextIcon />,
description: "Text displayed on a single line.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(BasicCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
1 change: 0 additions & 1 deletion src/components/fields/Status/ConditionModalContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export default function ConditionModalContent({
{type === "number" && (
<Grid container direction="row" justifyContent="space-between">
<div style={{ width: "45%" }}>
{console.log(operatorOptions)}
<MultiSelect
options={operatorOptions}
onChange={(v) => handleUpdate("operator")(v)}
Expand Down
2 changes: 2 additions & 0 deletions src/components/fields/Url/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import UrlIcon from "@mui/icons-material/Link";
import TableCell from "./TableCell";
import TextEditor from "@src/components/Table/editors/TextEditor";
import { filterOperators } from "../ShortText/Filter";
import BasicContextMenuActions from "../_BasicCell/BasicCellContextMenuActions";

const SideDrawerField = lazy(
() =>
Expand All @@ -21,6 +22,7 @@ export const config: IFieldConfig = {
initializable: true,
icon: <UrlIcon />,
description: "Web address. Not validated.",
contextMenuActions: BasicContextMenuActions,
TableCell: withBasicCell(TableCell),
TableEditor: TextEditor,
SideDrawerField,
Expand Down
Loading