@atlaskit/editor-plugin-layout
Version:
Layout plugin for @atlaskit/editor-core
274 lines (272 loc) • 13.4 kB
JavaScript
import React from 'react';
import { layoutColumn, layoutSection, layoutColumnWithLocalId, layoutSectionWithLocalId } from '@atlaskit/adf-schema';
import { layoutSectionWithSingleColumn, layoutSectionWithSingleColumnLocalId } from '@atlaskit/adf-schema/schema';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
import { TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM, TRANSFORM_STRUCTURE_MENU_SECTION, TRANSFORM_STRUCTURE_MENU_SECTION_RANK } from '@atlaskit/editor-common/block-menu';
import { layoutMessages, toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
import { IconFiveColumnLayout, IconFourColumnLayout, IconLayout, IconOneColumnLayout, IconThreeColumnLayout, IconTwoColumnLayout } from '@atlaskit/editor-common/quick-insert';
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
import { findParentNode } from '@atlaskit/editor-prosemirror/utils';
import { fg } from '@atlaskit/platform-feature-flags';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
var LAYOUT_SECTION_NODE_NAME = 'layoutSection';
import { createDefaultLayoutSection, createMultiColumnLayoutSection, insertLayoutColumnsWithAnalytics } from './pm-plugins/actions';
import { default as createLayoutPlugin } from './pm-plugins/main';
import { pluginKey } from './pm-plugins/plugin-key';
import { default as createLayoutResizingPlugin } from './pm-plugins/resizing';
import { GlobalStylesWrapper } from './ui/global-styles';
import { createLayoutBlockMenuItem } from './ui/LayoutBlockMenuItem';
import { buildToolbar } from './ui/toolbar';
/**
* This function is used to set the selection into
* the first paragraph of the first column of a layout section.
* This function is only intended to be used after inserting a new layout section.
* @param tr - transaction
* @returns - transaction with the selection set to the first paragraph of the first column
*/
export var selectIntoLayoutSection = function selectIntoLayoutSection(tr) {
var _nodeWithPos$node$fir;
if (!editorExperiment('single_column_layouts', true)) {
return tr;
}
var _tr$doc$type$schema$n = tr.doc.type.schema.nodes,
layoutSection = _tr$doc$type$schema$n.layoutSection,
paragraph = _tr$doc$type$schema$n.paragraph;
var nodeWithPos = findParentNode(function (node) {
return node.type === layoutSection;
})(tr.selection);
if (!nodeWithPos || !nodeWithPos.node || nodeWithPos.node.type.name !== 'layoutSection' || ((_nodeWithPos$node$fir = nodeWithPos.node.firstChild) === null || _nodeWithPos$node$fir === void 0 || (_nodeWithPos$node$fir = _nodeWithPos$node$fir.firstChild) === null || _nodeWithPos$node$fir === void 0 ? void 0 : _nodeWithPos$node$fir.type) !== paragraph) {
return tr;
}
// set text selection at the beginning of the layout section
// will set the selection to the first column
tr.setSelection(TextSelection.create(tr.doc, nodeWithPos.pos));
return tr;
};
export var layoutPlugin = function layoutPlugin(_ref) {
var _api$analytics;
var _ref$config = _ref.config,
options = _ref$config === void 0 ? {} : _ref$config,
api = _ref.api;
var allowAdvancedSingleColumnLayout = editorExperiment('advanced_layouts', true) && editorExperiment('single_column_layouts', true, {
exposure: true
});
if (editorExperiment('platform_editor_block_menu', true)) {
var _api$blockMenu;
api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 || _api$blockMenu.actions.registerBlockMenuComponents([{
type: 'block-menu-item',
key: TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key,
parent: {
type: 'block-menu-section',
key: TRANSFORM_STRUCTURE_MENU_SECTION.key,
rank: TRANSFORM_STRUCTURE_MENU_SECTION_RANK[TRANSFORM_STRUCTURE_LAYOUT_MENU_ITEM.key]
},
component: createLayoutBlockMenuItem(api),
isHidden: function isHidden() {
var _api$blockMenu2;
return Boolean(api === null || api === void 0 || (_api$blockMenu2 = api.blockMenu) === null || _api$blockMenu2 === void 0 ? void 0 : _api$blockMenu2.actions.isTransformOptionDisabled(LAYOUT_SECTION_NODE_NAME));
}
}]);
}
return {
name: 'layout',
nodes: function nodes() {
return [{
name: 'layoutSection',
node: editorExperiment('advanced_layouts', true) ? fg('platform_editor_adf_with_localid') ? layoutSectionWithSingleColumnLocalId : layoutSectionWithSingleColumn : fg('platform_editor_adf_with_localid') ? layoutSectionWithLocalId : layoutSection
}, {
name: 'layoutColumn',
node: fg('platform_editor_adf_with_localid') ? layoutColumnWithLocalId : layoutColumn
}];
},
pmPlugins: function pmPlugins() {
var plugins = [{
name: 'layout',
plugin: function plugin() {
return createLayoutPlugin(options);
}
}];
if ((options.editorAppearance === 'full-page' || options.editorAppearance === 'full-width' || options.editorAppearance === 'max' && editorExperiment('platform_editor_layout_column_resize_handle', true)) && api && editorExperiment('advanced_layouts', true)) {
plugins.push({
name: 'layoutResizing',
plugin: function plugin(_ref2) {
var portalProviderAPI = _ref2.portalProviderAPI,
eventDispatcher = _ref2.eventDispatcher;
return createLayoutResizingPlugin(options, api, portalProviderAPI, eventDispatcher);
}
});
}
return plugins;
},
actions: {
insertLayoutColumns: insertLayoutColumnsWithAnalytics(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
},
pluginsOptions: {
floatingToolbar: function floatingToolbar(state, intl) {
var _ref3 = pluginKey.getState(state),
pos = _ref3.pos,
allowBreakout = _ref3.allowBreakout,
addSidebarLayouts = _ref3.addSidebarLayouts,
allowSingleColumnLayout = _ref3.allowSingleColumnLayout,
isResizing = _ref3.isResizing;
var shouldHideToolbar = isResizing && editorExperiment('single_column_layouts', true);
if (pos !== null && !shouldHideToolbar) {
return buildToolbar(state, intl, pos, allowBreakout, addSidebarLayouts, allowSingleColumnLayout, allowAdvancedSingleColumnLayout, api);
}
return undefined;
},
quickInsert: function quickInsert(_ref4) {
var formatMessage = _ref4.formatMessage;
var withInsertLayoutAnalytics = function withInsertLayoutAnalytics(tr, columnCount) {
var _api$analytics2;
api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || (_api$analytics2 = _api$analytics2.actions) === null || _api$analytics2 === void 0 || _api$analytics2.attachAnalyticsEvent({
action: ACTION.INSERTED,
actionSubject: ACTION_SUBJECT.DOCUMENT,
actionSubjectId: ACTION_SUBJECT_ID.LAYOUT,
attributes: {
inputMethod: INPUT_METHOD.QUICK_INSERT,
columnCount: columnCount
},
eventType: EVENT_TYPE.TRACK
})(tr);
return tr;
};
var advancedSingleColumnOption = allowAdvancedSingleColumnLayout ? [{
id: 'onecolumnlayout',
title: formatMessage(layoutMessages.singleColumnAdvancedLayout),
description: formatMessage(messages.singleColumnsDescriptionAdvancedLayout),
keywords: ['layout', 'column', 'section', 'single column'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconOneColumnLayout, null);
},
action: function action(insert, state) {
var tr = insert(createMultiColumnLayoutSection(state, 1));
if (fg('platform_editor_column_count_analytics')) {
withInsertLayoutAnalytics(tr, 1);
} else {
withInsertLayoutAnalytics(tr);
}
selectIntoLayoutSection(tr);
return tr;
}
}] : [];
if (editorExperiment('advanced_layouts', true)) {
return [].concat(advancedSingleColumnOption, [{
id: 'twocolumnslayout',
title: formatMessage(layoutMessages.twoColumnsAdvancedLayout),
description: formatMessage(messages.columnsDescriptionAdvancedLayout, {
numberOfColumns: 'two'
}),
keywords: ['layout', 'column', 'section', 'two column'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconTwoColumnLayout, null);
},
action: function action(insert, state) {
var tr = insert(createMultiColumnLayoutSection(state, 2));
if (fg('platform_editor_column_count_analytics')) {
withInsertLayoutAnalytics(tr, 2);
} else {
withInsertLayoutAnalytics(tr);
}
selectIntoLayoutSection(tr);
return tr;
}
}, {
id: 'threecolumnslayout',
title: formatMessage(layoutMessages.threeColumnsAdvancedLayout),
description: formatMessage(messages.columnsDescriptionAdvancedLayout, {
numberOfColumns: 'three'
}),
keywords: ['layout', 'column', 'section', 'three column'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconThreeColumnLayout, null);
},
action: function action(insert, state) {
var tr = insert(createMultiColumnLayoutSection(state, 3));
if (fg('platform_editor_column_count_analytics')) {
withInsertLayoutAnalytics(tr, 3);
} else {
withInsertLayoutAnalytics(tr);
}
selectIntoLayoutSection(tr);
return tr;
}
}, {
id: 'fourcolumnslayout',
title: formatMessage(layoutMessages.fourColumns),
description: formatMessage(messages.columnsDescriptionAdvancedLayout, {
numberOfColumns: 'four'
}),
keywords: ['layout', 'column', 'section', 'four column'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconFourColumnLayout, null);
},
action: function action(insert, state) {
var tr = insert(createMultiColumnLayoutSection(state, 4));
if (fg('platform_editor_column_count_analytics')) {
withInsertLayoutAnalytics(tr, 4);
} else {
withInsertLayoutAnalytics(tr);
}
selectIntoLayoutSection(tr);
return tr;
}
}, {
id: 'fivecolumnslayout',
title: formatMessage(layoutMessages.fiveColumns),
description: formatMessage(messages.columnsDescriptionAdvancedLayout, {
numberOfColumns: 'five'
}),
keywords: ['layout', 'column', 'section', 'five column'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconFiveColumnLayout, null);
},
action: function action(insert, state) {
var tr = insert(createMultiColumnLayoutSection(state, 5));
if (fg('platform_editor_column_count_analytics')) {
withInsertLayoutAnalytics(tr, 5);
} else {
withInsertLayoutAnalytics(tr);
}
selectIntoLayoutSection(tr);
return tr;
}
}]);
} else {
return [{
id: 'layout',
title: formatMessage(messages.columns),
description: formatMessage(messages.columnsDescription),
keywords: ['column', 'section'],
priority: 1100,
icon: function icon() {
return /*#__PURE__*/React.createElement(IconLayout, null);
},
action: function action(insert, state) {
var _api$analytics3;
var tr = insert(createDefaultLayoutSection(state));
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || (_api$analytics3 = _api$analytics3.actions) === null || _api$analytics3 === void 0 || _api$analytics3.attachAnalyticsEvent({
action: ACTION.INSERTED,
actionSubject: ACTION_SUBJECT.DOCUMENT,
actionSubjectId: ACTION_SUBJECT_ID.LAYOUT,
attributes: {
inputMethod: INPUT_METHOD.QUICK_INSERT
},
eventType: EVENT_TYPE.TRACK
})(tr);
return tr;
}
}];
}
}
},
contentComponent: function contentComponent() {
return editorExperiment('advanced_layouts', true) ? /*#__PURE__*/React.createElement(GlobalStylesWrapper, null) : null;
}
};
};