@shopify/polaris
Version:
Shopify’s admin product component library
110 lines (99 loc) • 3.14 kB
text/typescript
import {useState, useCallback} from 'react';
export enum SelectionType {
All = 'all',
Page = 'page',
Multi = 'multi',
Single = 'single',
}
type Range = [number, number];
type ResourceIDResolver<T extends {[key: string]: unknown}> = (
resource: T,
) => string;
function defaultResourceIDResolver(resource: {[key: string]: any}): string {
if ('id' in resource) {
return resource.id;
}
throw new Error(
'Your resource does not directly contain an `id`. Pass a `resourceIDResolver` to `useIndexResourceState`',
);
}
export function useIndexResourceState<T extends {[key: string]: unknown}>(
resources: T[],
{
selectedResources: initSelectedResources = [],
allResourcesSelected: initAllResourcesSelected = false,
resourceIDResolver = defaultResourceIDResolver,
}: {
selectedResources?: string[];
allResourcesSelected?: boolean;
resourceIDResolver?: ResourceIDResolver<T>;
} = {
selectedResources: [],
allResourcesSelected: false,
resourceIDResolver: defaultResourceIDResolver,
},
) {
const [selectedResources, setSelectedResources] = useState(
initSelectedResources,
);
const [allResourcesSelected, setAllResourcesSelected] = useState(
initAllResourcesSelected,
);
const handleSelectionChange = useCallback(
(
selectionType: SelectionType,
isSelecting: boolean,
selection?: string | Range,
) => {
if (selectionType === SelectionType.All) {
setAllResourcesSelected(isSelecting);
} else if (allResourcesSelected) {
setAllResourcesSelected(false);
}
switch (selectionType) {
case SelectionType.Single:
setSelectedResources((newSelectedResources) =>
isSelecting
? [...newSelectedResources, selection as string]
: newSelectedResources.filter((id) => id !== selection),
);
break;
case SelectionType.All:
case SelectionType.Page:
setSelectedResources(
isSelecting ? resources.map(resourceIDResolver) : [],
);
break;
case SelectionType.Multi:
if (!selection) break;
setSelectedResources((newSelectedResources) => {
const ids: string[] = [];
for (let i = selection[0] as number; i <= selection[1]; i++) {
const id = resourceIDResolver(resources[i]);
if (
(isSelecting && !newSelectedResources.includes(id)) ||
(!isSelecting && newSelectedResources.includes(id))
) {
ids.push(id);
}
}
return isSelecting
? [...newSelectedResources, ...ids]
: newSelectedResources.filter((id) => !ids.includes(id));
});
break;
}
},
[allResourcesSelected, resources, resourceIDResolver],
);
const clearSelection = useCallback(() => {
setSelectedResources([]);
setAllResourcesSelected(false);
}, []);
return {
selectedResources,
allResourcesSelected,
handleSelectionChange,
clearSelection,
};
}