UNPKG

@atlaskit/editor-plugin-floating-toolbar

Version:

Floating toolbar plugin for @atlaskit/editor-core

609 lines (594 loc) 30.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.ContentComponent = ContentComponent; exports.floatingToolbarPlugin = void 0; exports.floatingToolbarPluginFactory = floatingToolbarPluginFactory; exports.pluginKey = exports.getRelevantConfig = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _react = _interopRequireDefault(require("react")); var _camelCase = _interopRequireDefault(require("lodash/camelCase")); var _analytics = require("@atlaskit/editor-common/analytics"); var _coreUtils = require("@atlaskit/editor-common/core-utils"); var _errorBoundary = require("@atlaskit/editor-common/error-boundary"); var _hooks = require("@atlaskit/editor-common/hooks"); var _providerFactory = require("@atlaskit/editor-common/provider-factory"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _toolbarFlagCheck = require("@atlaskit/editor-common/toolbar-flag-check"); var _ui = require("@atlaskit/editor-common/ui"); var _state = require("@atlaskit/editor-prosemirror/state"); var _utils = require("@atlaskit/editor-prosemirror/utils"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _commands = require("./pm-plugins/commands"); var _forceFocus = _interopRequireWildcard(require("./pm-plugins/force-focus")); var _commands2 = require("./pm-plugins/toolbar-data/commands"); var _plugin = require("./pm-plugins/toolbar-data/plugin"); var _pluginKey = require("./pm-plugins/toolbar-data/plugin-key"); var _utils2 = require("./pm-plugins/utils"); var _ConfirmationModal = require("./ui/ConfirmationModal"); var _Toolbar = _interopRequireDefault(require("./ui/Toolbar")); var _utils3 = require("./ui/utils"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } 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; } var SUPPRESS_TOOLBAR_USER_INTENTS = ['dragging', 'tableContextualMenuPopupOpen', 'tableDragMenuPopupOpen', 'commenting', 'resizing', 'blockMenuOpen', 'statusPickerOpen']; // TODO: AFP-2532 - Fix automatic suppressions below var getRelevantConfig = exports.getRelevantConfig = function getRelevantConfig(selection, configs) { // node selections always take precedence, see if var configPair; configs.find(function (config) { var node = (0, _utils.findSelectedNodeOfType)(config.nodeType)(selection); if (node) { configPair = { node: node.node, pos: node.pos, config: config }; } return !!node; }); if (configPair) { return configPair; } // create mapping of node type name to configs var configByNodeType = {}; configs.forEach(function (config) { if (Array.isArray(config.nodeType)) { config.nodeType.forEach(function (nodeType) { configByNodeType[nodeType.name] = config; }); } else { configByNodeType[config.nodeType.name] = config; } }); // search up the tree from selection var $from = selection.$from; for (var i = $from.depth; i > 0; i--) { var node = $from.node(i); var matchedConfig = configByNodeType[node.type.name]; if (matchedConfig) { return { config: matchedConfig, node: node, pos: $from.pos }; } } // if it is AllSelection (can be result of Cmd+A) - use first node if (selection instanceof _state.AllSelection) { var docNode = $from.node(0); var _matchedConfig = null; var firstChild = (0, _utils2.findNode)(docNode, function (node) { _matchedConfig = configByNodeType[node.type.name]; return !!_matchedConfig; }); if (firstChild && _matchedConfig) { return { config: _matchedConfig, node: firstChild, pos: $from.pos }; } } return; }; var getDomRefFromSelection = function getDomRefFromSelection(view, dispatchAnalyticsEvent) { try { // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting return (0, _utils.findDomRefAtPos)(view.state.selection.from, view.domAtPos.bind(view)); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { // eslint-disable-next-line no-console console.warn(error); if (dispatchAnalyticsEvent) { var payload = { action: _analytics.ACTION.ERRORED, actionSubject: _analytics.ACTION_SUBJECT.CONTENT_COMPONENT, eventType: _analytics.EVENT_TYPE.OPERATIONAL, attributes: { component: _analytics.CONTENT_COMPONENT.FLOATING_TOOLBAR, selection: view.state.selection.toJSON(), position: view.state.selection.from, docSize: view.state.doc.nodeSize, error: error.toString(), // @ts-expect-error - Object literal may only specify known properties, 'errorStack' does not exist in type // This error was introduced after upgrading to TypeScript 5 errorStack: error.stack || undefined } }; dispatchAnalyticsEvent(payload); } } }; function filterUndefined(x) { return !!x; } var floatingToolbarPlugin = exports.floatingToolbarPlugin = function floatingToolbarPlugin(_ref) { var api = _ref.api; return { name: 'floatingToolbar', pmPlugins: function pmPlugins() { var floatingToolbarHandlers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var plugins = [{ // Should be after all toolbar plugins name: 'floatingToolbar', plugin: function plugin(_ref2) { var providerFactory = _ref2.providerFactory, getIntl = _ref2.getIntl; return floatingToolbarPluginFactory({ api: api, floatingToolbarHandlers: floatingToolbarHandlers, providerFactory: providerFactory, getIntl: getIntl }); } }, { name: 'floatingToolbarData', plugin: function plugin(_ref3) { var dispatch = _ref3.dispatch; return (0, _plugin.createPlugin)(dispatch); } }, { name: 'forceFocus', plugin: function plugin() { return (0, _forceFocus.default)(); } }]; return plugins; }, actions: { forceFocusSelector: _forceFocus.forceFocusSelector }, commands: { copyNode: function copyNode(nodeType, inputMethod) { var _api$analytics; return (0, _commands.copyNode)(nodeType, api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, inputMethod); } }, getSharedState: function getSharedState(editorState) { var _api$interaction, _pluginKey$getState$g, _pluginKey$getState, _pluginKey$getState$g2; if (!editorState) { return undefined; } var interactionState = api === null || api === void 0 || (_api$interaction = api.interaction) === null || _api$interaction === void 0 || (_api$interaction = _api$interaction.sharedState.currentState()) === null || _api$interaction === void 0 ? void 0 : _api$interaction.interactionState; var configWithNodeInfo = interactionState !== 'hasNotHadInteraction' ? (_pluginKey$getState$g = (_pluginKey$getState = pluginKey.getState(editorState)) === null || _pluginKey$getState === void 0 || (_pluginKey$getState$g2 = _pluginKey$getState.getConfigWithNodeInfo) === null || _pluginKey$getState$g2 === void 0 ? void 0 : _pluginKey$getState$g2.call(_pluginKey$getState, editorState)) !== null && _pluginKey$getState$g !== void 0 ? _pluginKey$getState$g : undefined : undefined; return { configWithNodeInfo: configWithNodeInfo, floatingToolbarData: _pluginKey.pluginKey.getState(editorState) }; }, contentComponent: function contentComponent(_ref4) { var popupsMountPoint = _ref4.popupsMountPoint, popupsBoundariesElement = _ref4.popupsBoundariesElement, popupsScrollableElement = _ref4.popupsScrollableElement, editorView = _ref4.editorView, providerFactory = _ref4.providerFactory, dispatchAnalyticsEvent = _ref4.dispatchAnalyticsEvent; if (!editorView) { return null; } return /*#__PURE__*/_react.default.createElement(ContentComponent, { editorView: editorView, pluginInjectionApi: api, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement, providerFactory: providerFactory, dispatchAnalyticsEvent: dispatchAnalyticsEvent }); } }; }; /** * React component that renders the floating toolbar UI for the editor. * * This component manages the display of floating toolbars based on the current editor state, * selection, and configuration. It handles visibility conditions, positioning, toolbar items * consolidation, and confirmation dialogs. * * @param props - Component properties * @param props.pluginInjectionApi - Plugin injection API for accessing other plugin states * @param props.editorView - ProseMirror EditorView instance * @param props.popupsMountPoint - DOM element where popups should be mounted * @param props.popupsBoundariesElement - Element that defines popup boundaries * @param props.popupsScrollableElement - Scrollable container element for popups * @param props.providerFactory - Factory for creating various providers * @param props.dispatchAnalyticsEvent - Function to dispatch analytics events * @returns JSX element representing the floating toolbar or null if not visible */ function ContentComponent(_ref5) { var _configWithNodeInfo$c, _configWithNodeInfo$c2, _items, _pluginInjectionApi$c, _pluginInjectionApi$d, _confirmButtonItem, _confirmButtonItem2, _confirmButtonItem3; var pluginInjectionApi = _ref5.pluginInjectionApi, editorView = _ref5.editorView, popupsMountPoint = _ref5.popupsMountPoint, popupsBoundariesElement = _ref5.popupsBoundariesElement, popupsScrollableElement = _ref5.popupsScrollableElement, providerFactory = _ref5.providerFactory, dispatchAnalyticsEvent = _ref5.dispatchAnalyticsEvent; var _useSharedPluginState = (0, _hooks.useSharedPluginState)(pluginInjectionApi, ['floatingToolbar', 'editorDisabled', 'editorViewMode', 'userIntent']), floatingToolbarState = _useSharedPluginState.floatingToolbarState, editorDisabledState = _useSharedPluginState.editorDisabledState, editorViewModeState = _useSharedPluginState.editorViewModeState, userIntentState = _useSharedPluginState.userIntentState; var _ref6 = floatingToolbarState !== null && floatingToolbarState !== void 0 ? floatingToolbarState : {}, configWithNodeInfo = _ref6.configWithNodeInfo, floatingToolbarData = _ref6.floatingToolbarData; if ((0, _coreUtils.isSSR)()) { return null; } if (!configWithNodeInfo || !configWithNodeInfo.config || typeof ((_configWithNodeInfo$c = configWithNodeInfo.config) === null || _configWithNodeInfo$c === void 0 ? void 0 : _configWithNodeInfo$c.visible) !== 'undefined' && !((_configWithNodeInfo$c2 = configWithNodeInfo.config) !== null && _configWithNodeInfo$c2 !== void 0 && _configWithNodeInfo$c2.visible)) { return null; } if (userIntentState !== null && userIntentState !== void 0 && userIntentState.currentUserIntent && SUPPRESS_TOOLBAR_USER_INTENTS.includes(userIntentState === null || userIntentState === void 0 ? void 0 : userIntentState.currentUserIntent)) { return null; } var config = configWithNodeInfo.config, node = configWithNodeInfo.node; // When the new inline editor-toolbar is enabled, suppress floating toolbar for text selections. if (Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar)) { var selection = editorView.state.selection; var isCellSelection = '$anchorCell' in selection && !selection.empty; var isTextSelected = selection instanceof _state.TextSelection && !selection.empty; // don't dismiss table toolbar when a cell selection is caused by clicking the drag handle (which has it's own userIntent) if (isTextSelected && config.className !== 'hyperlink-floating-toolbar' || isCellSelection && (userIntentState === null || userIntentState === void 0 ? void 0 : userIntentState.currentUserIntent) === 'default') { return null; } } var items = config.items; var groupLabel = config.groupLabel; var title = config.title, _config$getDomRef = config.getDomRef, getDomRef = _config$getDomRef === void 0 ? getDomRefFromSelection : _config$getDomRef, _config$align = config.align, align = _config$align === void 0 ? 'center' : _config$align, _config$className = config.className, className = _config$className === void 0 ? '' : _config$className, height = config.height, width = config.width, zIndex = config.zIndex, _config$offset = config.offset, offset = _config$offset === void 0 ? [0, 12] : _config$offset, forcePlacement = config.forcePlacement, preventPopupOverflow = config.preventPopupOverflow, onPositionCalculated = config.onPositionCalculated, _config$absoluteOffse = config.absoluteOffset, absoluteOffset = _config$absoluteOffse === void 0 ? { top: 0, left: 0, right: 0, bottom: 0 } : _config$absoluteOffse, focusTrap = config.focusTrap, _config$mediaAssistiv = config.mediaAssistiveMessage, mediaAssistiveMessage = _config$mediaAssistiv === void 0 ? '' : _config$mediaAssistiv, _config$stick = config.stick, stick = _config$stick === void 0 ? true : _config$stick; var targetRef = getDomRef(editorView, dispatchAnalyticsEvent); var isEditorDisabled = editorDisabledState && editorDisabledState.editorDisabled; var isInViewMode = (editorViewModeState === null || editorViewModeState === void 0 ? void 0 : editorViewModeState.mode) === 'view'; if (!targetRef || isEditorDisabled && !isInViewMode) { return null; } // TODO: MODES-3950 - Update this view mode specific logic once we refactor view mode. // We should inverse the responsibility here: A blacklist for toolbar items in view mode, rather than this white list. // Also consider moving this logic to the more specific toolbar plugins (media and selection). var iterableItems = Array.isArray(items) ? items : (_items = items) === null || _items === void 0 ? void 0 : _items(node); if (isInViewMode) { // Typescript note: Not all toolbar item types have the `supportsViewMode` prop. var toolbarItemViewModeProp = 'supportsViewMode'; // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) items = iterableItems.filter(function (item) { return toolbarItemViewModeProp in item && !!item[toolbarItemViewModeProp]; }); } if ((0, _toolbarFlagCheck.areToolbarFlagsEnabled)(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar))) { var _items2; // Consolidate floating toolbar items var toolbarItemsArray = Array.isArray(items) ? items : (_items2 = items) === null || _items2 === void 0 ? void 0 : _items2(node); // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) var overflowDropdownItems = toolbarItemsArray.filter(function (item) { return item.type === 'overflow-dropdown'; }); if (overflowDropdownItems.length > 1) { var consolidatedOverflowDropdown = (0, _utils3.consolidateOverflowDropdownItems)(overflowDropdownItems); // eslint-disable-next-line @atlassian/perf-linting/no-expensive-computations-in-render -- Ignored via go/ees017 (to be fixed) var otherItems = toolbarItemsArray.filter(function (item) { return item.type !== 'overflow-dropdown'; }); if (otherItems.length > 0) { // remove the last separators while (((_otherItems$at = otherItems.at(-1)) === null || _otherItems$at === void 0 ? void 0 : _otherItems$at.type) === 'separator') { var _otherItems$at; otherItems.pop(); } } items = [].concat((0, _toConsumableArray2.default)(otherItems), [{ type: 'separator', fullHeight: true, supportsViewMode: true }, consolidatedOverflowDropdown]); } // Apply analytics to dropdown if (overflowDropdownItems.length > 0 && dispatchAnalyticsEvent) { var _items3; var currentItems = Array.isArray(items) ? items : (_items3 = items) === null || _items3 === void 0 ? void 0 : _items3(node); var updatedItems = currentItems.map(function (item) { if (item.type !== 'overflow-dropdown') { return item; } var originalOnClick = item.onClick; return _objectSpread(_objectSpread({}, item), {}, { onClick: function onClick() { var _pluginInjectionApi$e; var editorContentMode = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$e = pluginInjectionApi.editorViewMode) === null || _pluginInjectionApi$e === void 0 || (_pluginInjectionApi$e = _pluginInjectionApi$e.sharedState.currentState()) === null || _pluginInjectionApi$e === void 0 ? void 0 : _pluginInjectionApi$e.mode; dispatchAnalyticsEvent({ action: _analytics.ACTION.CLICKED, actionSubject: _analytics.ACTION_SUBJECT.BUTTON, actionSubjectId: _analytics.ACTION_SUBJECT_ID.FLOATING_TOOLBAR_OVERFLOW, eventType: _analytics.EVENT_TYPE.UI, attributes: { editorContentMode: editorContentMode } }); // Call original onClick if it exists originalOnClick === null || originalOnClick === void 0 || originalOnClick(); } }); }); items = updatedItems; } } var customPositionCalculation; var toolbarItems = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.copyButton) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.actions.processCopyButtonItems(editorView.state)(Array.isArray(items) ? items : items(node), pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$d = pluginInjectionApi.decorations) === null || _pluginInjectionApi$d === void 0 ? void 0 : _pluginInjectionApi$d.actions.hoverDecoration); if (onPositionCalculated) { customPositionCalculation = function customPositionCalculation(nextPos) { return onPositionCalculated(editorView, nextPos); }; } var dispatchCommand = function dispatchCommand(fn) { return fn && fn(editorView.state, editorView.dispatch, editorView); }; // Confirm dialog var confirmButtonItem; var _ref7 = floatingToolbarData || {}, confirmDialogForItem = _ref7.confirmDialogForItem, confirmDialogForItemOption = _ref7.confirmDialogForItemOption; var matchingItem = confirmDialogForItem ? toolbarItems === null || toolbarItems === void 0 ? void 0 : toolbarItems[confirmDialogForItem] : undefined; if ((matchingItem === null || matchingItem === void 0 ? void 0 : matchingItem.type) === 'button') { confirmButtonItem = matchingItem; } if ((matchingItem === null || matchingItem === void 0 ? void 0 : matchingItem.type) === 'overflow-dropdown' && confirmDialogForItemOption !== undefined) { var matchingItemOption = matchingItem.options[confirmDialogForItemOption]; // OverflowDropdownOption is the only member of the union that does not have a 'type' property if (!('type' in matchingItemOption)) { confirmButtonItem = matchingItemOption; } } var scrollable = config.scrollable; var confirmDialogOptions = typeof ((_confirmButtonItem = confirmButtonItem) === null || _confirmButtonItem === void 0 ? void 0 : _confirmButtonItem.confirmDialog) === 'function' ? (_confirmButtonItem2 = confirmButtonItem) === null || _confirmButtonItem2 === void 0 ? void 0 : _confirmButtonItem2.confirmDialog() : (_confirmButtonItem3 = confirmButtonItem) === null || _confirmButtonItem3 === void 0 ? void 0 : _confirmButtonItem3.confirmDialog; return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, { component: _analytics.ACTION_SUBJECT.FLOATING_TOOLBAR_PLUGIN, componentId: (0, _camelCase.default)(title), dispatchAnalyticsEvent: dispatchAnalyticsEvent, fallbackComponent: null }, /*#__PURE__*/_react.default.createElement(_ui.Popup, { ariaLabel: title, role: 'toolbar', offset: offset, target: targetRef, alignY: "bottom", forcePlacement: forcePlacement, fitHeight: height, fitWidth: width, absoluteOffset: absoluteOffset, alignX: align, stick: stick, zIndex: zIndex, mountTo: popupsMountPoint, boundariesElement: popupsBoundariesElement, scrollableElement: popupsScrollableElement, onPositionCalculated: customPositionCalculation // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 , style: scrollable ? { maxWidth: '100%' } : {}, focusTrap: focusTrap, preventOverflow: preventPopupOverflow }, /*#__PURE__*/_react.default.createElement(_providerFactory.WithProviders, { providerFactory: providerFactory // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , providers: ['extensionProvider'] // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , renderNode: function renderNode(providers) { return /*#__PURE__*/_react.default.createElement(_Toolbar.default, { target: targetRef // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion , items: toolbarItems, groupLabel: groupLabel, node: node, dispatchCommand: dispatchCommand, editorView: editorView // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: className // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , focusEditor: function focusEditor() { return editorView.focus(); }, providerFactory: providerFactory, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement, dispatchAnalyticsEvent: dispatchAnalyticsEvent, extensionsProvider: providers.extensionProvider, scrollable: scrollable, api: pluginInjectionApi, mediaAssistiveMessage: mediaAssistiveMessage }); } })), /*#__PURE__*/_react.default.createElement(_ConfirmationModal.ConfirmationModal, { testId: "ak-floating-toolbar-confirmation-modal", options: confirmDialogOptions // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onConfirm: function onConfirm() { var isChecked = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (!!confirmDialogOptions.onConfirm) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion dispatchCommand(confirmDialogOptions.onConfirm(isChecked)); } else { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion dispatchCommand(confirmButtonItem.onClick); } } // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , onClose: function onClose() { dispatchCommand((0, _commands2.hideConfirmDialog)()); // Need to set focus to Editor here, // As when the Confirmation dialog pop up, and user interacts with the dialog, Editor loses focus. // So when Confirmation dialog is closed, Editor does not have the focus, then cursor goes to the position 1 of the doc, // instead of the cursor position before the dialog pop up. if (!editorView.hasFocus()) { editorView.focus(); } } })); } /** * * ProseMirror Plugin * */ // We throttle update of this plugin with RAF. // So from other plugins you will always get the previous state. var pluginKey = exports.pluginKey = new _state.PluginKey('floatingToolbarPluginKey'); /** * Clean up floating toolbar configs from undesired properties. */ function sanitizeFloatingToolbarConfig(config) { // Cleanup from non existing node types if (Array.isArray(config.nodeType)) { return _objectSpread(_objectSpread({}, config), {}, { nodeType: config.nodeType.filter(filterUndefined) }); } return config; } /** * Creates a floating toolbar plugin for the ProseMirror editor. * * This factory function creates a SafePlugin that manages floating toolbars in the editor. * It processes an array of floating toolbar handlers and determines which toolbar configuration * should be active based on the current editor state and selection. * * @param options - Configuration object for the floating toolbar plugin * @param options.floatingToolbarHandlers - Array of handlers that return toolbar configurations * @param options.getIntl - Function that returns the IntlShape instance for internationalization * @param options.providerFactory - Factory for creating various providers used by the editor * @returns A SafePlugin instance that manages floating toolbar state and behavior */ function floatingToolbarPluginFactory(options) { var floatingToolbarHandlers = options.floatingToolbarHandlers, providerFactory = options.providerFactory, getIntl = options.getIntl, api = options.api; var intl = getIntl(); var getConfigWithNodeInfo = function getConfigWithNodeInfo(editorState) { var activeConfigs = []; for (var index = 0; index < floatingToolbarHandlers.length; index++) { var handler = floatingToolbarHandlers[index]; var config = handler(editorState, intl, providerFactory, activeConfigs); if (config) { var _api$userIntent; if (SUPPRESS_TOOLBAR_USER_INTENTS.includes((api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || (_api$userIntent = _api$userIntent.sharedState.currentState()) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.currentUserIntent) || '')) { activeConfigs = undefined; break; } activeConfigs.push(sanitizeFloatingToolbarConfig(config)); } } var relevantConfig = activeConfigs && getRelevantConfig(editorState.selection, activeConfigs); return relevantConfig; }; var getIsToolbarSuppressed = function getIsToolbarSuppressed() { return false; }; var apply = function apply() { var newPluginState = { getConfigWithNodeInfo: getConfigWithNodeInfo }; return newPluginState; }; return new _safePlugin.SafePlugin({ key: pluginKey, state: { init: function init() { return { getConfigWithNodeInfo: getConfigWithNodeInfo }; }, apply: (0, _expValEquals.expValEquals)('platform_editor_lovability_suppress_toolbar_event', 'isEnabled', true) ? function (_tr, _pluginState, __oldEditorState) { var suppressedToolbar = getIsToolbarSuppressed(); var newPluginState = { getConfigWithNodeInfo: getConfigWithNodeInfo, suppressedToolbar: suppressedToolbar }; return newPluginState; } : apply }, view: (0, _expValEquals.expValEquals)('platform_editor_lovability_suppress_toolbar_event', 'isEnabled', true) ? function () { return { update: function update(view, prevState) { var pluginState = pluginKey.getState(view.state); var prevPluginState = pluginKey.getState(prevState); if (pluginState !== null && pluginState !== void 0 && pluginState.suppressedToolbar && !(prevPluginState !== null && prevPluginState !== void 0 && prevPluginState.suppressedToolbar)) { var _api$analytics2; api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.fireAnalyticsEvent({ action: _analytics.ACTION.SUPPRESSED, actionSubject: _analytics.ACTION_SUBJECT.FLOATING_TOOLBAR_PLUGIN, actionSubjectId: _analytics.ACTION_SUBJECT_ID.FLOATING_TOOLBAR, eventType: _analytics.EVENT_TYPE.TRACK }); } } }; } : undefined }); }