import * as React from 'react'; import { createContext, useCallback, useState, useMemo } from 'react'; import isEqual from 'lodash/isEqual'; import { ResourceDefinition } from '../types'; export type ResourceDefinitions = { [name: string]: ResourceDefinition; }; export type ResourceDefinitionContextValue = { definitions: ResourceDefinitions; register: (config: ResourceDefinition) => void; unregister: (config: ResourceDefinition) => void; }; export const ResourceDefinitionContext = createContext< ResourceDefinitionContextValue >({ definitions: {}, register: () => {}, unregister: () => {}, }); /** * Context to store the current resource Definition. * * Use the useResourceDefinition() hook to read the context. * * @example * * import { useResourceDefinition, useTranslate } from 'ra-core'; * * const PostMenuItem = () => { * const { name, icon } = useResourceDefinition({ resource: 'posts' }); * * return ( * * {icon} * {name} * * ); * }; */ export const ResourceDefinitionContextProvider = ({ definitions: defaultDefinitions = {}, children, }: { definitions?: ResourceDefinitions; children: React.ReactNode; }) => { const [definitions, setState] = useState( defaultDefinitions ); const register = useCallback((config: ResourceDefinition) => { setState(prev => isEqual(prev[config.name], config) ? prev : { ...prev, [config.name]: config, } ); }, []); const unregister = useCallback((config: ResourceDefinition) => { setState(prev => { const { [config.name]: _, ...rest } = prev; return rest; }); }, []); const contextValue = useMemo( () => ({ definitions, register, unregister }), [definitions] // eslint-disable-line react-hooks/exhaustive-deps ); return ( {children} ); };