@atlaskit/editor-plugin-synced-block 2.1.0 → 2.2.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.
- package/CHANGELOG.md +19 -0
- package/afm-cc/tsconfig.json +9 -0
- package/afm-dev-agents/tsconfig.json +9 -0
- package/afm-jira/tsconfig.json +9 -0
- package/afm-passionfruit/tsconfig.json +9 -0
- package/afm-post-office/tsconfig.json +9 -0
- package/afm-rovo-extension/tsconfig.json +9 -0
- package/afm-townsquare/tsconfig.json +9 -0
- package/dist/cjs/nodeviews/syncedBlock.js +118 -75
- package/dist/cjs/pm-plugins/actions.js +23 -9
- package/dist/cjs/pm-plugins/main.js +34 -8
- package/dist/cjs/pm-plugins/utils/track-sync-blocks.js +54 -0
- package/dist/cjs/pm-plugins/utils/utils.js +11 -0
- package/dist/cjs/syncedBlockPlugin.js +12 -3
- package/dist/cjs/ui/ContentComponent.js +55 -0
- package/dist/cjs/ui/SyncBlockEditorWrapper.js +38 -0
- package/dist/cjs/ui/SyncBlockRendererWrapper.js +26 -0
- package/dist/cjs/ui/floating-toolbar.js +58 -3
- package/dist/es2019/nodeviews/syncedBlock.js +103 -67
- package/dist/es2019/pm-plugins/actions.js +23 -8
- package/dist/es2019/pm-plugins/main.js +35 -8
- package/dist/es2019/pm-plugins/utils/track-sync-blocks.js +50 -0
- package/dist/es2019/pm-plugins/utils/utils.js +7 -0
- package/dist/es2019/syncedBlockPlugin.js +10 -3
- package/dist/es2019/ui/ContentComponent.js +41 -0
- package/dist/es2019/ui/SyncBlockEditorWrapper.js +28 -0
- package/dist/es2019/ui/SyncBlockRendererWrapper.js +20 -0
- package/dist/es2019/ui/floating-toolbar.js +56 -2
- package/dist/esm/nodeviews/syncedBlock.js +116 -72
- package/dist/esm/pm-plugins/actions.js +21 -8
- package/dist/esm/pm-plugins/main.js +34 -8
- package/dist/esm/pm-plugins/utils/track-sync-blocks.js +48 -0
- package/dist/esm/pm-plugins/utils/utils.js +5 -0
- package/dist/esm/syncedBlockPlugin.js +12 -3
- package/dist/esm/ui/ContentComponent.js +46 -0
- package/dist/esm/ui/SyncBlockEditorWrapper.js +31 -0
- package/dist/esm/ui/SyncBlockRendererWrapper.js +19 -0
- package/dist/esm/ui/floating-toolbar.js +57 -3
- package/dist/types/nodeviews/syncedBlock.d.ts +29 -15
- package/dist/types/pm-plugins/actions.d.ts +3 -1
- package/dist/types/pm-plugins/main.d.ts +3 -3
- package/dist/types/pm-plugins/utils/track-sync-blocks.d.ts +7 -0
- package/dist/types/pm-plugins/utils/utils.d.ts +3 -0
- package/dist/types/syncedBlockPluginType.d.ts +8 -2
- package/dist/types/ui/ContentComponent.d.ts +5 -0
- package/dist/types/ui/SyncBlockEditorWrapper.d.ts +16 -0
- package/dist/types/ui/SyncBlockRendererWrapper.d.ts +9 -0
- package/dist/types/ui/floating-toolbar.d.ts +6 -2
- package/dist/types-ts4.5/nodeviews/syncedBlock.d.ts +29 -15
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +3 -1
- package/dist/types-ts4.5/pm-plugins/main.d.ts +3 -3
- package/dist/types-ts4.5/pm-plugins/utils/track-sync-blocks.d.ts +7 -0
- package/dist/types-ts4.5/pm-plugins/utils/utils.d.ts +3 -0
- package/dist/types-ts4.5/syncedBlockPluginType.d.ts +10 -2
- package/dist/types-ts4.5/ui/ContentComponent.d.ts +5 -0
- package/dist/types-ts4.5/ui/SyncBlockEditorWrapper.d.ts +16 -0
- package/dist/types-ts4.5/ui/SyncBlockRendererWrapper.d.ts +9 -0
- package/dist/types-ts4.5/ui/floating-toolbar.d.ts +6 -2
- package/package.json +8 -4
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.ContentComponent = void 0;
|
|
9
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
var _new = _interopRequireDefault(require("@atlaskit/button/new"));
|
|
12
|
+
var _modalDialog = _interopRequireWildcard(require("@atlaskit/modal-dialog"));
|
|
13
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
14
|
+
var ContentComponent = exports.ContentComponent = function ContentComponent(_ref) {
|
|
15
|
+
var syncBlockStoreManager = _ref.syncBlockStoreManager;
|
|
16
|
+
var _useState = (0, _react.useState)(false),
|
|
17
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
18
|
+
isOpen = _useState2[0],
|
|
19
|
+
setIsOpen = _useState2[1];
|
|
20
|
+
var resolverRef = _react.default.useRef(undefined);
|
|
21
|
+
var handleClose = (0, _react.useCallback)(function (confirm) {
|
|
22
|
+
return function () {
|
|
23
|
+
if (resolverRef.current) {
|
|
24
|
+
resolverRef.current(confirm);
|
|
25
|
+
resolverRef.current = undefined;
|
|
26
|
+
}
|
|
27
|
+
setIsOpen(false);
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
var confirmationCallback = (0, _react.useCallback)(function () {
|
|
31
|
+
setIsOpen(true);
|
|
32
|
+
var confirmedPromise = new Promise(function (resolve) {
|
|
33
|
+
resolverRef.current = resolve;
|
|
34
|
+
});
|
|
35
|
+
return confirmedPromise;
|
|
36
|
+
}, []);
|
|
37
|
+
(0, _react.useEffect)(function () {
|
|
38
|
+
var unregister = syncBlockStoreManager.registerConfirmationCallback(confirmationCallback);
|
|
39
|
+
return function () {
|
|
40
|
+
unregister();
|
|
41
|
+
};
|
|
42
|
+
}, [syncBlockStoreManager, confirmationCallback]);
|
|
43
|
+
return /*#__PURE__*/_react.default.createElement(_modalDialog.ModalTransition, null, isOpen && /*#__PURE__*/_react.default.createElement(_modalDialog.default, {
|
|
44
|
+
onClose: handleClose(false)
|
|
45
|
+
}, /*#__PURE__*/_react.default.createElement(_modalDialog.ModalHeader, {
|
|
46
|
+
hasCloseButton: true
|
|
47
|
+
}, /*#__PURE__*/_react.default.createElement(_modalDialog.ModalTitle, null, "Confirmation")), /*#__PURE__*/_react.default.createElement(_modalDialog.ModalBody, null, /*#__PURE__*/_react.default.createElement("div", null, "Are you sure you want to delete this synced block?")), /*#__PURE__*/_react.default.createElement(_modalDialog.ModalFooter, null, /*#__PURE__*/_react.default.createElement(_new.default, {
|
|
48
|
+
appearance: "subtle",
|
|
49
|
+
onClick: handleClose(false)
|
|
50
|
+
}, "Cancel"), /*#__PURE__*/_react.default.createElement(_new.default, {
|
|
51
|
+
appearance: "danger",
|
|
52
|
+
onClick: handleClose(true),
|
|
53
|
+
autoFocus: true
|
|
54
|
+
}, "Delete"))));
|
|
55
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.SyncBlockEditorWrapperDataId = exports.SyncBlockEditorWrapper = void 0;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var SyncBlockEditorWrapperDataId = exports.SyncBlockEditorWrapperDataId = 'sync-block-plugin-editor-wrapper';
|
|
10
|
+
var SyncBlockEditorWrapperComponent = function SyncBlockEditorWrapperComponent(_ref) {
|
|
11
|
+
var defaultDocument = _ref.defaultDocument,
|
|
12
|
+
getSyncedBlockEditor = _ref.getSyncedBlockEditor,
|
|
13
|
+
popupsBoundariesElement = _ref.popupsBoundariesElement,
|
|
14
|
+
popupsMountPoint = _ref.popupsMountPoint,
|
|
15
|
+
setInnerEditorView = _ref.setInnerEditorView,
|
|
16
|
+
handleContentChanges = _ref.handleContentChanges;
|
|
17
|
+
return (
|
|
18
|
+
/*#__PURE__*/
|
|
19
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/design-system/ensure-design-token-usage
|
|
20
|
+
_react.default.createElement("div", {
|
|
21
|
+
"data-testid": SyncBlockEditorWrapperDataId,
|
|
22
|
+
style: {
|
|
23
|
+
border: 'purple solid 1px'
|
|
24
|
+
}
|
|
25
|
+
}, getSyncedBlockEditor({
|
|
26
|
+
popupsBoundariesElement: popupsBoundariesElement,
|
|
27
|
+
defaultDocument: defaultDocument,
|
|
28
|
+
popupsMountPoint: popupsMountPoint,
|
|
29
|
+
onChange: function onChange(value) {
|
|
30
|
+
return handleContentChanges(value.state.doc);
|
|
31
|
+
},
|
|
32
|
+
onEditorReady: function onEditorReady(value) {
|
|
33
|
+
return setInnerEditorView(value.editorView);
|
|
34
|
+
}
|
|
35
|
+
}))
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
var SyncBlockEditorWrapper = exports.SyncBlockEditorWrapper = /*#__PURE__*/_react.default.memo(SyncBlockEditorWrapperComponent);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.SyncBlockRendererWrapper = void 0;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
10
|
+
var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) {
|
|
11
|
+
var getSyncedBlockRenderer = _ref.getSyncedBlockRenderer,
|
|
12
|
+
docNode = _ref.docNode;
|
|
13
|
+
return (
|
|
14
|
+
/*#__PURE__*/
|
|
15
|
+
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop, @atlaskit/design-system/ensure-design-token-usage
|
|
16
|
+
_react.default.createElement("div", {
|
|
17
|
+
"data-testid": SyncBlockRendererWrapperDataId,
|
|
18
|
+
style: {
|
|
19
|
+
border: 'blue solid 1px'
|
|
20
|
+
}
|
|
21
|
+
}, getSyncedBlockRenderer({
|
|
22
|
+
docNode: docNode
|
|
23
|
+
}))
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
var SyncBlockRendererWrapper = exports.SyncBlockRendererWrapper = /*#__PURE__*/_react.default.memo(SyncBlockRendererWrapperComponent);
|
|
@@ -1,11 +1,66 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
3
4
|
Object.defineProperty(exports, "__esModule", {
|
|
4
5
|
value: true
|
|
5
6
|
});
|
|
6
7
|
exports.getToolbarConfig = void 0;
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
var _utils = require("@atlaskit/editor-prosemirror/utils");
|
|
9
|
+
var _copy = _interopRequireDefault(require("@atlaskit/icon/core/copy"));
|
|
10
|
+
var _linkExternal = _interopRequireDefault(require("@atlaskit/icon/core/link-external"));
|
|
11
|
+
var _actions = require("../pm-plugins/actions");
|
|
12
|
+
var _utils2 = require("../pm-plugins/utils/utils");
|
|
13
|
+
var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig(state, _intl) {
|
|
14
|
+
var _options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
15
|
+
var _providerFactory = arguments.length > 3 ? arguments[3] : undefined;
|
|
16
|
+
var syncBlockObject = (0, _utils2.findSyncBlock)(state);
|
|
17
|
+
if (!syncBlockObject) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
var nodeType = state.schema.nodes.syncBlock;
|
|
21
|
+
var items = [];
|
|
22
|
+
var copyButton = {
|
|
23
|
+
id: 'editor.syncedBlock.copy',
|
|
24
|
+
type: 'button',
|
|
25
|
+
appearance: 'subtle',
|
|
26
|
+
icon: _copy.default,
|
|
27
|
+
title: 'Copy',
|
|
28
|
+
showTitle: true,
|
|
29
|
+
tooltipContent: 'Copy reference to clipboard',
|
|
30
|
+
onClick: _actions.copySyncedBlockReferenceToClipboard
|
|
31
|
+
};
|
|
32
|
+
items.push(copyButton);
|
|
33
|
+
if (syncBlockObject.node.attrs.resourceId !== syncBlockObject.node.attrs.localId) {
|
|
34
|
+
var editSourceButton = {
|
|
35
|
+
id: 'editor.syncedBlock.editSource',
|
|
36
|
+
type: 'button',
|
|
37
|
+
appearance: 'subtle',
|
|
38
|
+
icon: _linkExternal.default,
|
|
39
|
+
title: 'Edit source',
|
|
40
|
+
showTitle: true,
|
|
41
|
+
tooltipContent: 'Navigate to source page of the sync block',
|
|
42
|
+
disabled: true,
|
|
43
|
+
onClick: function onClick(_state, _dispatch, view) {
|
|
44
|
+
if (!view) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// to be implemented in a follow up PR
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
items.push(editSourceButton);
|
|
52
|
+
}
|
|
53
|
+
var getDomRef = function getDomRef(editorView) {
|
|
54
|
+
var domAtPos = editorView.domAtPos.bind(editorView);
|
|
55
|
+
var element = (0, _utils.findDomRefAtPos)(syncBlockObject.pos, domAtPos);
|
|
56
|
+
return element;
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
title: 'Synced Block floating controls',
|
|
60
|
+
getDomRef: getDomRef,
|
|
61
|
+
nodeType: nodeType,
|
|
62
|
+
items: items,
|
|
63
|
+
scrollable: true,
|
|
64
|
+
groupLabel: 'Synced blocks'
|
|
10
65
|
};
|
|
11
66
|
};
|
|
@@ -1,105 +1,141 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { useMemo, useRef, useState } from 'react';
|
|
1
|
+
import React from 'react';
|
|
3
2
|
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
4
|
-
|
|
3
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { SyncBlockEditorWrapper, SyncBlockEditorWrapperDataId } from '../ui/SyncBlockEditorWrapper';
|
|
5
|
+
import { SyncBlockRendererWrapper } from '../ui/SyncBlockRendererWrapper';
|
|
6
|
+
const defaultSyncBlockEditorDocument = {
|
|
5
7
|
version: 1,
|
|
6
8
|
type: 'doc',
|
|
7
9
|
content: [{
|
|
8
10
|
type: 'paragraph',
|
|
9
11
|
content: [{
|
|
10
12
|
type: 'text',
|
|
11
|
-
text: 'This is a
|
|
13
|
+
text: 'This is a source sync block. Edit me to update the content.'
|
|
12
14
|
}]
|
|
13
15
|
}]
|
|
14
16
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const content = editorView.state.doc.toJSON().content;
|
|
26
|
-
const rendererDocument = {
|
|
27
|
-
version: 1,
|
|
28
|
-
type: 'doc',
|
|
29
|
-
content
|
|
30
|
-
};
|
|
31
|
-
setRendererDocument(rendererDocument);
|
|
32
|
-
};
|
|
33
|
-
const onEditorReady = ({
|
|
34
|
-
editorView
|
|
35
|
-
}) => {
|
|
36
|
-
innerEditorView.current = editorView || null;
|
|
37
|
-
};
|
|
38
|
-
const boundariesElement = useMemo(() => {
|
|
39
|
-
// eslint-disable-next-line @atlaskit/editor/no-as-casting
|
|
40
|
-
return dom.closest('.fabric-editor-popup-scroll-parent');
|
|
41
|
-
}, [dom]);
|
|
42
|
-
if (!boundariesElement || !(boundariesElement instanceof HTMLElement)) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
if (!(config !== null && config !== void 0 && config.getSyncedBlockEditor) || !(config !== null && config !== void 0 && config.getSyncedBlockRenderer)) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return /*#__PURE__*/React.createElement("div", {
|
|
49
|
-
"data-testid": SyncBlockEditorWrapperDataId
|
|
50
|
-
}, config.getSyncedBlockEditor({
|
|
51
|
-
boundariesElement: boundariesElement,
|
|
52
|
-
defaultDocument: defaultSyncBlockDocument,
|
|
53
|
-
mountPoint: dom,
|
|
54
|
-
onChange: onChange,
|
|
55
|
-
onEditorReady: onEditorReady
|
|
56
|
-
}), /*#__PURE__*/React.createElement("div", {
|
|
57
|
-
style: {
|
|
58
|
-
width: '100%',
|
|
59
|
-
height: '1px',
|
|
60
|
-
// eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage
|
|
61
|
-
backgroundColor: 'purple'
|
|
62
|
-
}
|
|
63
|
-
}), config.getSyncedBlockRenderer({
|
|
64
|
-
docNode: rendererDocument
|
|
65
|
-
}));
|
|
17
|
+
const defaultSyncBlockRendererDocument = {
|
|
18
|
+
version: 1,
|
|
19
|
+
type: 'doc',
|
|
20
|
+
content: [{
|
|
21
|
+
type: 'paragraph',
|
|
22
|
+
content: [{
|
|
23
|
+
type: 'text',
|
|
24
|
+
text: 'This is a reference sync block. Stay tuned for updates...'
|
|
25
|
+
}]
|
|
26
|
+
}]
|
|
66
27
|
};
|
|
67
28
|
class SyncBlock extends ReactNodeView {
|
|
29
|
+
constructor(props) {
|
|
30
|
+
super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
|
|
31
|
+
const {
|
|
32
|
+
resourceId,
|
|
33
|
+
localId
|
|
34
|
+
} = props.node.attrs;
|
|
35
|
+
// Temporary solution to identify the source
|
|
36
|
+
this.isSource = resourceId === localId;
|
|
37
|
+
this.options = props.options;
|
|
38
|
+
}
|
|
68
39
|
createDomRef() {
|
|
69
40
|
const domRef = document.createElement('div');
|
|
70
|
-
domRef.setAttribute('style', 'border: purple solid 1px;');
|
|
71
41
|
return domRef;
|
|
72
42
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
43
|
+
handleContentChanges(_updatedDoc) {
|
|
44
|
+
// write data
|
|
45
|
+
}
|
|
46
|
+
setInnerEditorView(_editorView) {
|
|
47
|
+
// set inner editor view
|
|
48
|
+
}
|
|
49
|
+
renderEditor() {
|
|
50
|
+
var _this$options, _this$options2;
|
|
51
|
+
const popupsBoundariesElement = this.dom.closest('.fabric-editor-popup-scroll-parent');
|
|
52
|
+
if (!(popupsBoundariesElement instanceof HTMLElement)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
if (!((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.getSyncedBlockEditor)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return /*#__PURE__*/React.createElement(SyncBlockEditorWrapper, {
|
|
59
|
+
popupsBoundariesElement: popupsBoundariesElement,
|
|
60
|
+
popupsMountPoint: this.dom,
|
|
61
|
+
defaultDocument: defaultSyncBlockEditorDocument,
|
|
62
|
+
handleContentChanges: this.handleContentChanges,
|
|
63
|
+
setInnerEditorView: this.setInnerEditorView,
|
|
64
|
+
getSyncedBlockEditor: (_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.getSyncedBlockEditor
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
renderRenderer() {
|
|
68
|
+
var _this$options3, _this$options4;
|
|
69
|
+
if (!((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.getSyncedBlockRenderer)) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// get document node from data provider
|
|
74
|
+
const docNode = defaultSyncBlockRendererDocument;
|
|
75
|
+
return /*#__PURE__*/React.createElement(SyncBlockRendererWrapper, {
|
|
76
|
+
docNode: docNode,
|
|
77
|
+
getSyncedBlockRenderer: (_this$options4 = this.options) === null || _this$options4 === void 0 ? void 0 : _this$options4.getSyncedBlockRenderer
|
|
77
78
|
});
|
|
78
79
|
}
|
|
80
|
+
render() {
|
|
81
|
+
if (this.isSource) {
|
|
82
|
+
return this.renderEditor();
|
|
83
|
+
}
|
|
84
|
+
return this.renderRenderer();
|
|
85
|
+
}
|
|
79
86
|
stopEvent(event) {
|
|
80
87
|
var _target$closest;
|
|
81
88
|
const target = event.target;
|
|
82
89
|
if (!target) {
|
|
83
90
|
return false;
|
|
84
91
|
}
|
|
85
|
-
|
|
92
|
+
const isInNestedEditor = ((_target$closest = target.closest) === null || _target$closest === void 0 ? void 0 : _target$closest.call(target, `[data-testid="${SyncBlockEditorWrapperDataId}"]`)) != null;
|
|
93
|
+
if (isInNestedEditor) {
|
|
94
|
+
this.selectNode();
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
selectNode() {
|
|
100
|
+
this.selectSyncBlockNode(undefined);
|
|
86
101
|
}
|
|
87
102
|
destroy() {
|
|
88
103
|
var _this$unsubscribe;
|
|
89
104
|
(_this$unsubscribe = this.unsubscribe) === null || _this$unsubscribe === void 0 ? void 0 : _this$unsubscribe.call(this);
|
|
90
105
|
super.destroy();
|
|
91
106
|
}
|
|
107
|
+
selectSyncBlockNode(relativeSelectionPos) {
|
|
108
|
+
var _this$reactComponentP, _this$reactComponentP2;
|
|
109
|
+
const getPos = typeof this.getPos === 'function' ? this.getPos() : 0;
|
|
110
|
+
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;
|
|
111
|
+
if (!selectionAPI) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const tr = selectionAPI.selectNearNode({
|
|
115
|
+
selectionRelativeToNode: relativeSelectionPos,
|
|
116
|
+
selection: NodeSelection.create(this.view.state.doc, getPos !== null && getPos !== void 0 ? getPos : 0)
|
|
117
|
+
})(this.view.state);
|
|
118
|
+
if (tr) {
|
|
119
|
+
this.view.dispatch(tr);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
92
122
|
}
|
|
93
123
|
export const syncBlockNodeView = ({
|
|
94
|
-
|
|
95
|
-
pmPluginFactoryParams
|
|
124
|
+
options,
|
|
125
|
+
pmPluginFactoryParams,
|
|
126
|
+
api
|
|
96
127
|
}) => (node, view, getPos) => {
|
|
97
128
|
const {
|
|
98
129
|
portalProviderAPI,
|
|
99
130
|
eventDispatcher
|
|
100
131
|
} = pmPluginFactoryParams;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
132
|
+
return new SyncBlock({
|
|
133
|
+
api,
|
|
134
|
+
options,
|
|
135
|
+
node,
|
|
136
|
+
view,
|
|
137
|
+
getPos,
|
|
138
|
+
portalProviderAPI,
|
|
139
|
+
eventDispatcher
|
|
140
|
+
}).init();
|
|
105
141
|
};
|
|
@@ -1,19 +1,34 @@
|
|
|
1
|
+
import uuid from 'uuid';
|
|
2
|
+
import { toDOM, copyDomNode } from '@atlaskit/editor-common/copy-button';
|
|
3
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
1
4
|
import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
2
|
-
const getRandomId = () => {
|
|
3
|
-
if (!globalThis.crypto || typeof globalThis.crypto.randomUUID !== 'function') {
|
|
4
|
-
return new Date().toISOString();
|
|
5
|
-
}
|
|
6
|
-
return globalThis.crypto.randomUUID();
|
|
7
|
-
};
|
|
8
5
|
export const createSyncedBlock = state => {
|
|
6
|
+
const id = uuid();
|
|
9
7
|
const tr = state.tr;
|
|
10
8
|
// const { breakout } = state.schema.marks;
|
|
11
9
|
const node = state.schema.nodes.syncBlock.createChecked({
|
|
12
|
-
resourceId:
|
|
13
|
-
localId:
|
|
10
|
+
resourceId: id,
|
|
11
|
+
localId: id
|
|
14
12
|
}, null
|
|
15
13
|
// [breakout.create({ mode: 'wide' })],
|
|
16
14
|
);
|
|
17
15
|
safeInsert(node)(tr);
|
|
18
16
|
return tr;
|
|
17
|
+
};
|
|
18
|
+
export const copySyncedBlockReferenceToClipboard = (state, _dispatch, _view) => {
|
|
19
|
+
const {
|
|
20
|
+
schema,
|
|
21
|
+
selection
|
|
22
|
+
} = state;
|
|
23
|
+
if (selection instanceof NodeSelection) {
|
|
24
|
+
const nodeType = selection.node.type;
|
|
25
|
+
const domNode = toDOM(selection.node, schema);
|
|
26
|
+
// clear local-id
|
|
27
|
+
if (domNode instanceof HTMLElement) {
|
|
28
|
+
domNode.setAttribute('data-local-id', '');
|
|
29
|
+
}
|
|
30
|
+
copyDomNode(domNode, nodeType, selection);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
19
34
|
};
|
|
@@ -1,32 +1,59 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
3
3
|
import { lazySyncBlockView } from '../nodeviews/lazySyncedBlock';
|
|
4
|
+
import { trackSyncBlocks } from './utils/track-sync-blocks';
|
|
4
5
|
export const syncedBlockPluginKey = new PluginKey('syncedBlockPlugin');
|
|
5
6
|
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
7
8
|
|
|
8
|
-
export const createPlugin = (
|
|
9
|
+
export const createPlugin = (options, pmPluginFactoryParams, syncBlockStore, api) => {
|
|
9
10
|
return new SafePlugin({
|
|
10
11
|
key: syncedBlockPluginKey,
|
|
11
12
|
state: {
|
|
12
13
|
init() {
|
|
13
14
|
return {};
|
|
14
15
|
},
|
|
15
|
-
apply: (
|
|
16
|
-
const meta = tr.getMeta(syncedBlockPluginKey);
|
|
17
|
-
if (meta) {
|
|
18
|
-
return meta;
|
|
19
|
-
}
|
|
16
|
+
apply: (_tr, currentPluginState) => {
|
|
20
17
|
return currentPluginState;
|
|
21
18
|
}
|
|
22
19
|
},
|
|
23
20
|
props: {
|
|
24
21
|
nodeViews: {
|
|
25
22
|
syncBlock: lazySyncBlockView({
|
|
26
|
-
|
|
27
|
-
pmPluginFactoryParams
|
|
23
|
+
options,
|
|
24
|
+
pmPluginFactoryParams,
|
|
25
|
+
api
|
|
28
26
|
})
|
|
29
27
|
}
|
|
28
|
+
},
|
|
29
|
+
view: editorView => {
|
|
30
|
+
syncBlockStore.setEditorView(editorView);
|
|
31
|
+
return {
|
|
32
|
+
destroy() {
|
|
33
|
+
syncBlockStore.setEditorView(undefined);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
filterTransaction: (tr, state) => {
|
|
38
|
+
// Ignore transactions that don't change the document
|
|
39
|
+
// or are from remote (collab) or already confirmed sync block deletion
|
|
40
|
+
// We only care about local changes that change the document
|
|
41
|
+
// and are not yet confirmed for sync block deletion
|
|
42
|
+
if (!tr.docChanged || !(syncBlockStore !== null && syncBlockStore !== void 0 && syncBlockStore.requireConfirmationBeforeDelete()) || Boolean(tr.getMeta('isRemote')) || Boolean(tr.getMeta('isConfirmedSyncBlockDeletion'))) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
const {
|
|
46
|
+
removed
|
|
47
|
+
} = trackSyncBlocks(syncBlockStore, tr, state);
|
|
48
|
+
if (removed.length > 0) {
|
|
49
|
+
// If there are source sync blocks being removed, and we need to confirm with user before deleting,
|
|
50
|
+
// we block the transaction here, and wait for user confirmation to proceed with deletion.
|
|
51
|
+
// See editor-common/src/sync-block/sync-block-store-manager.ts for how we handle user confirmation and
|
|
52
|
+
// proceed with deletion.
|
|
53
|
+
syncBlockStore.deleteSyncBlocksWithConfirmation(tr, removed);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
30
57
|
}
|
|
31
58
|
});
|
|
32
59
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
|
|
2
|
+
export const trackSyncBlocks = (storeManager, tr, state) => {
|
|
3
|
+
const sourceSyncBlockRemoved = {};
|
|
4
|
+
const sourceSyncBlockAdded = {};
|
|
5
|
+
tr.steps.map(step => {
|
|
6
|
+
if (step instanceof ReplaceStep || step instanceof ReplaceAroundStep) {
|
|
7
|
+
const {
|
|
8
|
+
from,
|
|
9
|
+
to
|
|
10
|
+
} = step;
|
|
11
|
+
// replaced a range, check for deleted syncBlock
|
|
12
|
+
if (from !== to) {
|
|
13
|
+
state.doc.nodesBetween(step.from, step.to, node => {
|
|
14
|
+
if (storeManager.isSourceBlock(node)) {
|
|
15
|
+
if (sourceSyncBlockAdded[node.attrs.localId]) {
|
|
16
|
+
// If a source block added and then removed in the same transaction,
|
|
17
|
+
// we treat it as no-op.
|
|
18
|
+
delete sourceSyncBlockAdded[node.attrs.localId];
|
|
19
|
+
} else {
|
|
20
|
+
sourceSyncBlockRemoved[node.attrs.localId] = node.attrs;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// we don't need to go deeper
|
|
24
|
+
return false;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// replaced content, check for inserted syncBlock
|
|
29
|
+
if (step.slice.content.size > 0) {
|
|
30
|
+
step.slice.content.nodesBetween(0, step.slice.content.size, node => {
|
|
31
|
+
if (storeManager.isSourceBlock(node)) {
|
|
32
|
+
if (sourceSyncBlockRemoved[node.attrs.localId]) {
|
|
33
|
+
// If a source block is removed and added back in the same transaction,
|
|
34
|
+
// we treat it as no-op.
|
|
35
|
+
delete sourceSyncBlockRemoved[node.attrs.localId];
|
|
36
|
+
} else {
|
|
37
|
+
sourceSyncBlockAdded[node.attrs.localId] = node.attrs;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// we don't need to go deeper
|
|
41
|
+
return false;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
removed: Object.values(sourceSyncBlockRemoved),
|
|
48
|
+
added: Object.values(sourceSyncBlockAdded)
|
|
49
|
+
};
|
|
50
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { findParentNodeOfType, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
2
|
+
export const findSyncBlock = (state, selection) => {
|
|
3
|
+
const {
|
|
4
|
+
syncBlock
|
|
5
|
+
} = state.schema.nodes;
|
|
6
|
+
return findSelectedNodeOfType(syncBlock)(selection || state.selection) || findParentNodeOfType(syncBlock)(selection || state.selection);
|
|
7
|
+
};
|
|
@@ -4,9 +4,11 @@ import { SyncBlockStoreManager } from '@atlaskit/editor-common/sync-block';
|
|
|
4
4
|
import SmartLinkIcon from '@atlaskit/icon/core/smart-link';
|
|
5
5
|
import { createSyncedBlock } from './pm-plugins/actions';
|
|
6
6
|
import { createPlugin } from './pm-plugins/main';
|
|
7
|
+
import { ContentComponent } from './ui/ContentComponent';
|
|
7
8
|
import { getToolbarConfig } from './ui/floating-toolbar';
|
|
8
9
|
export const syncedBlockPlugin = ({
|
|
9
|
-
config
|
|
10
|
+
config,
|
|
11
|
+
api
|
|
10
12
|
}) => {
|
|
11
13
|
const syncBlockStore = new SyncBlockStoreManager(config === null || config === void 0 ? void 0 : config.dataProvider);
|
|
12
14
|
return {
|
|
@@ -20,7 +22,7 @@ export const syncedBlockPlugin = ({
|
|
|
20
22
|
pmPlugins() {
|
|
21
23
|
return [{
|
|
22
24
|
name: 'syncedBlockPlugin',
|
|
23
|
-
plugin: params => createPlugin(config, params, syncBlockStore)
|
|
25
|
+
plugin: params => createPlugin(config, params, syncBlockStore, api)
|
|
24
26
|
}];
|
|
25
27
|
},
|
|
26
28
|
pluginsOptions: {
|
|
@@ -38,7 +40,12 @@ export const syncedBlockPlugin = ({
|
|
|
38
40
|
return createSyncedBlock(state);
|
|
39
41
|
}
|
|
40
42
|
}],
|
|
41
|
-
floatingToolbar: getToolbarConfig()
|
|
43
|
+
floatingToolbar: (state, intl, providerFactory) => getToolbarConfig(state, intl, config, providerFactory)
|
|
44
|
+
},
|
|
45
|
+
contentComponent: () => {
|
|
46
|
+
return /*#__PURE__*/React.createElement(ContentComponent, {
|
|
47
|
+
syncBlockStoreManager: syncBlockStore
|
|
48
|
+
});
|
|
42
49
|
}
|
|
43
50
|
};
|
|
44
51
|
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import Button from '@atlaskit/button/new';
|
|
3
|
+
import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
|
|
4
|
+
export const ContentComponent = ({
|
|
5
|
+
syncBlockStoreManager
|
|
6
|
+
}) => {
|
|
7
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
+
const resolverRef = React.useRef(undefined);
|
|
9
|
+
const handleClose = useCallback(confirm => () => {
|
|
10
|
+
if (resolverRef.current) {
|
|
11
|
+
resolverRef.current(confirm);
|
|
12
|
+
resolverRef.current = undefined;
|
|
13
|
+
}
|
|
14
|
+
setIsOpen(false);
|
|
15
|
+
}, []);
|
|
16
|
+
const confirmationCallback = useCallback(() => {
|
|
17
|
+
setIsOpen(true);
|
|
18
|
+
const confirmedPromise = new Promise(resolve => {
|
|
19
|
+
resolverRef.current = resolve;
|
|
20
|
+
});
|
|
21
|
+
return confirmedPromise;
|
|
22
|
+
}, []);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const unregister = syncBlockStoreManager.registerConfirmationCallback(confirmationCallback);
|
|
25
|
+
return () => {
|
|
26
|
+
unregister();
|
|
27
|
+
};
|
|
28
|
+
}, [syncBlockStoreManager, confirmationCallback]);
|
|
29
|
+
return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
|
|
30
|
+
onClose: handleClose(false)
|
|
31
|
+
}, /*#__PURE__*/React.createElement(ModalHeader, {
|
|
32
|
+
hasCloseButton: true
|
|
33
|
+
}, /*#__PURE__*/React.createElement(ModalTitle, null, "Confirmation")), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement("div", null, "Are you sure you want to delete this synced block?")), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
|
|
34
|
+
appearance: "subtle",
|
|
35
|
+
onClick: handleClose(false)
|
|
36
|
+
}, "Cancel"), /*#__PURE__*/React.createElement(Button, {
|
|
37
|
+
appearance: "danger",
|
|
38
|
+
onClick: handleClose(true),
|
|
39
|
+
autoFocus: true
|
|
40
|
+
}, "Delete"))));
|
|
41
|
+
};
|