@atlaskit/editor-plugin-synced-block 3.5.1 → 3.6.1

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 (55) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/nodeviews/bodiedLazySyncedBlock.js +26 -0
  3. package/dist/cjs/nodeviews/bodiedSyncedBlock.js +87 -0
  4. package/dist/cjs/nodeviews/syncedBlock.js +8 -115
  5. package/dist/cjs/pm-plugins/actions.js +48 -40
  6. package/dist/cjs/pm-plugins/main.js +8 -2
  7. package/dist/cjs/pm-plugins/utils/track-sync-blocks.js +8 -0
  8. package/dist/cjs/pm-plugins/utils/utils.js +12 -2
  9. package/dist/cjs/syncedBlockPlugin.js +3 -0
  10. package/dist/cjs/ui/BodiedSyncBlockWrapper.js +25 -0
  11. package/dist/cjs/ui/CreateSyncedBlockDropdownItem.js +15 -2
  12. package/dist/cjs/ui/SyncBlockLabel.js +3 -2
  13. package/dist/cjs/ui/floating-toolbar.js +5 -3
  14. package/dist/es2019/nodeviews/bodiedLazySyncedBlock.js +16 -0
  15. package/dist/es2019/nodeviews/bodiedSyncedBlock.js +62 -0
  16. package/dist/es2019/nodeviews/syncedBlock.js +7 -96
  17. package/dist/es2019/pm-plugins/actions.js +56 -46
  18. package/dist/es2019/pm-plugins/main.js +8 -2
  19. package/dist/es2019/pm-plugins/utils/track-sync-blocks.js +8 -0
  20. package/dist/es2019/pm-plugins/utils/utils.js +11 -1
  21. package/dist/es2019/syncedBlockPlugin.js +4 -1
  22. package/dist/es2019/ui/BodiedSyncBlockWrapper.js +19 -0
  23. package/dist/es2019/ui/CreateSyncedBlockDropdownItem.js +16 -2
  24. package/dist/es2019/ui/SyncBlockLabel.js +3 -2
  25. package/dist/es2019/ui/floating-toolbar.js +12 -4
  26. package/dist/esm/nodeviews/bodiedLazySyncedBlock.js +15 -0
  27. package/dist/esm/nodeviews/bodiedSyncedBlock.js +80 -0
  28. package/dist/esm/nodeviews/syncedBlock.js +9 -116
  29. package/dist/esm/pm-plugins/actions.js +47 -39
  30. package/dist/esm/pm-plugins/main.js +8 -2
  31. package/dist/esm/pm-plugins/utils/track-sync-blocks.js +8 -0
  32. package/dist/esm/pm-plugins/utils/utils.js +11 -1
  33. package/dist/esm/syncedBlockPlugin.js +4 -1
  34. package/dist/esm/ui/BodiedSyncBlockWrapper.js +18 -0
  35. package/dist/esm/ui/CreateSyncedBlockDropdownItem.js +15 -2
  36. package/dist/esm/ui/SyncBlockLabel.js +3 -2
  37. package/dist/esm/ui/floating-toolbar.js +6 -4
  38. package/dist/types/nodeviews/bodiedLazySyncedBlock.d.ts +3 -0
  39. package/dist/types/nodeviews/bodiedSyncedBlock.d.ts +25 -0
  40. package/dist/types/nodeviews/syncedBlock.d.ts +1 -20
  41. package/dist/types/pm-plugins/utils/utils.d.ts +6 -2
  42. package/dist/types/syncedBlockPluginType.d.ts +2 -0
  43. package/dist/types/ui/BodiedSyncBlockWrapper.d.ts +9 -0
  44. package/dist/types-ts4.5/nodeviews/bodiedLazySyncedBlock.d.ts +3 -0
  45. package/dist/types-ts4.5/nodeviews/bodiedSyncedBlock.d.ts +25 -0
  46. package/dist/types-ts4.5/nodeviews/syncedBlock.d.ts +1 -20
  47. package/dist/types-ts4.5/pm-plugins/utils/utils.d.ts +6 -2
  48. package/dist/types-ts4.5/syncedBlockPluginType.d.ts +2 -0
  49. package/dist/types-ts4.5/ui/BodiedSyncBlockWrapper.d.ts +9 -0
  50. package/package.json +6 -6
  51. package/dist/cjs/ui/SyncBlockEditorWrapper.js +0 -45
  52. package/dist/es2019/ui/SyncBlockEditorWrapper.js +0 -29
  53. package/dist/esm/ui/SyncBlockEditorWrapper.js +0 -36
  54. package/dist/types/ui/SyncBlockEditorWrapper.d.ts +0 -16
  55. package/dist/types-ts4.5/ui/SyncBlockEditorWrapper.d.ts +0 -16
