@atlaskit/editor-plugin-expand 1.3.0 → 1.3.2

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 (77) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/legacyExpand/nodeviews/index.js +18 -5
  3. package/dist/cjs/singlePlayerExpand/commands.js +134 -0
  4. package/dist/cjs/singlePlayerExpand/node-views/index.js +381 -0
  5. package/dist/cjs/singlePlayerExpand/plugin.js +72 -9
  6. package/dist/cjs/singlePlayerExpand/pm-plugins/keymap.js +121 -0
  7. package/dist/cjs/singlePlayerExpand/pm-plugins/main.js +68 -0
  8. package/dist/cjs/singlePlayerExpand/toolbar.js +59 -0
  9. package/dist/cjs/singlePlayerExpand/ui/ExpandButton.js +87 -0
  10. package/dist/cjs/singlePlayerExpand/ui/NodeView.js +59 -0
  11. package/dist/cjs/singlePlayerExpand/utils.js +35 -0
  12. package/dist/es2019/index.js +0 -2
  13. package/dist/es2019/legacyExpand/nodeviews/index.js +18 -5
  14. package/dist/es2019/legacyExpand/pm-plugins/keymap.js +1 -2
  15. package/dist/es2019/singlePlayerExpand/commands.js +118 -0
  16. package/dist/es2019/singlePlayerExpand/node-views/index.js +370 -0
  17. package/dist/es2019/singlePlayerExpand/plugin.js +69 -10
  18. package/dist/es2019/singlePlayerExpand/pm-plugins/keymap.js +137 -0
  19. package/dist/es2019/singlePlayerExpand/pm-plugins/main.js +53 -0
  20. package/dist/es2019/singlePlayerExpand/toolbar.js +51 -0
  21. package/dist/es2019/singlePlayerExpand/ui/ExpandButton.js +77 -0
  22. package/dist/es2019/singlePlayerExpand/ui/NodeView.js +52 -0
  23. package/dist/es2019/singlePlayerExpand/utils.js +5 -0
  24. package/dist/esm/index.js +0 -2
  25. package/dist/esm/legacyExpand/nodeviews/index.js +18 -5
  26. package/dist/esm/legacyExpand/pm-plugins/keymap.js +1 -2
  27. package/dist/esm/singlePlayerExpand/commands.js +128 -0
  28. package/dist/esm/singlePlayerExpand/node-views/index.js +373 -0
  29. package/dist/esm/singlePlayerExpand/plugin.js +71 -10
  30. package/dist/esm/singlePlayerExpand/pm-plugins/keymap.js +115 -0
  31. package/dist/esm/singlePlayerExpand/pm-plugins/main.js +60 -0
  32. package/dist/esm/singlePlayerExpand/toolbar.js +52 -0
  33. package/dist/esm/singlePlayerExpand/ui/ExpandButton.js +77 -0
  34. package/dist/esm/singlePlayerExpand/ui/NodeView.js +53 -0
  35. package/dist/esm/singlePlayerExpand/utils.js +5 -0
  36. package/dist/types/index.d.ts +1 -1
  37. package/dist/types/legacyExpand/nodeviews/index.d.ts +1 -1
  38. package/dist/types/legacyExpand/plugin.d.ts +1 -1
  39. package/dist/types/legacyExpand/pm-plugins/keymap.d.ts +1 -1
  40. package/dist/types/legacyExpand/pm-plugins/main.d.ts +2 -2
  41. package/dist/types/legacyExpand/pm-plugins/plugin-factory.d.ts +1 -1
  42. package/dist/types/legacyExpand/reducer.d.ts +1 -1
  43. package/dist/types/legacyExpand/toolbar.d.ts +1 -1
  44. package/dist/types/plugin.d.ts +1 -1
  45. package/dist/types/singlePlayerExpand/commands.d.ts +15 -0
  46. package/dist/types/singlePlayerExpand/node-views/index.d.ts +51 -0
  47. package/dist/types/singlePlayerExpand/plugin.d.ts +1 -1
  48. package/dist/types/singlePlayerExpand/pm-plugins/keymap.d.ts +6 -0
  49. package/dist/types/singlePlayerExpand/pm-plugins/main.d.ts +9 -0
  50. package/dist/types/singlePlayerExpand/toolbar.d.ts +3 -0
  51. package/dist/types/singlePlayerExpand/ui/ExpandButton.d.ts +13 -0
  52. package/dist/types/singlePlayerExpand/ui/NodeView.d.ts +5 -0
  53. package/dist/types/singlePlayerExpand/utils.d.ts +3 -0
  54. package/dist/{types-ts4.5/legacyExpand → types}/types.d.ts +1 -1
  55. package/dist/types-ts4.5/index.d.ts +1 -1
  56. package/dist/types-ts4.5/legacyExpand/nodeviews/index.d.ts +1 -1
  57. package/dist/types-ts4.5/legacyExpand/plugin.d.ts +1 -1
  58. package/dist/types-ts4.5/legacyExpand/pm-plugins/keymap.d.ts +1 -1
  59. package/dist/types-ts4.5/legacyExpand/pm-plugins/main.d.ts +2 -2
  60. package/dist/types-ts4.5/legacyExpand/pm-plugins/plugin-factory.d.ts +1 -1
  61. package/dist/types-ts4.5/legacyExpand/reducer.d.ts +1 -1
  62. package/dist/types-ts4.5/legacyExpand/toolbar.d.ts +1 -1
  63. package/dist/types-ts4.5/plugin.d.ts +1 -1
  64. package/dist/types-ts4.5/singlePlayerExpand/commands.d.ts +15 -0
  65. package/dist/types-ts4.5/singlePlayerExpand/node-views/index.d.ts +51 -0
  66. package/dist/types-ts4.5/singlePlayerExpand/plugin.d.ts +1 -1
  67. package/dist/types-ts4.5/singlePlayerExpand/pm-plugins/keymap.d.ts +6 -0
  68. package/dist/types-ts4.5/singlePlayerExpand/pm-plugins/main.d.ts +9 -0
  69. package/dist/types-ts4.5/singlePlayerExpand/toolbar.d.ts +3 -0
  70. package/dist/types-ts4.5/singlePlayerExpand/ui/ExpandButton.d.ts +13 -0
  71. package/dist/types-ts4.5/singlePlayerExpand/ui/NodeView.d.ts +5 -0
  72. package/dist/types-ts4.5/singlePlayerExpand/utils.d.ts +3 -0
  73. package/dist/{types/legacyExpand → types-ts4.5}/types.d.ts +1 -1
  74. package/package.json +5 -5
  75. /package/dist/cjs/{legacyExpand/types.js → types.js} +0 -0
  76. /package/dist/es2019/{legacyExpand/types.js → types.js} +0 -0
  77. /package/dist/esm/{legacyExpand/types.js → types.js} +0 -0
