@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
138 lines (134 loc) • 5.39 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useSharedPluginStateSelector = useSharedPluginStateSelector;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
var _react = require("react");
var _get = _interopRequireDefault(require("lodash/get"));
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
var _usePluginStateEffect = require("../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'>
* ```
*/
/**
*
* NOTE: Generally you want to use `useSharedPluginStateWithSelector` over this which behaves similarly
* but selects a slice of the state which is more performant.
*
* ⚠️⚠️⚠️ 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
* @param options
* @returns
*/
function useSharedPluginStateSelector(api, plugin) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var transformer = (0, _react.useCallback)(function (pluginState) {
var _plugin$split = plugin.split('.'),
_plugin$split2 = (0, _toArray2.default)(_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 (0, _get.default)(pluginState === null || pluginState === void 0 ? void 0 : pluginState["".concat(pluginName, "State")], properties);
}, [plugin]);
var pluginNameArray = (0, _react.useMemo)(function () {
var _plugin$split3 = plugin.split('.'),
_plugin$split4 = (0, _slicedToArray2.default)(_plugin$split3, 1),
pluginName = _plugin$split4[0];
return [pluginName];
}, [plugin]);
var initialState = (0, _react.useMemo)(function () {
var _api$pluginName;
if (options.disabled) {
return;
}
var _plugin$split5 = plugin.split('.'),
_plugin$split6 = (0, _slicedToArray2.default)(_plugin$split5, 1),
pluginName = _plugin$split6[0];
return transformer((0, _defineProperty2.default)({}, "".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, options.disabled, transformer]);
return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer, initialState, options);
}
function useSharedPluginStateSelectorInternal(api, plugins, transformer, initialState) {
var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
var _useState = (0, _react.useState)(function () {
return initialState;
}),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
selectedPluginState = _useState2[0],
setSelectedPluginState = _useState2[1];
(0, _usePluginStateEffect.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 (!(0, _isEqual.default)(transformedValue, selectedPluginState)) {
setSelectedPluginState(function () {
return transformedValue;
});
}
}, options);
return selectedPluginState;
}