@kaizen/components 2.2.3 → 2.3.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/codemods/migrateGuidanceBlockActionsToActionsSlot/migrateGuidanceBlockActionsToActionsSlot.spec.ts +209 -26
- package/codemods/migrateGuidanceBlockActionsToActionsSlot/migrateGuidanceBlockActionsToActionsSlot.ts +24 -1
- package/codemods/migrateGuidanceBlockActionsToActionsSlot/transformActionsToActionsSlot.spec.ts +107 -1
- package/codemods/migrateGuidanceBlockActionsToActionsSlot/transformActionsToActionsSlot.ts +20 -0
- package/codemods/runV1Codemods/__snapshots__/runV1Codemods.spec.ts.snap +2 -3
- package/codemods/runV1Codemods/runV1Codemods.spec.ts +2 -3
- package/codemods/utils/transformV1ButtonPropsToButtonOrLinkButton.ts +44 -14
- package/dist/cjs/src/MenuV1/index.cjs +4 -3
- package/dist/cjs/src/TitleBlock/TitleBlock.cjs +26 -36
- package/dist/cjs/src/TitleBlock/TitleBlock.module.scss.cjs +3 -0
- package/dist/cjs/src/TitleBlock/subcomponents/MainActions.cjs +90 -45
- package/dist/cjs/src/TitleBlock/subcomponents/MainActions.module.scss.cjs +3 -1
- package/dist/cjs/src/TitleBlock/subcomponents/SecondaryActions.cjs +51 -14
- package/dist/esm/src/MenuV1/index.mjs +5 -3
- package/dist/esm/src/TitleBlock/TitleBlock.mjs +27 -37
- package/dist/esm/src/TitleBlock/TitleBlock.module.scss.mjs +3 -0
- package/dist/esm/src/TitleBlock/subcomponents/MainActions.mjs +92 -47
- package/dist/esm/src/TitleBlock/subcomponents/MainActions.module.scss.mjs +3 -1
- package/dist/esm/src/TitleBlock/subcomponents/SecondaryActions.mjs +51 -14
- package/dist/styles.css +51 -201
- package/dist/types/TitleBlock/TitleBlock.d.ts +1 -1
- package/dist/types/TitleBlock/subcomponents/MainActions.d.ts +4 -3
- package/package.json +1 -1
- package/src/TitleBlock/TitleBlock.module.scss +28 -10
- package/src/TitleBlock/TitleBlock.spec.tsx +33 -461
- package/src/TitleBlock/TitleBlock.tsx +4 -24
- package/src/TitleBlock/_docs/TitleBlock.stories.tsx +25 -5
- package/src/TitleBlock/_mixins.scss +6 -0
- package/src/TitleBlock/subcomponents/MainActions.module.scss +27 -2
- package/src/TitleBlock/subcomponents/MainActions.tsx +127 -70
- package/src/TitleBlock/subcomponents/SecondaryActions.tsx +105 -45
- package/src/TitleBlock/subcomponents/Toolbar.tsx +1 -0
- package/dist/cjs/src/MenuV1/subcomponents/MenuHeading/MenuHeading.cjs +0 -27
- package/dist/cjs/src/MenuV1/subcomponents/MenuHeading/MenuHeading.module.scss.cjs +0 -6
- package/dist/cjs/src/TitleBlock/subcomponents/MobileActions.cjs +0 -306
- package/dist/cjs/src/TitleBlock/subcomponents/MobileActions.module.scss.cjs +0 -16
- package/dist/esm/src/MenuV1/subcomponents/MenuHeading/MenuHeading.mjs +0 -21
- package/dist/esm/src/MenuV1/subcomponents/MenuHeading/MenuHeading.module.scss.mjs +0 -4
- package/dist/esm/src/TitleBlock/subcomponents/MobileActions.mjs +0 -300
- package/dist/esm/src/TitleBlock/subcomponents/MobileActions.module.scss.mjs +0 -14
- package/dist/types/TitleBlock/subcomponents/MobileActions.d.ts +0 -14
- package/src/TitleBlock/subcomponents/MobileActions.module.scss +0 -208
- package/src/TitleBlock/subcomponents/MobileActions.spec.tsx +0 -210
- package/src/TitleBlock/subcomponents/MobileActions.tsx +0 -472
|
@@ -15,9 +15,10 @@ const transformGuidanceBlock = (sourceFile: TransformSourceArgs['sourceFile']):
|
|
|
15
15
|
})
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
describe('
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
describe('migrateGuidanceBlockActionsToActionsSlot()', () => {
|
|
19
|
+
describe('basic transformation', () => {
|
|
20
|
+
it('imports Button and transforms all button-like actions prop into a Button component', () => {
|
|
21
|
+
const inputAst = parseJsx(`
|
|
21
22
|
import { GuidanceBlock } from "@kaizen/components"
|
|
22
23
|
<GuidanceBlock
|
|
23
24
|
layout="default"
|
|
@@ -34,21 +35,21 @@ describe('transformActionsToButtonNext()', () => {
|
|
|
34
35
|
},
|
|
35
36
|
}}
|
|
36
37
|
/>`)
|
|
37
|
-
|
|
38
|
-
import { GuidanceBlock } from "@kaizen/components"
|
|
39
|
-
import { Button } from "@kaizen/components/next"
|
|
38
|
+
const outputAst = parseJsx(`
|
|
39
|
+
import { GuidanceBlock, Button, Icon } from "@kaizen/components"
|
|
40
40
|
<GuidanceBlock
|
|
41
41
|
layout="default"
|
|
42
42
|
illustration={<Informative alt="" />}
|
|
43
43
|
content={<div>Test</div>}
|
|
44
|
-
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large">Primary action</Button><Button onPress={() => alert('click 2')} variant="tertiary" size="large">Secondary action</Button></>}
|
|
44
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button><Button onPress={() => alert('click 2')} variant="tertiary" size="large">Secondary action</Button></>}
|
|
45
45
|
/>
|
|
46
46
|
`)
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('imports and transforms all button-like and link-like actions prop into a Button and LinkButton', () => {
|
|
52
|
+
const inputAst = parseJsx(`
|
|
52
53
|
import { GuidanceBlock } from "@kaizen/components"
|
|
53
54
|
<GuidanceBlock
|
|
54
55
|
layout="default"
|
|
@@ -65,23 +66,22 @@ describe('transformActionsToButtonNext()', () => {
|
|
|
65
66
|
},
|
|
66
67
|
}}
|
|
67
68
|
/>`)
|
|
68
|
-
|
|
69
|
-
import {
|
|
70
|
-
import { Button } from "@kaizen/components/next"
|
|
69
|
+
const outputAst = parseJsx(`
|
|
70
|
+
import {GuidanceBlock, Button, LinkButton, Icon } from "@kaizen/components"
|
|
71
71
|
<GuidanceBlock
|
|
72
72
|
layout="default"
|
|
73
73
|
illustration={<Informative alt="" />}
|
|
74
74
|
content={<div>Test</div>}
|
|
75
|
-
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
75
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
76
76
|
/>
|
|
77
77
|
`)
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
import { Button } from "@kaizen/components
|
|
79
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('does not redeclare imports if found', () => {
|
|
83
|
+
const inputAst = parseJsx(`
|
|
84
|
+
import { Button, GuidanceBlock } from "@kaizen/components"
|
|
85
85
|
const MockLayout = () => (
|
|
86
86
|
<>
|
|
87
87
|
<GuidanceBlock
|
|
@@ -102,21 +102,204 @@ describe('transformActionsToButtonNext()', () => {
|
|
|
102
102
|
<Button onPress={() => alert('page click 1')} variant="primary" size="large">Page button</Button>
|
|
103
103
|
</>
|
|
104
104
|
)`)
|
|
105
|
-
|
|
106
|
-
import { GuidanceBlock, LinkButton } from "@kaizen/components"
|
|
107
|
-
import { Button } from "@kaizen/components/next"
|
|
105
|
+
const outputAst = parseJsx(`
|
|
106
|
+
import { Button, GuidanceBlock, LinkButton, Icon } from "@kaizen/components"
|
|
108
107
|
const MockLayout = () => (
|
|
109
108
|
<>
|
|
110
109
|
<GuidanceBlock
|
|
111
110
|
layout="default"
|
|
112
111
|
illustration={<Informative alt="" />}
|
|
113
112
|
content={<div>Test</div>}
|
|
114
|
-
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
113
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
115
114
|
/>
|
|
116
115
|
<Button onPress={() => alert('page click 1')} variant="primary" size="large">Page button</Button>
|
|
117
116
|
</>
|
|
118
117
|
)`)
|
|
119
118
|
|
|
120
|
-
|
|
119
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('preserves custom icon components without adding Icon import', () => {
|
|
123
|
+
const inputAst = parseJsx(`
|
|
124
|
+
import { GuidanceBlock } from "@kaizen/components"
|
|
125
|
+
<GuidanceBlock
|
|
126
|
+
actions={{
|
|
127
|
+
primary: {
|
|
128
|
+
label: 'Action',
|
|
129
|
+
onClick: () => {},
|
|
130
|
+
icon: <MyCustomIcon />,
|
|
131
|
+
iconPosition: 'end',
|
|
132
|
+
},
|
|
133
|
+
}}
|
|
134
|
+
/>`)
|
|
135
|
+
const outputAst = parseJsx(`
|
|
136
|
+
import { GuidanceBlock, Button } from "@kaizen/components"
|
|
137
|
+
<GuidanceBlock
|
|
138
|
+
actionsSlot={<><Button onPress={() => {}} icon={<MyCustomIcon />} iconPosition='end' variant="secondary" size="large">Action</Button></>}
|
|
139
|
+
/>
|
|
140
|
+
`)
|
|
141
|
+
|
|
142
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
describe('arrow icon handling', () => {
|
|
146
|
+
// When withActionButtonArrow not specified, add arrow icon actionsSlot secondary Button
|
|
147
|
+
it('adds arrow icon to actionsSlot secondary Button when withActionButtonArrow is not explicitly set', () => {
|
|
148
|
+
const inputAst = parseJsx(`
|
|
149
|
+
import { GuidanceBlock, LinkButton } from "@kaizen/components"
|
|
150
|
+
<GuidanceBlock
|
|
151
|
+
layout="default"
|
|
152
|
+
illustration={<Informative alt="" />}
|
|
153
|
+
content={<div>Test</div>}
|
|
154
|
+
actions={{
|
|
155
|
+
primary: {
|
|
156
|
+
label: 'Primary action',
|
|
157
|
+
onClick: () => alert('click 1'),
|
|
158
|
+
},
|
|
159
|
+
secondary: {
|
|
160
|
+
label: 'Secondary action',
|
|
161
|
+
href: "#secondary"
|
|
162
|
+
},
|
|
163
|
+
}}
|
|
164
|
+
/>`)
|
|
165
|
+
const outputAst = parseJsx(`
|
|
166
|
+
import { GuidanceBlock, LinkButton, Button, Icon } from "@kaizen/components"
|
|
167
|
+
<GuidanceBlock
|
|
168
|
+
layout="default"
|
|
169
|
+
illustration={<Informative alt="" />}
|
|
170
|
+
content={<div>Test</div>}
|
|
171
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
172
|
+
/>
|
|
173
|
+
`)
|
|
174
|
+
|
|
175
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
// When withActionButtonArrow is set to true, add arrow icon to actionsSlot secondary Button
|
|
179
|
+
it('adds arrow icon to actionsSlot secondary Button when withActionButtonArrow is true', () => {
|
|
180
|
+
const inputAst = parseJsx(`
|
|
181
|
+
import { GuidanceBlock } from "@kaizen/components"
|
|
182
|
+
<GuidanceBlock
|
|
183
|
+
layout="default"
|
|
184
|
+
illustration={<Informative alt="" />}
|
|
185
|
+
content={<div>Test</div>}
|
|
186
|
+
withActionButtonArrow={true}
|
|
187
|
+
actions={{
|
|
188
|
+
primary: {
|
|
189
|
+
label: 'Primary action',
|
|
190
|
+
onClick: () => alert('click 1'),
|
|
191
|
+
},
|
|
192
|
+
secondary: {
|
|
193
|
+
label: 'Secondary action',
|
|
194
|
+
href: "#secondary"
|
|
195
|
+
},
|
|
196
|
+
}}
|
|
197
|
+
/>`)
|
|
198
|
+
const outputAst = parseJsx(`
|
|
199
|
+
import { GuidanceBlock, Button, LinkButton, Icon } from "@kaizen/components"
|
|
200
|
+
<GuidanceBlock
|
|
201
|
+
layout="default"
|
|
202
|
+
illustration={<Informative alt="" />}
|
|
203
|
+
content={<div>Test</div>}
|
|
204
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
205
|
+
/>
|
|
206
|
+
`)
|
|
207
|
+
|
|
208
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
// When withActionButtonArrow is explicitly false, do not add arrow icon to actionsSlot secondary Button
|
|
212
|
+
it('does not add arrow icon to actionsSlot secondary Button when withActionButtonArrow is false', () => {
|
|
213
|
+
const inputAst = parseJsx(`
|
|
214
|
+
import { GuidanceBlock } from "@kaizen/components"
|
|
215
|
+
<GuidanceBlock
|
|
216
|
+
layout="default"
|
|
217
|
+
illustration={<Informative alt="" />}
|
|
218
|
+
content={<div>Test</div>}
|
|
219
|
+
withActionButtonArrow={false}
|
|
220
|
+
actions={{
|
|
221
|
+
primary: {
|
|
222
|
+
label: 'Primary action',
|
|
223
|
+
onClick: () => alert('click 1'),
|
|
224
|
+
},
|
|
225
|
+
secondary: {
|
|
226
|
+
label: 'Secondary action',
|
|
227
|
+
href: "#secondary"
|
|
228
|
+
},
|
|
229
|
+
}}
|
|
230
|
+
/>`)
|
|
231
|
+
const outputAst = parseJsx(`
|
|
232
|
+
import { GuidanceBlock, Button, LinkButton } from "@kaizen/components"
|
|
233
|
+
<GuidanceBlock
|
|
234
|
+
layout="default"
|
|
235
|
+
illustration={<Informative alt="" />}
|
|
236
|
+
content={<div>Test</div>}
|
|
237
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
238
|
+
/>
|
|
239
|
+
`)
|
|
240
|
+
|
|
241
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
describe('removes deprecated props', () => {
|
|
246
|
+
it('removes withActionButtonArrow prop', () => {
|
|
247
|
+
const inputAst = parseJsx(`
|
|
248
|
+
import { GuidanceBlock } from "@kaizen/components"
|
|
249
|
+
<GuidanceBlock
|
|
250
|
+
layout="default"
|
|
251
|
+
illustration={<Informative alt="" />}
|
|
252
|
+
content={<div>Test</div>}
|
|
253
|
+
withActionButtonArrow={true}
|
|
254
|
+
actions={{
|
|
255
|
+
primary: {
|
|
256
|
+
label: 'Primary action',
|
|
257
|
+
onClick: () => alert('click 1'),
|
|
258
|
+
},
|
|
259
|
+
}}
|
|
260
|
+
/>
|
|
261
|
+
`)
|
|
262
|
+
const outputAst = parseJsx(`
|
|
263
|
+
import { GuidanceBlock, Button, Icon } from "@kaizen/components"
|
|
264
|
+
<GuidanceBlock
|
|
265
|
+
layout="default"
|
|
266
|
+
illustration={<Informative alt="" />}
|
|
267
|
+
content={<div>Test</div>}
|
|
268
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button></>}
|
|
269
|
+
/>
|
|
270
|
+
`)
|
|
271
|
+
|
|
272
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
it('removes secondaryDismiss prop', () => {
|
|
276
|
+
const inputAst = parseJsx(`
|
|
277
|
+
import { GuidanceBlock } from "@kaizen/components"
|
|
278
|
+
<GuidanceBlock
|
|
279
|
+
layout="default"
|
|
280
|
+
illustration={<Informative alt="" />}
|
|
281
|
+
content={<div>Test</div>}
|
|
282
|
+
secondaryDismiss={true}
|
|
283
|
+
actions={{
|
|
284
|
+
primary: {
|
|
285
|
+
label: 'Primary action',
|
|
286
|
+
onClick: () => alert('click 1'),
|
|
287
|
+
},
|
|
288
|
+
}}
|
|
289
|
+
/>
|
|
290
|
+
`)
|
|
291
|
+
const outputAst = parseJsx(`
|
|
292
|
+
import {GuidanceBlock, Button, Icon } from "@kaizen/components"
|
|
293
|
+
<GuidanceBlock
|
|
294
|
+
layout="default"
|
|
295
|
+
illustration={<Informative alt="" />}
|
|
296
|
+
content={<div>Test</div>}
|
|
297
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational />} iconPosition="end">Primary action</Button></>}
|
|
298
|
+
/>
|
|
299
|
+
`)
|
|
300
|
+
|
|
301
|
+
expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
|
|
302
|
+
})
|
|
303
|
+
})
|
|
121
304
|
})
|
|
122
305
|
})
|
|
@@ -8,8 +8,9 @@ import {
|
|
|
8
8
|
} from '../utils'
|
|
9
9
|
import { transformActionsToActionsSlot } from './transformActionsToActionsSlot'
|
|
10
10
|
|
|
11
|
-
const BUTTON_IMPORT_DESTINATION = '@kaizen/components
|
|
11
|
+
const BUTTON_IMPORT_DESTINATION = '@kaizen/components'
|
|
12
12
|
const LINKBUTTON_IMPORT_DESTINATION = '@kaizen/components'
|
|
13
|
+
const ICON_IMPORT_DESTINATION = '@kaizen/components'
|
|
13
14
|
|
|
14
15
|
export const migrateGuidanceBlockActionsToActionsSlot =
|
|
15
16
|
(tagsMap: TagImportAttributesMap): ts.TransformerFactory<ts.SourceFile> =>
|
|
@@ -40,6 +41,9 @@ export const migrateGuidanceBlockActionsToActionsSlot =
|
|
|
40
41
|
tagName === 'GuidanceBlock' ||
|
|
41
42
|
tagImportAttributes.importModuleName === 'GuidanceBlock'
|
|
42
43
|
) {
|
|
44
|
+
// Added flag to add arrow-forward icon to the secondary-variant Button created from the primary action, to minimise visual changes
|
|
45
|
+
let hasActionButtonArrow: boolean = true
|
|
46
|
+
|
|
43
47
|
const componentProps: ts.JsxAttributeLike[] = node.attributes.properties.reduce<
|
|
44
48
|
ts.JsxAttributeLike[]
|
|
45
49
|
>((guidanceBlockProps, prop) => {
|
|
@@ -47,9 +51,23 @@ export const migrateGuidanceBlockActionsToActionsSlot =
|
|
|
47
51
|
const propName = prop.name.getText()
|
|
48
52
|
const propValue = prop.initializer as ts.JsxExpression
|
|
49
53
|
|
|
54
|
+
if (propName === 'withActionButtonArrow') {
|
|
55
|
+
if (propValue?.expression?.kind === ts.SyntaxKind.FalseKeyword) {
|
|
56
|
+
hasActionButtonArrow = false
|
|
57
|
+
} else {
|
|
58
|
+
hasActionButtonArrow = true
|
|
59
|
+
}
|
|
60
|
+
return guidanceBlockProps
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (propName === 'secondaryDismiss') {
|
|
64
|
+
return guidanceBlockProps
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
if (propName === 'actions') {
|
|
51
68
|
const transformedActions = transformActionsToActionsSlot(
|
|
52
69
|
propValue.getChildren()[1] as ts.ObjectLiteralExpression,
|
|
70
|
+
hasActionButtonArrow,
|
|
53
71
|
)
|
|
54
72
|
|
|
55
73
|
if (transformedActions?.importsToAdd) {
|
|
@@ -72,6 +90,11 @@ export const migrateGuidanceBlockActionsToActionsSlot =
|
|
|
72
90
|
: undefined,
|
|
73
91
|
})
|
|
74
92
|
}
|
|
93
|
+
if (importToAdd === 'Icon') {
|
|
94
|
+
setImportToAdd(importsToAdd, ICON_IMPORT_DESTINATION, {
|
|
95
|
+
componentName: 'Icon',
|
|
96
|
+
})
|
|
97
|
+
}
|
|
75
98
|
})
|
|
76
99
|
}
|
|
77
100
|
|
package/codemods/migrateGuidanceBlockActionsToActionsSlot/transformActionsToActionsSlot.spec.ts
CHANGED
|
@@ -19,6 +19,7 @@ export const mockedTransformer =
|
|
|
19
19
|
if (propName === 'actions') {
|
|
20
20
|
const transformedActions = transformActionsToActionsSlot(
|
|
21
21
|
propValue.getChildren()[1] as ts.ObjectLiteralExpression,
|
|
22
|
+
true,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
return transformedActions?.actionsSlotAttr
|
|
@@ -74,7 +75,7 @@ describe('transformActionsToActionsSlot()', () => {
|
|
|
74
75
|
layout="default"
|
|
75
76
|
illustration={<Informative alt="" />}
|
|
76
77
|
content={<div>Test</div>}
|
|
77
|
-
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
78
|
+
actionsSlot={<><Button onPress={() => alert('click 1')} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational/>} iconPosition="end">Primary action</Button><LinkButton href="#secondary" variant="tertiary" size="large">Secondary action</LinkButton></>}
|
|
78
79
|
/>
|
|
79
80
|
`)
|
|
80
81
|
|
|
@@ -193,4 +194,109 @@ describe('transformActionsToActionsSlot()', () => {
|
|
|
193
194
|
printAst(outputAst).replace(/\s+/g, ' '),
|
|
194
195
|
)
|
|
195
196
|
})
|
|
197
|
+
|
|
198
|
+
it('removes primary: true and applies variantOverride as secondary for primary actions', () => {
|
|
199
|
+
const inputAst = parseJsx(`
|
|
200
|
+
<GuidanceBlock
|
|
201
|
+
actions={{
|
|
202
|
+
primary: {
|
|
203
|
+
label: 'Action',
|
|
204
|
+
onClick: () => {},
|
|
205
|
+
primary: true,
|
|
206
|
+
},
|
|
207
|
+
}}
|
|
208
|
+
/>`)
|
|
209
|
+
const outputAst = parseJsx(`
|
|
210
|
+
<GuidanceBlock
|
|
211
|
+
actionsSlot={<><Button onPress={() => {}} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational/>} iconPosition="end">Action</Button></>}
|
|
212
|
+
/>
|
|
213
|
+
`)
|
|
214
|
+
|
|
215
|
+
expect(transformInput(inputAst)).toBe(printAst(outputAst))
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('removes secondary: true and applies variantOverride as secondary for primary actions', () => {
|
|
219
|
+
const inputAst = parseJsx(`
|
|
220
|
+
<GuidanceBlock
|
|
221
|
+
actions={{
|
|
222
|
+
primary: {
|
|
223
|
+
label: 'Action',
|
|
224
|
+
onClick: () => {},
|
|
225
|
+
secondary: true,
|
|
226
|
+
},
|
|
227
|
+
}}
|
|
228
|
+
/>`)
|
|
229
|
+
const outputAst = parseJsx(`
|
|
230
|
+
<GuidanceBlock
|
|
231
|
+
actionsSlot={<><Button onPress={() => {}} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational/>} iconPosition="end">Action</Button></>}
|
|
232
|
+
/>
|
|
233
|
+
`)
|
|
234
|
+
|
|
235
|
+
expect(transformInput(inputAst)).toBe(printAst(outputAst))
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('removes primary: true and applies variantOverride as tertiary for secondary actions', () => {
|
|
239
|
+
const inputAst = parseJsx(`
|
|
240
|
+
<GuidanceBlock
|
|
241
|
+
actions={{
|
|
242
|
+
secondary: {
|
|
243
|
+
label: 'Secondary Action',
|
|
244
|
+
onClick: () => {},
|
|
245
|
+
primary: true,
|
|
246
|
+
},
|
|
247
|
+
}}
|
|
248
|
+
/>`)
|
|
249
|
+
const outputAst = parseJsx(`
|
|
250
|
+
<GuidanceBlock
|
|
251
|
+
actionsSlot={<><Button onPress={() => {}} variant="tertiary" size="large">Secondary Action</Button></>}
|
|
252
|
+
/>
|
|
253
|
+
`)
|
|
254
|
+
|
|
255
|
+
expect(transformInput(inputAst)).toBe(printAst(outputAst))
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
it('removes secondary: true and applies variantOverride as tertiary for secondary actions', () => {
|
|
259
|
+
const inputAst = parseJsx(`
|
|
260
|
+
<GuidanceBlock
|
|
261
|
+
actions={{
|
|
262
|
+
secondary: {
|
|
263
|
+
label: 'Secondary Action',
|
|
264
|
+
onClick: () => {},
|
|
265
|
+
secondary: true,
|
|
266
|
+
},
|
|
267
|
+
}}
|
|
268
|
+
/>`)
|
|
269
|
+
const outputAst = parseJsx(`
|
|
270
|
+
<GuidanceBlock
|
|
271
|
+
actionsSlot={<><Button onPress={() => {}} variant="tertiary" size="large">Secondary Action</Button></>}
|
|
272
|
+
/>
|
|
273
|
+
`)
|
|
274
|
+
|
|
275
|
+
expect(transformInput(inputAst)).toBe(printAst(outputAst))
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('applies correct variants for both primary and secondary actions with primary: true', () => {
|
|
279
|
+
const inputAst = parseJsx(`
|
|
280
|
+
<GuidanceBlock
|
|
281
|
+
actions={{
|
|
282
|
+
primary: {
|
|
283
|
+
label: 'Primary',
|
|
284
|
+
onClick: () => {},
|
|
285
|
+
primary: true,
|
|
286
|
+
},
|
|
287
|
+
secondary: {
|
|
288
|
+
label: 'Secondary',
|
|
289
|
+
onClick: () => {},
|
|
290
|
+
primary: true,
|
|
291
|
+
},
|
|
292
|
+
}}
|
|
293
|
+
/>`)
|
|
294
|
+
const outputAst = parseJsx(`
|
|
295
|
+
<GuidanceBlock
|
|
296
|
+
actionsSlot={<><Button onPress={() => {}} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational/>} iconPosition="end">Primary</Button><Button onPress={() => {}} variant="tertiary" size="large">Secondary</Button></>}
|
|
297
|
+
/>
|
|
298
|
+
`)
|
|
299
|
+
|
|
300
|
+
expect(transformInput(inputAst)).toBe(printAst(outputAst))
|
|
301
|
+
})
|
|
196
302
|
})
|
|
@@ -13,9 +13,11 @@ type GuidanceBlockTransformedActions = {
|
|
|
13
13
|
*/
|
|
14
14
|
export const transformActionsToActionsSlot = (
|
|
15
15
|
node: ts.ObjectLiteralExpression,
|
|
16
|
+
hasActionButtonArrow: boolean,
|
|
16
17
|
): GuidanceBlockTransformedActions | undefined => {
|
|
17
18
|
if (ts.isObjectLiteralExpression(node)) {
|
|
18
19
|
const newImports: (string | undefined)[] = []
|
|
20
|
+
let arrowIconWasAdded = false
|
|
19
21
|
|
|
20
22
|
const primaryAction = node.properties.find((prop) => prop?.name?.getText() === 'primary') as
|
|
21
23
|
| ts.PropertyAssignment
|
|
@@ -30,10 +32,23 @@ export const transformActionsToActionsSlot = (
|
|
|
30
32
|
|
|
31
33
|
if (primaryAction) {
|
|
32
34
|
const actionValue = primaryAction.initializer as ts.ObjectLiteralExpression
|
|
35
|
+
|
|
36
|
+
// Check if icon prop already exists
|
|
37
|
+
const hasExistingIcon = actionValue.properties.some(
|
|
38
|
+
(prop) => prop?.name?.getText() === 'icon',
|
|
39
|
+
)
|
|
40
|
+
|
|
33
41
|
const transformedComponent = transformV1ButtonPropsToButtonOrLinkButton(
|
|
34
42
|
actionValue,
|
|
35
43
|
'secondary',
|
|
44
|
+
hasActionButtonArrow,
|
|
36
45
|
)
|
|
46
|
+
|
|
47
|
+
// Track if arrow icon was actually added (only if hasActionButtonArrow is true and no existing icon)
|
|
48
|
+
if (hasActionButtonArrow && !hasExistingIcon) {
|
|
49
|
+
arrowIconWasAdded = true
|
|
50
|
+
}
|
|
51
|
+
|
|
37
52
|
primaryButton = transformedComponent.component
|
|
38
53
|
newImports.push(transformedComponent.import)
|
|
39
54
|
}
|
|
@@ -61,6 +76,11 @@ export const transformActionsToActionsSlot = (
|
|
|
61
76
|
),
|
|
62
77
|
)
|
|
63
78
|
|
|
79
|
+
// Add Icon import if arrow icon was added
|
|
80
|
+
if (arrowIconWasAdded) {
|
|
81
|
+
newImports.push('Icon')
|
|
82
|
+
}
|
|
83
|
+
|
|
64
84
|
return {
|
|
65
85
|
actionsSlotAttr: newActionsSlotAttr,
|
|
66
86
|
importsToAdd: newImports.filter(Boolean) as string[],
|
|
@@ -4,8 +4,7 @@ exports[`runV1Codemods > MockComponentDir Snapshot Tests > should transform Mock
|
|
|
4
4
|
{
|
|
5
5
|
"MockComponent.tsx": "// @ts-nocheck this is a mock file - we can ignore this
|
|
6
6
|
import React from 'react';
|
|
7
|
-
import { BrandMoment, Card, GlobalNotification, GuidanceBlock, Informative, ProgressBar, Well, LinkButton } from '@kaizen/components';
|
|
8
|
-
import { Button } from "@kaizen/components/next";
|
|
7
|
+
import { BrandMoment, Card, GlobalNotification, GuidanceBlock, Informative, ProgressBar, Well, Button, LinkButton, Icon } from '@kaizen/components';
|
|
9
8
|
import { MockSubcomponent } from './subcomponents/MockSubcomponent';
|
|
10
9
|
|
|
11
10
|
export const MockComponent = (): JSX.Element => {
|
|
@@ -13,7 +12,7 @@ export const MockComponent = (): JSX.Element => {
|
|
|
13
12
|
<GuidanceBlock illustration={<Informative alt=""/>} text={{
|
|
14
13
|
title: 'This is the call to action title',
|
|
15
14
|
description: 'Mussum Ipsum, cacilds vidis litro abertis. Suco de cevadiss, é um leite divinis.',
|
|
16
|
-
}} actionsSlot={<><Button onPress={() => undefined} variant="secondary" size="large">Action!</Button><LinkButton href='/cancel' variant="tertiary" size="large">Cancel</LinkButton></>}/>
|
|
15
|
+
}} actionsSlot={<><Button onPress={() => undefined} variant="secondary" size="large" icon={<Icon name="arrow_forward" shouldMirrorInRTL isPresentational/>} iconPosition="end">Action!</Button><LinkButton href='/cancel' variant="tertiary" size="large">Cancel</LinkButton></>}/>
|
|
17
16
|
<BrandMoment variant="success">
|
|
18
17
|
<div>Success message</div>
|
|
19
18
|
</BrandMoment>
|
|
@@ -71,9 +71,8 @@ describe('runV1Codemods', () => {
|
|
|
71
71
|
|
|
72
72
|
expect(transformedFiles['MockComponent.tsx']).toContain('actionsSlot')
|
|
73
73
|
expect(transformedFiles['MockComponent.tsx']).not.toContain('actions={{')
|
|
74
|
-
expect(transformedFiles['MockComponent.tsx']).toContain(
|
|
75
|
-
|
|
76
|
-
)
|
|
74
|
+
expect(transformedFiles['MockComponent.tsx']).toContain('Button')
|
|
75
|
+
expect(transformedFiles['MockComponent.tsx']).toContain(`from '@kaizen/components'`)
|
|
77
76
|
|
|
78
77
|
expect(transformedFiles['subcomponents/MockSubcomponent.tsx']).toContain('onPress')
|
|
79
78
|
expect(transformedFiles['subcomponents/MockSubcomponent.tsx']).toContain(
|
|
@@ -64,9 +64,9 @@ export const transformButtonProp = (
|
|
|
64
64
|
return oldValue ? createStringProp('size', buttonSizeMap[oldValue]) : undefined
|
|
65
65
|
}
|
|
66
66
|
case 'primary':
|
|
67
|
-
return
|
|
67
|
+
return null
|
|
68
68
|
case 'secondary':
|
|
69
|
-
return
|
|
69
|
+
return null
|
|
70
70
|
case 'destructive':
|
|
71
71
|
return null
|
|
72
72
|
default:
|
|
@@ -84,11 +84,13 @@ export const transformV1ButtonPropsToButtonOrLinkButton = (
|
|
|
84
84
|
buttonProps: ts.ObjectLiteralExpression,
|
|
85
85
|
/** optional override for the variant type if needed, ie: primary or secondary actions*/
|
|
86
86
|
variantOverride?: string,
|
|
87
|
+
/** whether to add an arrow icon to the button */
|
|
88
|
+
addArrowIcon?: boolean,
|
|
87
89
|
): TransformButtonProp => {
|
|
88
90
|
let childrenValue: ts.JsxAttributeValue | undefined
|
|
89
91
|
let hasSizeProp = false
|
|
90
|
-
let hasVariant = false
|
|
91
92
|
let hasLinkAttr = false
|
|
93
|
+
let hasIconProp = false
|
|
92
94
|
|
|
93
95
|
const newProps = buttonProps.properties.reduce<ts.JsxAttributeLike[]>((acc, currentProp) => {
|
|
94
96
|
const propName = currentProp?.name?.getText()
|
|
@@ -119,14 +121,14 @@ export const transformV1ButtonPropsToButtonOrLinkButton = (
|
|
|
119
121
|
]
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
if (propName === 'primary' || propName === 'secondary' || variantOverride) {
|
|
123
|
-
hasVariant = true
|
|
124
|
-
}
|
|
125
|
-
|
|
126
124
|
if (propName === 'size') {
|
|
127
125
|
hasSizeProp = true
|
|
128
126
|
}
|
|
129
127
|
|
|
128
|
+
if (propName === 'icon') {
|
|
129
|
+
hasIconProp = true
|
|
130
|
+
}
|
|
131
|
+
|
|
130
132
|
if (propName === 'href') {
|
|
131
133
|
hasLinkAttr = true
|
|
132
134
|
if (propValue && propValue?.kind !== ts.SyntaxKind.StringLiteral) {
|
|
@@ -172,18 +174,46 @@ export const transformV1ButtonPropsToButtonOrLinkButton = (
|
|
|
172
174
|
return acc
|
|
173
175
|
}, [])
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (variantOverride) {
|
|
180
|
-
newProps.push(createStringProp('variant', variantOverride))
|
|
181
|
-
}
|
|
177
|
+
// Always add variant from variantOverride, or default to 'secondary'
|
|
178
|
+
newProps.push(createStringProp('variant', variantOverride ?? 'secondary'))
|
|
182
179
|
|
|
183
180
|
if (!hasSizeProp) {
|
|
184
181
|
newProps.push(createStringProp('size', 'large'))
|
|
185
182
|
}
|
|
186
183
|
|
|
184
|
+
// Only add arrow icon if addArrowIcon is true AND there's no existing icon prop
|
|
185
|
+
if (addArrowIcon && !hasIconProp) {
|
|
186
|
+
const iconProp = ts.factory.createJsxAttribute(
|
|
187
|
+
ts.factory.createIdentifier('icon'),
|
|
188
|
+
ts.factory.createJsxExpression(
|
|
189
|
+
undefined,
|
|
190
|
+
ts.factory.createJsxSelfClosingElement(
|
|
191
|
+
ts.factory.createIdentifier('Icon'),
|
|
192
|
+
undefined,
|
|
193
|
+
ts.factory.createJsxAttributes([
|
|
194
|
+
ts.factory.createJsxAttribute(
|
|
195
|
+
ts.factory.createIdentifier('name'),
|
|
196
|
+
ts.factory.createStringLiteral('arrow_forward'),
|
|
197
|
+
),
|
|
198
|
+
ts.factory.createJsxAttribute(
|
|
199
|
+
ts.factory.createIdentifier('shouldMirrorInRTL'),
|
|
200
|
+
undefined,
|
|
201
|
+
),
|
|
202
|
+
ts.factory.createJsxAttribute(
|
|
203
|
+
ts.factory.createIdentifier('isPresentational'),
|
|
204
|
+
undefined,
|
|
205
|
+
),
|
|
206
|
+
]),
|
|
207
|
+
),
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
const iconPositionProp = ts.factory.createJsxAttribute(
|
|
211
|
+
ts.factory.createIdentifier('iconPosition'),
|
|
212
|
+
ts.factory.createStringLiteral('end'),
|
|
213
|
+
)
|
|
214
|
+
newProps.push(iconProp, iconPositionProp)
|
|
215
|
+
}
|
|
216
|
+
|
|
187
217
|
return {
|
|
188
218
|
import: hasLinkAttr ? 'LinkButton' : 'Button',
|
|
189
219
|
component: createJsxElementWithChildren(
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var Menu$1 = require('./Menu.cjs');
|
|
4
|
-
|
|
4
|
+
require('tslib');
|
|
5
|
+
require('react');
|
|
6
|
+
require('classnames');
|
|
7
|
+
require('../Heading/Heading.cjs');
|
|
5
8
|
var MenuItem$1 = require('./subcomponents/MenuItem/MenuItem.cjs');
|
|
6
9
|
var MenuList$1 = require('./subcomponents/MenuList/MenuList.cjs');
|
|
7
10
|
require('./subcomponents/StatelessMenu/StatelessMenu.cjs');
|
|
8
11
|
|
|
9
12
|
// Since we can't add a deprecation flag on a * export
|
|
10
13
|
var Menu = Menu$1.Menu;
|
|
11
|
-
var MenuHeading = MenuHeading$1.MenuHeading;
|
|
12
14
|
var MenuItem = MenuItem$1.MenuItem;
|
|
13
15
|
var MenuList = MenuList$1.MenuList;
|
|
14
16
|
exports.Menu = Menu;
|
|
15
|
-
exports.MenuHeading = MenuHeading;
|
|
16
17
|
exports.MenuItem = MenuItem;
|
|
17
18
|
exports.MenuList = MenuList;
|