Skip to content

Commit 44b78bf

Browse files
committed
Allow setting an icon to the Chip component
- Add icon prop to set an icon at the left of the Chip component. - Add __icon pseudo-prop to style the passed icon from theme's config.
1 parent 9a3cffe commit 44b78bf

File tree

8 files changed

+51
-18
lines changed

8 files changed

+51
-18
lines changed

Diff for: src/components/main/Button/index.tsx

+5-13
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
1-
import React, { ReactElement } from 'react';
1+
import React from 'react';
22
import Pressable from '../Pressable';
33
import { HStack } from '../Stack';
44
import Text from '../Text';
55
import { useButtonPropsResolver } from './hooks';
6-
import type { IButtonIconProps, IButtonProps } from './types';
7-
8-
const cloneIconWithProps = (
9-
element: ReactElement<IButtonIconProps> | undefined,
10-
props: IButtonIconProps
11-
) => (
12-
element && React.isValidElement( element )
13-
? React.cloneElement( element, { ...props, ...element.props } )
14-
: null
15-
);
6+
import type { IButtonProps } from './types';
7+
import cloneElement from '../../utils/cloneElement';
168

179
const Button = ( {
1810
children,
@@ -28,8 +20,8 @@ const Button = ( {
2820
rightIconProps
2921
} = useButtonPropsResolver( props );
3022

31-
const leftIcon = cloneIconWithProps( leftIconProp, leftIconProps || {} );
32-
const rightIcon = cloneIconWithProps( rightIconProp, rightIconProps || {} );
23+
const leftIcon = cloneElement( leftIconProp, leftIconProps || {} );
24+
const rightIcon = cloneElement( rightIconProp, rightIconProps || {} );
3325

3426
return (
3527
<Pressable

Diff for: src/components/main/Chip/hooks.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const useChipPropsResolver = ( props: Omit<IChipProps, 'label'> ) => {
2020
const {
2121
__stack: stackProps,
2222
__label: labelProps,
23+
__icon: iconProps,
2324
...containerProps
2425
} = useComponentPropsResolver( 'Chip', props, state ) as IChipProps;
2526

@@ -33,6 +34,7 @@ export const useChipPropsResolver = ( props: Omit<IChipProps, 'label'> ) => {
3334
return {
3435
containerProps,
3536
stackProps,
36-
labelProps
37+
labelProps,
38+
iconProps
3739
};
3840
};

Diff for: src/components/main/Chip/index.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,31 @@ import { HStack } from '../Stack';
55
import Text from '../Text';
66
import { useChipPropsResolver } from './hooks';
77
import type { IChipProps } from './types';
8+
import cloneElement from '../../utils/cloneElement';
89

910
const Chip = ( {
10-
label, testID, ...props
11+
label,
12+
testID,
13+
icon: iconProp,
14+
...props
1115
}: IChipProps, ref?: React.Ref<View> ) => {
1216
const {
1317
containerProps,
1418
stackProps,
15-
labelProps
19+
labelProps,
20+
iconProps
1621
} = useChipPropsResolver( props );
1722

23+
const icon = cloneElement( iconProp, iconProps || {} );
24+
1825
return (
1926
<Pressable
2027
{...containerProps}
2128
testID={testID}
2229
ref={ref}
2330
>
2431
<HStack {...stackProps}>
32+
<>{icon}</>
2533
<Text
2634
{...labelProps}
2735
testID={testID ? `${testID}-label` : undefined}

Diff for: src/components/main/Chip/types.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import type { ReactElement } from 'react';
12
import type { ComponentStyledProps } from 'src/core/components/types';
3+
import type { IIconProps } from '../Icon/types';
24
import type { IPressableProps } from '../Pressable/types';
35

46
export interface IChipProps extends Omit<IPressableProps, 'children' | 'variant' | 'size'>,
57
ComponentStyledProps<'Chip'>
68
{
79
label: string,
8-
selected?: boolean
10+
selected?: boolean,
11+
icon?: ReactElement<IIconProps>,
912
}

Diff for: src/components/utils/cloneElement.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React, { ReactElement } from 'react';
2+
3+
const cloneElement = <PropsType extends Partial<PropsType> & React.Attributes>(
4+
element: ReactElement<PropsType> | undefined,
5+
props: PropsType
6+
) => (
7+
element && React.isValidElement( element )
8+
? React.cloneElement( element, { ...props, ...element.props } )
9+
: null
10+
);
11+
12+
export default cloneElement;

Diff for: src/core/components/types/pseudoProps.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ interface ITextInputPseudoProps {
5858
// CHIP pseudoprops
5959
interface IChipPseudoProps {
6060
__stack: ComponentBaseStyledProps<'Stack'>,
61-
__label: ComponentBaseStyledProps<'Text'>
61+
__label: ComponentBaseStyledProps<'Text'>,
62+
__icon: ComponentBaseStyledProps<'Icon'>
6263
}
6364

6465
// Pseudoprops config for all components

Diff for: src/core/theme/defaultTheme/components/Chip.ts

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export default {
1212
color: 'primary.900',
1313
variant: 'small-bold'
1414
},
15+
__icon: {
16+
size: 'xs',
17+
marginRight: '2'
18+
},
1519
__disabled: {
1620
backgroundColor: 'primary.50',
1721
__label: {

Diff for: tests/components/main/Chip.test.js

+11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import React from 'react';
22
import { render } from '@testing-library/react-native';
33
import WithThemeProvider from '../../support/withThemeProvider';
4+
import FakeBaseIcon from '../../support/FakeBaseIcon';
45

6+
import Icon from '../../../src/components/main/Icon';
57
import Chip from '../../../src/components/main/Chip';
68

79
const { itBehavesLike } = require( '../../support/sharedExamples' );
810

11+
const TestIcon = () => (
12+
<Icon name="test" testID="test-icon" as={FakeBaseIcon} />
13+
);
14+
915
describe( 'Chip', () => {
1016
const label = 'Label';
1117

@@ -24,6 +30,11 @@ describe( 'Chip', () => {
2430
expect( getByTestId( 'test-chip' ) ).toHaveStyle( { borderColor: '#01164D' } );
2531
} );
2632

33+
it( 'shows an icon when it\'s set', () => {
34+
const { queryByTestId } = renderChip( { label, icon: <TestIcon /> } );
35+
expect( queryByTestId( 'test-icon' ) ).not.toBeUndefined();
36+
} );
37+
2738
itBehavesLike(
2839
'aStyledSystemComponent',
2940
{

0 commit comments

Comments
 (0)