@atlaskit/menu 2.0.1 → 2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @atlaskit/menu
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#41571](https://bitbucket.org/atlassian/atlassian-frontend/pull-requests/41571) [`997b0489687`](https://bitbucket.org/atlassian/atlassian-frontend/commits/997b0489687) - Add codemod to convert link item components with invalid `href` attributes to button items. The `href` attribute will be required for link items in a later major upgrade. Using this will ease the transition.
8
+
3
9
  ## 2.0.1
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,208 @@
1
+ import core, {
2
+ API,
3
+ ASTPath,
4
+ FileInfo,
5
+ ImportDeclaration,
6
+ ImportSpecifier,
7
+ Options,
8
+ } from 'jscodeshift';
9
+
10
+ const invalidHrefValues = ['', '#'];
11
+ const pkg = '@atlaskit/menu';
12
+
13
+ function getJSXAttributesByName(
14
+ j: core.JSCodeshift,
15
+ element: ASTPath<any>,
16
+ attributeName: string,
17
+ ) {
18
+ return j(element)
19
+ .find(j.JSXOpeningElement)
20
+ .find(j.JSXAttribute)
21
+ .filter((attribute) => {
22
+ const matches = j(attribute)
23
+ .find(j.JSXIdentifier)
24
+ .filter((identifier) => identifier.value.name === attributeName);
25
+ return Boolean(matches.length);
26
+ });
27
+ }
28
+
29
+ function getImportSpecifier(
30
+ j: core.JSCodeshift,
31
+ source: ReturnType<typeof j>,
32
+ specifier: string,
33
+ imported: string,
34
+ ) {
35
+ const specifiers = source
36
+ .find(j.ImportDeclaration)
37
+ .filter(
38
+ (path: ASTPath<ImportDeclaration>) =>
39
+ path.node.source.value === specifier,
40
+ )
41
+ .find(j.ImportSpecifier)
42
+ .filter(
43
+ (path: ASTPath<ImportSpecifier>) => path.value.imported.name === imported,
44
+ );
45
+
46
+ if (!specifiers.length) {
47
+ return null;
48
+ }
49
+
50
+ return specifiers.nodes()[0]!.local!.name;
51
+ }
52
+
53
+ function convertInvalidLinkItemsToButtonItems(
54
+ j: core.JSCodeshift,
55
+ source: ReturnType<typeof j>,
56
+ specifier: string,
57
+ ) {
58
+ // For each instance of LinkItem
59
+ source.findJSXElements(specifier).forEach((element) => {
60
+ const hrefPropCollection = getJSXAttributesByName(j, element, 'href');
61
+
62
+ // base case: no `href` prop exists, it is invalid
63
+ let validHref = false;
64
+
65
+ // if `href` exists
66
+ if (hrefPropCollection.length > 0) {
67
+ const hrefProp = hrefPropCollection.get();
68
+
69
+ const hrefStringLiteral = j(hrefProp).find(j.StringLiteral);
70
+ const hrefExpressionContainer = j(hrefProp)
71
+ .find(j.JSXExpressionContainer)
72
+ .find(j.Expression);
73
+
74
+ // This is tin foil hattery. Can something be neither a string literal
75
+ // nor an expression container? Don't know but gonna cover that
76
+ if (
77
+ hrefStringLiteral.length === 0 &&
78
+ hrefExpressionContainer.length === 0
79
+ ) {
80
+ return;
81
+ }
82
+
83
+ if (hrefStringLiteral.length > 0) {
84
+ const hrefValue = hrefStringLiteral.get().value.value;
85
+ if (invalidHrefValues.includes(hrefValue)) {
86
+ j(hrefProp).forEach((el) => j(el).remove());
87
+ } else {
88
+ validHref = true;
89
+ }
90
+ } else {
91
+ // It seems foolish to try and resolve variables, so we will assume it
92
+ // is valid
93
+ validHref = true;
94
+ }
95
+ }
96
+
97
+ if (!validHref) {
98
+ const pkgImport = source
99
+ .find(j.ImportDeclaration)
100
+ .filter((path) => path.node.source.value === pkg);
101
+ const buttonItemIsImported =
102
+ pkgImport
103
+ .find(j.ImportSpecifier)
104
+ .nodes()
105
+ .filter((node) => node.imported.name === 'ButtonItem').length > 0;
106
+ if (!buttonItemIsImported) {
107
+ // Add ButtonItem to imports
108
+ const newSpecifier = j.importSpecifier(j.identifier('ButtonItem'));
109
+ pkgImport.forEach((moduleImport) => {
110
+ const specifiers = moduleImport.node.specifiers
111
+ ? [...moduleImport.node.specifiers]
112
+ : [];
113
+ j(moduleImport).replaceWith(
114
+ j.importDeclaration(
115
+ specifiers.concat([newSpecifier]),
116
+ moduleImport.node.source,
117
+ ),
118
+ );
119
+ });
120
+ }
121
+
122
+ // Replace existing LinkItem with ButtonItem, while maintaining the same props
123
+ if (element.value.openingElement.name.type === 'JSXIdentifier') {
124
+ element.value.openingElement.name.name = 'ButtonItem';
125
+ if (
126
+ element.value.closingElement &&
127
+ element.value.closingElement.name.type === 'JSXIdentifier'
128
+ ) {
129
+ element.value.closingElement.name.name = 'ButtonItem';
130
+ }
131
+ }
132
+ }
133
+ });
134
+ }
135
+
136
+ function removeLinkItemImportIfNoLinkItemsExist(
137
+ j: core.JSCodeshift,
138
+ source: ReturnType<typeof j>,
139
+ specifier: string,
140
+ ) {
141
+ // Get all instances of LinkItem
142
+ const linkItemInstances = source.findJSXElements(specifier);
143
+
144
+ // if none, delete from imports
145
+ if (linkItemInstances.length === 0) {
146
+ source
147
+ .find(j.ImportDeclaration)
148
+ .filter((path) => path.node.source.value === pkg)
149
+ .forEach((moduleImport) => {
150
+ j(moduleImport).replaceWith(
151
+ j.importDeclaration(
152
+ moduleImport.node.specifiers &&
153
+ moduleImport.node.specifiers
154
+ .filter(
155
+ // This should be `ImportSpecifier | ImportDefaultSpecifier |
156
+ // ImportNamespaceSpecifier` but it still throws even though
157
+ // I'm filtering
158
+ (
159
+ currentSpecifier: any,
160
+ ): currentSpecifier is ImportSpecifier =>
161
+ currentSpecifier?.imported,
162
+ )
163
+ .filter(
164
+ (currentSpecifier: ImportSpecifier) =>
165
+ currentSpecifier.imported.name !== specifier,
166
+ ),
167
+ moduleImport.node.source,
168
+ ),
169
+ );
170
+ });
171
+ }
172
+ }
173
+
174
+ function hasImportDeclaration(
175
+ j: core.JSCodeshift,
176
+ source: ReturnType<typeof j>,
177
+ importPath: string,
178
+ ) {
179
+ return !!source
180
+ .find(j.ImportDeclaration)
181
+ .filter((path) => path.node.source.value === importPath).length;
182
+ }
183
+
184
+ export default function transformer(
185
+ fileInfo: FileInfo,
186
+ { jscodeshift: j }: API,
187
+ options: Options,
188
+ ) {
189
+ const source = j(fileInfo.source);
190
+
191
+ if (hasImportDeclaration(j, source, pkg)) {
192
+ const importSpecifier = getImportSpecifier(j, source, pkg, 'LinkItem');
193
+
194
+ if (importSpecifier != null) {
195
+ convertInvalidLinkItemsToButtonItems(j, source, importSpecifier);
196
+ removeLinkItemImportIfNoLinkItemsExist(j, source, importSpecifier);
197
+ }
198
+
199
+ return source.toSource(
200
+ options.printOptions || {
201
+ quote: 'single',
202
+ trailingComma: true,
203
+ },
204
+ );
205
+ }
206
+
207
+ return fileInfo.source;
208
+ }
@@ -0,0 +1,308 @@
1
+ jest.autoMockOff();
2
+
3
+ import * as transformer from '../2.1.0-invalid-link-item-to-button-item';
4
+
5
+ const defineInlineTest = require('jscodeshift/dist/testUtils').defineInlineTest;
6
+
7
+ describe('Converts link items with invalid or missing `href` to button items', () => {
8
+ /**
9
+ *
10
+ * Success cases
11
+ *
12
+ */
13
+ defineInlineTest(
14
+ { ...transformer, parser: 'tsx' },
15
+ {},
16
+ `
17
+ import { LinkItem } from '@atlaskit/something';
18
+
19
+ const App = () => {
20
+ return <LinkItem />;
21
+ }
22
+ `,
23
+ `
24
+ import { LinkItem } from '@atlaskit/something';
25
+
26
+ const App = () => {
27
+ return <LinkItem />;
28
+ }
29
+ `,
30
+ 'leaves unrelated code untouched',
31
+ );
32
+
33
+ defineInlineTest(
34
+ { ...transformer, parser: 'tsx' },
35
+ {},
36
+ `
37
+ import { LinkItem } from '@atlaskit/menu';
38
+ import { variable } from 'somewhere';
39
+
40
+ const App = () => {
41
+ return <LinkItem href={variable}>test</LinkItem>;
42
+ }
43
+ `,
44
+ `
45
+ import { LinkItem } from '@atlaskit/menu';
46
+ import { variable } from 'somewhere';
47
+
48
+ const App = () => {
49
+ return <LinkItem href={variable}>test</LinkItem>;
50
+ }
51
+ `,
52
+ 'should not do anything with `href`s that are variables',
53
+ );
54
+
55
+ defineInlineTest(
56
+ { ...transformer, parser: 'tsx' },
57
+ {},
58
+ `
59
+ import { LinkItem } from '@atlaskit/menu';
60
+
61
+ const App = () => {
62
+ return <LinkItem href="http://valid.com">test</LinkItem>;
63
+ }
64
+ `,
65
+ `
66
+ import { LinkItem } from '@atlaskit/menu';
67
+
68
+ const App = () => {
69
+ return <LinkItem href="http://valid.com">test</LinkItem>;
70
+ }
71
+ `,
72
+ 'should not do anything with a valid `href`',
73
+ );
74
+
75
+ /**
76
+ *
77
+ * Missing `href`
78
+ *
79
+ */
80
+
81
+ defineInlineTest(
82
+ { ...transformer, parser: 'tsx' },
83
+ {},
84
+ `
85
+ import { LinkItem } from '@atlaskit/menu';
86
+
87
+ const App = () => {
88
+ return <LinkItem>test</LinkItem>;
89
+ }
90
+ `,
91
+ `
92
+ import { ButtonItem } from '@atlaskit/menu';
93
+
94
+ const App = () => {
95
+ return <ButtonItem>test</ButtonItem>;
96
+ }
97
+ `,
98
+ 'Should convert to ButtonItem if no href exists on LinkItem',
99
+ );
100
+
101
+ defineInlineTest(
102
+ { ...transformer, parser: 'tsx' },
103
+ {},
104
+ `
105
+ import { LinkItem } from '@atlaskit/menu';
106
+
107
+ const App = () => {
108
+ return <LinkItem id="test">test</LinkItem>;
109
+ }
110
+ `,
111
+ `
112
+ import { ButtonItem } from '@atlaskit/menu';
113
+
114
+ const App = () => {
115
+ return <ButtonItem id="test">test</ButtonItem>;
116
+ }
117
+ `,
118
+ 'Should convert to ButtonItem but keep existing props if no href exists on LinkItem',
119
+ );
120
+
121
+ /**
122
+ *
123
+ * Invalid `href`
124
+ *
125
+ */
126
+
127
+ defineInlineTest(
128
+ { ...transformer, parser: 'tsx' },
129
+ {},
130
+ `
131
+ import { LinkItem } from '@atlaskit/menu';
132
+
133
+ const App = () => {
134
+ return <LinkItem href="#">test</LinkItem>;
135
+ }
136
+ `,
137
+ `
138
+ import { ButtonItem } from '@atlaskit/menu';
139
+
140
+ const App = () => {
141
+ return <ButtonItem>test</ButtonItem>;
142
+ }
143
+ `,
144
+ 'Should convert to ButtonItem if invalid `href`',
145
+ );
146
+
147
+ defineInlineTest(
148
+ { ...transformer, parser: 'tsx' },
149
+ {},
150
+ `
151
+ import { LinkItem } from '@atlaskit/menu';
152
+
153
+ const App = () => {
154
+ return <LinkItem href="#" id="test">test</LinkItem>;
155
+ }
156
+ `,
157
+ `
158
+ import { ButtonItem } from '@atlaskit/menu';
159
+
160
+ const App = () => {
161
+ return <ButtonItem id="test">test</ButtonItem>;
162
+ }
163
+ `,
164
+ 'Should convert to ButtonItem but keep existing props if invalid `href`',
165
+ );
166
+
167
+ defineInlineTest(
168
+ { ...transformer, parser: 'tsx' },
169
+ {},
170
+ `
171
+ import { LinkItem } from '@atlaskit/menu';
172
+
173
+ const App = () => {
174
+ return <LinkItem href="">test</LinkItem>;
175
+ }
176
+ `,
177
+ `
178
+ import { ButtonItem } from '@atlaskit/menu';
179
+
180
+ const App = () => {
181
+ return <ButtonItem>test</ButtonItem>;
182
+ }
183
+ `,
184
+ 'Should convert to ButtonItem if invalid `href`',
185
+ );
186
+
187
+ /**
188
+ *
189
+ * Expressions
190
+ *
191
+ */
192
+
193
+ defineInlineTest(
194
+ { ...transformer, parser: 'tsx' },
195
+ {},
196
+ `
197
+ import { LinkItem } from '@atlaskit/menu';
198
+
199
+ const App = () => {
200
+ return <LinkItem href={''}>test</LinkItem>;
201
+ }
202
+ `,
203
+ `
204
+ import { ButtonItem } from '@atlaskit/menu';
205
+
206
+ const App = () => {
207
+ return <ButtonItem>test</ButtonItem>;
208
+ }
209
+ `,
210
+ 'should handle strings in expression containers',
211
+ );
212
+
213
+ /**
214
+ *
215
+ * Edge cases
216
+ *
217
+ */
218
+
219
+ defineInlineTest(
220
+ { ...transformer, parser: 'tsx' },
221
+ {},
222
+ `
223
+ import { LinkItem, ButtonItem } from '@atlaskit/menu';
224
+
225
+ const App = () => {
226
+ return (
227
+ <div>
228
+ <LinkItem href="">test 1</LinkItem>
229
+ <ButtonItem>test 2</ButtonItem>
230
+ </div>
231
+ );
232
+ }
233
+ `,
234
+ `
235
+ import { ButtonItem } from '@atlaskit/menu';
236
+
237
+ const App = () => {
238
+ return (
239
+ <div>
240
+ <ButtonItem>test 1</ButtonItem>
241
+ <ButtonItem>test 2</ButtonItem>
242
+ </div>
243
+ );
244
+ }
245
+ `,
246
+ 'Should handle multiple item types',
247
+ );
248
+
249
+ defineInlineTest(
250
+ { ...transformer, parser: 'tsx' },
251
+ {},
252
+ `
253
+ import { LinkItem, CustomItem } from '@atlaskit/menu';
254
+
255
+ const App = () => {
256
+ return (
257
+ <div>
258
+ <LinkItem href="">test 1</LinkItem>
259
+ <CustomItem>test 2</CustomItem>
260
+ </div>
261
+ );
262
+ }
263
+ `,
264
+ `
265
+ import { CustomItem, ButtonItem } from '@atlaskit/menu';
266
+
267
+ const App = () => {
268
+ return (
269
+ <div>
270
+ <ButtonItem>test 1</ButtonItem>
271
+ <CustomItem>test 2</CustomItem>
272
+ </div>
273
+ );
274
+ }
275
+ `,
276
+ 'Should not delete other imports',
277
+ );
278
+
279
+ defineInlineTest(
280
+ { ...transformer, parser: 'tsx' },
281
+ {},
282
+ `
283
+ import { LinkItem } from '@atlaskit/menu';
284
+
285
+ const App = () => {
286
+ return (
287
+ <div>
288
+ <LinkItem href="">test 1</LinkItem>
289
+ <LinkItem href="http://example.com">test 2</LinkItem>
290
+ </div>
291
+ );
292
+ }
293
+ `,
294
+ `
295
+ import { LinkItem, ButtonItem } from '@atlaskit/menu';
296
+
297
+ const App = () => {
298
+ return (
299
+ <div>
300
+ <ButtonItem>test 1</ButtonItem>
301
+ <LinkItem href="http://example.com">test 2</LinkItem>
302
+ </div>
303
+ );
304
+ }
305
+ `,
306
+ 'Should allow valid `href` and convert invalid ones',
307
+ );
308
+ });
@@ -188,7 +188,8 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
188
188
  _ref$isDisabled = _ref.isDisabled,
