@atlaskit/editor-plugin-insert-block
Version:
Insert block plugin for @atlaskit/editor-core
181 lines • 6.02 kB
JavaScript
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();
}
};
}
});
};