@atlaskit/editor-common 118.10.1 → 118.10.3

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @atlaskit/editor-common
2
2
 
3
+ ## 118.10.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`2ba69c4d87919`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/2ba69c4d87919) -
8
+ Add an experiment-gated empty frame placeholder for multi-bodied extensions under
9
+ confluence_native_tabs_m15.
10
+
11
+ ## 118.10.2
12
+
13
+ ### Patch Changes
14
+
15
+ - [`1d1cb3e25a787`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1d1cb3e25a787) -
16
+ Fix BE-streaming Review moment data loss and chimera diffs: derive coarse review segments as
17
+ closed, whole top-level node slices (mapped consistently between the pre-edit and post-edit doc),
18
+ filter out position-neutral phantom collab touches, and fall back to a safe add-only segment when
19
+ a change relocates content. Behind the platform_editor_backend_review_moment_agent_types gate.
20
+ - Updated dependencies
21
+
3
22
  ## 118.10.1
4
23
 
5
24
  ### Patch Changes
@@ -13,10 +13,21 @@ exports.AGENT_REMOTE_EDIT_REVIEW_DATA = void 0;
13
13
  * plugins already depend on.
14
14
  *
15
15
  * Stamped whenever a received remote-step batch contains agent-authored steps.
16
- * Consumed by `aiSessionContextPlugin.apply()`,
17
- * which appends coarse `aiContentPositions` entriesexactly like the in-editor
18
- * (FE) streaming path's `AI_FINAL_STREAMING_TRANSFORMATION_DATA`, so the whole
19
- * downstream Review moment pipeline (merge segment diff undo/redo → accept)
20
- * is reused unchanged.
16
+ *
17
+ * The batch is reduced to COARSE segments one per edited top-level region — in
18
+ * exactly the shape the AI plugin already stores in `aiContentPositions` for the
19
+ * FE (`buildCommitTransaction`) path: `[startPos, endPos]` in the live doc plus a
20
+ * closed `originalSlice` / `newSlice` pair. The AI plugin appends these verbatim,
21
+ * then the Post Stream Review screen refines them identically to FE
22
+ * (`calculateTopLevelNodeSegments`, and `calculateDiffSegments` when the
23
+ * diff-based-segmenting gate is on). Producing coarse segments here (rather than
24
+ * fine-grained diffs) preserves the screen's two-layer contract; producing them
25
+ * as CLOSED, whole-top-level-node slices avoids the boundary-bleed / open-slice
26
+ * data-loss hazards of the earlier hand-rolled per-step slicing.
21
27
  */
22
- var AGENT_REMOTE_EDIT_REVIEW_DATA = exports.AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
28
+ var AGENT_REMOTE_EDIT_REVIEW_DATA = exports.AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
29
+
30
+ /**
31
+ * One coarse reviewable segment for a single edited top-level region, matching the
32
+ * `aiContentPositions` entry shape the AI plugin stores for FE streaming.
33
+ */
@@ -15,9 +15,12 @@ var _react = _interopRequireWildcard(require("react"));
15
15
  var _react2 = require("@emotion/react");
16
16
  var _bindEventListener = require("bind-event-listener");
17
17
  var _classnames = _interopRequireDefault(require("classnames"));
18
+ var _reactIntl = require("react-intl");
18
19
  var _file = _interopRequireDefault(require("@atlaskit/icon/core/file"));
20
+ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
19
21
  var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
20
22
  var _hooks = require("../../hooks");
23
+ var _placeholderText = require("../../messages/placeholder-text");
21
24
  var _MultiBodiedExtension = require("../../ui/MultiBodiedExtension");
22
25
  var _utils = require("../../utils");
23
26
  var _Lozenge = _interopRequireDefault(require("../Extension/Lozenge"));
@@ -45,6 +48,20 @@ var getContainerCssExtendedStyles = function getContainerCssExtendedStyles(activ
45
48
  showMacroInteractionDesignUpdates && _MultiBodiedExtension.removeMarginsAndBorder)))
