Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
00e72de
refactor(list): replace React.Children injection in List.Accordion wi…
matkoson Jun 18, 2026
0e91ea5
refactor(dialog): remove child composition injection
matkoson Jun 23, 2026
41ecff8
refactor(card): remove child composition injection
matkoson Jun 23, 2026
2d97fbc
refactor(toggle-button): style row buttons via context
matkoson Jun 23, 2026
012f27f
test: align composition tests with upstream utilities
matkoson Jun 29, 2026
426827f
fix: preserve dialog icon title spacing
matkoson Jun 29, 2026
d2f5f61
refactor(toggle-button): align segmented row to MD3 spec
matkoson Jun 30, 2026
414bc13
test(toggle-button): assert MD3 secondaryContainer selected fill in row
matkoson Jun 30, 2026
17199df
refactor(appbar): provide shared values via context
matkoson Jun 30, 2026
b3d0b92
revert(toggle-button): drop MD3 redesign, keep legacy visual identity
matkoson Jun 30, 2026
0d08f46
fix(toggle-button, dialog): address review feedback on composition re…
matkoson Jul 2, 2026
38fb0b4
fix(card, dialog, appbar): resolve remaining Copilot review findings
matkoson Jul 6, 2026
a33bb5b
Merge branch 'main' into refactor/react-children-takeover
adam-sajko Aug 28, 2026
526de9e
revert: drop Appbar from this PR
adam-sajko Aug 28, 2026
6e81c50
fix: preserve child keys in Card and Dialog action rows
adam-sajko Aug 25, 2026
3d070b5
test: stabilise the Tooltip pressOut timing
adam-sajko Aug 25, 2026
6b22e0b
docs: document Card, Dialog, List and ToggleButton.Row breaking changes
adam-sajko Aug 28, 2026
6d0b2dc
Merge branch 'main' into refactor/react-children-takeover
adam-sajko Sep 3, 2026
d377ebf
Merge remote-tracking branch 'upstream/main' into refactor/react-chil…
adam-sajko Sep 8, 2026
4ed52e3
refactor: apply review feedback to card, dialog, list and toggle button
adam-sajko Sep 9, 2026
ca3591e
Merge remote-tracking branch 'upstream/main' into refactor/react-chil…
adam-sajko Sep 9, 2026
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
74 changes: 74 additions & 0 deletions docs/6.x/docs/guides/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ e.g.:
- The default elevation changed from level `1` to level `3`.
- The `style` prop no longer configures the background color or border radius. You can override `theme.colors.surfaceContainerHigh` and `theme.shapes.corner.extraLarge` using the `theme` prop instead.

#### `Dialog.Actions`

`Dialog.Actions` no longer forces `compact` and `uppercase` on its buttons. Set them on the buttons if you want the old look.

```tsx
// Before (v5)
<Dialog.Actions>
<Button onPress={hide}>Done</Button>
</Dialog.Actions>

// After (v6)
<Dialog.Actions>
<Button compact uppercase onPress={hide}>
Done
</Button>
</Dialog.Actions>
```

### TextInput

