@atlaskit/editor-plugin-quick-insert
Version:
Quick insert plugin for @atlaskit/editor-core
216 lines • 10.3 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _toArray from "@babel/runtime/helpers/toArray";
var _excluded = ["rows", "selectableItems", "selectedItemIndex", "activeItemKey", "selectionSource"];
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
import React, { useCallback, useId, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import { INPUT_METHOD } from '@atlaskit/editor-common/analytics/types/enums';
import { toolbarInsertBlockMessages } from '@atlaskit/editor-common/messages/insert-block';
import { QuickInsertProvider } from '@atlaskit/editor-common/quick-insert/provider';
import { useRegisteredMenuContext } from '@atlaskit/editor-common/registered-menu/context';
import { REGISTERED_MENU_SURFACE_CONTEXT } from '@atlaskit/editor-common/registered-menu/surface-context';
import { useRegisteredMenu } from '@atlaskit/editor-common/registered-menu/use-registered-menu';
import { isSectionOverflowItemKey } from '@atlaskit/editor-common/type-ahead-is-section-overflow-item-key';
import { typeAheadListMessages } from '@atlaskit/editor-common/type-ahead/messages';
import MenuGroup from '@atlaskit/menu/menu-group';
import { getQuickInsertMenuModel } from './get-quick-insert-menu-model';
import { getQuickInsertMenuItemId } from './getQuickInsertMenuItemId';
import { RegisteredQuickInsertMenuItem } from './RegisteredQuickInsertMenuItem';
import { selectQuickInsertCategoryItems } from './selectQuickInsertCategoryItems';
import { ToolbarQuickInsertMenu } from './ToolbarQuickInsertMenu';
import { TypeAheadQuickInsertMenu } from './TypeAheadQuickInsertMenu';
import { useQuickInsertSearchAnalytics } from './useQuickInsertSearchAnalytics';
var DEFAULT_MENU_MAX_HEIGHT = 480;
var isImeEnter = function isImeEnter(event) {
return event.isComposing || event.keyCode === 229;
};
var QuickInsertMenuRoot = function QuickInsertMenuRoot(_ref) {
var _surfaceContext$get, _registeredMenu$maxHe;
var emptyStateHandler = _ref.emptyStateHandler,
fireAnalyticsEvent = _ref.fireAnalyticsEvent,
getItemRank = _ref.getItemRank,
getRecommendedItems = _ref.getRecommendedItems;
var registeredMenu = useRegisteredMenuContext();
var _registeredMenu$query = registeredMenu.query,
query = _registeredMenu$query === void 0 ? '' : _registeredMenu$query,
selectFromHost = registeredMenu.select,
surfaceContext = registeredMenu.surfaceContext;
var surface = (_surfaceContext$get = surfaceContext.get(REGISTERED_MENU_SURFACE_CONTEXT)) === null || _surfaceContext$get === void 0 ? void 0 : _surfaceContext$get.surface;
if (!selectFromHost || !surface || surface === 'element-browser') {
throw new Error('QuickInsertMenuRoot requires a selection action and registered menu surface');
}
var _useIntl = useIntl(),
formatMessage = _useIntl.formatMessage;
var components = registeredMenu.components,
runtimeItemRank = registeredMenu.getItemRank,
rootComponent = registeredMenu.rootComponent;
var model = useMemo(function () {
return getQuickInsertMenuModel({
components: components,
formatMessage: formatMessage,
getItemRank: runtimeItemRank !== null && runtimeItemRank !== void 0 ? runtimeItemRank : getItemRank,
getRecommendedItems: getRecommendedItems,
query: query,
rootComponent: rootComponent,
selectCategoryItems: components.some(function (_ref2) {
var key = _ref2.key;
return isSectionOverflowItemKey(key);
}) ? selectQuickInsertCategoryItems : undefined,
surfaceContext: surfaceContext
});
}, [components, formatMessage, getItemRank, getRecommendedItems, query, rootComponent, runtimeItemRank, surfaceContext]);
var resultCount = useMemo(function () {
return model.sections.reduce(function (count, _ref3) {
var _ref4 = _toArray(_ref3),
items = _arrayLikeToArray(_ref4).slice(1);
return count + items.filter(function (_ref5) {
var key = _ref5.key;
return !isSectionOverflowItemKey(key);
}).length;
}, 0);
}, [model.sections]);
var flushSearchAnalytics = useQuickInsertSearchAnalytics({
surface: surface,
fireAnalyticsEvent: fireAnalyticsEvent,
query: query,
resultCount: resultCount
});
var selectItem = useCallback(function (selection) {
flushSearchAnalytics();
selectFromHost(function (insert) {
return selection({
insert: insert,
source: surface === 'toolbar' ? INPUT_METHOD.INSERT_MENU : INPUT_METHOD.QUICK_INSERT
});
});
}, [flushSearchAnalytics, selectFromHost, surface]);
var menuContextValue = useMemo(function () {
return {
editorView: registeredMenu.editorView,
isOffline: registeredMenu.isOffline,
popupsMountPoint: registeredMenu.portalMountPoint,
select: selectItem,
surfaceContext: registeredMenu.surfaceContext
};
}, [registeredMenu.editorView, registeredMenu.isOffline, registeredMenu.portalMountPoint, registeredMenu.surfaceContext, selectItem]);
var listLabel = formatMessage(surface === 'typeahead' ? typeAheadListMessages.quickInsertInputLabel : toolbarInsertBlockMessages.insertMenu);
var _useRegisteredMenu = useRegisteredMenu({
model: model,
resetKey: query
}),
rows = _useRegisteredMenu.rows,
selectableItems = _useRegisteredMenu.selectableItems,
selectedItemIndex = _useRegisteredMenu.selectedItemIndex,
activeItemKey = _useRegisteredMenu.activeItemKey,
selectionSource = _useRegisteredMenu.selectionSource,
listEvents = _objectWithoutProperties(_useRegisteredMenu, _excluded);
var listId = useId();
var _useState = useState({
startIndex: -1,
stopIndex: -1
}),
_useState2 = _slicedToArray(_useState, 2),
renderedItems = _useState2[0],
setRenderedItems = _useState2[1];
var menuRef = useRef(null);
var maxHeight = (_registeredMenu$maxHe = registeredMenu.maxHeight) !== null && _registeredMenu$maxHe !== void 0 ? _registeredMenu$maxHe : DEFAULT_MENU_MAX_HEIGHT;
var itemCount = selectableItems.length + (model.footer ? 1 : 0);
var activeItemId = selectedItemIndex >= 0 && selectedItemIndex < itemCount ? getQuickInsertMenuItemId(listId, selectedItemIndex) : undefined;
var isActiveItemMounted = selectedItemIndex >= 0 && selectedItemIndex < itemCount && (selectedItemIndex >= renderedItems.startIndex && selectedItemIndex <= renderedItems.stopIndex || Boolean(model.footer) && selectedItemIndex === itemCount - 1);
var selectActiveItem = useCallback(function () {
if (isActiveItemMounted && activeItemId) {
var _menuRef$current;
(_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 || (_menuRef$current = _menuRef$current.ownerDocument.getElementById(activeItemId)) === null || _menuRef$current === void 0 || _menuRef$current.click();
}
}, [activeItemId, isActiveItemMounted]);
var onMenuKeyDown = useCallback(function (event) {
if (event.key === 'ArrowDown') {
listEvents.selectNext();
return true;
}
if (event.key === 'ArrowUp') {
listEvents.selectPrevious();
return true;
}
if (event.key === 'Enter') {
if (isImeEnter(event)) {
return false;
}
selectActiveItem();
return true;
}
return false;
}, [listEvents.selectNext, listEvents.selectPrevious, selectActiveItem]);
var containsTarget = useCallback(function (target) {
var _menuRef$current2;
return Boolean((_menuRef$current2 = menuRef.current) === null || _menuRef$current2 === void 0 ? void 0 : _menuRef$current2.contains(target));
}, []);
var interaction = useMemo(function () {
return {
activeDescendantId: isActiveItemMounted ? activeItemId : undefined,
containsTarget: containsTarget,
expanded: itemCount > 0,
label: listLabel,
listId: listId,
onKeyDown: onMenuKeyDown,
onClose: flushSearchAnalytics,
optionCount: itemCount,
selectNext: listEvents.selectNext,
selectPrevious: listEvents.selectPrevious
};
}, [activeItemId, containsTarget, flushSearchAnalytics, isActiveItemMounted, itemCount, listId, listLabel, listEvents.selectNext, listEvents.selectPrevious, onMenuKeyDown]);
useLayoutEffect(function () {
if (!model.root) {
return;
}
return registeredMenu.registerInteraction(interaction);
}, [model.root, interaction, registeredMenu.registerInteraction]);
if (!model.root) {
return null;
}
return /*#__PURE__*/React.createElement(QuickInsertProvider, {
value: menuContextValue
}, /*#__PURE__*/React.createElement("div", {
ref: menuRef
}, /*#__PURE__*/React.createElement(MenuGroup, null, surface === 'typeahead' ? /*#__PURE__*/React.createElement(TypeAheadQuickInsertMenu, {
Item: RegisteredQuickInsertMenuItem,
activeItemKey: activeItemKey,
hasScrollPadding: true,
itemCount: itemCount,
listId: listId,
listLabel: listLabel,
maxHeight: maxHeight,
model: model,
onItemBlur: listEvents.onItemBlur,
onItemFocus: listEvents.onItemFocus,
onItemHover: listEvents.onItemHover,
onItemLeave: listEvents.onItemLeave,
onItemVisibilityChange: listEvents.onItemVisibilityChange,
onRenderedItemsChange: setRenderedItems,
query: query,
rows: rows,
selectedItemIndex: selectedItemIndex,
selectionSource: selectionSource
}) : /*#__PURE__*/React.createElement(ToolbarQuickInsertMenu, {
Item: RegisteredQuickInsertMenuItem,
activePreviewItemKey: activeItemKey,
emptyStateHandler: emptyStateHandler,
itemCount: itemCount,
listId: listId,
listLabel: listLabel,
maxHeight: maxHeight,
model: model,
onItemBlur: listEvents.onItemBlur,
onItemFocus: listEvents.onItemFocus,
onItemHover: listEvents.onItemHover,
onItemLeave: listEvents.onItemLeave,
onItemVisibilityChange: listEvents.onItemVisibilityChange,
onRenderedItemsChange: setRenderedItems,
query: query,
rows: rows,
selectedItemIndex: selectedItemIndex,
selectionSource: selectionSource
}))));
};
export default QuickInsertMenuRoot;