@atlaskit/editor-plugin-block-menu
Version:
BlockMenu plugin for @atlaskit/editor-core
248 lines (246 loc) • 9.14 kB
JavaScript
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();
}
};
}
});
};