@yandex/ui
Version:
Yandex UI components
86 lines (85 loc) • 3.55 kB
JavaScript
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';