Files
feishin/src/renderer/features/context-menu/context-menu-controller.tsx
T

152 lines
4.9 KiB
TypeScript

import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useRef } from 'react';
import { createCallable } from 'react-call';
import { useParams } from 'react-router';
import { AlbumArtistContextMenu } from '/@/renderer/features/context-menu/menus/album-artist-context-menu';
import { AlbumContextMenu } from '/@/renderer/features/context-menu/menus/album-context-menu';
import { ArtistContextMenu } from '/@/renderer/features/context-menu/menus/artist-context-menu';
import { FolderContextMenu } from '/@/renderer/features/context-menu/menus/folder-context-menu';
import { GenreContextMenu } from '/@/renderer/features/context-menu/menus/genre-context-menu';
import { PlaylistContextMenu } from '/@/renderer/features/context-menu/menus/playlist-context-menu';
import { PlaylistSongContextMenu } from '/@/renderer/features/context-menu/menus/playlist-song-context-menu';
import { QueueContextMenu } from '/@/renderer/features/context-menu/menus/queue-context-menu';
import { SongContextMenu } from '/@/renderer/features/context-menu/menus/song-context-menu';
import { ContextMenu } from '/@/shared/components/context-menu/context-menu';
import {
Album,
AlbumArtist,
Artist,
Folder,
Genre,
LibraryItem,
Playlist,
QueueSong,
Song,
} from '/@/shared/types/domain-types';
interface ContextMenuControllerProps {
cmd: ContextMenuCommand;
event: React.MouseEvent<unknown>;
}
export const ContextMenuController = createCallable<ContextMenuControllerProps, void>(
({ call, cmd, event }) => {
const { libraryId } = useParams() as { libraryId: string };
const queryClient = useQueryClient();
const triggerRef = useRef<HTMLDivElement>(null);
const isExecuted = useRef<boolean>(false);
useEffect(() => {
if (isExecuted.current) {
return;
}
if (!triggerRef.current) {
return;
}
const handleContextMenu = () => {
event.preventDefault();
triggerRef.current?.dispatchEvent(
new MouseEvent('contextmenu', {
bubbles: true,
clientX: event.clientX,
clientY: event.clientY,
}),
);
};
isExecuted.current = true;
handleContextMenu();
}, [call, cmd, event, event.clientX, event.clientY, libraryId, queryClient]);
return (
<ContextMenu>
<ContextMenu.Target>
<div
ref={triggerRef}
style={{
height: 0,
left: 0,
pointerEvents: 'none',
position: 'absolute',
top: 0,
userSelect: 'none',
width: 0,
}}
/>
</ContextMenu.Target>
{cmd.type === LibraryItem.QUEUE_SONG && <QueueContextMenu {...cmd} />}
{cmd.type === LibraryItem.ALBUM && <AlbumContextMenu {...cmd} />}
{cmd.type === LibraryItem.ALBUM_ARTIST && <AlbumArtistContextMenu {...cmd} />}
{cmd.type === LibraryItem.ARTIST && <ArtistContextMenu {...cmd} />}
{cmd.type === LibraryItem.FOLDER && <FolderContextMenu {...cmd} />}
{cmd.type === LibraryItem.GENRE && <GenreContextMenu {...cmd} />}
{cmd.type === LibraryItem.PLAYLIST && <PlaylistContextMenu {...cmd} />}
{cmd.type === LibraryItem.PLAYLIST_SONG && <PlaylistSongContextMenu {...cmd} />}
{cmd.type === LibraryItem.SONG && <SongContextMenu {...cmd} />}
</ContextMenu>
);
},
);
export type ContextMenuCommand =
| AlbumArtistContextMenuProps
| AlbumContextMenuProps
| ArtistContextMenuProps
| FolderContextMenuProps
| GenreContextMenuProps
| PlaylistContextMenuProps
| PlaylistSongContextMenuProps
| QueueSongContextMenuProps
| SongContextMenuProps;
type AlbumArtistContextMenuProps = {
items: AlbumArtist[];
type: LibraryItem.ALBUM_ARTIST;
};
type AlbumContextMenuProps = {
items: Album[];
type: LibraryItem.ALBUM;
};
type ArtistContextMenuProps = {
items: Artist[];
type: LibraryItem.ARTIST;
};
type FolderContextMenuProps = {
items: Folder[];
type: LibraryItem.FOLDER;
};
type GenreContextMenuProps = {
items: Genre[];
type: LibraryItem.GENRE;
};
type PlaylistContextMenuProps = {
items: Playlist[];
type: LibraryItem.PLAYLIST;
};
type PlaylistSongContextMenuProps = {
items: Song[];
type: LibraryItem.PLAYLIST_SONG;
};
type QueueSongContextMenuProps = {
items: QueueSong[];
type: LibraryItem.QUEUE_SONG;
};
type SongContextMenuProps = {
items: Song[];
type: LibraryItem.SONG;
};