@atlaskit/editor-plugin-placeholder 1.5.0 → 2.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,31 @@
1
1
  # @atlaskit/editor-plugin-placeholder
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#117363](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/117363)
8
+ [`10a0f7f6c2027`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/10a0f7f6c2027) -
9
+ This package's `peerDependencies` have been adjusted for `react` and/or `react-dom` to reflect the
10
+ status of only supporting React 18 going forward. No explicit breaking change to React support has
11
+ been made in this release, but this is to signify going forward, breaking changes for React 16 or
12
+ React 17 may come via non-major semver releases.
13
+
14
+ Please refer this community post for more details:
15
+ https://community.developer.atlassian.com/t/rfc-78-dropping-support-for-react-16-and-rendering-in-a-react-18-concurrent-root-in-jira-and-confluence/87026
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+
21
+ ## 1.6.0
22
+
23
+ ### Minor Changes
24
+
25
+ - [#113560](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/113560)
26
+ [`0acdf46472e21`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/0acdf46472e21) -
27
+ Add new setPlaceholder API so the placeholder text can be changed dynamically via the editor API.
28
+
3
29
  ## 1.5.0
4
30
 
5
31
  ### Minor Changes
@@ -44,7 +44,7 @@ function createPlaceholderDecoration(editorState, placeholderText) {
44
44
  }
45
45
  return _view.DecorationSet.create(editorState.doc, [_view.Decoration.widget(pos, placeholderDecoration, {
46
46
  side: 0,
47
- key: 'placeholder'
47
+ key: "placeholder ".concat(placeholderText)
48
48
  })]);
49
49
  }
50
50
  function setPlaceHolderState(placeholderText, pos) {
@@ -54,12 +54,15 @@ function setPlaceHolderState(placeholderText, pos) {
54
54
  pos: pos ? pos : 1
55
55
  };
56
56
  }
57
- var emptyPlaceholder = {
58
- hasPlaceholder: false
57
+ var emptyPlaceholder = function emptyPlaceholder(placeholderText) {
58
+ return {
59
+ hasPlaceholder: false,
60
+ placeholderText: placeholderText
61
+ };
59
62
  };
60
63
  function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpen, defaultPlaceholderText, bracketPlaceholderText) {
61
64
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
62
- return emptyPlaceholder;
65
+ return emptyPlaceholder(defaultPlaceholderText);
63
66
  }
64
67
  if (defaultPlaceholderText && (0, _utils.isEmptyDocument)(editorState.doc)) {
65
68
  return setPlaceHolderState(defaultPlaceholderText);
@@ -70,7 +73,7 @@ function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpe
70
73
  var bracketHint = ' ' + bracketPlaceholderText;
71
74
  return setPlaceHolderState(bracketHint, $from.pos - 1);
72
75
  }
73
- return emptyPlaceholder;
76
+ return emptyPlaceholder(defaultPlaceholderText);
74
77
  }