The Paper 6.x `TextInput` is a complete rewrite with a new API. Import the component the same way, but note that the props and behavior have changed significantly.
Expand Down Expand Up @@ -308,3 +326,59 @@ const theme = {
style={{ fontSize: 16, color: '#1C1B1F' }}
/>
```

### Card

#### `Card.Actions`

`Card.Actions` no longer styles its buttons for you. It used to force `mode="outlined"` on the first button, `mode="contained"` on the rest, and `compact` on all of them. Set what you need on each button.

```tsx
// Before (v5)
<Card.Actions>
<Button>Cancel</Button>
<Button>Ok</Button>
</Card.Actions>

// After (v6)
<Card.Actions>
<Button mode="outlined">Cancel</Button>
<Button mode="contained">Ok</Button>
</Card.Actions>
```

#### `Card.Content`

`Card.Content` now has 16dp of padding on every side. It used to drop its top or bottom padding when it sat next to a `Card.Cover` or `Card.Title`, so cards that mix those sections grow a little taller. Pass `style` if you want the tighter spacing back.

### List

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No ### ToggleButton section, but ToggleButton.Row changes visibly - divider ownership moves to the row and alignSelf: 'flex-start' is new. Card, Dialog and List all got one.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch, done


#### `List.Accordion`

An accordion with a `left` element now indents only its `List.Item` children. Anything else you put inside keeps its own padding, so indent it yourself to line it up with the items.

```tsx
// Before (v5)
<List.Accordion title="Group" left={props => <List.Icon {...props} icon="folder" />}>
<View>
<Text>Custom row</Text>
</View>
</List.Accordion>

// After (v6)
<List.Accordion title="Group" left={props => <List.Icon {...props} icon="folder" />}>
<View style={{ paddingLeft: 40 }}>
<Text>Custom row</Text>
</View>
</List.Accordion>
```

`theme` set on `List.Accordion` no longer reaches its children either. Pass it to the child that needs the override.

### ToggleButton

#### `ToggleButton.Row`

`ToggleButton.Row` no longer reaches into its children to style them, so a `ToggleButton` you wrap in a component of your own now picks up the segmented look.

The row draws the dividers between buttons itself. A `borderWidth` or `borderColor` set on an individual `ToggleButton` no longer builds the segmented outline.
10 changes: 8 additions & 2 deletions example/src/Examples/CardExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,12 @@ const CardExample = () => {
<Card style={styles.card} mode={selectedMode}>
<Card.Cover source={require('../../assets/images/forest.jpg')} />
<Card.Actions>
<Button onPress={() => {}}>Share</Button>
<Button onPress={() => {}}>Explore</Button>
<Button mode="outlined" onPress={() => {}}>
Share
</Button>
<Button mode="contained" onPress={() => {}}>
Explore
</Button>
</Card.Actions>
</Card>
<Card style={styles.card} mode={selectedMode}>
Expand Down Expand Up @@ -104,12 +108,14 @@ const CardExample = () => {
<Card.Title title="Custom Button styles" />
<Card.Actions>
<Button
mode="outlined"
theme={{ shapes: { corner: { largeIncreased: 12 } } }}
onPress={() => {}}
>
Share
</Button>
<Button
mode="contained"
theme={{ shapes: { corner: { largeIncreased: 12 } } }}
onPress={() => {}}
>
Expand Down
16 changes: 12 additions & 4 deletions example/src/Examples/TeamDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ const News = () => {
</Text>
</Card.Content>
<Card.Actions>
<Button onPress={() => {}}>Share</Button>
<Button onPress={() => {}}>Read more</Button>
<Button mode="outlined" onPress={() => {}}>
Share
</Button>
<Button mode="contained" onPress={() => {}}>
Read more
</Button>
</Card.Actions>
</Card>
<Card style={styles.card} mode="contained">
Expand All @@ -110,8 +114,12 @@ const News = () => {
</Text>
</Card.Content>
<Card.Actions>
<Button onPress={() => {}}>Share</Button>
<Button onPress={() => {}}>Read more</Button>
<Button mode="outlined" onPress={() => {}}>
Share
</Button>
<Button mode="contained" onPress={() => {}}>
Read more
</Button>
</Card.Actions>
</Card>
</View>
Expand Down
26 changes: 5 additions & 21 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ export type Props = Omit<ViewProps, 'style'> & {
* </Card.Content>
* <Card.Cover source={{ uri: 'https://picsum.photos/700' }} />
* <Card.Actions>
* <Button>Cancel</Button>
* <Button>Ok</Button>
* <Button mode="outlined">Cancel</Button>
* <Button mode="contained">Ok</Button>
* </Card.Actions>
* </Card>
* );
Expand Down Expand Up @@ -182,15 +182,6 @@ const Card = ({
}
});

const total = React.Children.count(children);
const siblings = React.Children.map(children, (child) =>
React.isValidElement(child) && child.type
? typeof child.type !== 'string' && 'displayName' in child.type
? child.type.displayName
: null
: null
);

const { backgroundColor, borderColor: themedBorderColor } = getCardColors({
theme,
mode: cardMode,
Expand All @@ -204,16 +195,8 @@ const Card = ({
const borderRadius = theme.shapes.corner.medium;

const content = (
<View style={[styles.innerContainer, contentStyle]}>
{React.Children.map(children, (child, index) =>
React.isValidElement(child)
? React.cloneElement(child as React.ReactElement<any>, {
index,
total,
siblings,
})
: child
)}
<View style={[styles.innerContainer, { borderRadius }, contentStyle]}>
{children}
</View>
);

Expand Down Expand Up @@ -276,6 +259,7 @@ Card.Title = CardTitle;
const styles = StyleSheet.create({
innerContainer: {
flexShrink: 1,
overflow: 'hidden',
},
outline: {
borderWidth: 1,
Expand Down
27 changes: 4 additions & 23 deletions src/components/Card/CardActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';

import type { CardActionChildProps } from './utils';
import { useInternalTheme } from '../../core/theming';
import type { ThemeProp } from '../../theme/types';

Expand All @@ -26,8 +25,8 @@ export type Props = ViewProps & {
* const MyComponent = () => (
* <Card>
* <Card.Actions>
* <Button>Cancel</Button>
* <Button>Ok</Button>
* <Button mode="outlined">Cancel</Button>
* <Button mode="contained">Ok</Button>
* </Card.Actions>
* </Card>
* );
Expand All @@ -46,23 +45,7 @@ const CardActions = ({ theme, style, children, ...rest }: Props) => {

return (
<View {...rest} style={containerStyle}>
{React.Children.map(children, (child, index) => {
if (!React.isValidElement<CardActionChildProps>(child)) {
return child;
}

const compact = child.props.compact;
const mode =
child.props.mode ?? (index === 0 ? 'outlined' : 'contained');
const childStyle = [styles.button, child.props.style];

return React.cloneElement(child, {
...child.props,
compact,
mode,
style: childStyle,
});
})}
{children}
</View>
);
};
Expand All @@ -73,11 +56,9 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
columnGap: 8,
padding: 8,
},
button: {
marginLeft: 8,
},
});

export default CardActions;
63 changes: 4 additions & 59 deletions src/components/Card/CardContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,6 @@ export type Props = ViewProps & {
* Items inside the `Card.Content`.
*/
children: React.ReactNode;
/**
* @internal
*/
index?: number;
/**
* @internal
*/
total?: number;
/**
* @internal
*/
siblings?: Array<string | null>;
style?: StyleProp<ViewStyle>;
};

Expand All @@ -42,58 +30,15 @@ export type Props = ViewProps & {
* export default MyComponent;
* ```
*/
const CardContent = ({ index, total, siblings, style, ...rest }: Props) => {
const cover = 'Card.Cover';
const title = 'Card.Title';

let contentStyle, prev, next;

if (typeof index === 'number' && siblings) {
prev = siblings[index - 1];
next = siblings[index + 1];
}

if (
(prev === cover && next === cover) ||
(prev === title && next === title) ||
total === 1
) {
contentStyle = styles.only;
} else if (index === 0) {
if (next === cover || next === title) {
contentStyle = styles.only;
} else {
contentStyle = styles.first;
}
} else if (typeof total === 'number' && index === total - 1) {
if (prev === cover || prev === title) {
contentStyle = styles.only;
} else {
contentStyle = styles.last;
}
} else if (prev === cover || prev === title) {
contentStyle = styles.first;
} else if (next === cover || next === title) {
contentStyle = styles.last;
}

return <View {...rest} style={[styles.container, contentStyle, style]} />;
};
const CardContent = ({ style, ...rest }: Props) => (
<View {...rest} style={[styles.container, style]} />
);

CardContent.displayName = 'Card.Content';

const styles = StyleSheet.create({
container: {
paddingHorizontal: 16,
},
first: {
paddingTop: 16,
},
last: {
paddingBottom: 16,
},
only: {
paddingVertical: 16,
padding: 16,
},
});

Expand Down
18 changes: 1 addition & 17 deletions src/components/Card/CardCover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,6 @@ import type { ThemeProp } from '../../theme/types';
import { splitStyles } from '../../utils/splitStyles';

export type Props = ImageProps & {
/**
* @internal
*/
index?: number;
/**
* @internal
*/
total?: number;
style?: StyleProp<ViewStyle>;
/**
* @optional
Expand All @@ -42,13 +34,7 @@ export type Props = ImageProps & {
*
* @extends Image props https://reactnative.dev/docs/image#props
*/
const CardCover = ({
index,
total,
style,
theme: themeOverrides,
...rest
}: Props) => {
const CardCover = ({ style, theme: themeOverrides, ...rest }: Props) => {
const theme = useInternalTheme(themeOverrides);

const flattenedStyles = StyleSheet.flatten<ViewStyle>(style) || {};
Expand All @@ -59,8 +45,6 @@ const CardCover = ({

const coverStyle = getCardCoverStyle({
theme,
index,
total,
borderRadiusStyles,
});

Expand Down
8 changes: 0 additions & 8 deletions src/components/Card/CardTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,6 @@ export type Props = ViewProps & {
* Style for the right element wrapper.
*/
rightStyle?: StyleProp<ViewStyle>;
/**
* @internal
*/
index?: number;
/**
* @internal
*/
total?: number;
/**
* Specifies the largest possible scale a title font can reach.
*/
Expand Down
Loading