@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
136 lines (135 loc) • 3.98 kB
JavaScript
import React, { useEffect, useRef, useState } from 'react';
import Loadable from 'react-loadable';
import { getContextualToolbarItemsFromModule } from '../extensions';
import { nodeToJSON } from '../utils';
import { DropdownMenuItem } from './DropdownMenuItem';
import { DropdownSeparator } from './DropdownSeparator';
const noop = () => null;
const isDefaultExport = mod => {
return mod.hasOwnProperty('default');
};
const resolveExtensionIcon = async getIcon => {
if (!getIcon) {
return noop;
}
const maybeIcon = await getIcon();
return isDefaultExport(maybeIcon) ? maybeIcon.default : maybeIcon;
};
const convertExtensionToDropdownMenuItem = ({
item,
disabled,
node,
extension,
IconComponent
}) => {
let title = '';
if (item.label) {
title = item.label;
} else if (typeof item.tooltip === 'string') {
title = item.tooltip;
} else if (item.ariaLabel) {
title = item.ariaLabel;
}
item.disabled = (disabled === null || disabled === void 0 ? void 0 : disabled(item.key)) || false;
const getIcon = () => {
const label = item.label || '';
return IconComponent ? /*#__PURE__*/React.createElement(IconComponent, {
label: label
}) : undefined;
};
return {
title,
icon: getIcon(),
disabled: item.disabled,
onClick: () => {
if (typeof item.action !== 'function') {
throw new Error(`'action' of context toolbar item '${item.key}' is not a function`);
}
const targetNodeAdf = nodeToJSON(node);
extension.extensionApi && item.action(targetNodeAdf, extension.extensionApi);
return true;
}
};
};
const DropdownMenuExtensionItem = ({
item,
editorView,
disabled,
node,
extension,
dropdownOptions
}) => {
// Use ref to keep icon component stable across renders
const iconRef = useRef(null);
if (!iconRef.current && item.icon) {
iconRef.current = Loadable({
loader: () => resolveExtensionIcon(item.icon),
loading: noop
});
}
const dropdownItem = convertExtensionToDropdownMenuItem({
item,
disabled,
node,
extension,
IconComponent: iconRef.current
});
if (!dropdownItem) {
return null;
}
return /*#__PURE__*/React.createElement(DropdownMenuItem, {
key: item.key,
item: dropdownItem,
editorView: editorView,
hide: dropdownOptions.hide,
dispatchCommand: dropdownOptions.dispatchCommand,
showSelected: dropdownOptions.showSelected,
intl: dropdownOptions.intl
});
};
export const DropdownMenuExtensionItems = props => {
const {
node,
editorView,
extension,
disabled,
dropdownOptions,
areAnyNewToolbarFlagsEnabled
} = props;
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [extensions, setExtensions] = useState([]);
useEffect(() => {
getExtensions();
async function getExtensions() {
const provider = await extension.extensionProvider;
if (provider) {
setExtensions(await provider.getExtensions());
}
}
}, [extension.extensionProvider]);
const nodeAdf = React.useMemo(() => nodeToJSON(node), [node]);
const extensionItems = React.useMemo(() => {
if (!extension.extensionApi) {
return [];
}
return getContextualToolbarItemsFromModule(extensions, nodeAdf, extension.extensionApi);
}, [extensions, nodeAdf, extension.extensionApi]);
if (!extensionItems.length || !dropdownOptions) {
return null;
}
return /*#__PURE__*/React.createElement(React.Fragment, null, extensionItems.map((item, _idx) => {
if (!('key' in item)) {
return null;
}
return /*#__PURE__*/React.createElement(DropdownMenuExtensionItem, {
key: item.key,
item: item,
editorView: editorView,
disabled: disabled,
node: node,
extension: extension,
dropdownOptions: dropdownOptions
});
}), areAnyNewToolbarFlagsEnabled && /*#__PURE__*/React.createElement(DropdownSeparator, null));
};