@atlaskit/editor-plugin-media 12.4.1 → 12.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/cjs/nodeviews/helpers.js +5 -1
- package/dist/cjs/nodeviews/mediaNodeUpdater.js +72 -3
- package/dist/cjs/nodeviews/mediaSingleNext.js +11 -5
- package/dist/cjs/nodeviews/nodeviewHelpers.js +26 -0
- package/dist/cjs/pm-plugins/main.js +213 -20
- package/dist/cjs/ui/toolbar/index.js +13 -1
- package/dist/es2019/nodeviews/helpers.js +5 -1
- package/dist/es2019/nodeviews/mediaNodeUpdater.js +77 -1
- package/dist/es2019/nodeviews/mediaSingleNext.js +11 -5
- package/dist/es2019/nodeviews/nodeviewHelpers.js +20 -0
- package/dist/es2019/pm-plugins/main.js +211 -4
- package/dist/es2019/ui/toolbar/index.js +13 -1
- package/dist/esm/nodeviews/helpers.js +5 -1
- package/dist/esm/nodeviews/mediaNodeUpdater.js +70 -1
- package/dist/esm/nodeviews/mediaSingleNext.js +11 -5
- package/dist/esm/nodeviews/nodeviewHelpers.js +20 -0
- package/dist/esm/pm-plugins/main.js +203 -10
- package/dist/esm/ui/toolbar/index.js +13 -1
- package/dist/types/nodeviews/mediaNodeUpdater.d.ts +3 -1
- package/dist/types/nodeviews/nodeviewHelpers.d.ts +11 -0
- package/dist/types/pm-plugins/main.d.ts +12 -0
- package/dist/types/pm-plugins/types.d.ts +3 -0
- package/dist/types-ts4.5/nodeviews/mediaNodeUpdater.d.ts +3 -1
- package/dist/types-ts4.5/nodeviews/nodeviewHelpers.d.ts +11 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +12 -0
- package/dist/types-ts4.5/pm-plugins/types.d.ts +3 -0
- package/nodeviewHelpers/package.json +17 -0
- package/package.json +5 -5
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
3
3
|
import uuidV4 from 'uuid/v4';
|
|
4
|
+
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
4
5
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
5
6
|
import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '@atlaskit/editor-common/media-single';
|
|
7
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
6
8
|
import { getAttrsFromUrl, isImageRepresentationReady, isMediaBlobUrl } from '@atlaskit/media-client';
|
|
7
9
|
import { getMediaClient } from '@atlaskit/media-client-react';
|
|
8
10
|
import { getClientIdForFile } from '@atlaskit/media-common';
|
|
@@ -11,6 +13,7 @@ import { replaceExternalMedia, updateCurrentMediaNodeAttrs, updateMediaNodeAttrs
|
|
|
11
13
|
import { stateKey as mediaStateKey } from '../pm-plugins/plugin-key';
|
|
12
14
|
import { batchMediaNodeAttrsUpdate } from '../pm-plugins/utils/batchMediaNodeAttrs';
|
|
13
15
|
import { getIdentifier } from '../pm-plugins/utils/media-common';
|
|
16
|
+
import { computeReplacementDisplayWidth } from './nodeviewHelpers';
|
|
14
17
|
const isMediaTypeSupported = type => {
|
|
15
18
|
if (type) {
|
|
16
19
|
return ['image', 'file'].includes(type);
|
|
@@ -179,7 +182,80 @@ export class MediaNodeUpdater {
|
|
|
179
182
|
return attrs.__contextId || null;
|
|
180
183
|
});
|
|
181
184
|
_defineProperty(this, "updateDimensions", dimensions => {
|
|
182
|
-
|
|
185
|
+
const {
|
|
186
|
+
view
|
|
187
|
+
} = this.props;
|
|
188
|
+
const mediaPluginState = mediaStateKey.getState(view.state);
|
|
189
|
+
const targetDisplayHeight = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.replaceMediaTargetDisplayHeight;
|
|
190
|
+
if (targetDisplayHeight !== null && targetDisplayHeight !== undefined && dimensions.width > 0) {
|
|
191
|
+
var _this$props$lineLengt, _mediaSingleNode$attr, _mediaSingleNode, _mediaSingleNode$attr2;
|
|
192
|
+
// Replace mode: combine intrinsic dimension update on the media node AND
|
|
193
|
+
// display width update on the mediaSingle into a single transaction so they
|
|
194
|
+
// are never out of sync and don't cause two separate renders/layout shifts.
|
|
195
|
+
|
|
196
|
+
// Clear the stored target height — this is a one-shot adjustment
|
|
197
|
+
if (mediaPluginState) {
|
|
198
|
+
mediaPluginState.replaceMediaTargetDisplayHeight = null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Clamp to the layout's maximum width so the image never overflows its container.
|
|
202
|
+
const lineLength = (_this$props$lineLengt = this.props.lineLength) !== null && _this$props$lineLengt !== void 0 ? _this$props$lineLengt : 760;
|
|
203
|
+
const {
|
|
204
|
+
state
|
|
205
|
+
} = view;
|
|
206
|
+
const {
|
|
207
|
+
mediaSingle
|
|
208
|
+
} = state.schema.nodes;
|
|
209
|
+
// Typed explicitly because TypeScript can't track mutations inside
|
|
210
|
+
// the descendants callback closure and would narrow these to `never`.
|
|
211
|
+
let mediaSinglePos = null;
|
|
212
|
+
let mediaSingleNode = null;
|
|
213
|
+
let mediaPos = null;
|
|
214
|
+
state.doc.descendants((node, pos) => {
|
|
215
|
+
if (mediaSinglePos !== null) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (node.type === mediaSingle) {
|
|
219
|
+
const mediaChild = node.firstChild;
|
|
220
|
+
if (mediaChild && mediaChild.attrs.id === dimensions.id) {
|
|
221
|
+
mediaSinglePos = pos;
|
|
222
|
+
mediaSingleNode = node;
|
|
223
|
+
mediaPos = pos + 1;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
});
|
|
228
|
+
const layout = (_mediaSingleNode$attr = (_mediaSingleNode = mediaSingleNode) === null || _mediaSingleNode === void 0 ? void 0 : (_mediaSingleNode$attr2 = _mediaSingleNode.attrs) === null || _mediaSingleNode$attr2 === void 0 ? void 0 : _mediaSingleNode$attr2.layout) !== null && _mediaSingleNode$attr !== void 0 ? _mediaSingleNode$attr : 'center';
|
|
229
|
+
const newDisplayWidth = computeReplacementDisplayWidth(targetDisplayHeight, dimensions.width, dimensions.height, layout, lineLength);
|
|
230
|
+
if (mediaSinglePos !== null && mediaSingleNode !== null && mediaPos !== null) {
|
|
231
|
+
const tr = state.tr;
|
|
232
|
+
|
|
233
|
+
// Update intrinsic dimensions on the media child node
|
|
234
|
+
tr.step(new SetAttrsStep(mediaPos, {
|
|
235
|
+
height: dimensions.height,
|
|
236
|
+
width: dimensions.width
|
|
237
|
+
}));
|
|
238
|
+
|
|
239
|
+
// Update display width on the mediaSingle parent
|
|
240
|
+
tr.setNodeMarkup(mediaSinglePos, undefined, {
|
|
241
|
+
...mediaSingleNode.attrs,
|
|
242
|
+
width: Math.round(newDisplayWidth),
|
|
243
|
+
widthType: 'pixel'
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Re-create the NodeSelection so the floating toolbar picks up
|
|
247
|
+
// the updated node and renders the full set of controls.
|
|
248
|
+
if (state.selection instanceof NodeSelection) {
|
|
249
|
+
tr.setSelection(NodeSelection.create(tr.doc, mediaSinglePos));
|
|
250
|
+
}
|
|
251
|
+
tr.setMeta('scrollIntoView', false);
|
|
252
|
+
view.dispatch(tr);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Normal (non-replace) path: use the existing batched update mechanism
|
|
258
|
+
batchMediaNodeAttrsUpdate(view, {
|
|
183
259
|
id: dimensions.id,
|
|
184
260
|
nextAttributes: {
|
|
185
261
|
height: dimensions.height,
|
|
@@ -104,7 +104,8 @@ const useMediaAsyncOperations = ({
|
|
|
104
104
|
mediaNode,
|
|
105
105
|
mediaNodeUpdater,
|
|
106
106
|
addPendingTask,
|
|
107
|
-
getPos
|
|
107
|
+
getPos,
|
|
108
|
+
mediaChildNodeId
|
|
108
109
|
}) => {
|
|
109
110
|
React.useEffect(() => {
|
|
110
111
|
if (!mediaNodeUpdater) {
|
|
@@ -122,7 +123,11 @@ const useMediaAsyncOperations = ({
|
|
|
122
123
|
mediaNode,
|
|
123
124
|
addPendingTask
|
|
124
125
|
});
|
|
125
|
-
|
|
126
|
+
// mediaChildNodeId is included so this effect re-runs when the media source
|
|
127
|
+
// is replaced (id changes), ensuring getRemoteDimensions fires for the new file
|
|
128
|
+
// with up-to-date updater props after setProps has been called.
|
|
129
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
130
|
+
}, [mediaNode, addPendingTask, mediaNodeUpdater, getPos, mediaChildNodeId]);
|
|
126
131
|
};
|
|
127
132
|
const noop = () => {};
|
|
128
133
|
|
|
@@ -248,7 +253,7 @@ const useUpdateSizeCallback = ({
|
|
|
248
253
|
*/
|
|
249
254
|
const FALLBACK_MOST_COMMON_WIDTH = 760;
|
|
250
255
|
export const MediaSingleNodeNext = mediaSingleNodeNextProps => {
|
|
251
|
-
var _pluginInjectionApi$m, _pluginInjectionApi$m2, _mediaNode$
|
|
256
|
+
var _mediaNode$firstChild, _pluginInjectionApi$m, _pluginInjectionApi$m2, _mediaNode$firstChild2;
|
|
252
257
|
const {
|
|
253
258
|
selected,
|
|
254
259
|
getPos,
|
|
@@ -288,7 +293,8 @@ export const MediaSingleNodeNext = mediaSingleNodeNextProps => {
|
|
|
288
293
|
mediaNodeUpdater,
|
|
289
294
|
getPos,
|
|
290
295
|
mediaNode,
|
|
291
|
-
addPendingTask: addPendingTask || noop
|
|
296
|
+
addPendingTask: addPendingTask || noop,
|
|
297
|
+
mediaChildNodeId: (_mediaNode$firstChild = mediaNode.firstChild) === null || _mediaNode$firstChild === void 0 ? void 0 : _mediaNode$firstChild.attrs.id
|
|
292
298
|
});
|
|
293
299
|
React.useLayoutEffect(() => {
|
|
294
300
|
mountedRef.current = true;
|
|
@@ -389,7 +395,7 @@ export const MediaSingleNodeNext = mediaSingleNodeNextProps => {
|
|
|
389
395
|
}, [mediaSingleWidthAttribute, widthType, width, layout, contentWidthForLegacyExperience, containerWidth]);
|
|
390
396
|
const currentMaxWidth = isSelected ? pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$m = pluginInjectionApi.media) === null || _pluginInjectionApi$m === void 0 ? void 0 : (_pluginInjectionApi$m2 = _pluginInjectionApi$m.sharedState.currentState()) === null || _pluginInjectionApi$m2 === void 0 ? void 0 : _pluginInjectionApi$m2.currentMaxWidth : undefined;
|
|
391
397
|
const contentWidth = currentMaxWidth || lineLength;
|
|
392
|
-
const isCurrentNodeDrafting = Boolean(isDrafting && targetNodeId === (mediaNode === null || mediaNode === void 0 ? void 0 : (_mediaNode$
|
|
398
|
+
const isCurrentNodeDrafting = Boolean(isDrafting && targetNodeId === (mediaNode === null || mediaNode === void 0 ? void 0 : (_mediaNode$firstChild2 = mediaNode.firstChild) === null || _mediaNode$firstChild2 === void 0 ? void 0 : _mediaNode$firstChild2.attrs.id));
|
|
393
399
|
const mediaSingleWrapperRef = /*#__PURE__*/React.createRef();
|
|
394
400
|
const captionPlaceHolderRef = /*#__PURE__*/React.createRef();
|
|
395
401
|
const browser = getBrowserInfo();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { akEditorFullWidthLayoutWidth, akEditorWideLayoutWidth } from '@atlaskit/editor-shared-styles';
|
|
2
|
+
const MIN_MEDIA_DISPLAY_WIDTH = 24;
|
|
3
|
+
/**
|
|
4
|
+
* Computes the new mediaSingle display width that preserves the original display height
|
|
5
|
+
* when a media node is replaced with a file of a different aspect ratio, clamped to valid bounds.
|
|
6
|
+
*
|
|
7
|
+
* @param targetDisplayHeight - The display height to preserve (from the old image)
|
|
8
|
+
* @param newIntrinsicWidth - The new file's intrinsic pixel width
|
|
9
|
+
* @param newIntrinsicHeight - The new file's intrinsic pixel height
|
|
10
|
+
* @param layout - The mediaSingle layout (affects max width)
|
|
11
|
+
* @param lineLength - The editor content column width in pixels
|
|
12
|
+
*/
|
|
13
|
+
export const computeReplacementDisplayWidth = (targetDisplayHeight, newIntrinsicWidth, newIntrinsicHeight, layout, lineLength) => {
|
|
14
|
+
if (newIntrinsicHeight <= 0) {
|
|
15
|
+
return MIN_MEDIA_DISPLAY_WIDTH;
|
|
16
|
+
}
|
|
17
|
+
const unclamped = targetDisplayHeight * (newIntrinsicWidth / newIntrinsicHeight);
|
|
18
|
+
const maxWidth = layout === 'full-width' ? akEditorFullWidthLayoutWidth : layout === 'wide' ? akEditorWideLayoutWidth : lineLength;
|
|
19
|
+
return Math.max(MIN_MEDIA_DISPLAY_WIDTH, Math.min(unclamped, maxWidth));
|
|
20
|
+
};
|
|
@@ -4,6 +4,7 @@ import React from 'react';
|
|
|
4
4
|
import { RawIntlProvider } from 'react-intl';
|
|
5
5
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
6
6
|
import uuid from 'uuid';
|
|
7
|
+
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
7
8
|
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
8
9
|
import { getBrowserInfo } from '@atlaskit/editor-common/browser';
|
|
9
10
|
import { mediaInlineImagesEnabled } from '@atlaskit/editor-common/media-inline';
|
|
@@ -18,6 +19,7 @@ import { CellSelection } from '@atlaskit/editor-tables/cell-selection';
|
|
|
18
19
|
import { isFileIdentifier } from '@atlaskit/media-client';
|
|
19
20
|
import { getMediaFeatureFlag } from '@atlaskit/media-common';
|
|
20
21
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
22
|
+
import { createMediaNodeUpdater } from '../nodeviews/mediaNodeUpdater';
|
|
21
23
|
// Ignored via go/ees005
|
|
22
24
|
// eslint-disable-next-line import/no-namespace
|
|
23
25
|
import * as helpers from '../pm-plugins/commands/helpers';
|
|
@@ -72,6 +74,15 @@ export class MediaPluginStateImplementation {
|
|
|
72
74
|
_defineProperty(this, "destroyed", false);
|
|
73
75
|
_defineProperty(this, "removeOnCloseListener", () => {});
|
|
74
76
|
_defineProperty(this, "onPopupToggleCallback", () => {});
|
|
77
|
+
// When non-null, holds the file ID of the media node being replaced. Used both as a
|
|
78
|
+
// flag (non-null = replace mode) and as a cross-check to ensure the correct node is
|
|
79
|
+
// updated if the selection moves between the picker opening and the file being picked.
|
|
80
|
+
_defineProperty(this, "replaceMediaFileId", null);
|
|
81
|
+
// The display height (in pixels) of the mediaSingle being replaced, computed at replace time
|
|
82
|
+
// from its display width and the old media node's intrinsic aspect ratio.
|
|
83
|
+
// Used by the nodeview to recompute display width from the new file's aspect ratio after
|
|
84
|
+
// dimensions are fetched, preserving visual height rather than visual width.
|
|
85
|
+
_defineProperty(this, "replaceMediaTargetDisplayHeight", null);
|
|
75
86
|
_defineProperty(this, "identifierCount", new Map());
|
|
76
87
|
// This is to enable mediaShallowCopySope to enable only shallow copying media referenced within the edtior
|
|
77
88
|
// see: trackOutOfScopeIdentifier
|
|
@@ -107,7 +118,7 @@ export class MediaPluginStateImplementation {
|
|
|
107
118
|
* called when we insert a new file via the picker (connected via pickerfacade)
|
|
108
119
|
*/
|
|
109
120
|
_defineProperty(this, "insertFile", (mediaState, onMediaStateChanged, pickerType, insertMediaVia) => {
|
|
110
|
-
var _this$pluginInjection, _this$pluginInjection2, _mediaState$collectio, _this$
|
|
121
|
+
var _this$pluginInjection, _this$pluginInjection2, _mediaState$collectio, _this$pluginInjection6, _this$pluginInjection7;
|
|
111
122
|
const {
|
|
112
123
|
state
|
|
113
124
|
} = this.view;
|
|
@@ -121,6 +132,21 @@ export class MediaPluginStateImplementation {
|
|
|
121
132
|
return;
|
|
122
133
|
}
|
|
123
134
|
|
|
135
|
+
// If replace mode was set but the selection has moved away from a mediaSingle
|
|
136
|
+
// (e.g. the user cancelled the replace picker and then inserted media elsewhere),
|
|
137
|
+
// clear replace state so this insertion proceeds as a normal insert.
|
|
138
|
+
if (this.replaceMediaFileId !== null) {
|
|
139
|
+
var _state$selection$node;
|
|
140
|
+
const {
|
|
141
|
+
mediaSingle
|
|
142
|
+
} = state.schema.nodes;
|
|
143
|
+
const isStillOnTargetMedia = state.selection instanceof NodeSelection && state.selection.node.type === mediaSingle && ((_state$selection$node = state.selection.node.firstChild) === null || _state$selection$node === void 0 ? void 0 : _state$selection$node.attrs.id) === this.replaceMediaFileId;
|
|
144
|
+
if (!isStillOnTargetMedia) {
|
|
145
|
+
this.replaceMediaFileId = null;
|
|
146
|
+
this.replaceMediaTargetDisplayHeight = null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
124
150
|
// We need to dispatch the change to event dispatcher only for successful files
|
|
125
151
|
if (mediaState.status !== 'error') {
|
|
126
152
|
this.updateAndDispatch({
|
|
@@ -131,13 +157,130 @@ export class MediaPluginStateImplementation {
|
|
|
131
157
|
this.uploadInProgressSubscriptions.forEach(fn => fn(true));
|
|
132
158
|
this.uploadInProgressSubscriptionsNotified = true;
|
|
133
159
|
}
|
|
160
|
+
|
|
161
|
+
// Replace mode: if a media node is being replaced, update its attrs in-place
|
|
162
|
+
// rather than inserting a new node. This preserves layout, width, and caption.
|
|
163
|
+
if (this.replaceMediaFileId !== null) {
|
|
164
|
+
var _mediaState$fileMimeT, _mediaState$fileName, _mediaState$fileSize;
|
|
165
|
+
// Clear replace mode immediately so subsequent insertions behave normally
|
|
166
|
+
this.replaceMediaFileId = null;
|
|
167
|
+
const {
|
|
168
|
+
state: currentState
|
|
169
|
+
} = this.view;
|
|
170
|
+
const mediaSinglePos = currentState.selection.from;
|
|
171
|
+
const mediaPos = mediaSinglePos + 1;
|
|
172
|
+
const mediaNode = currentState.doc.nodeAt(mediaPos);
|
|
173
|
+
if (!mediaNode || mediaNode.type.name !== 'media') {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Build a single transaction that:
|
|
178
|
+
// 1. Updates the media child node attrs (new file identity + cleared dimensions)
|
|
179
|
+
// 2. Re-creates the NodeSelection so the toolbar picks up the fresh node
|
|
180
|
+
const tr = currentState.tr;
|
|
181
|
+
tr.step(new SetAttrsStep(mediaPos, {
|
|
182
|
+
id: mediaState.id,
|
|
183
|
+
collection,
|
|
184
|
+
type: 'file',
|
|
185
|
+
__fileMimeType: (_mediaState$fileMimeT = mediaState.fileMimeType) !== null && _mediaState$fileMimeT !== void 0 ? _mediaState$fileMimeT : null,
|
|
186
|
+
__fileName: (_mediaState$fileName = mediaState.fileName) !== null && _mediaState$fileName !== void 0 ? _mediaState$fileName : null,
|
|
187
|
+
__fileSize: (_mediaState$fileSize = mediaState.fileSize) !== null && _mediaState$fileSize !== void 0 ? _mediaState$fileSize : null,
|
|
188
|
+
__mediaTraceId: null,
|
|
189
|
+
// Clear intrinsic dimensions — they'll be fetched once the file
|
|
190
|
+
// is processed and applied via updateDimensions in a single tx
|
|
191
|
+
// with the height-preserving mediaSingle width adjustment.
|
|
192
|
+
width: null,
|
|
193
|
+
height: null
|
|
194
|
+
}));
|
|
195
|
+
// Re-create the selection so the floating toolbar picks up
|
|
196
|
+
// the updated node and renders the full set of controls.
|
|
197
|
+
tr.setSelection(NodeSelection.create(tr.doc, mediaSinglePos));
|
|
198
|
+
tr.setMeta('scrollIntoView', false);
|
|
199
|
+
this.view.dispatch(tr);
|
|
200
|
+
|
|
201
|
+
// Still register the state-change listener so upload completion is tracked
|
|
202
|
+
onMediaStateChanged(this.handleMediaState);
|
|
203
|
+
const isEndState = state => state.status && MEDIA_RESOLVED_STATES.includes(state.status);
|
|
204
|
+
|
|
205
|
+
// After the file finishes uploading/processing, trigger a dimension fetch.
|
|
206
|
+
// getRemoteDimensions may fail if called too early (isImageRepresentationReady
|
|
207
|
+
// returns false while processing), so we wait for the ready state first.
|
|
208
|
+
const triggerDimensionFetch = () => {
|
|
209
|
+
// Find the media node in the doc by id and create a temporary
|
|
210
|
+
// MediaNodeUpdater to fetch and apply dimensions
|
|
211
|
+
const {
|
|
212
|
+
state: editorState
|
|
213
|
+
} = this.view;
|
|
214
|
+
const {
|
|
215
|
+
mediaSingle: mediaSingleType
|
|
216
|
+
} = editorState.schema.nodes;
|
|
217
|
+
let mediaChildNode = null;
|
|
218
|
+
editorState.doc.descendants(node => {
|
|
219
|
+
if (mediaChildNode) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
if (node.type === mediaSingleType) {
|
|
223
|
+
const child = node.firstChild;
|
|
224
|
+
if (child && child.attrs.id === mediaState.id) {
|
|
225
|
+
mediaChildNode = child;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
});
|
|
230
|
+
if (mediaChildNode) {
|
|
231
|
+
var _this$pluginInjection3, _this$pluginInjection4, _this$pluginInjection5;
|
|
232
|
+
const updater = createMediaNodeUpdater({
|
|
233
|
+
view: this.view,
|
|
234
|
+
mediaProvider: this.mediaProvider ? Promise.resolve(this.mediaProvider) : undefined,
|
|
235
|
+
contextIdentifierProvider: this.contextIdentifierProvider ? Promise.resolve(this.contextIdentifierProvider) : undefined,
|
|
236
|
+
node: mediaChildNode,
|
|
237
|
+
isMediaSingle: true,
|
|
238
|
+
lineLength: (_this$pluginInjection3 = this.pluginInjectionApi) === null || _this$pluginInjection3 === void 0 ? void 0 : (_this$pluginInjection4 = _this$pluginInjection3.width) === null || _this$pluginInjection4 === void 0 ? void 0 : (_this$pluginInjection5 = _this$pluginInjection4.sharedState.currentState()) === null || _this$pluginInjection5 === void 0 ? void 0 : _this$pluginInjection5.lineLength
|
|
239
|
+
});
|
|
240
|
+
updater.getRemoteDimensions().then(dims => {
|
|
241
|
+
if (dims) {
|
|
242
|
+
updater.updateDimensions(dims);
|
|
243
|
+
}
|
|
244
|
+
}).catch(() => {
|
|
245
|
+
// Silently ignore — if dimensions can't be fetched (e.g. network error),
|
|
246
|
+
// the image will render at its current size without the height-preserving
|
|
247
|
+
// width adjustment. This is an acceptable degraded experience.
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
if (!isEndState(mediaStateWithContext)) {
|
|
252
|
+
const uploadingPromise = new Promise(resolve => {
|
|
253
|
+
onMediaStateChanged(newState => {
|
|
254
|
+
if (isEndState(newState)) {
|
|
255
|
+
resolve(newState);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
this.taskManager.addPendingTask(uploadingPromise, mediaStateWithContext.id).then(() => {
|
|
260
|
+
this.updateAndDispatch({
|
|
261
|
+
allUploadsFinished: true
|
|
262
|
+
});
|
|
263
|
+
triggerDimensionFetch();
|
|
264
|
+
});
|
|
265
|
+
} else {
|
|
266
|
+
// File is already in a resolved state — fetch dimensions immediately
|
|
267
|
+
triggerDimensionFetch();
|
|
268
|
+
}
|
|
269
|
+
const {
|
|
270
|
+
view
|
|
271
|
+
} = this;
|
|
272
|
+
if (!view.hasFocus()) {
|
|
273
|
+
view.focus();
|
|
274
|
+
}
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
134
277
|
switch (getMediaNodeInsertionType(state, this.mediaOptions, mediaStateWithContext.fileMimeType)) {
|
|
135
278
|
case 'inline':
|
|
136
279
|
insertMediaInlineNode(editorAnalyticsAPI)(this.view, mediaStateWithContext, collection, this.allowInlineImages, this.getInputMethod(pickerType), insertMediaVia);
|
|
137
280
|
break;
|
|
138
281
|
case 'block':
|
|
139
282
|
// read width state right before inserting to get up-to-date and define values
|
|
140
|
-
const widthPluginState = (_this$
|
|
283
|
+
const widthPluginState = (_this$pluginInjection6 = this.pluginInjectionApi) === null || _this$pluginInjection6 === void 0 ? void 0 : (_this$pluginInjection7 = _this$pluginInjection6.width) === null || _this$pluginInjection7 === void 0 ? void 0 : _this$pluginInjection7.sharedState.currentState();
|
|
141
284
|
insertMediaSingleNode(this.view, mediaStateWithContext, this.getInputMethod(pickerType), collection, this.mediaOptions && this.mediaOptions.alignLeftOnInsert, widthPluginState, editorAnalyticsAPI, this.onNodeInserted, insertMediaVia, this.mediaOptions && this.mediaOptions.allowPixelResizing);
|
|
142
285
|
break;
|
|
143
286
|
case 'group':
|
|
@@ -212,6 +355,70 @@ export class MediaPluginStateImplementation {
|
|
|
212
355
|
}
|
|
213
356
|
this.onPopupToggleCallback(true);
|
|
214
357
|
});
|
|
358
|
+
/**
|
|
359
|
+
* Opens the media picker in "replace" mode. The next file selected/uploaded
|
|
360
|
+
* will replace the currently selected mediaSingle node's media child in-place,
|
|
361
|
+
* preserving layout, width, and caption.
|
|
362
|
+
*
|
|
363
|
+
* The display height is computed and stored so that after the new file's intrinsic
|
|
364
|
+
* dimensions are fetched, the mediaSingle display width can be adjusted to maintain
|
|
365
|
+
* visual height stability rather than width stability.
|
|
366
|
+
*/
|
|
367
|
+
_defineProperty(this, "showMediaPickerForReplace", () => {
|
|
368
|
+
var _this$pluginInjection8, _this$pluginInjection9, _this$pluginInjection0, _this$pluginInjection1;
|
|
369
|
+
const {
|
|
370
|
+
state
|
|
371
|
+
} = this.view;
|
|
372
|
+
const {
|
|
373
|
+
mediaSingle
|
|
374
|
+
} = state.schema.nodes;
|
|
375
|
+
const {
|
|
376
|
+
selection
|
|
377
|
+
} = state;
|
|
378
|
+
|
|
379
|
+
// Only activate replace mode when a mediaSingle is selected
|
|
380
|
+
if (!(selection instanceof NodeSelection) || selection.node.type !== mediaSingle) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const mediaSingleNode = selection.node;
|
|
384
|
+
const mediaNode = mediaSingleNode.firstChild;
|
|
385
|
+
if (!mediaNode) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Store the current media node's id so insertFile can identify and replace it
|
|
390
|
+
this.replaceMediaFileId = mediaNode.attrs.id;
|
|
391
|
+
|
|
392
|
+
// Compute and store the current display height so we can preserve it after
|
|
393
|
+
// the new file's intrinsic dimensions are known.
|
|
394
|
+
// displayHeight = displayWidth * (intrinsicHeight / intrinsicWidth)
|
|
395
|
+
const widthAttr = mediaSingleNode.attrs.width;
|
|
396
|
+
const widthType = mediaSingleNode.attrs.widthType;
|
|
397
|
+
const intrinsicWidth = mediaNode.attrs.width;
|
|
398
|
+
const intrinsicHeight = mediaNode.attrs.height;
|
|
399
|
+
|
|
400
|
+
// Resolve actual pixel display width from mediaSingle attrs.
|
|
401
|
+
const lineLength = (_this$pluginInjection8 = (_this$pluginInjection9 = this.pluginInjectionApi) === null || _this$pluginInjection9 === void 0 ? void 0 : (_this$pluginInjection0 = _this$pluginInjection9.width) === null || _this$pluginInjection0 === void 0 ? void 0 : (_this$pluginInjection1 = _this$pluginInjection0.sharedState.currentState()) === null || _this$pluginInjection1 === void 0 ? void 0 : _this$pluginInjection1.lineLength) !== null && _this$pluginInjection8 !== void 0 ? _this$pluginInjection8 : 760;
|
|
402
|
+
let displayWidth = null;
|
|
403
|
+
if (widthAttr && widthType === 'pixel') {
|
|
404
|
+
displayWidth = widthAttr;
|
|
405
|
+
} else if (widthAttr) {
|
|
406
|
+
// Default widthType is 'percentage' — convert to pixels
|
|
407
|
+
displayWidth = widthAttr / 100 * lineLength;
|
|
408
|
+
} else if (intrinsicWidth) {
|
|
409
|
+
// No width set at all (never resized) — fall back to intrinsic width
|
|
410
|
+
displayWidth = intrinsicWidth;
|
|
411
|
+
}
|
|
412
|
+
if (displayWidth && intrinsicWidth && intrinsicHeight && intrinsicWidth > 0) {
|
|
413
|
+
this.replaceMediaTargetDisplayHeight = displayWidth * (intrinsicHeight / intrinsicWidth);
|
|
414
|
+
} else {
|
|
415
|
+
// Can't compute display height — fall back to preserving width
|
|
416
|
+
this.replaceMediaTargetDisplayHeight = null;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Finally, show the media picker
|
|
420
|
+
this.showMediaPicker();
|
|
421
|
+
});
|
|
215
422
|
_defineProperty(this, "setBrowseFn", browseFn => {
|
|
216
423
|
this.openMediaPickerBrowser = browseFn;
|
|
217
424
|
});
|
|
@@ -618,8 +825,8 @@ export class MediaPluginStateImplementation {
|
|
|
618
825
|
return;
|
|
619
826
|
}
|
|
620
827
|
get contextIdentifierProvider() {
|
|
621
|
-
var _this$
|
|
622
|
-
return (_this$
|
|
828
|
+
var _this$pluginInjection10, _this$pluginInjection11, _this$pluginInjection12;
|
|
829
|
+
return (_this$pluginInjection10 = this.pluginInjectionApi) === null || _this$pluginInjection10 === void 0 ? void 0 : (_this$pluginInjection11 = _this$pluginInjection10.contextIdentifier) === null || _this$pluginInjection11 === void 0 ? void 0 : (_this$pluginInjection12 = _this$pluginInjection11.sharedState.currentState()) === null || _this$pluginInjection12 === void 0 ? void 0 : _this$pluginInjection12.contextIdentifierProvider;
|
|
623
830
|
}
|
|
624
831
|
selectLastAddedMediaNode() {
|
|
625
832
|
var _this$mediaOptions5;
|
|
@@ -19,6 +19,7 @@ import ImageFullscreenIcon from '@atlaskit/icon/core/image-fullscreen';
|
|
|
19
19
|
import ImageInlineIcon from '@atlaskit/icon/core/image-inline';
|
|
20
20
|
import MaximizeIcon from '@atlaskit/icon/core/maximize';
|
|
21
21
|
import SmartLinkCardIcon from '@atlaskit/icon/core/smart-link-card';
|
|
22
|
+
import UploadIcon from '@atlaskit/icon/core/upload';
|
|
22
23
|
import { mediaFilmstripItemDOMSelector } from '@atlaskit/media-filmstrip';
|
|
23
24
|
import { messages } from '@atlaskit/media-ui';
|
|
24
25
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -895,6 +896,7 @@ export const floatingToolbar = (state, intl, options = {}, pluginInjectionApi) =
|
|
|
895
896
|
if (!mediaPluginState.isResizing && areToolbarFlagsEnabled(Boolean(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : pluginInjectionApi.toolbar))) {
|
|
896
897
|
var _pluginInjectionApi$a0, _pluginInjectionApi$a1, _pluginInjectionApi$a10;
|
|
897
898
|
updateToFullHeightSeparator(items);
|
|
899
|
+
const showReplaceOption = !isViewOnly && mediaPluginState.allowsUploads && expValEquals('platform_editor_inline_media_replacement', 'isEnabled', true) && selectedNodeType === mediaSingle;
|
|
898
900
|
const customOptions = [...getLinkingDropdownOptions(state, intl, mediaLinkingState, allowMediaInline && selectedNodeType && selectedNodeType === mediaInline, allowLinking, isViewOnly), ...getAltTextDropdownOption(state, intl.formatMessage, allowAltTextOnImages, selectedNodeType, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a0 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a0 === void 0 ? void 0 : _pluginInjectionApi$a0.actions), ...getResizeDropdownOption(options, state, intl.formatMessage, selectedNodeType)];
|
|
899
901
|
if (customOptions.length) {
|
|
900
902
|
customOptions.push({
|
|
@@ -911,7 +913,17 @@ export const floatingToolbar = (state, intl, options = {}, pluginInjectionApi) =
|
|
|
911
913
|
type: 'overflow-dropdown',
|
|
912
914
|
id: 'media',
|
|
913
915
|
testId: overflowDropdwonBtnTriggerTestId,
|
|
914
|
-
options: [...customOptions, {
|
|
916
|
+
options: [...customOptions, ...(showReplaceOption ? [{
|
|
917
|
+
title: intl.formatMessage(mediaAndEmbedToolbarMessages.replaceMedia),
|
|
918
|
+
onClick: () => {
|
|
919
|
+
mediaPluginState.showMediaPickerForReplace();
|
|
920
|
+
return true;
|
|
921
|
+
},
|
|
922
|
+
icon: /*#__PURE__*/React.createElement(UploadIcon, {
|
|
923
|
+
label: ""
|
|
924
|
+
}),
|
|
925
|
+
testId: 'media-replace-toolbar-button'
|
|
926
|
+
}] : []), {
|
|
915
927
|
title: intl === null || intl === void 0 ? void 0 : intl.formatMessage(commonMessages.copyToClipboard),
|
|
916
928
|
onClick: () => {
|
|
917
929
|
var _pluginInjectionApi$c0, _pluginInjectionApi$f5;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
export var hasPrivateAttrsChanged = function hasPrivateAttrsChanged(currentAttrs, newAttrs) {
|
|
2
|
-
return currentAttrs.__fileName !== newAttrs.__fileName || currentAttrs.__fileMimeType !== newAttrs.__fileMimeType || currentAttrs.__fileSize !== newAttrs.__fileSize || currentAttrs.__contextId !== newAttrs.__contextId
|
|
2
|
+
return currentAttrs.__fileName !== newAttrs.__fileName || currentAttrs.__fileMimeType !== newAttrs.__fileMimeType || currentAttrs.__fileSize !== newAttrs.__fileSize || currentAttrs.__contextId !== newAttrs.__contextId ||
|
|
3
|
+
// A changed id means the media source was replaced — always re-initialise
|
|
4
|
+
// the updater so getRemoteDimensions fetches dimensions for the new file.
|
|
5
|
+
// Only check when id is explicitly present on the new attrs (it's Partial).
|
|
6
|
+
'id' in newAttrs && currentAttrs.id !== newAttrs.id;
|
|
3
7
|
};
|
|
@@ -10,8 +10,10 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
10
10
|
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
11
11
|
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
12
12
|
import uuidV4 from 'uuid/v4';
|
|
13
|
+
import { SetAttrsStep } from '@atlaskit/adf-schema/steps';
|
|
13
14
|
import { ACTION, ACTION_SUBJECT, EVENT_TYPE } from '@atlaskit/editor-common/analytics';
|
|
14
15
|
import { DEFAULT_IMAGE_HEIGHT, DEFAULT_IMAGE_WIDTH } from '@atlaskit/editor-common/media-single';
|
|
16
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
15
17
|
import { getAttrsFromUrl, isImageRepresentationReady, isMediaBlobUrl as _isMediaBlobUrl } from '@atlaskit/media-client';
|
|
16
18
|
import { getMediaClient } from '@atlaskit/media-client-react';
|
|
17
19
|
import { getClientIdForFile } from '@atlaskit/media-common';
|
|
@@ -20,6 +22,7 @@ import { replaceExternalMedia, updateCurrentMediaNodeAttrs, updateMediaNodeAttrs
|
|
|
20
22
|
import { stateKey as mediaStateKey } from '../pm-plugins/plugin-key';
|
|
21
23
|
import { batchMediaNodeAttrsUpdate } from '../pm-plugins/utils/batchMediaNodeAttrs';
|
|
22
24
|
import { getIdentifier } from '../pm-plugins/utils/media-common';
|
|
25
|
+
import { computeReplacementDisplayWidth } from './nodeviewHelpers';
|
|
23
26
|
var isMediaTypeSupported = function isMediaTypeSupported(type) {
|
|
24
27
|
if (type) {
|
|
25
28
|
return ['image', 'file'].includes(type);
|
|
@@ -318,7 +321,73 @@ export var MediaNodeUpdater = /*#__PURE__*/function () {
|
|
|
318
321
|
return attrs.__contextId || null;
|
|
319
322
|
});
|
|
320
323
|
_defineProperty(this, "updateDimensions", function (dimensions) {
|
|
321
|
-
|
|
324
|
+
var view = _this.props.view;
|
|
325
|
+
var mediaPluginState = mediaStateKey.getState(view.state);
|
|
326
|
+
var targetDisplayHeight = mediaPluginState === null || mediaPluginState === void 0 ? void 0 : mediaPluginState.replaceMediaTargetDisplayHeight;
|
|
327
|
+
if (targetDisplayHeight !== null && targetDisplayHeight !== undefined && dimensions.width > 0) {
|
|
328
|
+
var _this$props$lineLengt, _mediaSingleNode$attr, _mediaSingleNode;
|
|
329
|
+
// Replace mode: combine intrinsic dimension update on the media node AND
|
|
330
|
+
// display width update on the mediaSingle into a single transaction so they
|
|
331
|
+
// are never out of sync and don't cause two separate renders/layout shifts.
|
|
332
|
+
|
|
333
|
+
// Clear the stored target height — this is a one-shot adjustment
|
|
334
|
+
if (mediaPluginState) {
|
|
335
|
+
mediaPluginState.replaceMediaTargetDisplayHeight = null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Clamp to the layout's maximum width so the image never overflows its container.
|
|
339
|
+
var lineLength = (_this$props$lineLengt = _this.props.lineLength) !== null && _this$props$lineLengt !== void 0 ? _this$props$lineLengt : 760;
|
|
340
|
+
var state = view.state;
|
|
341
|
+
var mediaSingle = state.schema.nodes.mediaSingle;
|
|
342
|
+
// Typed explicitly because TypeScript can't track mutations inside
|
|
343
|
+
// the descendants callback closure and would narrow these to `never`.
|
|
344
|
+
var mediaSinglePos = null;
|
|
345
|
+
var mediaSingleNode = null;
|
|
346
|
+
var mediaPos = null;
|
|
347
|
+
state.doc.descendants(function (node, pos) {
|
|
348
|
+
if (mediaSinglePos !== null) {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
if (node.type === mediaSingle) {
|
|
352
|
+
var mediaChild = node.firstChild;
|
|
353
|
+
if (mediaChild && mediaChild.attrs.id === dimensions.id) {
|
|
354
|
+
mediaSinglePos = pos;
|
|
355
|
+
mediaSingleNode = node;
|
|
356
|
+
mediaPos = pos + 1;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return true;
|
|
360
|
+
});
|
|
361
|
+
var layout = (_mediaSingleNode$attr = (_mediaSingleNode = mediaSingleNode) === null || _mediaSingleNode === void 0 || (_mediaSingleNode = _mediaSingleNode.attrs) === null || _mediaSingleNode === void 0 ? void 0 : _mediaSingleNode.layout) !== null && _mediaSingleNode$attr !== void 0 ? _mediaSingleNode$attr : 'center';
|
|
362
|
+
var newDisplayWidth = computeReplacementDisplayWidth(targetDisplayHeight, dimensions.width, dimensions.height, layout, lineLength);
|
|
363
|
+
if (mediaSinglePos !== null && mediaSingleNode !== null && mediaPos !== null) {
|
|
364
|
+
var tr = state.tr;
|
|
365
|
+
|
|
366
|
+
// Update intrinsic dimensions on the media child node
|
|
367
|
+
tr.step(new SetAttrsStep(mediaPos, {
|
|
368
|
+
height: dimensions.height,
|
|
369
|
+
width: dimensions.width
|
|
370
|
+
}));
|
|
371
|
+
|
|
372
|
+
// Update display width on the mediaSingle parent
|
|
373
|
+
tr.setNodeMarkup(mediaSinglePos, undefined, _objectSpread(_objectSpread({}, mediaSingleNode.attrs), {}, {
|
|
374
|
+
width: Math.round(newDisplayWidth),
|
|
375
|
+
widthType: 'pixel'
|
|
376
|
+
}));
|
|
377
|
+
|
|
378
|
+
// Re-create the NodeSelection so the floating toolbar picks up
|
|
379
|
+
// the updated node and renders the full set of controls.
|
|
380
|
+
if (state.selection instanceof NodeSelection) {
|
|
381
|
+
tr.setSelection(NodeSelection.create(tr.doc, mediaSinglePos));
|
|
382
|
+
}
|
|
383
|
+
tr.setMeta('scrollIntoView', false);
|
|
384
|
+
view.dispatch(tr);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Normal (non-replace) path: use the existing batched update mechanism
|
|
390
|
+
batchMediaNodeAttrsUpdate(view, {
|
|
322
391
|
id: dimensions.id,
|
|
323
392
|
nextAttributes: {
|
|
324
393
|
height: dimensions.height,
|
|
@@ -145,7 +145,8 @@ var useMediaAsyncOperations = function useMediaAsyncOperations(_ref3) {
|
|
|
145
145
|
var mediaNode = _ref3.mediaNode,
|
|
146
146
|
mediaNodeUpdater = _ref3.mediaNodeUpdater,
|
|
147
147
|
addPendingTask = _ref3.addPendingTask,
|
|
148
|
-
getPos = _ref3.getPos
|
|
148
|
+
getPos = _ref3.getPos,
|
|
149
|
+
mediaChildNodeId = _ref3.mediaChildNodeId;
|
|
149
150
|
React.useEffect(function () {
|
|
150
151
|
if (!mediaNodeUpdater) {
|
|
151
152
|
return;
|
|
@@ -162,7 +163,11 @@ var useMediaAsyncOperations = function useMediaAsyncOperations(_ref3) {
|
|
|
162
163
|
mediaNode: mediaNode,
|
|
163
164
|
addPendingTask: addPendingTask
|
|
164
165
|
});
|
|
165
|
-
|
|
166
|
+
// mediaChildNodeId is included so this effect re-runs when the media source
|
|
167
|
+
// is replaced (id changes), ensuring getRemoteDimensions fires for the new file
|
|
168
|
+
// with up-to-date updater props after setProps has been called.
|
|
169
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
170
|
+
}, [mediaNode, addPendingTask, mediaNodeUpdater, getPos, mediaChildNodeId]);
|
|
166
171
|
};
|
|
167
172
|
var noop = function noop() {};
|
|
168
173
|
|
|
@@ -281,7 +286,7 @@ var useUpdateSizeCallback = function useUpdateSizeCallback(_ref5) {
|
|
|
281
286
|
*/
|
|
282
287
|
var FALLBACK_MOST_COMMON_WIDTH = 760;
|
|
283
288
|
export var MediaSingleNodeNext = function MediaSingleNodeNext(mediaSingleNodeNextProps) {
|
|
284
|
-
var _pluginInjectionApi$m, _mediaNode$
|
|
289
|
+
var _mediaNode$firstChild, _pluginInjectionApi$m, _mediaNode$firstChild2;
|
|
285
290
|
var selected = mediaSingleNodeNextProps.selected,
|
|
286
291
|
getPos = mediaSingleNodeNextProps.getPos,
|
|
287
292
|
nextMediaNode = mediaSingleNodeNextProps.node,
|
|
@@ -328,7 +333,8 @@ export var MediaSingleNodeNext = function MediaSingleNodeNext(mediaSingleNodeNex
|
|
|
328
333
|
mediaNodeUpdater: mediaNodeUpdater,
|
|
329
334
|
getPos: getPos,
|
|
330
335
|
mediaNode: mediaNode,
|
|
331
|
-
addPendingTask: addPendingTask || noop
|
|
336
|
+
addPendingTask: addPendingTask || noop,
|
|
337
|
+
mediaChildNodeId: (_mediaNode$firstChild = mediaNode.firstChild) === null || _mediaNode$firstChild === void 0 ? void 0 : _mediaNode$firstChild.attrs.id
|
|
332
338
|
});
|
|
333
339
|
React.useLayoutEffect(function () {
|
|
334
340
|
mountedRef.current = true;
|
|
@@ -423,7 +429,7 @@ export var MediaSingleNodeNext = function MediaSingleNodeNext(mediaSingleNodeNex
|
|
|
423
429
|
}, [mediaSingleWidthAttribute, widthType, width, layout, contentWidthForLegacyExperience, containerWidth]);
|
|
424
430
|
var currentMaxWidth = isSelected ? pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$m = pluginInjectionApi.media) === null || _pluginInjectionApi$m === void 0 || (_pluginInjectionApi$m = _pluginInjectionApi$m.sharedState.currentState()) === null || _pluginInjectionApi$m === void 0 ? void 0 : _pluginInjectionApi$m.currentMaxWidth : undefined;
|
|
425
431
|
var contentWidth = currentMaxWidth || lineLength;
|
|
426
|
-
var isCurrentNodeDrafting = Boolean(isDrafting && targetNodeId === (mediaNode === null || mediaNode === void 0 || (_mediaNode$
|
|
432
|
+
var isCurrentNodeDrafting = Boolean(isDrafting && targetNodeId === (mediaNode === null || mediaNode === void 0 || (_mediaNode$firstChild2 = mediaNode.firstChild) === null || _mediaNode$firstChild2 === void 0 ? void 0 : _mediaNode$firstChild2.attrs.id));
|
|
427
433
|
var mediaSingleWrapperRef = /*#__PURE__*/React.createRef();
|
|
428
434
|
var captionPlaceHolderRef = /*#__PURE__*/React.createRef();
|
|
429
435
|
var browser = getBrowserInfo();
|