@atlaskit/modal-dialog 12.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 +2111 -0
- package/LICENSE +13 -0
- package/README.md +13 -0
- package/__perf__/default.tsx +42 -0
- package/__perf__/interactions.tsx +136 -0
- package/__perf__/scroll.tsx +98 -0
- package/codemods/12.0.0-lite-mode.ts +51 -0
- package/codemods/__tests__/12.0.0-lite-mode.test.ts +493 -0
- package/codemods/__tests__/handle-prop-spread.tsx +276 -0
- package/codemods/__tests__/inline-WidthNames-declaration.test.ts +260 -0
- package/codemods/__tests__/map-actions-prop.tsx +436 -0
- package/codemods/__tests__/map-body-from-props.test.ts +645 -0
- package/codemods/__tests__/map-container-from-props.test.ts +323 -0
- package/codemods/__tests__/map-footer-from-props.test.ts +544 -0
- package/codemods/__tests__/map-header-from-props.test.ts +559 -0
- package/codemods/__tests__/map-heading-prop.tsx +438 -0
- package/codemods/__tests__/remove-appearance-prop.test.ts +79 -0
- package/codemods/__tests__/remove-component-override-props.test.ts +153 -0
- package/codemods/__tests__/remove-is-chromeless.tsx +182 -0
- package/codemods/__tests__/rename-appearance-type.test.ts +52 -0
- package/codemods/__tests__/rename-inner-component-prop-types.test.ts +82 -0
- package/codemods/__tests__/rename-scrollBehavior-to-shouldScrollInViewport.test.ts +237 -0
- package/codemods/internal/constants.tsx +41 -0
- package/codemods/internal/utils.tsx +223 -0
- package/codemods/migrations/handle-prop-spread.tsx +51 -0
- package/codemods/migrations/inline-WidthNames-declaration.ts +92 -0
- package/codemods/migrations/map-actions-prop.tsx +430 -0
- package/codemods/migrations/map-body-from-props.ts +147 -0
- package/codemods/migrations/map-container-from-props.ts +72 -0
- package/codemods/migrations/map-footer-from-props.ts +107 -0
- package/codemods/migrations/map-header-from-props.ts +101 -0
- package/codemods/migrations/map-heading-prop.tsx +193 -0
- package/codemods/migrations/remove-appearance-prop.ts +27 -0
- package/codemods/migrations/remove-component-override-props.ts +84 -0
- package/codemods/migrations/remove-is-chromeless.tsx +42 -0
- package/codemods/migrations/rename-appearance-type.ts +9 -0
- package/codemods/migrations/rename-inner-component-prop-types.ts +28 -0
- package/codemods/migrations/rename-scrollBehavior-to-shouldScrollInViewport.ts +82 -0
- package/dist/cjs/hooks.js +22 -0
- package/dist/cjs/index.js +63 -0
- package/dist/cjs/internal/components/modal-dialog.js +155 -0
- package/dist/cjs/internal/components/positioner.js +89 -0
- package/dist/cjs/internal/components/scroll-container.js +138 -0
- package/dist/cjs/internal/constants.js +48 -0
- package/dist/cjs/internal/context.js +13 -0
- package/dist/cjs/internal/hooks/use-modal-stack.js +110 -0
- package/dist/cjs/internal/hooks/use-on-motion-finish.js +24 -0
- package/dist/cjs/internal/hooks/use-prevent-programmatic-scroll.js +55 -0
- package/dist/cjs/internal/hooks/use-scroll.js +20 -0
- package/dist/cjs/internal/utils.js +35 -0
- package/dist/cjs/modal-body.js +66 -0
- package/dist/cjs/modal-footer.js +40 -0
- package/dist/cjs/modal-header.js +43 -0
- package/dist/cjs/modal-title.js +108 -0
- package/dist/cjs/modal-transition.js +21 -0
- package/dist/cjs/modal-wrapper.js +126 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/version.json +5 -0
- package/dist/es2019/hooks.js +11 -0
- package/dist/es2019/index.js +7 -0
- package/dist/es2019/internal/components/modal-dialog.js +120 -0
- package/dist/es2019/internal/components/positioner.js +78 -0
- package/dist/es2019/internal/components/scroll-container.js +97 -0
- package/dist/es2019/internal/constants.js +27 -0
- package/dist/es2019/internal/context.js +3 -0
- package/dist/es2019/internal/hooks/use-modal-stack.js +85 -0
- package/dist/es2019/internal/hooks/use-on-motion-finish.js +17 -0
- package/dist/es2019/internal/hooks/use-prevent-programmatic-scroll.js +39 -0
- package/dist/es2019/internal/hooks/use-scroll.js +11 -0
- package/dist/es2019/internal/utils.js +22 -0
- package/dist/es2019/modal-body.js +50 -0
- package/dist/es2019/modal-footer.js +30 -0
- package/dist/es2019/modal-header.js +30 -0
- package/dist/es2019/modal-title.js +94 -0
- package/dist/es2019/modal-transition.js +10 -0
- package/dist/es2019/modal-wrapper.js +88 -0
- package/dist/es2019/types.js +1 -0
- package/dist/es2019/version.json +5 -0
- package/dist/esm/hooks.js +11 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/internal/components/modal-dialog.js +131 -0
- package/dist/esm/internal/components/positioner.js +76 -0
- package/dist/esm/internal/components/scroll-container.js +114 -0
- package/dist/esm/internal/constants.js +27 -0
- package/dist/esm/internal/context.js +3 -0
- package/dist/esm/internal/hooks/use-modal-stack.js +96 -0
- package/dist/esm/internal/hooks/use-on-motion-finish.js +16 -0
- package/dist/esm/internal/hooks/use-prevent-programmatic-scroll.js +44 -0
- package/dist/esm/internal/hooks/use-scroll.js +11 -0
- package/dist/esm/internal/utils.js +22 -0
- package/dist/esm/modal-body.js +49 -0
- package/dist/esm/modal-footer.js +29 -0
- package/dist/esm/modal-header.js +29 -0
- package/dist/esm/modal-title.js +93 -0
- package/dist/esm/modal-transition.js +10 -0
- package/dist/esm/modal-wrapper.js +96 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/version.json +5 -0
- package/dist/types/hooks.d.ts +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/internal/components/modal-dialog.d.ts +3 -0
- package/dist/types/internal/components/positioner.d.ts +10 -0
- package/dist/types/internal/components/scroll-container.d.ts +20 -0
- package/dist/types/internal/constants.d.ts +25 -0
- package/dist/types/internal/context.d.ts +20 -0
- package/dist/types/internal/hooks/use-modal-stack.d.ts +13 -0
- package/dist/types/internal/hooks/use-on-motion-finish.d.ts +4 -0
- package/dist/types/internal/hooks/use-prevent-programmatic-scroll.d.ts +7 -0
- package/dist/types/internal/hooks/use-scroll.d.ts +1 -0
- package/dist/types/internal/utils.d.ts +3 -0
- package/dist/types/modal-body.d.ts +16 -0
- package/dist/types/modal-footer.d.ts +16 -0
- package/dist/types/modal-header.d.ts +16 -0
- package/dist/types/modal-title.d.ts +26 -0
- package/dist/types/modal-transition.d.ts +3 -0
- package/dist/types/modal-wrapper.d.ts +5 -0
- package/dist/types/types.d.ts +90 -0
- package/extract-react-types/modal-attributes.tsx +5 -0
- package/hooks/package.json +7 -0
- package/modal-body/package.json +7 -0
- package/modal-dialog/package.json +7 -0
- package/modal-footer/package.json +7 -0
- package/modal-header/package.json +7 -0
- package/modal-title/package.json +7 -0
- package/modal-transition/package.json +7 -0
- package/package.json +113 -0
- package/types/package.json +7 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import core, { ASTPath, Collection, JSXElement } from 'jscodeshift/src/core';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
addCommentToStartOfFile,
|
|
5
|
+
getDefaultSpecifier,
|
|
6
|
+
getDynamicImportName,
|
|
7
|
+
} from '@atlaskit/codemod-utils';
|
|
8
|
+
|
|
9
|
+
import { PACKAGE_NAME } from '../internal/constants';
|
|
10
|
+
|
|
11
|
+
const comment = `
|
|
12
|
+
This file is spreading props on the ModalDialog component, so we could not
|
|
13
|
+
automatically convert this usage to the new API.
|
|
14
|
+
|
|
15
|
+
The following props have been deprecated as part of moving to a compositional API:
|
|
16
|
+
|
|
17
|
+
- 'heading' prop has been replaced by ModalHeader and ModalTitle components.
|
|
18
|
+
- 'actions' prop has been replaced by ModalFooter component, with Button components from @atlaskit/button.
|
|
19
|
+
- 'scrollBehavior' prop has been replaced by 'shouldScrollInViewport', where "outside" from the previous prop maps to true in the new prop.
|
|
20
|
+
- 'isHeadingMultiline' prop has been replaced by 'isMultiline' prop on the ModalTitle component.
|
|
21
|
+
- 'appearance' prop has been moved to the ModalTitle component. To achieve the feature parity, pass the 'appearance' prop directly to ModalTitle and Button components inside ModalFooter.
|
|
22
|
+
|
|
23
|
+
Refer to the docs for the new API at https://atlassian.design/components/modal-dialog/examples
|
|
24
|
+
to complete the migration and use the new composable components.
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const handlePropSpread = (
|
|
28
|
+
j: core.JSCodeshift,
|
|
29
|
+
source: Collection<Node>,
|
|
30
|
+
) => {
|
|
31
|
+
const defaultSpecifierName = getDefaultSpecifier(j, source, PACKAGE_NAME);
|
|
32
|
+
const dynamicImportName = getDynamicImportName(j, source, PACKAGE_NAME);
|
|
33
|
+
const modalDialogComponentName = defaultSpecifierName || dynamicImportName;
|
|
34
|
+
|
|
35
|
+
if (!modalDialogComponentName) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
source
|
|
41
|
+
.findJSXElements(modalDialogComponentName)
|
|
42
|
+
.filter((element: ASTPath<JSXElement>) => {
|
|
43
|
+
return (
|
|
44
|
+
j(element).find(j.JSXOpeningElement).at(0).find(j.JSXSpreadAttribute)
|
|
45
|
+
.length > 0
|
|
46
|
+
);
|
|
47
|
+
}).length
|
|
48
|
+
) {
|
|
49
|
+
addCommentToStartOfFile({ j, base: source, message: comment });
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import core, {
|
|
2
|
+
Identifier,
|
|
3
|
+
TSCallSignatureDeclaration,
|
|
4
|
+
TSConstructSignatureDeclaration,
|
|
5
|
+
TSIndexSignature,
|
|
6
|
+
TSMethodSignature,
|
|
7
|
+
TSPropertySignature,
|
|
8
|
+
} from 'jscodeshift';
|
|
9
|
+
import { Collection } from 'jscodeshift/src/Collection';
|
|
10
|
+
|
|
11
|
+
import { getNamedSpecifier, removeImport } from '@atlaskit/codemod-utils';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
SHARED_VARIABLES_ENDPOINT,
|
|
15
|
+
WIDTH_NAMES_TYPE_NAME,
|
|
16
|
+
} from '../internal/constants';
|
|
17
|
+
|
|
18
|
+
export const inlineWidthNamesDeclaration = (
|
|
19
|
+
j: core.JSCodeshift,
|
|
20
|
+
source: Collection<Node>,
|
|
21
|
+
) => {
|
|
22
|
+
const namedSpecifier = getNamedSpecifier(
|
|
23
|
+
j,
|
|
24
|
+
source,
|
|
25
|
+
SHARED_VARIABLES_ENDPOINT,
|
|
26
|
+
WIDTH_NAMES_TYPE_NAME,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (!namedSpecifier) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
source.find(j.TSTypeAliasDeclaration).forEach((declaration) => {
|
|
34
|
+
const annotation = declaration.value.typeAnnotation;
|
|
35
|
+
|
|
36
|
+
if (annotation.type === 'TSTypeLiteral') {
|
|
37
|
+
replaceTypeAnnotationForWidthNames(j, namedSpecifier, annotation.members);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
source.find(j.TSInterfaceDeclaration).forEach((declaration) => {
|
|
42
|
+
replaceTypeAnnotationForWidthNames(
|
|
43
|
+
j,
|
|
44
|
+
namedSpecifier,
|
|
45
|
+
declaration.value.body.body,
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Remove import from /shared-variables as it's no longer supported
|
|
51
|
+
* and this is the only use case of that entry point.
|
|
52
|
+
*/
|
|
53
|
+
removeImport(j, source, SHARED_VARIABLES_ENDPOINT);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const replaceTypeAnnotationForWidthNames = (
|
|
57
|
+
j: core.JSCodeshift,
|
|
58
|
+
specifier: string,
|
|
59
|
+
typeAnnotations: (
|
|
60
|
+
| TSPropertySignature
|
|
61
|
+
| TSCallSignatureDeclaration
|
|
62
|
+
| TSConstructSignatureDeclaration
|
|
63
|
+
| TSIndexSignature
|
|
64
|
+
| TSMethodSignature
|
|
65
|
+
)[],
|
|
66
|
+
) => {
|
|
67
|
+
const widthNames = ['small', 'medium', 'large', 'x-large'];
|
|
68
|
+
|
|
69
|
+
typeAnnotations
|
|
70
|
+
.filter((property) => property.type === 'TSPropertySignature')
|
|
71
|
+
.map((property) => property as TSPropertySignature)
|
|
72
|
+
.filter((property: TSPropertySignature) => {
|
|
73
|
+
const typeAnnotation = property.typeAnnotation?.typeAnnotation;
|
|
74
|
+
|
|
75
|
+
if (!typeAnnotation) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
typeAnnotation.type === 'TSTypeReference' &&
|
|
81
|
+
typeAnnotation.typeName.type === 'Identifier' &&
|
|
82
|
+
(typeAnnotation.typeName as Identifier).name === specifier
|
|
83
|
+
);
|
|
84
|
+
})
|
|
85
|
+
.forEach((property: TSPropertySignature) => {
|
|
86
|
+
property.typeAnnotation = j.tsTypeAnnotation(
|
|
87
|
+
j.tsUnionType(
|
|
88
|
+
widthNames.map((name) => j.tsLiteralType(j.stringLiteral(name))),
|
|
89
|
+
),
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import core, {
|
|
2
|
+
ArrayExpression,
|
|
3
|
+
ASTPath,
|
|
4
|
+
Collection,
|
|
5
|
+
Identifier,
|
|
6
|
+
JSXAttribute,
|
|
7
|
+
JSXElement,
|
|
8
|
+
JSXExpressionContainer,
|
|
9
|
+
ObjectExpression,
|
|
10
|
+
Property,
|
|
11
|
+
VariableDeclaration,
|
|
12
|
+
VariableDeclarator,
|
|
13
|
+
} from 'jscodeshift/src/core';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
addCommentBefore,
|
|
17
|
+
addDynamicImport,
|
|
18
|
+
getDefaultSpecifier,
|
|
19
|
+
getDynamicImportName,
|
|
20
|
+
getJSXAttributesByName,
|
|
21
|
+
getSafeImportName,
|
|
22
|
+
tryCreateImport,
|
|
23
|
+
} from '@atlaskit/codemod-utils';
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
ACTIONS_PROP_NAME,
|
|
27
|
+
APPEARANCE_PROP_NAME,
|
|
28
|
+
AUTOFOCUS_PROP_NAME,
|
|
29
|
+
BUTTON_COMPONENT_FALLBACK_NAME,
|
|
30
|
+
BUTTON_COMPONENT_NAME,
|
|
31
|
+
BUTTON_ENDPOINT,
|
|
32
|
+
MODAL_FOOTER_COMPONENT_FALLBACK_NAME,
|
|
33
|
+
MODAL_FOOTER_COMPONENT_NAME,
|
|
34
|
+
MODAL_FOOTER_ENDPOINT,
|
|
35
|
+
PACKAGE_NAME,
|
|
36
|
+
} from '../internal/constants';
|
|
37
|
+
import {
|
|
38
|
+
addToImport,
|
|
39
|
+
getAppearanceFromProp,
|
|
40
|
+
getComponentImportName,
|
|
41
|
+
getVariableDeclarationPathByName,
|
|
42
|
+
} from '../internal/utils';
|
|
43
|
+
|
|
44
|
+
const comment = `
|
|
45
|
+
In this codemod, we are moving the position of the primary button to the right-hand side of
|
|
46
|
+
modal footer to align with the design guidelines while we convert your usage of 'actions' prop.
|
|
47
|
+
|
|
48
|
+
However, we could not definitively determine if the 'appearance' prop has been included in the 'actions' prop in this file,
|
|
49
|
+
so in this case, we have converted the 'actions' prop into Button components without moving the position of the primary button.
|
|
50
|
+
To complete the migration and align with the design guidelines, please make the necessary changes manually.`;
|
|
51
|
+
|
|
52
|
+
export const mapActionsProp = (
|
|
53
|
+
j: core.JSCodeshift,
|
|
54
|
+
source: Collection<Node>,
|
|
55
|
+
) => {
|
|
56
|
+
let isActionsPropPresent;
|
|
57
|
+
const defaultSpecifierName = getDefaultSpecifier(j, source, PACKAGE_NAME);
|
|
58
|
+
const buttonDefaultSpecifierName = getDefaultSpecifier(
|
|
59
|
+
j,
|
|
60
|
+
source,
|
|
61
|
+
BUTTON_ENDPOINT,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const dynamicImportName = getDynamicImportName(j, source, PACKAGE_NAME);
|
|
65
|
+
const modalDialogComponentName = defaultSpecifierName || dynamicImportName;
|
|
66
|
+
|
|
67
|
+
if (!modalDialogComponentName) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const modalFooterComponentName = getSafeImportName({
|
|
71
|
+
j,
|
|
72
|
+
base: source,
|
|
73
|
+
desiredName: MODAL_FOOTER_COMPONENT_NAME,
|
|
74
|
+
fallbackName: MODAL_FOOTER_COMPONENT_FALLBACK_NAME,
|
|
75
|
+
currentDefaultSpecifierName: null,
|
|
76
|
+
});
|
|
77
|
+
const buttonComponentName = getSafeImportName({
|
|
78
|
+
j,
|
|
79
|
+
base: source,
|
|
80
|
+
desiredName: BUTTON_COMPONENT_NAME,
|
|
81
|
+
fallbackName: BUTTON_COMPONENT_FALLBACK_NAME,
|
|
82
|
+
currentDefaultSpecifierName: buttonDefaultSpecifierName,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
source
|
|
86
|
+
.findJSXElements(modalDialogComponentName)
|
|
87
|
+
.forEach((element: ASTPath<JSXElement>) => {
|
|
88
|
+
getJSXAttributesByName(j, element, ACTIONS_PROP_NAME).forEach(
|
|
89
|
+
(attribute: ASTPath<JSXAttribute>) => {
|
|
90
|
+
const actionsPropValue = (attribute.node
|
|
91
|
+
.value as JSXExpressionContainer)?.expression;
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
!actionsPropValue ||
|
|
95
|
+
actionsPropValue.type === 'JSXEmptyExpression'
|
|
96
|
+
) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
isActionsPropPresent = true;
|
|
101
|
+
|
|
102
|
+
j(attribute).remove();
|
|
103
|
+
|
|
104
|
+
element.node.openingElement.selfClosing = false;
|
|
105
|
+
element.node.closingElement = j.jsxClosingElement(
|
|
106
|
+
j.jsxIdentifier(modalDialogComponentName),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const footerComponent = getFooterComponent(
|
|
110
|
+
j,
|
|
111
|
+
source,
|
|
112
|
+
element,
|
|
113
|
+
modalFooterComponentName,
|
|
114
|
+
buttonComponentName,
|
|
115
|
+
actionsPropValue,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (element.node.children) {
|
|
119
|
+
element.node.children.push(footerComponent, j.jsxText('\n'));
|
|
120
|
+
} else {
|
|
121
|
+
element.node.children = [footerComponent, j.jsxText('\n')];
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (isActionsPropPresent) {
|
|
128
|
+
if (defaultSpecifierName) {
|
|
129
|
+
addToImport(j, source, [
|
|
130
|
+
getComponentImportName(
|
|
131
|
+
j,
|
|
132
|
+
modalFooterComponentName,
|
|
133
|
+
MODAL_FOOTER_COMPONENT_NAME,
|
|
134
|
+
),
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
if (!buttonDefaultSpecifierName) {
|
|
138
|
+
tryCreateImport(j, source, PACKAGE_NAME, BUTTON_ENDPOINT);
|
|
139
|
+
addToImport(
|
|
140
|
+
j,
|
|
141
|
+
source,
|
|
142
|
+
[j.importDefaultSpecifier(j.identifier(buttonComponentName))],
|
|
143
|
+
BUTTON_ENDPOINT,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (dynamicImportName) {
|
|
148
|
+
addDynamicImport(
|
|
149
|
+
j,
|
|
150
|
+
getVariableDeclarationPathByName(j, source, dynamicImportName),
|
|
151
|
+
modalFooterComponentName,
|
|
152
|
+
MODAL_FOOTER_ENDPOINT,
|
|
153
|
+
);
|
|
154
|
+
addDynamicImport(
|
|
155
|
+
j,
|
|
156
|
+
getVariableDeclarationPathByName(j, source, dynamicImportName),
|
|
157
|
+
buttonComponentName,
|
|
158
|
+
BUTTON_ENDPOINT,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const getAppearanceForButton = (
|
|
165
|
+
j: core.JSCodeshift,
|
|
166
|
+
element: ASTPath<JSXElement>,
|
|
167
|
+
isAppearanceSetInActions: boolean,
|
|
168
|
+
defaultValue: string,
|
|
169
|
+
) => {
|
|
170
|
+
const modalDialogAppearance = getAppearanceFromProp(j, element);
|
|
171
|
+
const shouldUseModalDialogAppearance =
|
|
172
|
+
modalDialogAppearance && defaultValue === 'primary';
|
|
173
|
+
|
|
174
|
+
if (isAppearanceSetInActions && shouldUseModalDialogAppearance) {
|
|
175
|
+
return j.logicalExpression(
|
|
176
|
+
'||',
|
|
177
|
+
j.logicalExpression(
|
|
178
|
+
'||',
|
|
179
|
+
j.memberExpression(
|
|
180
|
+
j.identifier('props'),
|
|
181
|
+
j.identifier(APPEARANCE_PROP_NAME),
|
|
182
|
+
),
|
|
183
|
+
// @ts-ignore
|
|
184
|
+
modalDialogAppearance,
|
|
185
|
+
),
|
|
186
|
+
j.stringLiteral(defaultValue),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (isAppearanceSetInActions && !shouldUseModalDialogAppearance) {
|
|
191
|
+
return j.logicalExpression(
|
|
192
|
+
'||',
|
|
193
|
+
j.memberExpression(
|
|
194
|
+
j.identifier('props'),
|
|
195
|
+
j.identifier(APPEARANCE_PROP_NAME),
|
|
196
|
+
),
|
|
197
|
+
j.stringLiteral(defaultValue),
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!isAppearanceSetInActions && shouldUseModalDialogAppearance) {
|
|
202
|
+
return j.logicalExpression(
|
|
203
|
+
'||',
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
modalDialogAppearance,
|
|
206
|
+
j.stringLiteral(defaultValue),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return j.stringLiteral(defaultValue);
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const getFooterComponent = (
|
|
214
|
+
j: core.JSCodeshift,
|
|
215
|
+
source: Collection<Node>,
|
|
216
|
+
element: ASTPath<JSXElement>,
|
|
217
|
+
footerComponentName: string,
|
|
218
|
+
buttonComponentName: string,
|
|
219
|
+
actions: any,
|
|
220
|
+
) => {
|
|
221
|
+
const isAppearanceSetInActions = findAppearanceInActions(
|
|
222
|
+
j,
|
|
223
|
+
source,
|
|
224
|
+
element,
|
|
225
|
+
actions,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
return j.jsxElement(
|
|
229
|
+
j.jsxOpeningElement(j.jsxIdentifier(footerComponentName)),
|
|
230
|
+
j.jsxClosingElement(j.jsxIdentifier(footerComponentName)),
|
|
231
|
+
[
|
|
232
|
+
j.jsxText('\n'),
|
|
233
|
+
j.jsxExpressionContainer(
|
|
234
|
+
/**
|
|
235
|
+
* We reverse the button order only if
|
|
236
|
+
* appearance is NOT set in actions.
|
|
237
|
+
*/
|
|
238
|
+
isAppearanceSetInActions
|
|
239
|
+
? mapActionsAndKeepOrder(j, element, buttonComponentName, actions)
|
|
240
|
+
: mapActionsAndReverseOrder(j, element, buttonComponentName, actions),
|
|
241
|
+
),
|
|
242
|
+
j.jsxText('\n'),
|
|
243
|
+
],
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const mapActionsAndReverseOrder = (
|
|
248
|
+
j: core.JSCodeshift,
|
|
249
|
+
element: core.ASTPath<JSXElement>,
|
|
250
|
+
buttonComponentName: string,
|
|
251
|
+
actions: any,
|
|
252
|
+
) => {
|
|
253
|
+
return j.callExpression(
|
|
254
|
+
j.memberExpression(
|
|
255
|
+
j.callExpression(j.memberExpression(actions, j.identifier('map')), [
|
|
256
|
+
j.arrowFunctionExpression(
|
|
257
|
+
[j.identifier('props'), j.identifier('index')],
|
|
258
|
+
j.jsxElement(
|
|
259
|
+
j.jsxOpeningElement(
|
|
260
|
+
j.jsxIdentifier(buttonComponentName),
|
|
261
|
+
getAttributesForReversedButtons(j, element),
|
|
262
|
+
),
|
|
263
|
+
j.jsxClosingElement(j.jsxIdentifier(buttonComponentName)),
|
|
264
|
+
[
|
|
265
|
+
j.jsxExpressionContainer(
|
|
266
|
+
j.memberExpression(j.identifier('props'), j.identifier('text')),
|
|
267
|
+
),
|
|
268
|
+
],
|
|
269
|
+
),
|
|
270
|
+
),
|
|
271
|
+
]),
|
|
272
|
+
j.identifier('reverse'),
|
|
273
|
+
),
|
|
274
|
+
[],
|
|
275
|
+
);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const mapActionsAndKeepOrder = (
|
|
279
|
+
j: core.JSCodeshift,
|
|
280
|
+
element: core.ASTPath<JSXElement>,
|
|
281
|
+
buttonComponentName: string,
|
|
282
|
+
actions: any,
|
|
283
|
+
) => {
|
|
284
|
+
return j.callExpression(j.memberExpression(actions, j.identifier('map')), [
|
|
285
|
+
j.arrowFunctionExpression(
|
|
286
|
+
[j.identifier('props'), j.identifier('index')],
|
|
287
|
+
j.jsxElement(
|
|
288
|
+
j.jsxOpeningElement(
|
|
289
|
+
j.jsxIdentifier(buttonComponentName),
|
|
290
|
+
getAttributesForButtons(j, element),
|
|
291
|
+
),
|
|
292
|
+
j.jsxClosingElement(j.jsxIdentifier(buttonComponentName)),
|
|
293
|
+
[
|
|
294
|
+
j.jsxExpressionContainer(
|
|
295
|
+
j.memberExpression(j.identifier('props'), j.identifier('text')),
|
|
296
|
+
),
|
|
297
|
+
],
|
|
298
|
+
),
|
|
299
|
+
),
|
|
300
|
+
]);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const getAttributesForReversedButtons = (
|
|
304
|
+
j: core.JSCodeshift,
|
|
305
|
+
element: core.ASTPath<JSXElement>,
|
|
306
|
+
) => {
|
|
307
|
+
return [
|
|
308
|
+
j.jsxSpreadAttribute(j.identifier('props')),
|
|
309
|
+
j.jsxAttribute(
|
|
310
|
+
j.jsxIdentifier(AUTOFOCUS_PROP_NAME),
|
|
311
|
+
j.jsxExpressionContainer(
|
|
312
|
+
j.binaryExpression('===', j.identifier('index'), j.numericLiteral(0)),
|
|
313
|
+
),
|
|
314
|
+
),
|
|
315
|
+
j.jsxAttribute(
|
|
316
|
+
j.jsxIdentifier(APPEARANCE_PROP_NAME),
|
|
317
|
+
j.jsxExpressionContainer(
|
|
318
|
+
j.conditionalExpression(
|
|
319
|
+
j.binaryExpression('===', j.identifier('index'), j.numericLiteral(0)),
|
|
320
|
+
/**
|
|
321
|
+
* This function is called only when appearance is NOT found
|
|
322
|
+
* in actions – hence hardcoding it to 'false'.
|
|
323
|
+
*/
|
|
324
|
+
getAppearanceForButton(j, element, false, 'primary'),
|
|
325
|
+
getAppearanceForButton(j, element, false, 'subtle'),
|
|
326
|
+
),
|
|
327
|
+
),
|
|
328
|
+
),
|
|
329
|
+
];
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
const getAttributesForButtons = (
|
|
333
|
+
j: core.JSCodeshift,
|
|
334
|
+
element: core.ASTPath<JSXElement>,
|
|
335
|
+
) => {
|
|
336
|
+
return [
|
|
337
|
+
j.jsxSpreadAttribute(j.identifier('props')),
|
|
338
|
+
j.jsxAttribute(
|
|
339
|
+
j.jsxIdentifier(APPEARANCE_PROP_NAME),
|
|
340
|
+
j.jsxExpressionContainer(
|
|
341
|
+
j.conditionalExpression(
|
|
342
|
+
j.binaryExpression('===', j.identifier('index'), j.numericLiteral(0)),
|
|
343
|
+
/**
|
|
344
|
+
* This function is called only when appearance is found
|
|
345
|
+
* in actions – hence hardcoding it to 'true'.
|
|
346
|
+
*/
|
|
347
|
+
getAppearanceForButton(j, element, true, 'primary'),
|
|
348
|
+
getAppearanceForButton(j, element, true, 'subtle'),
|
|
349
|
+
),
|
|
350
|
+
),
|
|
351
|
+
),
|
|
352
|
+
];
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const findAppearanceInActions = (
|
|
356
|
+
j: core.JSCodeshift,
|
|
357
|
+
source: Collection<Node>,
|
|
358
|
+
element: core.ASTPath<JSXElement>,
|
|
359
|
+
actions: any,
|
|
360
|
+
) => {
|
|
361
|
+
if (actions.type === 'Identifier') {
|
|
362
|
+
const actionPropVariableName = (actions as Identifier).name;
|
|
363
|
+
|
|
364
|
+
const actionsVariableDeclaration = getVariableDeclarationByName(
|
|
365
|
+
source,
|
|
366
|
+
j,
|
|
367
|
+
actionPropVariableName,
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* If there are multiple variables declared with the same name,
|
|
372
|
+
* we assume that it is and keep the button order the same.
|
|
373
|
+
*/
|
|
374
|
+
if (actionsVariableDeclaration.length > 1) {
|
|
375
|
+
addCommentBefore(j, j(element), comment);
|
|
376
|
+
|
|
377
|
+
return true;
|
|
378
|
+
} else {
|
|
379
|
+
/**
|
|
380
|
+
* If actions prop is declared as variable, and we can find the declaration
|
|
381
|
+
* in the same file, we check if there's any appearance property set.
|
|
382
|
+
*/
|
|
383
|
+
const actionPropVariableValue = (actionsVariableDeclaration as any)?.nodes()[0]
|
|
384
|
+
.declarations[0]?.init;
|
|
385
|
+
|
|
386
|
+
return checkAppearancePropertyExistence(actionPropVariableValue);
|
|
387
|
+
}
|
|
388
|
+
} else if (actions.type === 'ArrayExpression') {
|
|
389
|
+
/**
|
|
390
|
+
* If actions prop is declared inline, we check if there's any appearance property set.
|
|
391
|
+
*/
|
|
392
|
+
return checkAppearancePropertyExistence(actions);
|
|
393
|
+
} else {
|
|
394
|
+
/**
|
|
395
|
+
* If we cannot definitively determine whether appearance is set in any of the actions,
|
|
396
|
+
* we assume that it is and keep the button order the same.
|
|
397
|
+
*/
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const checkAppearancePropertyExistence = (actions: any) => {
|
|
403
|
+
return (actions as ArrayExpression).elements.some((elem) => {
|
|
404
|
+
return (elem as ObjectExpression).properties.some((property) => {
|
|
405
|
+
return (
|
|
406
|
+
((property as Property).key as Identifier).name === APPEARANCE_PROP_NAME
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const getVariableDeclarationByName = (
|
|
413
|
+
source: core.Collection<Node>,
|
|
414
|
+
j: core.JSCodeshift,
|
|
415
|
+
variableName: string,
|
|
416
|
+
) => {
|
|
417
|
+
return source
|
|
418
|
+
.find(j.VariableDeclaration)
|
|
419
|
+
.filter((variableDeclaration: ASTPath<VariableDeclaration>) => {
|
|
420
|
+
return variableDeclaration.node.declarations.some(
|
|
421
|
+
(variableDeclarator) => {
|
|
422
|
+
const variableDeclaratorTyped = variableDeclarator as VariableDeclarator;
|
|
423
|
+
return (
|
|
424
|
+
variableDeclaratorTyped.id.type === 'Identifier' &&
|
|
425
|
+
variableDeclaratorTyped.id.name === variableName
|
|
426
|
+
);
|
|
427
|
+
},
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
};
|