mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-06 20:10:12 +02:00
add scrollToIndex alignment to lists
This commit is contained in:
@@ -360,10 +360,24 @@ export const ItemGridList = ({
|
||||
const controls = useDefaultItemListControls();
|
||||
|
||||
const scrollToIndex = useCallback(
|
||||
(index: number) => {
|
||||
(
|
||||
index: number,
|
||||
options?: { align?: 'bottom' | 'center' | 'top'; behavior?: 'auto' | 'smooth' },
|
||||
) => {
|
||||
if (!listRef.current || !tableMeta) return;
|
||||
const row = Math.floor(index / tableMeta.columnCount);
|
||||
listRef.current.scrollToItem(row, 'smart');
|
||||
|
||||
// Map alignment options to react-window's alignment
|
||||
let alignment: 'auto' | 'center' | 'end' | 'smart' | 'start' = 'smart';
|
||||
if (options?.align === 'top') {
|
||||
alignment = 'start';
|
||||
} else if (options?.align === 'center') {
|
||||
alignment = 'center';
|
||||
} else if (options?.align === 'bottom') {
|
||||
alignment = 'end';
|
||||
}
|
||||
|
||||
listRef.current.scrollToItem(row, alignment);
|
||||
},
|
||||
[tableMeta],
|
||||
);
|
||||
@@ -580,8 +594,8 @@ export const ItemGridList = ({
|
||||
const imperativeHandle: ItemListHandle = useMemo(() => {
|
||||
return {
|
||||
internalState,
|
||||
scrollToIndex: (index: number) => {
|
||||
scrollToIndex(index);
|
||||
scrollToIndex: (index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||
scrollToIndex(index, options);
|
||||
},
|
||||
scrollToOffset: (offset: number) => {
|
||||
scrollToOffset(offset);
|
||||
|
||||
@@ -703,14 +703,16 @@ export const ItemTableList = ({
|
||||
| HTMLDivElement
|
||||
| undefined;
|
||||
|
||||
const behavior = 'instant';
|
||||
|
||||
if (mainContainer) {
|
||||
mainContainer.scrollTo({ behavior: 'instant', top: offset });
|
||||
mainContainer.scrollTo({ behavior, top: offset });
|
||||
}
|
||||
if (pinnedLeftContainer) {
|
||||
pinnedLeftContainer.scrollTo({ behavior: 'instant', top: offset });
|
||||
pinnedLeftContainer.scrollTo({ behavior, top: offset });
|
||||
}
|
||||
if (pinnedRightContainer) {
|
||||
pinnedRightContainer.scrollTo({ behavior: 'instant', top: offset });
|
||||
pinnedRightContainer.scrollTo({ behavior, top: offset });
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -781,11 +783,80 @@ export const ItemTableList = ({
|
||||
);
|
||||
|
||||
const scrollToTableIndex = useCallback(
|
||||
(index: number) => {
|
||||
const offset = calculateScrollTopForIndex(index);
|
||||
(index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||
const mainContainer = rowRef.current?.childNodes[0] as HTMLDivElement | undefined;
|
||||
if (!mainContainer) return;
|
||||
|
||||
const viewportHeight = mainContainer.clientHeight;
|
||||
const align = options?.align || 'top';
|
||||
|
||||
// Calculate the base scroll offset (top of the row)
|
||||
let offset = calculateScrollTopForIndex(index);
|
||||
|
||||
// Calculate row height for the target index
|
||||
const adjustedIndex = enableHeader ? Math.max(0, index - 1) : index;
|
||||
const mockCellProps: TableItemProps = {
|
||||
cellPadding,
|
||||
columns: parsedColumns,
|
||||
controls: {} as ItemControls,
|
||||
data: enableHeader ? [null, ...data] : data,
|
||||
enableAlternateRowColors,
|
||||
enableExpansion,
|
||||
enableHeader,
|
||||
enableHorizontalBorders,
|
||||
enableRowHoverHighlight,
|
||||
enableSelection,
|
||||
enableVerticalBorders,
|
||||
getRowHeight: () => DEFAULT_ROW_HEIGHT,
|
||||
internalState: {} as ItemListStateActions,
|
||||
itemType,
|
||||
playerContext,
|
||||
size,
|
||||
tableId,
|
||||
};
|
||||
|
||||
let targetRowHeight: number;
|
||||
if (typeof rowHeight === 'number') {
|
||||
targetRowHeight = rowHeight;
|
||||
} else if (typeof rowHeight === 'function') {
|
||||
targetRowHeight = rowHeight(adjustedIndex, mockCellProps);
|
||||
} else {
|
||||
targetRowHeight = DEFAULT_ROW_HEIGHT;
|
||||
}
|
||||
|
||||
// Adjust offset based on alignment
|
||||
if (align === 'center') {
|
||||
offset = offset - viewportHeight / 2 + targetRowHeight / 2;
|
||||
} else if (align === 'bottom') {
|
||||
offset = offset - viewportHeight + targetRowHeight;
|
||||
}
|
||||
// 'top' uses the base offset
|
||||
|
||||
// Ensure offset is not negative
|
||||
offset = Math.max(0, offset);
|
||||
|
||||
scrollToTableOffset(offset);
|
||||
},
|
||||
[calculateScrollTopForIndex, scrollToTableOffset],
|
||||
[
|
||||
calculateScrollTopForIndex,
|
||||
scrollToTableOffset,
|
||||
enableHeader,
|
||||
cellPadding,
|
||||
parsedColumns,
|
||||
data,
|
||||
enableAlternateRowColors,
|
||||
enableExpansion,
|
||||
enableHorizontalBorders,
|
||||
enableRowHoverHighlight,
|
||||
enableSelection,
|
||||
enableVerticalBorders,
|
||||
itemType,
|
||||
playerContext,
|
||||
size,
|
||||
tableId,
|
||||
DEFAULT_ROW_HEIGHT,
|
||||
rowHeight,
|
||||
],
|
||||
);
|
||||
|
||||
const [initialize] = useOverlayScrollbars({
|
||||
@@ -1280,8 +1351,8 @@ export const ItemTableList = ({
|
||||
const imperativeHandle: ItemListHandle = useMemo(() => {
|
||||
return {
|
||||
internalState,
|
||||
scrollToIndex: (index: number) => {
|
||||
scrollToTableIndex(enableHeader ? index + 1 : index);
|
||||
scrollToIndex: (index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||
scrollToTableIndex(enableHeader ? index + 1 : index, options);
|
||||
},
|
||||
scrollToOffset: (offset: number) => {
|
||||
scrollToTableOffset(offset);
|
||||
|
||||
@@ -54,7 +54,10 @@ export interface ItemListGridComponentProps<TQuery> extends ItemListComponentPro
|
||||
|
||||
export interface ItemListHandle {
|
||||
internalState: ItemListStateActions;
|
||||
scrollToIndex: (index: number, options?: { behavior?: 'auto' | 'smooth' }) => void;
|
||||
scrollToIndex: (
|
||||
index: number,
|
||||
options?: { align?: 'top' | 'bottom' | 'center'; behavior?: 'auto' | 'smooth' },
|
||||
) => void;
|
||||
scrollToOffset: (offset: number, options?: { behavior?: 'auto' | 'smooth' }) => void;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user