mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-25 19:01:14 +01:00
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import type { WritableAtom } from 'jotai';
|
|
import { useAtomValue, useStore } from 'jotai';
|
|
import { selectAtom } from 'jotai/utils';
|
|
import { createContext, useCallback, useContext, useMemo } from 'react';
|
|
|
|
type CollapsedMap = Record<string, boolean>;
|
|
type SetAction = CollapsedMap | ((prev: CollapsedMap) => CollapsedMap);
|
|
export type CollapsedAtom = WritableAtom<CollapsedMap, [SetAction], void>;
|
|
|
|
export const CollapsedAtomContext = createContext<CollapsedAtom | null>(null);
|
|
|
|
export function useCollapsedAtom(): CollapsedAtom {
|
|
const atom = useContext(CollapsedAtomContext);
|
|
if (!atom) throw new Error('CollapsedAtomContext not provided');
|
|
return atom;
|
|
}
|
|
|
|
export function useIsCollapsed(itemId: string | undefined) {
|
|
const collapsedAtom = useCollapsedAtom();
|
|
const derivedAtom = useMemo(
|
|
() => selectAtom(collapsedAtom, (map) => !!map[itemId ?? 'n/a'], Object.is),
|
|
[collapsedAtom, itemId],
|
|
);
|
|
return useAtomValue(derivedAtom);
|
|
}
|
|
|
|
export function useSetCollapsed(itemId: string | undefined) {
|
|
const collapsedAtom = useCollapsedAtom();
|
|
const store = useStore();
|
|
return useCallback(
|
|
(next: boolean | ((prev: boolean) => boolean)) => {
|
|
const key = itemId ?? 'n/a';
|
|
const prevMap = store.get(collapsedAtom);
|
|
const prevValue = !!prevMap[key];
|
|
const value = typeof next === 'function' ? next(prevValue) : next;
|
|
if (value === prevValue) return;
|
|
store.set(collapsedAtom, { ...prevMap, [key]: value });
|
|
},
|
|
[collapsedAtom, itemId, store],
|
|
);
|
|
}
|
|
|
|
export function useCollapsedMap() {
|
|
const collapsedAtom = useCollapsedAtom();
|
|
return useAtomValue(collapsedAtom);
|
|
}
|
|
|
|
export function useIsAncestorCollapsed(ancestorIds: string[]) {
|
|
const collapsedAtom = useCollapsedAtom();
|
|
const derivedAtom = useMemo(
|
|
() =>
|
|
selectAtom(
|
|
collapsedAtom,
|
|
(collapsed) => ancestorIds.some((id) => collapsed[id]),
|
|
(a, b) => a === b,
|
|
),
|
|
[collapsedAtom, ancestorIds],
|
|
);
|
|
return useAtomValue(derivedAtom);
|
|
}
|