@atlaskit/editor-plugin-find-replace 21.0.1 → 21.1.0

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 (29) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/findReplacePlugin.js +12 -2
  3. package/dist/cjs/pm-plugins/commands-with-analytics.js +9 -2
  4. package/dist/cjs/pm-plugins/keymap.js +6 -6
  5. package/dist/cjs/pm-plugins/view-mode-shortcut.js +68 -0
  6. package/dist/cjs/ui/FindReplace.js +20 -4
  7. package/dist/cjs/ui/FindReplaceDropDownOrToolbarButtonWithState.js +18 -2
  8. package/dist/cjs/ui/Replace.js +13 -6
  9. package/dist/es2019/findReplacePlugin.js +10 -2
  10. package/dist/es2019/pm-plugins/commands-with-analytics.js +20 -10
  11. package/dist/es2019/pm-plugins/keymap.js +6 -6
  12. package/dist/es2019/pm-plugins/view-mode-shortcut.js +61 -0
  13. package/dist/es2019/ui/FindReplace.js +21 -5
  14. package/dist/es2019/ui/FindReplaceDropDownOrToolbarButtonWithState.js +12 -2
  15. package/dist/es2019/ui/Replace.js +12 -6
  16. package/dist/esm/findReplacePlugin.js +12 -2
  17. package/dist/esm/pm-plugins/commands-with-analytics.js +10 -2
  18. package/dist/esm/pm-plugins/keymap.js +6 -6
  19. package/dist/esm/pm-plugins/view-mode-shortcut.js +63 -0
  20. package/dist/esm/ui/FindReplace.js +22 -5
  21. package/dist/esm/ui/FindReplaceDropDownOrToolbarButtonWithState.js +18 -2
  22. package/dist/esm/ui/Replace.js +14 -7
  23. package/dist/types/findReplacePluginType.d.ts +2 -0
  24. package/dist/types/pm-plugins/commands-with-analytics.d.ts +8 -2
  25. package/dist/types/pm-plugins/keymap.d.ts +2 -1
  26. package/dist/types/pm-plugins/view-mode-shortcut.d.ts +10 -0
  27. package/dist/types/ui/FindReplace.d.ts +5 -0
  28. package/dist/types/ui/Replace.d.ts +6 -0
  29. package/package.json +6 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @atlaskit/editor-plugin-find-replace
2
2
 
3
+ ## 21.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`111eaadd44c1c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/111eaadd44c1c) -
8
+ EDITOR-8995: Make the editor find dialog usable in live view. The find dialog now accepts an
9
+ `allowReplace` prop, and hides the replace label, field, replacement count message, both replace
10
+ buttons and the horizontal rule when it is false. It also names the dialog "Find" instead of "Find
11
+ and Replace" in that state. The find plugin derives `allowReplace` from the `editorViewMode`
12
+ shared state, so view mode never offers replace. A new ProseMirror plugin opens the dialog on
13
+ `Mod-f` in view mode, where no keymap fires, behind the `platform_editor_collapsible_headings`
14
+ experiment. The `activated` analytics event gains an `editorViewMode` attribute.
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+
3
20
  ## 21.0.1
4
21
 
5
22
  ### Patch Changes
@@ -9,6 +9,7 @@ var _react = _interopRequireDefault(require("react"));
9
9
  var _analytics = require("@atlaskit/editor-common/analytics");
10
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
11
  var _types = require("@atlaskit/editor-common/types");
12
+ var _unsafeExpValNoExposure = require("@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure");
12
13
  var _fg = require("@atlaskit/platform-feature-flags/fg");
13
14
  var _editorExperiment = require("@atlaskit/tmp-editor-statsig/editor-experiment");
14
15
  var _commands = require("./pm-plugins/commands");
@@ -16,6 +17,7 @@ var _commandsWithAnalytics = require("./pm-plugins/commands-with-analytics");
16
17
  var _keymap = _interopRequireDefault(require("./pm-plugins/keymap"));
17
18
  var _main = require("./pm-plugins/main");
18
19
  var _pluginKey = require("./pm-plugins/plugin-key");
20
+ var _viewModeShortcut = require("./pm-plugins/view-mode-shortcut");
19
21
  var _FindReplaceDropDownOrToolbarButtonWithState = _interopRequireDefault(require("./ui/FindReplaceDropDownOrToolbarButtonWithState"));
20
22
  var findReplacePlugin = exports.findReplacePlugin = function findReplacePlugin(_ref) {
21
23
  var _api$primaryToolbar;
@@ -77,9 +79,17 @@ var findReplacePlugin = exports.findReplacePlugin = function findReplacePlugin(_
77
79
  name: 'findReplaceKeymap',
78
80
  plugin: function plugin() {
79
81
  var _api$analytics;
80
- return (0, _keymap.default)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
82
+ return (0, _keymap.default)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode);
81
83
  }
82
84
  }];
