@atlaskit/editor-plugin-annotation 13.0.4 → 14.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # @atlaskit/editor-plugin-annotation
2
2
 
3
+ ## 14.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 13.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`e60449618db02`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/e60449618db02) -
14
+ Add safe coordination between inline comments and AI suggestion cards.
15
+
16
+ Inline comment providers can supply a close guard:
17
+
18
+ ```ts
19
+ const annotationProvider = {
20
+ inlineComment: {
21
+ ...inlineCommentOptions,
22
+ requestClose: async () => {
23
+ // Prompt for confirmation when there is unsaved comment content.
24
+ return canCloseComment;
25
+ },
26
+ },
27
+ };
28
+ ```
29
+
30
+ Plugins with an optional `AnnotationPlugin` dependency can request that the active comment close
31
+ before continuing:
32
+
33
+ ```ts
34
+ const canContinue = await api?.annotation?.actions.requestCloseInlineComment();
35
+
36
+ if (canContinue) {
37
+ api?.aiSuggestions?.actions.selectSuggestion(suggestionId);
38
+ }
39
+ ```
40
+
41
+ The action resolves to `false` when closing is cancelled or fails. It resolves to `true` when the
42
+ comment closes or no close capability is configured.
43
+
44
+ ### Patch Changes
45
+
46
+ - Updated dependencies
47
+
3
48
  ## 13.0.4
4
49
 
5
50
  ### Patch Changes
@@ -5,7 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.annotationPlugin = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
8
9
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
9
11
  var _react = _interopRequireDefault(require("react"));
10
12
  var _coreUtils = require("@atlaskit/editor-common/core-utils");
11
13
  var _hooks = require("@atlaskit/editor-common/hooks");
@@ -15,6 +17,7 @@ var _annotationMark = require("./nodeviews/annotationMark");
15
17
  var _inlineComment = require("./pm-plugins/inline-comment");
16
18
  var _keymap = require("./pm-plugins/keymap");
17
19
  var _toolbar = require("./pm-plugins/toolbar");
20
+ var _types = require("./pm-plugins/types");
18
21
  var _utils = require("./pm-plugins/utils");
19
22
  var _InlineCommentView = require("./ui/InlineCommentView");
20
23
  var _toolbarComponents = require("./ui/toolbar-components");
@@ -26,6 +29,55 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
26
29
  api = _ref.api;
27
30
  var featureFlags = api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState();
28
31
  var isToolbarAIFCEnabled = Boolean(api === null || api === void 0 ? void 0 : api.toolbar);
32
+ /**
33
+ * Allows external editor UI, currently AI suggestions, to safely close an inline comment
34
+ * without bypassing the provider's unsaved-content guard.
35
+ */
36
+ var requestCloseInlineComment = /*#__PURE__*/function () {
37
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
38
+ var _api$core$actions$exe, requestClose, canClose, _t;
39
+ return _regenerator.default.wrap(function (_context) {
40
+ while (1) switch (_context.prev = _context.next) {
41
+ case 0:
42
+ _context.prev = 0;
43
+ requestClose = annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.requestClose;
44
+ if (requestClose) {
45
+ _context.next = 1;
46
+ break;
47
+ }
48
+ return _context.abrupt("return", true);
49
+ case 1:
50
+ _context.next = 2;
51
+ return requestClose();
52
+ case 2:
53
+ canClose = _context.sent;
54
+ if (canClose) {
55
+ _context.next = 3;
56
+ break;
57
+ }
58
+ return _context.abrupt("return", false);
59
+ case 3:
60
+ return _context.abrupt("return", (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(function (_ref3) {
61
+ var tr = _ref3.tr;
62
+ tr.setMeta(_utils.inlineCommentPluginKey, {
63
+ type: _types.ACTIONS.CLOSE_COMPONENT
64
+ });
65
+ return tr;
66
+ })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false);
67
+ case 4:
68
+ _context.prev = 4;
69
+ _t = _context["catch"](0);
70
+ return _context.abrupt("return", false);
71
+ case 5:
72
+ case "end":
73
+ return _context.stop();
74
+ }
75
+ }, _callee, null, [[0, 4]]);
76
+ }));
77
+ return function requestCloseInlineComment() {
78
+ return _ref2.apply(this, arguments);
79
+ };
80
+ }();
29
81
  if (isToolbarAIFCEnabled) {
30
82
  var _api$toolbar;
31
83
  api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 || _api$toolbar.actions.registerComponents((0, _toolbarComponents.getToolbarComponents)(api, annotationProviders));
@@ -40,6 +92,7 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
40
92
  },
