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 (
*
* );
* };
*/
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}
);
};