189
189
  isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled,
190
190
  _ref$isSelected = _ref.isSelected,
191
- isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected;
191
+ isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected,
192
+ testId = _ref.testId;
192
193
  (0, _deprecationWarning.propDeprecationWarning)("@atlaskit/menu" || '', 'overrides', overrides !== undefined, '' // TODO: Create DAC post when primitives/xcss are available as alternatives
193
194
  );
194
195
 
@@ -208,10 +209,12 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
208
209
  spread: "space-between",
209
210
  alignBlock: "center",
210
211
  space: gapMap[spacing],
211
- grow: "fill"
212
+ grow: "fill",
213
+ testId: testId && "".concat(testId, "--container")
212
214
  }, iconBefore && (0, _react2.jsx)("span", {
213
215
  "data-item-elem-before": true,
214
- css: beforeAfterElementStyles
216
+ css: beforeAfterElementStyles,
217
+ "data-testid": testId && "".concat(testId, "--icon-before")
215
218
  }, iconBefore), title && (0, _react2.jsx)("span", {
216
219
  css: contentStyles
217
220
  }, renderTitle('span', {
@@ -223,7 +226,8 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
223
226
  css: [descriptionStyles, isDisabled && disabledDescriptionStyles, shouldDescriptionWrap ? wordBreakStyles : truncateStyles]
224
227
  }, description)), iconAfter && (0, _react2.jsx)("span", {
225
228
  "data-item-elem-after": true,
226
- css: beforeAfterElementStyles
229
+ css: beforeAfterElementStyles,
230
+ "data-testid": testId && "".concat(testId, "--icon-after")
227
231
  }, iconAfter))
