UNPKG

@atlaskit/editor-plugin-toolbar

Version:

Toolbar plugin for @atlaskit/editor-core

194 lines (193 loc) 7.13 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 _platformFeatureFlags = require("@atlaskit/platform-feature-flags"); 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' }; /** * 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; var editorView; var targetEl; var shiftArrowKeyPressed = false; var mouseDownPos; 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 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; if (isBlockMenuWithinNode(getTarget())) { return { status: 'abort', reason: ABORT_REASON.BLOCK_MENU_OPENED }; } else if (isSelectionWithoutTextContent((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.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)) { return true; } var target = getTarget(); return isSelectionToolbarWithinNode(target) || isBlockMenuWithinNode(target) && (0, _platformFeatureFlags.fg)('platform_editor_toolbar_open_experience_fix'); }; 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 }); } if (shiftArrowKeyPressed && !newState.selection.eq(oldState.selection) && !isSelectionWithoutTextContent(newState.selection)) { 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 }; }, mouseup: function mouseup(view, e) { if (!mouseDownPos || shouldSkipExperienceStart(view.state.selection)) { return; } if (e.clientX !== mouseDownPos.x || e.clientY !== mouseDownPos.y) { 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, _ref3) { var shiftKey = _ref3.shiftKey, key = _ref3.key; shiftArrowKeyPressed = shiftKey && 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(_ref4) { var type = _ref4.type, addedNodes = _ref4.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'; };