75
78
  function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api) {
76
79
  if (!defaultPlaceholderText && !bracketPlaceholderText) {
@@ -83,20 +86,15 @@ function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api) {
83
86
  var _api$focus, _api$typeAhead;
84
87
  return createPlaceHolderStateFrom(Boolean(api === null || api === void 0 || (_api$focus = api.focus) === null || _api$focus === void 0 || (_api$focus = _api$focus.sharedState.currentState()) === null || _api$focus === void 0 ? void 0 : _api$focus.hasFocus), state, api === null || api === void 0 || (_api$typeAhead = api.typeAhead) === null || _api$typeAhead === void 0 ? void 0 : _api$typeAhead.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
85
88
  },
86
- apply: function apply(tr, _oldPluginState, _oldEditorState, newEditorState) {
87
- var _api$focus2, _api$typeAhead3;
89
+ apply: function apply(tr, placeholderState, _oldEditorState, newEditorState) {
90
+ var _api$focus2, _api$typeAhead3, _placeholderState$pla;
88
91
  var meta = tr.getMeta(pluginKey);
89
92
  var isEditorFocused = Boolean(api === null || api === void 0 || (_api$focus2 = api.focus) === null || _api$focus2 === void 0 || (_api$focus2 = _api$focus2.sharedState.currentState()) === null || _api$focus2 === void 0 ? void 0 : _api$focus2.hasFocus);
90
- if (meta) {
91
- if (meta.removePlaceholder) {
92
- return emptyPlaceholder;
93
- }
94
- if (meta.applyPlaceholderIfEmpty) {
95
- var _api$typeAhead2;
96
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
97
- }
93
+ if ((meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined) {
94
+ var _api$typeAhead2;
95
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, meta.placeholderText, bracketPlaceholderText);
98
96
  }
99
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
97
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText, bracketPlaceholderText);
100
98
  }
101
99
  },
102
100
  props: {
@@ -118,8 +116,23 @@ function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api) {
118
116
  var placeholderPlugin = exports.placeholderPlugin = function placeholderPlugin(_ref) {
119
117
  var options = _ref.config,
120
118
  api = _ref.api;
119
+ var currentPlaceholder = options === null || options === void 0 ? void 0 : options.placeholder;
121
120
  return {
122
121
  name: 'placeholder',
122
+ commands: {
123
+ setPlaceholder: function setPlaceholder(placeholderText) {
124
+ return function (_ref2) {
125
+ var tr = _ref2.tr;
126
+ if (currentPlaceholder !== placeholderText) {
127
+ currentPlaceholder = placeholderText;
128
+ return tr.setMeta(pluginKey, {
129
+ placeholderText: placeholderText
130
+ });
131
+ }
132
+ return null;
133
+ };
134
+ }
135
+ },
123
136
  pmPlugins: function pmPlugins() {
124
137
  return [{
125
138
  name: 'placeholder',
@@ -35,7 +35,7 @@ export function createPlaceholderDecoration(editorState, placeholderText, pos =
35
35
  }
36
36
  return DecorationSet.create(editorState.doc, [Decoration.widget(pos, placeholderDecoration, {
37
37
  side: 0,
38
- key: 'placeholder'
38
+ key: `placeholder ${placeholderText}`
39
39
  })]);
40
40
  }
41
41
  function setPlaceHolderState(placeholderText, pos) {
@@ -45,12 +45,13 @@ function setPlaceHolderState(placeholderText, pos) {
45
45
  pos: pos ? pos : 1
46
46
  };
47
47
  }
48
- const emptyPlaceholder = {
49
- hasPlaceholder: false
50
- };
48
+ const emptyPlaceholder = placeholderText => ({
49
+ hasPlaceholder: false,
50
+ placeholderText
51
+ });
51
52
  function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpen, defaultPlaceholderText, bracketPlaceholderText) {
52
53
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
53
- return emptyPlaceholder;
54
+ return emptyPlaceholder(defaultPlaceholderText);
54
55
  }
55
56
  if (defaultPlaceholderText && isEmptyDocument(editorState.doc)) {
56
57
  return setPlaceHolderState(defaultPlaceholderText);
@@ -63,7 +64,7 @@ function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpe
63
64
  const bracketHint = ' ' + bracketPlaceholderText;
64
65
  return setPlaceHolderState(bracketHint, $from.pos - 1);
65
66
  }
66
- return emptyPlaceholder;
67
+ return emptyPlaceholder(defaultPlaceholderText);
67
68
  }
68
69
  export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api) {
69
70
  if (!defaultPlaceholderText && !bracketPlaceholderText) {
@@ -76,20 +77,15 @@ export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api
76
77
  var _api$focus, _api$focus$sharedStat, _api$typeAhead;
77
78
  return createPlaceHolderStateFrom(Boolean(api === null || api === void 0 ? void 0 : (_api$focus = api.focus) === null || _api$focus === void 0 ? void 0 : (_api$focus$sharedStat = _api$focus.sharedState.currentState()) === null || _api$focus$sharedStat === void 0 ? void 0 : _api$focus$sharedStat.hasFocus), state, api === null || api === void 0 ? void 0 : (_api$typeAhead = api.typeAhead) === null || _api$typeAhead === void 0 ? void 0 : _api$typeAhead.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
78
79
  },
79
- apply: (tr, _oldPluginState, _oldEditorState, newEditorState) => {
80
- var _api$focus2, _api$focus2$sharedSta, _api$typeAhead3;
80
+ apply: (tr, placeholderState, _oldEditorState, newEditorState) => {
81
+ var _api$focus2, _api$focus2$sharedSta, _api$typeAhead3, _placeholderState$pla;
81
82
  const meta = tr.getMeta(pluginKey);
82
83
  const isEditorFocused = Boolean(api === null || api === void 0 ? void 0 : (_api$focus2 = api.focus) === null || _api$focus2 === void 0 ? void 0 : (_api$focus2$sharedSta = _api$focus2.sharedState.currentState()) === null || _api$focus2$sharedSta === void 0 ? void 0 : _api$focus2$sharedSta.hasFocus);
83
- if (meta) {
84
- if (meta.removePlaceholder) {
85
- return emptyPlaceholder;
86
- }
87
- if (meta.applyPlaceholderIfEmpty) {
88
- var _api$typeAhead2;
89
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 ? void 0 : (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
90
- }
84
+ if ((meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined) {
85
+ var _api$typeAhead2;
86
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 ? void 0 : (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, meta.placeholderText, bracketPlaceholderText);
91
87
  }
92
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 ? void 0 : (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
88
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 ? void 0 : (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText, bracketPlaceholderText);
93
89
  }
94
90
  },
95
91
  props: {
@@ -112,12 +108,28 @@ export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api
112
108
  export const placeholderPlugin = ({
113
109
  config: options,
114
110
  api
115
- }) => ({
116
- name: 'placeholder',
117
- pmPlugins() {
118
- return [{
119
- name: 'placeholder',
120
- plugin: () => createPlugin(options && options.placeholder, options && options.placeholderBracketHint, api)
121
- }];
122
- }
123
- });
111
+ }) => {
112
+ let currentPlaceholder = options === null || options === void 0 ? void 0 : options.placeholder;
113
+ return {
114
+ name: 'placeholder',
115
+ commands: {
116
+ setPlaceholder: placeholderText => ({
117
+ tr
118
+ }) => {
119
+ if (currentPlaceholder !== placeholderText) {
120
+ currentPlaceholder = placeholderText;
121
+ return tr.setMeta(pluginKey, {
122
+ placeholderText: placeholderText
123
+ });
124
+ }
125
+ return null;
126
+ }
127
+ },
128
+ pmPlugins() {
129
+ return [{
130
+ name: 'placeholder',
131
+ plugin: () => createPlugin(options && options.placeholder, options && options.placeholderBracketHint, api)
132
+ }];
133
+ }
134
+ };
135
+ };
@@ -36,7 +36,7 @@ export function createPlaceholderDecoration(editorState, placeholderText) {
36
36
  }
37
37
  return DecorationSet.create(editorState.doc, [Decoration.widget(pos, placeholderDecoration, {
38
38
  side: 0,
39
- key: 'placeholder'
39
+ key: "placeholder ".concat(placeholderText)
40
40
  })]);
41
41
  }
42
42
  function setPlaceHolderState(placeholderText, pos) {
@@ -46,12 +46,15 @@ function setPlaceHolderState(placeholderText, pos) {
46
46
  pos: pos ? pos : 1
47
47
  };
48
48
  }
49
- var emptyPlaceholder = {
50
- hasPlaceholder: false
49
+ var emptyPlaceholder = function emptyPlaceholder(placeholderText) {
50
+ return {
51
+ hasPlaceholder: false,
52
+ placeholderText: placeholderText
53
+ };
51
54
  };
52
55
  function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpen, defaultPlaceholderText, bracketPlaceholderText) {
53
56
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
54
- return emptyPlaceholder;
57
+ return emptyPlaceholder(defaultPlaceholderText);
55
58
  }
56
59
  if (defaultPlaceholderText && isEmptyDocument(editorState.doc)) {
57
60
  return setPlaceHolderState(defaultPlaceholderText);
@@ -62,7 +65,7 @@ function createPlaceHolderStateFrom(isEditorFocused, editorState, isTypeAheadOpe
62
65
  var bracketHint = ' ' + bracketPlaceholderText;
63
66
  return setPlaceHolderState(bracketHint, $from.pos - 1);
64
67
  }
65
- return emptyPlaceholder;
68
+ return emptyPlaceholder(defaultPlaceholderText);
66
69
  }
67
70
  export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api) {
68
71
  if (!defaultPlaceholderText && !bracketPlaceholderText) {
@@ -75,20 +78,15 @@ export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api
75
78
  var _api$focus, _api$typeAhead;
76
79
  return createPlaceHolderStateFrom(Boolean(api === null || api === void 0 || (_api$focus = api.focus) === null || _api$focus === void 0 || (_api$focus = _api$focus.sharedState.currentState()) === null || _api$focus === void 0 ? void 0 : _api$focus.hasFocus), state, api === null || api === void 0 || (_api$typeAhead = api.typeAhead) === null || _api$typeAhead === void 0 ? void 0 : _api$typeAhead.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
77
80
  },
78
- apply: function apply(tr, _oldPluginState, _oldEditorState, newEditorState) {
79
- var _api$focus2, _api$typeAhead3;
81
+ apply: function apply(tr, placeholderState, _oldEditorState, newEditorState) {
82
+ var _api$focus2, _api$typeAhead3, _placeholderState$pla;
80
83
  var meta = tr.getMeta(pluginKey);
81
84
  var isEditorFocused = Boolean(api === null || api === void 0 || (_api$focus2 = api.focus) === null || _api$focus2 === void 0 || (_api$focus2 = _api$focus2.sharedState.currentState()) === null || _api$focus2 === void 0 ? void 0 : _api$focus2.hasFocus);
82
- if (meta) {
83
- if (meta.removePlaceholder) {
84
- return emptyPlaceholder;
85
- }
86
- if (meta.applyPlaceholderIfEmpty) {
87
- var _api$typeAhead2;
88
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
89
- }
85
+ if ((meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined) {
86
+ var _api$typeAhead2;
87
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen, meta.placeholderText, bracketPlaceholderText);
90
88
  }
91
- return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, defaultPlaceholderText, bracketPlaceholderText);
89
+ return createPlaceHolderStateFrom(isEditorFocused, newEditorState, api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen, (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText, bracketPlaceholderText);
92
90
  }
93
91
  },
94
92
  props: {
@@ -110,8 +108,23 @@ export function createPlugin(defaultPlaceholderText, bracketPlaceholderText, api
110
108
  export var placeholderPlugin = function placeholderPlugin(_ref) {
111
109
  var options = _ref.config,
112
110
  api = _ref.api;
111
+ var currentPlaceholder = options === null || options === void 0 ? void 0 : options.placeholder;
113
112
  return {
114
113
  name: 'placeholder',
114
+ commands: {
115
+ setPlaceholder: function setPlaceholder(placeholderText) {
116
+ return function (_ref2) {
117
+ var tr = _ref2.tr;
118
+ if (currentPlaceholder !== placeholderText) {
119
+ currentPlaceholder = placeholderText;
120
+ return tr.setMeta(pluginKey, {
121
+ placeholderText: placeholderText
122
+ });
123
+ }
124
+ return null;
125
+ };
126
+ }
127
+ },
115
128
  pmPlugins: function pmPlugins() {
116
129
  return [{
117
130
  name: 'placeholder',
@@ -1,4 +1,4 @@
1
- import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
2
  import type { CompositionPlugin } from '@atlaskit/editor-plugin-composition';
3
3
  import type { FocusPlugin } from '@atlaskit/editor-plugin-focus';
4
4
  import type { TypeAheadPlugin } from '@atlaskit/editor-plugin-type-ahead';
@@ -8,5 +8,8 @@ export interface PlaceholderPluginOptions {
8
8
  }
9
9
  export type PlaceholderPlugin = NextEditorPlugin<'placeholder', {
10
10
  pluginConfiguration: PlaceholderPluginOptions | undefined;
11
+ commands: {
12
+ setPlaceholder: (placeholder: string) => EditorCommand;
13
+ };
11
14
  dependencies: [FocusPlugin, CompositionPlugin, TypeAheadPlugin];
12
15
  }>;
@@ -1,4 +1,4 @@
1
- import type { NextEditorPlugin } from '@atlaskit/editor-common/types';
1
+ import type { EditorCommand, NextEditorPlugin } from '@atlaskit/editor-common/types';
2
2
  import type { CompositionPlugin } from '@atlaskit/editor-plugin-composition';
3
3
  import type { FocusPlugin } from '@atlaskit/editor-plugin-focus';
4
4
  import type { TypeAheadPlugin } from '@atlaskit/editor-plugin-type-ahead';
@@ -8,6 +8,9 @@ export interface PlaceholderPluginOptions {
8
8
  }
9
9
  export type PlaceholderPlugin = NextEditorPlugin<'placeholder', {
10
10
  pluginConfiguration: PlaceholderPluginOptions | undefined;
11
+ commands: {
12
+ setPlaceholder: (placeholder: string) => EditorCommand;
13
+ };
11
14
  dependencies: [
12
15
  FocusPlugin,
13
16
  CompositionPlugin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-placeholder",
3
- "version": "1.5.0",
3
+ "version": "2.0.0",
4
4
  "description": "Placeholder plugin for @atlaskit/editor-core.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -31,16 +31,16 @@
31
31
  ".": "./src/index.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@atlaskit/editor-common": "^99.10.0",
34
+ "@atlaskit/editor-common": "^100.0.0",
35
35
  "@atlaskit/editor-plugin-composition": "^1.3.0",
36
36
  "@atlaskit/editor-plugin-focus": "^1.5.0",
37
- "@atlaskit/editor-plugin-type-ahead": "^1.13.0",
37
+ "@atlaskit/editor-plugin-type-ahead": "^2.0.0",
38
38
  "@atlaskit/editor-prosemirror": "7.0.0",
39
39
  "@babel/runtime": "^7.0.0"
40
40
  },
41
41
  "peerDependencies": {
42
- "react": "^16.8.0 || ^17.0.0 || ~18.2.0",
43
- "react-dom": "^16.8.0 || ^17.0.0 || ^18.2.0"
42
+ "react": "^18.2.0",
43
+ "react-dom": "^18.2.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@testing-library/react": "^13.4.0",