@atlaskit/editor-core 203.16.5 → 203.17.2

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/afm-cc/tsconfig.json +6 -0
  3. package/afm-jira/tsconfig.json +6 -0
  4. package/afm-post-office/tsconfig.json +6 -0
  5. package/dist/cjs/composable-editor/core-editor.js +5 -2
  6. package/dist/cjs/composable-editor/core-performance-metrics.js +109 -0
  7. package/dist/cjs/index.js +13 -0
  8. package/dist/cjs/ui/Addon/ClickAreaBlock/contentComponentWrapper.js +22 -0
  9. package/dist/cjs/ui/Addon/click-area-helper.js +5 -3
  10. package/dist/cjs/ui/Appearance/Comment/Comment.js +3 -2
  11. package/dist/cjs/ui/Appearance/FullPage/FullPageContentArea.js +3 -2
  12. package/dist/cjs/ui/Appearance/FullPage/FullPageToolbar.js +28 -4
  13. package/dist/cjs/ui/Appearance/FullPage/StyledComponents.js +11 -1
  14. package/dist/cjs/ui/ContentStyles/extension.js +1 -1
  15. package/dist/cjs/ui/Toolbar/ToolbarPortal.compiled.css +3 -0
  16. package/dist/cjs/ui/Toolbar/ToolbarPortal.js +48 -0
  17. package/dist/cjs/version-wrapper.js +1 -1
  18. package/dist/es2019/composable-editor/core-editor.js +6 -3
  19. package/dist/es2019/composable-editor/core-performance-metrics.js +92 -0
  20. package/dist/es2019/index.js +1 -0
  21. package/dist/es2019/ui/Addon/ClickAreaBlock/contentComponentWrapper.js +15 -0
  22. package/dist/es2019/ui/Addon/click-area-helper.js +5 -2
  23. package/dist/es2019/ui/Appearance/Comment/Comment.js +3 -2
  24. package/dist/es2019/ui/Appearance/FullPage/FullPageContentArea.js +3 -2
  25. package/dist/es2019/ui/Appearance/FullPage/FullPageToolbar.js +27 -2
  26. package/dist/es2019/ui/Appearance/FullPage/StyledComponents.js +11 -1
  27. package/dist/es2019/ui/ContentStyles/extension.js +5 -0
  28. package/dist/es2019/ui/Toolbar/ToolbarPortal.compiled.css +3 -0
  29. package/dist/es2019/ui/Toolbar/ToolbarPortal.js +40 -0
  30. package/dist/es2019/version-wrapper.js +1 -1
  31. package/dist/esm/composable-editor/core-editor.js +6 -3
  32. package/dist/esm/composable-editor/core-performance-metrics.js +101 -0
  33. package/dist/esm/index.js +1 -0
  34. package/dist/esm/ui/Addon/ClickAreaBlock/contentComponentWrapper.js +15 -0
  35. package/dist/esm/ui/Addon/click-area-helper.js +5 -2
  36. package/dist/esm/ui/Appearance/Comment/Comment.js +3 -2
  37. package/dist/esm/ui/Appearance/FullPage/FullPageContentArea.js +3 -2
  38. package/dist/esm/ui/Appearance/FullPage/FullPageToolbar.js +28 -4
  39. package/dist/esm/ui/Appearance/FullPage/StyledComponents.js +11 -1
  40. package/dist/esm/ui/ContentStyles/extension.js +1 -1
  41. package/dist/esm/ui/Toolbar/ToolbarPortal.compiled.css +3 -0
  42. package/dist/esm/ui/Toolbar/ToolbarPortal.js +41 -0
  43. package/dist/esm/version-wrapper.js +1 -1
  44. package/dist/types/composable-editor/core-performance-metrics.d.ts +4 -0
  45. package/dist/types/create-editor/create-universal-preset.d.ts +52 -6
  46. package/dist/types/index.d.ts +1 -0
  47. package/dist/types/presets/universal.d.ts +52 -6
  48. package/dist/types/presets/useUniversalPreset.d.ts +52 -6
  49. package/dist/types/ui/Addon/ClickAreaBlock/contentComponentWrapper.d.ts +6 -0
  50. package/dist/types/ui/Addon/click-area-helper.d.ts +1 -0
  51. package/dist/types/ui/Toolbar/ToolbarPortal.d.ts +21 -0
  52. package/dist/types-ts4.5/composable-editor/core-performance-metrics.d.ts +4 -0
  53. package/dist/types-ts4.5/create-editor/create-universal-preset.d.ts +56 -6
  54. package/dist/types-ts4.5/index.d.ts +1 -0
  55. package/dist/types-ts4.5/presets/universal.d.ts +56 -6
  56. package/dist/types-ts4.5/presets/useUniversalPreset.d.ts +56 -6
  57. package/dist/types-ts4.5/ui/Addon/ClickAreaBlock/contentComponentWrapper.d.ts +6 -0
  58. package/dist/types-ts4.5/ui/Addon/click-area-helper.d.ts +1 -0
  59. package/dist/types-ts4.5/ui/Toolbar/ToolbarPortal.d.ts +21 -0
  60. package/package.json +33 -11
  61. package/dist/cjs/ui/Addon/ClickAreaInline/index.js +0 -41
  62. package/dist/cjs/ui/Addon/ClickAreaMobile/index.js +0 -105
  63. package/dist/es2019/ui/Addon/ClickAreaInline/index.js +0 -34
  64. package/dist/es2019/ui/Addon/ClickAreaMobile/index.js +0 -85
  65. package/dist/esm/ui/Addon/ClickAreaInline/index.js +0 -33
  66. package/dist/esm/ui/Addon/ClickAreaMobile/index.js +0 -103
  67. package/dist/types/ui/Addon/ClickAreaInline/index.d.ts +0 -13
  68. package/dist/types/ui/Addon/ClickAreaMobile/index.d.ts +0 -34
  69. package/dist/types-ts4.5/ui/Addon/ClickAreaInline/index.d.ts +0 -13
  70. package/dist/types-ts4.5/ui/Addon/ClickAreaMobile/index.d.ts +0 -34
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @jsxRuntime classic
3
+ * @jsx jsx
4
+ */
5
+ import { useEffect, useCallback, useState, useRef, Fragment, memo } from 'react';
6
+
7
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
8
+ import { jsx } from '@emotion/react';
9
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents';
10
+ import { ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '@atlaskit/editor-common/analytics';
11
+ import { PerformanceMetrics } from '@atlaskit/editor-performance-metrics/react';
12
+ import UFOLoadHold from '@atlaskit/react-ufo/load-hold';
13
+ export const EditorUFOBridge = /*#__PURE__*/memo(() => {
14
+ const [hold, setHold] = useState(true);
15
+ const onTTAI = useCallback(() => {
16
+ setHold(false);
17
+ }, []);
18
+ return jsx(Fragment, null, jsx(UFOLoadHold, {
19
+ name: "editor-core",
20
+ hold: hold
21
+ }), jsx(PerformanceMetrics, {
22
+ onTTAI: onTTAI
23
+ }));
24
+ });
25
+ export const EditorPerformanceMetrics = /*#__PURE__*/memo(() => {
26
+ const {
27
+ createAnalyticsEvent
28
+ } = useAnalyticsEvents();
29
+ const [ttai, setTTAI] = useState(null);
30
+ const [ttvc, setTTVC] = useState(null);
31
+ const [latency, setUserLatency] = useState(null);
32
+ const ttvcSentRef = useRef(false);
33
+ const latencySentRef = useRef(false);
34
+ const handleAnalyticsEvent = useCallback(data => {
35
+ fireAnalyticsEvent(createAnalyticsEvent)(data);
36
+ }, [createAnalyticsEvent]);
37
+ const onTTAI = useCallback(({
38
+ idleAt
39
+ }) => {
40
+ setTTAI(idleAt);
41
+ }, []);
42
+ const onTTVC = useCallback(({
43
+ ttvc
44
+ }) => {
45
+ setTTVC(ttvc);
46
+ }, []);
47
+ const onUserLatency = useCallback(({
48
+ latency
49
+ }) => {
50
+ setUserLatency(latency);
51
+ }, []);
52
+ useEffect(() => {
53
+ if (!ttai || !ttvc || ttvcSentRef.current) {
54
+ return;
55
+ }
56
+ ttvcSentRef.current = true;
57
+ handleAnalyticsEvent({
58
+ payload: {
59
+ // @ts-expect-error Temporary data - let's not extend the public analytics enum
60
+ action: 'ttvc',
61
+ actionSubject: ACTION_SUBJECT.EDITOR,
62
+ eventType: EVENT_TYPE.OPERATIONAL,
63
+ attributes: {
64
+ ttvc,
65
+ ttai
66
+ }
67
+ }
68
+ });
69
+ }, [handleAnalyticsEvent, ttai, ttvc]);
70
+ useEffect(() => {
71
+ if (!latency || latencySentRef.current) {
72
+ return;
73
+ }
74
+ latencySentRef.current = true;
75
+ handleAnalyticsEvent({
76
+ payload: {
77
+ // @ts-expect-error Temporary data - let's not extend the public analytics enum
78
+ action: 'latency',
79
+ actionSubject: ACTION_SUBJECT.EDITOR,
80
+ eventType: EVENT_TYPE.OPERATIONAL,
81
+ attributes: {
82
+ latency
83
+ }
84
+ }
85
+ });
86
+ }, [handleAnalyticsEvent, latency]);
87
+ return jsx(PerformanceMetrics, {
88
+ onTTAI: onTTAI,
89
+ onTTVC: onTTVC,
90
+ onUserLatency: onUserLatency
91
+ });
92
+ });
@@ -21,6 +21,7 @@ export { default as WithEditorActions } from './ui/WithEditorActions';
21
21
  */
22
22
  export { default as WithHelpTrigger } from './ui/WithHelpTrigger';
23
23
  export { default as CollapsedEditor } from './ui/CollapsedEditor';
24
+ export { ToolbarPortalContextProvider, useToolbarPortal } from './ui/Toolbar/ToolbarPortal';
24
25
  export { default as ToolbarHelp } from './ui/ToolbarHelp';
25
26
  export {
26
27
  // eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
3
+ export const ignoreAttribute = 'data-editor-content-component';
4
+
5
+ /**
6
+ * Wraps content components in a data attribute to ignore
7
+ */
8
+ export const contentComponentClickWrapper = reactComponents => {
9
+ if (!fg('platform_editor_content_component_ignore_click')) {
10
+ return reactComponents;
11
+ }
12
+ return /*#__PURE__*/React.createElement("div", {
13
+ "data-editor-content-component": 'true'
14
+ }, reactComponents);
15
+ };
@@ -2,6 +2,8 @@ import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
2
2
  import { addParagraphAtEnd } from '@atlaskit/editor-common/commands';
3
3
  import { setSelectionTopLevelBlocks } from '@atlaskit/editor-common/selection';
4
4
  import { closestElement } from '@atlaskit/editor-common/utils';
5
+ import { ignoreAttribute } from './ClickAreaBlock/contentComponentWrapper';
6
+
5
7
  // we ignore all of the clicks made inside <div class="ak-editor-content-area" /> (but not clicks on the node itself)
6
8
  const insideContentArea = ref => {
7
9
  while (ref) {
@@ -72,6 +74,7 @@ const clickAreaClickHandler = (view, event) => {
72
74
  // Ignored via go/ees005
73
75
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
74
76
  closestElement(selection === null || selection === void 0 ? void 0 : selection.anchorNode, '[data-editor-popup]');
77
+ const isContentComponent = !!closestElement(target, `[${ignoreAttribute}]`) || (target === null || target === void 0 ? void 0 : target.getAttribute(ignoreAttribute)) === 'true';
75
78
 
76
79
  // This is a super workaround to find when events are coming from Confluence InlineComment modal
77
80
  // We don't own those components, so we can't change them
@@ -87,14 +90,14 @@ const clickAreaClickHandler = (view, event) => {
87
90
  const edgeCaseScenario3 = isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused;
88
91
  const edgeCaseScenario4 = isEventComingFromContentArea && !isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused;
89
92
  const edgeCases = edgeCaseScenario1 || edgeCaseScenario2 || edgeCaseScenario3 || edgeCaseScenario4;
90
- const isClickOutsideEditor = edgeCases && !isDatasourcePopupClicked && !isEventComingFromInlineCommentPopup && !isButtonClicked && !isInputClicked && !isTextAreaClicked && !isPopupClicked && !isBreadcrumbClicked && !isEditorPopupTextSelected && checkForModal(target);
93
+ const isClickOutsideEditor = edgeCases && !isDatasourcePopupClicked && !isEventComingFromInlineCommentPopup && !isButtonClicked && !isInputClicked && !isTextAreaClicked && !isPopupClicked && !isBreadcrumbClicked && !isEditorPopupTextSelected && !isContentComponent && checkForModal(target);
91
94
 
92
95
  // click was within editor container and focus should be brought to input
93
96
  if (isClickOutsideEditor && view) {
94
97
  outsideProsemirrorEditorClickHandler(view, event);
95
98
  }
96
99
  };
97
- const outsideProsemirrorEditorClickHandler = (view, event) => {
100
+ export const outsideProsemirrorEditorClickHandler = (view, event) => {
98
101
  var _view$hasFocus2;
99
102
  const {
100
103
  dispatch,
@@ -20,6 +20,7 @@ import { akEditorMobileBreakoutPoint } from '@atlaskit/editor-shared-styles';
20
20
  // Ignored via go/ees005
21
21
  // eslint-disable-next-line import/no-named-as-default
22
22
  import ClickAreaBlock from '../../Addon/ClickAreaBlock';
23
+ import { contentComponentClickWrapper } from '../../Addon/ClickAreaBlock/contentComponentWrapper';
23
24
  import { createEditorContentStyle } from '../../ContentStyles';
24
25
  import PluginSlot from '../../PluginSlot';
25
26
  import { ToolbarWithSizeDetector as Toolbar } from '../../Toolbar/ToolbarWithSizeDetector';
@@ -224,7 +225,7 @@ export const CommentEditorWithIntl = props => {
224
225
  }),
225
226
  featureFlags: featureFlags,
226
227
  viewMode: editorViewModeState === null || editorViewModeState === void 0 ? void 0 : editorViewModeState.mode
227
- }, customContentComponents && 'before' in customContentComponents ? customContentComponents.before : customContentComponents, jsx(PluginSlot, {
228
+ }, customContentComponents && 'before' in customContentComponents ? contentComponentClickWrapper(customContentComponents.before) : contentComponentClickWrapper(customContentComponents), jsx(PluginSlot, {
228
229
  editorView: editorView,
229
230
  editorActions: editorActions,
230
231
  eventDispatcher: eventDispatcher,
@@ -239,7 +240,7 @@ export const CommentEditorWithIntl = props => {
239
240
  disabled: !!disabled,
240
241
  wrapperElement: wrapperElementRef.current,
241
242
  pluginHooks: pluginHooks
242
- }), editorDOMElement, customContentComponents && 'after' in customContentComponents ? customContentComponents.after : null);
243
+ }), editorDOMElement, customContentComponents && 'after' in customContentComponents ? contentComponentClickWrapper(customContentComponents.after) : null);
243
244
  }))), showSecondaryToolbar && jsx("div", {
244
245
  css: secondaryToolbarStyles,
245
246
  "data-testid": "ak-editor-secondary-toolbar"
@@ -13,6 +13,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
13
13
  // Ignored via go/ees005
14
14
  // eslint-disable-next-line import/no-named-as-default
15
15
  import ClickAreaBlock from '../../Addon/ClickAreaBlock';
16
+ import { contentComponentClickWrapper } from '../../Addon/ClickAreaBlock/contentComponentWrapper';
16
17
  import { ContextPanel } from '../../ContextPanel';
17
18
  import PluginSlot from '../../PluginSlot';
18
19
  import { contentArea, contentAreaHeightNoToolbar, contentAreaWrapper, editorContentAreaStyle, editorContentGutterStyle, ScrollContainer, sidebarArea } from './StyledComponents';
@@ -82,7 +83,7 @@ const Content = /*#__PURE__*/React.forwardRef((props, ref) => {
82
83
  ,
83
84
  className: ['ak-editor-content-area', 'appearance-full-page', fullWidthMode ? 'fabric-editor--full-width-mode' : ''].join(' '),
84
85
  ref: contentAreaRef
85
- }, !!props.customContentComponents && 'before' in props.customContentComponents ? props.customContentComponents.before : props.customContentComponents, jsx(PluginSlot, {
86
+ }, !!props.customContentComponents && 'before' in props.customContentComponents ? contentComponentClickWrapper(props.customContentComponents.before) : contentComponentClickWrapper(props.customContentComponents), jsx(PluginSlot, {
86
87
  editorView: props.editorView,
87
88
  editorActions: props.editorActions,
88
89
  eventDispatcher: props.eventDispatcher,
@@ -98,7 +99,7 @@ const Content = /*#__PURE__*/React.forwardRef((props, ref) => {
98
99
  containerElement: scrollContainerRef.current,
99
100
  dispatchAnalyticsEvent: props.dispatchAnalyticsEvent,
100
101
  wrapperElement: props.wrapperElement
101
- }), props.editorDOMElement, !!props.customContentComponents && 'after' in props.customContentComponents ? props.customContentComponents.after : null))))), jsx("div", {
102
+ }), props.editorDOMElement, !!props.customContentComponents && 'after' in props.customContentComponents ? contentComponentClickWrapper(props.customContentComponents.after) : null))))), jsx("div", {
102
103
  css: sidebarArea
103
104
  }, props.contextPanel || jsx(ContextPanel, {
104
105
  editorAPI: props.editorAPI,
@@ -11,11 +11,13 @@ import { injectIntl } from 'react-intl-next';
11
11
  import { fullPageMessages as messages } from '@atlaskit/editor-common/messages';
12
12
  import { ContextPanelConsumer } from '@atlaskit/editor-common/ui';
13
13
  import { ToolbarArrowKeyNavigationProvider } from '@atlaskit/editor-common/ui-menu';
14
+ import { fg } from '@atlaskit/platform-feature-flags';
15
+ import { ToolbarPortalMountPoint, useToolbarPortal } from '../../Toolbar/ToolbarPortal';
14
16
  import { ToolbarWithSizeDetector as Toolbar } from '../../Toolbar/ToolbarWithSizeDetector';
15
17
  import { BeforePrimaryToolbarWrapper } from './BeforeWrapper';
16
18
  import { customToolbarWrapperStyle, mainToolbarFirstChildStyle, mainToolbarIconBeforeStyle, mainToolbarSecondChildStyle, mainToolbarStyle, MAXIMUM_TWO_LINE_TOOLBAR_BREAKPOINT, nonCustomToolbarWrapperStyle } from './MainToolbar';
17
19
  export const EditorToolbar = /*#__PURE__*/React.memo(props => {
18
- var _props$customPrimaryT;
20
+ var _props$customPrimaryT, _useToolbarPortal;
19
21
  const [shouldSplitToolbar, setShouldSplitToolbar] = useState(false);
20
22
  const {
21
23
  editorAPI
@@ -86,6 +88,14 @@ export const EditorToolbar = /*#__PURE__*/React.memo(props => {
86
88
  event.preventDefault();
87
89
  event.stopPropagation();
88
90
  };
91
+
92
+ // When a toolbar portal context is provided, render the toolbar inside a portal.
93
+ // Otherwise fall back to a fragment just to avoid forking rendering logic.
94
+ const {
95
+ Portal: ToolbarPortal
96
+ } = (_useToolbarPortal = useToolbarPortal()) !== null && _useToolbarPortal !== void 0 ? _useToolbarPortal : {
97
+ Portal: React.Fragment
98
+ };
89
99
  return jsx(ContextPanelConsumer, null, ({
90
100
  width: contextPanelWidth
91
101
  }) => jsx(ToolbarArrowKeyNavigationProvider, {
@@ -94,7 +104,22 @@ export const EditorToolbar = /*#__PURE__*/React.memo(props => {
94
104
  isShortcutToFocusToolbar: isShortcutToFocusToolbar,
95
105
  handleEscape: handleEscape,
96
106
  intl: props.intl
107
+ }, fg('platform_editor_lcm_toolbar_portals') ? jsx(ToolbarPortal, null, jsx("div", {
108
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
109
+ css: mainToolbarStyle(props.showKeyline || contextPanelWidth > 0, twoLineEditorToolbar),
110
+ "data-testid": "ak-editor-main-toolbar"
97
111
  }, jsx("div", {
112
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
113
+ css: mainToolbarFirstChildStyle(twoLineEditorToolbar),
114
+ role: "toolbar",
115
+ "aria-label": props.intl.formatMessage(messages.toolbarLabel)
116
+ }, shouldSplitToolbar ? customToolbar : nonCustomToolbar), jsx("div", {
117
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
118
+ css: mainToolbarSecondChildStyle(twoLineEditorToolbar),
119
+ "data-testid": "avatar-group-outside-plugin",
120
+ role: "region",
121
+ "aria-label": props.intl.formatMessage(messages.pageActionsLabel)
122
+ }, shouldSplitToolbar ? nonCustomToolbar : customToolbar), jsx(ToolbarPortalMountPoint, null))) : jsx("div", {
98
123
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
99
124
  css: mainToolbarStyle(props.showKeyline || contextPanelWidth > 0, twoLineEditorToolbar),
100
125
  "data-testid": "ak-editor-main-toolbar"
@@ -106,7 +131,7 @@ export const EditorToolbar = /*#__PURE__*/React.memo(props => {
106
131
  }, shouldSplitToolbar ? customToolbar : nonCustomToolbar), jsx("div", {
107
132
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
108
133
  css: mainToolbarSecondChildStyle(twoLineEditorToolbar),
109
- "data-testid": 'avatar-group-outside-plugin',
134
+ "data-testid": "avatar-group-outside-plugin",
110
135
  role: "region",
111
136
  "aria-label": props.intl.formatMessage(messages.pageActionsLabel)
112
137
  }, shouldSplitToolbar ? nonCustomToolbar : customToolbar))));
@@ -80,7 +80,17 @@ export const contentAreaHeightNoToolbar = css({
80
80
  export const sidebarArea = css({
81
81
  height: '100%',
82
82
  boxSizing: 'border-box',
83
- alignSelf: 'flex-end'
83
+ alignSelf: 'flex-end',
84
+ // Make the sidebar sticky within the legacy content macro
85
+ // to prevent it from aligning to the bottom with large content.
86
+ // This style is only applied when opening inside the legacy content macro.
87
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-nested-selectors
88
+ '.extension-editable-area &': {
89
+ height: 'auto',
90
+ position: 'sticky',
91
+ top: 0,
92
+ alignSelf: 'flex-start'
93
+ }
84
94
  });
85
95
 
86
96
  // initially hide until we have a containerWidth and can properly size them,
@@ -180,6 +180,11 @@ export const extensionStyles = css`
180
180
 
181
181
  .extensionView-content-wrap .extension-container {
182
182
  overflow: hidden;
183
+
184
+ /* Don't hide overflow for editors inside extensions */
185
+ &:has(.extension-editable-area) {
186
+ overflow: visible;
187
+ }
183
188
  }
184
189
 
185
190
  .bodiedExtensionView-content-wrap .extensionView-content-wrap .extension-container {
@@ -0,0 +1,3 @@
1
+ ._1r04ze3t{inset:var(--ds-space-0,0)}
2
+ ._fiawglyw:empty{display:none}
3
+ ._kqswstnw{position:absolute}
@@ -0,0 +1,40 @@
1
+ /* ToolbarPortal.tsx generated by @compiled/babel-plugin v0.36.1 */
2
+ import "./ToolbarPortal.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React from 'react';
5
+ const ToolbarPortalContext = /*#__PURE__*/React.createContext(undefined);
6
+ export const ToolbarPortalContextProvider = ({
7
+ children,
8
+ portal,
9
+ isActive
10
+ }) => {
11
+ const value = React.useMemo(() => ({
12
+ Portal: portal,
13
+ isActive
14
+ }), [portal, isActive]);
15
+ return /*#__PURE__*/React.createElement(ToolbarPortalContext.Provider, {
16
+ value: value
17
+ }, children);
18
+ };
19
+
20
+ // NOTE: This doesn't throw on undefined context on purpose, as it is likely that
21
+ // the outer toolbar _won't_ have a context provider as it is unlikely to portal
22
+ // anywhere
23
+ export const useToolbarPortal = () => {
24
+ return React.useContext(ToolbarPortalContext);
25
+ };
26
+ const toolbarPortalStyles = {
27
+ portal: "_1r04ze3t _kqswstnw _fiawglyw"
28
+ };
29
+ export const ToolbarPortalMountPoint = () => {
30
+ const portal = useToolbarPortal();
31
+
32
+ // Don't render a mountpoint when we're already inside a portal
33
+ if (portal) {
34
+ return null;
35
+ }
36
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
37
+ return /*#__PURE__*/React.createElement("div", {
38
+ className: ax([toolbarPortalStyles.portal, "ak-editor-toolbar-portal"])
39
+ });
40
+ };
@@ -1,2 +1,2 @@
1
1
  export const name = "@atlaskit/editor-core";
2
- export const version = "203.16.5";
2
+ export const version = "203.17.2";
@@ -6,7 +6,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
6
6
  * @jsxRuntime classic
7
7
  * @jsx jsx
8
8
  */
9
- import { useCallback, useMemo, useRef } from 'react';
9
+ import { useCallback, useMemo, useRef, Fragment } from 'react';
10
10
 
11
11
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
12
12
  import { jsx } from '@emotion/react';
@@ -17,11 +17,13 @@ import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents'
17
17
  import { ACTION, fireAnalyticsEvent } from '@atlaskit/editor-common/analytics';
18
18
  import { startMeasure, stopMeasure } from '@atlaskit/editor-common/performance-measures';
19
19
  import { getAnalyticsAppearance } from '@atlaskit/editor-common/utils/analytics';
20
+ import { fg } from '@atlaskit/platform-feature-flags';
20
21
  import EditorActions from '../actions';
21
22
  import { useEditorContext } from '../ui/EditorContext';
22
23
  import { createFeatureFlagsFromProps } from '../utils/feature-flags-from-props';
23
24
  import measurements from '../utils/performance/measure-enum';
24
25
  import { name, version } from '../version-wrapper';
26
+ import { EditorUFOBridge, EditorPerformanceMetrics } from './core-performance-metrics';
25
27
  import { EditorInternal } from './editor-internal';
26
28
  import useMeasureEditorMountTime from './hooks/useMeasureEditorMountTime';
27
29
  // Ignored via go/ees005
@@ -87,7 +89,8 @@ function Editor(passedProps) {
87
89
  onSaveFromProps(view);
88
90
  }
89
91
  }, [onSaveFromProps]);
90
- return jsx(EditorInternal, {
92
+ var isFullPageApperance = Boolean(props.appearance && ['full-page', 'full-width'].includes(props.appearance));
93
+ return jsx(Fragment, null, isFullPageApperance && fg('platform_editor_fe--ufo-bridge') ? jsx(EditorUFOBridge, null) : null, isFullPageApperance && fg('platform_editor_fe--performance_metrics') ? jsx(EditorPerformanceMetrics, null) : null, jsx(EditorInternal, {
91
94
  props: props,
92
95
  handleAnalyticsEvent: handleAnalyticsEvent,
93
96
  createAnalyticsEvent: createAnalyticsEvent,
@@ -98,7 +101,7 @@ function Editor(passedProps) {
98
101
  onEditorDestroyed: onEditorDestroyed,
99
102
  providerFactory: providerFactory,
100
103
  AppearanceComponent: props.AppearanceComponent
101
- });
104
+ }));
102
105
  }
103
106
  var useMemoEditorFeatureFlags = function useMemoEditorFeatureFlags(featureFlags) {
104
107
  var ffRef = useRef(featureFlags);
@@ -0,0 +1,101 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ /**
3
+ * @jsxRuntime classic
4
+ * @jsx jsx
5
+ */
6
+ import { useEffect, useCallback, useState, useRef, Fragment, memo } from 'react';
7
+
8
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
9
+ import { jsx } from '@emotion/react';
10
+ import { useAnalyticsEvents } from '@atlaskit/analytics-next/useAnalyticsEvents';
11
+ import { ACTION_SUBJECT, EVENT_TYPE, fireAnalyticsEvent } from '@atlaskit/editor-common/analytics';
12
+ import { PerformanceMetrics } from '@atlaskit/editor-performance-metrics/react';
13
+ import UFOLoadHold from '@atlaskit/react-ufo/load-hold';
14
+ export var EditorUFOBridge = /*#__PURE__*/memo(function () {
15
+ var _useState = useState(true),
16
+ _useState2 = _slicedToArray(_useState, 2),
17
+ hold = _useState2[0],
18
+ setHold = _useState2[1];
19
+ var onTTAI = useCallback(function () {
20
+ setHold(false);
21
+ }, []);
22
+ return jsx(Fragment, null, jsx(UFOLoadHold, {
23
+ name: "editor-core",
24
+ hold: hold
25
+ }), jsx(PerformanceMetrics, {
26
+ onTTAI: onTTAI
27
+ }));
28
+ });
29
+ export var EditorPerformanceMetrics = /*#__PURE__*/memo(function () {
30
+ var _useAnalyticsEvents = useAnalyticsEvents(),
31
+ createAnalyticsEvent = _useAnalyticsEvents.createAnalyticsEvent;
32
+ var _useState3 = useState(null),
33
+ _useState4 = _slicedToArray(_useState3, 2),
34
+ ttai = _useState4[0],
35
+ setTTAI = _useState4[1];
36
+ var _useState5 = useState(null),
37
+ _useState6 = _slicedToArray(_useState5, 2),
38
+ ttvc = _useState6[0],
39
+ setTTVC = _useState6[1];
40
+ var _useState7 = useState(null),
41
+ _useState8 = _slicedToArray(_useState7, 2),
42
+ latency = _useState8[0],
43
+ setUserLatency = _useState8[1];
44
+ var ttvcSentRef = useRef(false);
45
+ var latencySentRef = useRef(false);
46
+ var handleAnalyticsEvent = useCallback(function (data) {
47
+ fireAnalyticsEvent(createAnalyticsEvent)(data);
48
+ }, [createAnalyticsEvent]);
49
+ var onTTAI = useCallback(function (_ref) {
50
+ var idleAt = _ref.idleAt;
51
+ setTTAI(idleAt);
52
+ }, []);
53
+ var onTTVC = useCallback(function (_ref2) {
54
+ var ttvc = _ref2.ttvc;
55
+ setTTVC(ttvc);
56
+ }, []);
57
+ var onUserLatency = useCallback(function (_ref3) {
58
+ var latency = _ref3.latency;
59
+ setUserLatency(latency);
60
+ }, []);
61
+ useEffect(function () {
62
+ if (!ttai || !ttvc || ttvcSentRef.current) {
63
+ return;
64
+ }
65
+ ttvcSentRef.current = true;
66
+ handleAnalyticsEvent({
67
+ payload: {
68
+ // @ts-expect-error Temporary data - let's not extend the public analytics enum
69
+ action: 'ttvc',
70
+ actionSubject: ACTION_SUBJECT.EDITOR,
71
+ eventType: EVENT_TYPE.OPERATIONAL,
72
+ attributes: {
73
+ ttvc: ttvc,
74
+ ttai: ttai
75
+ }
76
+ }
77
+ });
78
+ }, [handleAnalyticsEvent, ttai, ttvc]);
79
+ useEffect(function () {
80
+ if (!latency || latencySentRef.current) {
81
+ return;
82
+ }
83
+ latencySentRef.current = true;
84
+ handleAnalyticsEvent({
85
+ payload: {
86
+ // @ts-expect-error Temporary data - let's not extend the public analytics enum
87
+ action: 'latency',
88
+ actionSubject: ACTION_SUBJECT.EDITOR,
89
+ eventType: EVENT_TYPE.OPERATIONAL,
90
+ attributes: {
91
+ latency: latency
92
+ }
93
+ }
94
+ });
95
+ }, [handleAnalyticsEvent, latency]);
96
+ return jsx(PerformanceMetrics, {
97
+ onTTAI: onTTAI,
98
+ onTTVC: onTTVC,
99
+ onUserLatency: onUserLatency
100
+ });
101
+ });
package/dist/esm/index.js CHANGED
@@ -21,6 +21,7 @@ export { default as WithEditorActions } from './ui/WithEditorActions';
21
21
  */
22
22
  export { default as WithHelpTrigger } from './ui/WithHelpTrigger';
23
23
  export { default as CollapsedEditor } from './ui/CollapsedEditor';
24
+ export { ToolbarPortalContextProvider, useToolbarPortal } from './ui/Toolbar/ToolbarPortal';
24
25
  export { default as ToolbarHelp } from './ui/ToolbarHelp';
25
26
  export {
26
27
  // eslint-disable-next-line @repo/internal/deprecations/deprecation-ticket-required -- Ignored via go/ED-25883
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { fg } from '@atlaskit/platform-feature-flags';
3
+ export var ignoreAttribute = 'data-editor-content-component';
4
+
5
+ /**
6
+ * Wraps content components in a data attribute to ignore
7
+ */
8
+ export var contentComponentClickWrapper = function contentComponentClickWrapper(reactComponents) {
9
+ if (!fg('platform_editor_content_component_ignore_click')) {
10
+ return reactComponents;
11
+ }
12
+ return /*#__PURE__*/React.createElement("div", {
13
+ "data-editor-content-component": 'true'
14
+ }, reactComponents);
15
+ };
@@ -2,6 +2,8 @@ import { tintDirtyTransaction } from '@atlaskit/editor-common/collab';
2
2
  import { addParagraphAtEnd } from '@atlaskit/editor-common/commands';
3
3
  import { setSelectionTopLevelBlocks } from '@atlaskit/editor-common/selection';
4
4
  import { closestElement } from '@atlaskit/editor-common/utils';
5
+ import { ignoreAttribute } from './ClickAreaBlock/contentComponentWrapper';
6
+
5
7
  // we ignore all of the clicks made inside <div class="ak-editor-content-area" /> (but not clicks on the node itself)
6
8
  var insideContentArea = function insideContentArea(ref) {
7
9
  while (ref) {
@@ -72,6 +74,7 @@ var clickAreaClickHandler = function clickAreaClickHandler(view, event) {
72
74
  // Ignored via go/ees005
73
75
  // eslint-disable-next-line @atlaskit/editor/no-as-casting
74
76
  closestElement(selection === null || selection === void 0 ? void 0 : selection.anchorNode, '[data-editor-popup]');
77
+ var isContentComponent = !!closestElement(target, "[".concat(ignoreAttribute, "]")) || (target === null || target === void 0 ? void 0 : target.getAttribute(ignoreAttribute)) === 'true';
75
78
 
76
79
  // This is a super workaround to find when events are coming from Confluence InlineComment modal
77
80
  // We don't own those components, so we can't change them
@@ -87,14 +90,14 @@ var clickAreaClickHandler = function clickAreaClickHandler(view, event) {
87
90
  var edgeCaseScenario3 = isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused;
88
91
  var edgeCaseScenario4 = isEventComingFromContentArea && !isTargetContentArea && !isTargetInsideContentArea && !isEditorFocused;
89
92
  var edgeCases = edgeCaseScenario1 || edgeCaseScenario2 || edgeCaseScenario3 || edgeCaseScenario4;
90
- var isClickOutsideEditor = edgeCases && !isDatasourcePopupClicked && !isEventComingFromInlineCommentPopup && !isButtonClicked && !isInputClicked && !isTextAreaClicked && !isPopupClicked && !isBreadcrumbClicked && !isEditorPopupTextSelected && checkForModal(target);
93
+ var isClickOutsideEditor = edgeCases && !isDatasourcePopupClicked && !isEventComingFromInlineCommentPopup && !isButtonClicked && !isInputClicked && !isTextAreaClicked && !isPopupClicked && !isBreadcrumbClicked && !isEditorPopupTextSelected && !isContentComponent && checkForModal(target);
91
94
 
92
95
  // click was within editor container and focus should be brought to input
93
96
  if (isClickOutsideEditor && view) {
94
97
  outsideProsemirrorEditorClickHandler(view, event);
95
98
  }
96
99
  };
97
- var outsideProsemirrorEditorClickHandler = function outsideProsemirrorEditorClickHandler(view, event) {
100
+ export var outsideProsemirrorEditorClickHandler = function outsideProsemirrorEditorClickHandler(view, event) {
98
101
  var _view$hasFocus2;
99
102
  var dispatch = view.dispatch,
100
103
  dom = view.dom,
@@ -21,6 +21,7 @@ import { akEditorMobileBreakoutPoint } from '@atlaskit/editor-shared-styles';
21
21
  // Ignored via go/ees005
22
22
  // eslint-disable-next-line import/no-named-as-default
23
23
  import ClickAreaBlock from '../../Addon/ClickAreaBlock';
24
+ import { contentComponentClickWrapper } from '../../Addon/ClickAreaBlock/contentComponentWrapper';
24
25
  import { createEditorContentStyle } from '../../ContentStyles';
25
26
  import PluginSlot from '../../PluginSlot';
26
27
  import { ToolbarWithSizeDetector as Toolbar } from '../../Toolbar/ToolbarWithSizeDetector';
@@ -227,7 +228,7 @@ export var CommentEditorWithIntl = function CommentEditorWithIntl(props) {
227
228
  }),
228
229
  featureFlags: featureFlags,
229
230
  viewMode: editorViewModeState === null || editorViewModeState === void 0 ? void 0 : editorViewModeState.mode
230
- }, customContentComponents && 'before' in customContentComponents ? customContentComponents.before : customContentComponents, jsx(PluginSlot, {
231
+ }, customContentComponents && 'before' in customContentComponents ? contentComponentClickWrapper(customContentComponents.before) : contentComponentClickWrapper(customContentComponents), jsx(PluginSlot, {
231
232
  editorView: editorView,
232
233
  editorActions: editorActions,
233
234
  eventDispatcher: eventDispatcher,
@@ -242,7 +243,7 @@ export var CommentEditorWithIntl = function CommentEditorWithIntl(props) {
242
243
  disabled: !!disabled,
243
244
  wrapperElement: wrapperElementRef.current,
244
245
  pluginHooks: pluginHooks
245
- }), editorDOMElement, customContentComponents && 'after' in customContentComponents ? customContentComponents.after : null);
246
+ }), editorDOMElement, customContentComponents && 'after' in customContentComponents ? contentComponentClickWrapper(customContentComponents.after) : null);
246
247
  }))), showSecondaryToolbar && jsx("div", {
247
248
  css: secondaryToolbarStyles,
248
249
  "data-testid": "ak-editor-secondary-toolbar"
@@ -13,6 +13,7 @@ import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
13
13
  // Ignored via go/ees005
14
14
  // eslint-disable-next-line import/no-named-as-default
15
15
  import ClickAreaBlock from '../../Addon/ClickAreaBlock';
16
+ import { contentComponentClickWrapper } from '../../Addon/ClickAreaBlock/contentComponentWrapper';
16
17
  import { ContextPanel } from '../../ContextPanel';
17
18
  import PluginSlot from '../../PluginSlot';
18
19
  import { contentArea, contentAreaHeightNoToolbar, contentAreaWrapper, editorContentAreaStyle, editorContentGutterStyle, ScrollContainer, sidebarArea } from './StyledComponents';
@@ -84,7 +85,7 @@ var Content = /*#__PURE__*/React.forwardRef(function (props, ref) {
84
85
  ,
85
86
  className: ['ak-editor-content-area', 'appearance-full-page', fullWidthMode ? 'fabric-editor--full-width-mode' : ''].join(' '),
86
87
  ref: contentAreaRef
87
- }, !!props.customContentComponents && 'before' in props.customContentComponents ? props.customContentComponents.before : props.customContentComponents, jsx(PluginSlot, {
88
+ }, !!props.customContentComponents && 'before' in props.customContentComponents ? contentComponentClickWrapper(props.customContentComponents.before) : contentComponentClickWrapper(props.customContentComponents), jsx(PluginSlot, {
88
89
  editorView: props.editorView,
89
90
  editorActions: props.editorActions,
90
91
  eventDispatcher: props.eventDispatcher,
@@ -100,7 +101,7 @@ var Content = /*#__PURE__*/React.forwardRef(function (props, ref) {
100
101
  containerElement: scrollContainerRef.current,
101
102
  dispatchAnalyticsEvent: props.dispatchAnalyticsEvent,
102
103
  wrapperElement: props.wrapperElement
103
- }), props.editorDOMElement, !!props.customContentComponents && 'after' in props.customContentComponents ? props.customContentComponents.after : null))))), jsx("div", {
104
+ }), props.editorDOMElement, !!props.customContentComponents && 'after' in props.customContentComponents ? contentComponentClickWrapper(props.customContentComponents.after) : null))))), jsx("div", {
104
105
  css: sidebarArea
105
106
  }, props.contextPanel || jsx(ContextPanel, {
106
107
  editorAPI: props.editorAPI,