UNPKG

@atlaskit/editor-plugin-insert-block

Version:

Insert block plugin for @atlaskit/editor-core

181 lines 6.02 kB
import { bind } from 'bind-event-listener'; import { getDocument } from '@atlaskit/browser-apis'; import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckPopupMutation, ExperienceCheckTimeout, getSelectionAncestorDOM } from '@atlaskit/editor-common/experiences'; import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { TOOLBAR_BUTTON_TEST_ID } from '@atlaskit/editor-common/toolbar'; import { PluginKey } from '@atlaskit/editor-prosemirror/state'; import { handleEditorNodeInsertDomMutation, isToolbarButtonClick } from './toolbar-experience-utils'; const pluginKey = new PluginKey('toolbarActionExperiences'); const TIMEOUT_DURATION = 1000; const PRIMARY_TOOLBAR = 'primaryToolbar'; const ABORT_REASON = { USER_CANCELED: 'userCanceled', EDITOR_DESTROYED: 'editorDestroyed' }; export const getToolbarActionExperiencesPlugin = ({ dispatchAnalyticsEvent }) => { let editorView; let lastClickedToolbarButton; const getEditorDom = () => { var _editorView; if (((_editorView = editorView) === null || _editorView === void 0 ? void 0 : _editorView.dom) instanceof HTMLElement) { return editorView.dom; } return null; }; const getInlinePopupTarget = () => { var _lastClickedToolbarBu; if (!lastClickedToolbarButton) { return undefined; } return (_lastClickedToolbarBu = lastClickedToolbarButton.closest('[data-toolbar-component="button-group"]')) !== null && _lastClickedToolbarBu !== void 0 ? _lastClickedToolbarBu : lastClickedToolbarButton; }; const observeConfigs = () => { const narrowTarget = getSelectionAncestorDOM(editorView); const editorDom = getEditorDom(); return [...(narrowTarget ? [{ target: narrowTarget, options: { childList: true, subtree: true } }] : []), ...(editorDom ? [{ target: editorDom, options: { childList: true } }] : [])]; }; const createNodeInsertExperience = action => new Experience(EXPERIENCE_ID.TOOLBAR_ACTION, { action, actionSubjectId: PRIMARY_TOOLBAR, dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckDomMutation({ onDomMutation: handleEditorNodeInsertDomMutation, observeConfig: observeConfigs })] }); const buildPopupMutationConfig = (popupSelector, type) => { switch (type) { case 'inline': return { type, nestedElementQuery: popupSelector, getTarget: getInlinePopupTarget, subtree: true }; case 'editorRoot': return { type, nestedElementQuery: popupSelector, getEditorDom }; } }; const createPopupExperience = (action, popupSelector, type) => new Experience(EXPERIENCE_ID.TOOLBAR_ACTION, { action, actionSubjectId: PRIMARY_TOOLBAR, dispatchAnalyticsEvent, checks: [new ExperienceCheckTimeout({ durationMs: TIMEOUT_DURATION }), new ExperienceCheckPopupMutation(buildPopupMutationConfig(popupSelector, type))] }); const experienceButtonMappings = [{ experience: createPopupExperience('insert', '[data-testid="popup-wrapper"]', 'inline'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.INSERT }, { experience: createPopupExperience('emoji', '[data-emoji-picker-container], [data-emoji-picker-container="true"], [data-testid="popup-wrapper"]', 'inline'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.EMOJI }, { experience: createPopupExperience('media', '[data-testid="popup-wrapper"]', 'inline'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.MEDIA }, { experience: createPopupExperience('mention', '[data-testid="popup-wrapper"], [data-type-ahead="typeaheadDecoration"]', 'editorRoot'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.MENTION }, { experience: createNodeInsertExperience('table'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.TABLE }, { experience: createPopupExperience('tableSelector', '[data-testid="popup-wrapper"]', 'inline'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.TABLE_SELECTOR }, { experience: createNodeInsertExperience('layout'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.LAYOUT }, { experience: createPopupExperience('image', '[data-testid="popup-wrapper"]', 'inline'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.IMAGE }, { experience: createNodeInsertExperience('action'), buttonTestId: TOOLBAR_BUTTON_TEST_ID.TASK_LIST }]; const handleToolbarButtonClick = target => { for (const { experience, buttonTestId } of experienceButtonMappings) { if (isToolbarButtonClick(target, buttonTestId)) { // Store the clicked button so inline popup checks can find its button-group lastClickedToolbarButton = target; experience.start({ forceRestart: true }); return; } } }; const abortAllExperiences = reason => { for (const { experience } of experienceButtonMappings) { experience.abort({ reason }); } }; const doc = getDocument(); if (!doc) { return new SafePlugin({ key: pluginKey }); } const unbindClickListener = bind(doc, { type: 'click', listener: event => { const target = event.target; if (target instanceof HTMLElement) { handleToolbarButtonClick(target); } }, options: { capture: true } }); const unbindKeydownListener = bind(doc, { type: 'keydown', listener: event => { if (event.key === 'Escape') { abortAllExperiences(ABORT_REASON.USER_CANCELED); } }, options: { capture: true } }); return new SafePlugin({ key: pluginKey, view: view => { editorView = view; return { destroy: () => { abortAllExperiences(ABORT_REASON.EDITOR_DESTROYED); editorView = undefined; unbindClickListener(); unbindKeydownListener(); } }; } }); };