Initial commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
import { createContext, useCallback, useContext, useMemo, useState } from "react";
|
||||
|
||||
type Ctx = {
|
||||
ids: Set<number>;
|
||||
has: (id: number) => boolean;
|
||||
toggle: (id: number) => void;
|
||||
selectMany: (ids: number[]) => void;
|
||||
setMany: (ids: number[]) => void;
|
||||
selectRangeTo: (id: number, orderedIds: number[]) => void;
|
||||
clear: () => void;
|
||||
lastClickedId: number | null;
|
||||
};
|
||||
|
||||
const ActressSelectCtx = createContext<Ctx | null>(null);
|
||||
|
||||
export function ActressSelectionProvider({ children }: { children: React.ReactNode }) {
|
||||
const [ids, setIds] = useState<Set<number>>(new Set());
|
||||
const [lastClickedId, setLastClickedId] = useState<number | null>(null);
|
||||
|
||||
const toggle = useCallback((id: number) => {
|
||||
setIds((cur) => {
|
||||
const next = new Set(cur);
|
||||
if (next.has(id)) next.delete(id); else next.add(id);
|
||||
return next;
|
||||
});
|
||||
setLastClickedId(id);
|
||||
}, []);
|
||||
|
||||
const selectMany = useCallback((newIds: number[]) => {
|
||||
setIds((cur) => {
|
||||
const next = new Set(cur);
|
||||
newIds.forEach((i) => next.add(i));
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setMany = useCallback((newIds: number[]) => {
|
||||
setIds(new Set(newIds));
|
||||
}, []);
|
||||
|
||||
const selectRangeTo = useCallback((id: number, orderedIds: number[]) => {
|
||||
const last = lastClickedId;
|
||||
if (last == null) {
|
||||
setIds((cur) => {
|
||||
const next = new Set(cur);
|
||||
next.add(id);
|
||||
return next;
|
||||
});
|
||||
setLastClickedId(id);
|
||||
return;
|
||||
}
|
||||
const a = orderedIds.indexOf(last);
|
||||
const b = orderedIds.indexOf(id);
|
||||
if (a === -1 || b === -1) {
|
||||
setIds((cur) => {
|
||||
const next = new Set(cur);
|
||||
next.add(id);
|
||||
return next;
|
||||
});
|
||||
setLastClickedId(id);
|
||||
return;
|
||||
}
|
||||
const [start, end] = a < b ? [a, b] : [b, a];
|
||||
const range = orderedIds.slice(start, end + 1);
|
||||
setIds((cur) => {
|
||||
const next = new Set(cur);
|
||||
range.forEach((i) => next.add(i));
|
||||
return next;
|
||||
});
|
||||
setLastClickedId(id);
|
||||
}, [lastClickedId]);
|
||||
|
||||
const clear = useCallback(() => {
|
||||
setIds(new Set());
|
||||
setLastClickedId(null);
|
||||
}, []);
|
||||
|
||||
const value = useMemo<Ctx>(() => ({
|
||||
ids,
|
||||
has: (id) => ids.has(id),
|
||||
toggle,
|
||||
selectMany,
|
||||
setMany,
|
||||
selectRangeTo,
|
||||
clear,
|
||||
lastClickedId,
|
||||
}), [ids, toggle, selectMany, setMany, selectRangeTo, clear, lastClickedId]);
|
||||
|
||||
return <ActressSelectCtx.Provider value={value}>{children}</ActressSelectCtx.Provider>;
|
||||
}
|
||||
|
||||
export function useActressSelection() {
|
||||
const ctx = useContext(ActressSelectCtx);
|
||||
if (!ctx) throw new Error("useActressSelection must be used within ActressSelectionProvider");
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user