85
+ if (api !== null && api !== void 0 && api.editorViewMode && (0, _unsafeExpValNoExposure.UNSAFE_expValNoExposure)('platform_editor_collapsible_headings', 'isEnabled', false)) {
86
+ plugins.push({
87
+ name: 'findReplaceViewModeShortcut',
88
+ plugin: function plugin() {
89
+ return (0, _viewModeShortcut.viewModeShortcutPlugin)(api);
90
+ }
91
+ });
92
+ }
83
93
  if ((0, _editorExperiment.editorExperiment)('platform_editor_controls', 'variant1', {
84
94
  exposure: false
85
95
  })) {
@@ -138,7 +148,7 @@ var findReplacePlugin = exports.findReplacePlugin = function findReplacePlugin(_
138
148
  dispatch = _editorViewRef$curren.dispatch;
139
149
  if (api !== null && api !== void 0 && (_api$analytics2 = api.analytics) !== null && _api$analytics2 !== void 0 && _api$analytics2.actions) {
140
150
  var _api$analytics3;
141
- (0, _commandsWithAnalytics.activateWithAnalytics)(api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions)({
151
+ (0, _commandsWithAnalytics.activateWithAnalytics)(api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
142
152
  triggerMethod: triggerMethod || _analytics.TRIGGER_METHOD.EXTERNAL
143
153
  })(state, dispatch);
144
154
  } else {
@@ -8,17 +8,24 @@ var _analytics = require("@atlaskit/editor-common/analytics");
8
8
  var _editorAnalytics = require("@atlaskit/editor-common/editor-analytics");
9
9
  var _state = require("@atlaskit/editor-prosemirror/state");
10
10
  var _commands = require("./commands");
11
- var activateWithAnalytics = exports.activateWithAnalytics = function activateWithAnalytics(editorAnalyticsAPI) {
11
+ /**
12
+ * Hosts that do not install `editorViewMode` are always editing, so the attribute
13
+ * falls back to `edit` when the api is absent.
14
+ */
15
+
16
+ var activateWithAnalytics = exports.activateWithAnalytics = function activateWithAnalytics(editorAnalyticsAPI, editorViewModeAPI) {
12
17
  return function (_ref) {
13
18
  var triggerMethod = _ref.triggerMethod;
14
19
  return (0, _editorAnalytics.withAnalytics)(editorAnalyticsAPI, function (state) {
20
+ var _editorViewModeAPI$sh, _editorViewModeAPI$sh2;
15
21
  return {
16
22
  eventType: _analytics.EVENT_TYPE.UI,
17
23
  action: _analytics.ACTION.ACTIVATED,
18
24
  actionSubject: _analytics.ACTION_SUBJECT.FIND_REPLACE_DIALOG,
19
25
  attributes: {
20
26
  inputMethod: state.selection instanceof _state.TextSelection && !state.selection.empty ? _analytics.INPUT_METHOD.PREFILL : _analytics.INPUT_METHOD.KEYBOARD,
21
- triggerMethod: triggerMethod
27
+ triggerMethod: triggerMethod,
28
+ editorViewMode: (_editorViewModeAPI$sh = editorViewModeAPI === null || editorViewModeAPI === void 0 || (_editorViewModeAPI$sh2 = editorViewModeAPI.sharedState.currentState()) === null || _editorViewModeAPI$sh2 === void 0 ? void 0 : _editorViewModeAPI$sh2.mode) !== null && _editorViewModeAPI$sh !== void 0 ? _editorViewModeAPI$sh : 'edit'
22
29
  }
23
30
  };
24
31
  })((0, _commands.activate)());
@@ -8,19 +8,19 @@ var _analytics = require("@atlaskit/editor-common/analytics");
8
8
  var _keymaps = require("@atlaskit/editor-common/keymaps");
9
9
  var _keymap = require("@atlaskit/editor-prosemirror/keymap");
10
10
  var _commandsWithAnalytics = require("./commands-with-analytics");
11
- var activateFindReplace = function activateFindReplace(editorAnalyticsAPI) {
11
+ var activateFindReplace = function activateFindReplace(editorAnalyticsAPI, editorViewModeAPI) {
12
12
  return function (state, dispatch) {
13
- (0, _commandsWithAnalytics.activateWithAnalytics)(editorAnalyticsAPI)({
13
+ (0, _commandsWithAnalytics.activateWithAnalytics)(editorAnalyticsAPI, editorViewModeAPI)({
14
14
  triggerMethod: _analytics.TRIGGER_METHOD.SHORTCUT
15
15
  })(state, dispatch);
16
16
  return true;
17
17
  };
18
18
  };
19
- var keymapPlugin = function keymapPlugin(editorAnalyticsAPI) {
19
+ var keymapPlugin = function keymapPlugin(editorAnalyticsAPI, editorViewModeAPI) {
20
20
  var list = {};
21
- // Ignored via go/ees005
22
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
23
- (0, _keymaps.bindKeymapWithCommand)(_keymaps.find.common, activateFindReplace(editorAnalyticsAPI), list);
21
+ if (_keymaps.find.common) {
22
+ (0, _keymaps.bindKeymapWithCommand)(_keymaps.find.common, activateFindReplace(editorAnalyticsAPI, editorViewModeAPI), list);
23
+ }
24
24
  return (0, _keymap.keymap)(list);
25
25
  };
26
26
  var _default = exports.default = keymapPlugin;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.viewModeShortcutPlugin = void 0;
7
+ var _bindEventListener = require("bind-event-listener");
8
+ var _analytics = require("@atlaskit/editor-common/analytics");
9
+ var _keymaps = require("@atlaskit/editor-common/keymaps");
10
+ var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
+ var _keymap = require("@atlaskit/editor-prosemirror/keymap");
12
+ var _commandsWithAnalytics = require("./commands-with-analytics");
13
+ /**
14
+ * Whether the event came from a field the user is typing into. `Mod-f` belongs to
15
+ * that field, not to us.
16
+ */
17
+ var isFromTextEntry = function isFromTextEntry(event) {
18
+ var target = event.target;
19
+ return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
20
+ };
21
+ var activateInViewMode = function activateInViewMode(api) {
22
+ return function (state, dispatch) {
23
+ var _api$editorViewMode, _api$analytics;
24
+ // In edit mode `./keymap.ts` already handles `Mod-f`. Handling it here as well
25
+ // would activate the dialog twice from a single keypress.
26
+ if ((api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) !== 'view') {
27
+ return false;
28
+ }
29
+ (0, _commandsWithAnalytics.activateWithAnalytics)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
30
+ triggerMethod: _analytics.TRIGGER_METHOD.SHORTCUT
31
+ })(state, dispatch);
32
+ return true;
33
+ };
34
+ };
35
+
36
+ /**
37
+ * Opens the find dialog on `Mod-f` while the editor is in view mode.
38
+ *
39
+ * The listener is bound on the document so that it still fires in view mode, where
40
+ * ProseMirror delivers the keydown to neither `keymap()` nor `handleDOMEvents`.
41
+ */
42
+ var viewModeShortcutPlugin = exports.viewModeShortcutPlugin = function viewModeShortcutPlugin(api) {
43
+ var bindings = {};
44
+ if (_keymaps.find.common) {
45
+ (0, _keymaps.bindKeymapWithCommand)(_keymaps.find.common, activateInViewMode(api), bindings);
46
+ }
47
+ var handleKeydown = (0, _keymap.keydownHandler)(bindings);
48
+ return new _safePlugin.SafePlugin({
49
+ view: function view(_view) {
50
+ var unbind = (0, _bindEventListener.bind)(_view.root, {
51
+ type: 'keydown',
52
+ listener: function listener(event) {
53
+ // `view.root` is `Document | ShadowRoot`, so the binding widens the event.
54
+ if (!(event instanceof KeyboardEvent) || isFromTextEntry(event)) {
55
+ return;
56
+ }
57
+ if (handleKeydown(_view, event)) {
58
+ // Without this the browser find bar opens on top of our dialog.
59
+ event.preventDefault();
60
+ }
61
+ }
62
+ });
63
+ return {
64
+ destroy: unbind
65
+ };
66
+ }
67
+ });
68
+ };
@@ -22,6 +22,17 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
22
22
  * @jsxRuntime classic
23
23
  * @jsx jsx
24
24
  */ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
25
+ // Magic number taken from ./FindReplaceToolbarButton.tsx
26
+ var dropdownWidth = 382;
27
+
28
+ // Without replace the find row is the widest row, so the popup would size to it and
29
+ // change width as the match counter appears. Pin it to the width the dropdown reserves.
30
+ var findOnlyWidthStyles = (0, _react2.css)({
31
+ boxSizing: 'border-box',
32
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
33
+ width: "".concat(dropdownWidth, "px"),
34
+ maxWidth: '100%'
35
+ });
25
36
  // eslint-disable-next-line @repo/internal/react/no-class-components
26
37
  var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
27
38
  function FindReplace(props) {
@@ -78,16 +89,18 @@ var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
78
89
  allowMatchCase = _this$props.allowMatchCase,
79
90
  shouldMatchCase = _this$props.shouldMatchCase,
80
91
  onToggleMatchCase = _this$props.onToggleMatchCase,
81
- intl = _this$props.intl;
92
+ intl = _this$props.intl,
93
+ _this$props$allowRepl = _this$props.allowReplace,
94
+ allowReplace = _this$props$allowRepl === void 0 ? true : _this$props$allowRepl;
82
95
  var focusToolbarButton = this.props.focusToolbarButton || function () {};
83
96
  return (0, _react2.jsx)("div", {
84
97
  role: 'dialog',
85
- "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(_messages.findReplaceMessages.findReplaceDialogAriaLabel),
98
+ "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(allowReplace ? _messages.findReplaceMessages.findReplaceDialogAriaLabel : _messages.findReplaceMessages.findDialogAriaLabel),
86
99
  "aria-modal": false,
87
100
  ref: this.modalRef
88
101
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
89
102
  ,
90
- css: [_uiStyles.wrapperStyles, _uiStyles.wrapperPaddingStyles]
103
+ css: [_uiStyles.wrapperStyles, _uiStyles.wrapperPaddingStyles, !allowReplace && findOnlyWidthStyles]
91
104
  }, (0, _react2.jsx)(_Find.default, {
92
105
  allowMatchCase: allowMatchCase,
93
106
  shouldMatchCase: shouldMatchCase,
@@ -104,11 +117,14 @@ var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
104
117
  onArrowDown: this.setFocusToReplace,
105
118
  findTyped: this.state.findTyped,
106
119
  setFindTyped: this.setFindTyped
107
- }), (0, _react2.jsx)("hr", {
120
+ }), allowReplace &&
121
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
122
+ (0, _react2.jsx)("hr", {
108
123
  role: "presentation",
109
124
  css: _uiStyles.ruleStyles,
110
125
  id: "replace-hr-element"
111
126
  }), (0, _react2.jsx)(_Replace.default, {
127
+ allowReplace: allowReplace,
112
128
  canReplace: !!isReplaceable,
113
129
  replaceText: replaceText,
114
130
  onReplace: onReplace,
@@ -9,6 +9,9 @@ exports.default = void 0;
9
9
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
10
  var _react = _interopRequireWildcard(require("react"));
11
11
  var _analytics = require("@atlaskit/editor-common/analytics");
12
+ var _hooks = require("@atlaskit/editor-common/hooks");
13
+ var _unsafeExpValNoExposure = require("@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure");
14
+ var _conditionalHooksFactory = require("@atlaskit/platform-feature-flags-react/conditional-hooks-factory/conditional-hooks-factory");
12
15
  var _commands = require("../pm-plugins/commands");
13
16
  var _commandsWithAnalytics = require("../pm-plugins/commands-with-analytics");
14
17
  var _FindReplaceDropdown = _interopRequireDefault(require("./FindReplaceDropdown"));
@@ -39,6 +42,16 @@ var useSharedPluginStateNoDebounce = function useSharedPluginStateNoDebounce(api
39
42
  findReplaceState: state
40
43
  };
41
44
  };
45
+ var useEditorViewMode = (0, _conditionalHooksFactory.conditionalHooksFactory)(function () {
46
+ return (0, _unsafeExpValNoExposure.UNSAFE_expValNoExposure)('platform_editor_collapsible_headings', 'isEnabled', false);
47
+ }, function (api) {
48
+ return (0, _hooks.useSharedPluginStateWithSelector)(api, ['editorViewMode'], function (states) {
49
+ var _states$editorViewMod;
50
+ return (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode;
51
+ });
52
+ }, function () {
53
+ return undefined;
54
+ });
42
55
  var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithState(_ref2) {
43
56
  var _api$analytics, _matches$index;
44
57
  var popupsBoundariesElement = _ref2.popupsBoundariesElement,
@@ -55,6 +68,8 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
55
68
  var editorAnalyticsAPI = api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
56
69
  var _useSharedPluginState = useSharedPluginStateNoDebounce(api),
57
70
  findReplaceState = _useSharedPluginState.findReplaceState;
71
+ var editorViewMode = useEditorViewMode(api);
72
+ var allowReplace = editorViewMode !== 'view';
58
73
  var shouldMatchCase = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.shouldMatchCase;
59
74
  var isActive = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.isActive;
60
75
  var findText = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.findText;
@@ -82,7 +97,7 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
82
97
  };
83
98
  var handleActivate = function handleActivate() {
84
99
  runWithEditorFocused(function () {
85
- return dispatchCommand((0, _commandsWithAnalytics.activateWithAnalytics)(editorAnalyticsAPI)({
100
+ return dispatchCommand((0, _commandsWithAnalytics.activateWithAnalytics)(editorAnalyticsAPI, api === null || api === void 0 ? void 0 : api.editorViewMode)({
86
101
  triggerMethod: _analytics.TRIGGER_METHOD.TOOLBAR
87
102
  }));
88
103
  });
@@ -176,7 +191,8 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
176
191
  onReplace: handleReplace,
177
192
  onReplaceAll: handleReplaceAll,
178
193
  takeFullWidth: !!takeFullWidth,
179
- isButtonHidden: isButtonHidden
194
+ isButtonHidden: isButtonHidden,
195
+ allowReplace: allowReplace
180
196
  });
181
197
  };
182
198
  var _default_1 = /*#__PURE__*/_react.default.memo(FindReplaceToolbarButtonWithState);
@@ -31,6 +31,11 @@ var replaceWithLabelStyle = (0, _primitives.xcss)({
31
31
  var actionButtonContainerStyles = (0, _primitives.xcss)({
32
32
  paddingTop: 'space.200'
33
33
  });
34
+
35
+ // Without the replace field above it, the button row needs no separating space.
36
+ var findOnlyActionButtonContainerStyles = (0, _primitives.xcss)({
37
+ paddingTop: 'space.0'
38
+ });
34
39
  var actionButtonParentInlineStyles = (0, _primitives.xcss)({
35
40
  justifyContent: 'space-between',
36
41
  flexDirection: 'row-reverse',
@@ -44,7 +49,9 @@ var closeButtonInlineStyles = (0, _primitives.xcss)({
44
49
  marginRight: 'auto'
45
50
  });
46
51
  var Replace = function Replace(_ref) {
47
- var canReplace = _ref.canReplace,
52
+ var _ref$allowReplace = _ref.allowReplace,
53
+ allowReplace = _ref$allowReplace === void 0 ? true : _ref$allowReplace,
54
+ canReplace = _ref.canReplace,
48
55
  initialReplaceText = _ref.replaceText,
49
56
  onReplace = _ref.onReplace,
50
57
  onReplaceAll = _ref.onReplaceAll,
@@ -194,7 +201,7 @@ var Replace = function Replace(_ref) {
194
201
  });
195
202
  return /*#__PURE__*/_react.default.createElement(_primitives.Box, {
196
203
  xcss: replaceContainerStyles
197
- }, /*#__PURE__*/_react.default.createElement(_primitives.Box, {
204
+ }, allowReplace && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_primitives.Box, {
198
205
  xcss: replaceWithLabelStyle
199
206
  }, /*#__PURE__*/_react.default.createElement(_primitives.Text, {
200
207
  id: "replace-text-field-label",
@@ -217,8 +224,8 @@ var Replace = function Replace(_ref) {
217
224
  ref: successReplacementMessageRef
218
225
  }, /*#__PURE__*/_react.default.createElement(_validMessage.ValidMessage, {
219
226
  testId: "message-success-replacement"
220
- }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, "\xA0") : resultsReplace)), /*#__PURE__*/_react.default.createElement(_primitives.Box, {
221
- xcss: actionButtonContainerStyles
227
+ }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, "\xA0") : resultsReplace))), /*#__PURE__*/_react.default.createElement(_primitives.Box, {
228
+ xcss: allowReplace ? actionButtonContainerStyles : findOnlyActionButtonContainerStyles
222
229
  }, /*#__PURE__*/_react.default.createElement(_primitives.Inline, {
223
230
  xcss: actionButtonParentInlineStyles
224
231
  }, /*#__PURE__*/_react.default.createElement(_primitives.Inline, {
@@ -251,7 +258,7 @@ var Replace = function Replace(_ref) {
251
258
  keymapDescription: 'Shift Enter',
252
259
  onClick: handleFindPrevClick,
253
260
  disabled: count.total <= 1
254
- }), /*#__PURE__*/_react.default.createElement(_button.default, {
261
+ }), allowReplace && /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_button.default, {
255
262
  testId: 'Replace',
256
263
  id: "replace-button",
257
264
  onClick: handleReplaceClick,
@@ -262,7 +269,7 @@ var Replace = function Replace(_ref) {
262
269
  id: "replaceAll-button",
263
270
  onClick: handleReplaceAllClick,
264
271
  isDisabled: count.totalReplaceable === 0
265
- }, replaceAll)), /*#__PURE__*/_react.default.createElement(_primitives.Inline, {
272
+ }, replaceAll))), /*#__PURE__*/_react.default.createElement(_primitives.Inline, {
266
273
  xcss: closeButtonInlineStyles
267
274
  }, /*#__PURE__*/_react.default.createElement(_button.default, {
268
275
  appearance: "subtle",
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
4
  import { ToolbarSize } from '@atlaskit/editor-common/types';
5
+ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
5
6
  import { fg } from '@atlaskit/platform-feature-flags/fg';
6
7
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
7
8
  import { activate } from './pm-plugins/commands';
@@ -9,6 +10,7 @@ import { activateWithAnalytics } from './pm-plugins/commands-with-analytics';
9
10
  import keymapPlugin from './pm-plugins/keymap';
10
11
  import { createPlugin } from './pm-plugins/main';
11
12
  import { findReplacePluginKey } from './pm-plugins/plugin-key';
13
+ import { viewModeShortcutPlugin } from './pm-plugins/view-mode-shortcut';
12
14
  import FindReplaceDropDownOrToolbarButtonWithState from './ui/FindReplaceDropDownOrToolbarButtonWithState';
13
15
  export const findReplacePlugin = ({
14
16
  config: props,
@@ -71,9 +73,15 @@ export const findReplacePlugin = ({
71
73
  name: 'findReplaceKeymap',
72
74
  plugin: () => {
73
75
  var _api$analytics;
74
- return keymapPlugin(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
76
+ return keymapPlugin(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode);
75
77
  }
76
78
  }];
79
+ if (api !== null && api !== void 0 && api.editorViewMode && UNSAFE_expValNoExposure('platform_editor_collapsible_headings', 'isEnabled', false)) {
80
+ plugins.push({
81
+ name: 'findReplaceViewModeShortcut',
82
+ plugin: () => viewModeShortcutPlugin(api)
83
+ });
84
+ }
77
85
  if (editorExperiment('platform_editor_controls', 'variant1', {
78
86
  exposure: false
79
87
  })) {
@@ -134,7 +142,7 @@ export const findReplacePlugin = ({
134
142
  } = editorViewRef.current;
135
143
  if (api !== null && api !== void 0 && (_api$analytics2 = api.analytics) !== null && _api$analytics2 !== void 0 && _api$analytics2.actions) {
136
144
  var _api$analytics3;
137
- activateWithAnalytics(api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions)({
145
+ activateWithAnalytics(api === null || api === void 0 ? void 0 : (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
138
146
  triggerMethod: triggerMethod || TRIGGER_METHOD.EXTERNAL
139
147
  })(state, dispatch);
140
148
  } else {
@@ -2,17 +2,27 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/edit
2
2
  import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
3
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
4
4
  import { activate, cancelSearch, find, findNext, findPrevious, replace, replaceAll } from './commands';
5
- export const activateWithAnalytics = editorAnalyticsAPI => ({
5
+
6
+ /**
7
+ * Hosts that do not install `editorViewMode` are always editing, so the attribute
8
+ * falls back to `edit` when the api is absent.
9
+ */
10
+
11
+ export const activateWithAnalytics = (editorAnalyticsAPI, editorViewModeAPI) => ({
6
12
  triggerMethod
7
- }) => withAnalytics(editorAnalyticsAPI, state => ({
8
- eventType: EVENT_TYPE.UI,
9
- action: ACTION.ACTIVATED,
10
- actionSubject: ACTION_SUBJECT.FIND_REPLACE_DIALOG,
11
- attributes: {
12
- inputMethod: state.selection instanceof TextSelection && !state.selection.empty ? INPUT_METHOD.PREFILL : INPUT_METHOD.KEYBOARD,
13
- triggerMethod
14
- }
15
- }))(activate());
13
+ }) => withAnalytics(editorAnalyticsAPI, state => {
14
+ var _editorViewModeAPI$sh, _editorViewModeAPI$sh2;
15
+ return {
16
+ eventType: EVENT_TYPE.UI,
17
+ action: ACTION.ACTIVATED,
18
+ actionSubject: ACTION_SUBJECT.FIND_REPLACE_DIALOG,
19
+ attributes: {
20
+ inputMethod: state.selection instanceof TextSelection && !state.selection.empty ? INPUT_METHOD.PREFILL : INPUT_METHOD.KEYBOARD,
21
+ triggerMethod,
22
+ editorViewMode: (_editorViewModeAPI$sh = editorViewModeAPI === null || editorViewModeAPI === void 0 ? void 0 : (_editorViewModeAPI$sh2 = editorViewModeAPI.sharedState.currentState()) === null || _editorViewModeAPI$sh2 === void 0 ? void 0 : _editorViewModeAPI$sh2.mode) !== null && _editorViewModeAPI$sh !== void 0 ? _editorViewModeAPI$sh : 'edit'
23
+ }
24
+ };
25
+ })(activate());
16
26
  export const findWithAnalytics = editorAnalyticsAPI => ({
17
27
  editorView,
18
28
  containerElement,
@@ -2,17 +2,17 @@ import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
2
2
  import { bindKeymapWithCommand, find as findKeymap } from '@atlaskit/editor-common/keymaps';
3
3
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
4
4
  import { activateWithAnalytics } from './commands-with-analytics';
5
- const activateFindReplace = editorAnalyticsAPI => (state, dispatch) => {
6
- activateWithAnalytics(editorAnalyticsAPI)({
5
+ const activateFindReplace = (editorAnalyticsAPI, editorViewModeAPI) => (state, dispatch) => {
6
+ activateWithAnalytics(editorAnalyticsAPI, editorViewModeAPI)({
7
7
  triggerMethod: TRIGGER_METHOD.SHORTCUT
8
8
  })(state, dispatch);
9
9
  return true;
10
10
  };
11
- const keymapPlugin = editorAnalyticsAPI => {
11
+ const keymapPlugin = (editorAnalyticsAPI, editorViewModeAPI) => {
12
12
  const list = {};
13
- // Ignored via go/ees005
14
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
15
- bindKeymapWithCommand(findKeymap.common, activateFindReplace(editorAnalyticsAPI), list);
13
+ if (findKeymap.common) {
14
+ bindKeymapWithCommand(findKeymap.common, activateFindReplace(editorAnalyticsAPI, editorViewModeAPI), list);
15
+ }
16
16
  return keymap(list);
17
17
  };
18
18
  export default keymapPlugin;
@@ -0,0 +1,61 @@
1
+ import { bind } from 'bind-event-listener';
2
+ import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { bindKeymapWithCommand, find as findKeymap } from '@atlaskit/editor-common/keymaps';
4
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
+ import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
6
+ import { activateWithAnalytics } from './commands-with-analytics';
7
+
8
+ /**
9
+ * Whether the event came from a field the user is typing into. `Mod-f` belongs to
10
+ * that field, not to us.
11
+ */
12
+ const isFromTextEntry = event => {
13
+ const target = event.target;
14
+ return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
15
+ };
16
+ const activateInViewMode = api => (state, dispatch) => {
17
+ var _api$editorViewMode, _api$editorViewMode$s, _api$analytics;
18
+ // In edit mode `./keymap.ts` already handles `Mod-f`. Handling it here as well
19
+ // would activate the dialog twice from a single keypress.
20
+ if ((api === null || api === void 0 ? void 0 : (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode) !== 'view') {
21
+ return false;
22
+ }
23
+ activateWithAnalytics(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
24
+ triggerMethod: TRIGGER_METHOD.SHORTCUT
25
+ })(state, dispatch);
26
+ return true;
27
+ };
28
+
29
+ /**
30
+ * Opens the find dialog on `Mod-f` while the editor is in view mode.
31
+ *
32
+ * The listener is bound on the document so that it still fires in view mode, where
33
+ * ProseMirror delivers the keydown to neither `keymap()` nor `handleDOMEvents`.
34
+ */
35
+ export const viewModeShortcutPlugin = api => {
36
+ const bindings = {};
37
+ if (findKeymap.common) {
38
+ bindKeymapWithCommand(findKeymap.common, activateInViewMode(api), bindings);
39
+ }
40
+ const handleKeydown = keydownHandler(bindings);
41
+ return new SafePlugin({
42
+ view: view => {
43
+ const unbind = bind(view.root, {
44
+ type: 'keydown',
45
+ listener: event => {
46
+ // `view.root` is `Document | ShadowRoot`, so the binding widens the event.
47
+ if (!(event instanceof KeyboardEvent) || isFromTextEntry(event)) {
48
+ return;
49
+ }
50
+ if (handleKeydown(view, event)) {
51
+ // Without this the browser find bar opens on top of our dialog.
52
+ event.preventDefault();
53
+ }
54
+ }
55
+ });
56
+ return {
57
+ destroy: unbind
58
+ };
59
+ }
60
+ });
61
+ };
@@ -9,11 +9,23 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
9
9
  import React from 'react';
10
10
 
11
11
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
12
- import { jsx } from '@emotion/react';
12
+ import { css, jsx } from '@emotion/react';
13
13
  import { findReplaceMessages as messages } from '@atlaskit/editor-common/messages';
14
14
  import Find from './Find';
15
15
  import Replace from './Replace';
16
16
  import { ruleStyles, wrapperPaddingStyles, wrapperStyles } from './ui-styles';
17
+
18
+ // Magic number taken from ./FindReplaceToolbarButton.tsx
19
+ const dropdownWidth = 382;
20
+
21
+ // Without replace the find row is the widest row, so the popup would size to it and
22
+ // change width as the match counter appears. Pin it to the width the dropdown reserves.
23
+ const findOnlyWidthStyles = css({
24
+ boxSizing: 'border-box',
25
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
26
+ width: `${dropdownWidth}px`,
27
+ maxWidth: '100%'
28
+ });
17
29
  // eslint-disable-next-line @repo/internal/react/no-class-components
18
30
  class FindReplace extends React.PureComponent {
19
31
  constructor(props) {
@@ -64,17 +76,18 @@ class FindReplace extends React.PureComponent {
64
76
  allowMatchCase,
65
77
  shouldMatchCase,
66
78
  onToggleMatchCase,
67
- intl
79
+ intl,
80
+ allowReplace = true
68
81
  } = this.props;
69
82
  const focusToolbarButton = this.props.focusToolbarButton || (() => {});
70
83
  return jsx("div", {
71
84
  role: 'dialog',
72
- "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(messages.findReplaceDialogAriaLabel),
85
+ "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(allowReplace ? messages.findReplaceDialogAriaLabel : messages.findDialogAriaLabel),
73
86
  "aria-modal": false,
74
87
  ref: this.modalRef
75
88
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
76
89
  ,
77
- css: [wrapperStyles, wrapperPaddingStyles]
90
+ css: [wrapperStyles, wrapperPaddingStyles, !allowReplace && findOnlyWidthStyles]
78
91
  }, jsx(Find, {
79
92
  allowMatchCase: allowMatchCase,
80
93
  shouldMatchCase: shouldMatchCase,
@@ -91,11 +104,14 @@ class FindReplace extends React.PureComponent {
91
104
  onArrowDown: this.setFocusToReplace,
92
105
  findTyped: this.state.findTyped,
93
106
  setFindTyped: this.setFindTyped
94
- }), jsx("hr", {
107
+ }), allowReplace &&
108
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
109
+ jsx("hr", {
95
110
  role: "presentation",
96
111
  css: ruleStyles,
97
112
  id: "replace-hr-element"
98
113
  }), jsx(Replace, {
114
+ allowReplace: allowReplace,
99
115
  canReplace: !!isReplaceable,
100
116
  replaceText: replaceText,
101
117
  onReplace: onReplace,
@@ -1,5 +1,8 @@
1
1
  import React, { useLayoutEffect, useState } from 'react';
2
2
  import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
4
+ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
5
+ import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react/conditional-hooks-factory/conditional-hooks-factory';
3
6
  import { blur, toggleMatchCase } from '../pm-plugins/commands';
4
7
  import { activateWithAnalytics, cancelSearchWithAnalytics, findNextWithAnalytics, findPrevWithAnalytics, findWithAnalytics, replaceAllWithAnalytics, replaceWithAnalytics } from '../pm-plugins/commands-with-analytics';
5
8
  import FindReplaceDropdown from './FindReplaceDropdown';
@@ -28,6 +31,10 @@ const useSharedPluginStateNoDebounce = api => {
28
31
  findReplaceState: state
29
32
  };
30
33
  };
34
+ const useEditorViewMode = conditionalHooksFactory(() => UNSAFE_expValNoExposure('platform_editor_collapsible_headings', 'isEnabled', false), api => useSharedPluginStateWithSelector(api, ['editorViewMode'], states => {
35
+ var _states$editorViewMod;
36
+ return (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode;
37
+ }), () => undefined);
31
38
  const FindReplaceToolbarButtonWithState = ({
32
39
  popupsBoundariesElement,
33
40
  popupsMountPoint,
@@ -46,6 +53,8 @@ const FindReplaceToolbarButtonWithState = ({
46
53
  const {
47
54
  findReplaceState
48
55
  } = useSharedPluginStateNoDebounce(api);
56
+ const editorViewMode = useEditorViewMode(api);
57
+ const allowReplace = editorViewMode !== 'view';
49
58
  const shouldMatchCase = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.shouldMatchCase;
50
59
  const isActive = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.isActive;
51
60
  const findText = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.findText;
@@ -74,7 +83,7 @@ const FindReplaceToolbarButtonWithState = ({
74
83
  cmd(state, dispatch, editorView);
75
84
  };
76
85
  const handleActivate = () => {
77
- runWithEditorFocused(() => dispatchCommand(activateWithAnalytics(editorAnalyticsAPI)({
86
+ runWithEditorFocused(() => dispatchCommand(activateWithAnalytics(editorAnalyticsAPI, api === null || api === void 0 ? void 0 : api.editorViewMode)({
78
87
  triggerMethod: TRIGGER_METHOD.TOOLBAR
79
88
  })));
80
89
  };
@@ -160,7 +169,8 @@ const FindReplaceToolbarButtonWithState = ({
160
169
  onReplace: handleReplace,
161
170
  onReplaceAll: handleReplaceAll,
162
171
  takeFullWidth: !!takeFullWidth,
163
- isButtonHidden: isButtonHidden
172
+ isButtonHidden: isButtonHidden,
173
+ allowReplace: allowReplace
164
174
  });
165
175
  };
166
176
  const _default_1 = /*#__PURE__*/React.memo(FindReplaceToolbarButtonWithState);
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect } from 'react';
1
+ import React, { Fragment, useState, useRef, useEffect } from 'react';
2
2
  import { injectIntl } from 'react-intl';
3
3
  import Button from '@atlaskit/button/default/button';
4
4
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE, TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
@@ -20,6 +20,11 @@ const replaceWithLabelStyle = xcss({
20
20
  const actionButtonContainerStyles = xcss({
21
21
  paddingTop: 'space.200'
22
22
  });
23
+
24
+ // Without the replace field above it, the button row needs no separating space.
25
+ const findOnlyActionButtonContainerStyles = xcss({
26
+ paddingTop: 'space.0'
27
+ });
23
28
  const actionButtonParentInlineStyles = xcss({
24
29
  justifyContent: 'space-between',
25
30
  flexDirection: 'row-reverse',
@@ -33,6 +38,7 @@ const closeButtonInlineStyles = xcss({
33
38
  marginRight: 'auto'
34
39
  });
35
40
  const Replace = ({
41
+ allowReplace = true,
36
42
  canReplace,
37
43
  replaceText: initialReplaceText,
38
44
  onReplace,
@@ -163,7 +169,7 @@ const Replace = ({
163
169
  });
164
170
  return /*#__PURE__*/React.createElement(Box, {
165
171
  xcss: replaceContainerStyles
166
- }, /*#__PURE__*/React.createElement(Box, {
172
+ }, allowReplace && /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Box, {
167
173
  xcss: replaceWithLabelStyle
168
174
  }, /*#__PURE__*/React.createElement(Text, {
169
175
  id: "replace-text-field-label",
@@ -186,8 +192,8 @@ const Replace = ({
186
192
  ref: successReplacementMessageRef
187
193
  }, /*#__PURE__*/React.createElement(ValidMessage, {
188
194
  testId: "message-success-replacement"
189
- }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, '\u00a0') : resultsReplace)), /*#__PURE__*/React.createElement(Box, {
190
- xcss: actionButtonContainerStyles
195
+ }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, '\u00a0') : resultsReplace))), /*#__PURE__*/React.createElement(Box, {
196
+ xcss: allowReplace ? actionButtonContainerStyles : findOnlyActionButtonContainerStyles
191
197
  }, /*#__PURE__*/React.createElement(Inline, {
192
198
  xcss: actionButtonParentInlineStyles
193
199
  }, /*#__PURE__*/React.createElement(Inline, {
@@ -216,7 +222,7 @@ const Replace = ({
216
222
  keymapDescription: 'Shift Enter',
217
223
  onClick: handleFindPrevClick,
218
224
  disabled: count.total <= 1
219
- }), /*#__PURE__*/React.createElement(Button, {
225
+ }), allowReplace && /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Button, {
220
226
  testId: 'Replace',
221
227
  id: "replace-button",
222
228
  onClick: handleReplaceClick,
@@ -227,7 +233,7 @@ const Replace = ({
227
233
  id: "replaceAll-button",
228
234
  onClick: handleReplaceAllClick,
229
235
  isDisabled: count.totalReplaceable === 0
230
- }, replaceAll)), /*#__PURE__*/React.createElement(Inline, {
236
+ }, replaceAll))), /*#__PURE__*/React.createElement(Inline, {
231
237
  xcss: closeButtonInlineStyles
232
238
  }, /*#__PURE__*/React.createElement(Button, {
233
239
  appearance: "subtle",
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
3
3
  import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
4
4
  import { ToolbarSize } from '@atlaskit/editor-common/types';
5
+ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
5
6
  import { fg } from '@atlaskit/platform-feature-flags/fg';
6
7
  import { editorExperiment } from '@atlaskit/tmp-editor-statsig/editor-experiment';
7
8
  import { activate } from './pm-plugins/commands';
@@ -9,6 +10,7 @@ import { activateWithAnalytics } from './pm-plugins/commands-with-analytics';
9
10
  import keymapPlugin from './pm-plugins/keymap';
10
11
  import { createPlugin } from './pm-plugins/main';
11
12
  import { findReplacePluginKey } from './pm-plugins/plugin-key';
13
+ import { viewModeShortcutPlugin } from './pm-plugins/view-mode-shortcut';
12
14
  import FindReplaceDropDownOrToolbarButtonWithState from './ui/FindReplaceDropDownOrToolbarButtonWithState';
13
15
  export var findReplacePlugin = function findReplacePlugin(_ref) {
14
16
  var _api$primaryToolbar;
@@ -70,9 +72,17 @@ export var findReplacePlugin = function findReplacePlugin(_ref) {
70
72
  name: 'findReplaceKeymap',
71
73
  plugin: function plugin() {
72
74
  var _api$analytics;
73
- return keymapPlugin(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
75
+ return keymapPlugin(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode);
74
76
  }
75
77
  }];
78
+ if (api !== null && api !== void 0 && api.editorViewMode && UNSAFE_expValNoExposure('platform_editor_collapsible_headings', 'isEnabled', false)) {
79
+ plugins.push({
80
+ name: 'findReplaceViewModeShortcut',
81
+ plugin: function plugin() {
82
+ return viewModeShortcutPlugin(api);
83
+ }
84
+ });
85
+ }
76
86
  if (editorExperiment('platform_editor_controls', 'variant1', {
77
87
  exposure: false
78
88
  })) {
@@ -131,7 +141,7 @@ export var findReplacePlugin = function findReplacePlugin(_ref) {
131
141
  dispatch = _editorViewRef$curren.dispatch;
132
142
  if (api !== null && api !== void 0 && (_api$analytics2 = api.analytics) !== null && _api$analytics2 !== void 0 && _api$analytics2.actions) {
133
143
  var _api$analytics3;
134
- activateWithAnalytics(api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions)({
144
+ activateWithAnalytics(api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 ? void 0 : _api$analytics3.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
135
145
  triggerMethod: triggerMethod || TRIGGER_METHOD.EXTERNAL
136
146
  })(state, dispatch);
137
147
  } else {
@@ -2,17 +2,25 @@ import { ACTION, ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/edit
2
2
  import { withAnalytics } from '@atlaskit/editor-common/editor-analytics';
3
3
  import { TextSelection } from '@atlaskit/editor-prosemirror/state';
4
4
  import { activate, cancelSearch, find, findNext, findPrevious, replace, replaceAll } from './commands';
5
- export var activateWithAnalytics = function activateWithAnalytics(editorAnalyticsAPI) {
5
+
6
+ /**
7
+ * Hosts that do not install `editorViewMode` are always editing, so the attribute
8
+ * falls back to `edit` when the api is absent.
9
+ */
10
+
11
+ export var activateWithAnalytics = function activateWithAnalytics(editorAnalyticsAPI, editorViewModeAPI) {
6
12
  return function (_ref) {
7
13
  var triggerMethod = _ref.triggerMethod;
8
14
  return withAnalytics(editorAnalyticsAPI, function (state) {
15
+ var _editorViewModeAPI$sh, _editorViewModeAPI$sh2;
9
16
  return {
10
17
  eventType: EVENT_TYPE.UI,
11
18
  action: ACTION.ACTIVATED,
12
19
  actionSubject: ACTION_SUBJECT.FIND_REPLACE_DIALOG,
13
20
  attributes: {
14
21
  inputMethod: state.selection instanceof TextSelection && !state.selection.empty ? INPUT_METHOD.PREFILL : INPUT_METHOD.KEYBOARD,
15
- triggerMethod: triggerMethod
22
+ triggerMethod: triggerMethod,
23
+ editorViewMode: (_editorViewModeAPI$sh = editorViewModeAPI === null || editorViewModeAPI === void 0 || (_editorViewModeAPI$sh2 = editorViewModeAPI.sharedState.currentState()) === null || _editorViewModeAPI$sh2 === void 0 ? void 0 : _editorViewModeAPI$sh2.mode) !== null && _editorViewModeAPI$sh !== void 0 ? _editorViewModeAPI$sh : 'edit'
16
24
  }
17
25
  };
18
26
  })(activate());
@@ -2,19 +2,19 @@ import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
2
2
  import { bindKeymapWithCommand, find as findKeymap } from '@atlaskit/editor-common/keymaps';
3
3
  import { keymap } from '@atlaskit/editor-prosemirror/keymap';
4
4
  import { activateWithAnalytics } from './commands-with-analytics';
5
- var activateFindReplace = function activateFindReplace(editorAnalyticsAPI) {
5
+ var activateFindReplace = function activateFindReplace(editorAnalyticsAPI, editorViewModeAPI) {
6
6
  return function (state, dispatch) {
7
- activateWithAnalytics(editorAnalyticsAPI)({
7
+ activateWithAnalytics(editorAnalyticsAPI, editorViewModeAPI)({
8
8
  triggerMethod: TRIGGER_METHOD.SHORTCUT
9
9
  })(state, dispatch);
10
10
  return true;
11
11
  };
12
12
  };
13
- var keymapPlugin = function keymapPlugin(editorAnalyticsAPI) {
13
+ var keymapPlugin = function keymapPlugin(editorAnalyticsAPI, editorViewModeAPI) {
14
14
  var list = {};
15
- // Ignored via go/ees005
16
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
17
- bindKeymapWithCommand(findKeymap.common, activateFindReplace(editorAnalyticsAPI), list);
15
+ if (findKeymap.common) {
16
+ bindKeymapWithCommand(findKeymap.common, activateFindReplace(editorAnalyticsAPI, editorViewModeAPI), list);
17
+ }
18
18
  return keymap(list);
19
19
  };
20
20
  export default keymapPlugin;
@@ -0,0 +1,63 @@
1
+ import { bind } from 'bind-event-listener';
2
+ import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
3
+ import { bindKeymapWithCommand, find as findKeymap } from '@atlaskit/editor-common/keymaps';
4
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
5
+ import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
6
+ import { activateWithAnalytics } from './commands-with-analytics';
7
+
8
+ /**
9
+ * Whether the event came from a field the user is typing into. `Mod-f` belongs to
10
+ * that field, not to us.
11
+ */
12
+ var isFromTextEntry = function isFromTextEntry(event) {
13
+ var target = event.target;
14
+ return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLElement && target.isContentEditable;
15
+ };
16
+ var activateInViewMode = function activateInViewMode(api) {
17
+ return function (state, dispatch) {
18
+ var _api$editorViewMode, _api$analytics;
19
+ // In edit mode `./keymap.ts` already handles `Mod-f`. Handling it here as well
20
+ // would activate the dialog twice from a single keypress.
21
+ if ((api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) !== 'view') {
22
+ return false;
23
+ }
24
+ activateWithAnalytics(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, api === null || api === void 0 ? void 0 : api.editorViewMode)({
25
+ triggerMethod: TRIGGER_METHOD.SHORTCUT
26
+ })(state, dispatch);
27
+ return true;
28
+ };
29
+ };
30
+
31
+ /**
32
+ * Opens the find dialog on `Mod-f` while the editor is in view mode.
33
+ *
34
+ * The listener is bound on the document so that it still fires in view mode, where
35
+ * ProseMirror delivers the keydown to neither `keymap()` nor `handleDOMEvents`.
36
+ */
37
+ export var viewModeShortcutPlugin = function viewModeShortcutPlugin(api) {
38
+ var bindings = {};
39
+ if (findKeymap.common) {
40
+ bindKeymapWithCommand(findKeymap.common, activateInViewMode(api), bindings);
41
+ }
42
+ var handleKeydown = keydownHandler(bindings);
43
+ return new SafePlugin({
44
+ view: function view(_view) {
45
+ var unbind = bind(_view.root, {
46
+ type: 'keydown',
47
+ listener: function listener(event) {
48
+ // `view.root` is `Document | ShadowRoot`, so the binding widens the event.
49
+ if (!(event instanceof KeyboardEvent) || isFromTextEntry(event)) {
50
+ return;
51
+ }
52
+ if (handleKeydown(_view, event)) {
53
+ // Without this the browser find bar opens on top of our dialog.
54
+ event.preventDefault();
55
+ }
56
+ }
57
+ });
58
+ return {
59
+ destroy: unbind
60
+ };
61
+ }
62
+ });
63
+ };
@@ -16,11 +16,23 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
16
16
  import React from 'react';
17
17
 
18
18
  // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
19
- import { jsx } from '@emotion/react';
19
+ import { css, jsx } from '@emotion/react';
20
20
  import { findReplaceMessages as messages } from '@atlaskit/editor-common/messages';
21
21
  import Find from './Find';
22
22
  import Replace from './Replace';
23
23
  import { ruleStyles, wrapperPaddingStyles, wrapperStyles } from './ui-styles';
24
+
25
+ // Magic number taken from ./FindReplaceToolbarButton.tsx
26
+ var dropdownWidth = 382;
27
+
28
+ // Without replace the find row is the widest row, so the popup would size to it and
29
+ // change width as the match counter appears. Pin it to the width the dropdown reserves.
30
+ var findOnlyWidthStyles = css({
31
+ boxSizing: 'border-box',
32
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values -- Ignored via go/DSP-18766
33
+ width: "".concat(dropdownWidth, "px"),
34
+ maxWidth: '100%'
35
+ });
24
36
  // eslint-disable-next-line @repo/internal/react/no-class-components
25
37
  var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
26
38
  function FindReplace(props) {
@@ -77,16 +89,18 @@ var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
77
89
  allowMatchCase = _this$props.allowMatchCase,
78
90
  shouldMatchCase = _this$props.shouldMatchCase,
79
91
  onToggleMatchCase = _this$props.onToggleMatchCase,
80
- intl = _this$props.intl;
92
+ intl = _this$props.intl,
93
+ _this$props$allowRepl = _this$props.allowReplace,
94
+ allowReplace = _this$props$allowRepl === void 0 ? true : _this$props$allowRepl;
81
95
  var focusToolbarButton = this.props.focusToolbarButton || function () {};
82
96
  return jsx("div", {
83
97
  role: 'dialog',
84
- "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(messages.findReplaceDialogAriaLabel),
98
+ "aria-label": intl === null || intl === void 0 ? void 0 : intl.formatMessage(allowReplace ? messages.findReplaceDialogAriaLabel : messages.findDialogAriaLabel),
85
99
  "aria-modal": false,
86
100
  ref: this.modalRef
87
101
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
88
102
  ,
89
- css: [wrapperStyles, wrapperPaddingStyles]
103
+ css: [wrapperStyles, wrapperPaddingStyles, !allowReplace && findOnlyWidthStyles]
90
104
  }, jsx(Find, {
91
105
  allowMatchCase: allowMatchCase,
92
106
  shouldMatchCase: shouldMatchCase,
@@ -103,11 +117,14 @@ var FindReplace = /*#__PURE__*/function (_React$PureComponent) {
103
117
  onArrowDown: this.setFocusToReplace,
104
118
  findTyped: this.state.findTyped,
105
119
  setFindTyped: this.setFindTyped
106
- }), jsx("hr", {
120
+ }), allowReplace &&
121
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
122
+ jsx("hr", {
107
123
  role: "presentation",
108
124
  css: ruleStyles,
109
125
  id: "replace-hr-element"
110
126
  }), jsx(Replace, {
127
+ allowReplace: allowReplace,
111
128
  canReplace: !!isReplaceable,
112
129
  replaceText: replaceText,
113
130
  onReplace: onReplace,
@@ -1,6 +1,9 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import React, { useLayoutEffect, useState } from 'react';
3
3
  import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
4
+ import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
5
+ import { UNSAFE_expValNoExposure } from '@atlaskit/platform-feature-experiments/unsafe-exp-val-no-exposure';
6
+ import { conditionalHooksFactory } from '@atlaskit/platform-feature-flags-react/conditional-hooks-factory/conditional-hooks-factory';
4
7
  import { blur, toggleMatchCase } from '../pm-plugins/commands';
5
8
  import { activateWithAnalytics, cancelSearchWithAnalytics, findNextWithAnalytics, findPrevWithAnalytics, findWithAnalytics, replaceAllWithAnalytics, replaceWithAnalytics } from '../pm-plugins/commands-with-analytics';
6
9
  import FindReplaceDropdown from './FindReplaceDropdown';
@@ -31,6 +34,16 @@ var useSharedPluginStateNoDebounce = function useSharedPluginStateNoDebounce(api
31
34
  findReplaceState: state
32
35
  };
33
36
  };
37
+ var useEditorViewMode = conditionalHooksFactory(function () {
38
+ return UNSAFE_expValNoExposure('platform_editor_collapsible_headings', 'isEnabled', false);
39
+ }, function (api) {
40
+ return useSharedPluginStateWithSelector(api, ['editorViewMode'], function (states) {
41
+ var _states$editorViewMod;
42
+ return (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode;
43
+ });
44
+ }, function () {
45
+ return undefined;
46
+ });
34
47
  var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithState(_ref2) {
35
48
  var _api$analytics, _matches$index;
36
49
  var popupsBoundariesElement = _ref2.popupsBoundariesElement,
@@ -47,6 +60,8 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
47
60
  var editorAnalyticsAPI = api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions;
48
61
  var _useSharedPluginState = useSharedPluginStateNoDebounce(api),
49
62
  findReplaceState = _useSharedPluginState.findReplaceState;
63
+ var editorViewMode = useEditorViewMode(api);
64
+ var allowReplace = editorViewMode !== 'view';
50
65
  var shouldMatchCase = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.shouldMatchCase;
51
66
  var isActive = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.isActive;
52
67
  var findText = findReplaceState === null || findReplaceState === void 0 ? void 0 : findReplaceState.findText;
@@ -74,7 +89,7 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
74
89
  };
75
90
  var handleActivate = function handleActivate() {
76
91
  runWithEditorFocused(function () {
77
- return dispatchCommand(activateWithAnalytics(editorAnalyticsAPI)({
92
+ return dispatchCommand(activateWithAnalytics(editorAnalyticsAPI, api === null || api === void 0 ? void 0 : api.editorViewMode)({
78
93
  triggerMethod: TRIGGER_METHOD.TOOLBAR
79
94
  }));
80
95
  });
@@ -168,7 +183,8 @@ var FindReplaceToolbarButtonWithState = function FindReplaceToolbarButtonWithSta
168
183
  onReplace: handleReplace,
169
184
  onReplaceAll: handleReplaceAll,
170
185
  takeFullWidth: !!takeFullWidth,
171
- isButtonHidden: isButtonHidden
186
+ isButtonHidden: isButtonHidden,
187
+ allowReplace: allowReplace
172
188
  });
173
189
  };
174
190
  var _default_1 = /*#__PURE__*/React.memo(FindReplaceToolbarButtonWithState);
@@ -1,5 +1,5 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import React, { useState, useRef, useEffect } from 'react';
2
+ import React, { Fragment, useState, useRef, useEffect } from 'react';
3
3
  import { injectIntl } from 'react-intl';
4
4
  import Button from '@atlaskit/button/default/button';
5
5
  import { ACTION, ACTION_SUBJECT, EVENT_TYPE, TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
@@ -21,6 +21,11 @@ var replaceWithLabelStyle = xcss({
21
21
  var actionButtonContainerStyles = xcss({
22
22
  paddingTop: 'space.200'
23
23
  });
24
+
25
+ // Without the replace field above it, the button row needs no separating space.
26
+ var findOnlyActionButtonContainerStyles = xcss({
27
+ paddingTop: 'space.0'
28
+ });
24
29
  var actionButtonParentInlineStyles = xcss({
25
30
  justifyContent: 'space-between',
26
31
  flexDirection: 'row-reverse',
@@ -34,7 +39,9 @@ var closeButtonInlineStyles = xcss({
34
39
  marginRight: 'auto'
35
40
  });
36
41
  var Replace = function Replace(_ref) {
37
- var canReplace = _ref.canReplace,
42
+ var _ref$allowReplace = _ref.allowReplace,
43
+ allowReplace = _ref$allowReplace === void 0 ? true : _ref$allowReplace,
44
+ canReplace = _ref.canReplace,
38
45
  initialReplaceText = _ref.replaceText,
39
46
  onReplace = _ref.onReplace,
40
47
  onReplaceAll = _ref.onReplaceAll,
@@ -184,7 +191,7 @@ var Replace = function Replace(_ref) {
184
191
  });
185
192
  return /*#__PURE__*/React.createElement(Box, {
186
193
  xcss: replaceContainerStyles
187
- }, /*#__PURE__*/React.createElement(Box, {
194
+ }, allowReplace && /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Box, {
188
195
  xcss: replaceWithLabelStyle
189
196
  }, /*#__PURE__*/React.createElement(Text, {
190
197
  id: "replace-text-field-label",
@@ -207,8 +214,8 @@ var Replace = function Replace(_ref) {
207
214
  ref: successReplacementMessageRef
208
215
  }, /*#__PURE__*/React.createElement(ValidMessage, {
209
216
  testId: "message-success-replacement"
210
- }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, "\xA0") : resultsReplace)), /*#__PURE__*/React.createElement(Box, {
211
- xcss: actionButtonContainerStyles
217
+ }, fakeSuccessReplacementMessageUpdate ? resultsReplace.replace(SPACE_REGEX, "\xA0") : resultsReplace))), /*#__PURE__*/React.createElement(Box, {
218
+ xcss: allowReplace ? actionButtonContainerStyles : findOnlyActionButtonContainerStyles
212
219
  }, /*#__PURE__*/React.createElement(Inline, {
213
220
  xcss: actionButtonParentInlineStyles
214
221
  }, /*#__PURE__*/React.createElement(Inline, {
@@ -241,7 +248,7 @@ var Replace = function Replace(_ref) {
241
248
  keymapDescription: 'Shift Enter',
242
249
  onClick: handleFindPrevClick,
243
250
  disabled: count.total <= 1
244
- }), /*#__PURE__*/React.createElement(Button, {
251
+ }), allowReplace && /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(Button, {
245
252
  testId: 'Replace',
246
253
  id: "replace-button",
247
254
  onClick: handleReplaceClick,
@@ -252,7 +259,7 @@ var Replace = function Replace(_ref) {
252
259
  id: "replaceAll-button",
253
260
  onClick: handleReplaceAllClick,
254
261
  isDisabled: count.totalReplaceable === 0
255
- }, replaceAll)), /*#__PURE__*/React.createElement(Inline, {
262
+ }, replaceAll))), /*#__PURE__*/React.createElement(Inline, {
256
263
  xcss: closeButtonInlineStyles
257
264
  }, /*#__PURE__*/React.createElement(Button, {
258
265
  appearance: "subtle",
@@ -3,6 +3,7 @@ import type { NextEditorPlugin, OptionalPlugin } from '@atlaskit/editor-common/t
3
3
  import type { AnalyticsPlugin } from '@atlaskit/editor-plugin-analytics';
4
4
  import type { BlockCollapsePlugin } from '@atlaskit/editor-plugin-block-collapse/blockCollapsePluginType';
5
5
  import type { CardPlugin } from '@atlaskit/editor-plugin-card';
6
+ import type { EditorViewModePlugin } from '@atlaskit/editor-plugin-editor-viewmode/editorViewmodePluginType';
6
7
  import type { ExpandPlugin } from '@atlaskit/editor-plugin-expand';
7
8
  import type { MentionsPlugin } from '@atlaskit/editor-plugin-mentions';
8
9
  import type { PrimaryToolbarPlugin } from '@atlaskit/editor-plugin-primary-toolbar';
@@ -19,6 +20,7 @@ export type FindReplacePluginDependencies = [
19
20
  OptionalPlugin<CardPlugin>,
20
21
  OptionalPlugin<ExpandPlugin>,
21
22
  OptionalPlugin<BlockCollapsePlugin>,
23
+ OptionalPlugin<EditorViewModePlugin>,
22
24
  OptionalPlugin<SyncedBlockPlugin>
23
25
  ];
24
26
  export type FindReplacePlugin = NextEditorPlugin<'findReplace', {
@@ -1,7 +1,13 @@
1
1
  import type { EditorAnalyticsAPI, TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
2
- import type { Command } from '@atlaskit/editor-common/types';
2
+ import type { Command, ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
3
  import type { EditorView } from '@atlaskit/editor-prosemirror/view';
4
- export declare const activateWithAnalytics: (editorAnalyticsAPI: EditorAnalyticsAPI | undefined) => ({ triggerMethod, }: {
4
+ import type { FindReplacePlugin } from '../findReplacePluginType';
5
+ /**
6
+ * Hosts that do not install `editorViewMode` are always editing, so the attribute
7
+ * falls back to `edit` when the api is absent.
8
+ */
9
+ export type EditorViewModeAPI = ExtractInjectionAPI<FindReplacePlugin>['editorViewMode'];
10
+ export declare const activateWithAnalytics: (editorAnalyticsAPI: EditorAnalyticsAPI | undefined, editorViewModeAPI?: EditorViewModeAPI) => ({ triggerMethod, }: {
5
11
  triggerMethod: TRIGGER_METHOD.SHORTCUT | TRIGGER_METHOD.TOOLBAR | TRIGGER_METHOD.EXTERNAL;
6
12
  }) => Command;
7
13
  export declare const findWithAnalytics: (editorAnalyticsAPI: EditorAnalyticsAPI | undefined) => ({ editorView, containerElement, keyword, }: {
@@ -1,4 +1,5 @@
1
1
  import type { EditorAnalyticsAPI } from '@atlaskit/editor-common/analytics';
2
2
  import type { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
3
- declare const keymapPlugin: (editorAnalyticsAPI: EditorAnalyticsAPI | undefined) => SafePlugin;
3
+ import type { EditorViewModeAPI } from './commands-with-analytics';
4
+ declare const keymapPlugin: (editorAnalyticsAPI: EditorAnalyticsAPI | undefined, editorViewModeAPI: EditorViewModeAPI) => SafePlugin;
4
5
  export default keymapPlugin;
@@ -0,0 +1,10 @@
1
+ import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
2
+ import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
+ import type { FindReplacePlugin } from '../findReplacePluginType';
4
+ /**
5
+ * Opens the find dialog on `Mod-f` while the editor is in view mode.
6
+ *
7
+ * The listener is bound on the document so that it still fires in view mode, where
8
+ * ProseMirror delivers the keydown to neither `keymap()` nor `handleDOMEvents`.
9
+ */
10
+ export declare const viewModeShortcutPlugin: (api?: ExtractInjectionAPI<FindReplacePlugin>) => SafePlugin;
@@ -8,6 +8,11 @@ import type { IntlShape } from 'react-intl';
8
8
  import type { DispatchAnalyticsEvent, TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
9
9
  import type { MatchCaseProps } from '../types';
10
10
  export type FindReplaceProps = {
11
+ /**
12
+ * When `false`, the dialog offers find only: the replace label, field, replacement
13
+ * count message and both replace buttons are not rendered.
14
+ */
15
+ allowReplace?: boolean;
11
16
  count: {
12
17
  index: number;
13
18
  total: number;
@@ -3,6 +3,12 @@ import type { WithIntlProps, WrappedComponentProps } from 'react-intl';
3
3
  import type { DispatchAnalyticsEvent } from '@atlaskit/editor-common/analytics';
4
4
  import { TRIGGER_METHOD } from '@atlaskit/editor-common/analytics';
5
5
  export type ReplaceProps = {
6
+ /**
7
+ * When `false`, the replace label, field, replacement count message and both
8
+ * replace buttons are not rendered. Both chevrons and the Close button stay.
9
+ * Defaults to `true`.
10
+ */
11
+ allowReplace?: boolean;
6
12
  canReplace: boolean;
7
13
  count: {
8
14
  index: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-find-replace",
3
- "version": "21.0.1",
3
+ "version": "21.1.0",
4
4
  "description": "find replace plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -24,6 +24,7 @@
24
24
  "@atlaskit/editor-plugin-analytics": "^21.0.0",
25
25
  "@atlaskit/editor-plugin-block-collapse": "^7.0.0",
26
26
  "@atlaskit/editor-plugin-card": "^27.0.0",
27
+ "@atlaskit/editor-plugin-editor-viewmode": "^23.0.0",
27
28
  "@atlaskit/editor-plugin-expand": "^22.0.0",
28
29
  "@atlaskit/editor-plugin-mentions": "^23.0.0",
29
30
  "@atlaskit/editor-plugin-primary-toolbar": "^22.0.0",
@@ -36,13 +37,15 @@
36
37
  "@atlaskit/mention": "^30.0.0",
37
38
  "@atlaskit/platform-feature-experiments": "^0.3.0",
38
39
  "@atlaskit/platform-feature-flags": "^2.2.0",
40
+ "@atlaskit/platform-feature-flags-react": "^1.2.0",
39
41
  "@atlaskit/primitives": "^22.5.0",
40
42
  "@atlaskit/textfield": "^10.2.0",
41
- "@atlaskit/tmp-editor-statsig": "^206.0.0",
43
+ "@atlaskit/tmp-editor-statsig": "^207.0.0",
42
44
  "@atlaskit/tokens": "^20.0.0",
43
45
  "@atlaskit/tooltip": "^24.3.0",
44
46
  "@babel/runtime": "^7.0.0",
45
47
  "@emotion/react": "^11.7.1",
48
+ "bind-event-listener": "^3.0.0",
46
49
  "classnames": "^2.2.5",
47
50
  "lodash": "^4.17.21",
48
51
  "raf-schd": "^4.0.3"
@@ -57,7 +60,7 @@
57
60
  "react-intl": "^7.0.0"
58
61
  },
59
62
  "peerDependencies": {
60
- "@atlaskit/editor-common": "^125.1.0",
63
+ "@atlaskit/editor-common": "^125.2.0",
61
64
  "react": "^18.2.0 || ^19.2.0",
62
65
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"
63
66
  },