@atlaskit/editor-plugin-layout 11.0.3 → 11.0.4
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 +7 -0
- package/dist/cjs/layoutPlugin.js +3 -2
- package/dist/cjs/nodeviews/index.js +49 -1
- package/dist/cjs/pm-plugins/resizing.js +29 -4
- package/dist/cjs/ui/LayoutSSRReactContextsProvider.js +34 -0
- package/dist/es2019/layoutPlugin.js +3 -2
- package/dist/es2019/nodeviews/index.js +49 -1
- package/dist/es2019/pm-plugins/resizing.js +37 -7
- package/dist/es2019/ui/LayoutSSRReactContextsProvider.js +28 -0
- package/dist/esm/layoutPlugin.js +3 -2
- package/dist/esm/nodeviews/index.js +49 -1
- package/dist/esm/pm-plugins/resizing.js +29 -4
- package/dist/esm/ui/LayoutSSRReactContextsProvider.js +27 -0
- package/dist/types/nodeviews/index.d.ts +5 -0
- package/dist/types/pm-plugins/resizing.d.ts +2 -1
- package/dist/types/ui/LayoutSSRReactContextsProvider.d.ts +19 -0
- package/dist/types-ts4.5/nodeviews/index.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/resizing.d.ts +2 -1
- package/dist/types-ts4.5/ui/LayoutSSRReactContextsProvider.d.ts +19 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-layout
|
|
2
2
|
|
|
3
|
+
## 11.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`1f5c61250d103`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1f5c61250d103) -
|
|
8
|
+
Updating layout plugin to support ssr streaming
|
|
9
|
+
|
|
3
10
|
## 11.0.3
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/dist/cjs/layoutPlugin.js
CHANGED
|
@@ -114,8 +114,9 @@ var layoutPlugin = exports.layoutPlugin = function layoutPlugin(_ref) {
|
|
|
114
114
|
name: 'layoutResizing',
|
|
115
115
|
plugin: function plugin(_ref2) {
|
|
116
116
|
var portalProviderAPI = _ref2.portalProviderAPI,
|
|
117
|
-
eventDispatcher = _ref2.eventDispatcher
|
|
118
|
-
|
|
117
|
+
eventDispatcher = _ref2.eventDispatcher,
|
|
118
|
+
getIntl = _ref2.getIntl;
|
|
119
|
+
return (0, _resizing.default)(options, api, portalProviderAPI, eventDispatcher, getIntl());
|
|
119
120
|
}
|
|
120
121
|
});
|
|
121
122
|
}
|
|
@@ -13,8 +13,9 @@ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/ge
|
|
|
13
13
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
14
14
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
15
15
|
var _react = _interopRequireWildcard(require("react"));
|
|
16
|
+
var _coreUtils = require("@atlaskit/editor-common/core-utils");
|
|
16
17
|
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
17
|
-
var _reactNodeView =
|
|
18
|
+
var _reactNodeView = _interopRequireWildcard(require("@atlaskit/editor-common/react-node-view"));
|
|
18
19
|
var _resizer = require("@atlaskit/editor-common/resizer");
|
|
19
20
|
var _useSharedPluginStateSelector = require("@atlaskit/editor-common/use-shared-plugin-state-selector");
|
|
20
21
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
@@ -22,6 +23,7 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
|
22
23
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
23
24
|
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
|
|
24
25
|
var _utils = require("../pm-plugins/utils");
|
|
26
|
+
var _LayoutSSRReactContextsProvider = require("../ui/LayoutSSRReactContextsProvider");
|
|
25
27
|
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); }
|
|
26
28
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
27
29
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
@@ -140,6 +142,7 @@ var LayoutSectionView = exports.LayoutSectionView = /*#__PURE__*/function (_Reac
|
|
|
140
142
|
* @param props.eventDispatcher
|
|
141
143
|
* @param props.pluginInjectionApi
|
|
142
144
|
* @param props.options
|
|
145
|
+
* @param props.intl
|
|
143
146
|
* @example
|
|
144
147
|
*/
|
|
145
148
|
function LayoutSectionView(props) {
|
|
@@ -148,6 +151,7 @@ var LayoutSectionView = exports.LayoutSectionView = /*#__PURE__*/function (_Reac
|
|
|
148
151
|
_this = _callSuper(this, LayoutSectionView, [props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props]);
|
|
149
152
|
_this.isEmpty = isEmptyLayout(_this.node);
|
|
150
153
|
_this.options = props.options;
|
|
154
|
+
_this.intl = props.intl;
|
|
151
155
|
return _this;
|
|
152
156
|
}
|
|
153
157
|
|
|
@@ -160,6 +164,13 @@ var LayoutSectionView = exports.LayoutSectionView = /*#__PURE__*/function (_Reac
|
|
|
160
164
|
return (0, _createClass2.default)(LayoutSectionView, [{
|
|
161
165
|
key: "getContentDOM",
|
|
162
166
|
value: function getContentDOM() {
|
|
167
|
+
// Build the layout DOM via the schema's toDOM spec. This is the same
|
|
168
|
+
// path used in both CSR and SSR — the only SSR-specific concern is
|
|
169
|
+
// re-attaching `contentDOM` (= the `[data-layout-section]` element)
|
|
170
|
+
// after the portal's renderToStaticMarkup + innerHTML write detaches
|
|
171
|
+
// it. We handle that by stamping `data-ssr-content-dom-ref` on the
|
|
172
|
+
// outer container so `ReactNodeView.init()` can find a re-attach
|
|
173
|
+
// target inside `domRef` after the portal write.
|
|
163
174
|
var _ref2 = _model.DOMSerializer.renderSpec(document, toDOM(this.node)),
|
|
164
175
|
container = _ref2.dom,
|
|
165
176
|
contentDOM = _ref2.contentDOM;
|
|
@@ -172,6 +183,20 @@ var LayoutSectionView = exports.LayoutSectionView = /*#__PURE__*/function (_Reac
|
|
|
172
183
|
if ((0, _platformFeatureFlags.fg)('platform_editor_adf_with_localid')) {
|
|
173
184
|
this.layoutDOM.setAttribute('data-local-id', this.node.attrs.localId);
|
|
174
185
|
}
|
|
186
|
+
|
|
187
|
+
// SSR streaming re-attach note:
|
|
188
|
+
// In SSR, `init()` appends `container` into `domRef`; the portal's
|
|
189
|
+
// renderToStaticMarkup + innerHTML write then wipes `domRef`,
|
|
190
|
+
// detaching the entire subtree (with PM-serialized children inside
|
|
191
|
+
// `[data-layout-section]`). React's `render()` emits a
|
|
192
|
+
// `<NodeViewContentHole/>` placeholder inside `domRef`; the SSR
|
|
193
|
+
// re-attach logic in `init()` finds it via `[data-ssr-content-dom-ref]`
|
|
194
|
+
// and calls `_handleRef`, which appends `contentDOMWrapper` (the
|
|
195
|
+
// detached `container`) back inside the placeholder. The end result
|
|
196
|
+
// is `domRef > NodeViewContentHole > layout-section-container >
|
|
197
|
+
// [data-layout-section] > [data-layout-column] children` — the
|
|
198
|
+
// layout DOM contract is preserved.
|
|
199
|
+
|
|
175
200
|
return {
|
|
176
201
|
dom: container,
|
|
177
202
|
contentDOM: contentDOM
|
|
@@ -206,6 +231,29 @@ var LayoutSectionView = exports.LayoutSectionView = /*#__PURE__*/function (_Reac
|
|
|
206
231
|
if (this.layoutDOM) {
|
|
207
232
|
this.layoutDOM.setAttribute('data-empty-layout', Boolean(this.isEmpty).toString());
|
|
208
233
|
}
|
|
234
|
+
|
|
235
|
+
// SSR streaming path: render only a `<NodeViewContentHole/>` placeholder
|
|
236
|
+
// so ReactNodeView.init()'s SSR re-attach logic can find the marker
|
|
237
|
+
// (`data-ssr-content-dom-ref`) and re-append the detached
|
|
238
|
+
// contentDOMWrapper — which is the FULL layout structure
|
|
239
|
+
// (`layout-section-container > [data-layout-section] > children`) built
|
|
240
|
+
// in `getContentDOM` via DOMSerializer.renderSpec. This avoids
|
|
241
|
+
// duplicating layout structure between getContentDOM and render(), which
|
|
242
|
+
// previously caused an extra wrapping div between `[data-layout-section]`
|
|
243
|
+
// and the `[data-layout-column]` children and broke the flex layout.
|
|
244
|
+
//
|
|
245
|
+
// The BreakoutResizer is intentionally omitted in SSR — it relies on
|
|
246
|
+
// browser-only APIs and contributes no useful static markup. The
|
|
247
|
+
// LayoutSSRReactContextsProvider wraps the placeholder to inject the
|
|
248
|
+
// editor's IntlShape, defending against any descendants that call
|
|
249
|
+
// `useIntl()` during renderToStaticMarkup.
|
|
250
|
+
if ((0, _coreUtils.isSSR)() && (0, _coreUtils.isSSRStreaming)()) {
|
|
251
|
+
return /*#__PURE__*/_react.default.createElement(_LayoutSSRReactContextsProvider.LayoutSSRReactContextsProvider, {
|
|
252
|
+
intl: this.intl
|
|
253
|
+
}, /*#__PURE__*/_react.default.createElement(_reactNodeView.NodeViewContentHole, {
|
|
254
|
+
ref: forwardRef
|
|
255
|
+
}));
|
|
256
|
+
}
|
|
209
257
|
if ((0, _expValEquals.expValEquals)('platform_editor_breakout_resizing', 'isEnabled', true)) {
|
|
210
258
|
return null;
|
|
211
259
|
}
|
|
@@ -8,6 +8,8 @@ exports.pluginKey = exports.default = void 0;
|
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
9
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
10
10
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
11
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
12
|
+
var _coreUtils = require("@atlaskit/editor-common/core-utils");
|
|
11
13
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
12
14
|
var _model = require("@atlaskit/editor-prosemirror/model");
|
|
13
15
|
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
@@ -26,6 +28,28 @@ var pluginKey = exports.pluginKey = new _state.PluginKey('layoutResizingPlugin')
|
|
|
26
28
|
* (e.g. setting flex-basis to give real-time visual feedback without dispatching
|
|
27
29
|
* PM transactions) are not "corrected" back by ProseMirror's DOM reconciliation.
|
|
28
30
|
*/
|
|
31
|
+
var isLayoutElementLike = function isLayoutElementLike(element) {
|
|
32
|
+
if ((0, _coreUtils.isSSR)() && (0, _coreUtils.isSSRStreaming)()) {
|
|
33
|
+
// In SSR environments, `HTMLElement` is undefined globally so a plain
|
|
34
|
+
// `instanceof HTMLElement` check is always `false`. That makes the
|
|
35
|
+
// `DOMSerializer.renderSpec(...)` result get rejected by the guard below and
|
|
36
|
+
// the NodeView falls back to a bare `<div>`, losing every schema-defined
|
|
37
|
+
// attribute (`data-layout-column`, `style="flex-basis:..."`,
|
|
38
|
+
// `data-column-width`, plus the inner `<div data-layout-content="true">`
|
|
39
|
+
// wrapper) and breaking the layout's flex sizing in SSR output.
|
|
40
|
+
//
|
|
41
|
+
// To unblock SSR streaming without changing CSR semantics, we gate the check:
|
|
42
|
+
// - In SSR (and only when `platform_editor_editor_ssr_streaming` is enabled),
|
|
43
|
+
// use a duck-typed check that mirrors `safe-plugin`'s `isHTMLElement`.
|
|
44
|
+
// - Everywhere else, keep the original `instanceof HTMLElement` check exactly
|
|
45
|
+
// as it was so we don't accidentally widen acceptance in CSR.
|
|
46
|
+
if (element === null || element === undefined) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return (0, _typeof2.default)(element) === 'object' && 'innerHTML' in element && 'style' in element && 'classList' in element;
|
|
50
|
+
}
|
|
51
|
+
return element instanceof HTMLElement;
|
|
52
|
+
};
|
|
29
53
|
var LayoutColumnView = /*#__PURE__*/function () {
|
|
30
54
|
function LayoutColumnView(node, view, getPos) {
|
|
31
55
|
(0, _classCallCheck2.default)(this, LayoutColumnView);
|
|
@@ -43,7 +67,7 @@ var LayoutColumnView = /*#__PURE__*/function () {
|
|
|
43
67
|
var _DOMSerializer$render = _model.DOMSerializer.renderSpec(document, nodeType.spec.toDOM(node)),
|
|
44
68
|
dom = _DOMSerializer$render.dom,
|
|
45
69
|
contentDOM = _DOMSerializer$render.contentDOM;
|
|
46
|
-
if (!(dom
|
|
70
|
+
if (!isLayoutElementLike(dom) || !isLayoutElementLike(contentDOM)) {
|
|
47
71
|
var _fallbackDiv = document.createElement('div');
|
|
48
72
|
this.dom = _fallbackDiv;
|
|
49
73
|
this.contentDOM = _fallbackDiv;
|
|
@@ -71,7 +95,7 @@ var LayoutColumnView = /*#__PURE__*/function () {
|
|
|
71
95
|
}
|
|
72
96
|
}]);
|
|
73
97
|
}();
|
|
74
|
-
var _default = exports.default = function _default(options, pluginInjectionApi, portalProviderAPI, eventDispatcher) {
|
|
98
|
+
var _default = exports.default = function _default(options, pluginInjectionApi, portalProviderAPI, eventDispatcher, intl) {
|
|
75
99
|
return new _safePlugin.SafePlugin({
|
|
76
100
|
key: pluginKey,
|
|
77
101
|
props: {
|
|
@@ -84,10 +108,11 @@ var _default = exports.default = function _default(options, pluginInjectionApi,
|
|
|
84
108
|
portalProviderAPI: portalProviderAPI,
|
|
85
109
|
eventDispatcher: eventDispatcher,
|
|
86
110
|
pluginInjectionApi: pluginInjectionApi,
|
|
87
|
-
options: options
|
|
111
|
+
options: options,
|
|
112
|
+
intl: intl
|
|
88
113
|
}).init();
|
|
89
114
|
}
|
|
90
|
-
}, (0, _experiments.editorExperiment)('platform_editor_layout_column_resize_handle', true) ? {
|
|
115
|
+
}, (0, _experiments.editorExperiment)('platform_editor_layout_column_resize_handle', true) || (0, _coreUtils.isSSR)() && (0, _coreUtils.isSSRStreaming)() ? {
|
|
91
116
|
layoutColumn: function layoutColumn(node, view, getPos) {
|
|
92
117
|
return new LayoutColumnView(node, view, getPos);
|
|
93
118
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.LayoutSSRReactContextsProvider = LayoutSSRReactContextsProvider;
|
|
8
|
+
var _react = _interopRequireDefault(require("react"));
|
|
9
|
+
var _reactIntl = require("react-intl");
|
|
10
|
+
var _coreUtils = require("@atlaskit/editor-common/core-utils");
|
|
11
|
+
/**
|
|
12
|
+
* Wraps the layout section nodeview children with the editor's actual
|
|
13
|
+
* IntlProvider during SSR streaming (renderToStaticMarkup). This ensures any
|
|
14
|
+
* descendants that call `useIntl()` (e.g. `BreakoutResizer`'s ARIA labels)
|
|
15
|
+
* have a valid intl context and do not throw during the static render pass.
|
|
16
|
+
*
|
|
17
|
+
* Outside of SSR streaming this is a no-op passthrough.
|
|
18
|
+
*
|
|
19
|
+
* Follows the same pattern as `MediaSSRReactContextsProvider` and
|
|
20
|
+
* `SyncBlockSSRReactContextsProvider`.
|
|
21
|
+
*/
|
|
22
|
+
function LayoutSSRReactContextsProvider(_ref) {
|
|
23
|
+
var children = _ref.children,
|
|
24
|
+
intl = _ref.intl;
|
|
25
|
+
if (!(0, _coreUtils.isSSRStreaming)() || !(0, _coreUtils.isSSR)()) {
|
|
26
|
+
return children;
|
|
27
|
+
}
|
|
28
|
+
if (!intl) {
|
|
29
|
+
return children;
|
|
30
|
+
}
|
|
31
|
+
return /*#__PURE__*/_react.default.createElement(_reactIntl.RawIntlProvider, {
|
|
32
|
+
value: intl
|
|
33
|
+
}, children);
|
|
34
|
+
}
|
|
@@ -106,8 +106,9 @@ export const layoutPlugin = ({
|
|
|
106
106
|
name: 'layoutResizing',
|
|
107
107
|
plugin: ({
|
|
108
108
|
portalProviderAPI,
|
|
109
|
-
eventDispatcher
|
|
110
|
-
|
|
109
|
+
eventDispatcher,
|
|
110
|
+
getIntl
|
|
111
|
+
}) => createLayoutResizingPlugin(options, api, portalProviderAPI, eventDispatcher, getIntl())
|
|
111
112
|
});
|
|
112
113
|
}
|
|
113
114
|
return plugins;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
2
3
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
3
|
-
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
4
|
+
import ReactNodeView, { NodeViewContentHole } from '@atlaskit/editor-common/react-node-view';
|
|
4
5
|
import { BreakoutResizer, ignoreResizerMutations } from '@atlaskit/editor-common/resizer';
|
|
5
6
|
import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
|
|
6
7
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
@@ -8,6 +9,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
8
9
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
9
10
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
10
11
|
import { selectIntoLayout } from '../pm-plugins/utils';
|
|
12
|
+
import { LayoutSSRReactContextsProvider } from '../ui/LayoutSSRReactContextsProvider';
|
|
11
13
|
const layoutDynamicFullWidthGuidelineOffset = 16;
|
|
12
14
|
const isEmptyParagraph = node => {
|
|
13
15
|
return !!node && node.type.name === 'paragraph' && !node.childCount;
|
|
@@ -122,12 +124,14 @@ export class LayoutSectionView extends ReactNodeView {
|
|
|
122
124
|
* @param props.eventDispatcher
|
|
123
125
|
* @param props.pluginInjectionApi
|
|
124
126
|
* @param props.options
|
|
127
|
+
* @param props.intl
|
|
125
128
|
* @example
|
|
126
129
|
*/
|
|
127
130
|
constructor(props) {
|
|
128
131
|
super(props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props);
|
|
129
132
|
this.isEmpty = isEmptyLayout(this.node);
|
|
130
133
|
this.options = props.options;
|
|
134
|
+
this.intl = props.intl;
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
/**
|
|
@@ -136,6 +140,13 @@ export class LayoutSectionView extends ReactNodeView {
|
|
|
136
140
|
* @returns
|
|
137
141
|
*/
|
|
138
142
|
getContentDOM() {
|
|
143
|
+
// Build the layout DOM via the schema's toDOM spec. This is the same
|
|
144
|
+
// path used in both CSR and SSR — the only SSR-specific concern is
|
|
145
|
+
// re-attaching `contentDOM` (= the `[data-layout-section]` element)
|
|
146
|
+
// after the portal's renderToStaticMarkup + innerHTML write detaches
|
|
147
|
+
// it. We handle that by stamping `data-ssr-content-dom-ref` on the
|
|
148
|
+
// outer container so `ReactNodeView.init()` can find a re-attach
|
|
149
|
+
// target inside `domRef` after the portal write.
|
|
139
150
|
const {
|
|
140
151
|
dom: container,
|
|
141
152
|
contentDOM
|
|
@@ -149,6 +160,20 @@ export class LayoutSectionView extends ReactNodeView {
|
|
|
149
160
|
if (fg('platform_editor_adf_with_localid')) {
|
|
150
161
|
this.layoutDOM.setAttribute('data-local-id', this.node.attrs.localId);
|
|
151
162
|
}
|
|
163
|
+
|
|
164
|
+
// SSR streaming re-attach note:
|
|
165
|
+
// In SSR, `init()` appends `container` into `domRef`; the portal's
|
|
166
|
+
// renderToStaticMarkup + innerHTML write then wipes `domRef`,
|
|
167
|
+
// detaching the entire subtree (with PM-serialized children inside
|
|
168
|
+
// `[data-layout-section]`). React's `render()` emits a
|
|
169
|
+
// `<NodeViewContentHole/>` placeholder inside `domRef`; the SSR
|
|
170
|
+
// re-attach logic in `init()` finds it via `[data-ssr-content-dom-ref]`
|
|
171
|
+
// and calls `_handleRef`, which appends `contentDOMWrapper` (the
|
|
172
|
+
// detached `container`) back inside the placeholder. The end result
|
|
173
|
+
// is `domRef > NodeViewContentHole > layout-section-container >
|
|
174
|
+
// [data-layout-section] > [data-layout-column] children` — the
|
|
175
|
+
// layout DOM contract is preserved.
|
|
176
|
+
|
|
152
177
|
return {
|
|
153
178
|
dom: container,
|
|
154
179
|
contentDOM
|
|
@@ -179,6 +204,29 @@ export class LayoutSectionView extends ReactNodeView {
|
|
|
179
204
|
if (this.layoutDOM) {
|
|
180
205
|
this.layoutDOM.setAttribute('data-empty-layout', Boolean(this.isEmpty).toString());
|
|
181
206
|
}
|
|
207
|
+
|
|
208
|
+
// SSR streaming path: render only a `<NodeViewContentHole/>` placeholder
|
|
209
|
+
// so ReactNodeView.init()'s SSR re-attach logic can find the marker
|
|
210
|
+
// (`data-ssr-content-dom-ref`) and re-append the detached
|
|
211
|
+
// contentDOMWrapper — which is the FULL layout structure
|
|
212
|
+
// (`layout-section-container > [data-layout-section] > children`) built
|
|
213
|
+
// in `getContentDOM` via DOMSerializer.renderSpec. This avoids
|
|
214
|
+
// duplicating layout structure between getContentDOM and render(), which
|
|
215
|
+
// previously caused an extra wrapping div between `[data-layout-section]`
|
|
216
|
+
// and the `[data-layout-column]` children and broke the flex layout.
|
|
217
|
+
//
|
|
218
|
+
// The BreakoutResizer is intentionally omitted in SSR — it relies on
|
|
219
|
+
// browser-only APIs and contributes no useful static markup. The
|
|
220
|
+
// LayoutSSRReactContextsProvider wraps the placeholder to inject the
|
|
221
|
+
// editor's IntlShape, defending against any descendants that call
|
|
222
|
+
// `useIntl()` during renderToStaticMarkup.
|
|
223
|
+
if (isSSR() && isSSRStreaming()) {
|
|
224
|
+
return /*#__PURE__*/React.createElement(LayoutSSRReactContextsProvider, {
|
|
225
|
+
intl: this.intl
|
|
226
|
+
}, /*#__PURE__*/React.createElement(NodeViewContentHole, {
|
|
227
|
+
ref: forwardRef
|
|
228
|
+
}));
|
|
229
|
+
}
|
|
182
230
|
if (expValEquals('platform_editor_breakout_resizing', 'isEnabled', true)) {
|
|
183
231
|
return null;
|
|
184
232
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
1
2
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
3
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
3
4
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
@@ -14,6 +15,28 @@ export const pluginKey = new PluginKey('layoutResizingPlugin');
|
|
|
14
15
|
* (e.g. setting flex-basis to give real-time visual feedback without dispatching
|
|
15
16
|
* PM transactions) are not "corrected" back by ProseMirror's DOM reconciliation.
|
|
16
17
|
*/
|
|
18
|
+
const isLayoutElementLike = element => {
|
|
19
|
+
if (isSSR() && isSSRStreaming()) {
|
|
20
|
+
// In SSR environments, `HTMLElement` is undefined globally so a plain
|
|
21
|
+
// `instanceof HTMLElement` check is always `false`. That makes the
|
|
22
|
+
// `DOMSerializer.renderSpec(...)` result get rejected by the guard below and
|
|
23
|
+
// the NodeView falls back to a bare `<div>`, losing every schema-defined
|
|
24
|
+
// attribute (`data-layout-column`, `style="flex-basis:..."`,
|
|
25
|
+
// `data-column-width`, plus the inner `<div data-layout-content="true">`
|
|
26
|
+
// wrapper) and breaking the layout's flex sizing in SSR output.
|
|
27
|
+
//
|
|
28
|
+
// To unblock SSR streaming without changing CSR semantics, we gate the check:
|
|
29
|
+
// - In SSR (and only when `platform_editor_editor_ssr_streaming` is enabled),
|
|
30
|
+
// use a duck-typed check that mirrors `safe-plugin`'s `isHTMLElement`.
|
|
31
|
+
// - Everywhere else, keep the original `instanceof HTMLElement` check exactly
|
|
32
|
+
// as it was so we don't accidentally widen acceptance in CSR.
|
|
33
|
+
if (element === null || element === undefined) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return typeof element === 'object' && 'innerHTML' in element && 'style' in element && 'classList' in element;
|
|
37
|
+
}
|
|
38
|
+
return element instanceof HTMLElement;
|
|
39
|
+
};
|
|
17
40
|
class LayoutColumnView {
|
|
18
41
|
constructor(node, view, getPos) {
|
|
19
42
|
// Use the NodeSpec's own toDOM to produce the correct DOM structure and attributes.
|
|
@@ -31,7 +54,7 @@ class LayoutColumnView {
|
|
|
31
54
|
dom,
|
|
32
55
|
contentDOM
|
|
33
56
|
} = DOMSerializer.renderSpec(document, nodeType.spec.toDOM(node));
|
|
34
|
-
if (!(dom
|
|
57
|
+
if (!isLayoutElementLike(dom) || !isLayoutElementLike(contentDOM)) {
|
|
35
58
|
const fallbackDiv = document.createElement('div');
|
|
36
59
|
this.dom = fallbackDiv;
|
|
37
60
|
this.contentDOM = fallbackDiv;
|
|
@@ -56,7 +79,7 @@ class LayoutColumnView {
|
|
|
56
79
|
return mutation.type === 'attributes' && mutation.attributeName === 'style';
|
|
57
80
|
}
|
|
58
81
|
}
|
|
59
|
-
export default ((options, pluginInjectionApi, portalProviderAPI, eventDispatcher) => new SafePlugin({
|
|
82
|
+
export default ((options, pluginInjectionApi, portalProviderAPI, eventDispatcher, intl) => new SafePlugin({
|
|
60
83
|
key: pluginKey,
|
|
61
84
|
props: {
|
|
62
85
|
nodeViews: {
|
|
@@ -68,13 +91,20 @@ export default ((options, pluginInjectionApi, portalProviderAPI, eventDispatcher
|
|
|
68
91
|
portalProviderAPI,
|
|
69
92
|
eventDispatcher,
|
|
70
93
|
pluginInjectionApi,
|
|
71
|
-
options
|
|
94
|
+
options,
|
|
95
|
+
intl
|
|
72
96
|
}).init();
|
|
73
97
|
},
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
98
|
+
// Register the column node view when EITHER:
|
|
99
|
+
// 1. The resize handle experiment is on (its original purpose:
|
|
100
|
+
// suppress style-attribute MutationObserver callbacks during
|
|
101
|
+
// drag, allowing direct flex-basis writes without PM
|
|
102
|
+
// interference).
|
|
103
|
+
// 2. SSR streaming is enabled — the column node view stamps
|
|
104
|
+
// `container-type: inline-size` inline on each column dom so
|
|
105
|
+
// that the SSR-rendered table inside the column constrains
|
|
106
|
+
// its width to the column (see comment in the constructor).
|
|
107
|
+
...(editorExperiment('platform_editor_layout_column_resize_handle', true) || isSSR() && isSSRStreaming() ? {
|
|
78
108
|
layoutColumn: (node, view, getPos) => new LayoutColumnView(node, view, getPos)
|
|
79
109
|
} : {})
|
|
80
110
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { RawIntlProvider } from 'react-intl';
|
|
3
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
4
|
+
/**
|
|
5
|
+
* Wraps the layout section nodeview children with the editor's actual
|
|
6
|
+
* IntlProvider during SSR streaming (renderToStaticMarkup). This ensures any
|
|
7
|
+
* descendants that call `useIntl()` (e.g. `BreakoutResizer`'s ARIA labels)
|
|
8
|
+
* have a valid intl context and do not throw during the static render pass.
|
|
9
|
+
*
|
|
10
|
+
* Outside of SSR streaming this is a no-op passthrough.
|
|
11
|
+
*
|
|
12
|
+
* Follows the same pattern as `MediaSSRReactContextsProvider` and
|
|
13
|
+
* `SyncBlockSSRReactContextsProvider`.
|
|
14
|
+
*/
|
|
15
|
+
export function LayoutSSRReactContextsProvider({
|
|
16
|
+
children,
|
|
17
|
+
intl
|
|
18
|
+
}) {
|
|
19
|
+
if (!isSSRStreaming() || !isSSR()) {
|
|
20
|
+
return children;
|
|
21
|
+
}
|
|
22
|
+
if (!intl) {
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
25
|
+
return /*#__PURE__*/React.createElement(RawIntlProvider, {
|
|
26
|
+
value: intl
|
|
27
|
+
}, children);
|
|
28
|
+
}
|
package/dist/esm/layoutPlugin.js
CHANGED
|
@@ -107,8 +107,9 @@ export var layoutPlugin = function layoutPlugin(_ref) {
|
|
|
107
107
|
name: 'layoutResizing',
|
|
108
108
|
plugin: function plugin(_ref2) {
|
|
109
109
|
var portalProviderAPI = _ref2.portalProviderAPI,
|
|
110
|
-
eventDispatcher = _ref2.eventDispatcher
|
|
111
|
-
|
|
110
|
+
eventDispatcher = _ref2.eventDispatcher,
|
|
111
|
+
getIntl = _ref2.getIntl;
|
|
112
|
+
return createLayoutResizingPlugin(options, api, portalProviderAPI, eventDispatcher, getIntl());
|
|
112
113
|
}
|
|
113
114
|
});
|
|
114
115
|
}
|
|
@@ -9,8 +9,9 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
|
|
|
9
9
|
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; }
|
|
10
10
|
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; }
|
|
11
11
|
import React, { useCallback } from 'react';
|
|
12
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
12
13
|
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
13
|
-
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
14
|
+
import ReactNodeView, { NodeViewContentHole } from '@atlaskit/editor-common/react-node-view';
|
|
14
15
|
import { BreakoutResizer, ignoreResizerMutations } from '@atlaskit/editor-common/resizer';
|
|
15
16
|
import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
|
|
16
17
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
@@ -18,6 +19,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
|
|
|
18
19
|
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
|
|
19
20
|
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
|
|
20
21
|
import { selectIntoLayout } from '../pm-plugins/utils';
|
|
22
|
+
import { LayoutSSRReactContextsProvider } from '../ui/LayoutSSRReactContextsProvider';
|
|
21
23
|
var layoutDynamicFullWidthGuidelineOffset = 16;
|
|
22
24
|
var isEmptyParagraph = function isEmptyParagraph(node) {
|
|
23
25
|
return !!node && node.type.name === 'paragraph' && !node.childCount;
|
|
@@ -131,6 +133,7 @@ export var LayoutSectionView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
131
133
|
* @param props.eventDispatcher
|
|
132
134
|
* @param props.pluginInjectionApi
|
|
133
135
|
* @param props.options
|
|
136
|
+
* @param props.intl
|
|
134
137
|
* @example
|
|
135
138
|
*/
|
|
136
139
|
function LayoutSectionView(props) {
|
|
@@ -139,6 +142,7 @@ export var LayoutSectionView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
139
142
|
_this = _callSuper(this, LayoutSectionView, [props.node, props.view, props.getPos, props.portalProviderAPI, props.eventDispatcher, props]);
|
|
140
143
|
_this.isEmpty = isEmptyLayout(_this.node);
|
|
141
144
|
_this.options = props.options;
|
|
145
|
+
_this.intl = props.intl;
|
|
142
146
|
return _this;
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -151,6 +155,13 @@ export var LayoutSectionView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
151
155
|
return _createClass(LayoutSectionView, [{
|
|
152
156
|
key: "getContentDOM",
|
|
153
157
|
value: function getContentDOM() {
|
|
158
|
+
// Build the layout DOM via the schema's toDOM spec. This is the same
|
|
159
|
+
// path used in both CSR and SSR — the only SSR-specific concern is
|
|
160
|
+
// re-attaching `contentDOM` (= the `[data-layout-section]` element)
|
|
161
|
+
// after the portal's renderToStaticMarkup + innerHTML write detaches
|
|
162
|
+
// it. We handle that by stamping `data-ssr-content-dom-ref` on the
|
|
163
|
+
// outer container so `ReactNodeView.init()` can find a re-attach
|
|
164
|
+
// target inside `domRef` after the portal write.
|
|
154
165
|
var _ref2 = DOMSerializer.renderSpec(document, toDOM(this.node)),
|
|
155
166
|
container = _ref2.dom,
|
|
156
167
|
contentDOM = _ref2.contentDOM;
|
|
@@ -163,6 +174,20 @@ export var LayoutSectionView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
163
174
|
if (fg('platform_editor_adf_with_localid')) {
|
|
164
175
|
this.layoutDOM.setAttribute('data-local-id', this.node.attrs.localId);
|
|
165
176
|
}
|
|
177
|
+
|
|
178
|
+
// SSR streaming re-attach note:
|
|
179
|
+
// In SSR, `init()` appends `container` into `domRef`; the portal's
|
|
180
|
+
// renderToStaticMarkup + innerHTML write then wipes `domRef`,
|
|
181
|
+
// detaching the entire subtree (with PM-serialized children inside
|
|
182
|
+
// `[data-layout-section]`). React's `render()` emits a
|
|
183
|
+
// `<NodeViewContentHole/>` placeholder inside `domRef`; the SSR
|
|
184
|
+
// re-attach logic in `init()` finds it via `[data-ssr-content-dom-ref]`
|
|
185
|
+
// and calls `_handleRef`, which appends `contentDOMWrapper` (the
|
|
186
|
+
// detached `container`) back inside the placeholder. The end result
|
|
187
|
+
// is `domRef > NodeViewContentHole > layout-section-container >
|
|
188
|
+
// [data-layout-section] > [data-layout-column] children` — the
|
|
189
|
+
// layout DOM contract is preserved.
|
|
190
|
+
|
|
166
191
|
return {
|
|
167
192
|
dom: container,
|
|
168
193
|
contentDOM: contentDOM
|
|
@@ -197,6 +222,29 @@ export var LayoutSectionView = /*#__PURE__*/function (_ReactNodeView) {
|
|
|
197
222
|
if (this.layoutDOM) {
|
|
198
223
|
this.layoutDOM.setAttribute('data-empty-layout', Boolean(this.isEmpty).toString());
|
|
199
224
|
}
|
|
225
|
+
|
|
226
|
+
// SSR streaming path: render only a `<NodeViewContentHole/>` placeholder
|
|
227
|
+
// so ReactNodeView.init()'s SSR re-attach logic can find the marker
|
|
228
|
+
// (`data-ssr-content-dom-ref`) and re-append the detached
|
|
229
|
+
// contentDOMWrapper — which is the FULL layout structure
|
|
230
|
+
// (`layout-section-container > [data-layout-section] > children`) built
|
|
231
|
+
// in `getContentDOM` via DOMSerializer.renderSpec. This avoids
|
|
232
|
+
// duplicating layout structure between getContentDOM and render(), which
|
|
233
|
+
// previously caused an extra wrapping div between `[data-layout-section]`
|
|
234
|
+
// and the `[data-layout-column]` children and broke the flex layout.
|
|
235
|
+
//
|
|
236
|
+
// The BreakoutResizer is intentionally omitted in SSR — it relies on
|
|
237
|
+
// browser-only APIs and contributes no useful static markup. The
|
|
238
|
+
// LayoutSSRReactContextsProvider wraps the placeholder to inject the
|
|
239
|
+
// editor's IntlShape, defending against any descendants that call
|
|
240
|
+
// `useIntl()` during renderToStaticMarkup.
|
|
241
|
+
if (isSSR() && isSSRStreaming()) {
|
|
242
|
+
return /*#__PURE__*/React.createElement(LayoutSSRReactContextsProvider, {
|
|
243
|
+
intl: this.intl
|
|
244
|
+
}, /*#__PURE__*/React.createElement(NodeViewContentHole, {
|
|
245
|
+
ref: forwardRef
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
200
248
|
if (expValEquals('platform_editor_breakout_resizing', 'isEnabled', true)) {
|
|
201
249
|
return null;
|
|
202
250
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
3
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
4
|
+
import _typeof from "@babel/runtime/helpers/typeof";
|
|
4
5
|
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; }
|
|
5
6
|
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; }
|
|
7
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
6
8
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
7
9
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
8
10
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
@@ -19,6 +21,28 @@ export var pluginKey = new PluginKey('layoutResizingPlugin');
|
|
|
19
21
|
* (e.g. setting flex-basis to give real-time visual feedback without dispatching
|
|
20
22
|
* PM transactions) are not "corrected" back by ProseMirror's DOM reconciliation.
|
|
21
23
|
*/
|
|
24
|
+
var isLayoutElementLike = function isLayoutElementLike(element) {
|
|
25
|
+
if (isSSR() && isSSRStreaming()) {
|
|
26
|
+
// In SSR environments, `HTMLElement` is undefined globally so a plain
|
|
27
|
+
// `instanceof HTMLElement` check is always `false`. That makes the
|
|
28
|
+
// `DOMSerializer.renderSpec(...)` result get rejected by the guard below and
|
|
29
|
+
// the NodeView falls back to a bare `<div>`, losing every schema-defined
|
|
30
|
+
// attribute (`data-layout-column`, `style="flex-basis:..."`,
|
|
31
|
+
// `data-column-width`, plus the inner `<div data-layout-content="true">`
|
|
32
|
+
// wrapper) and breaking the layout's flex sizing in SSR output.
|
|
33
|
+
//
|
|
34
|
+
// To unblock SSR streaming without changing CSR semantics, we gate the check:
|
|
35
|
+
// - In SSR (and only when `platform_editor_editor_ssr_streaming` is enabled),
|
|
36
|
+
// use a duck-typed check that mirrors `safe-plugin`'s `isHTMLElement`.
|
|
37
|
+
// - Everywhere else, keep the original `instanceof HTMLElement` check exactly
|
|
38
|
+
// as it was so we don't accidentally widen acceptance in CSR.
|
|
39
|
+
if (element === null || element === undefined) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return _typeof(element) === 'object' && 'innerHTML' in element && 'style' in element && 'classList' in element;
|
|
43
|
+
}
|
|
44
|
+
return element instanceof HTMLElement;
|
|
45
|
+
};
|
|
22
46
|
var LayoutColumnView = /*#__PURE__*/function () {
|
|
23
47
|
function LayoutColumnView(node, view, getPos) {
|
|
24
48
|
_classCallCheck(this, LayoutColumnView);
|
|
@@ -36,7 +60,7 @@ var LayoutColumnView = /*#__PURE__*/function () {
|
|
|
36
60
|
var _DOMSerializer$render = DOMSerializer.renderSpec(document, nodeType.spec.toDOM(node)),
|
|
37
61
|
dom = _DOMSerializer$render.dom,
|
|
38
62
|
contentDOM = _DOMSerializer$render.contentDOM;
|
|
39
|
-
if (!(dom
|
|
63
|
+
if (!isLayoutElementLike(dom) || !isLayoutElementLike(contentDOM)) {
|
|
40
64
|
var _fallbackDiv = document.createElement('div');
|
|
41
65
|
this.dom = _fallbackDiv;
|
|
42
66
|
this.contentDOM = _fallbackDiv;
|
|
@@ -64,7 +88,7 @@ var LayoutColumnView = /*#__PURE__*/function () {
|
|
|
64
88
|
}
|
|
65
89
|
}]);
|
|
66
90
|
}();
|
|
67
|
-
export default (function (options, pluginInjectionApi, portalProviderAPI, eventDispatcher) {
|
|
91
|
+
export default (function (options, pluginInjectionApi, portalProviderAPI, eventDispatcher, intl) {
|
|
68
92
|
return new SafePlugin({
|
|
69
93
|
key: pluginKey,
|
|
70
94
|
props: {
|
|
@@ -77,10 +101,11 @@ export default (function (options, pluginInjectionApi, portalProviderAPI, eventD
|
|
|
77
101
|
portalProviderAPI: portalProviderAPI,
|
|
78
102
|
eventDispatcher: eventDispatcher,
|
|
79
103
|
pluginInjectionApi: pluginInjectionApi,
|
|
80
|
-
options: options
|
|
104
|
+
options: options,
|
|
105
|
+
intl: intl
|
|
81
106
|
}).init();
|
|
82
107
|
}
|
|
83
|
-
}, editorExperiment('platform_editor_layout_column_resize_handle', true) ? {
|
|
108
|
+
}, editorExperiment('platform_editor_layout_column_resize_handle', true) || isSSR() && isSSRStreaming() ? {
|
|
84
109
|
layoutColumn: function layoutColumn(node, view, getPos) {
|
|
85
110
|
return new LayoutColumnView(node, view, getPos);
|
|
86
111
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { RawIntlProvider } from 'react-intl';
|
|
3
|
+
import { isSSR, isSSRStreaming } from '@atlaskit/editor-common/core-utils';
|
|
4
|
+
/**
|
|
5
|
+
* Wraps the layout section nodeview children with the editor's actual
|
|
6
|
+
* IntlProvider during SSR streaming (renderToStaticMarkup). This ensures any
|
|
7
|
+
* descendants that call `useIntl()` (e.g. `BreakoutResizer`'s ARIA labels)
|
|
8
|
+
* have a valid intl context and do not throw during the static render pass.
|
|
9
|
+
*
|
|
10
|
+
* Outside of SSR streaming this is a no-op passthrough.
|
|
11
|
+
*
|
|
12
|
+
* Follows the same pattern as `MediaSSRReactContextsProvider` and
|
|
13
|
+
* `SyncBlockSSRReactContextsProvider`.
|
|
14
|
+
*/
|
|
15
|
+
export function LayoutSSRReactContextsProvider(_ref) {
|
|
16
|
+
var children = _ref.children,
|
|
17
|
+
intl = _ref.intl;
|
|
18
|
+
if (!isSSRStreaming() || !isSSR()) {
|
|
19
|
+
return children;
|
|
20
|
+
}
|
|
21
|
+
if (!intl) {
|
|
22
|
+
return children;
|
|
23
|
+
}
|
|
24
|
+
return /*#__PURE__*/React.createElement(RawIntlProvider, {
|
|
25
|
+
value: intl
|
|
26
|
+
}, children);
|
|
27
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { IntlShape } from 'react-intl';
|
|
2
3
|
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
3
4
|
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
4
5
|
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
@@ -10,6 +11,7 @@ import type { LayoutPluginOptions } from '../types';
|
|
|
10
11
|
type LayoutSectionViewProps = {
|
|
11
12
|
eventDispatcher: EventDispatcher;
|
|
12
13
|
getPos: getPosHandlerNode;
|
|
14
|
+
intl?: IntlShape;
|
|
13
15
|
node: PMNode;
|
|
14
16
|
options: LayoutPluginOptions;
|
|
15
17
|
pluginInjectionApi?: ExtractInjectionAPI<LayoutPlugin>;
|
|
@@ -24,6 +26,7 @@ export declare class LayoutSectionView extends ReactNodeView<LayoutSectionViewPr
|
|
|
24
26
|
options: LayoutPluginOptions;
|
|
25
27
|
layoutDOM?: HTMLElement;
|
|
26
28
|
isEmpty?: boolean;
|
|
29
|
+
private intl?;
|
|
27
30
|
/**
|
|
28
31
|
* constructor
|
|
29
32
|
* @param props
|
|
@@ -34,11 +37,13 @@ export declare class LayoutSectionView extends ReactNodeView<LayoutSectionViewPr
|
|
|
34
37
|
* @param props.eventDispatcher
|
|
35
38
|
* @param props.pluginInjectionApi
|
|
36
39
|
* @param props.options
|
|
40
|
+
* @param props.intl
|
|
37
41
|
* @example
|
|
38
42
|
*/
|
|
39
43
|
constructor(props: {
|
|
40
44
|
eventDispatcher: EventDispatcher;
|
|
41
45
|
getPos: getPosHandlerNode;
|
|
46
|
+
intl?: IntlShape;
|
|
42
47
|
node: PMNode;
|
|
43
48
|
options: LayoutPluginOptions;
|
|
44
49
|
pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IntlShape } from 'react-intl';
|
|
1
2
|
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
2
3
|
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
3
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
@@ -6,5 +7,5 @@ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
|
6
7
|
import type { LayoutPlugin } from '../layoutPluginType';
|
|
7
8
|
import type { LayoutPluginOptions } from '../types';
|
|
8
9
|
export declare const pluginKey: PluginKey;
|
|
9
|
-
declare const _default: (options: LayoutPluginOptions, pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher) => SafePlugin<undefined>;
|
|
10
|
+
declare const _default: (options: LayoutPluginOptions, pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher, intl?: IntlShape) => SafePlugin<undefined>;
|
|
10
11
|
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type IntlShape } from 'react-intl';
|
|
3
|
+
interface Props {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
intl: IntlShape | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Wraps the layout section nodeview children with the editor's actual
|
|
9
|
+
* IntlProvider during SSR streaming (renderToStaticMarkup). This ensures any
|
|
10
|
+
* descendants that call `useIntl()` (e.g. `BreakoutResizer`'s ARIA labels)
|
|
11
|
+
* have a valid intl context and do not throw during the static render pass.
|
|
12
|
+
*
|
|
13
|
+
* Outside of SSR streaming this is a no-op passthrough.
|
|
14
|
+
*
|
|
15
|
+
* Follows the same pattern as `MediaSSRReactContextsProvider` and
|
|
16
|
+
* `SyncBlockSSRReactContextsProvider`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function LayoutSSRReactContextsProvider({ children, intl }: Props): ReactNode;
|
|
19
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { IntlShape } from 'react-intl';
|
|
2
3
|
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
3
4
|
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
4
5
|
import ReactNodeView from '@atlaskit/editor-common/react-node-view';
|
|
@@ -10,6 +11,7 @@ import type { LayoutPluginOptions } from '../types';
|
|
|
10
11
|
type LayoutSectionViewProps = {
|
|
11
12
|
eventDispatcher: EventDispatcher;
|
|
12
13
|
getPos: getPosHandlerNode;
|
|
14
|
+
intl?: IntlShape;
|
|
13
15
|
node: PMNode;
|
|
14
16
|
options: LayoutPluginOptions;
|
|
15
17
|
pluginInjectionApi?: ExtractInjectionAPI<LayoutPlugin>;
|
|
@@ -24,6 +26,7 @@ export declare class LayoutSectionView extends ReactNodeView<LayoutSectionViewPr
|
|
|
24
26
|
options: LayoutPluginOptions;
|
|
25
27
|
layoutDOM?: HTMLElement;
|
|
26
28
|
isEmpty?: boolean;
|
|
29
|
+
private intl?;
|
|
27
30
|
/**
|
|
28
31
|
* constructor
|
|
29
32
|
* @param props
|
|
@@ -34,11 +37,13 @@ export declare class LayoutSectionView extends ReactNodeView<LayoutSectionViewPr
|
|
|
34
37
|
* @param props.eventDispatcher
|
|
35
38
|
* @param props.pluginInjectionApi
|
|
36
39
|
* @param props.options
|
|
40
|
+
* @param props.intl
|
|
37
41
|
* @example
|
|
38
42
|
*/
|
|
39
43
|
constructor(props: {
|
|
40
44
|
eventDispatcher: EventDispatcher;
|
|
41
45
|
getPos: getPosHandlerNode;
|
|
46
|
+
intl?: IntlShape;
|
|
42
47
|
node: PMNode;
|
|
43
48
|
options: LayoutPluginOptions;
|
|
44
49
|
pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { IntlShape } from 'react-intl';
|
|
1
2
|
import type { EventDispatcher } from '@atlaskit/editor-common/event-dispatcher';
|
|
2
3
|
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
3
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
@@ -6,5 +7,5 @@ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
|
6
7
|
import type { LayoutPlugin } from '../layoutPluginType';
|
|
7
8
|
import type { LayoutPluginOptions } from '../types';
|
|
8
9
|
export declare const pluginKey: PluginKey;
|
|
9
|
-
declare const _default: (options: LayoutPluginOptions, pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher) => SafePlugin<undefined>;
|
|
10
|
+
declare const _default: (options: LayoutPluginOptions, pluginInjectionApi: ExtractInjectionAPI<LayoutPlugin>, portalProviderAPI: PortalProviderAPI, eventDispatcher: EventDispatcher, intl?: IntlShape) => SafePlugin<undefined>;
|
|
10
11
|
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type IntlShape } from 'react-intl';
|
|
3
|
+
interface Props {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
intl: IntlShape | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Wraps the layout section nodeview children with the editor's actual
|
|
9
|
+
* IntlProvider during SSR streaming (renderToStaticMarkup). This ensures any
|
|
10
|
+
* descendants that call `useIntl()` (e.g. `BreakoutResizer`'s ARIA labels)
|
|
11
|
+
* have a valid intl context and do not throw during the static render pass.
|
|
12
|
+
*
|
|
13
|
+
* Outside of SSR streaming this is a no-op passthrough.
|
|
14
|
+
*
|
|
15
|
+
* Follows the same pattern as `MediaSSRReactContextsProvider` and
|
|
16
|
+
* `SyncBlockSSRReactContextsProvider`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function LayoutSSRReactContextsProvider({ children, intl }: Props): ReactNode;
|
|
19
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-layout",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.4",
|
|
4
4
|
"description": "Layout plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,14 +50,14 @@
|
|
|
50
50
|
"@atlaskit/icon": "^35.4.0",
|
|
51
51
|
"@atlaskit/icon-lab": "^6.13.0",
|
|
52
52
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
53
|
-
"@atlaskit/tmp-editor-statsig": "^89.
|
|
54
|
-
"@atlaskit/tokens": "^13.
|
|
53
|
+
"@atlaskit/tmp-editor-statsig": "^89.4.0",
|
|
54
|
+
"@atlaskit/tokens": "^13.3.0",
|
|
55
55
|
"@babel/runtime": "^7.0.0",
|
|
56
56
|
"@emotion/react": "^11.7.1",
|
|
57
57
|
"bind-event-listener": "^3.0.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@atlaskit/editor-common": "^115.
|
|
60
|
+
"@atlaskit/editor-common": "^115.6.0",
|
|
61
61
|
"react": "^18.2.0",
|
|
62
62
|
"react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
|
|
63
63
|
},
|