UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

76 lines (75 loc) • 2.66 kB
import { useSyncExternalStore } from "react"; //#region src/base-ui/FocusScope/store.ts let state = { activeScopeId: null, knownScopes: /* @__PURE__ */ new Map(), lastFocusedItem: /* @__PURE__ */ new Map() }; const listeners = /* @__PURE__ */ new Set(); const setState = (patch) => { state = { ...state, ...patch }; listeners.forEach((listener) => listener()); }; const subscribe = (listener) => { listeners.add(listener); return () => listeners.delete(listener); }; const getActiveScopeId = () => state.activeScopeId; const setActiveScope = (id) => { if (id !== null && !state.knownScopes.has(id)) return; if (state.activeScopeId === id) return; setState({ activeScopeId: id }); }; const getLastFocusedItem = (scopeId) => state.lastFocusedItem.get(scopeId) ?? null; const setLastFocusedItem = (scopeId, itemId) => { if ((state.lastFocusedItem.get(scopeId) ?? null) === itemId) return; const next = new Map(state.lastFocusedItem); if (itemId === null) next.delete(scopeId); else next.set(scopeId, itemId); setState({ lastFocusedItem: next }); }; const findScopeId = (event) => { return (event.target instanceof Element ? event.target : null)?.closest("[data-focus-scope]")?.dataset.focusScope ?? null; }; const onGlobalInteract = (event) => { const id = findScopeId(event); if (id !== null) setActiveScope(id); }; let listening = false; const ensureDocumentListeners = () => { if (listening || typeof document === "undefined") return; listening = true; document.addEventListener("pointerdown", onGlobalInteract, true); document.addEventListener("focusin", onGlobalInteract, true); }; const registerScope = (id) => { ensureDocumentListeners(); const next = new Map(state.knownScopes); next.set(id, (next.get(id) ?? 0) + 1); setState({ knownScopes: next }); return () => { const count = state.knownScopes.get(id) ?? 0; const scopes = new Map(state.knownScopes); if (count > 1) { scopes.set(id, count - 1); setState({ knownScopes: scopes }); return; } scopes.delete(id); const lastFocused = new Map(state.lastFocusedItem); lastFocused.delete(id); setState({ activeScopeId: state.activeScopeId === id ? null : state.activeScopeId, knownScopes: scopes, lastFocusedItem: lastFocused }); }; }; const useActiveScopeId = () => useSyncExternalStore(subscribe, getActiveScopeId, () => null); const useFocusScopeActive = (id) => useSyncExternalStore(subscribe, () => state.activeScopeId === id, () => false); //#endregion export { getActiveScopeId, getLastFocusedItem, registerScope, setActiveScope, setLastFocusedItem, subscribe, useActiveScopeId, useFocusScopeActive }; //# sourceMappingURL=store.mjs.map