@@ -0,0 +1,118 @@
1
+ import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
2
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { findExpand } from '@atlaskit/editor-common/transforms';
4
+ import { createWrapSelectionTransaction } from '@atlaskit/editor-common/utils';
5
+ import { Selection } from '@atlaskit/editor-prosemirror/state';
6
+ import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
7
+ import { findTable } from '@atlaskit/editor-tables/utils';
8
+
9
+ // Creates either an expand or a nestedExpand node based on the current selection
10
+ export const createExpandNode = state => {
11
+ const {
12
+ expand,
13
+ nestedExpand
14
+ } = state.schema.nodes;
15
+ const expandType = findTable(state.selection) ? nestedExpand : expand;
16
+ return expandType.createAndFill({});
17
+ };
18
+ export const insertExpand = editorAnalyticsAPI => (state, dispatch) => {
19
+ const expandNode = createExpandNode(state);
20
+ if (!expandNode) {
21
+ return false;
22
+ }
23
+ const tr = state.selection.empty ? safeInsert(expandNode)(state.tr).scrollIntoView() : createWrapSelectionTransaction({
24
+ state,
25
+ type: expandNode.type
26
+ });
27
+ const payload = {
28
+ action: ACTION.INSERTED,
29
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
30
+ actionSubjectId: (expandNode === null || expandNode === void 0 ? void 0 : expandNode.type) === state.schema.nodes.expand ? ACTION_SUBJECT_ID.EXPAND : ACTION_SUBJECT_ID.NESTED_EXPAND,
31
+ attributes: {
32
+ inputMethod: INPUT_METHOD.INSERT_MENU
33
+ },
34
+ eventType: EVENT_TYPE.TRACK
35
+ };
36
+ if (dispatch && expandNode) {
37
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(payload)(tr);
38
+ dispatch(tr);
39
+ }
40
+ return true;
41
+ };
42
+ export const deleteExpand = editorAnalyticsAPI => (state, dispatch) => {
43
+ const expandNode = findExpand(state);
44
+ if (!expandNode) {
45
+ return false;
46
+ }
47
+ return deleteExpandAtPos(editorAnalyticsAPI)(expandNode.pos, expandNode.node)(state, dispatch);
48
+ };
49
+ export const deleteExpandAtPos = editorAnalyticsAPI => (expandNodePos, expandNode) => (state, dispatch) => {
50
+ if (!expandNode || isNaN(expandNodePos)) {
51
+ return false;
52
+ }
53
+ const payload = {
54
+ action: ACTION.DELETED,
55
+ actionSubject: expandNode.type === state.schema.nodes.expand ? ACTION_SUBJECT.EXPAND : ACTION_SUBJECT.NESTED_EXPAND,
56
+ attributes: {
57
+ inputMethod: INPUT_METHOD.TOOLBAR
58
+ },
59
+ eventType: EVENT_TYPE.TRACK
60
+ };
61
+ if (expandNode && dispatch) {
62
+ const {
63
+ tr
64
+ } = state;
65
+ tr.delete(expandNodePos, expandNodePos + expandNode.nodeSize);
66
+ editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent(payload)(tr);
67
+ dispatch(tr);
68
+ }
69
+ return true;
70
+ };
71
+
72
+ // Used to clear any node or cell selection when expand title is focused
73
+ export const setSelectionInsideExpand = expandPos => (state, dispatch, editorView) => {
74
+ if (editorView) {
75
+ if (!editorView.hasFocus()) {
76
+ editorView.focus();
77
+ }
78
+ const sel = Selection.findFrom(editorView.state.doc.resolve(expandPos), 1, true);
79
+ if (sel && dispatch) {
80
+ dispatch(editorView.state.tr.setSelection(sel));
81
+ }
82
+ return true;
83
+ }
84
+ return false;
85
+ };
86
+ export const updateExpandTitle = ({
87
+ title,
88
+ nodeType,
89
+ pos
90
+ }) => (state, dispatch) => {
91
+ const node = state.doc.nodeAt(pos);
92
+ if (node && node.type === nodeType && dispatch) {
93
+ const {
94
+ tr
95
+ } = state;
96
+ tr.step(new SetAttrsStep(pos, {
97
+ ...node.attrs,
98
+ title
99
+ }));
100
+ dispatch(tr);
101
+ }
102
+ return true;
103
+ };
104
+ export const focusTitle = pos => (state, dispatch, editorView) => {
105
+ if (editorView) {
106
+ const dom = editorView.domAtPos(pos);
107
+ const expandWrapper = dom.node.parentElement;
108
+ if (expandWrapper) {
109
+ setSelectionInsideExpand(pos)(state, dispatch, editorView);
110
+ const input = expandWrapper.querySelector('input');
111
+ if (input) {
112
+ input.focus();
113
+ return true;
114
+ }
115
+ }
116
+ }
117
+ return false;
118
+ };
@@ -0,0 +1,370 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import ReactDOM from 'react-dom';
3
+ import { keyName } from 'w3c-keyname';
4
+ import { GapCursorSelection, RelativeSelectionPos, Side } from '@atlaskit/editor-common/selection';
5
+ import { expandClassNames } from '@atlaskit/editor-common/styles';
6
+ import { closestElement, isEmptyNode } from '@atlaskit/editor-common/utils';
7
+ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
8
+ import { NodeSelection, Selection } from '@atlaskit/editor-prosemirror/state';
9
+ import { deleteExpand, setSelectionInsideExpand, updateExpandTitle } from '../commands';
10
+ import { renderIcon, toDOM } from '../ui/NodeView';
11
+ export class ExpandNodeView {
12
+ constructor(node, view, getPos, getIntl, isMobile, selectNearNode, api, allowInteractiveExpand = true, __livePage = false) {
13
+ _defineProperty(this, "allowInteractiveExpand", true);
14
+ _defineProperty(this, "isMobile", false);
15
+ _defineProperty(this, "focusTitle", () => {
16
+ if (this.input) {
17
+ const {
18
+ state,
19
+ dispatch
20
+ } = this.view;
21
+ if (this.selectNearNode) {
22
+ const tr = this.selectNearNode({
23
+ selectionRelativeToNode: RelativeSelectionPos.Start
24
+ })(state);
25
+ if (dispatch) {
26
+ dispatch(tr);
27
+ }
28
+ }
29
+ const pos = this.getPos();
30
+ if (typeof pos === 'number') {
31
+ setSelectionInsideExpand(pos)(state, dispatch, this.view);
32
+ }
33
+ this.input.focus();
34
+ }
35
+ });
36
+ _defineProperty(this, "handleIconKeyDown", event => {
37
+ switch (keyName(event)) {
38
+ case 'Tab':
39
+ event.preventDefault();
40
+ this.focusTitle();
41
+ break;
42
+ case 'Enter':
43
+ event.preventDefault();
44
+ this.handleClick(event);
45
+ break;
46
+ }
47
+ });
48
+ _defineProperty(this, "handleClick", event => {
49
+ const pos = this.getPos();
50
+ if (typeof pos !== 'number') {
51
+ return;
52
+ }
53
+ const target = event.target;
54
+ if (closestElement(target, `.${expandClassNames.icon}`)) {
55
+ if (!this.allowInteractiveExpand) {
56
+ return;
57
+ }
58
+ event.stopPropagation();
59
+
60
+ // We blur the editorView, to prevent any keyboard showing on mobile
61
+ // When we're interacting with the expand toggle
62
+ if (this.view.dom instanceof HTMLElement) {
63
+ this.view.dom.blur();
64
+ }
65
+
66
+ // TODO https://product-fabric.atlassian.net/browse/ED-22841
67
+ // call toggleExpandExpanded
68
+
69
+ return;
70
+ }
71
+ if (target === this.input) {
72
+ event.stopPropagation();
73
+ this.focusTitle();
74
+ return;
75
+ }
76
+ });
77
+ _defineProperty(this, "handleInput", event => {
78
+ const pos = this.getPos();
79
+ if (typeof pos !== 'number') {
80
+ return;
81
+ }
82
+ const target = event.target;
83
+ if (target === this.input) {
84
+ event.stopPropagation();
85
+ const {
86
+ state,
87
+ dispatch
88
+ } = this.view;
89
+ updateExpandTitle({
90
+ title: target.value,
91
+ pos,
92
+ nodeType: this.node.type
93
+ })(state, dispatch);
94
+ }
95
+ });
96
+ _defineProperty(this, "handleFocus", event => {
97
+ event.stopImmediatePropagation();
98
+ });
99
+ _defineProperty(this, "handleTitleKeydown", event => {
100
+ switch (keyName(event)) {
101
+ case 'Enter':
102
+ // TO-DO
103
+ break;
104
+ case 'Tab':
105
+ case 'ArrowDown':
106
+ this.moveToOutsideOfTitle(event);
107
+ break;
108
+ case 'ArrowRight':
109
+ this.handleArrowRightFromTitle(event);
110
+ break;
111
+ case 'ArrowLeft':
112
+ this.handleArrowLeftFromTitle(event);
113
+ break;
114
+ case 'ArrowUp':
115
+ this.setLeftGapCursor(event);
116
+ break;
117
+ case 'Backspace':
118
+ this.deleteEmptyExpand();
119
+ break;
120
+ }
121
+ });
122
+ _defineProperty(this, "deleteEmptyExpand", () => {
123
+ const {
124
+ state
125
+ } = this.view;
126
+ const expandNode = this.node;
127
+ if (expandNode && isEmptyNode(state.schema)(expandNode)) {
128
+ var _this$api, _this$api$analytics;
129
+ deleteExpand((_this$api = this.api) === null || _this$api === void 0 ? void 0 : (_this$api$analytics = _this$api.analytics) === null || _this$api$analytics === void 0 ? void 0 : _this$api$analytics.actions)(state, this.view.dispatch);
130
+ }
131
+ });
132
+ _defineProperty(this, "moveToOutsideOfTitle", event => {
133
+ event.preventDefault();
134
+ const {
135
+ state,
136
+ dispatch
137
+ } = this.view;
138
+ const expandPos = this.getPos();
139
+ if (typeof expandPos !== 'number') {
140
+ return;
141
+ }
142
+ let pos = expandPos;
143
+ if (this.isCollapsed()) {
144
+ pos = expandPos + this.node.nodeSize;
145
+ }
146
+ const resolvedPos = state.doc.resolve(pos);
147
+ if (!resolvedPos) {
148
+ return;
149
+ }
150
+ if (this.isCollapsed() && resolvedPos.nodeAfter && ['expand', 'nestedExpand'].indexOf(resolvedPos.nodeAfter.type.name) > -1) {
151
+ return this.setRightGapCursor(event);
152
+ }
153
+ const sel = Selection.findFrom(resolvedPos, 1, true);
154
+ if (sel) {
155
+ // If the input has focus, ProseMirror doesn't
156
+ // Give PM focus back before changing our selection
157
+ this.view.focus();
158
+ dispatch(state.tr.setSelection(sel));
159
+ }
160
+ });
161
+ // TODO: https://product-fabric.atlassian.net/browse/ED-22841
162
+ _defineProperty(this, "isCollapsed", () => {
163
+ return false;
164
+ });
165
+ _defineProperty(this, "setRightGapCursor", event => {
166
+ if (!this.input) {
167
+ return;
168
+ }
169
+ const pos = this.getPos();
170
+ if (typeof pos !== 'number') {
171
+ return;
172
+ }
173
+ const {
174
+ value,
175
+ selectionStart,
176
+ selectionEnd
177
+ } = this.input;
178
+ if (selectionStart === selectionEnd && selectionStart === value.length) {
179
+ const {
180
+ state,
181
+ dispatch
182
+ } = this.view;
183
+ event.preventDefault();
184
+ this.view.focus();
185
+ dispatch(state.tr.setSelection(new GapCursorSelection(state.doc.resolve(this.node.nodeSize + pos), Side.RIGHT)));
186
+ }
187
+ });
188
+ _defineProperty(this, "setLeftGapCursor", event => {
189
+ if (!this.input) {
190
+ return;
191
+ }
192
+ const pos = this.getPos();
193
+ if (typeof pos !== 'number') {
194
+ return;
195
+ }
196
+ const {
197
+ selectionStart,
198
+ selectionEnd
199
+ } = this.input;
200
+ if (selectionStart === selectionEnd && selectionStart === 0) {
201
+ event.preventDefault();
202
+ const {
203
+ state,
204
+ dispatch
205
+ } = this.view;
206
+ this.view.focus();
207
+ dispatch(state.tr.setSelection(new GapCursorSelection(state.doc.resolve(pos), Side.LEFT)));
208
+ }
209
+ });
210
+ _defineProperty(this, "handleArrowRightFromTitle", event => {
211
+ if (!this.input || !this.selectNearNode) {
212
+ return;
213
+ }
214
+ const pos = this.getPos();
215
+ if (typeof pos !== 'number') {
216
+ return;
217
+ }
218
+ const {
219
+ value,
220
+ selectionStart,
221
+ selectionEnd
222
+ } = this.input;
223
+ if (selectionStart === selectionEnd && selectionStart === value.length) {
224
+ event.preventDefault();
225
+ const {
226
+ state,
227
+ dispatch
228
+ } = this.view;
229
+ this.view.focus();
230
+ const tr = this.selectNearNode({
231
+ selectionRelativeToNode: RelativeSelectionPos.End,
232
+ selection: NodeSelection.create(state.doc, pos)
233
+ })(state);
234
+ if (dispatch) {
235
+ dispatch(tr);
236
+ }
237
+ }
238
+ });
239
+ _defineProperty(this, "handleArrowLeftFromTitle", event => {
240
+ if (!this.input || !this.selectNearNode) {
241
+ return;
242
+ }
243
+ const pos = this.getPos();
244
+ if (typeof pos !== 'number') {
245
+ return;
246
+ }
247
+ const {
248
+ selectionStart,
249
+ selectionEnd
250
+ } = this.input;
251
+ if (selectionStart === selectionEnd && selectionStart === 0) {
252
+ var _this$api2, _this$api2$selection;
253
+ event.preventDefault();
254
+ const {
255
+ state,
256
+ dispatch
257
+ } = this.view;
258
+ this.view.focus();
259
+ const selectionSharedState = ((_this$api2 = this.api) === null || _this$api2 === void 0 ? void 0 : (_this$api2$selection = _this$api2.selection) === null || _this$api2$selection === void 0 ? void 0 : _this$api2$selection.sharedState.currentState()) || {};
260
+ // selectionRelativeToNode is undefined when user clicked to select node, then hit left to get focus in title
261
+ // This is a special case where we want to bypass node selection and jump straight to gap cursor
262
+ if ((selectionSharedState === null || selectionSharedState === void 0 ? void 0 : selectionSharedState.selectionRelativeToNode) === undefined) {
263
+ const tr = this.selectNearNode({
264
+ selectionRelativeToNode: undefined,
265
+ selection: new GapCursorSelection(state.doc.resolve(pos), Side.LEFT)
266
+ })(state);
267
+ if (dispatch) {
268
+ dispatch(tr);
269
+ }
270
+ } else {
271
+ const tr = this.selectNearNode({
272
+ selectionRelativeToNode: RelativeSelectionPos.Start,
273
+ selection: NodeSelection.create(state.doc, pos)
274
+ })(state);
275
+ if (dispatch) {
276
+ dispatch(tr);
277
+ }
278
+ }
279
+ }
280
+ });
281
+ this.selectNearNode = selectNearNode;
282
+ this.__livePage = __livePage;
283
+ this.intl = getIntl();
284
+ const {
285
+ dom,
286
+ contentDOM
287
+ } = DOMSerializer.renderSpec(document, toDOM(node, this.__livePage, this.intl));
288
+ this.allowInteractiveExpand = allowInteractiveExpand;
289
+ this.getPos = getPos;
290
+ this.view = view;
291
+ this.node = node;
292
+ this.dom = dom;
293
+ this.contentDOM = contentDOM;
294
+ this.isMobile = isMobile;
295
+ this.api = api;
296
+ this.icon = this.dom.querySelector(`.${expandClassNames.icon}`);
297
+ this.input = this.dom.querySelector(`.${expandClassNames.titleInput}`);
298
+ this.titleContainer = this.dom.querySelector(`.${expandClassNames.titleContainer}`);
299
+ renderIcon(this.icon, this.allowInteractiveExpand, this.intl);
300
+ if (!this.input || !this.titleContainer || !this.icon) {
301
+ return;
302
+ }
303
+
304
+ // Add event listeners
305
+ /* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners*/
306
+ this.dom.addEventListener('click', this.handleClick);
307
+ this.dom.addEventListener('input', this.handleInput);
308
+ this.input.addEventListener('keydown', this.handleTitleKeydown);
309
+ // If the user interacts in our title bar (either toggle or input)
310
+ // Prevent ProseMirror from getting a focus event (causes weird selection issues).
311
+ this.titleContainer.addEventListener('focus', this.handleFocus);
312
+ this.icon.addEventListener('keydown', this.handleIconKeyDown);
313
+ }
314
+ stopEvent(event) {
315
+ const target = event.target;
316
+ return target === this.input || target === this.icon || !!closestElement(target, `.${expandClassNames.icon}`);
317
+ }
318
+ ignoreMutation(mutationRecord) {
319
+ // ME-1931: Mobile relies on composition which creates dom mutations. If we ignore them, prosemirror
320
+ // does not recognise the changes and reverts them.
321
+ if (this.isMobile && (mutationRecord.type === 'characterData' || mutationRecord.type === 'childList')) {
322
+ return false;
323
+ }
324
+ if (mutationRecord.type === 'selection') {
325
+ return false;
326
+ }
327
+ return true;
328
+ }
329
+ update(node, _decorations) {
330
+ if (this.node.type === node.type) {
331
+ // TODO: https://product-fabric.atlassian.net/browse/ED-22841
332
+ // Handle toggling of the expand on update here
333
+
334
+ // During a collab session the title doesn't sync with other users
335
+ // since we're intentionally being less aggressive about re-rendering.
336
+ // We also apply a rAF to avoid abrupt continuous replacement of the title.
337
+ window.requestAnimationFrame(() => {
338
+ if (this.input && this.node.attrs.title !== this.input.value) {
339
+ this.input.value = this.node.attrs.title;
340
+ }
341
+ });
342
+ this.node = node;
343
+ return true;
344
+ }
345
+ return false;
346
+ }
347
+ destroy() {
348
+ if (!this.dom || !this.input || !this.titleContainer || !this.icon) {
349
+ return;
350
+ }
351
+ this.dom.removeEventListener('click', this.handleClick);
352
+ this.dom.removeEventListener('input', this.handleInput);
353
+ this.input.removeEventListener('keydown', this.handleTitleKeydown);
354
+ this.titleContainer.removeEventListener('focus', this.handleFocus);
355
+ this.icon.removeEventListener('keydown', this.handleIconKeyDown);
356
+ ReactDOM.unmountComponentAtNode(this.icon);
357
+ }
358
+ }
359
+ export default function ({
360
+ getIntl,
361
+ isMobile,
362
+ api,
363
+ allowInteractiveExpand = true,
364
+ __livePage
365
+ }) {
366
+ return (node, view, getPos) => {
367
+ var _api$selection, _api$selection$action;
368
+ return new ExpandNodeView(node, view, getPos, getIntl, isMobile, api === null || api === void 0 ? void 0 : (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : (_api$selection$action = _api$selection.actions) === null || _api$selection$action === void 0 ? void 0 : _api$selection$action.selectNearNode, api, allowInteractiveExpand, __livePage);
369
+ };
370
+ }
@@ -1,10 +1,19 @@
1
+ import React from 'react';
1
2
  import { expand, extendedNestedExpand, nestedExpand } 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 { IconExpand } from '@atlaskit/editor-common/quick-insert';
6
+ import { createWrapSelectionTransaction } from '@atlaskit/editor-common/utils';
2
7
  import { getBooleanFF } from '@atlaskit/platform-feature-flags';
3
-
4
- // TODO: https://product-fabric.atlassian.net/browse/ED-22840
5
- // In ED-22840 make sure we update the ExpandPlugin type to use singlePlayerExpands own types
6
-
7
- export const expandPlugin = () => {
8
+ import { createExpandNode, insertExpand } from './commands';
9
+ import { expandKeymap } from './pm-plugins/keymap';
10
+ import { createPlugin } from './pm-plugins/main';
11
+ import { getToolbarConfig } from './toolbar';
12
+ export const expandPlugin = ({
13
+ config: options = {},
14
+ api
15
+ }) => {
16
+ var _api$analytics;
8
17
  return {
9
18
  name: 'expand',
10
19
  nodes() {
@@ -18,13 +27,63 @@ export const expandPlugin = () => {
18
27
  }];
19
28
  },
20
29
  actions: {
21
- insertExpand: () => {
22
- return false;
23
- }
30
+ insertExpand: insertExpand(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions)
24
31
  },
25
32
  pmPlugins() {
26
- return [];
33
+ return [{
34
+ name: 'expand',
35
+ plugin: ({
36
+ dispatch,
37
+ getIntl
38
+ }) => {
39
+ var _options$allowInterac;
40
+ return createPlugin(dispatch, getIntl, options.appearance, options.useLongPressSelection, api, (_options$allowInterac = options.allowInteractiveExpand) !== null && _options$allowInterac !== void 0 ? _options$allowInterac : true, options.__livePage);
41
+ }
42
+ }, {
43
+ name: 'expandKeymap',
44
+ plugin: () => expandKeymap(api, {
45
+ __livePage: options.__livePage
46
+ })
47
+ }];
27
48
  },
28
- pluginsOptions: {}
49
+ pluginsOptions: {
50
+ floatingToolbar: getToolbarConfig(api),
51
+ quickInsert: ({
52
+ formatMessage
53
+ }) => {
54
+ if (options && options.allowInsertion !== true) {
55
+ return [];
56
+ }
57
+ return [{
58
+ id: 'expand',
59
+ title: formatMessage(messages.expand),
60
+ description: formatMessage(messages.expandDescription),
61
+ keywords: ['accordion', 'collapse'],
62
+ priority: 600,
63
+ icon: () => /*#__PURE__*/React.createElement(IconExpand, null),
64
+ action(insert, state) {
65
+ var _api$analytics2;
66
+ const node = createExpandNode(state);
67
+ if (!node) {
68
+ return false;
69
+ }
70
+ const tr = state.selection.empty ? insert(node) : createWrapSelectionTransaction({
71
+ state,
72
+ type: node.type
73
+ });
74
+ api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.attachAnalyticsEvent({
75
+ action: ACTION.INSERTED,
76
+ actionSubject: ACTION_SUBJECT.DOCUMENT,
77
+ actionSubjectId: node.type === state.schema.nodes.nestedExpand ? ACTION_SUBJECT_ID.NESTED_EXPAND : ACTION_SUBJECT_ID.EXPAND,
78
+ attributes: {
79
+ inputMethod: INPUT_METHOD.QUICK_INSERT
80
+ },
81
+ eventType: EVENT_TYPE.TRACK
82
+ })(tr);
83
+ return tr;
84
+ }
85
+ }];
86
+ }
87
+ }
29
88
  };
30
89
  };