UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

121 lines (116 loc) 4.42 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import _toArray from "@babel/runtime/helpers/toArray"; import { useState, useCallback, useMemo } from 'react'; import get from 'lodash/get'; import isEqual from 'lodash/isEqual'; import { usePluginStateEffect } from '../usePluginStateEffect'; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any /** * This is designed to iterate through an object to get the path of its result * based on separation via "." * * Example: * ```typescript * type Test = { deepObject: { value: number } }; * // Type should be `"deepObject" | "deepObject.value"` * type Result = NestedKeys<Test>; * ``` */ /** * This is designed to iterate through a path of an object to get the type of its result * based on separation via "." * * Example: * ```typescript * type Test = { deepObject: { value: number } } * // Type should be `number` * type Result = Path<Test, 'deepObject.value'> * ``` */ /** * * ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️ * If the plugins you are listening to generate multiple shared states while the user is typing, * your React Component will get only the last one. * * Used to return the current plugin state of input dependencies. * It will recursively retrieve a slice of the state using a "." to separate * parts of the state. * * Example: * * ```typescript * const pluginA: NextEditorPlugin< 'pluginA', { sharedState: { deepObj: { value: number | undefined } }; } > * ``` * You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value * * Example in plugin: * * ```typescript * function ExampleContent({ api }: Props) { * const title = useSharedPluginStateSelector(api, 'dog.title') * return <p>{ title } { exampleState.description }</p> * } * * const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => { * return { * name: 'example', * contentComponent: () => <ExampleContent api={api} /> * } * } * ``` * * NOTE: If you pass an invalid path, `undefined` will be returned * * @param api * @param plugin * @returns */ export function useSharedPluginStateSelector(api, plugin) { var transformer = useCallback(function (pluginState) { var _plugin$split = plugin.split('.'), _plugin$split2 = _toArray(_plugin$split), pluginName = _plugin$split2[0], properties = _plugin$split2.slice(1); if (!pluginState || (properties === null || properties === void 0 ? void 0 : properties.length) === 0) { return undefined; } return get(pluginState === null || pluginState === void 0 ? void 0 : pluginState["".concat(pluginName, "State")], properties); }, [plugin]); var pluginNameArray = useMemo(function () { var _plugin$split3 = plugin.split('.'), _plugin$split4 = _slicedToArray(_plugin$split3, 1), pluginName = _plugin$split4[0]; return [pluginName]; }, [plugin]); var initialState = useMemo(function () { var _api$pluginName; var _plugin$split5 = plugin.split('.'), _plugin$split6 = _slicedToArray(_plugin$split5, 1), pluginName = _plugin$split6[0]; return transformer(_defineProperty({}, "".concat(pluginName, "State"), api === null || api === void 0 || (_api$pluginName = api[pluginName]) === null || _api$pluginName === void 0 ? void 0 : _api$pluginName.sharedState.currentState())); }, [plugin, api, transformer]); return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer, initialState); } // eslint-disable-next-line @typescript-eslint/max-params function useSharedPluginStateSelectorInternal(api, plugins, transformer, initialState) { var _useState = useState(initialState), _useState2 = _slicedToArray(_useState, 2), selectedPluginState = _useState2[0], setSelectedPluginState = _useState2[1]; usePluginStateEffect(api, plugins, function (pluginStates) { // `pluginStates`: This is the same type through inference - but typescript doesn't recognise them as they are computed slightly differently var transformedValue = transformer(pluginStates); if (!isEqual(transformedValue, selectedPluginState)) { setSelectedPluginState(transformedValue); } }); return selectedPluginState; }