import type { Fn } from '../@aileron/declare/index.js'; import type { ModalNode } from '../core/index.js'; /** * Hook that counts the number of active modals based on a validation function. * * Provides a reactive count of modals that match specific criteria. By default, * counts visible modals, but can be customized with any validation logic. * Useful for managing overlays, z-index stacking, or conditional UI based on modal count. * * @param validate - Function to determine if a modal should be counted (default: checks visibility) * @param refreshKey - Optional key to force recalculation when changed * @returns Number of modals that pass the validation * * @example * Basic usage - count visible modals: * ```tsx * function ModalOverlay() { * const activeCount = useActiveModalCount(); * * if (activeCount === 0) return null; * * return ( *
* ); * } * ``` * * @example * Count modals by type: * ```tsx * function ModalStats() { * const alertCount = useActiveModalCount( * (modal) => modal?.type === 'alert' && modal.visible * ); * * const confirmCount = useActiveModalCount( * (modal) => modal?.type === 'confirm' && modal.visible * ); * * const promptCount = useActiveModalCount( * (modal) => modal?.type === 'prompt' && modal.visible * ); * * return ( *
*

Alerts: {alertCount}

*

Confirms: {confirmCount}

*

Prompts: {promptCount}

*
* ); * } * ``` * * @example * Prevent interactions when modals are active: * ```tsx * function App() { * const hasActiveModals = useActiveModalCount() > 0; * * return ( *
* *
* // Main content *
*
* ); * } * ``` * * @example * Count alive modals (including hidden ones): * ```tsx * function ModalMemoryMonitor() { * const aliveCount = useActiveModalCount( * (modal) => modal?.alive === true * ); * * const hiddenCount = useActiveModalCount( * (modal) => modal?.alive && !modal.visible * ); * * return ( *
*

Total alive modals: {aliveCount}

*

Hidden (animating out): {hiddenCount}

* *
* ); * } * ``` * * @example * Dynamic refresh with dependencies: * ```tsx * function FilteredModalCount({ filter }) { * const [refreshKey, setRefreshKey] = useState(0); * * // Count modals matching dynamic filter * const count = useActiveModalCount( * (modal) => { * if (!modal?.visible) return false; * if (filter.type && modal.type !== filter.type) return false; * if (filter.group && modal.group !== filter.group) return false; * return true; * }, * refreshKey // Force recalculation when key changes * ); * * // Refresh count when filter changes * useEffect(() => { * setRefreshKey(prev => prev + 1); * }, [filter]); * * return
Matching modals: {count}
; * } * ``` * * @example * Limit modal stacking: * ```tsx * function LimitedModalProvider({ children, maxModals = 3 }) { * const activeCount = useActiveModalCount(); * * const openModal = useCallback((modalConfig) => { * if (activeCount >= maxModals) { * alert({ * title: 'Too Many Modals', * content: `Maximum of ${maxModals} modals can be open at once.`, * subtype: 'warning', * }); * return Promise.reject(new Error('Modal limit exceeded')); * } * * return originalOpenModal(modalConfig); * }, [activeCount, maxModals]); * * return ( * * {children} * * ); * } * ``` * * @remarks * - Recalculates whenever modal list changes or refreshKey updates * - Default validation counts visible modals only * - Custom validation can check any modal properties * - Efficient memoization prevents unnecessary recalculations * - Use refreshKey to force updates based on external dependencies */ export declare const useActiveModalCount: (validate?: Fn<[node?: ModalNode], boolean | undefined>, refreshKey?: string | number) => number;