UNPKG

@atlaskit/editor-plugin-insert-block

Version:

Insert block plugin for @atlaskit/editor-core

267 lines (264 loc) 14.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.sortFeaturedItems = exports.default = exports.DEFAULT_HEIGHT = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = require("react"); var _react2 = require("@emotion/react"); var _reactIntl = require("react-intl"); var _CellMeasurer = require("react-virtualized/dist/commonjs/CellMeasurer"); var _analytics = require("@atlaskit/editor-common/analytics"); var _elementBrowser = require("@atlaskit/editor-common/element-browser"); var _hooks = require("@atlaskit/editor-common/hooks"); var _quickInsert = require("@atlaskit/editor-common/quick-insert"); var _uiReact = require("@atlaskit/editor-common/ui-react"); var _editorPluginConnectivity = require("@atlaskit/editor-plugin-connectivity"); var _expVal = require("@atlaskit/tmp-editor-statsig/expVal"); var _excluded = ["children"]; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } /** * @jsxRuntime classic * @jsx jsx */ /* eslint-disable @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports, jsdoc/require-description -- Ignored via go/DSP-18766; jsdoc debt surfaced by this mechanical PR */ var DEFAULT_HEIGHT = exports.DEFAULT_HEIGHT = 560; /** * Exported helper to allow testing of InsertMenu pinning logic. * * The `cc_fd_db_top_editor_toolbar` experiment adds new logic to sort elements by `priority`. * This newer implementation matches how the quick insert menu sorts elements. */ var sortFeaturedItems = exports.sortFeaturedItems = function sortFeaturedItems(featuredItems, formatMessage) { if (['new-description', 'orig-description'].includes((0, _expVal.expVal)('cc_fd_db_top_editor_toolbar', 'cohort', 'control')) || (0, _expVal.expValNoExposure)('cc_fd_wb_jira_quick_insert_experiment', 'isEnabled', false) || ['slot-two', 'slot-four'].includes((0, _expVal.expValNoExposure)('cc_fd_cwr_quick_insert', 'cohort', 'control'))) { // Sort by priority (lower first) on the concatenated list so items // with "priority" are at the top (e.g. Whiteboard before Database) return featuredItems.slice(0).sort(function (a, b) { return (a.priority || Number.POSITIVE_INFINITY) - (b.priority || Number.POSITIVE_INFINITY); }); } // NOTE: this is *not* the ideal way to approach this. Old logic sort whiteboards to top var DIAGRAM_KEY = 'whiteboard-extension:create-diagram'; var isDiagram = function isDiagram(item) { return item.key === DIAGRAM_KEY; }; var featuredWhiteboardsPresent = featuredItems.some(isDiagram); if (featuredWhiteboardsPresent) { var pin = function pin(key) { var idx = featuredItems.findIndex(function (item) { return item.key === key; }); var filtered = featuredItems.filter(function (item) { return !isDiagram(item); }); if (idx === -1) { return filtered; } var picked = _objectSpread(_objectSpread({}, featuredItems[idx]), {}, { description: formatMessage(_quickInsert.messages.featuredWhiteboardDescription) }); return [picked].concat((0, _toConsumableArray2.default)(filtered)); }; return pin(DIAGRAM_KEY); } return featuredItems; }; var selector = function selector(states) { var _states$connectivityS; return { connectivityMode: (_states$connectivityS = states.connectivityState) === null || _states$connectivityS === void 0 ? void 0 : _states$connectivityS.mode }; }; var InsertMenu = function InsertMenu(_ref) { var _pluginInjectionApi$q6, _pluginInjectionApi$q7; var editorView = _ref.editorView, dropdownItems = _ref.dropdownItems, showElementBrowserLink = _ref.showElementBrowserLink, onInsert = _ref.onInsert, toggleVisiblity = _ref.toggleVisiblity, pluginInjectionApi = _ref.pluginInjectionApi; var _useState = (0, _react.useState)(0), _useState2 = (0, _slicedToArray2.default)(_useState, 2), itemCount = _useState2[0], setItemCount = _useState2[1]; var _useState3 = (0, _react.useState)(DEFAULT_HEIGHT), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), height = _useState4[0], setHeight = _useState4[1]; var _useIntl = (0, _reactIntl.useIntl)(), formatMessage = _useIntl.formatMessage; var cache = (0, _react.useMemo)(function () { return new _CellMeasurer.CellMeasurerCache({ fixedWidth: true, defaultHeight: _elementBrowser.ELEMENT_ITEM_HEIGHT, minHeight: _elementBrowser.ELEMENT_ITEM_HEIGHT }); }, []); (0, _react.useLayoutEffect)(function () { // Figure based on visuals to exclude the searchbar, padding/margin, and the ViewMore item. var EXTRA_SPACE_EXCLUDING_ELEMENTLIST = 128; var totalItemHeight = // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) (0, _toConsumableArray2.default)(Array(itemCount)).reduce(function (sum, _, index) { return sum + cache.rowHeight({ index: index }); }, 0) + EXTRA_SPACE_EXCLUDING_ELEMENTLIST; if (itemCount > 0 && totalItemHeight < DEFAULT_HEIGHT) { setHeight(totalItemHeight); } else { setHeight(DEFAULT_HEIGHT); } }, [cache, itemCount]); var transform = (0, _react.useCallback)(function (item) { return { title: item.content, description: item.tooltipDescription, keyshortcut: item.shortcut, icon: function icon() { return getSvgIconForItem({ name: item.value.name }) || item.elemBefore; }, /** * @note This transformed items action is only used when a quick insert item has been * called from the quick insert menu and a search has not been performed. */ action: function action() { return onInsert({ item: item }); }, // "insertInsertMenuItem" expects these 2 properties. onClick: item.onClick, value: item.value }; }, [onInsert]); var quickInsertDropdownItems = dropdownItems.map(transform); var onInsertItem = (0, _react.useCallback)(function (item) { var _pluginInjectionApi$q; toggleVisiblity(); if (!editorView.hasFocus()) { editorView.focus(); } pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q === void 0 || _pluginInjectionApi$q.actions.insertItem(item, _analytics.INPUT_METHOD.TOOLBAR)(editorView.state, editorView.dispatch); }, [editorView, toggleVisiblity, pluginInjectionApi]); var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(pluginInjectionApi, ['connectivity'], selector), connectivityMode = _useSharedPluginState.connectivityMode; var getItems = (0, _react.useCallback)(function (query, category) { var result; /** * @warning The results if there is a query are not the same as the results if there is no query. * For example: If you have a typed panel and then select the panel item then it will call a different action * than is specified on the editor plugins quick insert * @see above transform function for more details. */ if (query) { var _pluginInjectionApi$q2, _pluginInjectionApi$q3; result = (_pluginInjectionApi$q2 = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q3 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q3 === void 0 || (_pluginInjectionApi$q3 = _pluginInjectionApi$q3.actions.getSuggestions({ query: query, category: category })) === null || _pluginInjectionApi$q3 === void 0 ? void 0 : _pluginInjectionApi$q3.map(function (item) { return (0, _editorPluginConnectivity.isOfflineMode)(connectivityMode) && item.isDisabledOffline ? _objectSpread(_objectSpread({}, item), {}, { isDisabled: true }) : item; })) !== null && _pluginInjectionApi$q2 !== void 0 ? _pluginInjectionApi$q2 : []; } else { var _pluginInjectionApi$q4, _pluginInjectionApi$q5; var featuredQuickInsertSuggestions = (_pluginInjectionApi$q4 = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q5 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q5 === void 0 || (_pluginInjectionApi$q5 = _pluginInjectionApi$q5.actions.getSuggestions({ category: category, featuredItems: true })) === null || _pluginInjectionApi$q5 === void 0 ? void 0 : _pluginInjectionApi$q5.map(function (item) { return (0, _editorPluginConnectivity.isOfflineMode)(connectivityMode) && item.isDisabledOffline ? _objectSpread(_objectSpread({}, item), {}, { isDisabled: true }) : item; })) !== null && _pluginInjectionApi$q4 !== void 0 ? _pluginInjectionApi$q4 : []; var unfilteredResult = quickInsertDropdownItems.concat(featuredQuickInsertSuggestions); // need to sort on the concatenated list so desired elements are at the top result = sortFeaturedItems(unfilteredResult, formatMessage); } setItemCount(result.length); return result; }, [pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q6 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q6 === void 0 ? void 0 : _pluginInjectionApi$q6.actions, quickInsertDropdownItems, connectivityMode, formatMessage]); var emptyStateHandler = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q7 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q7 === void 0 || (_pluginInjectionApi$q7 = _pluginInjectionApi$q7.sharedState.currentState()) === null || _pluginInjectionApi$q7 === void 0 ? void 0 : _pluginInjectionApi$q7.emptyStateHandler; var onViewMore = (0, _react.useCallback)(function () { var _pluginInjectionApi$c, _pluginInjectionApi$q8; toggleVisiblity(); pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.core) === null || _pluginInjectionApi$c === void 0 || _pluginInjectionApi$c.actions.execute(pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$q8 = pluginInjectionApi.quickInsert) === null || _pluginInjectionApi$q8 === void 0 ? void 0 : _pluginInjectionApi$q8.commands.openElementBrowserModal); }, [pluginInjectionApi, toggleVisiblity]); return ( // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage (0, _react2.jsx)("div", { css: insertMenuWrapper(height) }, (0, _react2.jsx)(ElementBrowserWrapper, { handleClickOutside: toggleVisiblity, handleEscapeKeydown: toggleVisiblity, closeOnTab: false }, (0, _react2.jsx)(_elementBrowser.ElementBrowser, { mode: "inline", getItems: getItems, emptyStateHandler: emptyStateHandler, onInsertItem: onInsertItem, showSearch: true, showCategories: false // On page resize we want the InlineElementBrowser to show updated tools/overflow items , key: quickInsertDropdownItems.length, onViewMore: showElementBrowserLink ? onViewMore : undefined, cache: cache }))) ); }; var getSvgIconForItem = function getSvgIconForItem(_ref2) { var name = _ref2.name; var Icon = { codeblock: _quickInsert.IconCode, panel: _quickInsert.IconPanel, blockquote: _quickInsert.IconQuote, decision: _quickInsert.IconDecision, horizontalrule: _quickInsert.IconDivider, expand: _quickInsert.IconExpand, date: _quickInsert.IconDate, status: _quickInsert.IconStatus }[name]; return Icon ? (0, _react2.jsx)(Icon, { label: "" }) : undefined; }; var insertMenuWrapper = function insertMenuWrapper(height) { return (0, _react2.css)({ display: 'flex', flexDirection: 'column', width: '320px', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 height: "".concat(height, "px"), backgroundColor: "var(--ds-surface-overlay, #FFFFFF)", borderRadius: "var(--ds-radius-small, 3px)", boxShadow: "var(--ds-shadow-overlay, 0px 8px 12px #1E1F2126, 0px 0px 1px #1E1F214f)" }); }; var flexWrapperStyles = (0, _react2.css)({ display: 'flex', flex: 1, boxSizing: 'border-box', overflow: 'hidden' }); var FlexWrapper = function FlexWrapper(props) { var setOutsideClickTargetRef = (0, _react.useContext)(_uiReact.OutsideClickTargetRefContext); var children = props.children, divProps = (0, _objectWithoutProperties2.default)(props, _excluded); return ( // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading (0, _react2.jsx)("div", (0, _extends2.default)({ ref: setOutsideClickTargetRef, css: flexWrapperStyles }, divProps), children) ); }; var ElementBrowserWrapper = (0, _uiReact.withReactEditorViewOuterListeners)(FlexWrapper); var _default = exports.default = InsertMenu;