228
232
  }));
229
233
  });
@@ -69,7 +69,8 @@ function (props, ref) {
69
69
  cssFn({
70
70
  isSelected: isSelected,
71
71
  isDisabled: isDisabled
72
- })
72
+ }),
73
+ testId: testId && "".concat(testId, "--primitive")
73
74
  }), function (_ref) {
74
75
  var children = _ref.children,
75
76
  className = _ref.className;
@@ -74,7 +74,8 @@ var CustomItem = /*#__PURE__*/(0, _react.memo)( /*#__PURE__*/(0, _react.forwardR
74
74
  css: (0, _react2.css)(cssFn({
75
75
  isDisabled: isDisabled,
76
76
  isSelected: isSelected
77
- }))
77
+ })),
78
+ testId: testId && "".concat(testId, "--primitive")
78
79
  }), function (_ref2) {
79
80
  var children = _ref2.children,
80
81
  className = _ref2.className;
@@ -74,7 +74,8 @@ function (props, ref) {
74
74
  isSelected: isSelected,
75
75
  isDisabled: isDisabled
76
76
  }),
77
- title: children
77
+ title: children,
78
+ testId: testId && "".concat(testId, "--primitive")
78
79
  }), function (_ref) {
79
80
  var children = _ref.children,
80
81
  className = _ref.className;
@@ -173,7 +173,8 @@ const MenuItemPrimitive = ({
173
173
  shouldTitleWrap = false,
174
174
  shouldDescriptionWrap = false,
175
175
  isDisabled = false,
176
- isSelected = false
176
+ isSelected = false,
177
+ testId
177
178
  }) => {
178
179
  propDeprecationWarning("@atlaskit/menu" || '', 'overrides', overrides !== undefined, '' // TODO: Create DAC post when primitives/xcss are available as alternatives
179
180
  );
@@ -195,10 +196,12 @@ const MenuItemPrimitive = ({
195
196
  spread: "space-between",
196
197
  alignBlock: "center",
197
198
  space: gapMap[spacing],
198
- grow: "fill"
199
+ grow: "fill",
200
+ testId: testId && `${testId}--container`
199
201
  }, iconBefore && jsx("span", {
200
202
  "data-item-elem-before": true,
201
- css: beforeAfterElementStyles
203
+ css: beforeAfterElementStyles,
204
+ "data-testid": testId && `${testId}--icon-before`
202
205
  }, iconBefore), title && jsx("span", {
203
206
  css: contentStyles
204
207
  }, renderTitle('span', {
@@ -210,7 +213,8 @@ const MenuItemPrimitive = ({
210
213
  css: [descriptionStyles, isDisabled && disabledDescriptionStyles, shouldDescriptionWrap ? wordBreakStyles : truncateStyles]
211
214
  }, description)), iconAfter && jsx("span", {
212
215
  "data-item-elem-after": true,
213
- css: beforeAfterElementStyles
216
+ css: beforeAfterElementStyles,
217
+ "data-testid": testId && `${testId}--icon-after`
214
218
  }, iconAfter))
215
219
  }));
216
220
  });
