UNPKG

@atlaskit/editor-plugin-toolbar

Version:

Toolbar plugin for @atlaskit/editor-core

224 lines (223 loc) 8.81 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getSelectionToolbarOpenExperiencePlugin = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _analytics = require("@atlaskit/editor-common/analytics"); var _experiences = require("@atlaskit/editor-common/experiences"); var _safePlugin = require("@atlaskit/editor-common/safe-plugin"); var _state = require("@atlaskit/editor-prosemirror/state"); var _fg = require("@atlaskit/platform-feature-flags/fg"); var _visibility = require("../../ui/SelectionToolbar/visibility"); var pluginKey = new _state.PluginKey('selectionToolbarOpenExperience'); var START_METHOD = { MOUSE_UP: 'mouseUp', KEY_DOWN: 'keyDown' }; var ABORT_REASON = { SELECTION_CLEARED: 'selectionCleared', BLOCK_MENU_OPENED: 'blockMenuOpened', EDITOR_DESTROYED: 'editorDestroyed', USER_INTENT_SUPPRESSED: 'userIntentSuppressed' }; /** * This experience tracks when the selection toolbar is opened. * * Start: When user makes a selection via mouseup or shift+arrow key down * Success: When the selection toolbar is added to the DOM within 1000ms of start * Failure: When 1000ms passes without the selection toolbar being added to the DOM * Abort: When selection transitions to empty or block menu is opened * * @see https://hello.atlassian.net/wiki/spaces/EDITOR/pages/6262117789/Experience+tracking+Selection+toolbar+open */ var getSelectionToolbarOpenExperiencePlugin = exports.getSelectionToolbarOpenExperiencePlugin = function getSelectionToolbarOpenExperiencePlugin(_ref) { var refs = _ref.refs, dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent, getCurrentUserIntent = _ref.getCurrentUserIntent; var isIntentFixEnabled = (0, _fg.fg)('platform_editor_toolbar_intent_fix'); var editorView; var targetEl; var shiftArrowKeyPressed = false; var mouseDownPos; var mouseDownSelection; var getTarget = function getTarget() { if (!targetEl) { var _editorView; targetEl = refs.popupsMountPoint || (0, _experiences.getPopupContainerFromEditorView)((_editorView = editorView) === null || _editorView === void 0 ? void 0 : _editorView.dom); } return targetEl; }; var isCurrentUserIntentSuppressingToolbar = function isCurrentUserIntentSuppressingToolbar(selection) { if (!selection) { return false; } var isCellSelection = !selection.empty && '$anchorCell' in selection; return (0, _visibility.isSelectionToolbarSuppressedByUserIntent)(getCurrentUserIntent === null || getCurrentUserIntent === void 0 ? void 0 : getCurrentUserIntent(), isCellSelection); }; var experience = new _experiences.Experience(_experiences.EXPERIENCE_ID.TOOLBAR_OPEN, { actionSubjectId: _analytics.ACTION_SUBJECT_ID.SELECTION_TOOLBAR, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new _experiences.ExperienceCheckTimeout({ durationMs: 1000, onTimeout: function onTimeout() { var _editorView2, _editorView3; if (isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.state.selection)) { return { status: 'abort', reason: ABORT_REASON.USER_INTENT_SUPPRESSED }; } else if (isBlockMenuWithinNode(getTarget())) { return { status: 'abort', reason: ABORT_REASON.BLOCK_MENU_OPENED }; } else if (isSelectionWithoutTextContent((_editorView3 = editorView) === null || _editorView3 === void 0 ? void 0 : _editorView3.state.selection)) { return { status: 'abort', reason: ABORT_REASON.SELECTION_CLEARED }; } } }), new _experiences.ExperienceCheckDomMutation({ onDomMutation: function onDomMutation(_ref2) { var mutations = _ref2.mutations; if (mutations.some(isSelectionToolbarAddedInMutation)) { return { status: 'success' }; } }, observeConfig: function observeConfig() { return { target: getTarget(), options: { childList: true } }; } })] }); var shouldSkipExperienceStart = function shouldSkipExperienceStart(selection) { if (isSelectionWithoutTextContent(selection) || isSelectionWithinCodeBlock(selection) || isIntentFixEnabled && isCurrentUserIntentSuppressingToolbar(selection)) { return true; } var target = getTarget(); if (!target) { // when target is not found, skip the experience start return true; } return isSelectionToolbarWithinNode(target) || isBlockMenuWithinNode(target); }; return new _safePlugin.SafePlugin({ key: pluginKey, state: { init: function init() { return {}; }, apply: function apply(_tr, pluginState, oldState, newState) { if (!oldState.selection.empty && isSelectionWithoutTextContent(newState.selection)) { experience.abort({ reason: ABORT_REASON.SELECTION_CLEARED }); } var shouldStartExperience = shiftArrowKeyPressed && !newState.selection.eq(oldState.selection) && !shouldSkipExperienceStart(newState.selection); if (shouldStartExperience) { experience.start({ method: START_METHOD.KEY_DOWN }); shiftArrowKeyPressed = false; } return pluginState; } }, props: { handleDOMEvents: { mousedown: function mousedown(view, e) { mouseDownPos = { x: e.clientX, y: e.clientY }; if (isIntentFixEnabled) { mouseDownSelection = view.state.selection; } }, mouseup: function mouseup(view, e) { var initialMouseDownPos = mouseDownPos; var selectionChanged = (0, _visibility.hasSelectionChanged)(mouseDownSelection, view.state.selection); if (isIntentFixEnabled) { mouseDownPos = undefined; mouseDownSelection = undefined; } if (!initialMouseDownPos || shouldSkipExperienceStart(view.state.selection)) { return; } var mouseCoordinatesChanged = e.clientX !== initialMouseDownPos.x || e.clientY !== initialMouseDownPos.y; if (mouseCoordinatesChanged && (!isIntentFixEnabled || selectionChanged)) { experience.start({ method: START_METHOD.MOUSE_UP }); } }, dblclick: function dblclick(view) { if (shouldSkipExperienceStart(view.state.selection)) { return; } experience.start({ method: START_METHOD.MOUSE_UP }); }, keydown: function keydown(_view, event) { shiftArrowKeyPressed = (isIntentFixEnabled ? (0, _visibility.isPlainShiftArrowKey)(event) : event.shiftKey && event.key.includes('Arrow')) && !isSelectionToolbarWithinNode(getTarget()); }, keyup: function keyup() { shiftArrowKeyPressed = false; } } }, view: function view(_view2) { editorView = _view2; return { destroy: function destroy() { experience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); } }; } }); }; var isSelectionToolbarAddedInMutation = function isSelectionToolbarAddedInMutation(_ref3) { var type = _ref3.type, addedNodes = _ref3.addedNodes; return type === 'childList' && (0, _toConsumableArray2.default)(addedNodes).some(isSelectionToolbarWithinNode); }; var isSelectionToolbarWithinNode = function isSelectionToolbarWithinNode(node) { return (0, _experiences.containsPopupWithNestedElement)(node, '[data-testid="editor-floating-toolbar"]'); }; var isBlockMenuWithinNode = function isBlockMenuWithinNode(node) { return (0, _experiences.containsPopupWithNestedElement)(node, '[data-testid="editor-block-menu"]'); }; var isSelectionWithoutTextContent = function isSelectionWithoutTextContent(selection) { if (!selection || selection.empty) { return true; } var hasText = false; selection.$from.doc.nodesBetween(selection.from, selection.to, function (node) { if (hasText) { return false; } if (node.isText && node.text && node.text.length > 0) { hasText = true; return false; } return true; }); return !hasText; }; var isSelectionWithinCodeBlock = function isSelectionWithinCodeBlock(selection) { var $from = selection.$from, $to = selection.$to; return $from.sameParent($to) && $from.parent.type.name === 'codeBlock'; };