@atlaskit/editor-plugin-layout 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE.md +13 -0
  3. package/README.md +30 -0
  4. package/dist/cjs/actions.js +345 -0
  5. package/dist/cjs/index.js +12 -0
  6. package/dist/cjs/plugin.js +91 -0
  7. package/dist/cjs/pm-plugins/main.js +148 -0
  8. package/dist/cjs/pm-plugins/plugin-key.js +8 -0
  9. package/dist/cjs/pm-plugins/types.js +5 -0
  10. package/dist/cjs/toolbar.js +118 -0
  11. package/dist/cjs/types.js +5 -0
  12. package/dist/es2019/actions.js +328 -0
  13. package/dist/es2019/index.js +1 -0
  14. package/dist/es2019/plugin.js +75 -0
  15. package/dist/es2019/pm-plugins/main.js +142 -0
  16. package/dist/es2019/pm-plugins/plugin-key.js +2 -0
  17. package/dist/es2019/pm-plugins/types.js +1 -0
  18. package/dist/es2019/toolbar.js +100 -0
  19. package/dist/es2019/types.js +1 -0
  20. package/dist/esm/actions.js +336 -0
  21. package/dist/esm/index.js +1 -0
  22. package/dist/esm/plugin.js +79 -0
  23. package/dist/esm/pm-plugins/main.js +141 -0
  24. package/dist/esm/pm-plugins/plugin-key.js +2 -0
  25. package/dist/esm/pm-plugins/types.js +1 -0
  26. package/dist/esm/toolbar.js +108 -0
  27. package/dist/esm/types.js +1 -0
  28. package/dist/types/actions.d.ts +22 -0
  29. package/dist/types/index.d.ts +3 -0
  30. package/dist/types/plugin.d.ts +15 -0
  31. package/dist/types/pm-plugins/main.d.ts +6 -0
  32. package/dist/types/pm-plugins/plugin-key.d.ts +3 -0
  33. package/dist/types/pm-plugins/types.d.ts +14 -0
  34. package/dist/types/toolbar.d.ts +6 -0
  35. package/dist/types/types.d.ts +13 -0
  36. package/dist/types-ts4.5/actions.d.ts +22 -0
  37. package/dist/types-ts4.5/index.d.ts +3 -0
  38. package/dist/types-ts4.5/plugin.d.ts +18 -0
  39. package/dist/types-ts4.5/pm-plugins/main.d.ts +6 -0
  40. package/dist/types-ts4.5/pm-plugins/plugin-key.d.ts +3 -0
  41. package/dist/types-ts4.5/pm-plugins/types.d.ts +14 -0
  42. package/dist/types-ts4.5/toolbar.d.ts +6 -0
  43. package/dist/types-ts4.5/types.d.ts +13 -0
  44. package/package.json +94 -0
  45. package/report.api.md +73 -0
  46. package/tmp/api-report-tmp.d.ts +43 -0
