mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 14:39:06 +00:00
refactor: improve context menu performance
- extract menu from rundown tree - lazy create actions
This commit is contained in:
committed by
Carlos Valente
parent
8e32314667
commit
1f8065143a
@@ -1,18 +1,24 @@
|
|||||||
import { MouseEvent } from 'react';
|
import { MouseEvent, useCallback } from 'react';
|
||||||
|
|
||||||
import { useContextMenuStore } from '../../features/rundown/rundown-context-menu/RundownContextMenu';
|
import { useContextMenuStore } from '../../features/rundown/rundown-context-menu/RundownContextMenu';
|
||||||
import { DropdownMenuOption } from '../components/dropdown-menu/DropdownMenu';
|
import { DropdownMenuOption } from '../components/dropdown-menu/DropdownMenu';
|
||||||
|
|
||||||
export const useContextMenu = <T extends HTMLElement>(options: DropdownMenuOption[]) => {
|
type ContextMenuOptions = () => DropdownMenuOption[];
|
||||||
|
|
||||||
|
export const useContextMenu = <T extends HTMLElement>(options: ContextMenuOptions) => {
|
||||||
const setContextMenu = useContextMenuStore((state) => state.setContextMenu);
|
const setContextMenu = useContextMenuStore((state) => state.setContextMenu);
|
||||||
|
|
||||||
const localCreateContextMenu = (contextMenuEvent: MouseEvent<T, globalThis.MouseEvent>) => {
|
const localCreateContextMenu = useCallback(
|
||||||
// prevent browser default context menu from showing up
|
(contextMenuEvent: MouseEvent<T, globalThis.MouseEvent>) => {
|
||||||
contextMenuEvent.preventDefault();
|
// prevent browser default context menu from showing up
|
||||||
|
contextMenuEvent.preventDefault();
|
||||||
|
|
||||||
const { pageX, pageY } = contextMenuEvent;
|
const { pageX, pageY } = contextMenuEvent;
|
||||||
return setContextMenu({ x: pageX, y: pageY }, options);
|
const menuOptions = options();
|
||||||
};
|
return setContextMenu({ x: pageX, y: pageY }, menuOptions);
|
||||||
|
},
|
||||||
|
[options, setContextMenu],
|
||||||
|
);
|
||||||
|
|
||||||
return [localCreateContextMenu];
|
return [localCreateContextMenu];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,9 +44,8 @@ function RundownExport() {
|
|||||||
<ViewNavigationMenu suppressSettings />
|
<ViewNavigationMenu suppressSettings />
|
||||||
<div className={style.rundown}>
|
<div className={style.rundown}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<RundownContextMenu>
|
<RundownWrapper isSmallDevice viewMode={viewMode} setViewMode={setViewMode} />
|
||||||
<RundownWrapper isSmallDevice viewMode={viewMode} setViewMode={setViewMode} />
|
<RundownContextMenu />
|
||||||
</RundownContextMenu>
|
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -65,9 +64,8 @@ function RundownExport() {
|
|||||||
<Editor.Panel className={style.list}>
|
<Editor.Panel className={style.list}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
{!isExtracted && <Editor.CornerExtract onClick={(event) => handleLinks('rundown', event)} />}
|
{!isExtracted && <Editor.CornerExtract onClick={(event) => handleLinks('rundown', event)} />}
|
||||||
<RundownContextMenu>
|
<RundownWrapper viewMode={viewMode} setViewMode={setViewMode} />
|
||||||
<RundownWrapper viewMode={viewMode} setViewMode={setViewMode} />
|
<RundownContextMenu />
|
||||||
</RundownContextMenu>
|
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Editor.Panel>
|
</Editor.Panel>
|
||||||
{!hideSideBar && (
|
{!hideSideBar && (
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { PropsWithChildren } from 'react';
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { DropdownMenuOption, PositionedDropdownMenu } from '../../../common/components/dropdown-menu/DropdownMenu';
|
import { DropdownMenuOption, PositionedDropdownMenu } from '../../../common/components/dropdown-menu/DropdownMenu';
|
||||||
@@ -24,7 +23,7 @@ export const useContextMenuStore = create<ContextMenuStore>((set) => ({
|
|||||||
setIsOpen: (newIsOpen) => set(() => ({ isOpen: newIsOpen })),
|
setIsOpen: (newIsOpen) => set(() => ({ isOpen: newIsOpen })),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export function RundownContextMenu({ children }: PropsWithChildren) {
|
export function RundownContextMenu() {
|
||||||
const { position, options, isOpen, setIsOpen } = useContextMenuStore();
|
const { position, options, isOpen, setIsOpen } = useContextMenuStore();
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
@@ -32,13 +31,8 @@ export function RundownContextMenu({ children }: PropsWithChildren) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
return children;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <PositionedDropdownMenu isOpen position={position} onClose={onClose} items={options} />;
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
<PositionedDropdownMenu isOpen position={position} onClose={onClose} items={options} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export default function RundownEvent({
|
|||||||
const handleRef = useRef<null | HTMLSpanElement>(null);
|
const handleRef = useRef<null | HTMLSpanElement>(null);
|
||||||
const [isVisible, setIsVisible] = useState(false);
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
|
||||||
const [onContextMenu] = useContextMenu<HTMLDivElement>(
|
const [onContextMenu] = useContextMenu<HTMLDivElement>(() =>
|
||||||
selectedEvents.size > 1
|
selectedEvents.size > 1
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default function RundownGroup({ data, hasCursor, collapsed, onCollapse }:
|
|||||||
const setSingleEntrySelection = useEventSelection((state) => state.setSingleEntrySelection);
|
const setSingleEntrySelection = useEventSelection((state) => state.setSingleEntrySelection);
|
||||||
const selectedEvents = useEventSelection((state) => state.selectedEvents);
|
const selectedEvents = useEventSelection((state) => state.selectedEvents);
|
||||||
|
|
||||||
const [onContextMenu] = useContextMenu<HTMLDivElement>([
|
const [onContextMenu] = useContextMenu<HTMLDivElement>(() => [
|
||||||
{
|
{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
label: 'Clone Group',
|
label: 'Clone Group',
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default function RundownMilestone({ colour, cue, entryId, hasCursor, titl
|
|||||||
const selectedEvents = useEventSelection((state) => state.selectedEvents);
|
const selectedEvents = useEventSelection((state) => state.selectedEvents);
|
||||||
const setSingleEntrySelection = useEventSelection((state) => state.setSingleEntrySelection);
|
const setSingleEntrySelection = useEventSelection((state) => state.setSingleEntrySelection);
|
||||||
|
|
||||||
const [onContextMenu] = useContextMenu<HTMLDivElement>([
|
const [onContextMenu] = useContextMenu<HTMLDivElement>(() => [
|
||||||
{
|
{
|
||||||
type: 'item',
|
type: 'item',
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
|
|||||||
Reference in New Issue
Block a user