diff --git a/example/src/Examples/CardExample.tsx b/example/src/Examples/CardExample.tsx
index ad3451e8b0..9de8b5cbbc 100644
--- a/example/src/Examples/CardExample.tsx
+++ b/example/src/Examples/CardExample.tsx
@@ -75,8 +75,12 @@ const CardExample = () => {
-
-
+
+
@@ -104,10 +108,10 @@ const CardExample = () => {
/>
-
diff --git a/example/src/Examples/TeamDetails.tsx b/example/src/Examples/TeamDetails.tsx
index 5970274f31..463e5148d8 100644
--- a/example/src/Examples/TeamDetails.tsx
+++ b/example/src/Examples/TeamDetails.tsx
@@ -93,8 +93,12 @@ const News = () => {
- {}}>Share
- {}}>Read more
+ {}}>
+ Share
+
+ {}}>
+ Read more
+
@@ -110,8 +114,12 @@ const News = () => {
- {}}>Share
- {}}>Read more
+ {}}>
+ Share
+
+ {}}>
+ Read more
+
diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx
index e1cc58c52a..fed3d55343 100644
--- a/src/components/Card/Card.tsx
+++ b/src/components/Card/Card.tsx
@@ -95,6 +95,8 @@ export type Props = $Omit, '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
@@ -112,8 +114,8 @@ export type Props = $Omit, 'mode'> & {
*
*
*
- * Cancel
- * Ok
+ * Cancel
+ * Ok
*
*
* );
@@ -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,
@@ -212,17 +207,11 @@ const Card = ({
};
const content = (
-
- {React.Children.map(children, (child, index) =>
- React.isValidElement(child)
- ? React.cloneElement(child as React.ReactElement, {
- index,
- total,
- siblings,
- borderRadiusStyles,
- })
- : child
- )}
+
+ {children}
);
@@ -288,6 +277,7 @@ Card.Title = CardTitle;
const styles = StyleSheet.create({
innerContainer: {
flexShrink: 1,
+ overflow: 'hidden',
},
outline: {
borderWidth: 1,
diff --git a/src/components/Card/CardActions.tsx b/src/components/Card/CardActions.tsx
index 689a97d1c1..e07a3034bc 100644
--- a/src/components/Card/CardActions.tsx
+++ b/src/components/Card/CardActions.tsx
@@ -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';
@@ -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
@@ -26,8 +27,8 @@ export type Props = ViewProps & {
* const MyComponent = () => (
*
*
- * Cancel
- * Ok
+ * Cancel
+ * Ok
*
*
* );
@@ -43,23 +44,7 @@ const CardActions = ({ theme, style, children, ...rest }: Props) => {
return (
- {React.Children.map(children, (child, index) => {
- if (!React.isValidElement(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}
);
};
@@ -70,11 +55,9 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
+ gap: 8,
padding: 8,
},
- button: {
- marginLeft: 8,
- },
});
export default CardActions;
diff --git a/src/components/Card/CardContent.tsx b/src/components/Card/CardContent.tsx
index af69fd7459..5784273d1b 100644
--- a/src/components/Card/CardContent.tsx
+++ b/src/components/Card/CardContent.tsx
@@ -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;
style?: StyleProp;
};
/**
* A component to show content inside a Card.
+ * Content uses uniform vertical padding and does not depend on neighboring
+ * card sections.
*
* ## Usage
* ```js
@@ -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 ;
-};
+const CardContent = ({ style, ...rest }: Props) => (
+
+);
CardContent.displayName = 'Card.Content';
const styles = StyleSheet.create({
container: {
paddingHorizontal: 16,
- },
- first: {
paddingTop: 16,
- },
- last: {
paddingBottom: 16,
},
- only: {
- paddingVertical: 16,
- },
});
export default CardContent;
diff --git a/src/components/Card/CardCover.tsx b/src/components/Card/CardCover.tsx
index e68bfb4adb..873561bd82 100644
--- a/src/components/Card/CardCover.tsx
+++ b/src/components/Card/CardCover.tsx
@@ -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;
/**
* @optional
@@ -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;
@@ -59,8 +45,6 @@ const CardCover = ({
const coverStyle = getCardCoverStyle({
theme,
- index,
- total,
borderRadiusStyles,
});
diff --git a/src/components/Card/CardTitle.tsx b/src/components/Card/CardTitle.tsx
index 2737fe6430..cf8beb20ef 100644
--- a/src/components/Card/CardTitle.tsx
+++ b/src/components/Card/CardTitle.tsx
@@ -81,14 +81,6 @@ export type Props = ViewProps & {
* Style for the right element wrapper.
*/
rightStyle?: StyleProp;
- /**
- * @internal
- */
- index?: number;
- /**
- * @internal
- */
- total?: number;
/**
* Specifies the largest possible scale a title font can reach.
*/
diff --git a/src/components/Card/utils.tsx b/src/components/Card/utils.tsx
index 785a23c820..ff4e117bab 100644
--- a/src/components/Card/utils.tsx
+++ b/src/components/Card/utils.tsx
@@ -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 {
diff --git a/src/components/Dialog/Dialog.tsx b/src/components/Dialog/Dialog.tsx
index e79804d324..a41f29aa11 100644
--- a/src/components/Dialog/Dialog.tsx
+++ b/src/components/Dialog/Dialog.tsx
@@ -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 = {
/**
@@ -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
@@ -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(child)) {
- return React.cloneElement(child, {
- style: [{ marginTop: 24 }, child.props.style],
- });
- }
-
- return child;
- })}
+ {children}
);
};
@@ -160,6 +151,7 @@ const styles = StyleSheet.create({
marginVertical: Platform.OS === 'android' ? 44 : 0,
elevation: DIALOG_ELEVATION,
justifyContent: 'flex-start',
+ paddingTop: 24,
},
});
diff --git a/src/components/Dialog/DialogActions.tsx b/src/components/Dialog/DialogActions.tsx
index 7e3799451e..c4eaa48c3f 100644
--- a/src/components/Dialog/DialogActions.tsx
+++ b/src/components/Dialog/DialogActions.tsx
@@ -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 { DialogActionChildProps } from './utils';
import { useInternalTheme } from '../../core/theming';
import type { ThemeProp } from '../../types';
@@ -20,6 +19,8 @@ export type Props = ViewProps & {
/**
* A component to show a list of actions in a Dialog.
+ * Actions are rendered directly, so configure each action button's props
+ * explicitly when you need non-default behavior.
*
* ## Usage
* ```js
@@ -48,24 +49,10 @@ export type Props = ViewProps & {
*/
const DialogActions = (props: Props) => {
useInternalTheme(props.theme);
- const actionsLength = React.Children.toArray(props.children).length;
return (
- {React.Children.map(props.children, (child, i) =>
- React.isValidElement(child)
- ? React.cloneElement(child, {
- compact: true,
- uppercase: false,
- style: [
- {
- marginRight: i + 1 === actionsLength ? 0 : 8,
- },
- child.props.style,
- ],
- })
- : child
- )}
+ {props.children}
);
};
@@ -78,6 +65,7 @@ const styles = StyleSheet.create({
flexGrow: 1,
alignItems: 'center',
justifyContent: 'flex-end',
+ gap: 8,
paddingBottom: 24,
paddingHorizontal: 24,
},
diff --git a/src/components/Dialog/DialogIcon.tsx b/src/components/Dialog/DialogIcon.tsx
index 199becd06c..46e70be39d 100644
--- a/src/components/Dialog/DialogIcon.tsx
+++ b/src/components/Dialog/DialogIcon.tsx
@@ -24,6 +24,10 @@ export type Props = {
* @optional
*/
theme?: ThemeProp;
+ /**
+ * testID to be used on tests.
+ */
+ testID?: string;
};
/**
@@ -68,6 +72,7 @@ const DialogIcon = ({
color,
icon,
theme: themeOverrides,
+ testID,
}: Props) => {
const theme = useInternalTheme(themeOverrides);
const { colors } = theme as Theme;
@@ -76,7 +81,7 @@ const DialogIcon = ({
const iconColor = color || colors.secondary;
return (
-
+
);
@@ -88,7 +93,8 @@ const styles = StyleSheet.create({
wrapper: {
alignItems: 'center',
justifyContent: 'center',
- paddingTop: 24,
+ marginBottom: 16,
+ paddingTop: 0,
},
});
diff --git a/src/components/Dialog/DialogTitle.tsx b/src/components/Dialog/DialogTitle.tsx
index bdf5021379..f361f911ab 100644
--- a/src/components/Dialog/DialogTitle.tsx
+++ b/src/components/Dialog/DialogTitle.tsx
@@ -81,7 +81,7 @@ const styles = StyleSheet.create({
marginHorizontal: 24,
},
v3Text: {
- marginTop: 16,
+ marginTop: 0,
marginBottom: 16,
},
});
diff --git a/src/components/List/ListAccordion.tsx b/src/components/List/ListAccordion.tsx
index 97730d58e6..9a3dcf0fde 100644
--- a/src/components/List/ListAccordion.tsx
+++ b/src/components/List/ListAccordion.tsx
@@ -12,8 +12,9 @@ import type {
ViewStyle,
} from 'react-native';
+import { ListAccordionContext } from './ListAccordionContext';
import { ListAccordionGroupContext } from './ListAccordionGroup';
-import type { ListChildProps, Style } from './utils';
+import type { Style } from './utils';
import { getAccordionColors, getLeftStyles } from './utils';
import { useLocale } from '../../core/locale';
import { useInternalTheme } from '../../core/theming';
@@ -324,23 +325,11 @@ const ListAccordion = ({
- {isExpanded
- ? React.Children.map(children, (child) => {
- if (
- left &&
- React.isValidElement(child) &&
- !child.props.left &&
- !child.props.right
- ) {
- return React.cloneElement(child, {
- style: [styles.child, child.props.style],
- theme,
- });
- }
-
- return child;
- })
- : null}
+ {isExpanded ? (
+
+ {children}
+
+ ) : null}
);
};
@@ -374,9 +363,6 @@ const styles = StyleSheet.create({
marginVertical: 6,
paddingLeft: 8,
},
- child: {
- paddingLeft: 40,
- },
content: {
flex: 1,
justifyContent: 'center',
diff --git a/src/components/List/ListAccordionContext.tsx b/src/components/List/ListAccordionContext.tsx
new file mode 100644
index 0000000000..306d9788bc
--- /dev/null
+++ b/src/components/List/ListAccordionContext.tsx
@@ -0,0 +1,15 @@
+import * as React from 'react';
+
+export type ListAccordionContextType = {
+ /**
+ * Whether descendant items that don't render their own `left`/`right`
+ * element should be indented to align under the accordion's content
+ * (past the leading icon).
+ */
+ leftIndent: boolean;
+};
+
+export const ListAccordionContext =
+ React.createContext({ leftIndent: false });
+
+ListAccordionContext.displayName = 'ListAccordionContext';
diff --git a/src/components/List/ListItem.tsx b/src/components/List/ListItem.tsx
index a6f0181f02..2c0d3452cd 100644
--- a/src/components/List/ListItem.tsx
+++ b/src/components/List/ListItem.tsx
@@ -10,6 +10,7 @@ import type {
ViewStyle,
} from 'react-native';
+import { ListAccordionContext } from './ListAccordionContext';
import { getLeftStyles, getRightStyles } from './utils';
import type { Style } from './utils';
import { useInternalTheme } from '../../core/theming';
@@ -161,6 +162,8 @@ const ListItem = ({
...rest
}: Props) => {
const theme = useInternalTheme(themeOverrides);
+ const { leftIndent } = React.useContext(ListAccordionContext);
+ const shouldIndent = leftIndent && !left && !right;
const [alignToTop, setAlignToTop] = React.useState(false);
const onDescriptionTextLayout = (
@@ -228,7 +231,11 @@ const ListItem = ({
{
const theme = useInternalTheme(themeOverrides);
const borderRadius = theme.shapes.corner.extraSmall;
+ const rowContext = React.useContext(ToggleButtonRowContext);
+ const isSegmentedRow = !!rowContext?.segmented;
return (
@@ -134,6 +137,7 @@ const ToggleButton = ({
borderRadius,
borderColor,
},
+ isSegmentedRow && styles.segmentedContent,
style,
]}
ref={ref}
@@ -152,6 +156,9 @@ const styles = StyleSheet.create({
height: 42,
margin: 0,
},
+ segmentedContent: {
+ borderRadius: 0,
+ },
});
export default ToggleButton;
diff --git a/src/components/ToggleButton/ToggleButtonRow.tsx b/src/components/ToggleButton/ToggleButtonRow.tsx
index 46e6aee48f..121e8e3d2d 100644
--- a/src/components/ToggleButton/ToggleButtonRow.tsx
+++ b/src/components/ToggleButton/ToggleButtonRow.tsx
@@ -2,8 +2,10 @@ import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import type { StyleProp, ViewStyle } from 'react-native';
-import ToggleButton from './ToggleButton';
import ToggleButtonGroup from './ToggleButtonGroup';
+import { ToggleButtonRowContext } from './ToggleButtonRowContext';
+import { useInternalTheme } from '../../core/theming';
+import type { ThemeProp } from '../../types';
export type Props = {
/**
@@ -19,8 +21,14 @@ export type Props = {
*/
children: React.ReactNode;
style?: StyleProp;
+ /**
+ * @optional
+ */
+ theme?: ThemeProp;
};
+const SEGMENTED_ROW_CONTEXT = { segmented: true };
+
/**
* Toggle button row renders a group of toggle buttons in a row.
*
@@ -44,33 +52,34 @@ export type Props = {
*
*```
*/
-const ToggleButtonRow = ({ value, onValueChange, children, style }: Props) => {
- const count = React.Children.count(children);
+const ToggleButtonRow = ({
+ value,
+ onValueChange,
+ children,
+ style,
+ theme: themeOverrides,
+}: Props) => {
+ const theme = useInternalTheme(themeOverrides);
+ const borderRadius = theme.shapes.corner.extraSmall;
+ const outlineColor = theme.colors.outline;
return (
-
- {React.Children.map(children, (child, i) => {
- // @ts-expect-error: TypeScript complains about child.type but it doesn't matter
- if (child && child.type === ToggleButton) {
- // @ts-expect-error: We're sure that child is a React Element
- return React.cloneElement(child, {
- style: [
- styles.button,
- i === 0
- ? styles.first
- : i === count - 1
- ? styles.last
- : styles.middle,
- // @ts-expect-error: We're sure that child is a React Element
- child.props.style,
- ],
- });
- }
-
- return child;
- })}
-
+
+
+
+ {children}
+
+
+
);
};
@@ -80,25 +89,10 @@ ToggleButtonRow.displayName = 'ToggleButton.Row';
const styles = StyleSheet.create({
row: {
flexDirection: 'row',
- },
- button: {
- borderWidth: StyleSheet.hairlineWidth,
- },
-
- first: {
- borderTopRightRadius: 0,
- borderBottomRightRadius: 0,
- },
-
- middle: {
- borderRadius: 0,
- borderLeftWidth: 0,
- },
-
- last: {
- borderLeftWidth: 0,
- borderTopLeftRadius: 0,
- borderBottomLeftRadius: 0,
+ alignSelf: 'flex-start',
+ gap: StyleSheet.hairlineWidth,
+ overflow: 'hidden',
+ padding: StyleSheet.hairlineWidth,
},
});
diff --git a/src/components/ToggleButton/ToggleButtonRowContext.tsx b/src/components/ToggleButton/ToggleButtonRowContext.tsx
new file mode 100644
index 0000000000..ff37016102
--- /dev/null
+++ b/src/components/ToggleButton/ToggleButtonRowContext.tsx
@@ -0,0 +1,8 @@
+import * as React from 'react';
+
+type ToggleButtonRowContextType = {
+ segmented: boolean;
+};
+
+export const ToggleButtonRowContext =
+ React.createContext(null);
diff --git a/src/components/__tests__/Card/Card.test.tsx b/src/components/__tests__/Card/Card.test.tsx
index 61659c8a24..c45132c0eb 100644
--- a/src/components/__tests__/Card/Card.test.tsx
+++ b/src/components/__tests__/Card/Card.test.tsx
@@ -1,3 +1,4 @@
+import type { ComponentProps } from 'react';
import { Animated, StyleSheet, Text } from 'react-native';
import { describe, expect, it, jest } from '@jest/globals';
@@ -91,6 +92,19 @@ describe('Card', () => {
expect(screen.getByTestId('card')).toHaveStyle(styles.contentStyle);
});
+ it('clips inner content to the card shape', async () => {
+ await render(
+
+
+
+ );
+
+ expect(screen.getByTestId('card')).toHaveStyle({
+ borderRadius: getTheme().shapes.corner.medium,
+ overflow: 'hidden',
+ });
+ });
+
it('does not render a disabled accessibility state', async () => {
await render({null});
@@ -127,18 +141,67 @@ describe('CardCover', () => {
describe('CardActions', () => {
it('renders button with passed mode', async () => {
+ const buttonProps = jest.fn();
+ const ProbeButton = (props: ComponentProps) => {
+ buttonProps(props);
+
+ return ;
+ };
+
+ await render(
+
+
+ Agree
+
+
+ );
+
+ expect(buttonProps).toHaveBeenCalledWith(
+ expect.objectContaining({ mode: 'contained' })
+ );
+ });
+
+ it('does not inject default button props', async () => {
+ const buttonProps = jest.fn();
+ const ProbeButton = (props: ComponentProps) => {
+ buttonProps(props);
+
+ return ;
+ };
+
+ await render(
+
+
+ Cancel
+ Agree
+
+
+ );
+
+ const [cancelButtonProps] = buttonProps.mock.calls[0];
+ const [agreeButtonProps] = buttonProps.mock.calls[1];
+
+ expect(cancelButtonProps).not.toHaveProperty('mode');
+ expect(cancelButtonProps).not.toHaveProperty('compact');
+ expect(agreeButtonProps).not.toHaveProperty('mode');
+ expect(agreeButtonProps).not.toHaveProperty('compact');
+ });
+
+ it('renders actions in a styled row', async () => {
await render(
- Agree
+ Cancel
+ Agree
);
- expect(
- // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion.
- screen.getByTestId('card-actions').props.children[0].props.mode
- ).toBe('contained');
+ expect(screen.getByTestId('card-actions')).toHaveStyle({
+ flexDirection: 'row',
+ gap: 8,
+ justifyContent: 'flex-end',
+ });
});
it('renders button with custom styles', async () => {
@@ -224,6 +287,25 @@ describe('getCardCoverStyle - border radius', () => {
});
});
+describe('CardContent', () => {
+ it('renders uniform vertical padding regardless of neighboring sections', async () => {
+ await render(
+
+
+
+
+ Card content
+
+
+ );
+
+ expect(screen.getByTestId('card-content')).toHaveStyle({
+ paddingTop: 16,
+ paddingBottom: 16,
+ });
+ });
+});
+
it('animated value changes correctly', async () => {
const value = new Animated.Value(1);
await render(
diff --git a/src/components/__tests__/Card/__snapshots__/Card.test.tsx.snap b/src/components/__tests__/Card/__snapshots__/Card.test.tsx.snap
index d1492cc475..46c1359b6d 100644
--- a/src/components/__tests__/Card/__snapshots__/Card.test.tsx.snap
+++ b/src/components/__tests__/Card/__snapshots__/Card.test.tsx.snap
@@ -62,6 +62,10 @@ exports[`Card renders an outlined card 1`] = `
[
{
"flexShrink": 1,
+ "overflow": "hidden",
+ },
+ {
+ "borderRadius": 12,
},
undefined,
]
diff --git a/src/components/__tests__/Dialog.test.tsx b/src/components/__tests__/Dialog.test.tsx
index 59785c52cf..c35d614469 100644
--- a/src/components/__tests__/Dialog.test.tsx
+++ b/src/components/__tests__/Dialog.test.tsx
@@ -1,3 +1,4 @@
+import type { ComponentProps } from 'react';
import {
Text,
StyleSheet,
@@ -93,17 +94,71 @@ describe('Dialog', () => {
expect(onDismiss).toHaveBeenCalledTimes(1);
});
- it('should apply top margin to the first child if the dialog is V3', async () => {
+ it('should apply top spacing to the dialog surface for a title-first dialog', async () => {
await render(
-