@@ -63,7 +63,8 @@ const ButtonItem = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(
63
63
  cssFn({
64
64
  isSelected,
65
65
  isDisabled
66
- })
66
+ }),
67
+ testId: testId && `${testId}--primitive`
67
68
  }), ({
68
69
  children,
69
70
  className
@@ -68,7 +68,8 @@ const CustomItem = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
68
68
  css: css(cssFn({
69
69
  isDisabled,
70
70
  isSelected
71
- }))
71
+ })),
72
+ testId: testId && `${testId}--primitive`
72
73
  }), ({
73
74
  children,
74
75
  className
@@ -68,7 +68,8 @@ const LinkItem = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(
68
68
  isSelected,
69
69
  isDisabled
70
70
  }),
71
- title: children
71
+ title: children,
72
+ testId: testId && `${testId}--primitive`
72
73
  }), ({
73
74
  children,
74
75
  className
@@ -180,7 +180,8 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
180
180
  _ref$isDisabled = _ref.isDisabled,
181
181
  isDisabled = _ref$isDisabled === void 0 ? false : _ref$isDisabled,
182
182
  _ref$isSelected = _ref.isSelected,
183
- isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected;
183
+ isSelected = _ref$isSelected === void 0 ? false : _ref$isSelected,
184
+ testId = _ref.testId;
184
185
  propDeprecationWarning("@atlaskit/menu" || '', 'overrides', overrides !== undefined, '' // TODO: Create DAC post when primitives/xcss are available as alternatives
185
186
  );
186
187
 
@@ -200,10 +201,12 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
200
201
  spread: "space-between",
201
202
  alignBlock: "center",
202
203
  space: gapMap[spacing],
203
- grow: "fill"
204
+ grow: "fill",
205
+ testId: testId && "".concat(testId, "--container")
204
206
  }, iconBefore && jsx("span", {
205
207
  "data-item-elem-before": true,
206
- css: beforeAfterElementStyles
208
+ css: beforeAfterElementStyles,
209
+ "data-testid": testId && "".concat(testId, "--icon-before")
207
210
  }, iconBefore), title && jsx("span", {
208
211
  css: contentStyles
209
212
  }, renderTitle('span', {
@@ -215,7 +218,8 @@ var MenuItemPrimitive = function MenuItemPrimitive(_ref) {
215
218
  css: [descriptionStyles, isDisabled && disabledDescriptionStyles, shouldDescriptionWrap ? wordBreakStyles : truncateStyles]
216
219
  }, description)), iconAfter && jsx("span", {
217
220
  "data-item-elem-after": true,
218
- css: beforeAfterElementStyles
221
+ css: beforeAfterElementStyles,
222
+ "data-testid": testId && "".concat(testId, "--icon-after")
219
223
  }, iconAfter))
220
224
  }));