41
93
  actions: {
42
94
  hasAnyUnResolvedAnnotationInPage: _utils.hasAnyUnResolvedAnnotationInPage,
95
+ requestCloseInlineComment: requestCloseInlineComment,
43
96
  stripNonExistingAnnotations: _utils.stripNonExistingAnnotations,
44
97
  setInlineCommentDraftState: (0, _editorCommands.setInlineCommentDraftState)(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
45
98
  showCommentForBlockNode: (0, _editorCommands.showInlineCommentForBlockNode)(annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
@@ -58,8 +111,8 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
58
111
  pmPlugins: function pmPlugins() {
59
112
  return [{
60
113
  name: 'annotation',
61
- plugin: function plugin(_ref2) {
62
- var dispatch = _ref2.dispatch;
114
+ plugin: function plugin(_ref4) {
115
+ var dispatch = _ref4.dispatch;
63
116
  if (annotationProviders) {
64
117
  var _api$analytics2;
65
118
  return (0, _inlineComment.inlineCommentPlugin)({
@@ -132,9 +185,9 @@ var annotationPlugin = exports.annotationPlugin = function annotationPlugin(_ref
132
185
  }
133
186
  }
134
187
  },
135
- contentComponent: function contentComponent(_ref3) {
136
- var editorView = _ref3.editorView,
137
- dispatchAnalyticsEvent = _ref3.dispatchAnalyticsEvent;
188
+ contentComponent: function contentComponent(_ref5) {
189
+ var editorView = _ref5.editorView,
190
+ dispatchAnalyticsEvent = _ref5.dispatchAnalyticsEvent;
138
191
  if (!annotationProviders || !editorView || (0, _coreUtils.isSSR)()) {
139
192
  return null;
140
193
  }
@@ -155,12 +208,12 @@ var selector = function selector(states) {
155
208
  annotations: (_states$annotationSta3 = states.annotationState) === null || _states$annotationSta3 === void 0 ? void 0 : _states$annotationSta3.annotations
156
209
  };
157
210
  };
158
- function AnnotationContentComponent(_ref4) {
211
+ function AnnotationContentComponent(_ref6) {
159
212
  var _api$analytics4;
160
- var api = _ref4.api,
161
- editorView = _ref4.editorView,
162
- annotationProviders = _ref4.annotationProviders,
163
- dispatchAnalyticsEvent = _ref4.dispatchAnalyticsEvent;
213
+ var api = _ref6.api,
214
+ editorView = _ref6.editorView,
215
+ annotationProviders = _ref6.annotationProviders,
216
+ dispatchAnalyticsEvent = _ref6.dispatchAnalyticsEvent;
164
217
  var annotationState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['annotation'], selector);
165
218
 
166
219
  // need to explicitly check for false as undefined is also a valid value to continue
@@ -7,7 +7,8 @@ import { annotationWithToDOMFix } from './nodeviews/annotationMark';
7
7
  import { inlineCommentPlugin } from './pm-plugins/inline-comment';
8
8
  import { keymapPlugin } from './pm-plugins/keymap';
9
9
  import { buildSuppressedToolbar, buildToolbar, shouldSuppressFloatingToolbar } from './pm-plugins/toolbar';
10
- import { getPluginState, hasAnyUnResolvedAnnotationInPage, stripNonExistingAnnotations } from './pm-plugins/utils';
10
+ import { ACTIONS } from './pm-plugins/types';
11
+ import { getPluginState, hasAnyUnResolvedAnnotationInPage, inlineCommentPluginKey, stripNonExistingAnnotations } from './pm-plugins/utils';
11
12
  import { InlineCommentView } from './ui/InlineCommentView';
12
13
  import { getToolbarComponents } from './ui/toolbar-components';
13
14
  export const annotationPlugin = ({
@@ -17,6 +18,34 @@ export const annotationPlugin = ({
17
18
  var _api$featureFlags, _api$analytics;
18
19
  const featureFlags = api === null || api === void 0 ? void 0 : (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState();
19
20
  const isToolbarAIFCEnabled = Boolean(api === null || api === void 0 ? void 0 : api.toolbar);
21
+ /**
22
+ * Allows external editor UI, currently AI suggestions, to safely close an inline comment
23
+ * without bypassing the provider's unsaved-content guard.
24
+ */
25
+ const requestCloseInlineComment = async () => {
26
+ try {
27
+ var _api$core$actions$exe;
28
+ const requestClose = annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.requestClose;
29
+ if (!requestClose) {
30
+ return true;
31
+ }
32
+ const canClose = await requestClose();
33
+ if (!canClose) {
34
+ return false;
35
+ }
36
+ return (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(({
37
+ tr
38
+ }) => {
39
+ tr.setMeta(inlineCommentPluginKey, {
40
+ type: ACTIONS.CLOSE_COMPONENT
41
+ });
42
+ return tr;
43
+ })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false;
44
+ } catch {
45
+ // Preserve the active comment if its close guard cannot complete.
46
+ return false;
47
+ }
48
+ };
20
49
  if (isToolbarAIFCEnabled) {
21
50
  var _api$toolbar;
22
51
  api === null || api === void 0 ? void 0 : (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 ? void 0 : _api$toolbar.actions.registerComponents(getToolbarComponents(api, annotationProviders));
@@ -31,6 +60,7 @@ export const annotationPlugin = ({
31
60
  },
32
61
  actions: {
33
62
  hasAnyUnResolvedAnnotationInPage,
63
+ requestCloseInlineComment,
34
64
  stripNonExistingAnnotations,
35
65
  setInlineCommentDraftState: setInlineCommentDraftState(api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
36
66
  showCommentForBlockNode: showInlineCommentForBlockNode(annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
@@ -1,6 +1,8 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
3
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
4
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
5
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
4
6
  import React from 'react';
5
7
  import { isSSR } from '@atlaskit/editor-common/core-utils';
6
8
  import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
@@ -10,7 +12,8 @@ import { annotationWithToDOMFix } from './nodeviews/annotationMark';
10
12
  import { inlineCommentPlugin } from './pm-plugins/inline-comment';
11
13
  import { keymapPlugin } from './pm-plugins/keymap';
12
14
  import { buildSuppressedToolbar, buildToolbar, shouldSuppressFloatingToolbar } from './pm-plugins/toolbar';
13
- import { getPluginState, hasAnyUnResolvedAnnotationInPage, stripNonExistingAnnotations } from './pm-plugins/utils';
15
+ import { ACTIONS } from './pm-plugins/types';
16
+ import { getPluginState, hasAnyUnResolvedAnnotationInPage, inlineCommentPluginKey, stripNonExistingAnnotations } from './pm-plugins/utils';
14
17
  import { InlineCommentView } from './ui/InlineCommentView';
15
18
  import { getToolbarComponents } from './ui/toolbar-components';
16
19
  export var annotationPlugin = function annotationPlugin(_ref) {
@@ -19,6 +22,55 @@ export var annotationPlugin = function annotationPlugin(_ref) {
19
22
  api = _ref.api;
20
23
  var featureFlags = api === null || api === void 0 || (_api$featureFlags = api.featureFlags) === null || _api$featureFlags === void 0 ? void 0 : _api$featureFlags.sharedState.currentState();
21
24
  var isToolbarAIFCEnabled = Boolean(api === null || api === void 0 ? void 0 : api.toolbar);
25
+ /**
26
+ * Allows external editor UI, currently AI suggestions, to safely close an inline comment
27
+ * without bypassing the provider's unsaved-content guard.
28
+ */
29
+ var requestCloseInlineComment = /*#__PURE__*/function () {
30
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
31
+ var _api$core$actions$exe, requestClose, canClose, _t;
32
+ return _regeneratorRuntime.wrap(function (_context) {
33
+ while (1) switch (_context.prev = _context.next) {
34
+ case 0:
35
+ _context.prev = 0;
36
+ requestClose = annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.requestClose;
37
+ if (requestClose) {
38
+ _context.next = 1;
39
+ break;
40
+ }
41
+ return _context.abrupt("return", true);
42
+ case 1:
43
+ _context.next = 2;
44
+ return requestClose();
45
+ case 2:
46
+ canClose = _context.sent;
47
+ if (canClose) {
48
+ _context.next = 3;
49
+ break;
50
+ }
51
+ return _context.abrupt("return", false);
52
+ case 3:
53
+ return _context.abrupt("return", (_api$core$actions$exe = api === null || api === void 0 ? void 0 : api.core.actions.execute(function (_ref3) {
54
+ var tr = _ref3.tr;
55
+ tr.setMeta(inlineCommentPluginKey, {
56
+ type: ACTIONS.CLOSE_COMPONENT
57
+ });
58
+ return tr;
59
+ })) !== null && _api$core$actions$exe !== void 0 ? _api$core$actions$exe : false);
60
+ case 4:
61
+ _context.prev = 4;
62
+ _t = _context["catch"](0);
63
+ return _context.abrupt("return", false);
64
+ case 5:
65
+ case "end":
66
+ return _context.stop();
67
+ }
68
+ }, _callee, null, [[0, 4]]);
69
+ }));
70
+ return function requestCloseInlineComment() {
71
+ return _ref2.apply(this, arguments);
72
+ };
73
+ }();
22
74
  if (isToolbarAIFCEnabled) {
23
75
  var _api$toolbar;
24
76
  api === null || api === void 0 || (_api$toolbar = api.toolbar) === null || _api$toolbar === void 0 || _api$toolbar.actions.registerComponents(getToolbarComponents(api, annotationProviders));
@@ -33,6 +85,7 @@ export var annotationPlugin = function annotationPlugin(_ref) {
33
85
  },
34
86
  actions: {
35
87
  hasAnyUnResolvedAnnotationInPage: hasAnyUnResolvedAnnotationInPage,
88
+ requestCloseInlineComment: requestCloseInlineComment,
36
89
  stripNonExistingAnnotations: stripNonExistingAnnotations,
37
90
  setInlineCommentDraftState: setInlineCommentDraftState(api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions, annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
38
91
  showCommentForBlockNode: showInlineCommentForBlockNode(annotationProviders === null || annotationProviders === void 0 ? void 0 : annotationProviders.inlineComment.supportedBlockNodes),
@@ -51,8 +104,8 @@ export var annotationPlugin = function annotationPlugin(_ref) {
51
104
  pmPlugins: function pmPlugins() {
52
105
  return [{
53
106
  name: 'annotation',
54
- plugin: function plugin(_ref2) {
55
- var dispatch = _ref2.dispatch;
107
+ plugin: function plugin(_ref4) {
108
+ var dispatch = _ref4.dispatch;
56
109
  if (annotationProviders) {
57
110
  var _api$analytics2;
58
111
  return inlineCommentPlugin({
@@ -125,9 +178,9 @@ export var annotationPlugin = function annotationPlugin(_ref) {
125
178
  }
126
179
  }
127
180
  },
128
- contentComponent: function contentComponent(_ref3) {
129
- var editorView = _ref3.editorView,
130
- dispatchAnalyticsEvent = _ref3.dispatchAnalyticsEvent;
181
+ contentComponent: function contentComponent(_ref5) {
182
+ var editorView = _ref5.editorView,
183
+ dispatchAnalyticsEvent = _ref5.dispatchAnalyticsEvent;
131
184
  if (!annotationProviders || !editorView || isSSR()) {
132
185
  return null;
133
186
  }
@@ -148,12 +201,12 @@ var selector = function selector(states) {
148
201
  annotations: (_states$annotationSta3 = states.annotationState) === null || _states$annotationSta3 === void 0 ? void 0 : _states$annotationSta3.annotations
149
202
  };
150
203
  };
151
- function AnnotationContentComponent(_ref4) {
204
+ function AnnotationContentComponent(_ref6) {
152
205
  var _api$analytics4;
153
- var api = _ref4.api,
154
- editorView = _ref4.editorView,
155
- annotationProviders = _ref4.annotationProviders,
156
- dispatchAnalyticsEvent = _ref4.dispatchAnalyticsEvent;
206
+ var api = _ref6.api,
207
+ editorView = _ref6.editorView,
208
+ annotationProviders = _ref6.annotationProviders,
209
+ dispatchAnalyticsEvent = _ref6.dispatchAnalyticsEvent;
157
210
  var annotationState = useSharedPluginStateWithSelector(api, ['annotation'], selector);
158
211
 
159
212
  // need to explicitly check for false as undefined is also a valid value to continue
@@ -28,6 +28,13 @@ export type AnnotationPluginOptions = AnnotationProviders;
28
28
  export type AnnotationPlugin = NextEditorPlugin<'annotation', {
29
29
  actions: {
30
30
  hasAnyUnResolvedAnnotationInPage: (state: EditorState) => boolean;
31
+ /**
32
+ * Requests that the active inline comment or comment draft be closed.
33
+ * Runs the provider's close guard before closing when one is configured.
34
+ * @returns `true` when the caller may continue because the comment closed or no close
35
+ * capability is configured; otherwise `false`.
36
+ */
37
+ requestCloseInlineComment: () => Promise<boolean>;
31
38
  setInlineCommentDraftState: SetInlineCommentDraftState;
32
39
  /**
33
40
  * Sets a pending selected annotation, opening its comment popup or panel.
@@ -101,6 +101,8 @@ export type InlineCommentAnnotationProvider = AnnotationTypeProvider<AnnotationT
101
101
  getCanAddComments?: () => boolean;
102
102
  isToolbarAbove?: boolean;
103
103
  onCommentButtonMount?: () => void;
104
+ /** Checks whether the active inline comment can be safely closed. */
105
+ requestClose?: () => Promise<boolean>;
104
106
  /**
105
107
  * @experimental Still under development. Do not use.
106
108
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-annotation",
3
- "version": "13.0.4",
3
+ "version": "14.0.0",
4
4
  "description": "Annotation plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -20,12 +20,12 @@
20
20
  "atlaskit:src": "src/index.ts",
21
21
  "dependencies": {
22
22
  "@atlaskit/adf-schema": "^56.6.0",
23
- "@atlaskit/editor-plugin-analytics": "^13.0.0",
24
- "@atlaskit/editor-plugin-connectivity": "^13.0.0",
25
- "@atlaskit/editor-plugin-editor-viewmode-effects": "^13.0.0",
26
- "@atlaskit/editor-plugin-feature-flags": "^12.0.0",
27
- "@atlaskit/editor-plugin-toolbar": "^10.1.0",
28
- "@atlaskit/editor-plugin-user-intent": "^11.0.0",
23
+ "@atlaskit/editor-plugin-analytics": "^14.0.0",
24
+ "@atlaskit/editor-plugin-connectivity": "^14.0.0",
25
+ "@atlaskit/editor-plugin-editor-viewmode-effects": "^14.0.0",
26
+ "@atlaskit/editor-plugin-feature-flags": "^13.0.0",
27
+ "@atlaskit/editor-plugin-toolbar": "^11.0.0",
28
+ "@atlaskit/editor-plugin-user-intent": "^12.0.0",
29
29
  "@atlaskit/editor-prosemirror": "^8.0.0",
30
30
  "@atlaskit/editor-toolbar": "^2.4.0",
31
31
  "@atlaskit/editor-toolbar-model": "^1.2.0",
@@ -35,7 +35,7 @@
35
35
  "@babel/runtime": "^7.0.0"
36
36
  },
37
37
  "peerDependencies": {
38
- "@atlaskit/editor-common": "^117.4.0",
38
+ "@atlaskit/editor-common": "^118.0.0",
39
39
  "react": "^18.2.0 || ^19.2.0",
40
40
  "react-dom": "^18.2.0 || ^19.2.0",
41
41
  "react-intl": "^5.25.1 || ^6.0.0 || ^7.0.0"