UNPKG

@yandex/ui

Version:

Yandex UI components

86 lines (85 loc) 3.55 kB
import { __read, __spread } from "tslib"; import { useRef, createElement, useEffect } from 'react'; import { createGlobalState } from '../createGlobalState'; /** * Реакт-хук для создания компонента с возможностью переопределения. * * @example * const ElementOriginal = ({ children }) => <div>{children}</div> * * const MyComponent = ({ renderElement }) => { * const Element = useRenderOverride(ElementOriginal, renderElement) * return <Element /> * } */ export function useRenderOverride(component, render) { // Создаем глобальное состояние, чтобы иметь возможность // обновлять каждый инстанс переопределенного компонента. var useDeps = useRef(createGlobalState([component, render])).current; var _a = __read(useDeps(), 2), setDeps = _a[1]; // Используем useRef для кэширования функции, т.к. реакт // не гарантирует постоянную мемоизацию для useMemo/Callback. var renderer = useRef(function RenderOverride(props) { var _a = __read(useDeps(), 1), deps = _a[0]; var _b = __read(deps || [], 2), nextComponent = _b[0], nextRender = _b[1]; if (deps === undefined || nextRender === undefined) { return createElement(nextComponent, props); } return nextRender(props, nextComponent); }).current; useEffect(function () { setDeps([component, render]); }, [setDeps, component, render]); return renderer; } /** * Реакт-провайдер для создания компонента с возможностью переопределения. * * @example * const ElementOriginal = ({ children }) => <div>{children}</div> * * const MyComponent = ({ renderElement }) => { * <RenderOverrideProvider component={ElementOriginal} render={renderElement}> * {(Element) => <Element />} * </RenderOverrideProvider> * } */ export var RenderOverrideProvider = function (_a) { var children = _a.children, component = _a.component, render = _a.render; var renderer = useRenderOverride(component, render); return children(renderer); }; RenderOverrideProvider.displayName = 'RenderOverrideProvider'; /** * Реакт-провайдер для создания нескольких компонентов с возможностью переопределения. * * @example * const ElementOriginal1 = ({ children }) => <div>{children}</div> * const ElementOriginal2 = ({ children }) => <div>{children}</div> * * const MyComponent = ({ renderElement1, renderElement2 }) => { * <MultiRenderOverrideProvider * components={[ * [ElementOriginal2, renderElement1], * [ElementOriginal2, renderElement2], * ]} * > * {(Element1, Element2) => ( * <> * <Element1 /> * <Element2 /> * </> * )} * </MultiRenderOverrideProvider> * } */ export var MultiRenderOverrideProvider = function (_a) { var children = _a.children, components = _a.components; // eslint-disable-next-line react-hooks/rules-of-hooks var renderers = components.map(function (_a) { var _b = __read(_a, 2), component = _b[0], render = _b[1]; return useRenderOverride(component, render); }); return children.apply(void 0, __spread(renderers)); }; MultiRenderOverrideProvider.displayName = 'MultiRenderOverrideProvider';