46
49
  );
47
50
  };
51
+
52
+ // Renders a visual placeholder when the active frame contains a single empty paragraph.
53
+ var getEmptyFramePlaceholderStyles = function getEmptyFramePlaceholderStyles(activeChildIndex, placeholderText) {
54
+ return (0, _react2.css)((0, _defineProperty2.default)({}, "& .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true']:nth-of-type(".concat(activeChildIndex + 1
55
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
56
+ , ") > p:only-child:has(.ProseMirror-trailingBreak:only-child)::before"), {
57
+ color: "var(--ds-text-subtlest, #6B6E76)",
58
+ // JSON.stringify produces a quoted and escaped CSS string.
59
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
60
+ content: placeholderText,
61
+ pointerEvents: 'none',
62
+ position: 'absolute'
63
+ }));
64
+ };
48
65
  var imageStyles = (0, _react2.css)({
49
66
  maxHeight: '24px',
50
67
  maxWidth: '24px'
@@ -189,6 +206,8 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
189
206
  node: node,
190
207
  type: 'image'
191
208
  });
209
+ var _useIntl = (0, _reactIntl.useIntl)(),
210
+ formatMessage = _useIntl.formatMessage;
192
211
  var _useState3 = (0, _react.useState)(0),
193
212
  _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
194
213
  activeChildIndex = _useState4[0],
@@ -242,6 +261,10 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
242
261
  mbeWrapperStyles = breakoutStyles;
243
262
  }
244
263
  var shouldUseUpdatedChrome = (0, _expValEquals.expValEquals)('confluence_native_tabs_experiment', 'isEnabled', true);
264
+ var shouldShowEmptyFramePlaceholder = (0, _isExperimentEnabled.isExperimentEnabled)('confluence_native_tabs_m15');
265
+ var emptyFramePlaceholderText = _react.default.useMemo(function () {
266
+ return JSON.stringify(formatMessage(_placeholderText.placeholderTextMessages.multiBodiedExtensionEmptyFramePlaceholderText));
267
+ }, [formatMessage]);
245
268
  var isSelectionInsideMultiBodiedExtension = useIsSelectionInsideNode(editorView, node, getPos, shouldUseUpdatedChrome && !isLivePageViewMode);
246
269
  var isMultiBodiedExtensionActive = isNodeSelected || isSelectionInsideMultiBodiedExtension;
247
270
  var shouldShowChromeOnInteraction = isNodeHovered || isMultiBodiedExtensionActive;
@@ -315,10 +338,10 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
315
338
  "data-testid": "multiBodiedExtension--overlay"
316
339
  }), getWrapperTitleContent(imageData, title, showMacroInteractionDesignUpdates), (0, _react2.jsx)("div", {
317
340
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
318
- className: containerClassNames
319
- // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
320
- ,
321
- css: getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates),
341
+ className: containerClassNames,
342
+ css: [/* eslint-disable @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 */
343
+ getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates), shouldShowEmptyFramePlaceholder && getEmptyFramePlaceholderStyles(activeChildIndex, emptyFramePlaceholderText)
344
+ /* eslint-enable @atlaskit/design-system/consistent-css-prop-usage */],
322
345
  "data-testid": "multiBodiedExtension--container",
323
346
  "data-multiBodiedExtension-container": true,
324
347
  "data-active-child-index": activeChildIndex
@@ -50,5 +50,10 @@ var placeholderTextMessages = exports.placeholderTextMessages = (0, _reactIntl.d
50
50
  id: 'fabric.editor.sourceSyncBlockPlaceholderText',
51
51
  defaultMessage: 'Add content you want to reuse. Copy and paste this block to sync in other locations.',
52
52
  description: 'Placeholder text shown inside an empty source sync block, prompting users to add reusable content that can be synced across multiple locations.'
53
+ },
54
+ multiBodiedExtensionEmptyFramePlaceholderText: {
55
+ id: 'fabric.editor.multiBodiedExtensionEmptyFramePlaceholderText',
56
+ defaultMessage: 'Type to add content or press / to insert elements',
57
+ description: 'Placeholder text shown inside an empty multi-bodied extension frame, prompting users to type content or use slash commands to insert elements.'
53
58
  }
