UNPKG

@atlaskit/editor-plugin-selection-toolbar

Version:

@atlaskit/editor-plugin-selection-toolbar for @atlaskit/editor-core

400 lines (395 loc) 23.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.selectionToolbarPlugin = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _react = _interopRequireDefault(require("react")); var _bindEventListener = require("bind-event-listener"); var _analytics = require("@atlaskit/editor-common/analytics"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _utils = require("@atlaskit/editor-common/utils"); var _state = require("@atlaskit/editor-prosemirror/state"); var _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); var _experiments = require("@atlaskit/tmp-editor-statsig/experiments"); var _commands = require("./pm-plugins/commands"); var _pluginKey = require("./pm-plugins/plugin-key"); var _PageVisibilityWatcher = require("./ui/PageVisibilityWatcher"); var _pinToolbarConfig = require("./ui/pin-toolbar-config"); var _PrimaryToolbarComponent = require("./ui/PrimaryToolbarComponent"); var _toolbarComponents = require("./ui/toolbar-components"); 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 getToolbarDocking = function getToolbarDocking(contextualFormattingEnabled, userPreferencesProvider) { if (contextualFormattingEnabled && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) { var _userPreferencesProvi; return (_userPreferencesProvi = userPreferencesProvider === null || userPreferencesProvider === void 0 ? void 0 : userPreferencesProvider.getPreference('toolbarDockingInitialPosition')) !== null && _userPreferencesProvi !== void 0 ? _userPreferencesProvi : 'none'; } return 'top'; }; var getToolbarDockingV2 = function getToolbarDockingV2(contextualFormattingEnabled, dockingPreference) { if (contextualFormattingEnabled && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) { return dockingPreference !== null && dockingPreference !== void 0 ? dockingPreference : 'none'; } return 'top'; }; var selectionToolbarPlugin = exports.selectionToolbarPlugin = function selectionToolbarPlugin(_ref) { var api = _ref.api, config = _ref.config; var __selectionToolbarHandlers = []; var primaryToolbarComponent; var isToolbarAIFCEnabled = Boolean(api === null || api === void 0 ? void 0 : api.toolbar); var userPreferencesProvider = config.userPreferencesProvider, contextualFormattingEnabled = config.contextualFormattingEnabled, disablePin = config.disablePin; if (isToolbarAIFCEnabled) { var _api$toolbar; /** * If toolbar is set to always-pinned or always-inline, there is no control over toolbar placement */ if ((api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 ? void 0 : _api$toolbar.actions.contextualFormattingMode()) === 'controlled') { var _api$toolbar2; api === null || api === void 0 || (_api$toolbar2 = api.toolbar) === null || _api$toolbar2 === void 0 || _api$toolbar2.actions.registerComponents((0, _toolbarComponents.getToolbarComponents)(api, true, disablePin)); } } else { if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1', { exposure: true })) { var _api$primaryToolbar; primaryToolbarComponent = function primaryToolbarComponent(_ref2) { var disabled = _ref2.disabled; return /*#__PURE__*/_react.default.createElement(_PrimaryToolbarComponent.PrimaryToolbarComponent, { api: api, disabled: disabled }); }; api === null || api === void 0 || (_api$primaryToolbar = api.primaryToolbar) === null || _api$primaryToolbar === void 0 || _api$primaryToolbar.actions.registerComponent({ name: 'pinToolbar', component: primaryToolbarComponent }); } } var previousToolbarDocking = (userPreferencesProvider === null || userPreferencesProvider === void 0 ? void 0 : userPreferencesProvider.getPreference('toolbarDockingInitialPosition')) || null; var isPreferenceInitialized = false; return { name: 'selectionToolbar', actions: { suppressToolbar: function suppressToolbar() { var _api$core$actions$exe; return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute((0, _commands.toggleToolbar)({ hide: true }))) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false; }, unsuppressToolbar: function unsuppressToolbar() { var _api$core$actions$exe2; return (_api$core$actions$exe2 = api === null || api === void 0 ? void 0 : api.core.actions.execute((0, _commands.toggleToolbar)({ hide: false }))) !== null && _api$core$actions$exe2 !== void 0 ? _api$core$actions$exe2 : false; }, setToolbarDocking: function setToolbarDocking(toolbarDocking) { var _api$core$actions$exe4, _api$analytics; if ((0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin')) { var _api$core$actions$exe3, _api$userPreferences; return (_api$core$actions$exe3 = api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 || (_api$userPreferences = api.userPreferences) === null || _api$userPreferences === void 0 ? void 0 : _api$userPreferences.actions.updateUserPreference('toolbarDockingPosition', toolbarDocking))) !== null && _api$core$actions$exe3 !== void 0 ? _api$core$actions$exe3 : false; } return (_api$core$actions$exe4 = api === null || api === void 0 ? void 0 : api.core.actions.execute((0, _commands.setToolbarDocking)({ toolbarDocking: toolbarDocking, userPreferencesProvider: userPreferencesProvider, editorAnalyticsApi: api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions }))) !== null && _api$core$actions$exe4 !== void 0 ? _api$core$actions$exe4 : false; }, forceToolbarDockingWithoutAnalytics: function forceToolbarDockingWithoutAnalytics(toolbarDocking) { var _api$core$actions$exe6; if ((0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin')) { var _api$core$actions$exe5, _api$userPreferences2; return (_api$core$actions$exe5 = api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 || (_api$userPreferences2 = api.userPreferences) === null || _api$userPreferences2 === void 0 ? void 0 : _api$userPreferences2.actions.updateUserPreference('toolbarDockingPosition', toolbarDocking))) !== null && _api$core$actions$exe5 !== void 0 ? _api$core$actions$exe5 : false; } return (_api$core$actions$exe6 = api === null || api === void 0 ? void 0 : api.core.actions.execute((0, _commands.forceToolbarDockingWithoutAnalytics)({ toolbarDocking: toolbarDocking, userPreferencesProvider: userPreferencesProvider }))) !== null && _api$core$actions$exe6 !== void 0 ? _api$core$actions$exe6 : false; }, refreshToolbarDocking: function refreshToolbarDocking() { if (userPreferencesProvider) { var _api$core$actions$exe7; var userToolbarDockingPref = getToolbarDocking(contextualFormattingEnabled, userPreferencesProvider); return (_api$core$actions$exe7 = api === null || api === void 0 ? void 0 : api.core.actions.execute((0, _commands.updateToolbarDocking)({ toolbarDocking: userToolbarDockingPref }))) !== null && _api$core$actions$exe7 !== void 0 ? _api$core$actions$exe7 : false; } return false; } }, getSharedState: function getSharedState(editorState) { if (!editorState) { return; } return _pluginKey.selectionToolbarPluginKey.getState(editorState); }, pmPlugins: function pmPlugins(selectionToolbarHandlers) { var _api$userPreferences3; if (selectionToolbarHandlers) { __selectionToolbarHandlers.push.apply(__selectionToolbarHandlers, (0, _toConsumableArray2.default)(selectionToolbarHandlers)); } var initialToolbarDocking = (0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin') ? getToolbarDockingV2(contextualFormattingEnabled, api === null || api === void 0 || (_api$userPreferences3 = api.userPreferences) === null || _api$userPreferences3 === void 0 || (_api$userPreferences3 = _api$userPreferences3.sharedState.currentState()) === null || _api$userPreferences3 === void 0 || (_api$userPreferences3 = _api$userPreferences3.preferences) === null || _api$userPreferences3 === void 0 ? void 0 : _api$userPreferences3.toolbarDockingPosition) : getToolbarDocking(contextualFormattingEnabled, userPreferencesProvider); return [{ name: 'selection-tracker', plugin: function plugin() { return new _safePlugin.SafePlugin({ key: _pluginKey.selectionToolbarPluginKey, state: { init: function init() { return { selectionStable: false, hide: false, toolbarDocking: initialToolbarDocking }; }, apply: function apply(tr, pluginState) { var meta = tr.getMeta(_pluginKey.selectionToolbarPluginKey); var newPluginState = pluginState; if (meta) { return _objectSpread(_objectSpread({}, newPluginState), meta); } if ((0, _experiments.editorExperiment)('platform_editor_block_menu', true)) { var _api$userIntent; var isBlockMenuOpen = (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) === 'blockMenuOpen'; newPluginState = _objectSpread(_objectSpread({}, newPluginState), {}, { isBlockMenuOpen: isBlockMenuOpen }); } // if the toolbarDockingInitialPosition preference has changed // update the toolbarDocking state if (!previousToolbarDocking) { // we currently only check for the initial value var toolbarDockingPreference = userPreferencesProvider === null || userPreferencesProvider === void 0 ? void 0 : userPreferencesProvider.getPreference('toolbarDockingInitialPosition'); if (toolbarDockingPreference && toolbarDockingPreference !== previousToolbarDocking) { previousToolbarDocking = toolbarDockingPreference; var userToolbarDockingPref = getToolbarDocking(contextualFormattingEnabled, userPreferencesProvider); if (pluginState.toolbarDocking !== userToolbarDockingPref) { return _objectSpread(_objectSpread({}, newPluginState), {}, { toolbarDocking: userToolbarDockingPref }); } } } return newPluginState; } }, view: function view(_view) { var unbind = (0, _bindEventListener.bind)(_view.root, { type: 'mouseup', listener: function listener(event) { var _api$editorViewMode; // We only want to set selectionStable to true if the editor has focus // to prevent the toolbar from showing when the editor is blurred // due to a click outside the editor. var editorViewModePlugin = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.sharedState.currentState(); var isViewModeEnabled = (editorViewModePlugin === null || editorViewModePlugin === void 0 ? void 0 : editorViewModePlugin.mode) === 'view'; var target = event.target; if (target && target instanceof Element) { var isRovoChangeToneButton = target.tagName === 'BUTTON' && _hasNestedSpanWithText(target, 'Change tone') || target.getAttribute('aria-label') === 'Change tone' || target.innerHTML === 'Change tone'; var isRovoTranslateButton = target.tagName === 'BUTTON' && _hasNestedSpanWithText(target, 'Translate options') || target.getAttribute('aria-label') === 'Translate options' || target.innerHTML === 'Translate options'; if (isRovoChangeToneButton || isRovoTranslateButton) { return null; } } _view.dispatch(_view.state.tr.setMeta(_pluginKey.selectionToolbarPluginKey, { selectionStable: !isViewModeEnabled ? _view.hasFocus() : true })); } }); var unbindEditorViewFocus = (0, _bindEventListener.bind)(_view.dom, { type: 'focus', listener: function listener() { _view.dispatch(_view.state.tr.setMeta(_pluginKey.selectionToolbarPluginKey, { selectionStable: true })); } }); return { destroy: function destroy() { unbind(); unbindEditorViewFocus(); } }; }, appendTransaction: function appendTransaction(_transactions, _oldState, newState) { if ((0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin')) { return null; } if (!isPreferenceInitialized && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) { var toolbarDockingPreference = userPreferencesProvider === null || userPreferencesProvider === void 0 ? void 0 : userPreferencesProvider.getPreference('toolbarDockingInitialPosition'); if (toolbarDockingPreference !== undefined) { var _api$analytics2; isPreferenceInitialized = true; var userToolbarDockingPref = getToolbarDocking(contextualFormattingEnabled, userPreferencesProvider); var tr = newState.tr; api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.attachAnalyticsEvent({ action: _analytics.ACTION.INITIALISED, actionSubject: _analytics.ACTION_SUBJECT.USER_PREFERENCES, actionSubjectId: _analytics.ACTION_SUBJECT_ID.SELECTION_TOOLBAR_PREFERENCES, attributes: { toolbarDocking: userToolbarDockingPref }, eventType: _analytics.EVENT_TYPE.OPERATIONAL })(tr); return tr; } } return null; }, props: { handleDOMEvents: { mousedown: function mousedown(view) { view.dispatch(view.state.tr.setMeta(_pluginKey.selectionToolbarPluginKey, { selectionStable: false })); return false; } } } }); } }]; }, pluginsOptions: isToolbarAIFCEnabled ? {} : { floatingToolbar: function floatingToolbar(state, intl, providerFactory) { var _ref3 = _pluginKey.selectionToolbarPluginKey.getState(state), selectionStable = _ref3.selectionStable, hide = _ref3.hide, toolbarDocking = _ref3.toolbarDocking, isBlockMenuOpen = _ref3.isBlockMenuOpen; var isCellSelection = ('$anchorCell' in state.selection); var isEditorControlsEnabled = (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1'); if (state.selection.empty || !selectionStable || hide || state.selection instanceof _state.NodeSelection || // $anchorCell is only available in CellSelection, this check is to // avoid importing CellSelection from @atlaskit/editor-tables isCellSelection && !isEditorControlsEnabled // for Editor Controls we want to show the toolbar on CellSelection ) { // If there is no active selection, or the selection is not stable, or the selection is a node selection, // do not show the toolbar. return; } if (isCellSelection && isEditorControlsEnabled) { var _api$blockControls; var isSelectedViaDragHandle = api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || (_api$blockControls = _api$blockControls.sharedState.currentState()) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.isSelectedViaDragHandle; if (isSelectedViaDragHandle) { return; } } if (isBlockMenuOpen && isEditorControlsEnabled && (0, _experiments.editorExperiment)('platform_editor_block_menu', true)) { // If the block menu is open, do not show the selection toolbar. return; } // Resolve the selectionToolbarHandlers to a list of SelectionToolbarGroups // and filter out any handlers which returned undefined var resolved = __selectionToolbarHandlers.map(function (selectionToolbarHandler) { return selectionToolbarHandler(state, intl, providerFactory); }).filter(function (resolved) { return resolved !== undefined; }); // Sort the groups by rank // This is intended to allow different plugins to control the order of the groups // they add to the selection toolbar. // ie. if you want to have your plugin's group appear first, set rank to -10 if there is currently another // plugin you expect to be run at the same time as with an rank of -9 resolved.sort(function (_ref4, _ref5) { var _ref4$rank = _ref4.rank, rankA = _ref4$rank === void 0 ? 0 : _ref4$rank; var _ref5$rank = _ref5.rank, rankB = _ref5$rank === void 0 ? 0 : _ref5$rank; if (rankA < rankB) { return 1; } return -1; }); var items = []; // This flattens the groups passed into the floating toolbar into a single list of items for (var i = 0; i < resolved.length; i++) { var _resolved$i; // add a seperator icon after each group except the last if (Array.isArray((_resolved$i = resolved[i]) === null || _resolved$i === void 0 ? void 0 : _resolved$i.items)) { items.push.apply(items, (0, _toConsumableArray2.default)(resolved[i].items)); } if ((0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) { if (resolved[i] && resolved[i + 1]) { var _resolved; if (((_resolved = resolved[i + 1]) === null || _resolved === void 0 ? void 0 : _resolved.pluginName) === 'annotation') { items.push({ type: 'separator', fullHeight: true }); } } } else { if (i !== resolved.length - 1) { items.push({ type: 'separator' }); } } } if (items.length > 0 && contextualFormattingEnabled && isEditorControlsEnabled) { var _api$userPreferences4; var toolbarDockingPref = api !== null && api !== void 0 && api.userPreferences && (0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin') ? api === null || api === void 0 || (_api$userPreferences4 = api.userPreferences) === null || _api$userPreferences4 === void 0 || (_api$userPreferences4 = _api$userPreferences4.sharedState.currentState()) === null || _api$userPreferences4 === void 0 || (_api$userPreferences4 = _api$userPreferences4.preferences) === null || _api$userPreferences4 === void 0 ? void 0 : _api$userPreferences4.toolbarDockingPosition : toolbarDocking; items.push.apply(items, (0, _toConsumableArray2.default)((0, _pinToolbarConfig.getPinOptionToolbarConfig)({ api: api, toolbarDocking: toolbarDockingPref, intl: intl }))); } var onPositionCalculated; var toolbarTitle = 'Selection toolbar'; if (isCellSelection && isEditorControlsEnabled) { onPositionCalculated = (0, _utils.calculateToolbarPositionOnCellSelection)(toolbarTitle); } else { var calcToolbarPosition = config.preferenceToolbarAboveSelection ? _utils.calculateToolbarPositionAboveSelection : _utils.calculateToolbarPositionTrackHead; onPositionCalculated = calcToolbarPosition(toolbarTitle); } var nodeType = getSelectionNodeTypes(state); return _objectSpread(_objectSpread({ title: 'Selection toolbar', nodeType: nodeType, items: items }, isEditorControlsEnabled && { scrollable: true }), {}, { onPositionCalculated: onPositionCalculated }); } }, contentComponent: (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1') && !(0, _platformFeatureFlags.fg)('platform_editor_use_preferences_plugin') && (0, _platformFeatureFlags.fg)('platform_editor_user_preferences_provider_update') ? function () { return /*#__PURE__*/_react.default.createElement(_PageVisibilityWatcher.PageVisibilityWatcher, { api: api, userPreferencesProvider: userPreferencesProvider }); } : undefined, primaryToolbarComponent: !(api !== null && api !== void 0 && api.primaryToolbar) && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1', { exposure: true }) ? primaryToolbarComponent : undefined }; }; function getSelectionNodeTypes(state) { var selectionNodeTypes = []; state.doc.nodesBetween(state.selection.from, state.selection.to, function (node) { if (selectionNodeTypes.indexOf(node.type) !== 0) { selectionNodeTypes.push(node.type); } }); return selectionNodeTypes; } var _hasNestedSpanWithText = function hasNestedSpanWithText(element, text) { if (element.tagName === 'SPAN' && element.innerHTML === text) { return true; } for (var _i = 0, _Array$from = Array.from(element.children); _i < _Array$from.length; _i++) { var child = _Array$from[_i]; if (_hasNestedSpanWithText(child, text)) { return true; } } return false; };