@@ -0,0 +1,62 @@
1
+ import React from 'react';
2
+ import ReactNodeView from '@atlaskit/editor-common/react-node-view';
3
+ import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
4
+ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
5
+ import { BodiedSyncBlockWrapper } from '../ui/BodiedSyncBlockWrapper';
6
+ const toDOM = () => ['div', {
7
+ class: BodiedSyncBlockSharedCssClassName.content,
8
+ contenteditable: true
9
+ }, 0];
10
+ class BodiedSyncBlock extends ReactNodeView {
11
+ constructor(props) {
12
+ super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
13
+ this.pluginOptions = props.pluginOptions;
14
+ }
15
+ createDomRef() {
16
+ const domRef = document.createElement('div');
17
+ domRef.classList.add(BodiedSyncBlockSharedCssClassName.prefix);
18
+ return domRef;
19
+ }
20
+ render(_props, forwardRef) {
21
+ var _this$pluginOptions;
22
+ return /*#__PURE__*/React.createElement(BodiedSyncBlockWrapper, {
23
+ ref: forwardRef,
24
+ dataProvider: (_this$pluginOptions = this.pluginOptions) === null || _this$pluginOptions === void 0 ? void 0 : _this$pluginOptions.dataProvider,
25
+ node: this.node
26
+ });
27
+ }
28
+ getContentDOM() {
29
+ const {
30
+ dom,
31
+ contentDOM
32
+ } = DOMSerializer.renderSpec(document, toDOM());
33
+ if (dom instanceof HTMLElement) {
34
+ return {
35
+ dom,
36
+ contentDOM
37
+ };
38
+ }
39
+ return undefined;
40
+ }
41
+ }
42
+ export const bodiedSyncBlockNodeView = ({
43
+ pluginOptions,
44
+ pmPluginFactoryParams,
45
+ api,
46
+ syncBlockStore
47
+ }) => (node, view, getPos) => {
48
+ const {
49
+ portalProviderAPI,
50
+ eventDispatcher
51
+ } = pmPluginFactoryParams;
52
+ return new BodiedSyncBlock({
53
+ api,
54
+ pluginOptions,
55
+ node,
56
+ view,
57
+ getPos,
58
+ portalProviderAPI,
59
+ eventDispatcher,
60
+ syncBlockStore
61
+ }).init();
62
+ };
@@ -1,21 +1,8 @@
1
1
  import React from 'react';
2
2
  import ReactNodeView from '@atlaskit/editor-common/react-node-view';
3
3
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
4
- import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
5
- import { convertSyncBlockPMNodeToSyncBlockData, useFetchDocNode, useHandleContentChanges } from '@atlaskit/editor-synced-block-provider';
6
- import { SyncBlockEditorWrapper, SyncBlockEditorWrapperDataId } from '../ui/SyncBlockEditorWrapper';
4
+ import { useFetchDocNode } from '@atlaskit/editor-synced-block-provider';
7
5
  import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