54
59
  });
@@ -28,7 +28,7 @@ var NETWORK_FAILURE_REGEX = /^network failure/i;
28
28
  var RESIZE_OBSERVER_LOOP_REGEX = /ResizeObserver loop completed with undelivered notifications/;
29
29
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
30
30
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
31
- var packageVersion = "118.10.0";
31
+ var packageVersion = "118.10.2";
32
32
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
33
33
  // Remove URL as it has UGC
34
34
  // Ignored via go/ees007
@@ -24,7 +24,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
24
24
  * @jsx jsx
25
25
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
26
26
  var packageName = "@atlaskit/editor-common";
27
- var packageVersion = "118.10.0";
27
+ var packageVersion = "118.10.2";
28
28
  var halfFocusRing = 1;
29
29
  var dropOffset = '0, 8';
30
30
  var fadeIn = (0, _react2.keyframes)({
@@ -7,10 +7,21 @@
7
7
  * plugins already depend on.
8
8
  *
9
9
  * Stamped whenever a received remote-step batch contains agent-authored steps.
10
- * Consumed by `aiSessionContextPlugin.apply()`,
11
- * which appends coarse `aiContentPositions` entriesexactly like the in-editor
12
- * (FE) streaming path's `AI_FINAL_STREAMING_TRANSFORMATION_DATA`, so the whole
13
- * downstream Review moment pipeline (merge segment diff undo/redo → accept)
14
- * is reused unchanged.
10
+ *
11
+ * The batch is reduced to COARSE segments one per edited top-level region — in
12
+ * exactly the shape the AI plugin already stores in `aiContentPositions` for the
13
+ * FE (`buildCommitTransaction`) path: `[startPos, endPos]` in the live doc plus a
14
+ * closed `originalSlice` / `newSlice` pair. The AI plugin appends these verbatim,
15
+ * then the Post Stream Review screen refines them identically to FE
16
+ * (`calculateTopLevelNodeSegments`, and `calculateDiffSegments` when the
17
+ * diff-based-segmenting gate is on). Producing coarse segments here (rather than
18
+ * fine-grained diffs) preserves the screen's two-layer contract; producing them
19
+ * as CLOSED, whole-top-level-node slices avoids the boundary-bleed / open-slice
20
+ * data-loss hazards of the earlier hand-rolled per-step slicing.
15
21
  */
16
- export const AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
22
+ export const AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
23
+
24
+ /**
25
+ * One coarse reviewable segment for a single edited top-level region, matching the
26
+ * `aiContentPositions` entry shape the AI plugin stores for FE streaming.
27
+ */
@@ -11,9 +11,12 @@ import React, { Fragment, useEffect, useRef, useState } from 'react';
11
11
  import { css, jsx } from '@emotion/react';
12
12
  import { bind } from 'bind-event-listener';
13
13
  import classnames from 'classnames';
14
+ import { useIntl } from 'react-intl';
14
15
  import EditorFileIcon from '@atlaskit/icon/core/file';
16
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
15
17
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
16
18
  import { useSharedPluginStateWithSelector } from '../../hooks';
19
+ import { placeholderTextMessages } from '../../messages/placeholder-text';
17
20
  import { removeMarginsAndBorder, sharedMultiBodiedExtensionStyles } from '../../ui/MultiBodiedExtension';
18
21
  import { calculateBreakoutStyles, getExtensionLozengeData } from '../../utils';
19
22
  import ExtensionLozenge from '../Extension/Lozenge';
@@ -33,6 +36,21 @@ css(sharedMultiBodiedExtensionStyles.mbeExtensionContainer, {
33
36
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values, @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
34
37
  showMacroInteractionDesignUpdates && removeMarginsAndBorder)
35
38
  });
39
+
40
+ // Renders a visual placeholder when the active frame contains a single empty paragraph.
41
+ const getEmptyFramePlaceholderStyles = (activeChildIndex, placeholderText) => css({
42
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
43
+ [`& .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true']:nth-of-type(${activeChildIndex + 1
44
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
45
+ }) > p:only-child:has(.ProseMirror-trailingBreak:only-child)::before`]: {
46
+ color: "var(--ds-text-subtlest, #6B6E76)",
47
+ // JSON.stringify produces a quoted and escaped CSS string.
48
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
49
+ content: placeholderText,
50
+ pointerEvents: 'none',
51
+ position: 'absolute'
52
+ }
53
+ });
36
54
  const imageStyles = css({
37
55
  maxHeight: '24px',
38
56
  maxWidth: '24px'
@@ -177,6 +195,9 @@ const MultiBodiedExtensionWithWidth = ({
177
195
  node,
178
196
  type: 'image'
179
197
  });
198
+ const {
199
+ formatMessage
200
+ } = useIntl();
180
201
  const [activeChildIndex, setActiveChildIndex] = useState(0);
181
202
  // Adding to avoid aliasing `this` for the callbacks
182
203
  const updateActiveChild = React.useCallback(index => {
@@ -228,6 +249,8 @@ const MultiBodiedExtensionWithWidth = ({
228
249
  mbeWrapperStyles = breakoutStyles;
229
250
  }
230
251
  const shouldUseUpdatedChrome = expValEquals('confluence_native_tabs_experiment', 'isEnabled', true);
252
+ const shouldShowEmptyFramePlaceholder = isExperimentEnabled('confluence_native_tabs_m15');
253
+ const emptyFramePlaceholderText = React.useMemo(() => JSON.stringify(formatMessage(placeholderTextMessages.multiBodiedExtensionEmptyFramePlaceholderText)), [formatMessage]);
231
254
  const isSelectionInsideMultiBodiedExtension = useIsSelectionInsideNode(editorView, node, getPos, shouldUseUpdatedChrome && !isLivePageViewMode);
232
255
  const isMultiBodiedExtensionActive = isNodeSelected || isSelectionInsideMultiBodiedExtension;
233
256
  const shouldShowChromeOnInteraction = isNodeHovered || isMultiBodiedExtensionActive;
@@ -297,10 +320,10 @@ const MultiBodiedExtensionWithWidth = ({
297
320
  "data-testid": "multiBodiedExtension--overlay"
298
321
  }), getWrapperTitleContent(imageData, title, showMacroInteractionDesignUpdates), jsx("div", {
299
322
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
300
- className: containerClassNames
301
- // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
302
- ,
303
- css: getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates),
323
+ className: containerClassNames,
324
+ css: [/* eslint-disable @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 */
325
+ getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates), shouldShowEmptyFramePlaceholder && getEmptyFramePlaceholderStyles(activeChildIndex, emptyFramePlaceholderText)
326
+ /* eslint-enable @atlaskit/design-system/consistent-css-prop-usage */],
304
327
  "data-testid": "multiBodiedExtension--container",
305
328
  "data-multiBodiedExtension-container": true,
306
329
  "data-active-child-index": activeChildIndex
@@ -44,5 +44,10 @@ export const placeholderTextMessages = defineMessages({
44
44
  id: 'fabric.editor.sourceSyncBlockPlaceholderText',
45
45
  defaultMessage: 'Add content you want to reuse. Copy and paste this block to sync in other locations.',
46
46
  description: 'Placeholder text shown inside an empty source sync block, prompting users to add reusable content that can be synced across multiple locations.'
47
+ },
48
+ multiBodiedExtensionEmptyFramePlaceholderText: {
49
+ id: 'fabric.editor.multiBodiedExtensionEmptyFramePlaceholderText',
50
+ defaultMessage: 'Type to add content or press / to insert elements',
51
+ description: 'Placeholder text shown inside an empty multi-bodied extension frame, prompting users to type content or use slash commands to insert elements.'
47
52
  }
48
53
  });
@@ -14,7 +14,7 @@ const NETWORK_FAILURE_REGEX = /^network failure/i;
14
14
  const RESIZE_OBSERVER_LOOP_REGEX = /ResizeObserver loop completed with undelivered notifications/;
15
15
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
16
16
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
17
- const packageVersion = "118.10.0";
17
+ const packageVersion = "118.10.2";
18
18
  const sanitiseSentryEvents = (data, _hint) => {
19
19
  // Remove URL as it has UGC
20
20
  // Ignored via go/ees007
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import { fg } from '@atlaskit/platform-feature-flags';
15
15
  import Layer from '../Layer';
16
16
  const packageName = "@atlaskit/editor-common";
17
- const packageVersion = "118.10.0";
17
+ const packageVersion = "118.10.2";
18
18
  const halfFocusRing = 1;
19
19
  const dropOffset = '0, 8';
20
20
  const fadeIn = keyframes({
@@ -7,10 +7,21 @@
7
7
  * plugins already depend on.
8
8
  *
9
9
  * Stamped whenever a received remote-step batch contains agent-authored steps.
10
- * Consumed by `aiSessionContextPlugin.apply()`,
11
- * which appends coarse `aiContentPositions` entriesexactly like the in-editor
12
- * (FE) streaming path's `AI_FINAL_STREAMING_TRANSFORMATION_DATA`, so the whole
13
- * downstream Review moment pipeline (merge segment diff undo/redo → accept)
14
- * is reused unchanged.
10
+ *
11
+ * The batch is reduced to COARSE segments one per edited top-level region — in
12
+ * exactly the shape the AI plugin already stores in `aiContentPositions` for the
13
+ * FE (`buildCommitTransaction`) path: `[startPos, endPos]` in the live doc plus a
14
+ * closed `originalSlice` / `newSlice` pair. The AI plugin appends these verbatim,
15
+ * then the Post Stream Review screen refines them identically to FE
16
+ * (`calculateTopLevelNodeSegments`, and `calculateDiffSegments` when the
17
+ * diff-based-segmenting gate is on). Producing coarse segments here (rather than
18
+ * fine-grained diffs) preserves the screen's two-layer contract; producing them
19
+ * as CLOSED, whole-top-level-node slices avoids the boundary-bleed / open-slice
20
+ * data-loss hazards of the earlier hand-rolled per-step slicing.
15
21
  */
16
- export var AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
22
+ export var AGENT_REMOTE_EDIT_REVIEW_DATA = 'agentRemoteEditReviewData';
23
+
24
+ /**
25
+ * One coarse reviewable segment for a single edited top-level region, matching the
26
+ * `aiContentPositions` entry shape the AI plugin stores for FE streaming.
27
+ */
@@ -16,9 +16,12 @@ import React, { Fragment, useEffect, useRef, useState } from 'react';
16
16
  import { css, jsx } from '@emotion/react';
17
17
  import { bind } from 'bind-event-listener';
18
18
  import classnames from 'classnames';
19
+ import { useIntl } from 'react-intl';
19
20
  import EditorFileIcon from '@atlaskit/icon/core/file';
21
+ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
20
22
  import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
21
23
  import { useSharedPluginStateWithSelector } from '../../hooks';
24
+ import { placeholderTextMessages } from '../../messages/placeholder-text';
22
25
  import { removeMarginsAndBorder, sharedMultiBodiedExtensionStyles } from '../../ui/MultiBodiedExtension';
23
26
  import { calculateBreakoutStyles, getExtensionLozengeData } from '../../utils';
24
27
  import ExtensionLozenge from '../Extension/Lozenge';
@@ -38,6 +41,20 @@ var getContainerCssExtendedStyles = function getContainerCssExtendedStyles(activ
38
41
  showMacroInteractionDesignUpdates && removeMarginsAndBorder)))
39
42
  );
40
43
  };
44
+
45
+ // Renders a visual placeholder when the active frame contains a single empty paragraph.
46
+ var getEmptyFramePlaceholderStyles = function getEmptyFramePlaceholderStyles(activeChildIndex, placeholderText) {
47
+ return css(_defineProperty({}, "& .multiBodiedExtension-content-dom-wrapper > [data-extension-frame='true']:nth-of-type(".concat(activeChildIndex + 1
48
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
49
+ , ") > p:only-child:has(.ProseMirror-trailingBreak:only-child)::before"), {
50
+ color: "var(--ds-text-subtlest, #6B6E76)",
51
+ // JSON.stringify produces a quoted and escaped CSS string.
52
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
53
+ content: placeholderText,
54
+ pointerEvents: 'none',
55
+ position: 'absolute'
56
+ }));
57
+ };
41
58
  var imageStyles = css({
42
59
  maxHeight: '24px',
43
60
  maxWidth: '24px'
@@ -182,6 +199,8 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
182
199
  node: node,
183
200
  type: 'image'
184
201
  });
202
+ var _useIntl = useIntl(),
203
+ formatMessage = _useIntl.formatMessage;
185
204
  var _useState3 = useState(0),
186
205
  _useState4 = _slicedToArray(_useState3, 2),
187
206
  activeChildIndex = _useState4[0],
@@ -235,6 +254,10 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
235
254
  mbeWrapperStyles = breakoutStyles;
236
255
  }
237
256
  var shouldUseUpdatedChrome = expValEquals('confluence_native_tabs_experiment', 'isEnabled', true);
257
+ var shouldShowEmptyFramePlaceholder = isExperimentEnabled('confluence_native_tabs_m15');
258
+ var emptyFramePlaceholderText = React.useMemo(function () {
259
+ return JSON.stringify(formatMessage(placeholderTextMessages.multiBodiedExtensionEmptyFramePlaceholderText));
260
+ }, [formatMessage]);
238
261
  var isSelectionInsideMultiBodiedExtension = useIsSelectionInsideNode(editorView, node, getPos, shouldUseUpdatedChrome && !isLivePageViewMode);
239
262
  var isMultiBodiedExtensionActive = isNodeSelected || isSelectionInsideMultiBodiedExtension;
240
263
  var shouldShowChromeOnInteraction = isNodeHovered || isMultiBodiedExtensionActive;
@@ -308,10 +331,10 @@ var MultiBodiedExtensionWithWidth = function MultiBodiedExtensionWithWidth(_ref2
308
331
  "data-testid": "multiBodiedExtension--overlay"
309
332
  }), getWrapperTitleContent(imageData, title, showMacroInteractionDesignUpdates), jsx("div", {
310
333
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
311
- className: containerClassNames
312
- // eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
313
- ,
314
- css: getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates),
334
+ className: containerClassNames,
335
+ css: [/* eslint-disable @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 */
336
+ getContainerCssExtendedStyles(activeChildIndex, showMacroInteractionDesignUpdates), shouldShowEmptyFramePlaceholder && getEmptyFramePlaceholderStyles(activeChildIndex, emptyFramePlaceholderText)
337
+ /* eslint-enable @atlaskit/design-system/consistent-css-prop-usage */],
315
338
  "data-testid": "multiBodiedExtension--container",
316
339
  "data-multiBodiedExtension-container": true,
317
340
  "data-active-child-index": activeChildIndex
@@ -44,5 +44,10 @@ export var placeholderTextMessages = defineMessages({
44
44
  id: 'fabric.editor.sourceSyncBlockPlaceholderText',
45
45
  defaultMessage: 'Add content you want to reuse. Copy and paste this block to sync in other locations.',
46
46
  description: 'Placeholder text shown inside an empty source sync block, prompting users to add reusable content that can be synced across multiple locations.'
47
+ },
48
+ multiBodiedExtensionEmptyFramePlaceholderText: {
49
+ id: 'fabric.editor.multiBodiedExtensionEmptyFramePlaceholderText',
50
+ defaultMessage: 'Type to add content or press / to insert elements',
51
+ description: 'Placeholder text shown inside an empty multi-bodied extension frame, prompting users to type content or use slash commands to insert elements.'
47
52
  }
48
53
  });
@@ -20,7 +20,7 @@ var NETWORK_FAILURE_REGEX = /^network failure/i;
20
20
  var RESIZE_OBSERVER_LOOP_REGEX = /ResizeObserver loop completed with undelivered notifications/;
21
21
  var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
22
22
  var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
23
- var packageVersion = "118.10.0";
23
+ var packageVersion = "118.10.2";
24
24
  var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
25
25
  // Remove URL as it has UGC
26
26
  // Ignored via go/ees007
@@ -21,7 +21,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
21
21
  import { fg } from '@atlaskit/platform-feature-flags';
22
22
  import Layer from '../Layer';
23
23
  var packageName = "@atlaskit/editor-common";
24
- var packageVersion = "118.10.0";
24
+ var packageVersion = "118.10.2";
25
25
  var halfFocusRing = 1;
26
26
  var dropOffset = '0, 8';
27
27
  var fadeIn = keyframes({
@@ -8,26 +8,39 @@ import type { Slice } from '@atlaskit/editor-prosemirror/model';
8
8
  * plugins already depend on.
9
9
  *
10
10
  * Stamped whenever a received remote-step batch contains agent-authored steps.
11
- * Consumed by `aiSessionContextPlugin.apply()`,
12
- * which appends coarse `aiContentPositions` entriesexactly like the in-editor
13
- * (FE) streaming path's `AI_FINAL_STREAMING_TRANSFORMATION_DATA`, so the whole
14
- * downstream Review moment pipeline (merge segment diff undo/redo → accept)
15
- * is reused unchanged.
11
+ *
12
+ * The batch is reduced to COARSE segments one per edited top-level region — in
13
+ * exactly the shape the AI plugin already stores in `aiContentPositions` for the
14
+ * FE (`buildCommitTransaction`) path: `[startPos, endPos]` in the live doc plus a
15
+ * closed `originalSlice` / `newSlice` pair. The AI plugin appends these verbatim,
16
+ * then the Post Stream Review screen refines them identically to FE
17
+ * (`calculateTopLevelNodeSegments`, and `calculateDiffSegments` when the
18
+ * diff-based-segmenting gate is on). Producing coarse segments here (rather than
19
+ * fine-grained diffs) preserves the screen's two-layer contract; producing them
20
+ * as CLOSED, whole-top-level-node slices avoids the boundary-bleed / open-slice
21
+ * data-loss hazards of the earlier hand-rolled per-step slicing.
16
22
  */
17
23
  export declare const AGENT_REMOTE_EDIT_REVIEW_DATA = "agentRemoteEditReviewData";
24
+ /**
25
+ * One coarse reviewable segment for a single edited top-level region, matching the
26
+ * `aiContentPositions` entry shape the AI plugin stores for FE streaming.
27
+ */
18
28
  export interface AgentRemoteEditReviewSegment {
19
- /** Live-doc end of the change after the batch applied. A `remove` is zero-width (`endPos === startPos`). */
29
+ /** Live-doc end of the applied (new) content. Equals `startPos` for a pure removal. */
20
30
  endPos: number;
31
+ /** Change kind, mirroring the FE coarse-entry classification. */
32
+ kind: 'add' | 'remove' | 'update';
21
33
  /**
22
- * Derived from the slice pair: empty original `add`, empty new `remove`,
23
- * else `update`. Carried so the consumer does not re-derive it.
34
+ * The post-edit content of this region (`tr.doc`), as a CLOSED slice snapped to
35
+ * whole top-level nodes. `Slice.empty` for a pure removal.
24
36
  */
25
- kind: 'add' | 'remove' | 'update';
26
- /** Content now at [startPos, endPos] AFTER the batch (the agent's content; for redo). */
27
37
  newSlice: Slice;
28
- /** Content that was at the range BEFORE the batch (for undo / "compare with original"). */
38
+ /**
39
+ * The pre-edit content of this region (`tr.before`), as a CLOSED slice snapped
40
+ * to whole top-level nodes. `Slice.empty` for a pure addition.
41
+ */
29
42
  originalSlice: Slice;
30
- /** Live-doc start of the change after the batch applied. */
43
+ /** Live-doc start of the applied (new) content. */
31
44
  startPos: number;
32
45
  }
33
46
  export interface AgentRemoteEditReviewData {
@@ -54,5 +67,10 @@ export interface AgentRemoteEditReviewData {
54
67
  * waiting for the idle debounce. `false`/absent ⇒ rely on the debounce.
55
68
  */
56
69
  complete?: boolean;
70
+ /**
71
+ * The coarse reviewable segments derived from the batch — one per edited
72
+ * top-level region, with closed whole-node slices. Appended verbatim to
73
+ * `aiContentPositions` by the AI plugin.
74
+ */
57
75
  segments: AgentRemoteEditReviewSegment[];
58
76
  }
@@ -1,47 +1,52 @@
1
1
  export declare const placeholderTextMessages: {
2
- placeholderTextPlaceholder: {
3
- id: string;
2
+ longEmptyNodePlaceholderADFPrefix: {
4
3
  defaultMessage: string;
5
4
  description: string;
6
- };
7
- shortEmptyNodePlaceholderText: {
8
5
  id: string;
9
- defaultMessage: string;
10
- description: string;
11
6
  };
12
- shortEmptyNodePlaceholderADFSlashShortcut: {
13
- id: string;
7
+ longEmptyNodePlaceholderADFSlashShortcut: {
14
8
  defaultMessage: string;
15
9
  description: string;
16
- };
17
- shortEmptyNodePlaceholderADFSuffix: {
18
10
  id: string;
11
+ };
12
+ longEmptyNodePlaceholderADFSuffix: {
19
13
  defaultMessage: string;
20
14
  description: string;
15
+ id: string;
21
16
  };
22
17
  longEmptyNodePlaceholderText: {
23
- id: string;
24
18
  defaultMessage: string;
25
19
  description: string;
26
- };
27
- longEmptyNodePlaceholderADFPrefix: {
28
20
  id: string;
21
+ };
22
+ multiBodiedExtensionEmptyFramePlaceholderText: {
29
23
  defaultMessage: string;
30
24
  description: string;
25
+ id: string;
31
26
  };
32
- longEmptyNodePlaceholderADFSlashShortcut: {
27
+ placeholderTextPlaceholder: {
28
+ defaultMessage: string;
29
+ description: string;
33
30
  id: string;
31
+ };
32
+ shortEmptyNodePlaceholderADFSlashShortcut: {
34
33
  defaultMessage: string;
35
34
  description: string;
35
+ id: string;
36
36
  };
37
- longEmptyNodePlaceholderADFSuffix: {
37
+ shortEmptyNodePlaceholderADFSuffix: {
38
+ defaultMessage: string;
39
+ description: string;
38
40
  id: string;
41
+ };
42
+ shortEmptyNodePlaceholderText: {
39
43
  defaultMessage: string;
40
44
  description: string;
45
+ id: string;
41
46
  };
42
47
  sourceSyncBlockPlaceholderText: {
43
- id: string;
44
48
  defaultMessage: string;
45
49
  description: string;
50
+ id: string;
46
51
  };
47
52
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-common",
3
- "version": "118.10.1",
3
+ "version": "118.10.3",
4
4
  "description": "A package that contains common classes and components for editor and renderer",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -76,7 +76,7 @@
76
76
  "@atlaskit/profilecard": "^26.17.0",
77
77
  "@atlaskit/prosemirror-history": "^1.1.0",
78
78
  "@atlaskit/react-compiler-gating": "^0.2.0",
79
- "@atlaskit/react-ufo": "^7.4.0",
79
+ "@atlaskit/react-ufo": "^7.5.0",
80
80
  "@atlaskit/section-message": "^10.0.0",
81
81
  "@atlaskit/smart-card": "^45.17.0",
82
82
  "@atlaskit/smart-user-picker": "^11.5.0",