@@ -0,0 +1,100 @@
1
+ import commonMessages, { layoutMessages as toolbarMessages } from '@atlaskit/editor-common/messages';
2
+ import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
3
+ import EditorLayoutSingleIcon from '@atlaskit/icon/glyph/editor/layout-single';
4
+ import LayoutThreeEqualIcon from '@atlaskit/icon/glyph/editor/layout-three-equal';
5
+ import LayoutThreeWithSidebarsIcon from '@atlaskit/icon/glyph/editor/layout-three-with-sidebars';
6
+ import LayoutTwoEqualIcon from '@atlaskit/icon/glyph/editor/layout-two-equal';
7
+ import LayoutTwoLeftSidebarIcon from '@atlaskit/icon/glyph/editor/layout-two-left-sidebar';
8
+ import LayoutTwoRightSidebarIcon from '@atlaskit/icon/glyph/editor/layout-two-right-sidebar';
9
+ import RemoveIcon from '@atlaskit/icon/glyph/editor/remove';
10
+ import { deleteActiveLayoutNode, getPresetLayout, setPresetLayout } from './actions';
11
+ const LAYOUT_TYPES = [{
12
+ id: 'editor.layout.twoEquals',
13
+ type: 'two_equal',
14
+ title: toolbarMessages.twoColumns,
15
+ icon: LayoutTwoEqualIcon
16
+ }, {
17
+ id: 'editor.layout.threeEquals',
18
+ type: 'three_equal',
19
+ title: toolbarMessages.threeColumns,
20
+ icon: LayoutThreeEqualIcon
21
+ }];
22
+ const LAYOUT_TYPES_WITH_SINGLE_COL = [{
23
+ id: 'editor.layout.singeLayout',
24
+ type: 'single',
25
+ title: toolbarMessages.singleColumn,
26
+ icon: EditorLayoutSingleIcon
27
+ }, ...LAYOUT_TYPES];
28
+ const SIDEBAR_LAYOUT_TYPES = [{
29
+ id: 'editor.layout.twoRightSidebar',
30
+ type: 'two_right_sidebar',
31
+ title: toolbarMessages.rightSidebar,
32
+ icon: LayoutTwoRightSidebarIcon
33
+ }, {
34
+ id: 'editor.layout.twoLeftSidebar',
35
+ type: 'two_left_sidebar',
36
+ title: toolbarMessages.leftSidebar,
37
+ icon: LayoutTwoLeftSidebarIcon
38
+ }, {
39
+ id: 'editor.layout.threeWithSidebars',
40
+ type: 'three_with_sidebars',
41
+ title: toolbarMessages.threeColumnsWithSidebars,
42
+ icon: LayoutThreeWithSidebarsIcon
43
+ }];
44
+ const buildLayoutButton = (intl, item, currentLayout, editorAnalyticsAPI) => ({
45
+ id: item.id,
46
+ type: 'button',
47
+ icon: item.icon,
48
+ testId: item.title.id ? `${item.title.id}` : undefined,
49
+ title: intl.formatMessage(item.title),
50
+ onClick: setPresetLayout(editorAnalyticsAPI)(item.type),
51
+ selected: !!currentLayout && currentLayout === item.type,
52
+ tabIndex: null
53
+ });
54
+ export const layoutToolbarTitle = 'Layout floating controls';
55
+ export const buildToolbar = (state, intl, pos, _allowBreakout, addSidebarLayouts, allowSingleColumnLayout, api) => {
56
+ var _api$decorations$acti, _api$decorations, _api$analytics;
57
+ const {
58
+ hoverDecoration
59
+ } = (_api$decorations$acti = api === null || api === void 0 ? void 0 : (_api$decorations = api.decorations) === null || _api$decorations === void 0 ? void 0 : _api$decorations.actions) !== null && _api$decorations$acti !== void 0 ? _api$decorations$acti : {};
60
+ const editorAnalyticsAPI = api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
61
+ const node = state.doc.nodeAt(pos);
62
+ if (node) {
63
+ const currentLayout = getPresetLayout(node);
64
+ const separator = {
65
+ type: 'separator'
66
+ };
67
+ const nodeType = state.schema.nodes.layoutSection;
68
+ const deleteButton = {
69
+ id: 'editor.layout.delete',
70
+ type: 'button',
71
+ appearance: 'danger',
72
+ focusEditoronEnter: true,
73
+ icon: RemoveIcon,
74
+ testId: commonMessages.remove.id,
75
+ title: intl.formatMessage(commonMessages.remove),
76
+ onClick: deleteActiveLayoutNode(editorAnalyticsAPI),
77
+ onMouseEnter: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, true),
78
+ onMouseLeave: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, false),
79
+ onFocus: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, true),
80
+ onBlur: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, false),
81
+ tabIndex: null
82
+ };
83
+ const layoutTypes = allowSingleColumnLayout ? LAYOUT_TYPES_WITH_SINGLE_COL : LAYOUT_TYPES;
84
+ return {
85
+ title: layoutToolbarTitle,
86
+ getDomRef: view => findDomRefAtPos(pos, view.domAtPos.bind(view)),
87
+ nodeType,
88
+ items: [...layoutTypes.map(i => buildLayoutButton(intl, i, currentLayout, editorAnalyticsAPI)), ...(addSidebarLayouts ? SIDEBAR_LAYOUT_TYPES.map(i => buildLayoutButton(intl, i, currentLayout, editorAnalyticsAPI)) : []), {
89
+ type: 'copy-button',
90
+ items: [separator, {
91
+ state,
92
+ formatMessage: intl.formatMessage,
93
+ nodeType
94
+ }]
95
+ }, separator, deleteButton],
96
+ scrollable: true
97
+ };
98
+ }
99
+ return;
100
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,336 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, LAYOUT_TYPE } from '@atlaskit/editor-common/analytics';
5
+ import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
6
+ import { flatmap, getStepRange, isEmptyDocument, mapChildren } from '@atlaskit/editor-common/utils';
7
+ import { Fragment, Slice } from '@atlaskit/editor-prosemirror/model';
8
+ import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
9
+ import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
10
+ import { pluginKey } from './pm-plugins/plugin-key';
11
+ export var ONE_COL_LAYOUTS = ['single'];
12
+ export var TWO_COL_LAYOUTS = ['two_equal', 'two_left_sidebar', 'two_right_sidebar'];
13
+ export var THREE_COL_LAYOUTS = ['three_equal', 'three_with_sidebars'];
14
+ var getWidthsForPreset = function getWidthsForPreset(presetLayout) {
15
+ switch (presetLayout) {
16
+ case 'single':
17
+ return [100];
18
+ case 'two_equal':
19
+ return [50, 50];
20
+ case 'three_equal':
21
+ return [33.33, 33.33, 33.33];
22
+ case 'two_left_sidebar':
23
+ return [33.33, 66.66];
24
+ case 'two_right_sidebar':
25
+ return [66.66, 33.33];
26
+ case 'three_with_sidebars':
27
+ return [25, 50, 25];
28
+ }
29
+ };
30
+
31
+ /**
32
+ * Finds layout preset based on the width attrs of all the layoutColumn nodes
33
+ * inside the layoutSection node
34
+ */
35
+ export var getPresetLayout = function getPresetLayout(section) {
36
+ var widths = mapChildren(section, function (column) {
37
+ return column.attrs.width;
38
+ }).join(',');
39
+ switch (widths) {
40
+ case '100':
41
+ return 'single';
42
+ case '33.33,33.33,33.33':
43
+ return 'three_equal';
44
+ case '25,50,25':
45
+ return 'three_with_sidebars';
46
+ case '50,50':
47
+ return 'two_equal';
48
+ case '33.33,66.66':
49
+ return 'two_left_sidebar';
50
+ case '66.66,33.33':
51
+ return 'two_right_sidebar';
52
+ }
53
+ return;
54
+ };
55
+ export var getSelectedLayout = function getSelectedLayout(maybeLayoutSection, current) {
56
+ if (maybeLayoutSection && getPresetLayout(maybeLayoutSection)) {
57
+ return getPresetLayout(maybeLayoutSection) || current;
58
+ }
59
+ return current;
60
+ };
61
+ export var createDefaultLayoutSection = function createDefaultLayoutSection(state) {
62
+ var _state$schema$nodes = state.schema.nodes,
63
+ layoutSection = _state$schema$nodes.layoutSection,
64
+ layoutColumn = _state$schema$nodes.layoutColumn;
65
+
66
+ // create a 50-50 layout by default
67
+ var columns = Fragment.fromArray([layoutColumn.createAndFill({
68
+ width: 50
69
+ }), layoutColumn.createAndFill({
70
+ width: 50
71
+ })]);
72
+ return layoutSection.createAndFill(undefined, columns);
73
+ };
74
+ export var insertLayoutColumns = function insertLayoutColumns(state, dispatch) {
75
+ if (dispatch) {
76
+ dispatch(safeInsert(createDefaultLayoutSection(state))(state.tr));
77
+ }
78
+ return true;
79
+ };
80
+ export var insertLayoutColumnsWithAnalytics = function insertLayoutColumnsWithAnalytics(editorAnalyticsAPI) {
81
+ return function (inputMethod) {
82
+ return withAnalytics(editorAnalyticsAPI, {
83
+ action: ACTION.INSERTED,
84
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
85
+ actionSubjectId: ACTION_SUBJECT_ID.LAYOUT,
86
+ attributes: {
87
+ inputMethod: inputMethod
88
+ },
89
+ eventType: EVENT_TYPE.TRACK
90
+ })(insertLayoutColumns);
91
+ };
92
+ };
93
+
94
+ /**
95
+ * Add a column to the right of existing layout
96
+ */
97
+ function addColumn(schema, pos) {
98
+ return function (tr) {
99
+ tr.replaceWith(tr.mapping.map(pos), tr.mapping.map(pos), schema.nodes.layoutColumn.createAndFill());
100
+ };
101
+ }
102
+ function removeLastColumnInLayout(column, columnPos, insideRightEdgePos) {
103
+ return function (tr) {
104
+ if (isEmptyDocument(column)) {
105
+ tr.replaceRange(tr.mapping.map(columnPos - 1), tr.mapping.map(insideRightEdgePos), Slice.empty);
106
+ } else {
107
+ tr.replaceRange(tr.mapping.map(columnPos - 1), tr.mapping.map(columnPos + 1), Slice.empty);
108
+ }
109
+ };
110
+ }
111
+ var fromTwoColsToThree = addColumn;
112
+ var fromOneColToTwo = addColumn;
113
+ var fromTwoColsToOne = removeLastColumnInLayout;
114
+ var fromThreeColsToTwo = removeLastColumnInLayout;
115
+ var fromOneColToThree = function fromOneColToThree(schema, pos) {
116
+ return function (tr) {
117
+ addColumn(schema, pos)(tr);
118
+ addColumn(schema, pos)(tr);
119
+ };
120
+ };
121
+ var fromThreeColstoOne = function fromThreeColstoOne(node, tr, insideRightEdgePos) {
122
+ var thirdColumn = node.content.child(2);
123
+ fromThreeColsToTwo(thirdColumn, insideRightEdgePos - thirdColumn.nodeSize, insideRightEdgePos)(tr);
124
+ var secondColumn = node.content.child(1);
125
+ fromTwoColsToOne(secondColumn, insideRightEdgePos - thirdColumn.nodeSize - secondColumn.nodeSize, insideRightEdgePos)(tr);
126
+ };
127
+
128
+ /**
129
+ * Handles switching from 2 -> 3 cols, or 3 -> 2 cols
130
+ * Switching from 2 -> 3 just adds a new one at the end
131
+ * Switching from 3 -> 2 moves all the content of the third col inside the second before
132
+ * removing it
133
+ */
134
+ function forceColumnStructure(state, node, pos, presetLayout) {
135
+ var tr = state.tr;
136
+ var insideRightEdgeOfLayoutSection = pos + node.nodeSize - 1;
137
+ var numCols = node.childCount;
138
+
139
+ // 3 columns -> 2 columns
140
+ if (TWO_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 3) {
141
+ var thirdColumn = node.content.child(2);
142
+ var columnPos = insideRightEdgeOfLayoutSection - thirdColumn.nodeSize;
143
+ fromThreeColsToTwo(thirdColumn, columnPos, insideRightEdgeOfLayoutSection)(tr);
144
+
145
+ // 2 columns -> 3 columns
146
+ } else if (THREE_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 2) {
147
+ fromTwoColsToThree(state.schema, insideRightEdgeOfLayoutSection)(tr);
148
+
149
+ // 2 columns -> 1 column
150
+ } else if (ONE_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 2) {
151
+ var secondColumn = node.content.child(1);
152
+ var _columnPos = insideRightEdgeOfLayoutSection - secondColumn.nodeSize;
153
+ fromTwoColsToOne(secondColumn, _columnPos, insideRightEdgeOfLayoutSection)(tr);
154
+
155
+ // 3 columns -> 1 column
156
+ } else if (ONE_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 3) {
157
+ fromThreeColstoOne(node, tr, insideRightEdgeOfLayoutSection);
158
+
159
+ // 1 column -> 2 columns
160
+ } else if (TWO_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 1) {
161
+ fromOneColToTwo(state.schema, insideRightEdgeOfLayoutSection)(tr);
162
+ // 1 column -> 3 columns
163
+ } else if (THREE_COL_LAYOUTS.indexOf(presetLayout) >= 0 && numCols === 1) {
164
+ fromOneColToThree(state.schema, insideRightEdgeOfLayoutSection)(tr);
165
+ }
166
+ return tr;
167
+ }
168
+ function columnWidth(node, schema, widths) {
169
+ var layoutColumn = schema.nodes.layoutColumn;
170
+ var truncatedWidths = widths.map(function (w) {
171
+ return Number(w.toFixed(2));
172
+ });
173
+ return flatmap(node.content, function (column, idx) {
174
+ if (column.type === layoutColumn) {
175
+ return layoutColumn.create(_objectSpread(_objectSpread({}, column.attrs), {}, {
176
+ width: truncatedWidths[idx]
177
+ }), column.content, column.marks);
178
+ } else {
179
+ return column;
180
+ }
181
+ });
182
+ }
183
+ function forceColumnWidths(state, tr, pos, presetLayout) {
184
+ var node = tr.doc.nodeAt(pos);
185
+ if (!node) {
186
+ return tr;
187
+ }
188
+ return tr.replaceWith(pos + 1, pos + node.nodeSize - 1, columnWidth(node, state.schema, getWidthsForPreset(presetLayout)));
189
+ }
190
+ export function forceSectionToPresetLayout(state, node, pos, presetLayout) {
191
+ var tr = forceColumnStructure(state, node, pos, presetLayout);
192
+
193
+ // save the selection here, since forcing column widths causes a change over the
194
+ // entire layoutSection, which remaps selection to the end. not remapping here
195
+ // is safe because the structure is no longer changing.
196
+ var selection = tr.selection;
197
+ tr = forceColumnWidths(state, tr, pos, presetLayout);
198
+ var selectionPos$ = tr.doc.resolve(selection.$from.pos);
199
+ return tr.setSelection(state.selection instanceof NodeSelection ? new NodeSelection(selectionPos$) : new TextSelection(selectionPos$));
200
+ }
201
+ export var setPresetLayout = function setPresetLayout(editorAnalyticsAPI) {
202
+ return function (layout) {
203
+ return function (state, dispatch) {
204
+ var _ref = pluginKey.getState(state),
205
+ pos = _ref.pos,
206
+ selectedLayout = _ref.selectedLayout;
207
+ if (selectedLayout === layout || pos === null) {
208
+ return false;
209
+ }
210
+ var node = state.doc.nodeAt(pos);
211
+ if (!node) {
212
+ return false;
213
+ }
214
+ var tr = forceSectionToPresetLayout(state, node, pos, layout);
215
+ if (tr) {
216
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({
217
+ action: ACTION.CHANGED_LAYOUT,
218
+ actionSubject: ACTION_SUBJECT.LAYOUT,
219
+ attributes: {
220
+ previousLayout: formatLayoutName(selectedLayout),
221
+ newLayout: formatLayoutName(layout)
222
+ },
223
+ eventType: EVENT_TYPE.TRACK
224
+ })(tr);
225
+ tr.setMeta('scrollIntoView', false);
226
+ if (dispatch) {
227
+ dispatch(tr);
228
+ }
229
+ return true;
230
+ }
231
+ return false;
232
+ };
233
+ };
234
+ };
235
+ function layoutNeedChanges(node) {
236
+ return !getPresetLayout(node);
237
+ }
238
+ function getLayoutChange(node, pos, schema) {
239
+ if (node.type === schema.nodes.layoutSection) {
240
+ if (!layoutNeedChanges(node)) {
241
+ return;
242
+ }
243
+ var presetLayout = node.childCount === 2 ? 'two_equal' : node.childCount === 3 ? 'three_equal' : 'single';
244
+ var fixedColumns = columnWidth(node, schema, getWidthsForPreset(presetLayout));
245
+ return {
246
+ from: pos + 1,
247
+ to: pos + node.nodeSize - 1,
248
+ slice: new Slice(fixedColumns, 0, 0)
249
+ };
250
+ }
251
+ }
252
+ export var fixColumnSizes = function fixColumnSizes(changedTr, state) {
253
+ var layoutSection = state.schema.nodes.layoutSection;
254
+ var change;
255
+ var range = getStepRange(changedTr);
256
+ if (!range) {
257
+ return undefined;
258
+ }
259
+ changedTr.doc.nodesBetween(range.from, range.to, function (node, pos) {
260
+ if (node.type !== layoutSection) {
261
+ return true; // Check all internal nodes expect for layout section
262
+ }
263
+ // Node is a section
264
+ if (layoutNeedChanges(node)) {
265
+ change = getLayoutChange(node, pos, state.schema);
266
+ }
267
+ return false; // We dont go deep, We dont accept nested layouts
268
+ });
269
+
270
+ // Hack to prevent: https://product-fabric.atlassian.net/browse/ED-7523
271
+ // By default prosemirror try to recreate the node with the default attributes
272
+ // The default attribute is invalid adf though. when this happen the node after
273
+ // current position is a layout section
274
+ var $pos = changedTr.doc.resolve(range.to);
275
+ if ($pos.depth > 0) {
276
+ // 'range.to' position could resolve to doc, in this ResolvedPos.after will throws
277
+ var pos = $pos.after();
278
+ var node = changedTr.doc.nodeAt(pos);
279
+ if (node && node.type === layoutSection && layoutNeedChanges(node)) {
280
+ change = getLayoutChange(node, pos, state.schema);
281
+ }
282
+ }
283
+ return change;
284
+ };
285
+ export var fixColumnStructure = function fixColumnStructure(state) {
286
+ var _ref2 = pluginKey.getState(state),
287
+ pos = _ref2.pos,
288
+ selectedLayout = _ref2.selectedLayout;
289
+ if (pos !== null && selectedLayout) {
290
+ var node = state.doc.nodeAt(pos);
291
+ if (node && node.childCount !== getWidthsForPreset(selectedLayout).length) {
292
+ return forceSectionToPresetLayout(state, node, pos, selectedLayout);
293
+ }
294
+ }
295
+ return;
296
+ };
297
+ export var deleteActiveLayoutNode = function deleteActiveLayoutNode(editorAnalyticsAPI) {
298
+ return function (state, dispatch) {
299
+ var _ref3 = pluginKey.getState(state),
300
+ pos = _ref3.pos,
301
+ selectedLayout = _ref3.selectedLayout;
302
+ if (pos !== null) {
303
+ var node = state.doc.nodeAt(pos);
304
+ if (dispatch) {
305
+ var tr = state.tr.delete(pos, pos + node.nodeSize);
306
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({
307
+ action: ACTION.DELETED,
308
+ actionSubject: ACTION_SUBJECT.LAYOUT,
309
+ attributes: {
310
+ layout: formatLayoutName(selectedLayout)
311
+ },
312
+ eventType: EVENT_TYPE.TRACK
313
+ })(tr);
314
+ dispatch(tr);
315
+ }
316
+ return true;
317
+ }
318
+ return false;
319
+ };
320
+ };
321
+ var formatLayoutName = function formatLayoutName(layout) {
322
+ switch (layout) {
323
+ case 'single':
324
+ return LAYOUT_TYPE.SINGLE_COL;
325
+ case 'two_equal':
326
+ return LAYOUT_TYPE.TWO_COLS_EQUAL;
327
+ case 'three_equal':
328
+ return LAYOUT_TYPE.THREE_COLS_EQUAL;
329
+ case 'two_left_sidebar':
330
+ return LAYOUT_TYPE.LEFT_SIDEBAR;
331
+ case 'two_right_sidebar':
332
+ return LAYOUT_TYPE.RIGHT_SIDEBAR;
333
+ case 'three_with_sidebars':
334
+ return LAYOUT_TYPE.THREE_WITH_SIDEBARS;
335
+ }
336
+ };
@@ -0,0 +1 @@
1
+ export { layoutPlugin } from './plugin';
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import { layoutColumn, layoutSection } from '@atlaskit/adf-schema';
3
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
4
+ import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages';
5
+ import { IconLayout } from '@atlaskit/editor-common/quick-insert';
6
+ import { createDefaultLayoutSection, insertLayoutColumnsWithAnalytics } from './actions';
7
+ import { default as createLayoutPlugin } from './pm-plugins/main';
8
+ import { pluginKey } from './pm-plugins/plugin-key';
9
+ import { buildToolbar } from './toolbar';
10
+ export { pluginKey };
11
+ export var layoutPlugin = function layoutPlugin(_ref) {
12
+ var _api$analytics;
13
+ var _ref$config = _ref.config,
14
+ options = _ref$config === void 0 ? {} : _ref$config,
15
+ api = _ref.api;
16
+ return {
17
+ name: 'layout',
18
+ nodes: function nodes() {
19
+ return [{
20
+ name: 'layoutSection',
21
+ node: layoutSection
22
+ }, {
23
+ name: 'layoutColumn',
24
+ node: layoutColumn
25
+ }];
26
+ },
27
+ pmPlugins: function pmPlugins() {
28
+ return [{
29
+ name: 'layout',
30
+ plugin: function plugin() {
31
+ return createLayoutPlugin(options);
32
+ }
33
+ }];
34
+ },
35
+ actions: {
36
+ insertLayoutColumns: insertLayoutColumnsWithAnalytics(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
37
+ },
38
+ pluginsOptions: {
39
+ floatingToolbar: function floatingToolbar(state, intl) {
40
+ var _ref2 = pluginKey.getState(state),
41
+ pos = _ref2.pos,
42
+ allowBreakout = _ref2.allowBreakout,
43
+ addSidebarLayouts = _ref2.addSidebarLayouts,
44
+ allowSingleColumnLayout = _ref2.allowSingleColumnLayout;
45
+ if (pos !== null) {
46
+ return buildToolbar(state, intl, pos, allowBreakout, addSidebarLayouts, allowSingleColumnLayout, api);
47
+ }
48
+ return undefined;
49
+ },
50
+ quickInsert: function quickInsert(_ref3) {
51
+ var formatMessage = _ref3.formatMessage;
52
+ return [{
53
+ id: 'layout',
54
+ title: formatMessage(messages.columns),
55
+ description: formatMessage(messages.columnsDescription),
56
+ keywords: ['column', 'section'],
57
+ priority: 1100,
58
+ icon: function icon() {
59
+ return /*#__PURE__*/React.createElement(IconLayout, null);
60
+ },
61
+ action: function action(insert, state) {
62
+ var _api$analytics2;
63
+ var tr = insert(createDefaultLayoutSection(state));
64
+ 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({
65
+ action: ACTION.INSERTED,
66
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
67
+ actionSubjectId: ACTION_SUBJECT_ID.LAYOUT,
68
+ attributes: {
69
+ inputMethod: INPUT_METHOD.QUICK_INSERT
70
+ },
71
+ eventType: EVENT_TYPE.TRACK
72
+ })(tr);
73
+ return tr;
74
+ }
75
+ }];
76
+ }
77
+ }
78
+ };
79
+ };
@@ -0,0 +1,141 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
+ import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
6
+ import { filterCommand as filter } from '@atlaskit/editor-common/utils';
7
+ import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
8
+ import { Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
9
+ import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
10
+ import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
11
+ import { fixColumnSizes, fixColumnStructure, getSelectedLayout } from '../actions';
12
+ import { pluginKey } from './plugin-key';
13
+ export var DEFAULT_LAYOUT = 'two_equal';
14
+ var isWholeSelectionInsideLayoutColumn = function isWholeSelectionInsideLayoutColumn(state) {
15
+ // Since findParentNodeOfType doesn't check if selection.to shares the parent, we do this check ourselves
16
+ var fromParent = findParentNodeOfType(state.schema.nodes.layoutColumn)(state.selection);
17
+ if (fromParent) {
18
+ var isToPosInsideSameLayoutColumn = state.selection.from < fromParent.pos + fromParent.node.nodeSize;
19
+ return isToPosInsideSameLayoutColumn;
20
+ }
21
+ return false;
22
+ };
23
+ var moveCursorToNextColumn = function moveCursorToNextColumn(state, dispatch) {
24
+ var selection = state.selection;
25
+ var _state$schema$nodes = state.schema.nodes,
26
+ layoutColumn = _state$schema$nodes.layoutColumn,
27
+ layoutSection = _state$schema$nodes.layoutSection;
28
+ var section = findParentNodeOfType(layoutSection)(selection);
29
+ var column = findParentNodeOfType(layoutColumn)(selection);
30
+ if (column.node !== section.node.lastChild) {
31
+ var $nextColumn = state.doc.resolve(column.pos + column.node.nodeSize);
32
+ var shiftedSelection = TextSelection.findFrom($nextColumn, 1);
33
+ if (dispatch) {
34
+ dispatch(state.tr.setSelection(shiftedSelection));
35
+ }
36
+ }
37
+ return true;
38
+ };
39
+
40
+ // TODO: Look at memoize-one-ing this fn
41
+ var getNodeDecoration = function getNodeDecoration(pos, node) {
42
+ return [Decoration.node(pos, pos + node.nodeSize, {
43
+ class: 'selected'
44
+ })];
45
+ };
46
+ var getInitialPluginState = function getInitialPluginState(options, state) {
47
+ var maybeLayoutSection = findParentNodeOfType(state.schema.nodes.layoutSection)(state.selection);
48
+ var allowBreakout = options.allowBreakout || false;
49
+ var addSidebarLayouts = options.UNSAFE_addSidebarLayouts || false;
50
+ var allowSingleColumnLayout = options.UNSAFE_allowSingleColumnLayout || false;
51
+ var pos = maybeLayoutSection ? maybeLayoutSection.pos : null;
52
+ var selectedLayout = getSelectedLayout(maybeLayoutSection && maybeLayoutSection.node, DEFAULT_LAYOUT);
53
+ return {
54
+ pos: pos,
55
+ allowBreakout: allowBreakout,
56
+ addSidebarLayouts: addSidebarLayouts,
57
+ selectedLayout: selectedLayout,
58
+ allowSingleColumnLayout: allowSingleColumnLayout
59
+ };
60
+ };
61
+ export default (function (options) {
62
+ return new SafePlugin({
63
+ key: pluginKey,
64
+ state: {
65
+ init: function init(_, state) {
66
+ return getInitialPluginState(options, state);
67
+ },
68
+ apply: function apply(tr, pluginState, _oldState, newState) {
69
+ if (tr.docChanged || tr.selectionSet) {
70
+ var layoutSection = newState.schema.nodes.layoutSection,
71
+ selection = newState.selection;
72
+ var maybeLayoutSection = findParentNodeOfType(layoutSection)(selection) || findSelectedNodeOfType([layoutSection])(selection);
73
+ var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
74
+ pos: maybeLayoutSection ? maybeLayoutSection.pos : null,
75
+ selectedLayout: getSelectedLayout(maybeLayoutSection && maybeLayoutSection.node, pluginState.selectedLayout)
76
+ });
77
+ return newPluginState;
78
+ }
79
+ return pluginState;
80
+ }
81
+ },
82
+ props: {
83
+ decorations: function decorations(state) {
84
+ var layoutState = pluginKey.getState(state);
85
+ if (layoutState.pos !== null) {
86
+ return DecorationSet.create(state.doc, getNodeDecoration(layoutState.pos, state.doc.nodeAt(layoutState.pos)));
87
+ }
88
+ return undefined;
89
+ },
90
+ handleKeyDown: keydownHandler({
91
+ Tab: filter(isWholeSelectionInsideLayoutColumn, moveCursorToNextColumn)
92
+ }),
93
+ handleClickOn: createSelectionClickHandler(['layoutColumn'], function (target) {
94
+ return target.hasAttribute('data-layout-section') || target.hasAttribute('data-layout-column');
95
+ }, {
96
+ useLongPressSelection: options.useLongPressSelection || false,
97
+ getNodeSelectionPos: function getNodeSelectionPos(state, nodePos) {
98
+ return state.doc.resolve(nodePos).before();
99
+ }
100
+ })
101
+ },
102
+ appendTransaction: function appendTransaction(transactions, _oldState, newState) {
103
+ var changes = [];
104
+ transactions.forEach(function (prevTr) {
105
+ // remap change segments across the transaction set
106
+ changes.forEach(function (change) {
107
+ return {
108
+ from: prevTr.mapping.map(change.from),
109
+ to: prevTr.mapping.map(change.to),
110
+ slice: change.slice
111
+ };
112
+ });
113
+
114
+ // don't consider transactions that don't mutate
115
+ if (!prevTr.docChanged) {
116
+ return;
117
+ }
118
+ var change = fixColumnSizes(prevTr, newState);
119
+ if (change) {
120
+ changes.push(change);
121
+ }
122
+ });
123
+ if (changes.length) {
124
+ var tr = newState.tr;
125
+ var selection = newState.selection.toJSON();
126
+ changes.forEach(function (change) {
127
+ tr.replaceRange(change.from, change.to, change.slice);
128
+ });
129
+
130
+ // selecting and deleting across columns in 3 col layouts can remove
131
+ // a layoutColumn so we fix the structure here
132
+ tr = fixColumnStructure(newState) || tr;
133
+ if (tr.docChanged) {
134
+ tr.setSelection(Selection.fromJSON(tr.doc, selection));
135
+ return tr;
136
+ }
137
+ }
138
+ return;
139
+ }
140
+ });
141
+ });
@@ -0,0 +1,2 @@
1
+ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
2
+ export var pluginKey = new PluginKey('layout');
@@ -0,0 +1 @@
1
+ export {};