mirror of
https://github.com/jeffvli/feishin.git
synced 2026-06-17 17:04:16 +02:00
refactor item list to use accessor function
This commit is contained in:
@@ -6,7 +6,7 @@ import { ItemListItem } from '/@/renderer/components/item-list/types';
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
|
||||
export const ActionsColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: any = (props.data as (any | undefined)[])[props.rowIndex];
|
||||
const row: any = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
|
||||
const handleActionClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -13,11 +13,10 @@ import { JoinedArtists } from '/@/renderer/features/albums/components/joined-art
|
||||
import { Album, RelatedAlbumArtist, Song } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumArtistsColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: RelatedAlbumArtist[] | undefined = (
|
||||
props.data as (RelatedAlbumArtist[] | undefined)[]
|
||||
)[props.rowIndex]?.[props.columns[props.columnIndex].id];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: RelatedAlbumArtist[] | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const item = props.data[props.rowIndex] as Album | Song | undefined;
|
||||
const item = rowItem as Album | Song | undefined;
|
||||
const albumArtistString = item && 'albumArtistName' in item ? item.albumArtistName : '';
|
||||
|
||||
if (Array.isArray(row)) {
|
||||
|
||||
@@ -15,11 +15,10 @@ import { Text } from '/@/shared/components/text/text';
|
||||
import { Song } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: null | string | undefined = (props.data as (null | string | undefined)[])[
|
||||
props.rowIndex
|
||||
]?.[props.columns[props.columnIndex].id];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: null | string | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const song = props.data[props.rowIndex] as Song | undefined;
|
||||
const song = rowItem as Song | undefined;
|
||||
const albumId = song?.albumId;
|
||||
|
||||
const albumPath = useMemo(() => {
|
||||
|
||||
@@ -16,9 +16,8 @@ import { Text } from '/@/shared/components/text/text';
|
||||
import { LibraryItem, RelatedAlbumArtist, Song } from '/@/shared/types/domain-types';
|
||||
|
||||
const AlbumArtistsColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: RelatedAlbumArtist[] | undefined = (
|
||||
props.data as (RelatedAlbumArtist[] | undefined)[]
|
||||
)[props.rowIndex]?.[props.columns[props.columnIndex].id];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: RelatedAlbumArtist[] | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const artists = useMemo(() => {
|
||||
if (!row) return [];
|
||||
@@ -67,7 +66,8 @@ const AlbumArtistsColumn = (props: ItemTableListInnerColumn) => {
|
||||
};
|
||||
|
||||
const SongArtistsColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: Song | undefined = (props.data as (Song | undefined)[])[props.rowIndex];
|
||||
const row: Song | undefined =
|
||||
(props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex]) as Song | undefined;
|
||||
|
||||
if (row) {
|
||||
return (
|
||||
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const CountColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: number | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'number') {
|
||||
return (
|
||||
|
||||
@@ -30,9 +30,8 @@ const getDateTooltipLabel = (utcString: string) => {
|
||||
};
|
||||
|
||||
export const DateColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string' && row) {
|
||||
return (
|
||||
@@ -52,12 +51,11 @@ export const DateColumn = (props: ItemTableListInnerColumn) => {
|
||||
};
|
||||
|
||||
export const AbsoluteDateColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (props.type === TableColumn.RELEASE_DATE) {
|
||||
const item = (props.data as (any | undefined)[])[props.rowIndex];
|
||||
const item = rowItem as any;
|
||||
if (item && 'releaseDate' in item && item.releaseDate) {
|
||||
const releaseDate = item.releaseDate;
|
||||
const originalDate =
|
||||
@@ -115,9 +113,8 @@ export const AbsoluteDateColumn = (props: ItemTableListInnerColumn) => {
|
||||
};
|
||||
|
||||
export const RelativeDateColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string') {
|
||||
return (
|
||||
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const DefaultColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: any | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: any | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string') {
|
||||
return <TableColumnTextContainer {...props}>{row}</TableColumnTextContainer>;
|
||||
|
||||
@@ -8,9 +8,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const DurationColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: number | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'number') {
|
||||
return (
|
||||
|
||||
@@ -8,9 +8,8 @@ import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutatio
|
||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||
|
||||
export const FavoriteColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: boolean | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: boolean | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const isMutatingCreateFavorite = useIsMutatingCreateFavorite();
|
||||
const isMutatingDeleteFavorite = useIsMutatingDeleteFavorite();
|
||||
@@ -31,7 +30,7 @@ export const FavoriteColumn = (props: ItemTableListInnerColumn) => {
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
const item = props.data[props.rowIndex] as ItemListItem;
|
||||
const item = rowItem as ItemListItem;
|
||||
const rowId = props.internalState.extractRowId(item);
|
||||
const index = rowId ? props.internalState.findItemIndex(rowId) : -1;
|
||||
props.controls.onFavorite?.({
|
||||
|
||||
@@ -18,9 +18,8 @@ import { stringToColor } from '/@/shared/utils/string-to-color';
|
||||
const MAX_GENRES = 4;
|
||||
|
||||
const GenreBadgeColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: Genre[] | undefined = (props.data as (Genre[] | undefined)[])[props.rowIndex]?.[
|
||||
'genres'
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: Genre[] | undefined = (rowItem as any)?.genres;
|
||||
|
||||
const genres = useMemo(() => {
|
||||
if (!row) return [];
|
||||
|
||||
@@ -15,9 +15,8 @@ import { Text } from '/@/shared/components/text/text';
|
||||
import { Genre } from '/@/shared/types/domain-types';
|
||||
|
||||
const GenreColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: Genre[] | undefined = (props.data as (Genre[] | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: Genre[] | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const genres = useMemo(() => {
|
||||
if (!row) return [];
|
||||
|
||||
@@ -20,8 +20,9 @@ import { Folder, LibraryItem } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const ImageColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.id;
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = rowItem?.id;
|
||||
const item = rowItem as any;
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const internalState = (props as any).internalState;
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@@ -113,7 +114,7 @@ export const ImageColumn = (props: ItemTableListInnerColumn) => {
|
||||
);
|
||||
}
|
||||
|
||||
if ((props.data[props.rowIndex] as unknown as Folder)?._itemType === LibraryItem.FOLDER) {
|
||||
if ((rowItem as unknown as Folder)?._itemType === LibraryItem.FOLDER) {
|
||||
return (
|
||||
<TableColumnContainer {...props}>
|
||||
<Icon className={styles.folderIcon} icon="folder" size="2xl" />
|
||||
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const NumericColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: number | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'number') {
|
||||
return <TableColumnTextContainer {...props}>{row}</TableColumnTextContainer>;
|
||||
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const PathColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string' && row) {
|
||||
return (
|
||||
|
||||
+5
-3
@@ -24,7 +24,9 @@ export const PlaylistReorderColumn = (props: ItemTableListInnerColumn) => {
|
||||
const { playlistId } = useParams() as { playlistId?: string };
|
||||
const isHeaderEnabled = !!props.enableHeader;
|
||||
const isDataRow = isHeaderEnabled ? props.rowIndex > 0 : true;
|
||||
const item = isDataRow ? props.data[props.rowIndex] : null;
|
||||
const item = isDataRow
|
||||
? (props.getRowItem?.(props.rowIndex) ?? props.data[props.rowIndex])
|
||||
: null;
|
||||
|
||||
const isPlaylistSong = props.itemType === LibraryItem.PLAYLIST_SONG;
|
||||
|
||||
@@ -153,8 +155,8 @@ export const PlaylistReorderColumn = (props: ItemTableListInnerColumn) => {
|
||||
const isDragging = props.internalState ? isDraggingState : isDraggingLocal;
|
||||
|
||||
const getValidDataItems = useCallback(() => {
|
||||
return props.data.filter((d) => d !== null && (d as any).id);
|
||||
}, [props.data]);
|
||||
return props.internalState.getData().filter((d) => d !== null && (d as any).id);
|
||||
}, [props.internalState]);
|
||||
|
||||
const handleMoveUp = useCallback(() => {
|
||||
if (!item || !isDataRow || !isPlaylistSong || !playlistId) {
|
||||
|
||||
@@ -7,9 +7,8 @@ import { useIsMutatingRating } from '/@/renderer/features/shared/mutations/set-r
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
|
||||
export const RatingColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: null | number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: null | number | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const isMutatingRating = useIsMutatingRating();
|
||||
|
||||
@@ -19,7 +18,7 @@ export const RatingColumn = (props: ItemTableListInnerColumn) => {
|
||||
<Rating
|
||||
className={row ? undefined : 'hover-only-flex'}
|
||||
onChange={(rating) => {
|
||||
const item = props.data[props.rowIndex] as ItemListItem;
|
||||
const item = rowItem as ItemListItem;
|
||||
const rowId = props.internalState.extractRowId(item);
|
||||
const index = rowId ? props.internalState.findItemIndex(rowId) : -1;
|
||||
props.controls.onRating?.({
|
||||
|
||||
@@ -61,7 +61,7 @@ const DefaultRowIndexColumn = (props: ItemTableListInnerColumn) => {
|
||||
icon="arrowDownS"
|
||||
iconProps={{ color: 'muted', size: 'md' }}
|
||||
onClick={(e) => {
|
||||
const item = data[rowIndex] as ItemListItem;
|
||||
const item = (props.getRowItem?.(rowIndex) ?? data[rowIndex]) as ItemListItem;
|
||||
const rowId = internalState.extractRowId(item);
|
||||
const index = rowId ? internalState.findItemIndex(rowId) : -1;
|
||||
controls.onExpand?.({
|
||||
@@ -87,7 +87,7 @@ const DefaultRowIndexColumn = (props: ItemTableListInnerColumn) => {
|
||||
|
||||
const QueueSongRowIndexColumn = (props: ItemTableListInnerColumn) => {
|
||||
const status = usePlayerStatus();
|
||||
const song = props.data[props.rowIndex] as QueueSong;
|
||||
const song = (props.getRowItem?.(props.rowIndex) ?? props.data[props.rowIndex]) as QueueSong;
|
||||
const isActive = useIsActiveRow(song?.id, song?._uniqueId);
|
||||
|
||||
const isActiveAndPlaying = isActive && status === PlayerStatus.PLAYING;
|
||||
|
||||
@@ -7,9 +7,8 @@ import {
|
||||
import { formatSizeString } from '/@/renderer/utils/format';
|
||||
|
||||
export const SizeColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: number | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'number') {
|
||||
return (
|
||||
|
||||
@@ -10,9 +10,8 @@ import {
|
||||
} from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
|
||||
|
||||
export const TextColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string' && row) {
|
||||
return (
|
||||
|
||||
@@ -29,13 +29,12 @@ export const TitleColumn = (props: ItemTableListInnerColumn) => {
|
||||
};
|
||||
|
||||
function DefaultTitleColumn(props: ItemTableListInnerColumn) {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (typeof row === 'string') {
|
||||
const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string);
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const path = getTitlePath(props.itemType, (rowItem as any).id as string);
|
||||
const item = rowItem as any;
|
||||
|
||||
const titleLinkProps = path
|
||||
? {
|
||||
@@ -71,16 +70,15 @@ function DefaultTitleColumn(props: ItemTableListInnerColumn) {
|
||||
}
|
||||
|
||||
function QueueSongTitleColumn(props: ItemTableListInnerColumn) {
|
||||
const row: string | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: string | undefined = rowItem?.[props.columns[props.columnIndex].id];
|
||||
|
||||
const song = props.data[props.rowIndex] as QueueSong;
|
||||
const song = rowItem as QueueSong;
|
||||
const isActive = useIsActiveRow(song?.id, song?._uniqueId);
|
||||
|
||||
if (typeof row === 'string') {
|
||||
const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string);
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const path = getTitlePath(props.itemType, (rowItem as any).id as string);
|
||||
const item = rowItem as any;
|
||||
|
||||
const titleLinkProps = path
|
||||
? {
|
||||
|
||||
+15
-13
@@ -26,8 +26,9 @@ import { Folder, LibraryItem, QueueSong } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
export const DefaultTitleCombinedColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: object | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.id;
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: object | undefined = (rowItem as any)?.id;
|
||||
const item = rowItem as any;
|
||||
const internalState = (props as any).internalState;
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@@ -76,9 +77,9 @@ export const DefaultTitleCombinedColumn = (props: ItemTableListInnerColumn) => {
|
||||
|
||||
if (item && 'name' in item && 'imageUrl' in item && 'artists' in item) {
|
||||
const rowHeight = props.getRowHeight(props.rowIndex, props);
|
||||
const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string);
|
||||
const path = getTitlePath(props.itemType, (rowItem as any).id as string);
|
||||
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const item = rowItem as any;
|
||||
const titleLinkProps = path
|
||||
? {
|
||||
component: Link,
|
||||
@@ -156,10 +157,11 @@ export const DefaultTitleCombinedColumn = (props: ItemTableListInnerColumn) => {
|
||||
};
|
||||
|
||||
export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) => {
|
||||
const row: object | undefined = (props.data as (any | undefined)[])[props.rowIndex];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const row: object | undefined = rowItem as any;
|
||||
|
||||
const song = props.data[props.rowIndex] as QueueSong;
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const song = rowItem as QueueSong;
|
||||
const item = rowItem as any;
|
||||
const internalState = (props as any).internalState;
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
@@ -209,9 +211,9 @@ export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) =>
|
||||
|
||||
if (row && 'name' in row && 'imageUrl' in row && 'artists' in row) {
|
||||
const rowHeight = props.getRowHeight(props.rowIndex, props);
|
||||
const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string);
|
||||
const path = getTitlePath(props.itemType, (rowItem as any).id as string);
|
||||
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const item = rowItem as any;
|
||||
|
||||
const titleLinkProps = path
|
||||
? {
|
||||
@@ -306,11 +308,11 @@ export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) =>
|
||||
);
|
||||
}
|
||||
|
||||
if ((props.data[props.rowIndex] as unknown as Folder)?._itemType === LibraryItem.FOLDER) {
|
||||
if ((rowItem as unknown as Folder)?._itemType === LibraryItem.FOLDER) {
|
||||
const rowHeight = props.getRowHeight(props.rowIndex, props);
|
||||
const path = getTitlePath(props.itemType, (props.data[props.rowIndex] as any).id as string);
|
||||
const path = getTitlePath(props.itemType, (rowItem as any).id as string);
|
||||
|
||||
const item = props.data[props.rowIndex] as any;
|
||||
const item = rowItem as any;
|
||||
const textStyles = isActive ? { color: 'var(--theme-colors-primary)' } : {};
|
||||
|
||||
const titleLinkProps = path
|
||||
@@ -322,7 +324,7 @@ export const QueueSongTitleCombinedColumn = (props: ItemTableListInnerColumn) =>
|
||||
}
|
||||
: {};
|
||||
|
||||
const title = (props.data[props.rowIndex] as unknown as Folder)?.name;
|
||||
const title = (rowItem as unknown as Folder)?.name;
|
||||
|
||||
return (
|
||||
<TableColumnContainer
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
import { SEPARATOR_STRING } from '/@/shared/api/utils';
|
||||
|
||||
export const YearColumn = (props: ItemTableListInnerColumn) => {
|
||||
const item = (props.data as (any | undefined)[])[props.rowIndex];
|
||||
const rowItem = props.getRowItem?.(props.rowIndex) ?? (props.data as any[])[props.rowIndex];
|
||||
const item = rowItem as any;
|
||||
|
||||
if (item && 'releaseYear' in item && item.releaseYear !== null) {
|
||||
const releaseYear = item.releaseYear;
|
||||
@@ -29,9 +30,7 @@ export const YearColumn = (props: ItemTableListInnerColumn) => {
|
||||
}
|
||||
}
|
||||
|
||||
const row: number | undefined = (props.data as (any | undefined)[])[props.rowIndex]?.[
|
||||
props.columns[props.columnIndex].id
|
||||
];
|
||||
const row: number | undefined = (rowItem as any)?.[props.columns[props.columnIndex].id];
|
||||
|
||||
if (row === null) {
|
||||
return <ColumnNullFallback {...props} />;
|
||||
|
||||
+24
-6
@@ -17,11 +17,14 @@ interface UseTableKeyboardNavigationProps {
|
||||
enableHeader: boolean;
|
||||
enableSelection: boolean;
|
||||
extractRowId: (item: unknown) => string | undefined;
|
||||
getItem?: (index: number) => undefined | unknown;
|
||||
getItemIndex?: (rowId: string) => number | undefined;
|
||||
getStateItem: (item: any) => ItemListStateItemWithRequiredProperties | null;
|
||||
hasRequiredStateItemProperties: (
|
||||
item: unknown,
|
||||
) => item is ItemListStateItemWithRequiredProperties;
|
||||
internalState: ItemListStateActions;
|
||||
itemCount?: number;
|
||||
itemType: LibraryItem;
|
||||
parsedColumns: TableItemProps['columns'];
|
||||
pinnedRightColumnCount: number;
|
||||
@@ -45,9 +48,12 @@ export const useTableKeyboardNavigation = ({
|
||||
enableHeader,
|
||||
enableSelection,
|
||||
extractRowId,
|
||||
getItem,
|
||||
getItemIndex,
|
||||
getStateItem,
|
||||
hasRequiredStateItemProperties,
|
||||
internalState,
|
||||
itemCount,
|
||||
itemType,
|
||||
parsedColumns,
|
||||
pinnedRightColumnCount,
|
||||
@@ -69,23 +75,26 @@ export const useTableKeyboardNavigation = ({
|
||||
const selected = internalState.getSelected();
|
||||
const validSelected = selected.filter(hasRequiredStateItemProperties);
|
||||
let currentIndex = -1;
|
||||
const totalCount = itemCount ?? data.length;
|
||||
|
||||
if (validSelected.length > 0) {
|
||||
const lastSelected = validSelected[validSelected.length - 1];
|
||||
currentIndex = data.findIndex(
|
||||
(d) => extractRowId(d) === extractRowId(lastSelected),
|
||||
);
|
||||
const rowId = extractRowId(lastSelected);
|
||||
if (rowId) {
|
||||
currentIndex =
|
||||
getItemIndex?.(rowId) ?? data.findIndex((d) => extractRowId(d) === rowId);
|
||||
}
|
||||
}
|
||||
|
||||
let newIndex = 0;
|
||||
if (currentIndex !== -1) {
|
||||
newIndex =
|
||||
e.key === 'ArrowDown'
|
||||
? Math.min(currentIndex + 1, data.length - 1)
|
||||
? Math.min(currentIndex + 1, totalCount - 1)
|
||||
: Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
|
||||
const newItem: any = data[newIndex];
|
||||
const newItem: any = getItem ? getItem(newIndex) : data[newIndex];
|
||||
if (!newItem) return;
|
||||
|
||||
const newItemListItem = getStateItem(newItem);
|
||||
@@ -118,7 +127,7 @@ export const useTableKeyboardNavigation = ({
|
||||
cellPadding,
|
||||
columns: parsedColumns,
|
||||
controls: {} as ItemControls,
|
||||
data: enableHeader ? [null, ...data] : data,
|
||||
data: enableHeader ? [null] : [],
|
||||
enableAlternateRowColors: false,
|
||||
enableExpansion: false,
|
||||
enableHeader,
|
||||
@@ -127,6 +136,12 @@ export const useTableKeyboardNavigation = ({
|
||||
enableSelection,
|
||||
enableVerticalBorders: false,
|
||||
getRowHeight: () => DEFAULT_ROW_HEIGHT,
|
||||
getRowItem: (rowIndex: number) => {
|
||||
if (!getItem) return undefined;
|
||||
if (enableHeader && rowIndex === 0) return null;
|
||||
const dataIndex = enableHeader ? rowIndex - 1 : rowIndex;
|
||||
return getItem(dataIndex);
|
||||
},
|
||||
internalState: {} as ItemListStateActions,
|
||||
itemType,
|
||||
playerContext,
|
||||
@@ -174,6 +189,8 @@ export const useTableKeyboardNavigation = ({
|
||||
calculateScrollTopForIndex,
|
||||
cellPadding,
|
||||
data,
|
||||
getItem,
|
||||
getItemIndex,
|
||||
DEFAULT_ROW_HEIGHT,
|
||||
enableHeader,
|
||||
enableSelection,
|
||||
@@ -181,6 +198,7 @@ export const useTableKeyboardNavigation = ({
|
||||
getStateItem,
|
||||
hasRequiredStateItemProperties,
|
||||
internalState,
|
||||
itemCount,
|
||||
itemType,
|
||||
parsedColumns,
|
||||
pinnedRightColumnCount,
|
||||
|
||||
@@ -84,7 +84,9 @@ export const ItemTableListColumn = (props: ItemTableListColumn) => {
|
||||
|
||||
const isHeaderEnabled = !!props.enableHeader;
|
||||
const isDataRow = isHeaderEnabled ? props.rowIndex > 0 : true;
|
||||
const item = isDataRow ? props.data[props.rowIndex] : null;
|
||||
const item = isDataRow
|
||||
? (props.getRowItem?.(props.rowIndex) ?? props.data[props.rowIndex])
|
||||
: null;
|
||||
const shouldEnableDrag = !!props.enableDrag && isDataRow && !!item;
|
||||
const itemType = (item as unknown as { _itemType?: LibraryItem })?._itemType || props.itemType;
|
||||
|
||||
@@ -585,7 +587,9 @@ export const TableColumnTextContainer = (
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const isDataRow = props.enableHeader ? props.rowIndex > 0 : true;
|
||||
const dataIndex = props.enableHeader ? props.rowIndex - 1 : props.rowIndex;
|
||||
const item = isDataRow ? props.data[props.rowIndex] : null;
|
||||
const item = isDataRow
|
||||
? (props.getRowItem?.(props.rowIndex) ?? props.data[props.rowIndex])
|
||||
: null;
|
||||
const itemRowId =
|
||||
item && typeof item === 'object' && 'id' in item
|
||||
? props.internalState.extractRowId(item)
|
||||
@@ -736,7 +740,9 @@ export const TableColumnContainer = (
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const isDataRow = props.enableHeader ? props.rowIndex > 0 : true;
|
||||
const dataIndex = props.enableHeader ? props.rowIndex - 1 : props.rowIndex;
|
||||
const item = isDataRow ? props.data[props.rowIndex] : null;
|
||||
const item = isDataRow
|
||||
? (props.getRowItem?.(props.rowIndex) ?? props.data[props.rowIndex])
|
||||
: null;
|
||||
const itemRowId =
|
||||
item && typeof item === 'object' && 'id' in item
|
||||
? props.internalState.extractRowId(item)
|
||||
|
||||
@@ -116,6 +116,7 @@ interface VirtualizedTableGridProps {
|
||||
enableScrollShadow: boolean;
|
||||
enableSelection: boolean;
|
||||
enableVerticalBorders: boolean;
|
||||
getItem?: (index: number) => undefined | unknown;
|
||||
getRowHeight: (index: number, cellProps: TableItemProps) => number;
|
||||
groups?: TableGroupHeader[];
|
||||
headerHeight: number;
|
||||
@@ -159,6 +160,7 @@ const VirtualizedTableGrid = ({
|
||||
enableScrollShadow,
|
||||
enableSelection,
|
||||
enableVerticalBorders,
|
||||
getItem,
|
||||
getRowHeight,
|
||||
groups,
|
||||
headerHeight,
|
||||
@@ -284,6 +286,44 @@ const VirtualizedTableGrid = ({
|
||||
[enableHeader, groupHeaderInfoByRowIndex, groupHeaderRowIndexes, groups],
|
||||
);
|
||||
|
||||
const getRowItem = useCallback(
|
||||
(rowIndex: number): null | undefined | unknown => {
|
||||
// Header row
|
||||
if (enableHeader && rowIndex === 0) return null;
|
||||
// Group header rows are represented as null in the row model
|
||||
if (groupHeaderInfoByRowIndex?.has(rowIndex)) return null;
|
||||
|
||||
if (!groups || groups.length === 0) {
|
||||
const dataIndex = enableHeader ? rowIndex - 1 : rowIndex;
|
||||
return getItem ? getItem(dataIndex) : dataWithGroups[rowIndex];
|
||||
}
|
||||
|
||||
const headerOffset = enableHeader ? 1 : 0;
|
||||
|
||||
// Count group header rows strictly before this rowIndex (upperBound on groupHeaderRowIndexes)
|
||||
let lo = 0;
|
||||
let hi = groupHeaderRowIndexes.length;
|
||||
const target = rowIndex - 1;
|
||||
while (lo < hi) {
|
||||
const mid = (lo + hi) >>> 1;
|
||||
if (groupHeaderRowIndexes[mid] <= target) lo = mid + 1;
|
||||
else hi = mid;
|
||||
}
|
||||
const groupHeadersBefore = lo;
|
||||
|
||||
const dataIndex = rowIndex - headerOffset - groupHeadersBefore;
|
||||
return getItem ? getItem(dataIndex) : undefined;
|
||||
},
|
||||
[
|
||||
dataWithGroups,
|
||||
enableHeader,
|
||||
getItem,
|
||||
groupHeaderInfoByRowIndex,
|
||||
groupHeaderRowIndexes,
|
||||
groups,
|
||||
],
|
||||
);
|
||||
|
||||
const stableConfigProps = useMemo(
|
||||
() => ({
|
||||
cellPadding,
|
||||
@@ -317,6 +357,7 @@ const VirtualizedTableGrid = ({
|
||||
data: dataWithGroups,
|
||||
getAdjustedRowIndex,
|
||||
getGroupRenderData,
|
||||
getRowItem,
|
||||
groupHeaderInfoByRowIndex,
|
||||
pinnedLeftColumnCount,
|
||||
pinnedLeftColumnWidths,
|
||||
@@ -327,6 +368,7 @@ const VirtualizedTableGrid = ({
|
||||
[
|
||||
calculatedColumnWidths,
|
||||
dataWithGroups,
|
||||
getRowItem,
|
||||
getAdjustedRowIndex,
|
||||
getGroupRenderData,
|
||||
groupHeaderInfoByRowIndex,
|
||||
@@ -724,6 +766,7 @@ export interface TableItemProps {
|
||||
getAdjustedRowIndex?: (rowIndex: number) => number;
|
||||
getGroupRenderData?: () => unknown[];
|
||||
getRowHeight: (index: number, cellProps: TableItemProps) => number;
|
||||
getRowItem?: (rowIndex: number) => null | undefined | unknown;
|
||||
groupHeaderInfoByRowIndex?: Map<number, { groupIndex: number; startDataIndex: number }>;
|
||||
groups?: TableGroupHeader[];
|
||||
internalState: ItemListStateActions;
|
||||
@@ -759,6 +802,8 @@ interface ItemTableListProps {
|
||||
enableStickyGroupRows?: boolean;
|
||||
enableStickyHeader?: boolean;
|
||||
enableVerticalBorders?: boolean;
|
||||
getItem?: (index: number) => undefined | unknown;
|
||||
getItemIndex?: (rowId: string) => number | undefined;
|
||||
getRowId?: ((item: unknown) => string) | string;
|
||||
groups?: TableGroupHeader[];
|
||||
headerHeight?: number;
|
||||
@@ -767,6 +812,7 @@ interface ItemTableListProps {
|
||||
to: number;
|
||||
type: 'index' | 'offset';
|
||||
};
|
||||
itemCount?: number;
|
||||
itemType: LibraryItem;
|
||||
onColumnReordered?: (
|
||||
columnIdFrom: TableColumn,
|
||||
@@ -802,10 +848,13 @@ const BaseItemTableList = ({
|
||||
enableStickyGroupRows = false,
|
||||
enableStickyHeader = false,
|
||||
enableVerticalBorders = false,
|
||||
getItem,
|
||||
getItemIndex,
|
||||
getRowId,
|
||||
groups,
|
||||
headerHeight = 40,
|
||||
initialTop,
|
||||
itemCount,
|
||||
itemType,
|
||||
onColumnReordered,
|
||||
onColumnResized,
|
||||
@@ -818,7 +867,8 @@ const BaseItemTableList = ({
|
||||
startRowIndex,
|
||||
}: ItemTableListProps) => {
|
||||
const tableId = useId();
|
||||
const totalItemCount = enableHeader ? data.length + 1 : data.length;
|
||||
const baseItemCount = itemCount ?? data.length;
|
||||
const totalItemCount = enableHeader ? baseItemCount + 1 : baseItemCount;
|
||||
const [centerContainerWidth, setCenterContainerWidth] = useState(0);
|
||||
const [totalContainerWidth, setTotalContainerWidth] = useState(0);
|
||||
|
||||
@@ -836,12 +886,29 @@ const BaseItemTableList = ({
|
||||
});
|
||||
const playerContext = usePlayer();
|
||||
|
||||
const { dataWithGroups, groupHeaderRowCount } = useTableRowModel({
|
||||
const {
|
||||
dataWithGroups: dataWithGroupsFromModel,
|
||||
groupHeaderRowCount: groupHeaderRowCountFromModel,
|
||||
} = useTableRowModel({
|
||||
data,
|
||||
enableHeader,
|
||||
groups,
|
||||
});
|
||||
|
||||
const shouldUseAccessor = typeof getItem === 'function' && typeof itemCount === 'number';
|
||||
|
||||
// Avoid constructing a massive row-model array for infinite lists.
|
||||
// Cell renderers use `getRowItem` accessor when provided.
|
||||
const dataWithGroups = useMemo<(null | unknown)[]>(() => {
|
||||
if (!shouldUseAccessor) return dataWithGroupsFromModel;
|
||||
return enableHeader ? [null] : [];
|
||||
}, [dataWithGroupsFromModel, enableHeader, shouldUseAccessor]);
|
||||
|
||||
const groupHeaderRowCount = useMemo(() => {
|
||||
if (!shouldUseAccessor) return groupHeaderRowCountFromModel;
|
||||
return groups?.length ? groups.length : 0;
|
||||
}, [groupHeaderRowCountFromModel, groups, shouldUseAccessor]);
|
||||
|
||||
const pinnedRowCount = enableHeader ? 1 : 0;
|
||||
|
||||
// Group headers are inserted at specific indexes, so they add to the total row count
|
||||
@@ -1007,8 +1074,9 @@ const BaseItemTableList = ({
|
||||
});
|
||||
|
||||
const getDataFn = useCallback(() => {
|
||||
return dataWithGroups;
|
||||
}, [dataWithGroups]);
|
||||
// For infinite lists, callers should pass `data` as the currently loaded items only.
|
||||
return data;
|
||||
}, [data]);
|
||||
|
||||
const extractRowId = useMemo(() => createExtractRowId(getRowId), [getRowId]);
|
||||
|
||||
@@ -1041,9 +1109,12 @@ const BaseItemTableList = ({
|
||||
enableHeader,
|
||||
enableSelection,
|
||||
extractRowId,
|
||||
getItem,
|
||||
getItemIndex,
|
||||
getStateItem,
|
||||
hasRequiredStateItemProperties,
|
||||
internalState,
|
||||
itemCount: baseItemCount,
|
||||
itemType,
|
||||
parsedColumns,
|
||||
pinnedRightColumnCount,
|
||||
@@ -1499,6 +1570,7 @@ const BaseItemTableList = ({
|
||||
enableScrollShadow={enableScrollShadow}
|
||||
enableSelection={enableSelection}
|
||||
enableVerticalBorders={enableVerticalBorders}
|
||||
getItem={getItem}
|
||||
getRowHeight={getRowHeight}
|
||||
groups={groups}
|
||||
headerHeight={headerHeight}
|
||||
|
||||
Reference in New Issue
Block a user