Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/player/src/views/Album/Album.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const Album: FC<AlbumProps> = () => {
return (
<ScrollableArea className="bg-background" data-testid="album-view">
<AlbumHeader providerId={providerId} albumId={albumId} />
<div className="p-6">
<div className="h-full p-6">
<AlbumTrackList providerId={providerId} albumId={albumId} />
</div>
</ScrollableArea>
Expand Down
660 changes: 334 additions & 326 deletions packages/player/src/views/Album/__snapshots__/Album.test.tsx.snap

Large diffs are not rendered by default.

1,076 changes: 546 additions & 530 deletions packages/player/src/views/Artist/__snapshots__/Artist.test.tsx.snap

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const PlaylistDetail: FC = () => {
className="flex-1"
/>
) : (
<div className="p-6">
<div className="h-full p-6">
<ConnectedTrackTable
tracks={tracks}
getItemId={editing.getItemId}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const PlaylistImport: FC = () => {
</PlaylistDetailHeader>
)}
{tracks.length > 0 && (
<div className="p-6">
<div className="h-full p-6">
<ConnectedTrackTable
tracks={tracks}
getItemId={getItemId}
Expand Down
22 changes: 20 additions & 2 deletions packages/ui/src/components/ScrollableArea/ScrollableArea.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
FC,
MutableRefObject,
ReactNode,
useCallback,
useEffect,
Expand All @@ -15,6 +16,8 @@ export type ScrollableAreaProps = {
className?: string;
fadeScrollbars?: boolean;
autoHideDelay?: number; // ms, default 1000
viewportRef?: MutableRefObject<HTMLDivElement | null>;
testViewportHeight?: number;
'data-testid'?: string;
};

Expand All @@ -37,7 +40,7 @@ const initialMetrics: ScrollMetrics = {
};

function useScrollMetrics(fadeScrollbars: boolean, autoHideDelay: number) {
const ref = useRef<HTMLDivElement>(null);
const ref = useRef<HTMLDivElement | null>(null);
const [metrics, setMetrics] = useState<ScrollMetrics>(initialMetrics);
const [isScrolling, setIsScrolling] = useState(false);
const hideTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
Expand Down Expand Up @@ -247,13 +250,25 @@ export const ScrollableArea: FC<ScrollableAreaProps> = ({
className,
fadeScrollbars = true,
autoHideDelay = 1000,
viewportRef,
testViewportHeight,
'data-testid': testId,
}) => {
const { ref, metrics, isScrolling, handleScroll } = useScrollMetrics(
fadeScrollbars,
autoHideDelay,
);

const setViewportNode = useCallback(
(node: HTMLDivElement | null) => {
ref.current = node;
if (viewportRef) {
viewportRef.current = node;
}
},
[ref, viewportRef],
);

const needsVertical = metrics.scrollHeight > metrics.clientHeight;
const needsHorizontal = metrics.scrollWidth > metrics.clientWidth;
const needsCorner = needsVertical && needsHorizontal;
Expand All @@ -264,10 +279,13 @@ export const ScrollableArea: FC<ScrollableAreaProps> = ({
data-testid={testId}
>
<div
ref={ref}
ref={setViewportNode}
className="scrollbar-hide flex h-full w-full flex-col overflow-auto"
onScroll={handleScroll}
style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
data-test-resize-observer-block-size={
testViewportHeight != null ? String(testViewportHeight) : undefined
}
>
{children}
</div>
Expand Down
122 changes: 62 additions & 60 deletions packages/ui/src/components/TrackTable/TrackTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useMemo, useRef } from 'react';
import { Track } from '@nuclearplayer/model';

import { cn } from '../../utils';
import { ScrollableArea } from '../ScrollableArea';
import { defaultDisplay, defaultFeatures } from './defaults';
import { useColumns } from './hooks/useColumns';
import { useGlobalFilter } from './hooks/useGlobalFilter';
Expand Down Expand Up @@ -111,7 +112,7 @@ export function TrackTable<T extends Track = Track>({

const dndItems = rows.map((row) => getItemId(row.original, row.index));

const mockViewportHeight = rowHeight * 12;
const testViewportHeight = rowHeight * 12;

return (
<TrackTableProvider
Expand All @@ -122,68 +123,69 @@ export function TrackTable<T extends Track = Track>({
labels: mergedLabels,
}}
>
<Toolbar
filterValue={globalFilter}
onFilterChange={setGlobalFilter}
className="mb-2"
/>
<div
ref={scrollParentRef}
className="relative flex max-h-full w-full overflow-y-auto"
data-test-resize-observer-inline-size="1024"
data-test-resize-observer-block-size={String(mockViewportHeight)}
>
<ReorderLayer
enabled={isReorderable}
items={dndItems}
onDragStart={onDragStart}
onDragEnd={onDragEnd as (evt: DragEndEvent) => void}
<div className="flex h-full flex-col">
<Toolbar
filterValue={globalFilter}
onFilterChange={setGlobalFilter}
className="mb-2 shrink-0"
/>
<ScrollableArea
viewportRef={scrollParentRef}
className="min-h-0 flex-1"
testViewportHeight={testViewportHeight}
>
<table
role="table"
className={cn(
'border-border relative w-full table-fixed border-(length:--border-width)',
classes?.root,
)}
<ReorderLayer
enabled={isReorderable}
items={dndItems}
onDragStart={onDragStart}
onDragEnd={onDragEnd as (evt: DragEndEvent) => void}
>
{resolvedFeatures?.header && (
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr
key={headerGroup.id}
role="row"
className="border-border bg-primary border-b-(length:--border-width)"
>
{headerGroup.headers.map((header) =>
flexRender(header.column.columnDef.header, {
...header.getContext(),
key: header.id,
}),
)}
</tr>
))}
</thead>
)}
<VirtualizedBody
rows={rows}
virtualItems={virtualItems}
paddingTop={paddingTop}
paddingBottom={paddingBottom}
colSpan={colCount}
rowHeight={rowHeight}
renderRow={({ row, virtual }) => (
<SortableRow
key={getItemId(row.original, row.index)}
row={row}
itemId={getItemId(row.original, row.index)}
style={{ height: rowHeight }}
isReorderable={isReorderable}
data-index={virtual.index}
/>
<table
role="table"
className={cn(
'border-border relative w-full table-fixed border-(length:--border-width)',
classes?.root,
)}
/>
</table>
</ReorderLayer>
>
{resolvedFeatures?.header && (
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr
key={headerGroup.id}
role="row"
className="border-border bg-primary border-b-(length:--border-width)"
>
{headerGroup.headers.map((header) =>
flexRender(header.column.columnDef.header, {
...header.getContext(),
key: header.id,
}),
)}
</tr>
))}
</thead>
)}
<VirtualizedBody
rows={rows}
virtualItems={virtualItems}
paddingTop={paddingTop}
paddingBottom={paddingBottom}
colSpan={colCount}
rowHeight={rowHeight}
renderRow={({ row, virtual }) => (
<SortableRow
key={getItemId(row.original, row.index)}
row={row}
itemId={getItemId(row.original, row.index)}
style={{ height: rowHeight }}
isReorderable={isReorderable}
data-index={virtual.index}
/>
)}
/>
</table>
</ReorderLayer>
</ScrollableArea>
</div>
</TrackTableProvider>
);
Expand Down
Loading
Loading