221
225
  });
@@ -62,7 +62,8 @@ function (props, ref) {
62
62
  cssFn({
63
63
  isSelected: isSelected,
64
64
  isDisabled: isDisabled
65
- })
65
+ }),
66
+ testId: testId && "".concat(testId, "--primitive")
66
67
  }), function (_ref) {
67
68
  var children = _ref.children,
68
69
  className = _ref.className;
@@ -68,7 +68,8 @@ var CustomItem = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(function (_ref, ref)
68
68
  css: css(cssFn({
69
69
  isDisabled: isDisabled,
70
70
  isSelected: isSelected
71
- }))
71
+ })),
72
+ testId: testId && "".concat(testId, "--primitive")
72
73
  }), function (_ref2) {
73
74
  var children = _ref2.children,
74
75
  className = _ref2.className;
@@ -67,7 +67,8 @@ function (props, ref) {
67
67
  isSelected: isSelected,
68
68
  isDisabled: isDisabled
69
69
  }),
70
- title: children
70
+ title: children,
71
+ testId: testId && "".concat(testId, "--primitive")
71
72
  }), function (_ref) {
72
73
  var children = _ref.children,
73
74
  className = _ref.className;
@@ -14,5 +14,5 @@ import type { MenuItemPrimitiveProps } from '../../types';
14
14
  * </MenuItemPrimitive>
15
15
  * ```
16
16
  */
17
- declare const MenuItemPrimitive: ({ children, title, description, iconAfter, iconBefore, overrides, className: UNSAFE_externalClassName, shouldTitleWrap, shouldDescriptionWrap, isDisabled, isSelected, }: MenuItemPrimitiveProps) => jsx.JSX.Element;
17
+ declare const MenuItemPrimitive: ({ children, title, description, iconAfter, iconBefore, overrides, className: UNSAFE_externalClassName, shouldTitleWrap, shouldDescriptionWrap, isDisabled, isSelected, testId, }: MenuItemPrimitiveProps) => jsx.JSX.Element;
18
18
  export default MenuItemPrimitive;
@@ -137,6 +137,7 @@ export interface MenuItemPrimitiveProps {
137
137
  isDisabled: boolean | undefined;
138
138
  isSelected: boolean | undefined;
139
139
  className?: string;
140
+ testId?: string;
140
141
  }
141
142
  export interface MenuItemProps {
142
143
  /**
@@ -14,5 +14,5 @@ import type { MenuItemPrimitiveProps } from '../../types';
14
14
  * </MenuItemPrimitive>
15
15
  * ```
16
16
  */
17
- declare const MenuItemPrimitive: ({ children, title, description, iconAfter, iconBefore, overrides, className: UNSAFE_externalClassName, shouldTitleWrap, shouldDescriptionWrap, isDisabled, isSelected, }: MenuItemPrimitiveProps) => jsx.JSX.Element;
17
+ declare const MenuItemPrimitive: ({ children, title, description, iconAfter, iconBefore, overrides, className: UNSAFE_externalClassName, shouldTitleWrap, shouldDescriptionWrap, isDisabled, isSelected, testId, }: MenuItemPrimitiveProps) => jsx.JSX.Element;
18
18
  export default MenuItemPrimitive;
@@ -137,6 +137,7 @@ export interface MenuItemPrimitiveProps {
137
137
  isDisabled: boolean | undefined;
138
138
  isSelected: boolean | undefined;
139
139
  className?: string;
140
+ testId?: string;
140
141
  }
141
142
  export interface MenuItemProps {
142
143
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/menu",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "A collection of composable menu components that can be used anywhere.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -31,7 +31,7 @@
31
31
  "@atlaskit/platform-feature-flags": "^0.2.0",
32
32
  "@atlaskit/primitives": "^1.6.0",
33
33
  "@atlaskit/theme": "^12.6.0",
34
- "@atlaskit/tokens": "^1.26.0",
34
+ "@atlaskit/tokens": "^1.27.0",
35
35
  "@babel/runtime": "^7.0.0",
36
36
  "@emotion/react": "^11.7.1"
37
37
  },