Files
supabase/packages/ui-patterns/CommandMenu/api/hooks/commandsHooks.ts
Charis 1b89fa0b5c feat: command menu v2 ui components (#27761)
Co-authored-by: Francesco Sansalvadore <f.sansalvadore@gmail.com>
2024-07-16 14:14:03 -04:00

70 lines
2.1 KiB
TypeScript

'use client'
import { isEqual } from 'lodash'
import { useEffect, useMemo, useRef } from 'react'
import { useSnapshot } from 'valtio'
import type { ICommand, CommandOptions } from '../types'
import { useCommandContext } from '../../internal/Context'
import { useCurrentPage } from './pagesHooks'
import { PageDefinition, isCommandsPage } from '../../internal/state/pagesState'
const useCommands = () => {
const { commandsState } = useCommandContext()
const { commandSections } = useSnapshot(commandsState)
const _currPage = useCurrentPage()
const currPage = _currPage as PageDefinition
if (currPage && isCommandsPage(currPage)) return currPage.sections
return commandSections
}
const useRegisterCommands = (
sectionName: string,
commands: ICommand[],
options: CommandOptions = {}
) => {
const { commandsState } = useCommandContext()
const { registerSection } = useSnapshot(commandsState)
const prevDeps = useRef(options?.deps)
options.enabled ??= true
const prevEnabled = useRef<boolean | undefined>(options.enabled)
const unsubscribe = useRef<() => void>()
/**
* useEffect handles the registration on first render, since React runs the
* first render twice in development. (Otherwise the first render would leave
* a dangling subscription.)
*
* It also handles final cleanup, since useMemo can't do this.
*
* useMemo handles the registration on subsequent renders, to ensure it
* happens synchronously.
*/
useMemo(() => {
if (!isEqual(prevDeps.current, options.deps) || prevEnabled.current !== options.enabled) {
unsubscribe.current?.()
unsubscribe.current = options.enabled
? registerSection(sectionName, commands, options)
: undefined
prevDeps.current = options.deps
prevEnabled.current = options.enabled
}
}, [registerSection, sectionName, commands, options])
useEffect(() => {
unsubscribe.current = options.enabled
? registerSection(sectionName, commands, options)
: undefined
return () => unsubscribe.current?.()
}, [])
}
export { useCommands, useRegisterCommands }