@atlaskit/editor-ssr-renderer 1.4.0 → 1.6.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 +20 -0
- package/dist/cjs/editor-ssr-renderer/EditorSSRRenderer.js +148 -18
- package/dist/es2019/editor-ssr-renderer/EditorSSRRenderer.js +118 -12
- package/dist/esm/editor-ssr-renderer/EditorSSRRenderer.js +149 -19
- package/dist/types/editor-ssr-renderer/EditorSSRRenderer.d.ts +3 -1
- package/dist/types-ts4.5/editor-ssr-renderer/EditorSSRRenderer.d.ts +3 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @atlaskit/editor-ssr-renderer
|
|
2
2
|
|
|
3
|
+
## 1.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`595b07a99bd65`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/595b07a99bd65) -
|
|
8
|
+
[https://hello.jira.atlassian.cloud/browse/EDITOR-3995](EDITOR-3995) - add toolbar supporting to
|
|
9
|
+
`EditorSSRRenderer`
|
|
10
|
+
|
|
11
|
+
## 1.5.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [`cbf58f8500db4`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/cbf58f8500db4) -
|
|
16
|
+
[https://hello.jira.atlassian.cloud/browse/EDITOR-3893](EDITOR-3893) - fix mussing <br /> in empty
|
|
17
|
+
textblocks in the `EditorSSRRenderer`
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies
|
|
22
|
+
|
|
3
23
|
## 1.4.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
|
@@ -9,18 +9,18 @@ exports.EditorSSRRenderer = EditorSSRRenderer;
|
|
|
9
9
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
10
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
11
11
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
12
|
-
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
13
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
14
12
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
15
13
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
16
14
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
15
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
16
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
17
17
|
var _react = _interopRequireWildcard(require("react"));
|
|
18
18
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
19
19
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
20
20
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
21
21
|
var _eventDispatcher = require("@atlaskit/editor-common/event-dispatcher");
|
|
22
22
|
var _providerFactory = require("@atlaskit/editor-common/provider-factory");
|
|
23
|
-
var _excluded = ["plugins", "schema", "doc", "portalProviderAPI", "intl"];
|
|
23
|
+
var _excluded = ["plugins", "schema", "doc", "portalProviderAPI", "intl", "onEditorStateChanged"];
|
|
24
24
|
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); }
|
|
25
25
|
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; }
|
|
26
26
|
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) { (0, _defineProperty2.default)(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; }
|
|
@@ -28,34 +28,127 @@ function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0,
|
|
|
28
28
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
29
29
|
// The copy of type from prosemirror-view.
|
|
30
30
|
// Probably, we need to fix this package exports and add `NodeViewConstructor` and `MarkViewConstructor` types here.
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* A lightweight EditorView implementation for SSR environments.
|
|
33
|
+
*
|
|
34
|
+
* It's kind of aggressive right now, we need to test and see how it works.
|
|
35
|
+
* Probably, we will need to implement more methods/properties in the future.
|
|
36
|
+
*
|
|
37
|
+
* If it doesn't work, we can extend `EditorView` directly instead of implementing `Partial<EditorView>`,
|
|
38
|
+
* but it will perform some DOM operation during the construction.
|
|
39
|
+
*/
|
|
40
|
+
var SSREditorView = /*#__PURE__*/function () {
|
|
41
|
+
function SSREditorView(place, props) {
|
|
33
42
|
(0, _classCallCheck2.default)(this, SSREditorView);
|
|
34
|
-
|
|
43
|
+
this.state = props.state;
|
|
44
|
+
this.dom = document.createElement('div');
|
|
45
|
+
this.editable = true;
|
|
46
|
+
this.dragging = null;
|
|
47
|
+
this.composing = false;
|
|
48
|
+
this.props = props;
|
|
49
|
+
this.root = document;
|
|
50
|
+
this.isDestroyed = false;
|
|
35
51
|
}
|
|
36
|
-
(0, _inherits2.default)(SSREditorView, _EditorView);
|
|
37
52
|
return (0, _createClass2.default)(SSREditorView, [{
|
|
38
53
|
key: "update",
|
|
39
54
|
value: function update() {
|
|
40
|
-
//
|
|
55
|
+
// No-op in SSR
|
|
41
56
|
}
|
|
42
57
|
}, {
|
|
43
58
|
key: "setProps",
|
|
44
59
|
value: function setProps() {
|
|
45
|
-
//
|
|
60
|
+
// No-op in SSR
|
|
46
61
|
}
|
|
47
62
|
}, {
|
|
48
63
|
key: "dispatchEvent",
|
|
49
64
|
value: function dispatchEvent() {
|
|
50
|
-
//
|
|
65
|
+
// No-op in SSR
|
|
51
66
|
}
|
|
52
67
|
}, {
|
|
53
68
|
key: "dispatch",
|
|
54
69
|
value: function dispatch() {
|
|
55
|
-
//
|
|
70
|
+
// No-op in SSR
|
|
71
|
+
}
|
|
72
|
+
}, {
|
|
73
|
+
key: "hasFocus",
|
|
74
|
+
value: function hasFocus() {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}, {
|
|
78
|
+
key: "focus",
|
|
79
|
+
value: function focus() {
|
|
80
|
+
// No-op in SSR
|
|
81
|
+
}
|
|
82
|
+
}, {
|
|
83
|
+
key: "updateRoot",
|
|
84
|
+
value: function updateRoot() {
|
|
85
|
+
// No-op in SSR
|
|
86
|
+
}
|
|
87
|
+
}, {
|
|
88
|
+
key: "posAtCoords",
|
|
89
|
+
value: function posAtCoords() {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}, {
|
|
93
|
+
key: "coordsAtPos",
|
|
94
|
+
value: function coordsAtPos() {
|
|
95
|
+
return {
|
|
96
|
+
left: 0,
|
|
97
|
+
right: 0,
|
|
98
|
+
top: 0,
|
|
99
|
+
bottom: 0
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}, {
|
|
103
|
+
key: "domAtPos",
|
|
104
|
+
value: function domAtPos() {
|
|
105
|
+
return {
|
|
106
|
+
node: this.root,
|
|
107
|
+
offset: 0
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}, {
|
|
111
|
+
key: "nodeDOM",
|
|
112
|
+
value: function nodeDOM() {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}, {
|
|
116
|
+
key: "posAtDOM",
|
|
117
|
+
value: function posAtDOM() {
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
}, {
|
|
121
|
+
key: "endOfTextblock",
|
|
122
|
+
value: function endOfTextblock() {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}, {
|
|
126
|
+
key: "pasteHTML",
|
|
127
|
+
value: function pasteHTML() {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}, {
|
|
131
|
+
key: "pasteText",
|
|
132
|
+
value: function pasteText() {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}, {
|
|
136
|
+
key: "destroy",
|
|
137
|
+
value: function destroy() {
|
|
138
|
+
// No-op in SSR
|
|
139
|
+
}
|
|
140
|
+
}, {
|
|
141
|
+
key: "updateState",
|
|
142
|
+
value: function updateState() {
|
|
143
|
+
// No-op in SSR
|
|
144
|
+
}
|
|
145
|
+
}, {
|
|
146
|
+
key: "someProp",
|
|
147
|
+
value: function someProp() {
|
|
148
|
+
return undefined;
|
|
56
149
|
}
|
|
57
150
|
}]);
|
|
58
|
-
}(
|
|
151
|
+
}();
|
|
59
152
|
var SSREventDispatcher = /*#__PURE__*/function (_EventDispatcher) {
|
|
60
153
|
function SSREventDispatcher() {
|
|
61
154
|
(0, _classCallCheck2.default)(this, SSREventDispatcher);
|
|
@@ -75,6 +168,7 @@ function EditorSSRRenderer(_ref) {
|
|
|
75
168
|
doc = _ref.doc,
|
|
76
169
|
portalProviderAPI = _ref.portalProviderAPI,
|
|
77
170
|
intl = _ref.intl,
|
|
171
|
+
onEditorStateChanged = _ref.onEditorStateChanged,
|
|
78
172
|
divProps = (0, _objectWithoutProperties2.default)(_ref, _excluded);
|
|
79
173
|
// PMPluginFactoryParams use `getIntl` function to get current intl instance,
|
|
80
174
|
// so we don't need to add `intl` as a dependency to `useMemo`.
|
|
@@ -121,15 +215,26 @@ function EditorSSRRenderer(_ref) {
|
|
|
121
215
|
return Object.assign(acc, plugin.props.markViews);
|
|
122
216
|
}, {});
|
|
123
217
|
}, [pmPlugins]);
|
|
218
|
+
var editorState = (0, _react.useMemo)(function () {
|
|
219
|
+
return _state.EditorState.create({
|
|
220
|
+
doc: doc,
|
|
221
|
+
schema: schema,
|
|
222
|
+
plugins: pmPlugins
|
|
223
|
+
});
|
|
224
|
+
}, [doc, pmPlugins, schema]);
|
|
225
|
+
|
|
226
|
+
// In React 19 could be replaced by `useEffectEvent` hook.
|
|
227
|
+
var onEditorStateChangedRef = (0, _react.useRef)(onEditorStateChanged);
|
|
228
|
+
onEditorStateChangedRef.current = onEditorStateChanged;
|
|
229
|
+
(0, _react.useLayoutEffect)(function () {
|
|
230
|
+
var _onEditorStateChanged;
|
|
231
|
+
(_onEditorStateChanged = onEditorStateChangedRef.current) === null || _onEditorStateChanged === void 0 || _onEditorStateChanged.call(onEditorStateChangedRef, editorState);
|
|
232
|
+
}, [editorState]);
|
|
124
233
|
var editorView = (0, _react.useMemo)(function () {
|
|
125
234
|
return new SSREditorView(null, {
|
|
126
|
-
state:
|
|
127
|
-
doc: doc,
|
|
128
|
-
schema: schema,
|
|
129
|
-
plugins: pmPlugins
|
|
130
|
-
})
|
|
235
|
+
state: editorState
|
|
131
236
|
});
|
|
132
|
-
}, [
|
|
237
|
+
}, [editorState]);
|
|
133
238
|
var _useMemo = (0, _react.useMemo)(function () {
|
|
134
239
|
var nodePositions = new WeakMap();
|
|
135
240
|
var toDomNodeRenderers = Object.fromEntries(Object.entries(schema.nodes).map(function (_ref3) {
|
|
@@ -161,6 +266,31 @@ function EditorSSRRenderer(_ref) {
|
|
|
161
266
|
var _nodePositions$get;
|
|
162
267
|
return (_nodePositions$get = nodePositions.get(node)) !== null && _nodePositions$get !== void 0 ? _nodePositions$get : 0;
|
|
163
268
|
}, [], _view.DecorationSet.create(node, []));
|
|
269
|
+
|
|
270
|
+
// ProseMirror View adds <br class="ProseMirror-trailingBreak" /> to empty nodes. Because we are using
|
|
271
|
+
// DOMSerializer, we should simulate the same behaviour to get the same HTML document.
|
|
272
|
+
//
|
|
273
|
+
// There are a lot of conditions that check for adding `<br />` but we could implement only the case when we
|
|
274
|
+
// are adding `<br />` to empty texblock, because if we add `<br />` in other cases it will change order of DOM nodes inside
|
|
275
|
+
// this node (`<br />`) will be the first, after will be other nodes. It's because we are adding `<br />` to root node before
|
|
276
|
+
// we are rendering child node.
|
|
277
|
+
//
|
|
278
|
+
// See: https://discuss.prosemirror.net/t/where-can-i-read-about-prosemirror-trailingbreak/6665
|
|
279
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L803
|
|
280
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L1365
|
|
281
|
+
if (nodeViewInstance.contentDOM &&
|
|
282
|
+
// if (this.node.isTextblock) updater.addTextblockHacks()
|
|
283
|
+
node.isTextblock &&
|
|
284
|
+
// !lastChild || // Empty textblock
|
|
285
|
+
!node.lastChild
|
|
286
|
+
// NOT IMPLEMENTED CASE !(lastChild instanceof TextViewDesc) ||
|
|
287
|
+
// NOT IMPLEMENTED CASE /\n$/.test(lastChild.node.text!) ||
|
|
288
|
+
// NOT IMPLEMENTED CASE (this.view.requiresGeckoHackNode && /\s$/.test(lastChild.node.text!))
|
|
289
|
+
) {
|
|
290
|
+
var br = document.createElement('br');
|
|
291
|
+
br.classList.add('ProseMirror-trailingBreak');
|
|
292
|
+
nodeViewInstance.contentDOM.appendChild(br);
|
|
293
|
+
}
|
|
164
294
|
return {
|
|
165
295
|
dom: nodeViewInstance.dom,
|
|
166
296
|
contentDOM: nodeViewInstance.contentDOM
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useMemo, useRef, useLayoutEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
3
3
|
import { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
4
4
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
5
5
|
import { EventDispatcher, createDispatch } from '@atlaskit/editor-common/event-dispatcher';
|
|
@@ -8,18 +8,87 @@ import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
|
|
|
8
8
|
// The copy of type from prosemirror-view.
|
|
9
9
|
// Probably, we need to fix this package exports and add `NodeViewConstructor` and `MarkViewConstructor` types here.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A lightweight EditorView implementation for SSR environments.
|
|
13
|
+
*
|
|
14
|
+
* It's kind of aggressive right now, we need to test and see how it works.
|
|
15
|
+
* Probably, we will need to implement more methods/properties in the future.
|
|
16
|
+
*
|
|
17
|
+
* If it doesn't work, we can extend `EditorView` directly instead of implementing `Partial<EditorView>`,
|
|
18
|
+
* but it will perform some DOM operation during the construction.
|
|
19
|
+
*/
|
|
20
|
+
class SSREditorView {
|
|
12
21
|
update() {
|
|
13
|
-
//
|
|
22
|
+
// No-op in SSR
|
|
14
23
|
}
|
|
15
24
|
setProps() {
|
|
16
|
-
//
|
|
25
|
+
// No-op in SSR
|
|
17
26
|
}
|
|
18
27
|
dispatchEvent() {
|
|
19
|
-
//
|
|
28
|
+
// No-op in SSR
|
|
20
29
|
}
|
|
21
30
|
dispatch() {
|
|
22
|
-
//
|
|
31
|
+
// No-op in SSR
|
|
32
|
+
}
|
|
33
|
+
hasFocus() {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
focus() {
|
|
37
|
+
// No-op in SSR
|
|
38
|
+
}
|
|
39
|
+
updateRoot() {
|
|
40
|
+
// No-op in SSR
|
|
41
|
+
}
|
|
42
|
+
posAtCoords() {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
coordsAtPos() {
|
|
46
|
+
return {
|
|
47
|
+
left: 0,
|
|
48
|
+
right: 0,
|
|
49
|
+
top: 0,
|
|
50
|
+
bottom: 0
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
domAtPos() {
|
|
54
|
+
return {
|
|
55
|
+
node: this.root,
|
|
56
|
+
offset: 0
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
nodeDOM() {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
posAtDOM() {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
endOfTextblock() {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
pasteHTML() {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
pasteText() {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
destroy() {
|
|
75
|
+
// No-op in SSR
|
|
76
|
+
}
|
|
77
|
+
updateState() {
|
|
78
|
+
// No-op in SSR
|
|
79
|
+
}
|
|
80
|
+
someProp() {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
constructor(place, props) {
|
|
84
|
+
this.state = props.state;
|
|
85
|
+
this.dom = document.createElement('div');
|
|
86
|
+
this.editable = true;
|
|
87
|
+
this.dragging = null;
|
|
88
|
+
this.composing = false;
|
|
89
|
+
this.props = props;
|
|
90
|
+
this.root = document;
|
|
91
|
+
this.isDestroyed = false;
|
|
23
92
|
}
|
|
24
93
|
}
|
|
25
94
|
class SSREventDispatcher extends EventDispatcher {
|
|
@@ -33,6 +102,7 @@ export function EditorSSRRenderer({
|
|
|
33
102
|
doc,
|
|
34
103
|
portalProviderAPI,
|
|
35
104
|
intl,
|
|
105
|
+
onEditorStateChanged,
|
|
36
106
|
...divProps
|
|
37
107
|
}) {
|
|
38
108
|
// PMPluginFactoryParams use `getIntl` function to get current intl instance,
|
|
@@ -79,15 +149,26 @@ export function EditorSSRRenderer({
|
|
|
79
149
|
return Object.assign(acc, plugin.props.markViews);
|
|
80
150
|
}, {});
|
|
81
151
|
}, [pmPlugins]);
|
|
152
|
+
const editorState = useMemo(() => {
|
|
153
|
+
return EditorState.create({
|
|
154
|
+
doc,
|
|
155
|
+
schema,
|
|
156
|
+
plugins: pmPlugins
|
|
157
|
+
});
|
|
158
|
+
}, [doc, pmPlugins, schema]);
|
|
159
|
+
|
|
160
|
+
// In React 19 could be replaced by `useEffectEvent` hook.
|
|
161
|
+
const onEditorStateChangedRef = useRef(onEditorStateChanged);
|
|
162
|
+
onEditorStateChangedRef.current = onEditorStateChanged;
|
|
163
|
+
useLayoutEffect(() => {
|
|
164
|
+
var _onEditorStateChanged;
|
|
165
|
+
(_onEditorStateChanged = onEditorStateChangedRef.current) === null || _onEditorStateChanged === void 0 ? void 0 : _onEditorStateChanged.call(onEditorStateChangedRef, editorState);
|
|
166
|
+
}, [editorState]);
|
|
82
167
|
const editorView = useMemo(() => {
|
|
83
168
|
return new SSREditorView(null, {
|
|
84
|
-
state:
|
|
85
|
-
doc,
|
|
86
|
-
schema,
|
|
87
|
-
plugins: pmPlugins
|
|
88
|
-
})
|
|
169
|
+
state: editorState
|
|
89
170
|
});
|
|
90
|
-
}, [
|
|
171
|
+
}, [editorState]);
|
|
91
172
|
const {
|
|
92
173
|
serializer,
|
|
93
174
|
nodePositions
|
|
@@ -105,6 +186,31 @@ export function EditorSSRRenderer({
|
|
|
105
186
|
var _nodePositions$get;
|
|
106
187
|
return (_nodePositions$get = nodePositions.get(node)) !== null && _nodePositions$get !== void 0 ? _nodePositions$get : 0;
|
|
107
188
|
}, [], DecorationSet.create(node, []));
|
|
189
|
+
|
|
190
|
+
// ProseMirror View adds <br class="ProseMirror-trailingBreak" /> to empty nodes. Because we are using
|
|
191
|
+
// DOMSerializer, we should simulate the same behaviour to get the same HTML document.
|
|
192
|
+
//
|
|
193
|
+
// There are a lot of conditions that check for adding `<br />` but we could implement only the case when we
|
|
194
|
+
// are adding `<br />` to empty texblock, because if we add `<br />` in other cases it will change order of DOM nodes inside
|
|
195
|
+
// this node (`<br />`) will be the first, after will be other nodes. It's because we are adding `<br />` to root node before
|
|
196
|
+
// we are rendering child node.
|
|
197
|
+
//
|
|
198
|
+
// See: https://discuss.prosemirror.net/t/where-can-i-read-about-prosemirror-trailingbreak/6665
|
|
199
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L803
|
|
200
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L1365
|
|
201
|
+
if (nodeViewInstance.contentDOM &&
|
|
202
|
+
// if (this.node.isTextblock) updater.addTextblockHacks()
|
|
203
|
+
node.isTextblock &&
|
|
204
|
+
// !lastChild || // Empty textblock
|
|
205
|
+
!node.lastChild
|
|
206
|
+
// NOT IMPLEMENTED CASE !(lastChild instanceof TextViewDesc) ||
|
|
207
|
+
// NOT IMPLEMENTED CASE /\n$/.test(lastChild.node.text!) ||
|
|
208
|
+
// NOT IMPLEMENTED CASE (this.view.requiresGeckoHackNode && /\s$/.test(lastChild.node.text!))
|
|
209
|
+
) {
|
|
210
|
+
const br = document.createElement('br');
|
|
211
|
+
br.classList.add('ProseMirror-trailingBreak');
|
|
212
|
+
nodeViewInstance.contentDOM.appendChild(br);
|
|
213
|
+
}
|
|
108
214
|
return {
|
|
109
215
|
dom: nodeViewInstance.dom,
|
|
110
216
|
contentDOM: nodeViewInstance.contentDOM
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
3
3
|
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
|
|
4
|
-
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
5
|
-
import _createClass from "@babel/runtime/helpers/createClass";
|
|
6
4
|
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
7
5
|
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
|
|
8
6
|
import _inherits from "@babel/runtime/helpers/inherits";
|
|
9
|
-
|
|
7
|
+
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
8
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
9
|
+
var _excluded = ["plugins", "schema", "doc", "portalProviderAPI", "intl", "onEditorStateChanged"];
|
|
10
10
|
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; }
|
|
11
11
|
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; }
|
|
12
12
|
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
|
|
13
13
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
14
14
|
import React, { useMemo, useRef, useLayoutEffect } from 'react';
|
|
15
|
-
import {
|
|
15
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
16
16
|
import { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
17
17
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
18
18
|
import { EventDispatcher, createDispatch } from '@atlaskit/editor-common/event-dispatcher';
|
|
@@ -20,34 +20,127 @@ import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
|
|
|
20
20
|
|
|
21
21
|
// The copy of type from prosemirror-view.
|
|
22
22
|
// Probably, we need to fix this package exports and add `NodeViewConstructor` and `MarkViewConstructor` types here.
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* A lightweight EditorView implementation for SSR environments.
|
|
25
|
+
*
|
|
26
|
+
* It's kind of aggressive right now, we need to test and see how it works.
|
|
27
|
+
* Probably, we will need to implement more methods/properties in the future.
|
|
28
|
+
*
|
|
29
|
+
* If it doesn't work, we can extend `EditorView` directly instead of implementing `Partial<EditorView>`,
|
|
30
|
+
* but it will perform some DOM operation during the construction.
|
|
31
|
+
*/
|
|
32
|
+
var SSREditorView = /*#__PURE__*/function () {
|
|
33
|
+
function SSREditorView(place, props) {
|
|
25
34
|
_classCallCheck(this, SSREditorView);
|
|
26
|
-
|
|
35
|
+
this.state = props.state;
|
|
36
|
+
this.dom = document.createElement('div');
|
|
37
|
+
this.editable = true;
|
|
38
|
+
this.dragging = null;
|
|
39
|
+
this.composing = false;
|
|
40
|
+
this.props = props;
|
|
41
|
+
this.root = document;
|
|
42
|
+
this.isDestroyed = false;
|
|
27
43
|
}
|
|
28
|
-
_inherits(SSREditorView, _EditorView);
|
|
29
44
|
return _createClass(SSREditorView, [{
|
|
30
45
|
key: "update",
|
|
31
46
|
value: function update() {
|
|
32
|
-
//
|
|
47
|
+
// No-op in SSR
|
|
33
48
|
}
|
|
34
49
|
}, {
|
|
35
50
|
key: "setProps",
|
|
36
51
|
value: function setProps() {
|
|
37
|
-
//
|
|
52
|
+
// No-op in SSR
|
|
38
53
|
}
|
|
39
54
|
}, {
|
|
40
55
|
key: "dispatchEvent",
|
|
41
56
|
value: function dispatchEvent() {
|
|
42
|
-
//
|
|
57
|
+
// No-op in SSR
|
|
43
58
|
}
|
|
44
59
|
}, {
|
|
45
60
|
key: "dispatch",
|
|
46
61
|
value: function dispatch() {
|
|
47
|
-
//
|
|
62
|
+
// No-op in SSR
|
|
63
|
+
}
|
|
64
|
+
}, {
|
|
65
|
+
key: "hasFocus",
|
|
66
|
+
value: function hasFocus() {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}, {
|
|
70
|
+
key: "focus",
|
|
71
|
+
value: function focus() {
|
|
72
|
+
// No-op in SSR
|
|
73
|
+
}
|
|
74
|
+
}, {
|
|
75
|
+
key: "updateRoot",
|
|
76
|
+
value: function updateRoot() {
|
|
77
|
+
// No-op in SSR
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
key: "posAtCoords",
|
|
81
|
+
value: function posAtCoords() {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}, {
|
|
85
|
+
key: "coordsAtPos",
|
|
86
|
+
value: function coordsAtPos() {
|
|
87
|
+
return {
|
|
88
|
+
left: 0,
|
|
89
|
+
right: 0,
|
|
90
|
+
top: 0,
|
|
91
|
+
bottom: 0
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}, {
|
|
95
|
+
key: "domAtPos",
|
|
96
|
+
value: function domAtPos() {
|
|
97
|
+
return {
|
|
98
|
+
node: this.root,
|
|
99
|
+
offset: 0
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}, {
|
|
103
|
+
key: "nodeDOM",
|
|
104
|
+
value: function nodeDOM() {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}, {
|
|
108
|
+
key: "posAtDOM",
|
|
109
|
+
value: function posAtDOM() {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
}, {
|
|
113
|
+
key: "endOfTextblock",
|
|
114
|
+
value: function endOfTextblock() {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}, {
|
|
118
|
+
key: "pasteHTML",
|
|
119
|
+
value: function pasteHTML() {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}, {
|
|
123
|
+
key: "pasteText",
|
|
124
|
+
value: function pasteText() {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}, {
|
|
128
|
+
key: "destroy",
|
|
129
|
+
value: function destroy() {
|
|
130
|
+
// No-op in SSR
|
|
131
|
+
}
|
|
132
|
+
}, {
|
|
133
|
+
key: "updateState",
|
|
134
|
+
value: function updateState() {
|
|
135
|
+
// No-op in SSR
|
|
136
|
+
}
|
|
137
|
+
}, {
|
|
138
|
+
key: "someProp",
|
|
139
|
+
value: function someProp() {
|
|
140
|
+
return undefined;
|
|
48
141
|
}
|
|
49
142
|
}]);
|
|
50
|
-
}(
|
|
143
|
+
}();
|
|
51
144
|
var SSREventDispatcher = /*#__PURE__*/function (_EventDispatcher) {
|
|
52
145
|
function SSREventDispatcher() {
|
|
53
146
|
_classCallCheck(this, SSREventDispatcher);
|
|
@@ -67,6 +160,7 @@ export function EditorSSRRenderer(_ref) {
|
|
|
67
160
|
doc = _ref.doc,
|
|
68
161
|
portalProviderAPI = _ref.portalProviderAPI,
|
|
69
162
|
intl = _ref.intl,
|
|
163
|
+
onEditorStateChanged = _ref.onEditorStateChanged,
|
|
70
164
|
divProps = _objectWithoutProperties(_ref, _excluded);
|
|
71
165
|
// PMPluginFactoryParams use `getIntl` function to get current intl instance,
|
|
72
166
|
// so we don't need to add `intl` as a dependency to `useMemo`.
|
|
@@ -113,15 +207,26 @@ export function EditorSSRRenderer(_ref) {
|
|
|
113
207
|
return Object.assign(acc, plugin.props.markViews);
|
|
114
208
|
}, {});
|
|
115
209
|
}, [pmPlugins]);
|
|
210
|
+
var editorState = useMemo(function () {
|
|
211
|
+
return EditorState.create({
|
|
212
|
+
doc: doc,
|
|
213
|
+
schema: schema,
|
|
214
|
+
plugins: pmPlugins
|
|
215
|
+
});
|
|
216
|
+
}, [doc, pmPlugins, schema]);
|
|
217
|
+
|
|
218
|
+
// In React 19 could be replaced by `useEffectEvent` hook.
|
|
219
|
+
var onEditorStateChangedRef = useRef(onEditorStateChanged);
|
|
220
|
+
onEditorStateChangedRef.current = onEditorStateChanged;
|
|
221
|
+
useLayoutEffect(function () {
|
|
222
|
+
var _onEditorStateChanged;
|
|
223
|
+
(_onEditorStateChanged = onEditorStateChangedRef.current) === null || _onEditorStateChanged === void 0 || _onEditorStateChanged.call(onEditorStateChangedRef, editorState);
|
|
224
|
+
}, [editorState]);
|
|
116
225
|
var editorView = useMemo(function () {
|
|
117
226
|
return new SSREditorView(null, {
|
|
118
|
-
state:
|
|
119
|
-
doc: doc,
|
|
120
|
-
schema: schema,
|
|
121
|
-
plugins: pmPlugins
|
|
122
|
-
})
|
|
227
|
+
state: editorState
|
|
123
228
|
});
|
|
124
|
-
}, [
|
|
229
|
+
}, [editorState]);
|
|
125
230
|
var _useMemo = useMemo(function () {
|
|
126
231
|
var nodePositions = new WeakMap();
|
|
127
232
|
var toDomNodeRenderers = Object.fromEntries(Object.entries(schema.nodes).map(function (_ref3) {
|
|
@@ -153,6 +258,31 @@ export function EditorSSRRenderer(_ref) {
|
|
|
153
258
|
var _nodePositions$get;
|
|
154
259
|
return (_nodePositions$get = nodePositions.get(node)) !== null && _nodePositions$get !== void 0 ? _nodePositions$get : 0;
|
|
155
260
|
}, [], DecorationSet.create(node, []));
|
|
261
|
+
|
|
262
|
+
// ProseMirror View adds <br class="ProseMirror-trailingBreak" /> to empty nodes. Because we are using
|
|
263
|
+
// DOMSerializer, we should simulate the same behaviour to get the same HTML document.
|
|
264
|
+
//
|
|
265
|
+
// There are a lot of conditions that check for adding `<br />` but we could implement only the case when we
|
|
266
|
+
// are adding `<br />` to empty texblock, because if we add `<br />` in other cases it will change order of DOM nodes inside
|
|
267
|
+
// this node (`<br />`) will be the first, after will be other nodes. It's because we are adding `<br />` to root node before
|
|
268
|
+
// we are rendering child node.
|
|
269
|
+
//
|
|
270
|
+
// See: https://discuss.prosemirror.net/t/where-can-i-read-about-prosemirror-trailingbreak/6665
|
|
271
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L803
|
|
272
|
+
// See: https://github.com/ProseMirror/prosemirror-view/blob/76c7c47f03730b18397b94bd269ece8a9cb7f486/src/viewdesc.ts#L1365
|
|
273
|
+
if (nodeViewInstance.contentDOM &&
|
|
274
|
+
// if (this.node.isTextblock) updater.addTextblockHacks()
|
|
275
|
+
node.isTextblock &&
|
|
276
|
+
// !lastChild || // Empty textblock
|
|
277
|
+
!node.lastChild
|
|
278
|
+
// NOT IMPLEMENTED CASE !(lastChild instanceof TextViewDesc) ||
|
|
279
|
+
// NOT IMPLEMENTED CASE /\n$/.test(lastChild.node.text!) ||
|
|
280
|
+
// NOT IMPLEMENTED CASE (this.view.requiresGeckoHackNode && /\s$/.test(lastChild.node.text!))
|
|
281
|
+
) {
|
|
282
|
+
var br = document.createElement('br');
|
|
283
|
+
br.classList.add('ProseMirror-trailingBreak');
|
|
284
|
+
nodeViewInstance.contentDOM.appendChild(br);
|
|
285
|
+
}
|
|
156
286
|
return {
|
|
157
287
|
dom: nodeViewInstance.dom,
|
|
158
288
|
contentDOM: nodeViewInstance.contentDOM
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { IntlShape } from 'react-intl-next';
|
|
3
|
+
import { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
3
4
|
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
4
5
|
import { type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
5
6
|
import type { EditorPlugin } from '@atlaskit/editor-common/types';
|
|
@@ -12,9 +13,10 @@ interface Props {
|
|
|
12
13
|
doc: PMNode | undefined;
|
|
13
14
|
id: string;
|
|
14
15
|
intl: IntlShape;
|
|
16
|
+
onEditorStateChanged?: (state: EditorState) => void;
|
|
15
17
|
plugins: EditorPlugin[];
|
|
16
18
|
portalProviderAPI: PortalProviderAPI;
|
|
17
19
|
schema: Schema;
|
|
18
20
|
}
|
|
19
|
-
export declare function EditorSSRRenderer({ plugins, schema, doc, portalProviderAPI, intl, ...divProps }: Props): React.JSX.Element;
|
|
21
|
+
export declare function EditorSSRRenderer({ plugins, schema, doc, portalProviderAPI, intl, onEditorStateChanged, ...divProps }: Props): React.JSX.Element;
|
|
20
22
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { IntlShape } from 'react-intl-next';
|
|
3
|
+
import { EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
3
4
|
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
4
5
|
import { type Schema } from '@atlaskit/editor-prosemirror/model';
|
|
5
6
|
import type { EditorPlugin } from '@atlaskit/editor-common/types';
|
|
@@ -12,9 +13,10 @@ interface Props {
|
|
|
12
13
|
doc: PMNode | undefined;
|
|
13
14
|
id: string;
|
|
14
15
|
intl: IntlShape;
|
|
16
|
+
onEditorStateChanged?: (state: EditorState) => void;
|
|
15
17
|
plugins: EditorPlugin[];
|
|
16
18
|
portalProviderAPI: PortalProviderAPI;
|
|
17
19
|
schema: Schema;
|
|
18
20
|
}
|
|
19
|
-
export declare function EditorSSRRenderer({ plugins, schema, doc, portalProviderAPI, intl, ...divProps }: Props): React.JSX.Element;
|
|
21
|
+
export declare function EditorSSRRenderer({ plugins, schema, doc, portalProviderAPI, intl, onEditorStateChanged, ...divProps }: Props): React.JSX.Element;
|
|
20
22
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-ssr-renderer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "SSR Renderer based on Editor",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"atlassian": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@atlaskit/editor-common": "^110.
|
|
36
|
+
"@atlaskit/editor-common": "^110.49.0",
|
|
37
37
|
"react": "^18.2.0"
|
|
38
38
|
}
|
|
39
39
|
}
|