Context menu with some commands (#217)

This commit is contained in:
Timur Khazamov 2020-01-07 07:50:59 +05:00 committed by Christopher Chedeau
parent 9fe3fe5091
commit 257f697a98
6 changed files with 250 additions and 25 deletions

View file

@ -1,5 +1,6 @@
import React from "react";
import { TwitterPicker } from "react-color";
import { Popover } from "./Popover";
export function ColorPicker({
color,
@ -17,8 +18,7 @@ export function ColorPicker({
onClick={() => setActive(!isActive)}
/>
{isActive ? (
<div className="popover">
<div className="cover" onClick={() => setActive(false)} />
<Popover onCloseRequest={() => setActive(false)}>
<TwitterPicker
colors={[
"#000000",
@ -39,7 +39,7 @@ export function ColorPicker({
onChange(changedColor.hex);
}}
/>
</div>
</Popover>
) : null}
<input
type="text"

View file

@ -0,0 +1,34 @@
.context-menu {
position: relative;
border-radius: 4px;
box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.2);
padding: 0;
list-style: none;
user-select: none;
}
.context-menu__option {
width: 150px;
}
.context-menu-option {
position: relative;
width: 100%;
margin: 0;
text-align: left;
border-radius: 0;
}
.context-menu-option:focus {
z-index: 1;
}
.context-menu__option:first-child .context-menu-option {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.context-menu__option:last-child .context-menu-option {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}

View file

@ -0,0 +1,85 @@
import React from "react";
import { Popover } from "./Popover";
import { render, unmountComponentAtNode } from "react-dom";
import "./ContextMenu.css";
type ContextMenuOption = {
label: string;
action(): void;
};
type Props = {
options: ContextMenuOption[];
onCloseRequest?(): void;
top: number;
left: number;
};
function ContextMenu({ options, onCloseRequest, top, left }: Props) {
return (
<Popover onCloseRequest={onCloseRequest} top={top} left={left}>
<ul className="context-menu" onContextMenu={e => e.preventDefault()}>
{options.map((option, idx) => (
<li
key={idx}
className="context-menu__option"
onClick={onCloseRequest}
>
<ContextMenuOption {...option} />
</li>
))}
</ul>
</Popover>
);
}
function ContextMenuOption({ label, action }: ContextMenuOption) {
return (
<button className="context-menu-option" onClick={action}>
{label}
</button>
);
}
let contextMenuNode: HTMLDivElement;
function getContextMenuNode(): HTMLDivElement {
if (contextMenuNode) {
return contextMenuNode;
}
const div = document.createElement("div");
document.body.appendChild(div);
return (contextMenuNode = div);
}
type ContextMenuParams = {
options: (ContextMenuOption | false | null | undefined)[];
top: number;
left: number;
};
function handleClose() {
unmountComponentAtNode(getContextMenuNode());
}
export default {
push(params: ContextMenuParams) {
const options = Array.of<ContextMenuOption>();
params.options.forEach(option => {
if (option) {
options.push(option);
}
});
if (options.length) {
render(
<ContextMenu
top={params.top}
left={params.left}
options={options}
onCloseRequest={handleClose}
/>,
getContextMenuNode()
);
}
}
};

View file

@ -0,0 +1,24 @@
import React from "react";
type Props = {
top?: number;
left?: number;
children?: React.ReactNode;
onCloseRequest?(): void;
};
export function Popover({ children, left, onCloseRequest, top }: Props) {
return (
<div className="popover" style={{ top: top, left: left }}>
<div
className="cover"
onClick={onCloseRequest}
onContextMenu={e => {
e.preventDefault();
if (onCloseRequest) onCloseRequest();
}}
/>
{children}
</div>
);
}