UNPKG

@wordpress/components

Version:
106 lines (99 loc) 4.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.useComponentsContext = exports.ContextSystemProvider = exports.ComponentsContext = void 0; var _deepmerge = _interopRequireDefault(require("deepmerge")); var _es = _interopRequireDefault(require("fast-deep-equal/es6")); var _isPlainObject = require("is-plain-object"); var _element = require("@wordpress/element"); var _warning = _interopRequireDefault(require("@wordpress/warning")); var _utils = require("../utils"); var _jsxRuntime = require("react/jsx-runtime"); /** * External dependencies */ /** * WordPress dependencies */ /** * Internal dependencies */ const ComponentsContext = exports.ComponentsContext = (0, _element.createContext)(/** @type {Record<string, any>} */{}); const useComponentsContext = () => (0, _element.useContext)(ComponentsContext); /** * Consolidates incoming ContextSystem values with a (potential) parent ContextSystem value. * * Note: This function will warn if it detects an un-memoized `value` * * @param {Object} props * @param {Record<string, any>} props.value * @return {Record<string, any>} The consolidated value. */ exports.useComponentsContext = useComponentsContext; function useContextSystemBridge({ value }) { const parentContext = useComponentsContext(); const valueRef = (0, _element.useRef)(value); (0, _utils.useUpdateEffect)(() => { if ( // Objects are equivalent. (0, _es.default)(valueRef.current, value) && // But not the same reference. valueRef.current !== value) { globalThis.SCRIPT_DEBUG === true ? (0, _warning.default)(`Please memoize your context: ${JSON.stringify(value)}`) : void 0; } }, [value]); // `parentContext` will always be memoized (i.e., the result of this hook itself) // or the default value from when the `ComponentsContext` was originally // initialized (which will never change, it's a static variable) // so this memoization will prevent `deepmerge()` from rerunning unless // the references to `value` change OR the `parentContext` has an actual material change // (because again, it's guaranteed to be memoized or a static reference to the empty object // so we know that the only changes for `parentContext` are material ones... i.e., why we // don't have to warn in the `useUpdateEffect` hook above for `parentContext` and we only // need to bother with the `value`). The `useUpdateEffect` above will ensure that we are // correctly warning when the `value` isn't being properly memoized. All of that to say // that this should be super safe to assume that `useMemo` will only run on actual // changes to the two dependencies, therefore saving us calls to `deepmerge()`! const config = (0, _element.useMemo)(() => { // Deep clone `parentContext` to avoid mutating it later. return (0, _deepmerge.default)(parentContext !== null && parentContext !== void 0 ? parentContext : {}, value !== null && value !== void 0 ? value : {}, { isMergeableObject: _isPlainObject.isPlainObject }); }, [parentContext, value]); return config; } /** * A Provider component that can modify props for connected components within * the Context system. * * @example * ```jsx * <ContextSystemProvider value={{ Button: { size: 'small' }}}> * <Button>...</Button> * </ContextSystemProvider> * ``` * * @template {Record<string, any>} T * @param {Object} options * @param {import('react').ReactNode} options.children Children to render. * @param {T} options.value Props to render into connected components. * @return {JSX.Element} A Provider wrapped component. */ const BaseContextSystemProvider = ({ children, value }) => { const contextValue = useContextSystemBridge({ value }); return /*#__PURE__*/(0, _jsxRuntime.jsx)(ComponentsContext.Provider, { value: contextValue, children: children }); }; const ContextSystemProvider = exports.ContextSystemProvider = (0, _element.memo)(BaseContextSystemProvider); //# sourceMappingURL=context-system-provider.js.map