Migrate react-contextmenu to react-contexify

This commit is contained in:
Marks Polakovs 2020-11-09 14:30:50 +00:00
parent 1e5aae0b51
commit feccb3155e
6 changed files with 82 additions and 48 deletions

View file

@ -76,7 +76,7 @@
"react-app-polyfill": "^1.0.4", "react-app-polyfill": "^1.0.4",
"react-beautiful-dnd": "^12.1.1", "react-beautiful-dnd": "^12.1.1",
"react-beforeunload": "^2.1.0", "react-beforeunload": "^2.1.0",
"react-contextmenu": "^2.13.0", "react-contexify": "^4.1.1",
"react-dev-utils": "^9.1.0", "react-dev-utils": "^9.1.0",
"react-dnd": "^9.4.0", "react-dnd": "^9.4.0",
"react-dnd-html5-backend": "^9.4.0", "react-dnd-html5-backend": "^9.4.0",

View file

@ -77,7 +77,7 @@ interface Album {
// TODO // TODO
} }
interface TimeslotItemBase { export interface TimeslotItemBase {
timeslotitemid: string; timeslotitemid: string;
channel: number; channel: number;
weight: number; weight: number;
@ -88,7 +88,7 @@ interface TimeslotItemBase {
cue: number; cue: number;
} }
interface TimeslotItemCentral { export interface TimeslotItemCentral {
type: "central"; type: "central";
artist: string; artist: string;
intro: number; intro: number;

View file

@ -1,15 +1,16 @@
import React, { memo } from "react"; import React, { memo } from "react";
import { PlanItem, itemId } from "./state"; import { PlanItem, itemId, isTrack, isAux } from "./state";
import { Track, AuxItem } from "../api"; import { Track, AuxItem } from "../api";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { RootState } from "../rootReducer"; import { RootState } from "../rootReducer";
import * as MixerState from "../mixer/state"; import * as MixerState from "../mixer/state";
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import { ContextMenuTrigger } from "react-contextmenu"; import { contextMenu } from "react-contexify";
import "./item.scss"; import "./item.scss";
export const TS_ITEM_MENU_ID = "SongMenu"; export const TS_ITEM_MENU_ID = "SongMenu";
export const TS_ITEM_AUX_ID = "AuxMenu";
export const Item = memo(function Item({ export const Item = memo(function Item({
item: x, item: x,
@ -22,7 +23,6 @@ export const Item = memo(function Item({
}) { }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const id = itemId(x); const id = itemId(x);
const isReal = "timeslotitemid" in x;
const isGhost = "ghostid" in x; const isGhost = "ghostid" in x;
const playerState = useSelector((state: RootState) => const playerState = useSelector((state: RootState) =>
@ -44,6 +44,30 @@ export const Item = memo(function Item({
} }
} }
function openContextMenu(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
e.preventDefault();
if (isTrack(x)) {
contextMenu.show({
id: TS_ITEM_MENU_ID,
event: e,
props: {
id,
title: x.title,
artist: x.artist,
},
});
} else if (isAux(x)) {
contextMenu.show({
id: TS_ITEM_MENU_ID,
event: e,
props: {
id,
title: x.title,
},
});
}
}
return ( return (
<Draggable <Draggable
draggableId={id} draggableId={id}
@ -69,31 +93,27 @@ export const Item = memo(function Item({
}` }`
} }
onClick={triggerClick} onClick={triggerClick}
onContextMenu={openContextMenu}
{...provided.draggableProps} {...provided.draggableProps}
{...provided.dragHandleProps} {...provided.dragHandleProps}
> >
<ContextMenuTrigger <span className={"icon " + x.type} />
id={isReal ? TS_ITEM_MENU_ID : ""} &nbsp;
collect={() => ({ id })} {x.title.toString()}
{"artist" in x && x.artist !== "" && " - " + x.artist}
<small
className={
"border rounded border-danger text-danger p-1 m-1" +
("clean" in x && x.clean === false ? "" : " d-none")
}
> >
<span className={"icon " + x.type} /> Explicit
&nbsp; </small>
{x.title.toString()} {showDebug && (
{"artist" in x && x.artist !== "" && " - " + x.artist} <code>
<small {itemId(x)} {"channel" in x && x.channel + "/" + x.weight}
className={ </code>
"border rounded border-danger text-danger p-1 m-1" + )}
("clean" in x && x.clean === false ? "" : " d-none")
}
>
Explicit
</small>
{showDebug && (
<code>
{itemId(x)} {"channel" in x && x.channel + "/" + x.weight}
</code>
)}
</ContextMenuTrigger>
</div> </div>
)} )}
</Draggable> </Draggable>

View file

@ -1,5 +1,6 @@
import React, { useState, useReducer, useEffect } from "react"; import React, { useState, useReducer, useEffect } from "react";
import { ContextMenu, MenuItem } from "react-contextmenu"; import { Menu, Item as CtxMenuItem } from "react-contexify";
import "react-contexify/dist/ReactContexify.min.css";
import { useBeforeunload } from "react-beforeunload"; import { useBeforeunload } from "react-beforeunload";
import { import {
FaBookOpen, FaBookOpen,
@ -379,13 +380,6 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
} }
} }
async function onCtxRemoveClick(e: any, data: { id: string }) {
dispatch(removeItem(timeslotId, data.id));
}
async function onCtxUnPlayedClick(e: any, data: { id: string }) {
dispatch(setItemPlayed({ itemId: data.id, played: false }));
}
// Add support for reloading the show plan from the iFrames. // Add support for reloading the show plan from the iFrames.
// There is a similar listener in showplanner/ImporterModal.tsx to handle closing the iframe. // There is a similar listener in showplanner/ImporterModal.tsx to handle closing the iframe.
useEffect(() => { useEffect(() => {
@ -440,14 +434,24 @@ const Showplanner: React.FC<{ timeslotId: number }> = function({ timeslotId }) {
</div> </div>
</DragDropContext> </DragDropContext>
</div> </div>
<ContextMenu id={TS_ITEM_MENU_ID}> <Menu id={TS_ITEM_MENU_ID}>
<MenuItem onClick={onCtxRemoveClick}> <CtxMenuItem
onClick={(args) =>
dispatch(removeItem(timeslotId, (args.props as any).id))
}
>
<FaTrash /> Remove <FaTrash /> Remove
</MenuItem> </CtxMenuItem>
<MenuItem onClick={onCtxUnPlayedClick}> <CtxMenuItem
onClick={(args) =>
dispatch(
setItemPlayed({ itemId: (args.props as any).id, played: false })
)
}
>
<FaCircleNotch /> Mark Unplayed <FaCircleNotch /> Mark Unplayed
</MenuItem> </CtxMenuItem>
</ContextMenu> </Menu>
<OptionsMenu /> <OptionsMenu />
<WelcomeModal <WelcomeModal
isOpen={showWelcomeModal} isOpen={showWelcomeModal}

View file

@ -47,6 +47,16 @@ export function itemId(
throw new Error("Can't get id of unknown item."); throw new Error("Can't get id of unknown item.");
} }
export function isTrack(
item: PlanItem | Track | AuxItem
): item is (api.TimeslotItemBase & api.TimeslotItemCentral) | Track {
return "trackid" in item;
}
export function isAux(item: PlanItem | Track | AuxItem): item is AuxItem {
return "auxid" in item;
}
interface ShowplanState { interface ShowplanState {
planLoading: boolean; planLoading: boolean;
planLoadError: string | null; planLoadError: string | null;

View file

@ -3299,7 +3299,7 @@ class-utils@^0.3.5:
isobject "^3.0.0" isobject "^3.0.0"
static-extend "^0.1.1" static-extend "^0.1.1"
classnames@^2.2.3, classnames@^2.2.5: classnames@^2.2.3, classnames@^2.2.6:
version "2.2.6" version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
@ -10100,13 +10100,13 @@ react-beforeunload@^2.1.0:
dependencies: dependencies:
prop-types "^15.7.2" prop-types "^15.7.2"
react-contextmenu@^2.13.0: react-contexify@^4.1.1:
version "2.13.0" version "4.1.1"
resolved "https://registry.yarnpkg.com/react-contextmenu/-/react-contextmenu-2.13.0.tgz#dabaea63124e30c85f1b4245c095b7045d013459" resolved "https://registry.yarnpkg.com/react-contexify/-/react-contexify-4.1.1.tgz#f5eba1ad82a923c033c91d0abcea1da0a71ebaa1"
integrity sha512-hhFuJX4di0zGV7H7pXPn42U70OZbGpQD+PxcdmKStNT5mebSjI+inhOuFESDmDbqVsN/f99hI5/nw95oXTVRXQ== integrity sha512-WJeRI4ohHEOmNiH0xb62a/eV+5ae168FB7H6pfbeEVJkf0UN7D5H99l6b89poc2LHKN1gOimFjREyY8quGVsXA==
dependencies: dependencies:
classnames "^2.2.5" classnames "^2.2.6"
object-assign "^4.1.0" prop-types "^15.6.2"
react-dev-utils@^10.2.1: react-dev-utils@^10.2.1:
version "10.2.1" version "10.2.1"