UNPKG

@atlaskit/editor-plugin-block-menu

Version:

BlockMenu plugin for @atlaskit/editor-core

248 lines (246 loc) 9.14 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import { bind } from 'bind-event-listener'; import { ACTION, ACTION_SUBJECT_ID } from '@atlaskit/editor-common/analytics'; import { BLOCK_MENU_ACTION_TEST_ID, BLOCK_MENU_TEST_ID, EXTENSION_MENU_ITEM_TEST_ID } from '@atlaskit/editor-common/block-menu'; import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckPopupMutation, ExperienceCheckTimeout, getPopupContainerFromEditorView, getSelectionAncestorDOM } from '@atlaskit/editor-common/experiences'; import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { PluginKey } from '@atlaskit/editor-prosemirror/state'; import { handleDeleteDomMutation, handleMoveDomMutation, handleTransformDomMutation, isBlockMenuVisible, isDragHandleElement } from './experience-check-utils'; var TIMEOUT_DURATION = 1000; var PORTAL_TEST_ID = { LINK_COPIED_TO_CLIPBOARD: 'link-copied-to-clipboard', SYNC_BLOCK_DELETE_CONFIRMATION: 'sync-block-delete-confirmation' }; var pluginKey = new PluginKey('blockMenuExperiences'); var START_METHOD = { DRAG_HANDLE_CLICK: 'dragHandleClick', KEYBOARD: 'keyboard' }; var ABORT_REASON = { USER_CANCELED: 'userCanceled', EDITOR_DESTROYED: 'editorDestroyed' }; export var getBlockMenuExperiencesPlugin = function getBlockMenuExperiencesPlugin(_ref) { var refs = _ref.refs, dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent; var popupTargetEl; var editorView; var getPopupsTarget = function getPopupsTarget() { if (!popupTargetEl) { var _editorView; popupTargetEl = refs.popupsMountPoint || getPopupContainerFromEditorView((_editorView = editorView) === null || _editorView === void 0 ? void 0 : _editorView.dom); } return popupTargetEl; }; var getEditorDom = function getEditorDom() { var _editorView2; if (((_editorView2 = editorView) === null || _editorView2 === void 0 ? void 0 : _editorView2.dom) instanceof HTMLElement) { return editorView.dom; } return null; }; var blockMenuOpenExperience = new Experience(EXPERIENCE_ID.MENU_OPEN, { actionSubjectId: ACTION_SUBJECT_ID.BLOCK_MENU, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckPopupMutation({ nestedElementQuery: "[data-testid=\"".concat(BLOCK_MENU_TEST_ID, "\"]"), getTarget: getPopupsTarget, type: 'editorContent' })] }); var observeConfigs = function observeConfigs() { var narrowTarget = getSelectionAncestorDOM(editorView); var editorDom = getEditorDom(); return [].concat(_toConsumableArray(narrowTarget ? [{ target: narrowTarget, options: { childList: true, subtree: true } }] : []), _toConsumableArray(editorDom ? [{ target: editorDom, options: { childList: true } }] : [])); }; var blockMoveUpExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, { action: ACTION.MOVED, actionSubjectId: ACTION_SUBJECT_ID.MOVE_UP_BLOCK, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckDomMutation({ onDomMutation: handleMoveDomMutation, observeConfig: observeConfigs })] }); var blockMoveDownExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, { action: ACTION.MOVED, actionSubjectId: ACTION_SUBJECT_ID.MOVE_DOWN_BLOCK, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckDomMutation({ onDomMutation: handleMoveDomMutation, observeConfig: observeConfigs })] }); var blockDeleteExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, { action: ACTION.DELETED, actionSubjectId: ACTION_SUBJECT_ID.DELETE_BLOCK, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckDomMutation({ onDomMutation: handleDeleteDomMutation, observeConfig: observeConfigs }), new ExperienceCheckPopupMutation({ nestedElementQuery: "[data-testid=\"".concat(PORTAL_TEST_ID.SYNC_BLOCK_DELETE_CONFIRMATION, "\"]"), type: 'portalRoot' })] }); var blockTransformExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, { action: ACTION.TRANSFORMED, actionSubjectId: ACTION_SUBJECT_ID.TRANSFORM_BLOCK, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckDomMutation({ onDomMutation: handleTransformDomMutation, observeConfig: observeConfigs })] }); var blockCopyLinkExperience = new Experience(EXPERIENCE_ID.MENU_ACTION, { action: ACTION.COPIED, actionSubjectId: ACTION_SUBJECT_ID.COPY_LINK_TO_BLOCK, dispatchAnalyticsEvent: dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckPopupMutation({ nestedElementQuery: "[data-testid=\"".concat(PORTAL_TEST_ID.LINK_COPIED_TO_CLIPBOARD, "\"]"), type: 'portalRoot' })] }); var handleMenuOpened = function handleMenuOpened(method) { // Don't start if block menu is already visible if (isBlockMenuVisible(getPopupsTarget())) { return; } blockMenuOpenExperience.start({ method: method }); }; var handleTransformActioned = function handleTransformActioned(target) { if (!target.closest('[data-testid="editor-turn-into-menu--content"]') || // Skip experience tracking when the clicked item is an extension menu item // (e.g. Jira macro, etc.) - they don't perform block transforms target.closest("[data-testid=\"".concat(EXTENSION_MENU_ITEM_TEST_ID, "\"]"))) { return false; } var turnIntoButton = target.closest('button'); if (turnIntoButton && turnIntoButton instanceof HTMLElement && !turnIntoButton.hasAttribute('disabled') && turnIntoButton.getAttribute('aria-disabled') !== 'true') { blockTransformExperience.start(); } return true; }; var handleItemActioned = function handleItemActioned(target) { if (handleTransformActioned(target)) { return; } var button = target.closest('button[data-testid]'); if (!button || !(button instanceof HTMLButtonElement) || button.disabled || button.getAttribute('aria-disabled') === 'true') { return; } var testId = button.dataset.testid; if (!testId) { return; } switch (testId) { case BLOCK_MENU_ACTION_TEST_ID.MOVE_UP: blockMoveUpExperience.start(); break; case BLOCK_MENU_ACTION_TEST_ID.MOVE_DOWN: blockMoveDownExperience.start(); break; case BLOCK_MENU_ACTION_TEST_ID.DELETE: blockDeleteExperience.start(); break; case BLOCK_MENU_ACTION_TEST_ID.COPY_LINK: blockCopyLinkExperience.start(); break; } }; var unbindClickListener = bind(document, { type: 'click', listener: function listener(event) { var target = event.target; if (!(target instanceof HTMLElement)) { return; } if (isDragHandleElement(target)) { handleMenuOpened(START_METHOD.DRAG_HANDLE_CLICK); } else { handleItemActioned(target); } }, options: { capture: true } }); var unbindKeydownListener = bind(document, { type: 'keydown', listener: function listener(event) { var target = event.target; if (!(target instanceof HTMLElement)) { return; } // Check if Enter or Space is pressed on a drag handle if ((event.key === 'Enter' || event.key === ' ') && isDragHandleElement(target)) { handleMenuOpened(START_METHOD.KEYBOARD); } // Abort on Escape key if block menu is not yet visible if (event.key === 'Escape' && !isBlockMenuVisible(getPopupsTarget())) { blockMenuOpenExperience.abort({ reason: ABORT_REASON.USER_CANCELED }); } }, options: { capture: true } }); return new SafePlugin({ key: pluginKey, view: function view(_view) { editorView = _view; return { destroy: function destroy() { blockMenuOpenExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); blockMoveUpExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); blockMoveDownExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); blockDeleteExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); blockTransformExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); blockCopyLinkExperience.abort({ reason: ABORT_REASON.EDITOR_DESTROYED }); editorView = undefined; unbindClickListener(); unbindKeydownListener(); } }; } }); };