@atlaskit/editor-plugin-block-menu 4.0.25 → 5.0.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 CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atlaskit/editor-plugin-block-menu
2
2
 
3
+ ## 5.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 5.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - [`6e51d74bb2a29`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/6e51d74bb2a29) -
14
+ [ux] ED-29560 Use hash instead of query parameter for link to block
15
+
16
+ ### Patch Changes
17
+
18
+ - [`4f5569bde5e64`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/4f5569bde5e64) -
19
+ Add new 'dragHandleSelected' user intent, use this to control table toolbar when drag handle is
20
+ selected
21
+ - Updated dependencies
22
+
3
23
  ## 4.0.25
4
24
 
5
25
  ### Patch Changes
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-cc/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-cc/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-cc/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-dev-agents/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-dev-agents/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-dev-agents/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-jira/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-jira/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-jira/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-passionfruit/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-passionfruit/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-passionfruit/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-post-office/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-post-office/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-post-office/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-rovo-extension/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-rovo-extension/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-rovo-extension/tsconfig.json"
61
64
  },
@@ -56,6 +56,9 @@
56
56
  {
57
57
  "path": "../../../platform/feature-flags/afm-townsquare/tsconfig.json"
58
58
  },
59
+ {
60
+ "path": "../../../platform/feature-flags-react/afm-townsquare/tsconfig.json"
61
+ },
59
62
  {
60
63
  "path": "../../../design-system/primitives/afm-townsquare/tsconfig.json"
61
64
  },
@@ -19,6 +19,8 @@ var _ui = require("@atlaskit/editor-common/ui");
19
19
  var _uiReact = require("@atlaskit/editor-common/ui-react");
20
20
  var _editorSharedStyles = require("@atlaskit/editor-shared-styles");
21
21
  var _editorToolbar = require("@atlaskit/editor-toolbar");
22
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
23
+ var _platformFeatureFlagsReact = require("@atlaskit/platform-feature-flags-react");
22
24
  var _compiled = require("@atlaskit/primitives/compiled");
23
25
  var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure");
24
26
  var _blockMenuProvider = require("./block-menu-provider");
@@ -31,10 +33,81 @@ var styles = {
31
33
  var DEFAULT_MENU_WIDTH = 230;
32
34
  var DRAG_HANDLE_OFFSET_PADDING = 5;
33
35
  var PopupWithListeners = (0, _uiReact.withReactEditorViewOuterListeners)(_ui.Popup);
34
- var BlockMenuContent = function BlockMenuContent(_ref) {
35
- var _api$blockMenu;
36
+ var useConditionalBlockMenuEffect = (0, _platformFeatureFlagsReact.conditionalHooksFactory)(function () {
37
+ return (0, _platformFeatureFlags.fg)('platform_editor_toolbar_aifc_user_intent_fix');
38
+ }, function (_ref) {
36
39
  var api = _ref.api,
37
- setRef = _ref.setRef;
40
+ isMenuOpen = _ref.isMenuOpen,
41
+ menuTriggerBy = _ref.menuTriggerBy,
42
+ selectedByShortcutOrDragHandle = _ref.selectedByShortcutOrDragHandle,
43
+ hasFocus = _ref.hasFocus,
44
+ shouldShowBlockMenuForEmptyLine = _ref.shouldShowBlockMenuForEmptyLine,
45
+ openedViaKeyboard = _ref.openedViaKeyboard,
46
+ prevIsMenuOpenRef = _ref.prevIsMenuOpenRef;
47
+ /**
48
+ * NOTE: do not add `currentUserIntent` to dependency array as it causes unnecessary re-renders and messes with the user intent state
49
+ */
50
+ (0, _react.useEffect)(function () {
51
+ var _api$userIntent;
52
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine) {
53
+ return;
54
+ }
55
+
56
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
57
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
58
+ var _api$analytics;
59
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
60
+ action: _analytics.ACTION.OPENED,
61
+ actionSubject: _analytics.ACTION_SUBJECT.BLOCK_MENU,
62
+ eventType: _analytics.EVENT_TYPE.UI,
63
+ attributes: {
64
+ inputMethod: openedViaKeyboard ? _analytics.INPUT_METHOD.KEYBOARD : _analytics.INPUT_METHOD.MOUSE
65
+ }
66
+ });
67
+ }
68
+
69
+ // Update the previous state
70
+ prevIsMenuOpenRef.current = isMenuOpen;
71
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
72
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, openedViaKeyboard, prevIsMenuOpenRef]);
73
+ }, function (_ref2) {
74
+ var api = _ref2.api,
75
+ isMenuOpen = _ref2.isMenuOpen,
76
+ menuTriggerBy = _ref2.menuTriggerBy,
77
+ selectedByShortcutOrDragHandle = _ref2.selectedByShortcutOrDragHandle,
78
+ hasFocus = _ref2.hasFocus,
79
+ shouldShowBlockMenuForEmptyLine = _ref2.shouldShowBlockMenuForEmptyLine,
80
+ currentUserIntent = _ref2.currentUserIntent,
81
+ openedViaKeyboard = _ref2.openedViaKeyboard,
82
+ prevIsMenuOpenRef = _ref2.prevIsMenuOpenRef;
83
+ (0, _react.useEffect)(function () {
84
+ var _api$userIntent2;
85
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
86
+ return;
87
+ }
88
+
89
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
90
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
91
+ var _api$analytics2;
92
+ api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.fireAnalyticsEvent({
93
+ action: _analytics.ACTION.OPENED,
94
+ actionSubject: _analytics.ACTION_SUBJECT.BLOCK_MENU,
95
+ eventType: _analytics.EVENT_TYPE.UI,
96
+ attributes: {
97
+ inputMethod: openedViaKeyboard ? _analytics.INPUT_METHOD.KEYBOARD : _analytics.INPUT_METHOD.MOUSE
98
+ }
99
+ });
100
+ }
101
+
102
+ // Update the previous state
103
+ prevIsMenuOpenRef.current = isMenuOpen;
104
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.commands.setCurrentUserIntent('blockMenuOpen'));
105
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard, prevIsMenuOpenRef]);
106
+ });
107
+ var BlockMenuContent = function BlockMenuContent(_ref3) {
108
+ var _api$blockMenu;
109
+ var api = _ref3.api,
110
+ setRef = _ref3.setRef;
38
111
  var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
39
112
  var setOutsideClickTargetRef = (0, _react.useContext)(_uiReact.OutsideClickTargetRefContext);
40
113
  var ref = function ref(el) {
@@ -63,13 +136,13 @@ var BlockMenuContent = function BlockMenuContent(_ref) {
63
136
  }
64
137
  }));
