@atlaskit/popup 2.0.0 → 2.0.2

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,21 @@
1
1
  # @atlaskit/popup
2
2
 
3
+ ## 2.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#121410](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/121410)
8
+ [`b26d53ac2517a`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/b26d53ac2517a) -
9
+ Prevent onClick handler gets called when popup is open on Firefox
10
+
11
+ ## 2.0.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [#118418](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/118418)
16
+ [`d2e804df6bf9c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/d2e804df6bf9c) -
17
+ Update dependencies and remove old codemod and unused internal exports.
18
+
3
19
  ## 2.0.0
4
20
 
5
21
  ### Major Changes
package/dist/cjs/popup.js CHANGED
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.default = exports.Popup = void 0;
7
+ exports.Popup = void 0;
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
9
  var _react = require("react");
10
10
  var _react2 = require("@emotion/react");
@@ -139,5 +139,4 @@ var Popup = exports.Popup = /*#__PURE__*/(0, _react.memo)(function (_ref) {
139
139
  }, popupContent);
140
140
  }
141
141
  return popupContent;
142
- });
143
- var _default = exports.default = Popup;
142
+ });
@@ -188,16 +188,32 @@ var useCloseManager = exports.useCloseManager = function useCloseManager(_ref) {
188
188
  }
189
189
  });
190
190
  }
191
- var unbind = (0, _bindEventListener.bindAll)(window, [{
192
- type: 'click',
193
- listener: onClick,
194
- options: {
195
- capture: capture
196
- }
197
- }, {
198
- type: 'keydown',
199
- listener: onKeyDown
200
- }]);
191
+ var unbind = _noop.default;
192
+ if ((0, _platformFeatureFlags.fg)('popup-onclose-fix')) {
193
+ setTimeout(function () {
194
+ unbind = (0, _bindEventListener.bindAll)(window, [{
195
+ type: 'click',
196
+ listener: onClick,
197
+ options: {
198
+ capture: capture
199
+ }
200
+ }, {
201
+ type: 'keydown',
202
+ listener: onKeyDown
203
+ }]);
204
+ }, 0);
205
+ } else {
206
+ unbind = (0, _bindEventListener.bindAll)(window, [{
207
+ type: 'click',
208
+ listener: onClick,
209
+ options: {
210
+ capture: capture
211
+ }
212
+ }, {
213
+ type: 'keydown',
214
+ listener: onKeyDown
215
+ }]);
216
+ }
201
217
 
202
218
  // bind onBlur event listener to fix popup not close when clicking on iframe outside
203
219
  var unbindBlur = _noop.default;
@@ -212,8 +228,14 @@ var useCloseManager = exports.useCloseManager = function useCloseManager(_ref) {
212
228
  });
213
229
  return function () {
214
230
  var _parentUnbind;
231
+ if ((0, _platformFeatureFlags.fg)('popup-onclose-fix')) {
232
+ setTimeout(function () {
233
+ unbind();
234
+ }, 0);
235
+ } else {
236
+ unbind();
237
+ }
215
238
  cancelAllFrames();
216
- unbind();
217
239
  (_parentUnbind = parentUnbind) === null || _parentUnbind === void 0 || _parentUnbind();
218
240
  unbindBlur();
219
241
  };
@@ -119,5 +119,4 @@ export const Popup = /*#__PURE__*/memo(({
119
119
  }, popupContent);
120
120
  }
121
121
  return popupContent;
122
- });
123
- export default Popup;
122
+ });
@@ -189,16 +189,32 @@ export const useCloseManager = ({
189
189
  }
190
190
  });
191
191
  }
192
- const unbind = bindAll(window, [{
193
- type: 'click',
194
- listener: onClick,
195
- options: {
196
- capture
197
- }
198
- }, {
199
- type: 'keydown',
200
- listener: onKeyDown
201
- }]);
192
+ let unbind = noop;
193
+ if (fg('popup-onclose-fix')) {
194
+ setTimeout(() => {
195
+ unbind = bindAll(window, [{
196
+ type: 'click',
197
+ listener: onClick,
198
+ options: {
199
+ capture
200
+ }
201
+ }, {
202
+ type: 'keydown',
203
+ listener: onKeyDown
204
+ }]);
205
+ }, 0);
206
+ } else {
207
+ unbind = bindAll(window, [{
208
+ type: 'click',
209
+ listener: onClick,
210
+ options: {
211
+ capture
212
+ }
213
+ }, {
214
+ type: 'keydown',
215
+ listener: onKeyDown
216
+ }]);
217
+ }
202
218
 
203
219
  // bind onBlur event listener to fix popup not close when clicking on iframe outside
204
220
  let unbindBlur = noop;
@@ -213,8 +229,14 @@ export const useCloseManager = ({
213
229
  });
214
230
  return () => {
215
231
  var _parentUnbind;
232
+ if (fg('popup-onclose-fix')) {
233
+ setTimeout(() => {
234
+ unbind();
235
+ }, 0);
236
+ } else {
237
+ unbind();
238
+ }
216
239
  cancelAllFrames();
217
- unbind();
218
240
  (_parentUnbind = parentUnbind) === null || _parentUnbind === void 0 ? void 0 : _parentUnbind();
219
241
  unbindBlur();
220
242
  };
package/dist/esm/popup.js CHANGED
@@ -131,5 +131,4 @@ export var Popup = /*#__PURE__*/memo(function (_ref) {
131
131
  }, popupContent);
132
132
  }
133
133
  return popupContent;
134
- });
135
- export default Popup;
134
+ });
@@ -180,16 +180,32 @@ export var useCloseManager = function useCloseManager(_ref) {
180
180
  }
181
181
  });
182
182
  }
183
- var unbind = bindAll(window, [{
184
- type: 'click',
185
- listener: onClick,
186
- options: {
187
- capture: capture
188
- }
189
- }, {
190
- type: 'keydown',
191
- listener: onKeyDown
192
- }]);
183
+ var unbind = noop;
184
+ if (fg('popup-onclose-fix')) {
185
+ setTimeout(function () {
186
+ unbind = bindAll(window, [{
187
+ type: 'click',
188
+ listener: onClick,
189
+ options: {
190
+ capture: capture
191
+ }
192
+ }, {
193
+ type: 'keydown',
194
+ listener: onKeyDown
195
+ }]);
196
+ }, 0);
197
+ } else {
198
+ unbind = bindAll(window, [{
199
+ type: 'click',
200
+ listener: onClick,
201
+ options: {
202
+ capture: capture
203
+ }
204
+ }, {
205
+ type: 'keydown',
206
+ listener: onKeyDown
207
+ }]);
208
+ }
193
209
 
194
210
  // bind onBlur event listener to fix popup not close when clicking on iframe outside
195
211
  var unbindBlur = noop;
@@ -204,8 +220,14 @@ export var useCloseManager = function useCloseManager(_ref) {
204
220
  });
205
221
  return function () {
206
222
  var _parentUnbind;
223
+ if (fg('popup-onclose-fix')) {
224
+ setTimeout(function () {
225
+ unbind();
226
+ }, 0);
227
+ } else {
228
+ unbind();
229
+ }
207
230
  cancelAllFrames();
208
- unbind();
209
231
  (_parentUnbind = parentUnbind) === null || _parentUnbind === void 0 || _parentUnbind();
210
232
  unbindBlur();
211
233
  };
@@ -5,4 +5,3 @@
5
5
  import { type FC } from 'react';
6
6
  import { type PopupProps } from './types';
7
7
  export declare const Popup: FC<PopupProps>;
8
- export default Popup;
@@ -5,4 +5,3 @@
5
5
  import { type FC } from 'react';
6
6
  import { type PopupProps } from './types';
7
7
  export declare const Popup: FC<PopupProps>;
8
- export default Popup;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/popup",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "A popup displays brief content in an overlay.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -45,9 +45,9 @@
45
45
  "@atlaskit/platform-feature-flags": "^1.1.0",
46
46
  "@atlaskit/popper": "^7.0.0",
47
47
  "@atlaskit/portal": "^5.0.0",
48
- "@atlaskit/primitives": "^14.0.0",
48
+ "@atlaskit/primitives": "^14.1.0",
49
49
  "@atlaskit/theme": "^17.0.0",
50
- "@atlaskit/tokens": "^4.0.0",
50
+ "@atlaskit/tokens": "^4.3.0",
51
51
  "@babel/runtime": "^7.0.0",
52
52
  "@emotion/react": "^11.7.1",
53
53
  "bind-event-listener": "^3.0.0",
@@ -63,15 +63,21 @@
63
63
  "@af/accessibility-testing": "*",
64
64
  "@af/integration-testing": "*",
65
65
  "@af/visual-regression": "*",
66
- "@atlaskit/button": "^21.0.0",
67
- "@atlaskit/icon": "^24.0.0",
66
+ "@atlaskit/button": "^21.1.0",
67
+ "@atlaskit/code": "^16.0.0",
68
+ "@atlaskit/docs": "*",
69
+ "@atlaskit/form": "^12.0.0",
70
+ "@atlaskit/heading": "^5.0.0",
71
+ "@atlaskit/icon": "^24.1.0",
72
+ "@atlaskit/link": "^3.0.0",
73
+ "@atlaskit/modal-dialog": "^13.0.0",
74
+ "@atlaskit/section-message": "*",
68
75
  "@atlaskit/ssr": "*",
69
76
  "@atlaskit/textfield": "^8.0.0",
70
77
  "@atlaskit/toggle": "^15.0.0",
71
78
  "@atlaskit/visual-regression": "*",
72
79
  "@atlassian/feature-flags-test-utils": "*",
73
80
  "@compiled/react": "^0.18.2",
74
- "@testing-library/dom": "^10.1.0",
75
81
  "@testing-library/react": "^13.4.0",
76
82
  "@testing-library/react-hooks": "^8.0.1",
77
83
  "@testing-library/user-event": "^14.4.3",
@@ -79,7 +85,6 @@
79
85
  "jscodeshift": "^0.13.0",
80
86
  "raf-stub": "^2.0.1",
81
87
  "react-dom": "^18.2.0",
82
- "storybook-addon-performance": "^0.17.3",
83
88
  "typescript": "~5.4.2"
84
89
  },
85
90
  "keywords": [
@@ -125,6 +130,9 @@
125
130
  },
126
131
  "fix-dropdown-close-outside-iframe": {
127
132
  "type": "boolean"
133
+ },
134
+ "popup-onclose-fix": {
135
+ "type": "boolean"
128
136
  }
129
137
  },
130
138
  "homepage": "https://atlassian.design/components/popup/"
@@ -1,178 +0,0 @@
1
- import {
2
- type API,
3
- type ASTPath,
4
- type default as core,
5
- type FileInfo,
6
- type JSXElement,
7
- JSXExpressionContainer,
8
- type Literal,
9
- type Options,
10
- } from 'jscodeshift';
11
- import { type Collection } from 'jscodeshift/src/Collection';
12
-
13
- import {
14
- addCommentToStartOfFile,
15
- getDefaultSpecifierName,
16
- getJSXAttributesByName,
17
- getSpecifierName,
18
- hasImportDeclaration,
19
- isUsingProp,
20
- updateRenderProps,
21
- } from './utils/helpers';
22
-
23
- function updateBoundariesProps(j: core.JSCodeshift, source: Collection<any>, specifier: string) {
24
- source.findJSXElements(specifier).forEach((path: ASTPath<JSXElement>) => {
25
- if (
26
- isUsingProp({
27
- j,
28
- base: source,
29
- element: path,
30
- propName: 'boundariesElement',
31
- })
32
- ) {
33
- // Get value from prop
34
- getJSXAttributesByName({
35
- j,
36
- element: path,
37
- attributeName: 'boundariesElement',
38
- }).forEach((attribute) => {
39
- const expression = attribute.node.value;
40
- if (expression && expression.type === 'StringLiteral') {
41
- const value = expression && expression.value;
42
- if (value === 'window') {
43
- j(attribute).replaceWith(
44
- j.jsxAttribute(j.jsxIdentifier('rootBoundary'), j.stringLiteral('document')),
45
- );
46
- } else if (value === 'viewport') {
47
- j(attribute).replaceWith(
48
- j.jsxAttribute(j.jsxIdentifier('rootBoundary'), j.stringLiteral('viewport')),
49
- );
50
- } else if (value === 'scrollParents') {
51
- j(attribute).replaceWith(
52
- j.jsxAttribute(j.jsxIdentifier('boundary'), j.stringLiteral('clippingParents')),
53
- );
54
- }
55
- }
56
- });
57
- // Add relevant replacement props
58
-
59
- // Remove old prop
60
- getJSXAttributesByName({
61
- j,
62
- element: path,
63
- attributeName: 'boundariesElement',
64
- }).remove();
65
- }
66
- });
67
- }
68
-
69
- function updateOffset(j: core.JSCodeshift, source: Collection<any>, specifier: string) {
70
- source.findJSXElements(specifier).forEach((path: ASTPath<JSXElement>) => {
71
- getJSXAttributesByName({
72
- j,
73
- element: path,
74
- attributeName: 'offset',
75
- })
76
- .find(JSXExpressionContainer)
77
- .forEach((attribute) => {
78
- const expression = attribute.value.expression;
79
- if (expression.type === 'StringLiteral') {
80
- const value = expression.value;
81
- // Not testing for cases like '10 + 10%' because I assume if you're
82
- // adding or taking numbers it's with units that are not supported
83
- // and will be picked up by the first case
84
- if (value.includes('%') || value.includes('vw') || value.includes('vh')) {
85
- addCommentToStartOfFile({
86
- j,
87
- base: source,
88
- message: `
89
- Popper.js has been upgraded from 1.14.1 to 2.4.2,
90
- and as a result the offset prop has changed to be an array. e.g '0px 8px' -> [0, 8]
91
- Along with this change you cannot use vw, vh or % units or addition or multiplication
92
- Change the offset value to use pixel values
93
- Further details can be found in the popper docs https://popper.js.org/docs/v2/modifiers/offset/
94
- `,
95
- });
96
- } else if (value.includes(',')) {
97
- // Split by comma
98
- const offsetArray: Literal[] = expression.value
99
- .split(',')
100
- //@ts-ignore
101
- .map((elem) => j.literal(parseInt(elem.replace(/\D/g, ''))));
102
- if (offsetArray.length === 2) {
103
- j(attribute).replaceWith(j.jsxExpressionContainer(j.arrayExpression(offsetArray)));
104
- }
105
- } else {
106
- // Split by space but check if it is a single number
107
- const offsetArray: Literal[] = expression.value
108
- .split(' ')
109
- .filter((elem) => elem.length)
110
- .map((elem) => j.literal(parseInt(elem.replace(/\D/g, ''))));
111
- if (offsetArray.length === 2) {
112
- j(attribute).replaceWith(j.jsxExpressionContainer(j.arrayExpression(offsetArray)));
113
- } else if (offsetArray.length === 1) {
114
- j(attribute).replaceWith(
115
- j.jsxExpressionContainer(j.arrayExpression([offsetArray[0], j.literal(0)])),
116
- );
117
- }
118
- }
119
- } else if (expression.type === 'NumericLiteral') {
120
- // If it is a single number convert to [number, 0]
121
- j(attribute).replaceWith(
122
- j.jsxExpressionContainer(j.arrayExpression([expression, j.literal(0)])),
123
- );
124
- } else if (expression.type === 'Identifier') {
125
- // If there is a variable add this comment
126
- addCommentToStartOfFile({
127
- j,
128
- base: source,
129
- message: `
130
- Popper.js has been upgraded from 1.14.1 to 2.4.2, and as a result the offset
131
- prop has changed to be an array. e.g '0px 8px' -> [0, 8]
132
- As you are using a variable, you will have change the offset prop manually
133
- Further details can be found in the popper docs https://popper.js.org/docs/v2/modifiers/offset/
134
- `,
135
- });
136
- }
137
- });
138
- });
139
- }
140
-
141
- export default function transformer(file: FileInfo, { jscodeshift: j }: API, options: Options) {
142
- const source = j(file.source);
143
-
144
- // Exit early if not relevant
145
- // We are doing this so we don't touch the formatting of unrelated files
146
- if (!hasImportDeclaration(j, file.source, '@atlaskit/popup')) {
147
- return file.source;
148
- }
149
-
150
- // Get imported name for the component
151
- var specifier = getDefaultSpecifierName({
152
- j,
153
- base: source,
154
- packageName: '@atlaskit/popup',
155
- });
156
- if (!specifier) {
157
- specifier = getSpecifierName({
158
- j,
159
- base: source,
160
- packageName: '@atlaskit/popup',
161
- component: 'Popup',
162
- });
163
- }
164
- if (!specifier) {
165
- return file.source;
166
- }
167
-
168
- // Convert boundaries prop
169
- updateBoundariesProps(j, source, specifier);
170
-
171
- // Convert offset prop
172
- updateOffset(j, source, specifier);
173
-
174
- // Rename render props
175
- updateRenderProps(j, source, specifier, 'scheduleUpdate', 'update');
176
-
177
- return source.toSource(options.printOptions || { quote: 'single' });
178
- }
@@ -1,532 +0,0 @@
1
- jest.autoMockOff();
2
-
3
- import noop from '@atlaskit/ds-lib/noop';
4
-
5
- import transformer from '../1.0.0-lite-mode';
6
-
7
- const applyTransform = require('jscodeshift/dist/testUtils').applyTransform;
8
-
9
- type TestArgs = {
10
- it: string;
11
- original: string;
12
- expected: string;
13
- mode?: 'only' | 'skip';
14
- before?: () => void;
15
- after?: () => void;
16
- };
17
-
18
- function check({
19
- it: name,
20
- original,
21
- expected,
22
- before = noop,
23
- after = noop,
24
- mode = undefined,
25
- }: TestArgs) {
26
- const run = mode === 'only' ? it.only : mode === 'skip' ? it.skip : it;
27
-
28
- run(name, () => {
29
- before();
30
- try {
31
- const output: string = applyTransform(
32
- { default: transformer, parser: 'tsx' },
33
- {},
34
- { source: original },
35
- );
36
- expect(output).toBe(expected.trim());
37
- } catch (e) {
38
- // a failed assertion will throw
39
- after();
40
- throw e;
41
- }
42
- // will only be hit if we don't throw
43
- after();
44
- });
45
- }
46
-
47
- /**
48
- * - `boundariesElement` has been replaced with two props: `boundary` and `rootBoundary`. The three supported values
49
- * from the boundariesElement prop have been split between the two as follows:
50
- * - `boundariesElement="scrollParents"` has been renamed: use `boundary="clippingParents"`.
51
- * - `boundariesElement="window"` has been renamed: use `rootBoundary="document"`, and acts in a similar fashion.
52
- * - `boundariesElement="viewport"` has been moved: use `rootBoundary="viewport"`.
53
- */
54
-
55
- describe('Convert boundaries props', () => {
56
- check({
57
- it: 'should turn `boundariesElement="scrollParents"` to `boundary="clippingParents"`',
58
- original: `
59
- import Popup from '@atlaskit/popup';
60
-
61
- export default () => (
62
- <Popup
63
- isOpen={isOpen}
64
- onClose={() => {}}
65
- boundariesElement='scrollParents'
66
- placement="bottom-start"
67
- content={() => (
68
- <div />
69
- )}
70
- trigger={triggerProps => (
71
- <div />
72
- )}
73
- />
74
- );
75
- `,
76
- expected: `
77
- import Popup from '@atlaskit/popup';
78
-
79
- export default () => (
80
- <Popup
81
- isOpen={isOpen}
82
- onClose={() => {}}
83
- boundary='clippingParents'
84
- placement="bottom-start"
85
- content={() => (
86
- <div />
87
- )}
88
- trigger={triggerProps => (
89
- <div />
90
- )}
91
- />
92
- );
93
- `,
94
- });
95
-
96
- check({
97
- it: 'should turn `boundariesElement="window"` into `rootBoundary="document"`',
98
- original: `
99
- import Popup from '@atlaskit/popup';
100
-
101
- export default () => (
102
- <Popup
103
- isOpen={isOpen}
104
- onClose={() => {}}
105
- boundariesElement='window'
106
- placement="bottom-start"
107
- content={() => (
108
- <div />
109
- )}
110
- trigger={triggerProps => (
111
- <div />
112
- )}
113
- />
114
- );
115
- `,
116
- expected: `
117
- import Popup from '@atlaskit/popup';
118
-
119
- export default () => (
120
- <Popup
121
- isOpen={isOpen}
122
- onClose={() => {}}
123
- rootBoundary='document'
124
- placement="bottom-start"
125
- content={() => (
126
- <div />
127
- )}
128
- trigger={triggerProps => (
129
- <div />
130
- )}
131
- />
132
- );
133
- `,
134
- });
135
-
136
- check({
137
- it: 'should turn `boundariesElement="viewport"` into `rootBoundary="viewport"`',
138
- original: `
139
- import Popup from '@atlaskit/popup';
140
-
141
- export default () => (
142
- <Popup
143
- isOpen={isOpen}
144
- onClose={() => {}}
145
- boundariesElement='viewport'
146
- placement="bottom-start"
147
- content={() => (
148
- <div />
149
- )}
150
- trigger={triggerProps => (
151
- <div />
152
- )}
153
- />
154
- );
155
- `,
156
- expected: `
157
- import Popup from '@atlaskit/popup';
158
-
159
- export default () => (
160
- <Popup
161
- isOpen={isOpen}
162
- onClose={() => {}}
163
- rootBoundary='viewport'
164
- placement="bottom-start"
165
- content={() => (
166
- <div />
167
- )}
168
- trigger={triggerProps => (
169
- <div />
170
- )}
171
- />
172
- );
173
- `,
174
- });
175
- });
176
-
177
- describe('Convert offset props', () => {
178
- /**
179
- * `offset` prop is no longer a string, but an array of two integers (i.e. '0px 8px' is now [0, 8])
180
- */
181
- check({
182
- it: 'should convert offset from a string to an array of two integers',
183
- original: `
184
- import Popup from '@atlaskit/popup';
185
-
186
- export default () => (
187
- <Popup
188
- isOpen={isOpen}
189
- onClose={() => {}}
190
- offset={'5px 8px'}
191
- content={() => (
192
- <div />
193
- )}
194
- trigger={triggerProps => (
195
- <div />
196
- )}
197
- />
198
- );
199
-
200
- function numCommaOffset() {
201
- return (
202
- <Popup
203
- isOpen={isOpen}
204
- onClose={() => {}}
205
- offset={'5px, 8px'}
206
- content={() => (
207
- <div />
208
- )}
209
- trigger={triggerProps => (
210
- <div />
211
- )}
212
- />
213
- );
214
- }
215
-
216
- function numStringOffset() {
217
- return (
218
- <Popup
219
- isOpen={isOpen}
220
- onClose={() => {}}
221
- offset={'10'}
222
- content={() => (
223
- <div />
224
- )}
225
- trigger={triggerProps => (
226
- <div />
227
- )}
228
- />
229
- );
230
- }
231
-
232
- function numOffset() {
233
- return (
234
- <Popup
235
- isOpen={isOpen}
236
- onClose={() => {}}
237
- offset={10}
238
- content={() => (
239
- <div />
240
- )}
241
- trigger={triggerProps => (
242
- <div />
243
- )}
244
- />
245
- );
246
- }
247
- `,
248
- expected: `
249
- import Popup from '@atlaskit/popup';
250
-
251
- export default () => (
252
- <Popup
253
- isOpen={isOpen}
254
- onClose={() => {}}
255
- offset={[5, 8]}
256
- content={() => (
257
- <div />
258
- )}
259
- trigger={triggerProps => (
260
- <div />
261
- )}
262
- />
263
- );
264
-
265
- function numCommaOffset() {
266
- return (
267
- <Popup
268
- isOpen={isOpen}
269
- onClose={() => {}}
270
- offset={[5, 8]}
271
- content={() => (
272
- <div />
273
- )}
274
- trigger={triggerProps => (
275
- <div />
276
- )}
277
- />
278
- );
279
- }
280
-
281
- function numStringOffset() {
282
- return (
283
- <Popup
284
- isOpen={isOpen}
285
- onClose={() => {}}
286
- offset={[10, 0]}
287
- content={() => (
288
- <div />
289
- )}
290
- trigger={triggerProps => (
291
- <div />
292
- )}
293
- />
294
- );
295
- }
296
-
297
- function numOffset() {
298
- return (
299
- <Popup
300
- isOpen={isOpen}
301
- onClose={() => {}}
302
- offset={[10, 0]}
303
- content={() => (
304
- <div />
305
- )}
306
- trigger={triggerProps => (
307
- <div />
308
- )}
309
- />
310
- );
311
- }
312
- `,
313
- });
314
- /**
315
- * If a user is passing in an offset with vh, vw or % in the offset, let them know that's no longer supported
316
- */
317
- check({
318
- it: 'should warn users using vh, vw or % in the offset',
319
- original: `
320
- import Popup from '@atlaskit/popup';
321
-
322
- export default () => (
323
- <Popup
324
- isOpen={isOpen}
325
- onClose={() => {}}
326
- offset={'5px + 7vh, 8px'}
327
- content={() => (
328
- <div />
329
- )}
330
- trigger={triggerProps => (
331
- <div />
332
- )}
333
- />
334
- );
335
- `,
336
- expected: `
337
- /* TODO: (from codemod) Popper.js has been upgraded from 1.14.1 to 2.4.2,
338
- and as a result the offset prop has changed to be an array. e.g '0px 8px' -> [0, 8]
339
- Along with this change you cannot use vw, vh or % units or addition or multiplication
340
- Change the offset value to use pixel values
341
- Further details can be found in the popper docs https://popper.js.org/docs/v2/modifiers/offset/ */
342
- import Popup from '@atlaskit/popup';
343
-
344
- export default () => (
345
- <Popup
346
- isOpen={isOpen}
347
- onClose={() => {}}
348
- offset={'5px + 7vh, 8px'}
349
- content={() => (
350
- <div />
351
- )}
352
- trigger={triggerProps => (
353
- <div />
354
- )}
355
- />
356
- );
357
- `,
358
- });
359
-
360
- /**
361
- * If a user is passing in a variable for offset then we should leave a comment to update it themselves
362
- */
363
- check({
364
- it: 'warn users passing in a variable for an offset',
365
- original: `
366
- import Popup from '@atlaskit/popup';
367
-
368
- function directOffset({offset}) {
369
- return (
370
- <Popup
371
- isOpen={isOpen}
372
- onClose={() => {}}
373
- offset={offset}
374
- content={() => (
375
- <div />
376
- )}
377
- trigger={triggerProps => (
378
- <div />
379
- )}
380
- />
381
- );
382
- }
383
- `,
384
- expected: `
385
- /* TODO: (from codemod) Popper.js has been upgraded from 1.14.1 to 2.4.2, and as a result the offset
386
- prop has changed to be an array. e.g '0px 8px' -> [0, 8]
387
- As you are using a variable, you will have change the offset prop manually
388
- Further details can be found in the popper docs https://popper.js.org/docs/v2/modifiers/offset/ */
389
- import Popup from '@atlaskit/popup';
390
-
391
- function directOffset({offset}) {
392
- return (
393
- <Popup
394
- isOpen={isOpen}
395
- onClose={() => {}}
396
- offset={offset}
397
- content={() => (
398
- <div />
399
- )}
400
- trigger={triggerProps => (
401
- <div />
402
- )}
403
- />
404
- );
405
- }
406
- `,
407
- });
408
- // Works with an aliased import and other imports
409
- check({
410
- it: 'should work with aliased import and other imports',
411
- original: `
412
-
413
- import AkPopup, { PopupProps as AkPopupProps, TriggerProps as AkTriggerProps } from '@atlaskit/popup';
414
-
415
- export default () => (
416
- <AkPopup
417
- isOpen={isOpen}
418
- onClose={() => {}}
419
- offset={'5px, 8px'}
420
- content={() => (
421
- <div />
422
- )}
423
- trigger={triggerProps => (
424
- <div />
425
- )}
426
- />
427
- );
428
- `,
429
- expected: `
430
- import AkPopup, { PopupProps as AkPopupProps, TriggerProps as AkTriggerProps } from '@atlaskit/popup';
431
-
432
- export default () => (
433
- <AkPopup
434
- isOpen={isOpen}
435
- onClose={() => {}}
436
- offset={[5, 8]}
437
- content={() => (
438
- <div />
439
- )}
440
- trigger={triggerProps => (
441
- <div />
442
- )}
443
- />
444
- );
445
- `,
446
- });
447
-
448
- // Works when not a default import
449
- check({
450
- it: 'should work when not accessed using a default import',
451
- original: `
452
- import { Popup } from '@atlaskit/popup';
453
-
454
- export default () => (
455
- <Popup
456
- isOpen={isOpen}
457
- onClose={() => {}}
458
- offset={'5px, 8px'}
459
- content={() => (
460
- <div />
461
- )}
462
- trigger={triggerProps => (
463
- <div />
464
- )}
465
- />
466
- );
467
- `,
468
- expected: `
469
- import { Popup } from '@atlaskit/popup';
470
-
471
- export default () => (
472
- <Popup
473
- isOpen={isOpen}
474
- onClose={() => {}}
475
- offset={[5, 8]}
476
- content={() => (
477
- <div />
478
- )}
479
- trigger={triggerProps => (
480
- <div />
481
- )}
482
- />
483
- );
484
- `,
485
- });
486
- });
487
-
488
- /**
489
- * Render Props:
490
- * - `scheduleUpdate`, for async updates, has been renamed to `update`, and now returns a Promise.
491
- */
492
- describe('Convert render props', () => {
493
- check({
494
- it: 'should rename schedulUpdate to `update`',
495
- original: `
496
- import Popup from '@atlaskit/popup';
497
-
498
- export default () => (
499
- <Popup
500
- isOpen={isOpen}
501
- onClose={() => {}}
502
- placement="bottom-start"
503
- content={({ scheduleUpdate }) => (
504
- <div />
505
- )}
506
- trigger={triggerProps => (
507
- <div />
508
- )}
509
- />
510
- );
511
- `,
512
- expected: `
513
- import Popup from '@atlaskit/popup';
514
-
515
- export default () => (
516
- <Popup
517
- isOpen={isOpen}
518
- onClose={() => {}}
519
- placement="bottom-start"
520
- content={({
521
- update: scheduleUpdate
522
- }) => (
523
- <div />
524
- )}
525
- trigger={triggerProps => (
526
- <div />
527
- )}
528
- />
529
- );
530
- `,
531
- });
532
- });
@@ -1,333 +0,0 @@
1
- import { type NodePath } from 'ast-types/lib/node-path';
2
- import {
3
- type ASTPath,
4
- type default as core,
5
- type ImportDeclaration,
6
- type JSXAttribute,
7
- type JSXElement,
8
- type Node,
9
- } from 'jscodeshift';
10
- import { type Collection } from 'jscodeshift/src/Collection';
11
-
12
- export type Nullable<T> = T | null;
13
-
14
- export function hasImportDeclaration(
15
- j: core.JSCodeshift,
16
- source: string,
17
- importPath: string,
18
- ): boolean {
19
- return (
20
- j(source)
21
- .find(j.ImportDeclaration)
22
- .filter((path: ASTPath<ImportDeclaration>) => path.node.source.value === importPath).length >
23
- 0
24
- );
25
- }
26
-
27
- export function getDefaultSpecifierName({
28
- j,
29
- base,
30
- packageName,
31
- }: {
32
- j: core.JSCodeshift;
33
- base: Collection<any>;
34
- packageName: string;
35
- }): Nullable<string> {
36
- const specifiers = base
37
- .find(j.ImportDeclaration)
38
- .filter((path) => path.node.source.value === packageName)
39
- .find(j.ImportDefaultSpecifier);
40
-
41
- if (!specifiers.length) {
42
- return null;
43
- }
44
- return specifiers.nodes()[0]!.local!.name;
45
- }
46
-
47
- export function getSpecifierName({
48
- j,
49
- base,
50
- packageName,
51
- component,
52
- }: {
53
- j: core.JSCodeshift;
54
- base: Collection<any>;
55
- packageName: string;
56
- component: string;
57
- }): Nullable<string> {
58
- const specifiers = base
59
- .find(j.ImportDeclaration)
60
- .filter((path) => path.node.source.value === packageName)
61
- .find(j.ImportSpecifier);
62
-
63
- if (!specifiers.length) {
64
- return null;
65
- }
66
- const specifierNode = specifiers.nodes().find((node) => node.imported.name === component);
67
- if (!specifierNode) {
68
- return null;
69
- }
70
- // @ts-ignore
71
- return specifierNode.local.name;
72
- }
73
-
74
- export function getJSXAttributesByName({
75
- j,
76
- element,
77
- attributeName,
78
- }: {
79
- j: core.JSCodeshift;
80
- element: JSXElement | ASTPath<JSXElement>;
81
- attributeName: string;
82
- }): Collection<JSXAttribute> {
83
- return j(element)
84
- .find(j.JSXOpeningElement)
85
- .find(j.JSXAttribute)
86
- .filter((attribute) => {
87
- const matches = j(attribute)
88
- .find(j.JSXIdentifier)
89
- .filter((identifier) => identifier.value.name === attributeName);
90
- return Boolean(matches.length);
91
- });
92
- }
93
-
94
- export function hasJSXAttributesByName({
95
- j,
96
- element,
97
- attributeName,
98
- }: {
99
- j: core.JSCodeshift;
100
- element: JSXElement;
101
- attributeName: string;
102
- }): boolean {
103
- return getJSXAttributesByName({ j, element, attributeName }).length > 0;
104
- }
105
-
106
- export function isUsingSupportedSpread({
107
- j,
108
- base,
109
- element,
110
- }: {
111
- j: core.JSCodeshift;
112
- base: Collection<any>;
113
- element: NodePath<JSXElement, JSXElement>;
114
- }): boolean {
115
- const isUsingSpread: boolean = j(element).find(j.JSXSpreadAttribute).length > 0;
116
-
117
- if (!isUsingSpread) {
118
- return true;
119
- }
120
-
121
- return (
122
- j(element)
123
- .find(j.JSXSpreadAttribute)
124
- .filter((spread) => {
125
- const argument = spread.value.argument;
126
- // in place expression is supported
127
- if (argument.type === 'ObjectExpression') {
128
- return true;
129
- }
130
-
131
- // Supporting identifiers that point to an a local object expression
132
- if (argument.type === 'Identifier') {
133
- return (
134
- base.find(j.VariableDeclarator).filter((declarator): boolean => {
135
- return (
136
- declarator.value.id.type === 'Identifier' &&
137
- // @ts-ignore
138
- declarator.value.init.type === 'ObjectExpression'
139
- );
140
- }).length > 0
141
- );
142
- }
143
-
144
- // We don't support anything else
145
- return false;
146
- }).length > 0
147
- );
148
- }
149
-
150
- export function isUsingThroughSpread({
151
- j,
152
- base,
153
- element,
154
- propName,
155
- }: {
156
- j: core.JSCodeshift;
157
- base: Collection<any>;
158
- element: NodePath<JSXElement, JSXElement>;
159
- propName: string;
160
- }): boolean {
161
- if (!isUsingSupportedSpread({ j, base, element })) {
162
- return false;
163
- }
164
-
165
- const isUsedThroughExpression: boolean =
166
- j(element)
167
- .find(j.JSXSpreadAttribute)
168
- .find(j.ObjectExpression)
169
- .filter((item) => {
170
- const match: boolean =
171
- item.value.properties.filter(
172
- (property) =>
173
- property.type === 'ObjectProperty' &&
174
- property.key.type === 'Identifier' &&
175
- property.key.name === propName,
176
- ).length > 0;
177
-
178
- return match;
179
- }).length > 0;
180
-
181
- if (isUsedThroughExpression) {
182
- return true;
183
- }
184
-
185
- const isUsedThroughIdentifier: boolean =
186
- j(element)
187
- .find(j.JSXSpreadAttribute)
188
- .find(j.Identifier)
189
- .filter((identifier): boolean => {
190
- return (
191
- base
192
- .find(j.VariableDeclarator)
193
- .filter(
194
- (declarator) =>
195
- declarator.value.id.type === 'Identifier' &&
196
- declarator.value.id.name === identifier.value.name,
197
- )
198
- .filter((declarator) => {
199
- const value = declarator.value;
200
- if (value.id.type !== 'Identifier') {
201
- return false;
202
- }
203
-
204
- if (value.id.name !== identifier.value.name) {
205
- return false;
206
- }
207
- // @ts-ignore
208
- if (value.init.type !== 'ObjectExpression') {
209
- return false;
210
- }
211
-
212
- const match: boolean =
213
- // @ts-ignore
214
- value.init.properties.filter(
215
- // @ts-ignore
216
- (property) =>
217
- property.type === 'ObjectProperty' &&
218
- property.key.type === 'Identifier' &&
219
- property.key.name === propName,
220
- ).length > 0;
221
-
222
- return match;
223
- }).length > 0
224
- );
225
- }).length > 0;
226
-
227
- return isUsedThroughIdentifier;
228
- }
229
-
230
- export function isUsingProp({
231
- j,
232
- base,
233
- element,
234
- propName,
235
- }: {
236
- j: core.JSCodeshift;
237
- base: Collection<any>;
238
- element: NodePath<JSXElement, JSXElement>;
239
- propName: string;
240
- }): boolean {
241
- return (
242
- hasJSXAttributesByName({
243
- j,
244
- element: element.value,
245
- attributeName: propName,
246
- }) ||
247
- isUsingThroughSpread({
248
- j,
249
- base,
250
- element,
251
- propName,
252
- })
253
- );
254
- }
255
-
256
- // not replacing newlines (which \s does)
257
- const spacesAndTabs: RegExp = /[ \t]{2,}/g;
258
- const lineStartWithSpaces: RegExp = /^[ \t]*/gm;
259
-
260
- function clean(value: string): string {
261
- return (
262
- value
263
- .replace(spacesAndTabs, ' ')
264
- .replace(lineStartWithSpaces, '')
265
- // using .trim() to clear the any newlines before the first text and after last text
266
- .trim()
267
- );
268
- }
269
-
270
- export function addCommentToStartOfFile({
271
- j,
272
- base,
273
- message,
274
- }: {
275
- j: core.JSCodeshift;
276
- base: Collection<Node>;
277
- message: string;
278
- }) {
279
- addCommentBefore({
280
- j,
281
- // @ts-ignore
282
- target: base.find(j.Program),
283
- message,
284
- });
285
- }
286
-
287
- export function addCommentBefore({
288
- j,
289
- target,
290
- message,
291
- }: {
292
- j: core.JSCodeshift;
293
- target: Collection<Node>;
294
- message: string;
295
- }) {
296
- const content: string = ` TODO: (from codemod) ${clean(message)} `;
297
- target.forEach((path) => {
298
- path.value.comments = path.value.comments || [];
299
-
300
- const exists = path.value.comments.find((comment) => comment.value === content);
301
-
302
- // avoiding duplicates of the same comment
303
- if (exists) {
304
- return;
305
- }
306
-
307
- path.value.comments.push(j.commentBlock(content));
308
- });
309
- }
310
-
311
- export function updateRenderProps(
312
- j: core.JSCodeshift,
313
- source: Collection<any>,
314
- specifier: string,
315
- oldProperty: string,
316
- newProperty: string,
317
- ) {
318
- source.findJSXElements(specifier).forEach((element: ASTPath<JSXElement>) => {
319
- j(element)
320
- .find(j.ArrowFunctionExpression)
321
- .find(j.ObjectPattern)
322
- .find(j.ObjectProperty)
323
- .filter(
324
- // @ts-ignore
325
- (path: ASTPath<ObjectProperty>) => path.value.key.name === oldProperty,
326
- )
327
- .forEach((path) => {
328
- j(path).replaceWith(
329
- j.property('init', j.identifier(newProperty), j.identifier(oldProperty)),
330
- );
331
- });
332
- });
333
- }