@kaizen/components 2.2.3 → 2.2.4

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.
@@ -15,9 +15,10 @@ const transformGuidanceBlock = (sourceFile: TransformSourceArgs['sourceFile']):
15
15
  })
16
16
  }
17
17
 
18
- describe('transformActionsToButtonNext()', () => {
19
- it('imports Button from the /next path and transforms all button-like actions prop into a Button component', () => {
20
- const inputAst = parseJsx(`
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
- const outputAst = parseJsx(`
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
- expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
49
- })
50
- it('imports and transforms all button-like and link-like actions prop into a Button and LinkButton', () => {
51
- const inputAst = parseJsx(`
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
- const outputAst = parseJsx(`
69
- import { GuidanceBlock, LinkButton } from "@kaizen/components"
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
- expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
80
- })
81
- it('does not redeclare imports if found', () => {
82
- const inputAst = parseJsx(`
83
- import { GuidanceBlock } from "@kaizen/components"
84
- import { Button } from "@kaizen/components/next"
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
- const outputAst = parseJsx(`
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
- expect(transformGuidanceBlock(inputAst)).toBe(printAst(outputAst))
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/next'
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
 
@@ -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
- 'import { Button } from "@kaizen/components/next"',
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 createStringProp('variant', 'primary')
67
+ return null
68
68
  case 'secondary':
69
- return createStringProp('variant', 'tertiary')
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
- if (!hasVariant) {
176
- newProps.push(createStringProp('variant', 'secondary'))
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(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaizen/components",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "Kaizen component library",
5
5
  "author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
6
6
  "homepage": "https://cultureamp.design",