mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 04:20:12 +02:00
add scrollToIndex alignment to lists
This commit is contained in:
@@ -360,10 +360,24 @@ export const ItemGridList = ({
|
|||||||
const controls = useDefaultItemListControls();
|
const controls = useDefaultItemListControls();
|
||||||
|
|
||||||
const scrollToIndex = useCallback(
|
const scrollToIndex = useCallback(
|
||||||
(index: number) => {
|
(
|
||||||
|
index: number,
|
||||||
|
options?: { align?: 'bottom' | 'center' | 'top'; behavior?: 'auto' | 'smooth' },
|
||||||
|
) => {
|
||||||
if (!listRef.current || !tableMeta) return;
|
if (!listRef.current || !tableMeta) return;
|
||||||
const row = Math.floor(index / tableMeta.columnCount);
|
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],
|
[tableMeta],
|
||||||
);
|
);
|
||||||
@@ -580,8 +594,8 @@ export const ItemGridList = ({
|
|||||||
const imperativeHandle: ItemListHandle = useMemo(() => {
|
const imperativeHandle: ItemListHandle = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
internalState,
|
internalState,
|
||||||
scrollToIndex: (index: number) => {
|
scrollToIndex: (index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||||
scrollToIndex(index);
|
scrollToIndex(index, options);
|
||||||
},
|
},
|
||||||
scrollToOffset: (offset: number) => {
|
scrollToOffset: (offset: number) => {
|
||||||
scrollToOffset(offset);
|
scrollToOffset(offset);
|
||||||
|
|||||||
@@ -703,14 +703,16 @@ export const ItemTableList = ({
|
|||||||
| HTMLDivElement
|
| HTMLDivElement
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
|
const behavior = 'instant';
|
||||||
|
|
||||||
if (mainContainer) {
|
if (mainContainer) {
|
||||||
mainContainer.scrollTo({ behavior: 'instant', top: offset });
|
mainContainer.scrollTo({ behavior, top: offset });
|
||||||
}
|
}
|
||||||
if (pinnedLeftContainer) {
|
if (pinnedLeftContainer) {
|
||||||
pinnedLeftContainer.scrollTo({ behavior: 'instant', top: offset });
|
pinnedLeftContainer.scrollTo({ behavior, top: offset });
|
||||||
}
|
}
|
||||||
if (pinnedRightContainer) {
|
if (pinnedRightContainer) {
|
||||||
pinnedRightContainer.scrollTo({ behavior: 'instant', top: offset });
|
pinnedRightContainer.scrollTo({ behavior, top: offset });
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -781,11 +783,80 @@ export const ItemTableList = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const scrollToTableIndex = useCallback(
|
const scrollToTableIndex = useCallback(
|
||||||
(index: number) => {
|
(index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||||
const offset = calculateScrollTopForIndex(index);
|
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);
|
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({
|
const [initialize] = useOverlayScrollbars({
|
||||||
@@ -1280,8 +1351,8 @@ export const ItemTableList = ({
|
|||||||
const imperativeHandle: ItemListHandle = useMemo(() => {
|
const imperativeHandle: ItemListHandle = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
internalState,
|
internalState,
|
||||||
scrollToIndex: (index: number) => {
|
scrollToIndex: (index: number, options?: { align?: 'bottom' | 'center' | 'top' }) => {
|
||||||
scrollToTableIndex(enableHeader ? index + 1 : index);
|
scrollToTableIndex(enableHeader ? index + 1 : index, options);
|
||||||
},
|
},
|
||||||
scrollToOffset: (offset: number) => {
|
scrollToOffset: (offset: number) => {
|
||||||
scrollToTableOffset(offset);
|
scrollToTableOffset(offset);
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ export interface ItemListGridComponentProps<TQuery> extends ItemListComponentPro
|
|||||||
|
|
||||||
export interface ItemListHandle {
|
export interface ItemListHandle {
|
||||||
internalState: ItemListStateActions;
|
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;
|
scrollToOffset: (offset: number, options?: { behavior?: 'auto' | 'smooth' }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user