8
- const defaultSyncBlockEditorDocument = {
9
- version: 1,
10
- type: 'doc',
11
- content: [{
12
- type: 'paragraph',
13
- content: [{
14
- type: 'text',
15
- text: 'This is a source sync block. Edit me to update the content.'
16
- }]
17
- }]
18
- };
19
6
  const defaultSyncBlockRendererDocument = {
20
7
  version: 1,
21
8
  type: 'doc',
@@ -39,47 +26,9 @@ class SyncBlock extends ReactNodeView {
39
26
  domRef.classList.add(SyncBlockSharedCssClassName.prefix);
40
27
  return domRef;
41
28
  }
42
- isSource() {
43
- return this.syncBlockStore.isSourceBlock(this.node);
44
- }
45
- setInnerEditorView(editorView) {
46
- var _this$options, _this$options$dataPro;
47
- // set inner editor view
48
- this.syncBlockStore.setSyncBlockNestedEditorView(editorView);
49
- const nodes = [convertSyncBlockPMNodeToSyncBlockData(this.node, false)];
50
- (_this$options = this.options) === null || _this$options === void 0 ? void 0 : (_this$options$dataPro = _this$options.dataProvider) === null || _this$options$dataPro === void 0 ? void 0 : _this$options$dataPro.fetchNodesData(nodes).then(data => {
51
- var _data$;
52
- const tr = editorView.state.tr;
53
- if (data && (_data$ = data[0]) !== null && _data$ !== void 0 && _data$.content) {
54
- const newNode = editorView.state.schema.nodeFromJSON(data[0].content);
55
- editorView.dispatch(tr.replaceWith(0, editorView.state.doc.nodeSize - 2, newNode));
56
- }
57
- });
58
- }
59
- renderEditor() {
60
- var _this$options2, _this$options4;
61
- const fabricEditorPopupScrollParent = this.view.dom.closest('.fabric-editor-popup-scroll-parent');
62
- if (!(fabricEditorPopupScrollParent instanceof HTMLElement)) {
63
- return null;
64
- }
65
- if (!((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.getSyncedBlockEditor)) {
66
- return null;
67
- }
68
- return /*#__PURE__*/React.createElement(SyncBlockEditorWrapper, {
69
- popupsBoundariesElement: fabricEditorPopupScrollParent,
70
- popupsMountPoint: fabricEditorPopupScrollParent,
71
- defaultDocument: defaultSyncBlockEditorDocument,
72
- useHandleContentChanges: updatedDoc => {
73
- var _this$options3;
74
- return useHandleContentChanges(updatedDoc, this.isSource(), this.node, (_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.dataProvider);
75
- },
76
- setInnerEditorView: editorView => this.setInnerEditorView(editorView),
77
- getSyncedBlockEditor: (_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.getSyncedBlockEditor
78
- });
79
- }
80
- renderRenderer() {
81
- var _this$options5, _this$options7;
82
- if (!((_this$options5 = this.options) !== null && _this$options5 !== void 0 && _this$options5.getSyncedBlockRenderer)) {
29
+ render() {
30
+ var _this$options, _this$options3;
31
+ if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.getSyncedBlockRenderer)) {
83
32
  return null;
84
33
  }
85
34
 
@@ -87,58 +36,20 @@ class SyncBlock extends ReactNodeView {
87
36
 
88
37
  return /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
89
38
  useFetchDocNode: () => {
90
- var _this$options6;
91
- return useFetchDocNode(this.view, this.node, defaultSyncBlockRendererDocument, (_this$options6 = this.options) === null || _this$options6 === void 0 ? void 0 : _this$options6.dataProvider);
39
+ var _this$options2;
40
+ return useFetchDocNode(this.view, this.node, defaultSyncBlockRendererDocument, (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.dataProvider);
92
41
  },
93
- getSyncedBlockRenderer: (_this$options7 = this.options) === null || _this$options7 === void 0 ? void 0 : _this$options7.getSyncedBlockRenderer
42
+ getSyncedBlockRenderer: (_this$options3 = this.options) === null || _this$options3 === void 0 ? void 0 : _this$options3.getSyncedBlockRenderer
94
43
  });
95
44
  }
96
- render() {
97
- if (this.isSource()) {
98
- return this.renderEditor();
99
- }
100
- return this.renderRenderer();
101
- }
102
- stopEvent(event) {
103
- var _target$closest;
104
- const target = event.target;
105
- if (!target) {
106
- return false;
107
- }
108
- const isInNestedEditor = ((_target$closest = target.closest) === null || _target$closest === void 0 ? void 0 : _target$closest.call(target, `[data-testid="${SyncBlockEditorWrapperDataId}"]`)) != null;
109
- if (isInNestedEditor) {
110
- this.selectNode();
111
- return true;
112
- }
113
- return false;
114
- }
115
- selectNode() {
116
- this.selectSyncBlockNode(undefined);
117
- }
118
45
  destroy() {
119
46
  var _this$unsubscribe;
120
47
  if (this.fetchIntervalId) {
121
48
  window.clearInterval(this.fetchIntervalId);
122
49
  }
123
- this.syncBlockStore.setSyncBlockNestedEditorView(undefined);
124
50
  (_this$unsubscribe = this.unsubscribe) === null || _this$unsubscribe === void 0 ? void 0 : _this$unsubscribe.call(this);
125
51
  super.destroy();
126
52
  }
127
- selectSyncBlockNode(relativeSelectionPos) {
128
- var _this$reactComponentP, _this$reactComponentP2;
129
- const getPos = typeof this.getPos === 'function' ? this.getPos() : 0;
130
- const selectionAPI = (_this$reactComponentP = this.reactComponentProps.api) === null || _this$reactComponentP === void 0 ? void 0 : (_this$reactComponentP2 = _this$reactComponentP.selection) === null || _this$reactComponentP2 === void 0 ? void 0 : _this$reactComponentP2.actions;
131
- if (!selectionAPI) {
132
- return;
133
- }
134
- const tr = selectionAPI.selectNearNode({
135
- selectionRelativeToNode: relativeSelectionPos,
136
- selection: NodeSelection.create(this.view.state.doc, getPos !== null && getPos !== void 0 ? getPos : 0)
137
- })(this.view.state);
138
- if (tr) {
139
- this.view.dispatch(tr);
140
- }
141
- }
142
53
  }
143
54
  export const syncBlockNodeView = ({
144
55
  options,
@@ -1,6 +1,6 @@
1
- import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
2
- import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
3
- import { canBeConvertedToSyncBlock, findSyncBlock } from './utils/utils';
1
+ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
2
+ import { copyDomNode, toDOM } from '@atlaskit/editor-common/copy-button';
3
+ import { canBeConvertedToSyncBlock, findSyncBlock, findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from './utils/utils';
4
4
  export const createSyncedBlock = ({
5
5
  tr,
6
6
  syncBlockStore,
@@ -9,69 +9,79 @@ export const createSyncedBlock = ({
9
9
  const {
10
10
  schema: {
11
11
  nodes: {
12
- syncBlock,
13
- doc
12
+ bodiedSyncBlock,
13
+ paragraph
14
14
  }
15
15
  }
16
16
  } = tr.doc.type;
17
- const syncBlockNode = syncBlockStore.createSyncBlockNode();
18
- const node = syncBlock.createAndFill({
19
- ...syncBlockNode.attrs
20
- });
21
- if (!node) {
22
- return false;
23
- }
24
17
 
25
18
  // If the selection is empty, we want to insert the sync block on a new line
26
19
  if (tr.selection.empty) {
20
+ const storeSyncBlockNode = syncBlockStore.createSyncBlockNode();
21
+ const paragraphNode = paragraph.createAndFill({});
22
+ const newBodiedSyncBlockNode = bodiedSyncBlock.createAndFill({
23
+ ...storeSyncBlockNode.attrs
24
+ }, paragraphNode ? [paragraphNode] : []);
25
+ if (!newBodiedSyncBlockNode) {
26
+ return false;
27
+ }
27
28
  if (typeAheadInsert) {
28
- tr = typeAheadInsert(node);
29
+ tr = typeAheadInsert(newBodiedSyncBlockNode);
29
30
  } else {
30
- tr = tr.replaceSelectionWith(node).scrollIntoView();
31
+ tr = tr.replaceSelectionWith(newBodiedSyncBlockNode).scrollIntoView();
31
32
  }
32
33
  } else {
33
34
  const conversionInfo = canBeConvertedToSyncBlock(tr.selection);
34
- if (conversionInfo) {
35
- tr.replaceWith(conversionInfo.from, conversionInfo.to, node).scrollIntoView();
36
- const innerNodeJson = doc.create({}, conversionInfo.contentToInclude).toJSON();
37
-
38
- // TMP solution to wait for the nested editor view to be set
39
- // this will be removed once we have a proper architecture settled
40
- setTimeout(() => {
41
- const editorView = syncBlockStore.getSyncBlockNestedEditorView();
42
- if (editorView) {
43
- const innerTr = editorView.state.tr;
44
- const innerNode = editorView.state.schema.nodeFromJSON(innerNodeJson);
45
- editorView.dispatch(innerTr.replaceWith(0, editorView.state.doc.nodeSize - 2, innerNode));
46
- }
47
- }, 1000);
35
+ if (!conversionInfo) {
36
+ // TODO: EDITOR-1665 - Raise an error analytics event
37
+ return false;
48
38
  } else {
49
- var _safeInsert;
50
- // still insert an empty sync block if conversion is not possible
51
- (_safeInsert = safeInsert(syncBlock.createAndFill(syncBlockNode.attrs))(tr)) === null || _safeInsert === void 0 ? void 0 : _safeInsert.scrollIntoView();
39
+ const storeSyncBlockNode = syncBlockStore.createSyncBlockNode();
40
+ const newBodiedSyncBlockNode = bodiedSyncBlock.createAndFill({
41
+ ...storeSyncBlockNode.attrs
42
+ }, conversionInfo.contentToInclude);
43
+ if (!newBodiedSyncBlockNode) {
44
+ return false;
45
+ }
46
+ tr.replaceWith(conversionInfo.from - 1, conversionInfo.to, newBodiedSyncBlockNode).scrollIntoView();
52
47
  }
53
48
  }
54
49
  return tr;
55
50
  };
56
- export const copySyncedBlockReferenceToClipboard = api => (state, dispatch, _view) => {
57
- if (!(api !== null && api !== void 0 && api.floatingToolbar) || !dispatch) {
51
+ export const copySyncedBlockReferenceToClipboard = api => (state, _dispatch, _view) => {
52
+ if (!(api !== null && api !== void 0 && api.floatingToolbar)) {
58
53
  return false;
59
54
  }
60
- const {
61
- schema: {
62
- nodes: {
63
- syncBlock
55
+ const syncBlockFindResult = findSyncBlockOrBodiedSyncBlock(state);
56
+ if (!syncBlockFindResult) {
57
+ return false;
58
+ }
59
+ const isBodiedSyncBlock = isBodiedSyncBlockNode(syncBlockFindResult.node, state.schema.nodes.bodiedSyncBlock);
60
+ let referenceSyncBlockNode = null;
61
+ if (isBodiedSyncBlock) {
62
+ const {
63
+ schema: {
64
+ nodes: {
65
+ syncBlock
66
+ }
64
67
  }
65
- },
66
- tr
67
- } = state;
68
- const newTr = api.floatingToolbar.commands.copyNode(syncBlock, INPUT_METHOD.FLOATING_TB)({
69
- tr
70
- });
71
- if (!newTr) {
68
+ } = state.tr.doc.type;
69
+
70
+ // create sync block reference node
71
+ referenceSyncBlockNode = syncBlock.createAndFill({
72
+ resourceId: syncBlockFindResult.node.attrs.resourceId
73
+ });
74
+ if (!referenceSyncBlockNode) {
75
+ return false;
76
+ }
77
+ } else {
78
+ referenceSyncBlockNode = syncBlockFindResult.node;
79
+ }
80
+ if (!referenceSyncBlockNode) {
72
81
  return false;
73
82
  }
74
- dispatch(newTr);
83
+ const domNode = toDOM(referenceSyncBlockNode, state.tr.doc.type.schema);
84
+ copyDomNode(domNode, referenceSyncBlockNode.type, state.tr.selection);
75
85
  return true;
76
86
  };
77
87
  export const editSyncedBlockSource = (syncBlockStore, api) => (state, dispatch, _view) => {
@@ -112,7 +122,7 @@ export const removeSyncedBlock = api => (state, dispatch, _view) => {
112
122
  },
113
123
  tr
114
124
  } = state;
115
- const syncBlock = findSyncBlock(state);
125
+ const syncBlock = findSyncBlockOrBodiedSyncBlock(state);
116
126
  if (!syncBlock) {
117
127
  return false;
118
128
  }
@@ -1,5 +1,6 @@
1
1
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
2
  import { PluginKey } from '@atlaskit/editor-prosemirror/state';
3
+ import { lazyBodiedSyncBlockView } from '../nodeviews/bodiedLazySyncedBlock';
3
4
  import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
4
5
  import { trackSyncBlocks } from './utils/track-sync-blocks';
5
6
  export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
@@ -28,6 +29,12 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
28
29
  pmPluginFactoryParams,
29
30
  api,
30
31
  syncBlockStore
32
+ }),
33
+ bodiedSyncBlock: lazyBodiedSyncBlockView({
34
+ pluginOptions: options,
35
+ pmPluginFactoryParams,
36
+ api,
37
+ syncBlockStore
31
38
  })
32
39
  }
33
40
  },
@@ -36,7 +43,6 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
36
43
  return {
37
44
  destroy() {
38
45
  syncBlockStore.setEditorView(undefined);
39
- syncBlockStore.setSyncBlockNestedEditorView(undefined);
40
46
  }
41
47
  };
42
48
  },
@@ -61,7 +67,7 @@ export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api
61
67
  }
62
68
  return true;
63
69
  },
64
- appendTransaction: (trs, oldState, newState) => {
70
+ appendTransaction: (trs, _oldState, newState) => {
65
71
  trs.filter(tr => tr.docChanged).forEach(tr => {
66
72
  syncBlockStore === null || syncBlockStore === void 0 ? void 0 : syncBlockStore.rebaseTransaction(tr, newState);
67
73
  });
@@ -1,5 +1,13 @@
1
1
  import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
2
2
  export const trackSyncBlocks = (storeManager, tr, state) => {
3
+ // TODO: EDITOR-2430 - Disable tracking for now, it will be updated to handle the new bodied sync block
4
+ const dontTrack = true;
5
+ if (dontTrack) {
6
+ return {
7
+ removed: [],
8
+ added: []
9
+ };
10
+ }
3
11
  const sourceSyncBlockRemoved = {};
4
12
  const sourceSyncBlockAdded = {};
5
13
 
@@ -6,8 +6,18 @@ export const findSyncBlock = (state, selection) => {
6
6
  const {
7
7
  syncBlock
8
8
  } = state.schema.nodes;
9
- return findSelectedNodeOfType(syncBlock)(selection || state.selection) || findParentNodeOfType(syncBlock)(selection || state.selection);
9
+ return findSelectedNodeOfType(syncBlock)(selection || state.selection);
10
10
  };
11
+ export const findBodiedSyncBlock = (state, selection) => {
12
+ const {
13
+ bodiedSyncBlock
14
+ } = state.schema.nodes;
15
+ return findSelectedNodeOfType(bodiedSyncBlock)(selection || state.selection) || findParentNodeOfType(bodiedSyncBlock)(selection || state.selection);
16
+ };
17
+ export const findSyncBlockOrBodiedSyncBlock = (state, selection) => {
18
+ return findSyncBlock(state, selection) || findBodiedSyncBlock(state, selection);
19
+ };
20
+ export const isBodiedSyncBlockNode = (node, bodiedSyncBlock) => node.type === bodiedSyncBlock;
11
21
  export const canBeConvertedToSyncBlock = selection => {
12
22
  let from = selection.from;
13
23
  let to = selection.to;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { syncBlock } from '@atlaskit/adf-schema';
2
+ import { bodiedSyncBlock, syncBlock } from '@atlaskit/adf-schema';
3
3
  import { blockTypeMessages } from '@atlaskit/editor-common/messages';
4
4
  import { IconSyncBlock } from '@atlaskit/editor-common/quick-insert';
5
5
  import { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
@@ -21,6 +21,9 @@ export const syncedBlockPlugin = ({
21
21
  return [{
22
22
  name: 'syncBlock',
23
23
  node: syncBlock
24
+ }, {
25
+ name: 'bodiedSyncBlock',
26
+ node: bodiedSyncBlock
24
27
  }];
25
28
  },
26
29
  pmPlugins() {
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { useHandleContentChanges } from '@atlaskit/editor-synced-block-provider';
3
+ import { SyncBlockLabel } from './SyncBlockLabel';
4
+ export const BodiedSyncBlockWrapper = /*#__PURE__*/React.forwardRef(({
5
+ node,
6
+ dataProvider
7
+ }, ref) => {
8
+ // TODO: EDITOR-2429 - this should be debounced (either here or in the data provider) to avoid excessive API writes
9
+ const docJSON = {
10
+ version: 1,
11
+ type: 'doc',
12
+ content: node.content.toJSON()
13
+ };
14
+ useHandleContentChanges(docJSON, true, node, dataProvider);
15
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(SyncBlockLabel, null), /*#__PURE__*/React.createElement("div", {
16
+ "data-testid": "bodied-sync-block-wrapper",
17
+ ref: ref
18
+ }));
19
+ });
@@ -16,8 +16,22 @@ export const CreateSyncedBlockDropdownItem = ({
16
16
  return null;
17
17
  }
18
18
  const onClick = () => {
19
- var _api$core;
20
- api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock());
19
+ var _api$core, _api$core2;
20
+ api === null || api === void 0 ? void 0 : (_api$core = api.core) === null || _api$core === void 0 ? void 0 : _api$core.actions.execute(({
21
+ tr
22
+ }) => {
23
+ var _api$blockControls, _api$blockControls$co;
24
+ api === null || api === void 0 ? void 0 : api.syncedBlock.commands.insertSyncedBlock()({
25
+ tr
26
+ });
27
+ api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : (_api$blockControls$co = _api$blockControls.commands) === null || _api$blockControls$co === void 0 ? void 0 : _api$blockControls$co.toggleBlockMenu({
28
+ closeMenu: true
29
+ })({
30
+ tr
31
+ });
32
+ return tr;
33
+ });
34
+ api === null || api === void 0 ? void 0 : (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions.focus();
21
35
  };
22
36
  return /*#__PURE__*/React.createElement(ToolbarDropdownItem, {
23
37
  elemBefore: /*#__PURE__*/React.createElement(SyncBlocksIcon, {
@@ -1,16 +1,17 @@
1
1
  import React from 'react';
2
2
  import { useIntl } from 'react-intl-next';
3
3
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
4
+ import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
4
5
  const SyncBlockLabelDataId = 'sync-block-label';
5
6
  const SyncBlockLabelComponent = () => {
6
7
  const {
7
8
  formatMessage
8
9
  } = useIntl();
9
10
  return /*#__PURE__*/React.createElement("div", {
10
- "data-testId": SyncBlockLabelDataId
11
+ "data-testid": SyncBlockLabelDataId
11
12
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
12
13
  ,
13
- className: "ak-editor-sync-block__label"
14
+ className: SyncBlockLabelSharedCssClassName.labelClassName
14
15
  }, formatMessage(messages.syncedBlockLabel));
15
16
  };
16
17
  export const SyncBlockLabel = /*#__PURE__*/React.memo(SyncBlockLabelComponent);
@@ -6,17 +6,25 @@ import CopyIcon from '@atlaskit/icon/core/copy';
6
6
  import DeleteIcon from '@atlaskit/icon/core/delete';
7
7
  import LinkExternalIcon from '@atlaskit/icon/core/link-external';
8
8
  import { copySyncedBlockReferenceToClipboard, editSyncedBlockSource, removeSyncedBlock } from '../pm-plugins/actions';
9
- import { findSyncBlock } from '../pm-plugins/utils/utils';
9
+ import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plugins/utils/utils';
10
10
  export const getToolbarConfig = (state, intl, _options = {}, _providerFactory, api, syncBlockStore) => {
11
11
  var _api$decorations;
12
- const syncBlockObject = findSyncBlock(state);
12
+ const syncBlockObject = findSyncBlockOrBodiedSyncBlock(state);
13
13
  if (!syncBlockObject) {
14
14
  return;
15
15
  }
16
+ const {
17
+ schema: {
18
+ nodes: {
19
+ bodiedSyncBlock
20
+ }
21
+ }
22
+ } = state;
23
+ const isBodiedSyncBlock = isBodiedSyncBlockNode(syncBlockObject.node, bodiedSyncBlock);
16
24
  const {
17
25
  formatMessage
18
26
  } = intl;
19
- const nodeType = state.schema.nodes.syncBlock;
27
+ const nodeType = syncBlockObject.node.type;
20
28
  const hoverDecoration = api === null || api === void 0 ? void 0 : (_api$decorations = api.decorations) === null || _api$decorations === void 0 ? void 0 : _api$decorations.actions.hoverDecoration;
21
29
  const hoverDecorationProps = (nodeType, className) => ({
22
30
  onMouseEnter: hoverDecoration === null || hoverDecoration === void 0 ? void 0 : hoverDecoration(nodeType, true, className),
@@ -38,7 +46,7 @@ export const getToolbarConfig = (state, intl, _options = {}, _providerFactory, a
38
46
  };
39
47
  items.push(copyButton);
40
48
  const disabled = !syncBlockStore.getSyncBlockURL(syncBlockObject.node.attrs.resourceId);
41
- if (!syncBlockStore.isSourceBlock(syncBlockObject.node)) {
49
+ if (!isBodiedSyncBlock) {
42
50
  const editSourceButton = {
43
51
  id: 'editor.syncedBlock.editSource',
44
52
  type: 'button',
@@ -0,0 +1,15 @@
1
+ import { withLazyLoading } from '@atlaskit/editor-common/lazy-node-view';
2
+ export var lazyBodiedSyncBlockView = function lazyBodiedSyncBlockView(props) {
3
+ return withLazyLoading({
4
+ nodeName: 'bodiedSyncBlock',
5
+ getNodeViewOptions: function getNodeViewOptions() {},
6
+ loader: function loader() {
7
+ var result = import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-bodied-synced-block-nodeview" */
8
+ './bodiedSyncedBlock').then(function (_ref) {
9
+ var bodiedSyncBlockNodeView = _ref.bodiedSyncBlockNodeView;
10
+ return bodiedSyncBlockNodeView(props);
11
+ });
12
+ return result;
13
+ }
14
+ });
15
+ };
@@ -0,0 +1,80 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
4
+ import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
5
+ import _inherits from "@babel/runtime/helpers/inherits";
6
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
7
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
8
+ import React from 'react';
9
+ import ReactNodeView from '@atlaskit/editor-common/react-node-view';
10
+ import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
11
+ import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
12
+ import { BodiedSyncBlockWrapper } from '../ui/BodiedSyncBlockWrapper';
13
+ var toDOM = function toDOM() {
14
+ return ['div', {
15
+ class: BodiedSyncBlockSharedCssClassName.content,
16
+ contenteditable: true
17
+ }, 0];
18
+ };
19
+ var BodiedSyncBlock = /*#__PURE__*/function (_ReactNodeView) {
20
+ function BodiedSyncBlock(props) {
21
+ var _this;
22
+ _classCallCheck(this, BodiedSyncBlock);
23
+ _this = _callSuper(this, BodiedSyncBlock, [props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props]);
24
+ _this.pluginOptions = props.pluginOptions;
25
+ return _this;
26
+ }
27
+ _inherits(BodiedSyncBlock, _ReactNodeView);
28
+ return _createClass(BodiedSyncBlock, [{
29
+ key: "createDomRef",
30
+ value: function createDomRef() {
31
+ var domRef = document.createElement('div');
32
+ domRef.classList.add(BodiedSyncBlockSharedCssClassName.prefix);
33
+ return domRef;
34
+ }
35
+ }, {
36
+ key: "render",
37
+ value: function render(_props, forwardRef) {
38
+ var _this$pluginOptions;
39
+ return /*#__PURE__*/React.createElement(BodiedSyncBlockWrapper, {
40
+ ref: forwardRef,
41
+ dataProvider: (_this$pluginOptions = this.pluginOptions) === null || _this$pluginOptions === void 0 ? void 0 : _this$pluginOptions.dataProvider,
42
+ node: this.node
43
+ });
44
+ }
45
+ }, {
46
+ key: "getContentDOM",
47
+ value: function getContentDOM() {
48
+ var _DOMSerializer$render = DOMSerializer.renderSpec(document, toDOM()),
49
+ dom = _DOMSerializer$render.dom,
50
+ contentDOM = _DOMSerializer$render.contentDOM;
51
+ if (dom instanceof HTMLElement) {
52
+ return {
53
+ dom: dom,
54
+ contentDOM: contentDOM
55
+ };
56
+ }
57
+ return undefined;
58
+ }
59
+ }]);
60
+ }(ReactNodeView);
61
+ export var bodiedSyncBlockNodeView = function bodiedSyncBlockNodeView(_ref) {
62
+ var pluginOptions = _ref.pluginOptions,
63
+ pmPluginFactoryParams = _ref.pmPluginFactoryParams,
64
+ api = _ref.api,
65
+ syncBlockStore = _ref.syncBlockStore;
66
+ return function (node, view, getPos) {
67
+ var portalProviderAPI = pmPluginFactoryParams.portalProviderAPI,
68
+ eventDispatcher = pmPluginFactoryParams.eventDispatcher;
69
+ return new BodiedSyncBlock({
70
+ api: api,
71
+ pluginOptions: pluginOptions,
72
+ node: node,
73
+ view: view,
74
+ getPos: getPos,
75
+ portalProviderAPI: portalProviderAPI,
76
+ eventDispatcher: eventDispatcher,
77
+ syncBlockStore: syncBlockStore
78
+ }).init();
79
+ };
80
+ };