Skip to content

Commit 185d598

Browse files
fix: dsr avatar linting violations (#674)
## **Description** This PR improves the Avatar components in the design-system-react package by removing ESLint ignores and fixing TypeScript type issues. 1. What is the reason for the change? - Several Avatar components were being ignored by ESLint checks - Components were using type assertions (`as any`) which can hide potential errors - Some components were using less optimal React imports 2. What is the improvement/solution? - Removed ESLint ignores for Avatar components - Properly typed `imageProps` to include `data-testid` property - Changed `React.forwardRef` to destructured `{ forwardRef }` from React - Fixed string concatenation in error messages - Added missing default case in AvatarGroupStory component - Fixed TailwindCSS class ordering ## **Related issues** Part of: #657 ## **Manual testing steps** 1. Run the storybook for design-system-react 2. Verify all Avatar components render properly 3. Verify tests pass for all Avatar components ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.
1 parent 8a2f400 commit 185d598

File tree

12 files changed

+60
-44
lines changed

12 files changed

+60
-44
lines changed

eslint.config.mjs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,8 @@ const config = createConfig([
2222
// design system react
2323
'packages/design-system-react/src/components/Icon/icons/*.tsx',
2424
'packages/design-system-react/src/components/Icon/icons/index.ts',
25-
'packages/design-system-react/src/components/AvatarFavicon/AvatarFavicon.test.tsx',
26-
'packages/design-system-react/src/components/AvatarGroup/AvatarGroup.stories.tsx',
27-
'packages/design-system-react/src/components/AvatarGroup/AvatarGroup.test.tsx',
28-
'packages/design-system-react/src/components/AvatarGroup/AvatarGroup.tsx',
29-
'packages/design-system-react/src/components/AvatarNetwork/AvatarNetwork.test.tsx',
30-
'packages/design-system-react/src/components/AvatarToken/AvatarToken.test.tsx',
25+
'packages/design-system-react/src/components/BadgeNetwork/BadgeNetwork.test.tsx',
26+
'packages/design-system-react/src/components/BadgeWrapper/BadgeWrapper.test.tsx',
3127
'packages/design-system-react/src/components/temp-components/Jazzicon/Jazzicon.test.tsx',
3228
'packages/design-system-react/src/components/temp-components/Jazzicon/Jazzicon.tsx',
3329
'packages/design-system-react/src/components/temp-components/Maskicon/Maskicon.test.tsx',

packages/design-system-react/src/components/AvatarFavicon/AvatarFavicon.test.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TWCLASSMAP_AVATARBASE_SIZE_BORDER,
88
TWCLASSMAP_AVATARBASE_HASBORDER_SIZE_DIMENSION,
99
} from '../AvatarBase/AvatarBase.constants';
10+
1011
import { AvatarFavicon } from './AvatarFavicon';
1112

1213
describe('AvatarFavicon', () => {
@@ -65,7 +66,7 @@ describe('AvatarFavicon', () => {
6566
<AvatarFavicon
6667
name="ACME"
6768
src={src}
68-
imageProps={{ 'data-testid': 'img', id: 'img-id' } as any}
69+
imageProps={{ 'data-testid': 'img', id: 'img-id' }}
6970
/>,
7071
);
7172
const img = screen.getByTestId('img') as HTMLImageElement;
@@ -80,7 +81,7 @@ describe('AvatarFavicon', () => {
8081
<AvatarFavicon
8182
name=""
8283
src={src}
83-
imageProps={{ 'data-testid': 'img2' } as any}
84+
imageProps={{ 'data-testid': 'img2' }}
8485
/>,
8586
);
8687
expect(screen.getByTestId('img2')).toHaveAttribute('alt', 'Dapp logo');
@@ -103,7 +104,7 @@ describe('AvatarFavicon', () => {
103104
<AvatarFavicon
104105
name="Beta"
105106
src="bad.png"
106-
imageProps={{ 'data-testid': 'bad-img', onError } as any}
107+
imageProps={{ 'data-testid': 'bad-img', onError }}
107108
/>,
108109
);
109110
fireEvent.error(screen.getByTestId('bad-img'));
@@ -143,7 +144,7 @@ describe('AvatarFavicon', () => {
143144
render(
144145
<AvatarFavicon
145146
src={src}
146-
imageProps={{ 'data-testid': 'img-no-name' } as any}
147+
imageProps={{ 'data-testid': 'img-no-name' }}
147148
/>,
148149
);
149150
const img = screen.getByTestId('img-no-name') as HTMLImageElement;

packages/design-system-react/src/components/AvatarFavicon/AvatarFavicon.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ export type AvatarFaviconProps = Omit<
2121
* Optional prop to pass to the underlying img element
2222
* Useful for overriding the default alt text which is the dapp name
2323
*/
24-
imageProps?: ComponentProps<'img'>;
24+
imageProps?: ComponentProps<'img'> & {
25+
'data-testid'?: string;
26+
};
2527
};

packages/design-system-react/src/components/AvatarGroup/AvatarGroup.stories.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
22
import React from 'react';
33

44
import { AvatarGroupSize, AvatarGroupVariant } from '../../types';
5+
56
import { AvatarGroup } from './AvatarGroup';
67
import {
78
SAMPLE_AVATARGROUP_AVATARACCOUNTPROPSARR,
@@ -90,6 +91,14 @@ const AvatarGroupStory: React.FC<Omit<AvatarGroupProps, 'avatarPropsArr'>> = ({
9091
avatarPropsArr={SAMPLE_AVATARGROUP_AVATARTOKENPROPSARR}
9192
/>
9293
);
94+
default:
95+
return (
96+
<AvatarGroup
97+
{...props}
98+
variant={AvatarGroupVariant.Favicon}
99+
avatarPropsArr={SAMPLE_AVATARGROUP_AVATARFAVICONPROPSARR}
100+
/>
101+
);
93102
}
94103
};
95104

@@ -140,10 +149,7 @@ export const Size: Story = {
140149
render: () => (
141150
<div>
142151
{Object.keys(AvatarGroupSize).map((sizeKey) => (
143-
<div
144-
key={sizeKey}
145-
className="flex flex-col gap-1 mb-4"
146-
>
152+
<div key={sizeKey} className="mb-4 flex flex-col gap-1">
147153
<AvatarGroupStory
148154
variant={AvatarGroupVariant.Account}
149155
size={AvatarGroupSize[sizeKey as keyof typeof AvatarGroupSize]}
@@ -180,19 +186,19 @@ export const Max: Story = {
180186
export const IsReverse: Story = {
181187
render: () => (
182188
<div className="flex flex-col gap-4">
183-
<div className="flex flex-col gap-1 items-start">
189+
<div className="flex flex-col items-start gap-1">
184190
<AvatarGroupStory variant={AvatarGroupVariant.Account} />
185191
<AvatarGroupStory variant={AvatarGroupVariant.Account} isReverse />
186192
</div>
187-
<div className="flex flex-col gap-1 items-start">
193+
<div className="flex flex-col items-start gap-1">
188194
<AvatarGroupStory variant={AvatarGroupVariant.Favicon} />
189195
<AvatarGroupStory variant={AvatarGroupVariant.Favicon} isReverse />
190196
</div>
191-
<div className="flex flex-col gap-1 items-start">
197+
<div className="flex flex-col items-start gap-1">
192198
<AvatarGroupStory variant={AvatarGroupVariant.Network} />
193199
<AvatarGroupStory variant={AvatarGroupVariant.Network} isReverse />
194200
</div>
195-
<div className="flex flex-col gap-1 items-start">
201+
<div className="flex flex-col items-start gap-1">
196202
<AvatarGroupStory variant={AvatarGroupVariant.Token} />
197203
<AvatarGroupStory variant={AvatarGroupVariant.Token} isReverse />
198204
</div>

packages/design-system-react/src/components/AvatarGroup/AvatarGroup.test.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AvatarGroupVariant, AvatarGroupSize } from '../../types';
55
import { AvatarAccountVariant } from '../AvatarAccount';
66
import { TWCLASSMAP_AVATARBASE_SIZE_BORDERRADIUSS_SQUARE } from '../AvatarBase/AvatarBase.constants';
77
import { TextColor } from '../Text';
8+
89
import { AvatarGroup } from './AvatarGroup';
910
import { AVATAR_GROUP_SIZE_NEGATIVESPACEBETWEENAVATARS_MAP } from './AvatarGroup.constants';
1011

@@ -119,11 +120,12 @@ describe('AvatarGroup', () => {
119120
expect(() =>
120121
render(
121122
<AvatarGroup
122-
variant={'Invalid' as any}
123-
avatarPropsArr={[{ foo: 'bar' } as any]}
123+
variant={'Invalid' as unknown as AvatarGroupVariant}
124+
// @ts-expect-error - invalid variant
125+
avatarPropsArr={[{ foo: 'bar' }]}
124126
/>,
125127
),
126-
).toThrow(/Invalid Avatar Variant: Invalid/);
128+
).toThrow(/Invalid Avatar Variant: Invalid/u);
127129
});
128130
});
129131

packages/design-system-react/src/components/AvatarGroup/AvatarGroup.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,25 @@ import React, { forwardRef, useCallback } from 'react';
22

33
import { AvatarGroupSize, AvatarGroupVariant } from '../../types';
44
import { twMerge } from '../../utils/tw-merge';
5+
import type { AvatarAccountProps } from '../AvatarAccount';
6+
import { AvatarAccount } from '../AvatarAccount';
7+
import type { AvatarBaseSize } from '../AvatarBase';
58
import { AvatarBase } from '../AvatarBase';
6-
import { AvatarAccount, AvatarAccountProps } from '../AvatarAccount';
7-
import { AvatarBaseSize, AvatarBaseShape } from '../AvatarBase';
8-
import { AvatarFavicon, AvatarFaviconProps } from '../AvatarFavicon';
9-
import { AvatarNetwork, AvatarNetworkProps } from '../AvatarNetwork';
10-
import { AvatarToken, AvatarTokenProps } from '../AvatarToken';
9+
import { AvatarBaseShape } from '../AvatarBase';
10+
import type { AvatarFaviconProps } from '../AvatarFavicon';
11+
import { AvatarFavicon } from '../AvatarFavicon';
12+
import type { AvatarNetworkProps } from '../AvatarNetwork';
13+
import { AvatarNetwork } from '../AvatarNetwork';
14+
import type { AvatarTokenProps } from '../AvatarToken';
15+
import { AvatarToken } from '../AvatarToken';
1116
import { TextColor } from '../Text';
17+
1218
import {
1319
AVATAR_GROUP_SIZE_ISREVERSE_NEGATIVESPACEBETWEENAVATARS_MAP,
1420
AVATAR_GROUP_SIZE_NEGATIVESPACEBETWEENAVATARS_MAP,
1521
AVATAR_GROUP_SIZE_OVERFLOWTEXT_TEXTVARIANT_MAP,
1622
} from './AvatarGroup.constants';
17-
import { AvatarGroupProps } from './AvatarGroup.types';
23+
import type { AvatarGroupProps } from './AvatarGroup.types';
1824

1925
export const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
2026
(
@@ -118,7 +124,7 @@ export const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(
118124
);
119125
default:
120126
throw new Error(
121-
`Invalid Avatar Variant: ${variant}. Expected one of: ${Object.values(AvatarGroupVariant).join(', ')}`,
127+
`Invalid Avatar Variant: ${String(variant)}. Expected one of: ${Object.values(AvatarGroupVariant).join(', ')}`,
122128
);
123129
}
124130
}),

packages/design-system-react/src/components/AvatarGroup/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ Example:
496496
src: { uri: 'https://example.com/token3.png' },
497497
},
498498
]}
499-
className="my-4 mx-2"
499+
className="mx-2 my-4"
500500
/>
501501
```
502502

packages/design-system-react/src/components/AvatarNetwork/AvatarNetwork.test.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TWCLASSMAP_AVATARBASE_SIZE_BORDER,
88
TWCLASSMAP_AVATARBASE_HASBORDER_SIZE_DIMENSION,
99
} from '../AvatarBase/AvatarBase.constants';
10+
1011
import { AvatarNetwork } from './AvatarNetwork';
1112

1213
describe('AvatarNetwork', () => {
@@ -65,7 +66,7 @@ describe('AvatarNetwork', () => {
6566
<AvatarNetwork
6667
name="ACME"
6768
src={src}
68-
imageProps={{ 'data-testid': 'img', id: 'img-id' } as any}
69+
imageProps={{ 'data-testid': 'img', id: 'img-id' }}
6970
/>,
7071
);
7172
const img = screen.getByTestId('img') as HTMLImageElement;
@@ -80,7 +81,7 @@ describe('AvatarNetwork', () => {
8081
<AvatarNetwork
8182
name=""
8283
src={src}
83-
imageProps={{ 'data-testid': 'img2' } as any}
84+
imageProps={{ 'data-testid': 'img2' }}
8485
/>,
8586
);
8687
expect(screen.getByTestId('img2')).toHaveAttribute('alt', 'Network logo');
@@ -103,7 +104,7 @@ describe('AvatarNetwork', () => {
103104
<AvatarNetwork
104105
name="Beta"
105106
src="bad.png"
106-
imageProps={{ 'data-testid': 'bad-img', onError } as any}
107+
imageProps={{ 'data-testid': 'bad-img', onError }}
107108
/>,
108109
);
109110
fireEvent.error(screen.getByTestId('bad-img'));
@@ -143,7 +144,7 @@ describe('AvatarNetwork', () => {
143144
render(
144145
<AvatarNetwork
145146
src={src}
146-
imageProps={{ 'data-testid': 'img-no-name' } as any}
147+
imageProps={{ 'data-testid': 'img-no-name' }}
147148
/>,
148149
);
149150
const img = screen.getByTestId('img-no-name') as HTMLImageElement;

packages/design-system-react/src/components/AvatarNetwork/AvatarNetwork.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ export type AvatarNetworkProps = Omit<
2121
* Optional prop to pass to the underlying img element
2222
* Useful for overriding the default alt text which is the network name
2323
*/
24-
imageProps?: ComponentProps<'img'>;
24+
imageProps?: ComponentProps<'img'> & {
25+
'data-testid'?: string;
26+
};
2527
};

packages/design-system-react/src/components/AvatarToken/AvatarToken.test.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TWCLASSMAP_AVATARBASE_SIZE_BORDER,
88
TWCLASSMAP_AVATARBASE_HASBORDER_SIZE_DIMENSION,
99
} from '../AvatarBase/AvatarBase.constants';
10+
1011
import { AvatarToken } from './AvatarToken';
1112

1213
describe('AvatarToken', () => {
@@ -65,7 +66,7 @@ describe('AvatarToken', () => {
6566
<AvatarToken
6667
name="ACME"
6768
src={src}
68-
imageProps={{ 'data-testid': 'img', id: 'img-id' } as any}
69+
imageProps={{ 'data-testid': 'img', id: 'img-id' }}
6970
/>,
7071
);
7172
const img = screen.getByTestId('img') as HTMLImageElement;
@@ -80,7 +81,7 @@ describe('AvatarToken', () => {
8081
<AvatarToken
8182
name=""
8283
src={src}
83-
imageProps={{ 'data-testid': 'img2' } as any}
84+
imageProps={{ 'data-testid': 'img2' }}
8485
/>,
8586
);
8687
expect(screen.getByTestId('img2')).toHaveAttribute('alt', 'Token logo');
@@ -103,7 +104,7 @@ describe('AvatarToken', () => {
103104
<AvatarToken
104105
name="Beta"
105106
src="bad.png"
106-
imageProps={{ 'data-testid': 'bad-img', onError } as any}
107+
imageProps={{ 'data-testid': 'bad-img', onError }}
107108
/>,
108109
);
109110
fireEvent.error(screen.getByTestId('bad-img'));
@@ -141,10 +142,7 @@ describe('AvatarToken', () => {
141142

142143
it('uses default alt text when name prop is omitted', () => {
143144
render(
144-
<AvatarToken
145-
src={src}
146-
imageProps={{ 'data-testid': 'img-no-name' } as any}
147-
/>,
145+
<AvatarToken src={src} imageProps={{ 'data-testid': 'img-no-name' }} />,
148146
);
149147
const img = screen.getByTestId('img-no-name') as HTMLImageElement;
150148
expect(img.alt).toBe('Token logo');

packages/design-system-react/src/components/AvatarToken/AvatarToken.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,7 @@ export type AvatarTokenProps = Omit<
2121
* Optional prop to pass to the underlying img element
2222
* Useful for overriding the default alt text which is the token name
2323
*/
24-
imageProps?: ComponentProps<'img'>;
24+
imageProps?: ComponentProps<'img'> & {
25+
'data-testid'?: string;
26+
};
2527
};

packages/design-system-react/src/components/BadgeNetwork/README.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Example:
7878
name="Ethereum"
7979
src="path/to/ethereum-logo.png"
8080
fallbackText="E"
81-
className="my-4 mx-2"
81+
className="mx-2 my-4"
8282
/>
8383
```
8484

0 commit comments

Comments
 (0)