@kaizen/components 0.0.0-canary-04-titleblock-logic-20251211225600 → 0.0.0-canary-guidance-block-codemod-20251212045145
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 +2 -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 +40 -0
- package/dist/cjs/src/MenuV1/index.cjs +3 -4
- package/dist/cjs/src/MenuV1/subcomponents/MenuHeading/MenuHeading.cjs +27 -0
- package/dist/cjs/src/MenuV1/subcomponents/MenuHeading/MenuHeading.module.scss.cjs +6 -0
- package/dist/cjs/src/TitleBlock/TitleBlock.cjs +36 -32
- package/dist/cjs/src/TitleBlock/TitleBlock.module.scss.cjs +1 -5
- package/dist/cjs/src/TitleBlock/subcomponents/MainActions.cjs +45 -90
- package/dist/cjs/src/TitleBlock/subcomponents/MainActions.module.scss.cjs +1 -3
- package/dist/cjs/src/TitleBlock/subcomponents/MobileActions.cjs +306 -0
- package/dist/cjs/src/TitleBlock/subcomponents/MobileActions.module.scss.cjs +16 -0
- package/dist/cjs/src/TitleBlock/subcomponents/SecondaryActions.cjs +14 -60
- package/dist/esm/src/MenuV1/index.mjs +3 -5
- package/dist/esm/src/MenuV1/subcomponents/MenuHeading/MenuHeading.mjs +21 -0
- package/dist/esm/src/MenuV1/subcomponents/MenuHeading/MenuHeading.module.scss.mjs +4 -0
- package/dist/esm/src/TitleBlock/TitleBlock.mjs +37 -33
- package/dist/esm/src/TitleBlock/TitleBlock.module.scss.mjs +1 -5
- package/dist/esm/src/TitleBlock/subcomponents/MainActions.mjs +47 -92
- package/dist/esm/src/TitleBlock/subcomponents/MainActions.module.scss.mjs +1 -3
- package/dist/esm/src/TitleBlock/subcomponents/MobileActions.mjs +300 -0
- package/dist/esm/src/TitleBlock/subcomponents/MobileActions.module.scss.mjs +14 -0
- package/dist/esm/src/TitleBlock/subcomponents/SecondaryActions.mjs +14 -60
- package/dist/styles.css +206 -82
- package/dist/types/TitleBlock/TitleBlock.d.ts +1 -1
- package/dist/types/TitleBlock/subcomponents/MainActions.d.ts +3 -4
- package/dist/types/TitleBlock/subcomponents/MobileActions.d.ts +14 -0
- package/package.json +1 -1
- package/src/TitleBlock/TitleBlock.module.scss +14 -55
- package/src/TitleBlock/TitleBlock.spec.tsx +461 -33
- package/src/TitleBlock/TitleBlock.tsx +24 -7
- package/src/TitleBlock/_docs/TitleBlock.stories.tsx +5 -25
- package/src/TitleBlock/_mixins.scss +0 -6
- package/src/TitleBlock/subcomponents/MainActions.module.scss +2 -28
- package/src/TitleBlock/subcomponents/MainActions.tsx +70 -127
- package/src/TitleBlock/subcomponents/MobileActions.module.scss +208 -0
- package/src/TitleBlock/subcomponents/MobileActions.spec.tsx +210 -0
- package/src/TitleBlock/subcomponents/MobileActions.tsx +472 -0
- package/src/TitleBlock/subcomponents/SecondaryActions.tsx +45 -114
- package/src/TitleBlock/subcomponents/Toolbar.tsx +0 -1
|
@@ -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
|
|
|
@@ -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(
|
|
@@ -84,11 +84,14 @@ 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
92
|
let hasVariant = false
|
|
91
93
|
let hasLinkAttr = false
|
|
94
|
+
let hasIconProp = false
|
|
92
95
|
|
|
93
96
|
const newProps = buttonProps.properties.reduce<ts.JsxAttributeLike[]>((acc, currentProp) => {
|
|
94
97
|
const propName = currentProp?.name?.getText()
|
|
@@ -127,6 +130,10 @@ export const transformV1ButtonPropsToButtonOrLinkButton = (
|
|
|
127
130
|
hasSizeProp = true
|
|
128
131
|
}
|
|
129
132
|
|
|
133
|
+
if (propName === 'icon') {
|
|
134
|
+
hasIconProp = true
|
|
135
|
+
}
|
|
136
|
+
|
|
130
137
|
if (propName === 'href') {
|
|
131
138
|
hasLinkAttr = true
|
|
132
139
|
if (propValue && propValue?.kind !== ts.SyntaxKind.StringLiteral) {
|
|
@@ -184,6 +191,39 @@ export const transformV1ButtonPropsToButtonOrLinkButton = (
|
|
|
184
191
|
newProps.push(createStringProp('size', 'large'))
|
|
185
192
|
}
|
|
186
193
|
|
|
194
|
+
// Only add arrow icon if addArrowIcon is true AND there's no existing icon prop
|
|
195
|
+
if (addArrowIcon && !hasIconProp) {
|
|
196
|
+
const iconProp = ts.factory.createJsxAttribute(
|
|
197
|
+
ts.factory.createIdentifier('icon'),
|
|
198
|
+
ts.factory.createJsxExpression(
|
|
199
|
+
undefined,
|
|
200
|
+
ts.factory.createJsxSelfClosingElement(
|
|
201
|
+
ts.factory.createIdentifier('Icon'),
|
|
202
|
+
undefined,
|
|
203
|
+
ts.factory.createJsxAttributes([
|
|
204
|
+
ts.factory.createJsxAttribute(
|
|
205
|
+
ts.factory.createIdentifier('name'),
|
|
206
|
+
ts.factory.createStringLiteral('arrow_forward'),
|
|
207
|
+
),
|
|
208
|
+
ts.factory.createJsxAttribute(
|
|
209
|
+
ts.factory.createIdentifier('shouldMirrorInRTL'),
|
|
210
|
+
undefined,
|
|
211
|
+
),
|
|
212
|
+
ts.factory.createJsxAttribute(
|
|
213
|
+
ts.factory.createIdentifier('isPresentational'),
|
|
214
|
+
undefined,
|
|
215
|
+
),
|
|
216
|
+
]),
|
|
217
|
+
),
|
|
218
|
+
),
|
|
219
|
+
)
|
|
220
|
+
const iconPositionProp = ts.factory.createJsxAttribute(
|
|
221
|
+
ts.factory.createIdentifier('iconPosition'),
|
|
222
|
+
ts.factory.createStringLiteral('end'),
|
|
223
|
+
)
|
|
224
|
+
newProps.push(iconProp, iconPositionProp)
|
|
225
|
+
}
|
|
226
|
+
|
|
187
227
|
return {
|
|
188
228
|
import: hasLinkAttr ? 'LinkButton' : 'Button',
|
|
189
229
|
component: createJsxElementWithChildren(
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var Menu$1 = require('./Menu.cjs');
|
|
4
|
-
require('
|
|
5
|
-
require('react');
|
|
6
|
-
require('classnames');
|
|
7
|
-
require('../Heading/Heading.cjs');
|
|
4
|
+
var MenuHeading$1 = require('./subcomponents/MenuHeading/MenuHeading.cjs');
|
|
8
5
|
var MenuItem$1 = require('./subcomponents/MenuItem/MenuItem.cjs');
|
|
9
6
|
var MenuList$1 = require('./subcomponents/MenuList/MenuList.cjs');
|
|
10
7
|
require('./subcomponents/StatelessMenu/StatelessMenu.cjs');
|
|
11
8
|
|
|
12
9
|
// Since we can't add a deprecation flag on a * export
|
|
13
10
|
var Menu = Menu$1.Menu;
|
|
11
|
+
var MenuHeading = MenuHeading$1.MenuHeading;
|
|
14
12
|
var MenuItem = MenuItem$1.MenuItem;
|
|
15
13
|
var MenuList = MenuList$1.MenuList;
|
|
16
14
|
exports.Menu = Menu;
|
|
15
|
+
exports.MenuHeading = MenuHeading;
|
|
17
16
|
exports.MenuItem = MenuItem;
|
|
18
17
|
exports.MenuList = MenuList;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var classnames = require('classnames');
|
|
6
|
+
var Heading = require('../../../Heading/Heading.cjs');
|
|
7
|
+
var MenuHeading_module = require('./MenuHeading.module.scss.cjs');
|
|
8
|
+
function _interopDefault(e) {
|
|
9
|
+
return e && e.__esModule ? e : {
|
|
10
|
+
default: e
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
|
+
var classnames__default = /*#__PURE__*/_interopDefault(classnames);
|
|
15
|
+
var MenuHeading = function (_a) {
|
|
16
|
+
var id = _a.id,
|
|
17
|
+
classNameOverride = _a.classNameOverride,
|
|
18
|
+
restProps = tslib.__rest(_a, ["id", "classNameOverride"]);
|
|
19
|
+
return React__default.default.createElement(Heading.Heading, tslib.__assign({
|
|
20
|
+
id: id,
|
|
21
|
+
variant: "heading-6",
|
|
22
|
+
tag: "span",
|
|
23
|
+
classNameOverride: classnames__default.default(MenuHeading_module.heading, classNameOverride)
|
|
24
|
+
}, restProps));
|
|
25
|
+
};
|
|
26
|
+
MenuHeading.displayName = 'MenuHeading';
|
|
27
|
+
exports.MenuHeading = MenuHeading;
|