@atlaskit/editor-plugin-insert-block
Version:
Insert block plugin for @atlaskit/editor-core
125 lines • 5.28 kB
JavaScript
import React, { useCallback, useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import { isOfflineMode } from '@atlaskit/editor-common/connectivity/isOfflineMode';
import { getAriaKeyshortcuts, insertElements, ToolTipContent } from '@atlaskit/editor-common/keymaps';
import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages/insert-block';
import Popup from '@atlaskit/editor-common/Popup';
import { useMenuPopupSizing } from '@atlaskit/editor-common/quick-insert/use-menu-popup-sizing';
import { useEditorToolbar } from '@atlaskit/editor-common/toolbar/context';
import { TOOLBAR_BUTTON_TEST_ID } from '@atlaskit/editor-common/toolbar/keys';
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/useSharedPluginStateWithSelector';
import { akEditorMenuZIndex } from '@atlaskit/editor-shared-styles/constants';
import { AddIcon } from '@atlaskit/editor-toolbar/add-icon';
import { ToolbarButton } from '@atlaskit/editor-toolbar/toolbar-button';
import { ToolbarTooltip } from '@atlaskit/editor-toolbar/toolbar-tooltip';
import { useToolbarUI } from '@atlaskit/editor-toolbar/ui-context';
import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
import { RegisteredInsertMenuContent } from './RegisteredInsertMenuContent';
const DEFAULT_MENU_MAX_HEIGHT = 520;
const POPUP_OFFSET = [0, 3];
/**
* The toolbar owns its popup lifecycle, but renders the same registered items
* and menu model as slash command.
*/
export const RegisteredInsertButton = ({
api
}) => {
const {
editorView
} = useEditorToolbar();
const isOptimistic = isExperimentEnabled('platform_editor_ssr_toolbar_optimistic');
const {
formatMessage
} = useIntl();
const {
isDisabled,
popupsBoundariesElement,
popupsMountPoint,
popupsScrollableElement
} = useToolbarUI();
const [isOpen, setIsOpen] = useState(false);
const buttonRef = useRef(null);
const menuHeight = useMenuPopupSizing({
target: buttonRef.current,
boundariesElement: popupsBoundariesElement,
scrollableElement: popupsScrollableElement,
maxHeight: DEFAULT_MENU_MAX_HEIGHT,
offset: POPUP_OFFSET[1],
isOpen
});
const {
connectivityMode,
isAllowed
} = useSharedPluginStateWithSelector(api, ['connectivity', 'typeAhead'], states => {
var _states$connectivityS, _states$typeAheadStat;
return {
connectivityMode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode,
isAllowed: (_states$typeAheadStat = states.typeAheadState) === null || _states$typeAheadStat === void 0 ? void 0 : _states$typeAheadStat.isAllowed
};
});
const close = useCallback((restoreFocus = false) => {
setIsOpen(false);
if (restoreFocus) {
requestAnimationFrame(() => {
var _buttonRef$current;
return (_buttonRef$current = buttonRef.current) === null || _buttonRef$current === void 0 ? void 0 : _buttonRef$current.focus();
});
}
}, []);
const open = useCallback(() => {
// Early clicks must not queue a popup to open when the editor becomes ready.
if (!editorView) {
return;
}
setIsOpen(true);
}, [editorView]);
const onPopupUnmount = useCallback(() => {
// Outside dismissal must not move focus away from the element that was clicked.
setIsOpen(false);
}, []);
const closeAndRestoreFocus = useCallback(() => close(true), [close]);
const closeForSelection = useCallback(() => close(false), [close]);
if (!(api !== null && api !== void 0 && api.insertBlock) || !editorView && !isOptimistic) {
return null;
}
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ToolbarTooltip, {
content: /*#__PURE__*/React.createElement(ToolTipContent, {
description: formatMessage(messages.insertMenu),
keymap: insertElements
})
}, /*#__PURE__*/React.createElement(ToolbarButton, {
ariaKeyshortcuts: getAriaKeyshortcuts(insertElements),
iconBefore: /*#__PURE__*/React.createElement(AddIcon, {
size: "small",
label: formatMessage(messages.insertMenu)
})
// Keep the optimistic SSR button visible before the live view is attached.
,
isDisabled: isDisabled || (!isOptimistic || !!editorView) && !isAllowed,
isSelected: isOpen,
onClick: isOpen ? () => close(true) : open,
ref: buttonRef,
testId: TOOLBAR_BUTTON_TEST_ID.INSERT
})), isOpen && buttonRef.current && editorView && /*#__PURE__*/React.createElement(Popup, {
alignX: "right",
boundariesElement: popupsBoundariesElement,
fitHeight: menuHeight,
fitWidth: 350,
mountTo: popupsMountPoint,
offset: POPUP_OFFSET,
onUnmount: onPopupUnmount,
preventOverflow: true,
scrollableElement: popupsScrollableElement,
target: buttonRef.current,
zIndex: akEditorMenuZIndex
}, /*#__PURE__*/React.createElement(RegisteredInsertMenuContent, {
api: api,
maxHeight: menuHeight,
editorView: editorView,
isOffline: isOfflineMode(connectivityMode),
onClose: closeAndRestoreFocus,
onDismiss: closeForSelection,
onSelect: closeForSelection,
target: buttonRef.current
})));
};