Skip to content
Draft
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
12 changes: 8 additions & 4 deletions example/src/Examples/CardExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,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,10 +108,10 @@ const CardExample = () => {
/>
<Card.Title title="Custom Button styles" />
<Card.Actions>
<Button style={styles.button} onPress={() => {}}>
<Button mode="outlined" style={styles.button} onPress={() => {}}>
Share
</Button>
<Button style={styles.button} onPress={() => {}}>
<Button mode="contained" style={styles.button} onPress={() => {}}>
Explore
</Button>
</Card.Actions>
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
30 changes: 10 additions & 20 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export type Props = $Omit<React.ComponentProps<typeof Surface>, 'mode'> & {

/**
* A card is a sheet of material that serves as an entry point to more detailed information.
* Card clips its inner content to the card shape and renders children directly;
* section spacing is owned by the section components themselves.
*
* ## Usage
* ```js
Expand All @@ -112,8 +114,8 @@ export type Props = $Omit<React.ComponentProps<typeof Surface>, 'mode'> & {
* </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 @@ -185,13 +187,6 @@ const Card = ({
runElevationAnimation('out');
});

const total = React.Children.count(children);
const siblings = React.Children.map(children, (child) =>
React.isValidElement(child) && child.type
? (child.type as any).displayName
: null
);

const { backgroundColor, borderColor: themedBorderColor } = getCardColors({
theme,
mode: cardMode,
Expand All @@ -212,17 +207,11 @@ const Card = ({
};

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

Expand Down Expand Up @@ -288,6 +277,7 @@ Card.Title = CardTitle;
const styles = StyleSheet.create({
innerContainer: {
flexShrink: 1,
overflow: 'hidden',
},
outline: {
borderWidth: 1,
Expand Down
29 changes: 6 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 '../../types';

Expand All @@ -17,6 +16,8 @@ export type Props = ViewProps & {

/**
* A component to show a list of actions inside a Card.
* Actions are rendered directly, so set button `mode`, `compact`, and custom
* spacing props explicitly on each action when needed.
*
* ## Usage
* ```js
Expand All @@ -26,8 +27,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 @@ -43,23 +44,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 @@ -70,11 +55,9 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
padding: 8,
},
button: {
marginLeft: 8,
},
});

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

/**
* A component to show content inside a Card.
* Content uses uniform vertical padding and does not depend on neighboring
* card sections.
*
* ## Usage
* ```js
Expand All @@ -42,59 +32,18 @@ export type Props = ViewProps & {
* export default MyComponent;
* ```
*/
const CardContent = ({ index, total, siblings, style, ...rest }: Props) => {
const cover = 'withInternalTheme(CardCover)';
const title = 'withInternalTheme(CardTitle)';

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,
},
});

export default CardContent;
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 '../../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(style) || {}) as ViewStyle;
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
4 changes: 0 additions & 4 deletions src/components/Card/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,10 @@ export type CardActionChildProps = {

export const getCardCoverStyle = ({
theme,
index: _index,
total: _total,
borderRadiusStyles,
}: {
theme: InternalTheme;
borderRadiusStyles: BorderRadiusStyles;
index?: number;
total?: number;
}) => {
if (Object.keys(borderRadiusStyles).length > 0) {
return {
Expand Down
16 changes: 4 additions & 12 deletions src/components/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import DialogTitle from './DialogTitle';
import { useInternalTheme } from '../../core/theming';
import type { Theme, ThemeProp } from '../../types';
import Modal from '../Modal';
import type { DialogChildProps } from './utils';

export type Props = {
/**
Expand Down Expand Up @@ -51,6 +50,8 @@ const DIALOG_ELEVATION: number = 24;
/**
* Dialogs inform users about a specific task and may contain critical information, require decisions, or involve multiple tasks.
* To render the `Dialog` above other components, you'll need to wrap it with the [`Portal`](../Portal) component.
* Dialog owns the top content inset, so first-slot components render without
* adding their own top offset.
*
* ## Usage
* ```js
Expand Down Expand Up @@ -122,17 +123,7 @@ const Dialog = ({
theme={theme}
testID={testID}
>
{React.Children.toArray(children)
.filter((child) => child != null && typeof child !== 'boolean')
.map((child, i) => {
if (i === 0 && React.isValidElement<DialogChildProps>(child)) {
return React.cloneElement(child, {
style: [{ marginTop: 24 }, child.props.style],
});
}

return child;
})}
{children}
</Modal>
);
};
Expand Down Expand Up @@ -160,6 +151,7 @@ const styles = StyleSheet.create({
marginVertical: Platform.OS === 'android' ? 44 : 0,
elevation: DIALOG_ELEVATION,
justifyContent: 'flex-start',
paddingTop: 24,
},
});

Expand Down
Loading