65
138
  };
66
- var BlockMenu = function BlockMenu(_ref2) {
67
- var _editorView$dom, _ref3, _editorView$hasFocus;
68
- var editorView = _ref2.editorView,
69
- api = _ref2.api,
70
- mountTo = _ref2.mountTo,
71
- boundariesElement = _ref2.boundariesElement,
72
- scrollableElement = _ref2.scrollableElement;
139
+ var BlockMenu = function BlockMenu(_ref4) {
140
+ var _editorView$dom, _ref5, _editorView$hasFocus;
141
+ var editorView = _ref4.editorView,
142
+ api = _ref4.api,
143
+ mountTo = _ref4.mountTo,
144
+ boundariesElement = _ref4.boundariesElement,
145
+ scrollableElement = _ref4.scrollableElement;
73
146
  var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['blockControls', 'userIntent'], function (states) {
74
147
  var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$userIntentSta, _states$blockControls4;
75
148
  return {
@@ -90,49 +163,39 @@ var BlockMenu = function BlockMenu(_ref2) {
90
163
  var targetHandleRef = editorView === null || editorView === void 0 || (_editorView$dom = editorView.dom) === null || _editorView$dom === void 0 ? void 0 : _editorView$dom.querySelector(_styles.DRAG_HANDLE_SELECTOR);
91
164
  var prevIsMenuOpenRef = (0, _react.useRef)(false);
92
165
  var popupRef = (0, _react.useRef)(undefined);
93
- var hasFocus = (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref3 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef || popupRef.current && (popupRef.current.contains(document.activeElement) || popupRef.current === document.activeElement)) !== null && _ref3 !== void 0 ? _ref3 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
166
+ var hasFocus = (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref5 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef || popupRef.current && (popupRef.current.contains(document.activeElement) || popupRef.current === document.activeElement)) !== null && _ref5 !== void 0 ? _ref5 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
94
167
  var hasSelection = !!editorView && !editorView.state.selection.empty;
95
168
  // hasSelection true, always show block menu
96
169
  // hasSelection false, only show block menu when empty line experiment is enabled
97
170
  var shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_empty_line', 'isEnabled', true);
98
- var selectedByShortcutOrDragHandle = isSelectedViaDragHandle || openedViaKeyboard && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
99
- (0, _react.useEffect)(function () {
100
- var _api$userIntent;
101
- if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
102
- return;
103
- }
171
+ var selectedByShortcutOrDragHandle = !!isSelectedViaDragHandle || !!openedViaKeyboard && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
104
172
 
105
- // Fire analytics event when block menu opens (only on first transition from closed to open)
106
- if (!prevIsMenuOpenRef.current && isMenuOpen) {
107
- var _api$analytics;
108
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
109
- action: _analytics.ACTION.OPENED,
110
- actionSubject: _analytics.ACTION_SUBJECT.BLOCK_MENU,
111
- eventType: _analytics.EVENT_TYPE.UI,
112
- attributes: {
113
- inputMethod: openedViaKeyboard ? _analytics.INPUT_METHOD.KEYBOARD : _analytics.INPUT_METHOD.MOUSE
114
- }
115
- });
116
- }
117
-
118
- // Update the previous state
119
- prevIsMenuOpenRef.current = isMenuOpen;
120
- api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
121
- }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard]);
173
+ // Use conditional hook based on feature flag
174
+ useConditionalBlockMenuEffect({
175
+ api: api,
176
+ isMenuOpen: isMenuOpen,
177
+ menuTriggerBy: menuTriggerBy,
178
+ selectedByShortcutOrDragHandle: selectedByShortcutOrDragHandle,
179
+ hasFocus: hasFocus,
180
+ shouldShowBlockMenuForEmptyLine: shouldShowBlockMenuForEmptyLine,
181
+ currentUserIntent: (0, _platformFeatureFlags.fg)('platform_editor_toolbar_aifc_user_intent_fix') ? undefined : currentUserIntent,
182
+ openedViaKeyboard: openedViaKeyboard,
183
+ prevIsMenuOpenRef: prevIsMenuOpenRef
184
+ });
122
185
  if (!isMenuOpen) {
123
186
  return null;
124
187
  }
125
188
  var closeMenu = function closeMenu() {
126
- api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
127
- var _api$blockControls, _api$userIntent2;
128
- var tr = _ref4.tr;
189
+ api === null || api === void 0 || api.core.actions.execute(function (_ref6) {
190
+ var _api$blockControls, _api$userIntent3;
191
+ var tr = _ref6.tr;
129
192
  api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.toggleBlockMenu({
130
193
  closeMenu: true
131
194
  })({
132
195
  tr: tr
133
196
  });
134
197
  onDropdownOpenChanged(false);
135
- api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 || _api$userIntent2.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
198
+ api === null || api === void 0 || (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 || _api$userIntent3.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
136
199
  tr: tr
137
200
  });
138
201
  return tr;
@@ -148,10 +211,10 @@ var BlockMenu = function BlockMenu(_ref2) {
148
211
  }
149
212
  };
150
213
  if (targetHandleRef instanceof HTMLElement) {
151
- var _api$analytics2;
214
+ var _api$analytics3;
152
215
  return /*#__PURE__*/_react.default.createElement(_errorBoundary.ErrorBoundary, {
153
216
  component: _analytics.ACTION_SUBJECT.BLOCK_MENU,
154
- dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
217
+ dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
155
218
  fallbackComponent: null
156
219
  }, /*#__PURE__*/_react.default.createElement(PopupWithListeners, {
157
220
  alignX: 'right',
@@ -46,8 +46,8 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
46
46
  return tr;
47
47
  });
48
48
  onDropdownOpenChanged(false);
49
- return (0, _copyLink.copyLink)(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
50
- }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api, onDropdownOpenChanged]);
49
+ return (0, _copyLink.copyLink)(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api);
50
+ }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api, onDropdownOpenChanged]);
51
51
  var checkIsNestedNode = (0, _react.useCallback)(function () {
52
52
  var _api$selection, _api$blockControls2;
53
53
  var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState) === null || _api$selection === void 0 || (_api$selection = _api$selection.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
@@ -7,12 +7,13 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports.copyLink = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _blockMenu = require("@atlaskit/editor-common/block-menu");
10
11
  var _clipboard = require("@atlaskit/editor-common/clipboard");
11
12
  var _state = require("@atlaskit/editor-prosemirror/state");
12
13
  var _editorTables = require("@atlaskit/editor-tables");
13
14
  var copyLink = exports.copyLink = /*#__PURE__*/function () {
14
15
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(getLinkPath) {
15
- var blockQueryParam,
16
+ var blockLinkHashPrefix,
16
17
  api,
17
18
  _api$selection,
18
19
  node,
@@ -24,7 +25,7 @@ var copyLink = exports.copyLink = /*#__PURE__*/function () {
24
25
  return _regenerator.default.wrap(function _callee$(_context) {
25
26
  while (1) switch (_context.prev = _context.next) {
26
27
  case 0:
27
- blockQueryParam = _args.length > 1 && _args[1] !== undefined ? _args[1] : 'block';
28
+ blockLinkHashPrefix = _args.length > 1 && _args[1] !== undefined ? _args[1] : _blockMenu.DEFAULT_BLOCK_LINK_HASH_PREFIX;
28
29
  api = _args.length > 2 ? _args[2] : undefined;
29
30
  _context.prev = 2;
30
31
  selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
@@ -48,8 +49,8 @@ var copyLink = exports.copyLink = /*#__PURE__*/function () {
48
49
  }
49
50
  return _context.abrupt("return", false);
50
51
  case 10:
51
- url = new URL(location.origin + path);
52
- url.searchParams.set(blockQueryParam, node.attrs.localId);
52
+ url = new URL(location.origin + path); // append the localId as a hash fragment in the form #block-{localId}
53
+ url.hash = "".concat(blockLinkHashPrefix).concat(node.attrs.localId);
53
54
  href = url.toString();
54
55
  _context.next = 15;
55
56
  return (0, _clipboard.copyToClipboard)(href);
@@ -12,6 +12,8 @@ import { Popup } from '@atlaskit/editor-common/ui';
12
12
  import { OutsideClickTargetRefContext, withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
13
13
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
14
14
  import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
16
+ import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react';
15
17
  import { Box } from '@atlaskit/primitives/compiled';
16
18
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
17
19
  import { useBlockMenu } from './block-menu-provider';
@@ -23,6 +25,77 @@ const styles = {
23
25
  const DEFAULT_MENU_WIDTH = 230;
24
26
  const DRAG_HANDLE_OFFSET_PADDING = 5;
25
27
  const PopupWithListeners = withReactEditorViewOuterListeners(Popup);
28
+ const useConditionalBlockMenuEffect = conditionalHooksFactory(() => fg('platform_editor_toolbar_aifc_user_intent_fix'), ({
29
+ api,
30
+ isMenuOpen,
31
+ menuTriggerBy,
32
+ selectedByShortcutOrDragHandle,
33
+ hasFocus,
34
+ shouldShowBlockMenuForEmptyLine,
35
+ openedViaKeyboard,
36
+ prevIsMenuOpenRef
37
+ }) => {
38
+ /**
39
+ * NOTE: do not add `currentUserIntent` to dependency array as it causes unnecessary re-renders and messes with the user intent state
40
+ */
41
+ useEffect(() => {
42
+ var _api$userIntent;
43
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine) {
44
+ return;
45
+ }
46
+
47
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
48
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
49
+ var _api$analytics;
50
+ api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent({
51
+ action: ACTION.OPENED,
52
+ actionSubject: ACTION_SUBJECT.BLOCK_MENU,
53
+ eventType: EVENT_TYPE.UI,
54
+ attributes: {
55
+ inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
56
+ }
57
+ });
58
+ }
59
+
60
+ // Update the previous state
61
+ prevIsMenuOpenRef.current = isMenuOpen;
62
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
63
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, openedViaKeyboard, prevIsMenuOpenRef]);
64
+ }, ({
65
+ api,
66
+ isMenuOpen,
67
+ menuTriggerBy,
68
+ selectedByShortcutOrDragHandle,
69
+ hasFocus,
70
+ shouldShowBlockMenuForEmptyLine,
71
+ currentUserIntent,
72
+ openedViaKeyboard,
73
+ prevIsMenuOpenRef
74
+ }) => {
75
+ useEffect(() => {
76
+ var _api$userIntent2;
77
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
78
+ return;
79
+ }
80
+
81
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
82
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
83
+ var _api$analytics2;
84
+ api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent({
85
+ action: ACTION.OPENED,
86
+ actionSubject: ACTION_SUBJECT.BLOCK_MENU,
87
+ eventType: EVENT_TYPE.UI,
88
+ attributes: {
89
+ inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
90
+ }
91
+ });
92
+ }
93
+
94
+ // Update the previous state
95
+ prevIsMenuOpenRef.current = isMenuOpen;
96
+ api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.commands.setCurrentUserIntent('blockMenuOpen'));
97
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard, prevIsMenuOpenRef]);
98
+ });
26
99
  const BlockMenuContent = ({
27
100
  api,
28
101
  setRef
@@ -85,30 +158,20 @@ const BlockMenu = ({
85
158
  // hasSelection true, always show block menu
86
159
  // hasSelection false, only show block menu when empty line experiment is enabled
87
160
  const shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true);
88
- const selectedByShortcutOrDragHandle = isSelectedViaDragHandle || openedViaKeyboard && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
89
- useEffect(() => {
90
- var _api$userIntent;
91
- if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
92
- return;
93
- }
161
+ const selectedByShortcutOrDragHandle = !!isSelectedViaDragHandle || !!openedViaKeyboard && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
94
162
 
95
- // Fire analytics event when block menu opens (only on first transition from closed to open)
96
- if (!prevIsMenuOpenRef.current && isMenuOpen) {
97
- var _api$analytics;
98
- api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions.fireAnalyticsEvent({
99
- action: ACTION.OPENED,
100
- actionSubject: ACTION_SUBJECT.BLOCK_MENU,
101
- eventType: EVENT_TYPE.UI,
102
- attributes: {
103
- inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
104
- }
105
- });
106
- }
107
-
108
- // Update the previous state
109
- prevIsMenuOpenRef.current = isMenuOpen;
110
- api === null || api === void 0 ? void 0 : api.core.actions.execute(api === null || api === void 0 ? void 0 : (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
111
- }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard]);
163
+ // Use conditional hook based on feature flag
164
+ useConditionalBlockMenuEffect({
165
+ api,
166
+ isMenuOpen,
167
+ menuTriggerBy,
168
+ selectedByShortcutOrDragHandle,
169
+ hasFocus,
170
+ shouldShowBlockMenuForEmptyLine,
171
+ currentUserIntent: fg('platform_editor_toolbar_aifc_user_intent_fix') ? undefined : currentUserIntent,
172
+ openedViaKeyboard,
173
+ prevIsMenuOpenRef
174
+ });
112
175
  if (!isMenuOpen) {
113
176
  return null;
114
177
  }
@@ -116,14 +179,14 @@ const BlockMenu = ({
116
179
  api === null || api === void 0 ? void 0 : api.core.actions.execute(({
117
180
  tr
118
181
  }) => {
119
- var _api$blockControls, _api$userIntent2;
182
+ var _api$blockControls, _api$userIntent3;
120
183
  api === null || api === void 0 ? void 0 : (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.commands.toggleBlockMenu({
121
184
  closeMenu: true
122
185
  })({
123
186
  tr
124
187
  });
125
188
  onDropdownOpenChanged(false);
126
- api === null || api === void 0 ? void 0 : (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
189
+ api === null || api === void 0 ? void 0 : (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 ? void 0 : _api$userIntent3.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
127
190
  tr
128
191
  });
129
192
  return tr;
@@ -139,10 +202,10 @@ const BlockMenu = ({
139
202
  }
140
203
  };
141
204
  if (targetHandleRef instanceof HTMLElement) {
142
- var _api$analytics2;
205
+ var _api$analytics3;
143
206
  return /*#__PURE__*/React.createElement(ErrorBoundary, {
144
207
  component: ACTION_SUBJECT.BLOCK_MENU,
145
- dispatchAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
208
+ dispatchAnalyticsEvent: api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
146
209
  fallbackComponent: null
147
210
  }, /*#__PURE__*/React.createElement(PopupWithListeners, {
148
211
  alignX: 'right',
@@ -41,8 +41,8 @@ const CopyLinkDropdownItemContent = ({
41
41
  return tr;
42
42
  });
43
43
  onDropdownOpenChanged(false);
44
- return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
45
- }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api, onDropdownOpenChanged]);
44
+ return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api);
45
+ }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api, onDropdownOpenChanged]);
46
46
  const checkIsNestedNode = useCallback(() => {
47
47
  var _api$selection, _api$selection$shared, _api$selection$shared2, _api$blockControls2, _api$blockControls2$s, _api$blockControls2$s2;
48
48
  const selection = api === null || api === void 0 ? void 0 : (_api$selection = api.selection) === null || _api$selection === void 0 ? void 0 : (_api$selection$shared = _api$selection.sharedState) === null || _api$selection$shared === void 0 ? void 0 : (_api$selection$shared2 = _api$selection$shared.currentState()) === null || _api$selection$shared2 === void 0 ? void 0 : _api$selection$shared2.selection;
@@ -1,7 +1,8 @@
1
+ import { DEFAULT_BLOCK_LINK_HASH_PREFIX } from '@atlaskit/editor-common/block-menu';
1
2
  import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
2
3
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
3
4
  import { CellSelection } from '@atlaskit/editor-tables';
4
- export const copyLink = async (getLinkPath, blockQueryParam = 'block', api) => {
5
+ export const copyLink = async (getLinkPath, blockLinkHashPrefix = DEFAULT_BLOCK_LINK_HASH_PREFIX, api) => {
5
6
  try {
6
7
  var _api$selection, _api$selection$shared;
7
8
  let node;
@@ -21,7 +22,8 @@ export const copyLink = async (getLinkPath, blockQueryParam = 'block', api) => {
21
22
  return false;
22
23
  }
23
24
  const url = new URL(location.origin + path);
24
- url.searchParams.set(blockQueryParam, node.attrs.localId);
25
+ // append the localId as a hash fragment in the form #block-{localId}
26
+ url.hash = `${blockLinkHashPrefix}${node.attrs.localId}`;
25
27
  const href = url.toString();
26
28
  await copyToClipboard(href);
27
29
  return true;
@@ -12,6 +12,8 @@ import { Popup } from '@atlaskit/editor-common/ui';
12
12
  import { OutsideClickTargetRefContext, withReactEditorViewOuterListeners } from '@atlaskit/editor-common/ui-react';
13
13
  import { akEditorFloatingOverlapPanelZIndex } from '@atlaskit/editor-shared-styles';
14
14
  import { ToolbarDropdownItem, ToolbarDropdownItemSection, ToolbarNestedDropdownMenu } from '@atlaskit/editor-toolbar';
15
+ import { fg } from '@atlaskit/platform-feature-flags';
16
+ import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react';
15
17
  import { Box } from '@atlaskit/primitives/compiled';
16
18
  import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure';
17
19
  import { useBlockMenu } from './block-menu-provider';
@@ -23,10 +25,81 @@ var styles = {
23
25
  var DEFAULT_MENU_WIDTH = 230;
24
26
  var DRAG_HANDLE_OFFSET_PADDING = 5;
25
27
  var PopupWithListeners = withReactEditorViewOuterListeners(Popup);
26
- var BlockMenuContent = function BlockMenuContent(_ref) {
27
- var _api$blockMenu;
28
+ var useConditionalBlockMenuEffect = conditionalHooksFactory(function () {
29
+ return fg('platform_editor_toolbar_aifc_user_intent_fix');
30
+ }, function (_ref) {
28
31
  var api = _ref.api,
29
- setRef = _ref.setRef;
32
+ isMenuOpen = _ref.isMenuOpen,
33
+ menuTriggerBy = _ref.menuTriggerBy,
34
+ selectedByShortcutOrDragHandle = _ref.selectedByShortcutOrDragHandle,
35
+ hasFocus = _ref.hasFocus,
36
+ shouldShowBlockMenuForEmptyLine = _ref.shouldShowBlockMenuForEmptyLine,
37
+ openedViaKeyboard = _ref.openedViaKeyboard,
38
+ prevIsMenuOpenRef = _ref.prevIsMenuOpenRef;
39
+ /**
40
+ * NOTE: do not add `currentUserIntent` to dependency array as it causes unnecessary re-renders and messes with the user intent state
41
+ */
42
+ useEffect(function () {
43
+ var _api$userIntent;
44
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine) {
45
+ return;
46
+ }
47
+
48
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
49
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
50
+ var _api$analytics;
51
+ api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
52
+ action: ACTION.OPENED,
53
+ actionSubject: ACTION_SUBJECT.BLOCK_MENU,
54
+ eventType: EVENT_TYPE.UI,
55
+ attributes: {
56
+ inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
57
+ }
58
+ });
59
+ }
60
+
61
+ // Update the previous state
62
+ prevIsMenuOpenRef.current = isMenuOpen;
63
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
64
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, openedViaKeyboard, prevIsMenuOpenRef]);
65
+ }, function (_ref2) {
66
+ var api = _ref2.api,
67
+ isMenuOpen = _ref2.isMenuOpen,
68
+ menuTriggerBy = _ref2.menuTriggerBy,
69
+ selectedByShortcutOrDragHandle = _ref2.selectedByShortcutOrDragHandle,
70
+ hasFocus = _ref2.hasFocus,
71
+ shouldShowBlockMenuForEmptyLine = _ref2.shouldShowBlockMenuForEmptyLine,
72
+ currentUserIntent = _ref2.currentUserIntent,
73
+ openedViaKeyboard = _ref2.openedViaKeyboard,
74
+ prevIsMenuOpenRef = _ref2.prevIsMenuOpenRef;
75
+ useEffect(function () {
76
+ var _api$userIntent2;
77
+ if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
78
+ return;
79
+ }
80
+
81
+ // Fire analytics event when block menu opens (only on first transition from closed to open)
82
+ if (!prevIsMenuOpenRef.current && isMenuOpen) {
83
+ var _api$analytics2;
84
+ api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 || _api$analytics2.actions.fireAnalyticsEvent({
85
+ action: ACTION.OPENED,
86
+ actionSubject: ACTION_SUBJECT.BLOCK_MENU,
87
+ eventType: EVENT_TYPE.UI,
88
+ attributes: {
89
+ inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
90
+ }
91
+ });
92
+ }
93
+
94
+ // Update the previous state
95
+ prevIsMenuOpenRef.current = isMenuOpen;
96
+ api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 ? void 0 : _api$userIntent2.commands.setCurrentUserIntent('blockMenuOpen'));
97
+ }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard, prevIsMenuOpenRef]);
98
+ });
99
+ var BlockMenuContent = function BlockMenuContent(_ref3) {
100
+ var _api$blockMenu;
101
+ var api = _ref3.api,
102
+ setRef = _ref3.setRef;
30
103
  var blockMenuComponents = api === null || api === void 0 || (_api$blockMenu = api.blockMenu) === null || _api$blockMenu === void 0 ? void 0 : _api$blockMenu.actions.getBlockMenuComponents();
31
104
  var setOutsideClickTargetRef = useContext(OutsideClickTargetRefContext);
32
105
  var ref = function ref(el) {
@@ -55,13 +128,13 @@ var BlockMenuContent = function BlockMenuContent(_ref) {
55
128
  }
56
129
  }));
57
130
  };
58
- var BlockMenu = function BlockMenu(_ref2) {
59
- var _editorView$dom, _ref3, _editorView$hasFocus;
60
- var editorView = _ref2.editorView,
61
- api = _ref2.api,
62
- mountTo = _ref2.mountTo,
63
- boundariesElement = _ref2.boundariesElement,
64
- scrollableElement = _ref2.scrollableElement;
131
+ var BlockMenu = function BlockMenu(_ref4) {
132
+ var _editorView$dom, _ref5, _editorView$hasFocus;
133
+ var editorView = _ref4.editorView,
134
+ api = _ref4.api,
135
+ mountTo = _ref4.mountTo,
136
+ boundariesElement = _ref4.boundariesElement,
137
+ scrollableElement = _ref4.scrollableElement;
65
138
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['blockControls', 'userIntent'], function (states) {
66
139
  var _states$blockControls, _states$blockControls2, _states$blockControls3, _states$userIntentSta, _states$blockControls4;
67
140
  return {
@@ -82,49 +155,39 @@ var BlockMenu = function BlockMenu(_ref2) {
82
155
  var targetHandleRef = editorView === null || editorView === void 0 || (_editorView$dom = editorView.dom) === null || _editorView$dom === void 0 ? void 0 : _editorView$dom.querySelector(DRAG_HANDLE_SELECTOR);
83
156
  var prevIsMenuOpenRef = useRef(false);
84
157
  var popupRef = useRef(undefined);
85
- var hasFocus = expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref3 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef || popupRef.current && (popupRef.current.contains(document.activeElement) || popupRef.current === document.activeElement)) !== null && _ref3 !== void 0 ? _ref3 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
158
+ var hasFocus = expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true) ? (_ref5 = (editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) || document.activeElement === targetHandleRef || popupRef.current && (popupRef.current.contains(document.activeElement) || popupRef.current === document.activeElement)) !== null && _ref5 !== void 0 ? _ref5 : false : (_editorView$hasFocus = editorView === null || editorView === void 0 ? void 0 : editorView.hasFocus()) !== null && _editorView$hasFocus !== void 0 ? _editorView$hasFocus : false;
86
159
  var hasSelection = !!editorView && !editorView.state.selection.empty;
87
160
  // hasSelection true, always show block menu
88
161
  // hasSelection false, only show block menu when empty line experiment is enabled
89
162
  var shouldShowBlockMenuForEmptyLine = hasSelection || !hasSelection && expValEqualsNoExposure('platform_editor_block_menu_empty_line', 'isEnabled', true);
90
- var selectedByShortcutOrDragHandle = isSelectedViaDragHandle || openedViaKeyboard && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
91
- useEffect(function () {
92
- var _api$userIntent;
93
- if (!isMenuOpen || !menuTriggerBy || !selectedByShortcutOrDragHandle || !hasFocus || !shouldShowBlockMenuForEmptyLine || ['resizing', 'dragging'].includes(currentUserIntent || '')) {
94
- return;
95
- }
163
+ var selectedByShortcutOrDragHandle = !!isSelectedViaDragHandle || !!openedViaKeyboard && expValEqualsNoExposure('platform_editor_block_menu_keyboard_navigation', 'isEnabled', true);
96
164
 
97
- // Fire analytics event when block menu opens (only on first transition from closed to open)
98
- if (!prevIsMenuOpenRef.current && isMenuOpen) {
99
- var _api$analytics;
100
- api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 || _api$analytics.actions.fireAnalyticsEvent({
101
- action: ACTION.OPENED,
102
- actionSubject: ACTION_SUBJECT.BLOCK_MENU,
103
- eventType: EVENT_TYPE.UI,
104
- attributes: {
105
- inputMethod: openedViaKeyboard ? INPUT_METHOD.KEYBOARD : INPUT_METHOD.MOUSE
106
- }
107
- });
108
- }
109
-
110
- // Update the previous state
111
- prevIsMenuOpenRef.current = isMenuOpen;
112
- api === null || api === void 0 || api.core.actions.execute(api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.commands.setCurrentUserIntent('blockMenuOpen'));
113
- }, [api, isMenuOpen, menuTriggerBy, selectedByShortcutOrDragHandle, hasFocus, shouldShowBlockMenuForEmptyLine, currentUserIntent, openedViaKeyboard]);
165
+ // Use conditional hook based on feature flag
166
+ useConditionalBlockMenuEffect({
167
+ api: api,
168
+ isMenuOpen: isMenuOpen,
169
+ menuTriggerBy: menuTriggerBy,
170
+ selectedByShortcutOrDragHandle: selectedByShortcutOrDragHandle,
171
+ hasFocus: hasFocus,
172
+ shouldShowBlockMenuForEmptyLine: shouldShowBlockMenuForEmptyLine,
173
+ currentUserIntent: fg('platform_editor_toolbar_aifc_user_intent_fix') ? undefined : currentUserIntent,
174
+ openedViaKeyboard: openedViaKeyboard,
175
+ prevIsMenuOpenRef: prevIsMenuOpenRef
176
+ });
114
177
  if (!isMenuOpen) {
115
178
  return null;
116
179
  }
117
180
  var closeMenu = function closeMenu() {
118
- api === null || api === void 0 || api.core.actions.execute(function (_ref4) {
119
- var _api$blockControls, _api$userIntent2;
120
- var tr = _ref4.tr;
181
+ api === null || api === void 0 || api.core.actions.execute(function (_ref6) {
182
+ var _api$blockControls, _api$userIntent3;
183
+ var tr = _ref6.tr;
121
184
  api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 || _api$blockControls.commands.toggleBlockMenu({
122
185
  closeMenu: true
123
186
  })({
124
187
  tr: tr
125
188
  });
126
189
  onDropdownOpenChanged(false);
127
- api === null || api === void 0 || (_api$userIntent2 = api.userIntent) === null || _api$userIntent2 === void 0 || _api$userIntent2.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
190
+ api === null || api === void 0 || (_api$userIntent3 = api.userIntent) === null || _api$userIntent3 === void 0 || _api$userIntent3.commands.setCurrentUserIntent(currentUserIntent === 'blockMenuOpen' ? 'default' : currentUserIntent || 'default')({
128
191
  tr: tr
129
192
  });
130
193
  return tr;
@@ -140,10 +203,10 @@ var BlockMenu = function BlockMenu(_ref2) {
140
203
  }
141
204
  };
142
205
  if (targetHandleRef instanceof HTMLElement) {
143
- var _api$analytics2;
206
+ var _api$analytics3;
144
207
  return /*#__PURE__*/React.createElement(ErrorBoundary, {
145
208
  component: ACTION_SUBJECT.BLOCK_MENU,
146
- dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions.fireAnalyticsEvent,
209
+ dispatchAnalyticsEvent: api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions.fireAnalyticsEvent,
147
210
  fallbackComponent: null
148
211
  }, /*#__PURE__*/React.createElement(PopupWithListeners, {
149
212
  alignX: 'right',
@@ -37,8 +37,8 @@ var CopyLinkDropdownItemContent = function CopyLinkDropdownItemContent(_ref) {
37
37
  return tr;
38
38
  });
39
39
  onDropdownOpenChanged(false);
40
- return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api);
41
- }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockQueryParam, api, onDropdownOpenChanged]);
40
+ return copyLink(config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api);
41
+ }, [config === null || config === void 0 ? void 0 : config.getLinkPath, config === null || config === void 0 ? void 0 : config.blockLinkHashPrefix, api, onDropdownOpenChanged]);
42
42
  var checkIsNestedNode = useCallback(function () {
43
43
  var _api$selection, _api$blockControls2;
44
44
  var selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState) === null || _api$selection === void 0 || (_api$selection = _api$selection.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
@@ -1,11 +1,12 @@
1
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ import { DEFAULT_BLOCK_LINK_HASH_PREFIX } from '@atlaskit/editor-common/block-menu';
3
4
  import { copyToClipboard } from '@atlaskit/editor-common/clipboard';
4
5
  import { NodeSelection, TextSelection } from '@atlaskit/editor-prosemirror/state';
5
6
  import { CellSelection } from '@atlaskit/editor-tables';
6
7
  export var copyLink = /*#__PURE__*/function () {
7
8
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(getLinkPath) {
8
- var blockQueryParam,
9
+ var blockLinkHashPrefix,
9
10
  api,
10
11
  _api$selection,
11
12
  node,
@@ -17,7 +18,7 @@ export var copyLink = /*#__PURE__*/function () {
17
18
  return _regeneratorRuntime.wrap(function _callee$(_context) {
18
19
  while (1) switch (_context.prev = _context.next) {
19
20
  case 0:
20
- blockQueryParam = _args.length > 1 && _args[1] !== undefined ? _args[1] : 'block';
21
+ blockLinkHashPrefix = _args.length > 1 && _args[1] !== undefined ? _args[1] : DEFAULT_BLOCK_LINK_HASH_PREFIX;
21
22
  api = _args.length > 2 ? _args[2] : undefined;
22
23
  _context.prev = 2;
23
24
  selection = api === null || api === void 0 || (_api$selection = api.selection) === null || _api$selection === void 0 || (_api$selection = _api$selection.sharedState.currentState()) === null || _api$selection === void 0 ? void 0 : _api$selection.selection;
@@ -41,8 +42,8 @@ export var copyLink = /*#__PURE__*/function () {
41
42
  }
42
43
  return _context.abrupt("return", false);
43
44
  case 10:
44
- url = new URL(location.origin + path);
45
- url.searchParams.set(blockQueryParam, node.attrs.localId);
45
+ url = new URL(location.origin + path); // append the localId as a hash fragment in the form #block-{localId}
46
+ url.hash = "".concat(blockLinkHashPrefix).concat(node.attrs.localId);
46
47
  href = url.toString();
47
48
  _context.next = 15;
48
49
  return copyToClipboard(href);
@@ -25,9 +25,10 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
25
25
  }>;
26
26
  export type BlockMenuPluginOptions = {
27
27
  /**
28
- * Optional query parameter name used for block-specific URL to create a deep link to specific block
28
+ * Optional hash prefix used for block-specific URL to create a deep link to specific block
29
+ * Default value from DEFAULT_BLOCK_LINK_HASH_PREFIX in @atlaskit/editor-common/block-menu
29
30
  */
30
- blockQueryParam?: string;
31
+ blockLinkHashPrefix?: string;
31
32
  /**
32
33
  * Optional function to retrieve the current link path for the editor context.
33
34
  * @returns The current link path as a string, or null if no path is available
@@ -1,3 +1,3 @@
1
1
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { BlockMenuPlugin } from '../../blockMenuPluginType';
3
- export declare const copyLink: (getLinkPath?: () => string | null, blockQueryParam?: string, api?: ExtractInjectionAPI<BlockMenuPlugin>) => Promise<boolean>;
3
+ export declare const copyLink: (getLinkPath?: () => string | null, blockLinkHashPrefix?: string, api?: ExtractInjectionAPI<BlockMenuPlugin>) => Promise<boolean>;
@@ -25,9 +25,10 @@ export type BlockMenuPlugin = NextEditorPlugin<'blockMenu', {
25
25
  }>;
26
26
  export type BlockMenuPluginOptions = {
27
27
  /**
28
- * Optional query parameter name used for block-specific URL to create a deep link to specific block
28
+ * Optional hash prefix used for block-specific URL to create a deep link to specific block
29
+ * Default value from DEFAULT_BLOCK_LINK_HASH_PREFIX in @atlaskit/editor-common/block-menu
29
30
  */
30
- blockQueryParam?: string;
31
+ blockLinkHashPrefix?: string;
31
32
  /**
32
33
  * Optional function to retrieve the current link path for the editor context.
33
34
  * @returns The current link path as a string, or null if no path is available
@@ -1,3 +1,3 @@
1
1
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { BlockMenuPlugin } from '../../blockMenuPluginType';
3
- export declare const copyLink: (getLinkPath?: () => string | null, blockQueryParam?: string, api?: ExtractInjectionAPI<BlockMenuPlugin>) => Promise<boolean>;
3
+ export declare const copyLink: (getLinkPath?: () => string | null, blockLinkHashPrefix?: string, api?: ExtractInjectionAPI<BlockMenuPlugin>) => Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-block-menu",
3
- "version": "4.0.25",
3
+ "version": "5.0.1",
4
4
  "description": "BlockMenu plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,24 +31,25 @@
31
31
  "@atlaskit/css": "^0.15.0",
32
32
  "@atlaskit/dropdown-menu": "^16.3.0",
33
33
  "@atlaskit/editor-plugin-analytics": "^6.2.0",
34
- "@atlaskit/editor-plugin-block-controls": "^7.3.0",
34
+ "@atlaskit/editor-plugin-block-controls": "^7.4.0",
35
35
  "@atlaskit/editor-plugin-decorations": "^6.1.0",
36
36
  "@atlaskit/editor-plugin-selection": "^6.1.0",
37
37
  "@atlaskit/editor-plugin-user-intent": "^4.0.0",
38
38
  "@atlaskit/editor-prosemirror": "7.0.0",
39
- "@atlaskit/editor-shared-styles": "^3.7.0",
39
+ "@atlaskit/editor-shared-styles": "^3.8.0",
40
40
  "@atlaskit/editor-tables": "^2.9.0",
41
- "@atlaskit/editor-toolbar": "^0.15.0",
41
+ "@atlaskit/editor-toolbar": "^0.16.0",
42
42
  "@atlaskit/icon": "^28.5.0",
43
43
  "@atlaskit/icon-lab": "^5.10.0",
44
44
  "@atlaskit/platform-feature-flags": "^1.1.0",
45
+ "@atlaskit/platform-feature-flags-react": "^0.3.0",
45
46
  "@atlaskit/primitives": "^16.0.0",
46
- "@atlaskit/tmp-editor-statsig": "^13.13.0",
47
+ "@atlaskit/tmp-editor-statsig": "^13.18.0",
47
48
  "@atlaskit/tokens": "^7.0.0",
48
49
  "@babel/runtime": "^7.0.0"
49
50
  },
50
51
  "peerDependencies": {
51
- "@atlaskit/editor-common": "^110.14.0",
52
+ "@atlaskit/editor-common": "^110.16.0",
52
53
  "react": "^18.2.0",
53
54
  "react-intl-next": "npm:react-intl@^5.18.1"
54
55
  },
@@ -109,6 +110,9 @@
109
110
  },
110
111
  "platform_editor_block_menu_shouldfitcontainer": {
111
112
  "type": "boolean"
113
+ },
114
+ "platform_editor_toolbar_aifc_user_intent_fix": {
115
+ "type": "boolean"
112
116
  }
113
117
  }
114
118
  }