Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions packages/design-system-react-native/MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This guide provides detailed instructions for migrating your project from one ve

## Table of Contents

- [From version 0.29.0 to 0.30.0](#from-version-0290-to-0300)
- [From version 0.28.0 to 0.29.0](#from-version-0280-to-0290)
- [From version 0.27.0 to 0.28.0](#from-version-0270-to-0280)
- [From Mobile Component Library](#from-mobile-component-library)
Expand Down Expand Up @@ -61,6 +62,47 @@ This guide provides detailed instructions for migrating your project from one ve

## Version Updates

### From version 0.29.0 to 0.30.0

#### `Content` shell accessories removed; row accessories moved to `ListItem`

`Content` is now inner-only (avatar, title/description, value/subvalue, and inline text accessories). Row shell accessories (`startAccessory`, `endAccessory`) live on `ListItem`. Column shell accessories (`topAccessory`, `bottomAccessory`) are removed — compose them manually with `BoxColumn`.

**What changed:**

- `startAccessory` / `endAccessory` removed from `ContentPropsShared` → use `ListItem` instead
- `topAccessory` / `bottomAccessory` removed from `ContentPropsShared` → wrap with `BoxColumn` instead

**Migration:**

`startAccessory` / `endAccessory` — moved to `ListItem`:

```tsx
// Before (0.29.0)
<Content startAccessory={<Icon name={IconName.Token} />} title="Label" />

// After (0.30.0)
<ListItem startAccessory={<Icon name={IconName.Token} />} title="Label" />
```

`topAccessory` / `bottomAccessory` — removed; compose manually:

```tsx
// Before (0.29.0)
<ListItem topAccessory={<BannerAlert />} title="Token" value="100" />

// After (0.30.0)
<BoxColumn topAccessory={<BannerAlert />}>
<ListItem title="Token" value="100" />
</BoxColumn>
```

**Impact:**

- Any call site passing `startAccessory` or `endAccessory` on `Content` must move those props to `ListItem`.
- Any call site using `topAccessory` or `bottomAccessory` on `Content` or `ListItem` must wrap the row in `BoxColumn` (or an equivalent layout) instead.
- Legacy `Content` shell rows used 16px spacing (`gap={4}`) between accessories and inner content. `ListItem` defaults to `accessoryGap={0}`; pass `accessoryGap={4}` to restore the previous spacing.

### From version 0.28.0 to 0.29.0

#### Severity vocabulary: `Error` renamed to `Danger` across `AvatarIconSeverity`, `IconAlertSeverity`, and `TagSeverity`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const meta: Meta<ListItemProps> = {
value: { control: 'text' },
subvalue: { control: 'text' },
isInteractive: { control: 'boolean' },
accessoryGap: {
control: 'select',
options: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
},
},
};

Expand Down Expand Up @@ -70,6 +74,7 @@ export const StartAccessory: Story = {
<ListItem
{...args}
startAccessory={<Icon name={IconName.Coin} />}
accessoryGap={4}
title="With start accessory"
description={undefined}
value={undefined}
Expand All @@ -82,13 +87,37 @@ export const EndAccessory: Story = {
<ListItem
{...args}
endAccessory={<Icon name={IconName.ArrowRight} />}
accessoryGap={4}
title="With end accessory"
description={undefined}
value={undefined}
/>
),
};

export const AccessoryGap: Story = {
render: (args: ListItemProps) => (
<>
<ListItem
{...args}
startAccessory={<Icon name={IconName.Coin} />}
accessoryGap={0}
title="accessoryGap={0}"
description={undefined}
value={undefined}
/>
<ListItem
{...args}
startAccessory={<Icon name={IconName.Coin} />}
accessoryGap={4}
title="accessoryGap={4}"
description={undefined}
value={undefined}
/>
</>
),
};

export const Avatar: Story = {
render: (args: ListItemProps) => (
<ListItem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,5 +281,18 @@ describe('ListItem', () => {
expect(getByTestId('start-accessory')).toBeOnTheScreen();
expect(getByTestId('avatar-slot')).toBeOnTheScreen();
});

it('renders endAccessory with avatar on the content row', () => {
const { getByTestId } = render(
<ListItem
title="Label"
endAccessory={<Text testID="end-accessory">E</Text>}
avatar={<Text testID="avatar-slot">A</Text>}
/>,
);

expect(getByTestId('end-accessory')).toBeOnTheScreen();
expect(getByTestId('avatar-slot')).toBeOnTheScreen();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const ListItem: React.FC<ListItemProps> = ({
style,
startAccessory,
endAccessory,
accessoryGap = 0,
verticalAlignment,
avatar,
title,
Expand Down Expand Up @@ -102,7 +103,7 @@ export const ListItem: React.FC<ListItemProps> = ({
startAccessory={startAccessory}
endAccessory={endAccessory}
alignItems={rowAlignment}
gap={0}
gap={accessoryGap}
twClassName="min-h-[46px] w-full"
>
{content}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,22 @@ import { Icon, IconName, ListItem } from '@metamask/design-system-react-native';
<ListItem title="Network" endAccessory={<Icon name={IconName.ArrowRight} />} />;
```

### `accessoryGap`

Gap between `startAccessory` / `endAccessory` and the inner content row. Uses the same spacing scale as `Box` `gap` (`BoxSpacing`); `4` is 16px. Defaults to `0` for tight layouts. Use `accessoryGap={4}` to match the spacing legacy `Content` shell rows used before accessories moved to `ListItem`.

| TYPE | REQUIRED | DEFAULT |
| ------------ | -------- | ------- |
| `BoxSpacing` | No | `0` |

```tsx
<ListItem
startAccessory={<Icon name={IconName.Coin} />}
accessoryGap={4}
title="With spaced start accessory"
/>
```

### `verticalAlignment`

Vertical alignment of the content row.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { ReactNode } from 'react';

import type { BoxSpacing } from '../Box';

/**
* ListItem shared props (ADR-0004).
*/
Expand All @@ -20,4 +22,11 @@ export type ListItemPropsShared = {
* Optional node rendered after the content row (e.g. chevron), after `Content`.
*/
endAccessory?: ReactNode;
/**
* Gap between `startAccessory` / `endAccessory` and the inner `Content` row.
* Uses design-system spacing tokens (`BoxSpacing`); `4` is 16px.
*
* @default 0
*/
accessoryGap?: BoxSpacing;
};
Loading