enforce data order in list selection

This commit is contained in:
jeffvli
2025-11-14 13:00:21 -08:00
parent da691fa978
commit af00110973
2 changed files with 52 additions and 20 deletions
@@ -8,7 +8,7 @@ import {
* Action creators for item grid state management
* These can be reused across different components and contexts
*/
export const itemGridActions = {
export const itemListActions = {
clearAll: (): ItemListAction => ({
type: 'CLEAR_ALL',
}),
@@ -71,7 +71,7 @@ export const itemGridActions = {
* Selector functions for item grid state
* These can be reused to extract specific data from state
*/
export const itemGridSelectors = {
export const itemListSelectors = {
getDragging: (state: ItemListState): unknown[] => {
return Array.from(state.draggingItems.values());
},
@@ -179,8 +179,8 @@ export const itemListUtils = {
return rowId ? currentState.expanded.has(rowId) : false;
});
return allExpanded
? itemGridActions.clearExpanded()
: itemGridActions.setExpanded(items, extractRowId);
? itemListActions.clearExpanded()
: itemListActions.setExpanded(items, extractRowId);
},
/**
@@ -196,7 +196,7 @@ export const itemListUtils = {
return rowId ? currentState.selected.has(rowId) : false;
});
return allSelected
? itemGridActions.clearSelected()
: itemGridActions.setSelected(items, extractRowId);
? itemListActions.clearSelected()
: itemListActions.setSelected(items, extractRowId);
},
};
@@ -1,8 +1,36 @@
import { useCallback, useMemo, useReducer } from 'react';
import { itemGridSelectors } from '/@/renderer/components/item-list/helpers/item-list-reducer-utils';
import { itemListSelectors } from '/@/renderer/components/item-list/helpers/item-list-reducer-utils';
import { LibraryItem } from '/@/shared/types/domain-types';
const sortByDataOrder = <T>(
items: T[],
data: unknown[],
extractRowId: (item: unknown) => string | undefined,
isIdArray: boolean,
): T[] => {
const rowIdToIndex = new Map<string, number>();
// Create a map of rowId to index in the data array
data.forEach((item, index) => {
if (item && typeof item === 'object') {
const itemRowId = extractRowId(item);
if (itemRowId) {
rowIdToIndex.set(itemRowId, index);
}
}
});
// Sort items by their index in the data array (create new array to avoid mutation)
return [...items].sort((a, b) => {
const rowIdA = isIdArray ? (a as string) : extractRowId(a as unknown);
const rowIdB = isIdArray ? (b as string) : extractRowId(b as unknown);
const indexA = rowIdA ? (rowIdToIndex.get(rowIdA) ?? Infinity) : Infinity;
const indexB = rowIdB ? (rowIdToIndex.get(rowIdB) ?? Infinity) : Infinity;
return indexA - indexB;
});
};
export type ItemListAction =
| {
extractRowId: (item: unknown) => string | undefined;
@@ -330,29 +358,31 @@ export const useItemListState = (
const isExpanded = useCallback(
(rowId: string) => {
return itemGridSelectors.isExpanded(state, rowId);
return itemListSelectors.isExpanded(state, rowId);
},
[state],
);
const isSelected = useCallback(
(rowId: string) => {
return itemGridSelectors.isSelected(state, rowId);
return itemListSelectors.isSelected(state, rowId);
},
[state],
);
const getExpanded = useCallback(() => {
return itemGridSelectors.getExpanded(state);
return itemListSelectors.getExpanded(state);
}, [state]);
const getDragging = useCallback(() => {
return itemGridSelectors.getDragging(state);
return itemListSelectors.getDragging(state);
}, [state]);
const getSelected = useCallback(() => {
return itemGridSelectors.getSelected(state);
}, [state]);
const selectedItems = itemListSelectors.getSelected(state);
const data = getDataFn ? getDataFn() : [];
return sortByDataOrder(selectedItems, data, extractRowIdFn, false);
}, [state, getDataFn, extractRowIdFn]);
const getDraggingIds = useCallback(() => {
return Array.from(state.dragging);
@@ -363,8 +393,10 @@ export const useItemListState = (
}, [state.expanded]);
const getSelectedIds = useCallback(() => {
return Array.from(state.selected);
}, [state.selected]);
const selectedIds = Array.from(state.selected);
const data = getDataFn ? getDataFn() : [];
return sortByDataOrder(selectedIds, data, extractRowIdFn, true);
}, [state.selected, getDataFn, extractRowIdFn]);
const clearExpanded = useCallback(() => {
dispatch({ type: 'CLEAR_EXPANDED' });
@@ -383,24 +415,24 @@ export const useItemListState = (
}, []);
const getVersion = useCallback(() => {
return itemGridSelectors.getVersion(state);
return itemListSelectors.getVersion(state);
}, [state]);
const hasExpanded = useCallback(() => {
return itemGridSelectors.hasAnyExpanded(state);
return itemListSelectors.hasAnyExpanded(state);
}, [state]);
const hasDragging = useCallback(() => {
return itemGridSelectors.hasAnyDragging(state);
return itemListSelectors.hasAnyDragging(state);
}, [state]);
const hasSelected = useCallback(() => {
return itemGridSelectors.hasAnySelected(state);
return itemListSelectors.hasAnySelected(state);
}, [state]);
const isDragging = useCallback(
(rowId: string) => {
return itemGridSelectors.isDragging(state, rowId);
return itemListSelectors.isDragging(state, rowId);
},
[state],
);