UNPKG

@atlaskit/editor-plugin-insert-block

Version:

Insert block plugin for @atlaskit/editor-core

243 lines (241 loc) 12.4 kB
import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; import React, { useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { getAriaKeyshortcuts, insertElements, ToolTipContent } from '@atlaskit/editor-common/keymaps'; import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages'; import { TOOLBAR_BUTTON_TEST_ID, useEditorToolbar } from '@atlaskit/editor-common/toolbar'; import { Popup } from '@atlaskit/editor-common/ui'; import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector'; import { akEditorMenuZIndex } from '@atlaskit/editor-shared-styles'; import { ToolbarButton, ToolbarTooltip, AddIcon, useToolbarUI } from '@atlaskit/editor-toolbar'; import InsertMenu, { DEFAULT_HEIGHT } from '../ElementBrowser/InsertMenu'; import { LINK_BUTTON_KEY } from './hooks/filterDropdownItems'; import { useEmojiPickerPopup } from './hooks/useEmojiPickerPopup'; import { useInsertButtonState } from './hooks/useInsertButtonState'; import { useTableSelectorPopup } from './hooks/useTableSelectorPopup'; import { EmojiPickerPopup } from './popups/EmojiPickerPopup'; // This determines how the popup should fit. We prefer the insert menu // opening on the bottom as we have a search bar and should only open on // top if there is more than sufficient room. var FIT_HEIGHT_BUFFER = 100; export var InsertButton = function InsertButton(_ref) { var api = _ref.api, breakpoint = _ref.breakpoint, _ref$showElementBrows = _ref.showElementBrowserLink, showElementBrowserLink = _ref$showElementBrows === void 0 ? false : _ref$showElementBrows, _ref$isFullPageAppear = _ref.isFullPageAppearance, isFullPageAppearance = _ref$isFullPageAppear === void 0 ? false : _ref$isFullPageAppear, tableSelectorSupported = _ref.tableSelectorSupported, nativeStatusSupported = _ref.nativeStatusSupported, horizontalRuleEnabled = _ref.horizontalRuleEnabled, expandEnabled = _ref.expandEnabled, insertMenuItems = _ref.insertMenuItems, numberOfButtons = _ref.numberOfButtons, onInsertBlockType = _ref.onInsertBlockType, toolbarConfig = _ref.toolbarConfig; var _useEditorToolbar = useEditorToolbar(), editorView = _useEditorToolbar.editorView; var _useToolbarUI = useToolbarUI(), isDisabled = _useToolbarUI.isDisabled, popupsMountPoint = _useToolbarUI.popupsMountPoint, popupsBoundariesElement = _useToolbarUI.popupsBoundariesElement, popupsScrollableElement = _useToolbarUI.popupsScrollableElement; var _useIntl = useIntl(), formatMessage = _useIntl.formatMessage; var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), insertMenuOpen = _useState2[0], setInsertMenuOpen = _useState2[1]; var insertButtonRef = useRef(null); var emojiPickerPopup = useEmojiPickerPopup({ api: api, buttonRef: insertButtonRef }); var tableSelectorPopup = useTableSelectorPopup({ api: api, buttonRef: insertButtonRef }); var showMediaPicker = useSharedPluginStateSelector(api, 'media.showMediaPicker'); var _useInsertButtonState = useInsertButtonState({ api: api, breakpoint: breakpoint, editorView: editorView || undefined, horizontalRuleEnabled: horizontalRuleEnabled, insertMenuItems: insertMenuItems, nativeStatusSupported: nativeStatusSupported, numberOfButtons: numberOfButtons, tableSelectorSupported: tableSelectorSupported, expandEnabled: expandEnabled, showElementBrowserLink: showElementBrowserLink, toolbarConfig: toolbarConfig }), dropdownItems = _useInsertButtonState.dropdownItems, emojiProvider = _useInsertButtonState.emojiProvider, isTypeAheadAllowed = _useInsertButtonState.isTypeAheadAllowed; if (!(api !== null && api !== void 0 && api.insertBlock)) { return null; } var toggleInsertMenuOpen = function toggleInsertMenuOpen(newState) { setInsertMenuOpen(newState); }; var onPopupUnmount = function onPopupUnmount() { requestAnimationFrame(function () { return api === null || api === void 0 ? void 0 : api.core.actions.focus(); }); }; var onClick = function onClick() { toggleInsertMenuOpen(!insertMenuOpen); }; var onItemActivated = function onItemActivated(_ref2) { var _api$core, _api$hyperlink, _api$imageUpload, _api$mention, _api$taskDecision, _api$rule, _api$core3, _api$date, _api$placeholderText, _api$layout, _api$core4, _api$status, _api$expand; var item = _ref2.item, inputMethod = _ref2.inputMethod; if (!editorView) { return; } var state = editorView.state, dispatch = editorView.dispatch; // need to do this before inserting nodes so scrollIntoView works properly if (!editorView.hasFocus()) { editorView.focus(); } switch (item.value.name) { case LINK_BUTTON_KEY: api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$hyperlink = api.hyperlink) === null || _api$hyperlink === void 0 ? void 0 : _api$hyperlink.commands.showLinkToolbar(inputMethod)); break; case 'table': // workaround to solve race condition where cursor is not placed correctly inside table queueMicrotask(function () { var _api$table, _api$table$actions$in, _api$table$actions; api === null || api === void 0 || (_api$table = api.table) === null || _api$table === void 0 || (_api$table$actions$in = (_api$table$actions = _api$table.actions).insertTable) === null || _api$table$actions$in === void 0 || _api$table$actions$in.call(_api$table$actions, { action: ACTION.INSERTED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: ACTION_SUBJECT_ID.TABLE, attributes: { inputMethod: inputMethod }, eventType: EVENT_TYPE.TRACK })(state, dispatch); }); break; case 'table selector': tableSelectorPopup.toggle(inputMethod); break; case 'image upload': if (api !== null && api !== void 0 && (_api$imageUpload = api.imageUpload) !== null && _api$imageUpload !== void 0 && _api$imageUpload.actions.startUpload) { api.imageUpload.actions.startUpload()(state, dispatch); } break; case 'media': if (showMediaPicker) { var _api$mediaInsert, _api$core2, _api$mediaInsert2; api !== null && api !== void 0 && (_api$mediaInsert = api.mediaInsert) !== null && _api$mediaInsert !== void 0 && _api$mediaInsert.commands.showMediaInsertPopup ? api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.execute(api === null || api === void 0 || (_api$mediaInsert2 = api.mediaInsert) === null || _api$mediaInsert2 === void 0 ? void 0 : _api$mediaInsert2.commands.showMediaInsertPopup()) : showMediaPicker === null || showMediaPicker === void 0 ? void 0 : showMediaPicker(); } break; case 'mention': api === null || api === void 0 || (_api$mention = api.mention) === null || _api$mention === void 0 || (_api$mention = _api$mention.actions) === null || _api$mention === void 0 || _api$mention.openTypeAhead(inputMethod); break; case 'emoji': emojiPickerPopup.toggle(inputMethod); break; case 'codeblock': case 'blockquote': case 'panel': onInsertBlockType === null || onInsertBlockType === void 0 || onInsertBlockType(item.value.name)(state, dispatch); break; case 'action': case 'decision': var listType = item.value.name === 'action' ? 'taskList' : 'decisionList'; api === null || api === void 0 || (_api$taskDecision = api.taskDecision) === null || _api$taskDecision === void 0 || _api$taskDecision.actions.insertTaskDecision(listType, inputMethod)(state, dispatch); break; case 'horizontalrule': api === null || api === void 0 || (_api$rule = api.rule) === null || _api$rule === void 0 || _api$rule.actions.insertHorizontalRule(inputMethod)(state, dispatch); break; case 'date': api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(api === null || api === void 0 || (_api$date = api.date) === null || _api$date === void 0 || (_api$date = _api$date.commands) === null || _api$date === void 0 ? void 0 : _api$date.insertDate({ inputMethod: inputMethod })); break; case 'placeholder text': api === null || api === void 0 || (_api$placeholderText = api.placeholderText) === null || _api$placeholderText === void 0 || _api$placeholderText.actions.showPlaceholderFloatingToolbar(state, dispatch); break; case 'layout': api === null || api === void 0 || (_api$layout = api.layout) === null || _api$layout === void 0 || _api$layout.actions.insertLayoutColumns(inputMethod)(state, dispatch); break; case 'status': api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(api === null || api === void 0 || (_api$status = api.status) === null || _api$status === void 0 || (_api$status = _api$status.commands) === null || _api$status === void 0 ? void 0 : _api$status.insertStatus(inputMethod)); break; case 'expand': api === null || api === void 0 || (_api$expand = api.expand) === null || _api$expand === void 0 || _api$expand.actions.insertExpand(state, dispatch); break; default: if (item && item.onClick) { item.onClick(); } break; } toggleInsertMenuOpen(false); }; var onInsert = function onInsert(_ref3) { var item = _ref3.item; onItemActivated({ item: item, inputMethod: INPUT_METHOD.INSERT_MENU }); }; var toggleVisibility = function toggleVisibility() { toggleInsertMenuOpen(!insertMenuOpen); }; return /*#__PURE__*/React.createElement(React.Fragment, null, insertMenuOpen && insertButtonRef.current && editorView && /*#__PURE__*/React.createElement(Popup, { target: insertButtonRef.current, fitHeight: DEFAULT_HEIGHT + FIT_HEIGHT_BUFFER, fitWidth: 350 // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , offset: [0, 3], mountTo: popupsMountPoint, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, onUnmount: onPopupUnmount, focusTrap: true, zIndex: akEditorMenuZIndex, preventOverflow: true, alignX: "right" }, /*#__PURE__*/React.createElement(InsertMenu, { editorView: editorView, dropdownItems: dropdownItems, onInsert: onInsert, toggleVisiblity: toggleVisibility, showElementBrowserLink: showElementBrowserLink, pluginInjectionApi: api, isFullPageAppearance: isFullPageAppearance })), emojiProvider && /*#__PURE__*/React.createElement(EmojiPickerPopup, { isOpen: emojiPickerPopup.isOpen, targetRef: insertButtonRef, emojiProvider: Promise.resolve(emojiProvider), onSelection: emojiPickerPopup.handleSelectedEmoji, onClickOutside: emojiPickerPopup.handleClickOutside, onEscapeKeydown: emojiPickerPopup.handleEscapeKeydown, onUnmount: emojiPickerPopup.onPopupUnmount, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement }), /*#__PURE__*/React.createElement(ToolbarTooltip, { content: /*#__PURE__*/React.createElement(ToolTipContent, { description: formatMessage(messages.insertMenu), keymap: insertElements }) }, /*#__PURE__*/React.createElement(ToolbarButton, { iconBefore: /*#__PURE__*/React.createElement(AddIcon, { size: "small", label: formatMessage(messages.insertMenu) }), ariaKeyshortcuts: getAriaKeyshortcuts(insertElements), ref: insertButtonRef, onClick: onClick, isSelected: insertMenuOpen, isDisabled: !isTypeAheadAllowed || isDisabled, testId: TOOLBAR_BUTTON_TEST_ID.INSERT }))); };