diff --git a/example/src/Examples/TextInputExample.tsx b/example/src/Examples/TextInputExample.tsx
index caecdc49b8..fbe11afd0a 100644
--- a/example/src/Examples/TextInputExample.tsx
+++ b/example/src/Examples/TextInputExample.tsx
@@ -672,7 +672,7 @@ const TextInputExample = () => {
@@ -681,7 +681,7 @@ const TextInputExample = () => {
diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx
index 1cb2ca6bed..59cebe3a93 100644
--- a/src/components/Button/Button.tsx
+++ b/src/components/Button/Button.tsx
@@ -210,7 +210,7 @@ const Button = (
},
[mode]
);
- const { roundness, animation } = theme;
+ const { animation } = theme;
const uppercase = uppercaseProp ?? false;
const isWeb = Platform.OS === 'web';
@@ -271,7 +271,7 @@ const Button = (
(style) => style.startsWith('border') && style.endsWith('Radius')
);
- const borderRadius = 5 * roundness;
+ const borderRadius = theme.shapes.corner.largeIncreased;
const iconSize = 18;
const {
diff --git a/src/components/Card/Card.tsx b/src/components/Card/Card.tsx
index 422101b4e8..c1522e5bf5 100644
--- a/src/components/Card/Card.tsx
+++ b/src/components/Card/Card.tsx
@@ -181,7 +181,7 @@ const Card = (
const { current: elevationDarkAdaptive } = React.useRef(
new Animated.Value(cardElevation)
);
- const { animation, dark, mode, roundness } = theme;
+ const { animation, dark, mode } = theme;
const prevDarkRef = React.useRef(dark);
React.useEffect(() => {
@@ -267,7 +267,7 @@ const Card = (
);
const borderRadiusCombinedStyles = {
- borderRadius: 3 * roundness,
+ borderRadius: theme.shapes.corner.medium,
...borderRadiusStyles,
};
diff --git a/src/components/Card/utils.tsx b/src/components/Card/utils.tsx
index b3d776662d..785a23c820 100644
--- a/src/components/Card/utils.tsx
+++ b/src/components/Card/utils.tsx
@@ -26,17 +26,15 @@ export const getCardCoverStyle = ({
index?: number;
total?: number;
}) => {
- const { roundness } = theme;
-
if (Object.keys(borderRadiusStyles).length > 0) {
return {
- borderRadius: 3 * roundness,
+ borderRadius: theme.shapes.corner.medium,
...borderRadiusStyles,
};
}
return {
- borderRadius: 3 * roundness,
+ borderRadius: theme.shapes.corner.medium,
};
};
diff --git a/src/components/Chip/Chip.tsx b/src/components/Chip/Chip.tsx
index fe3b30ab49..76d12d5ae1 100644
--- a/src/components/Chip/Chip.tsx
+++ b/src/components/Chip/Chip.tsx
@@ -205,7 +205,6 @@ const Chip = ({
...rest
}: Props) => {
const theme = useInternalTheme(themeOverrides);
- const { roundness } = theme;
const isWeb = Platform.OS === 'web';
const { current: elevation } = React.useRef(
@@ -244,7 +243,7 @@ const Chip = ({
});
const opacity = 0.38;
- const defaultBorderRadius = roundness * 2;
+ const defaultBorderRadius = theme.shapes.corner.small;
const iconSize = 18;
const {
diff --git a/src/components/Dialog/Dialog.tsx b/src/components/Dialog/Dialog.tsx
index fd6597c34e..717445aed7 100644
--- a/src/components/Dialog/Dialog.tsx
+++ b/src/components/Dialog/Dialog.tsx
@@ -105,8 +105,7 @@ const Dialog = ({
}: Props) => {
const { right, left } = useSafeAreaInsets();
const theme = useInternalTheme(themeOverrides);
- const { roundness } = theme as Theme;
- const borderRadius = 7 * roundness;
+ const borderRadius = (theme as Theme).shapes.corner.extraLarge;
const backgroundColor = theme.colors.surfaceContainerHigh;
diff --git a/src/components/Drawer/DrawerItem.tsx b/src/components/Drawer/DrawerItem.tsx
index 6902b4b8cb..9a68471474 100644
--- a/src/components/Drawer/DrawerItem.tsx
+++ b/src/components/Drawer/DrawerItem.tsx
@@ -100,7 +100,6 @@ const DrawerItem = ({
...rest
}: Props) => {
const theme = useInternalTheme(themeOverrides);
- const { roundness } = theme;
const backgroundColor = active ? theme.colors.secondaryContainer : undefined;
const contentColor = active
@@ -108,7 +107,7 @@ const DrawerItem = ({
: theme.colors.onSurfaceVariant;
const labelMargin = icon ? 12 : 0;
- const borderRadius = 7 * roundness;
+ const borderRadius = theme.shapes.corner.extraLarge;
const font = theme.fonts.labelLarge;
return (
diff --git a/src/components/FAB/utils.ts b/src/components/FAB/utils.ts
index ad49fa13be..93485aecb3 100644
--- a/src/components/FAB/utils.ts
+++ b/src/components/FAB/utils.ts
@@ -284,10 +284,10 @@ const v3LargeSize = {
width: 96,
};
-const getCustomFabSize = (customSize: number, roundness: number) => ({
+const getCustomFabSize = (customSize: number) => ({
height: customSize,
width: customSize,
- borderRadius: roundness === 0 ? 0 : customSize / roundness,
+ borderRadius: customSize / 4,
});
export const getFabStyle = ({
@@ -299,17 +299,15 @@ export const getFabStyle = ({
size: 'small' | 'medium' | 'large';
theme: InternalTheme;
}) => {
- const { roundness } = theme;
-
- if (customSize) return getCustomFabSize(customSize, roundness);
+ if (customSize) return getCustomFabSize(customSize);
switch (size) {
case 'small':
- return { ...v3SmallSize, borderRadius: 3 * roundness };
+ return { ...v3SmallSize, borderRadius: theme.shapes.corner.medium };
case 'medium':
- return { ...v3MediumSize, borderRadius: 4 * roundness };
+ return { ...v3MediumSize, borderRadius: theme.shapes.corner.large };
case 'large':
- return { ...v3LargeSize, borderRadius: 7 * roundness };
+ return { ...v3LargeSize, borderRadius: theme.shapes.corner.extraLarge };
}
};
diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx
index 4ba3d59a57..ebbd94e057 100644
--- a/src/components/Menu/Menu.tsx
+++ b/src/components/Menu/Menu.tsx
@@ -622,7 +622,7 @@ const Menu = ({
}),
},
],
- borderRadius: theme.roundness,
+ borderRadius: theme.shapes.corner.extraSmall,
...(scrollableMenuHeight ? { height: scrollableMenuHeight } : {}),
};
diff --git a/src/components/Searchbar.tsx b/src/components/Searchbar.tsx
index 76c9e03218..69fbfb572d 100644
--- a/src/components/Searchbar.tsx
+++ b/src/components/Searchbar.tsx
@@ -20,6 +20,7 @@ import IconButton from './IconButton/IconButton';
import MaterialCommunityIcon from './MaterialCommunityIcon';
import Surface from './Surface';
import { useInternalTheme } from '../core/theming';
+import { cornerNone } from '../theme/tokens/sys/shape';
import type { Theme, ThemeProp } from '../types';
import { forwardRef } from '../utils/forwardRef';
@@ -213,7 +214,7 @@ const Searchbar = forwardRef(
onClearIconPress?.(e);
};
- const { roundness, dark } = theme;
+ const { dark } = theme;
const placeholderTextColor = theme.colors.onSurface;
const textColor = theme.colors.onSurfaceVariant;
@@ -237,10 +238,12 @@ const Searchbar = forwardRef(
return (
{
const isAndroid = Platform.OS === 'android';
- const { colors, roundness } = theme;
+ const { colors } = theme;
+ const roundness = theme.shapes.corner.extraSmall;
const font = theme.fonts.bodyLarge;
const hasActiveOutline = parentState.focused || error;
@@ -156,8 +157,8 @@ const TextInputFlat = ({
const containerStyle = {
backgroundColor,
- borderTopLeftRadius: theme.roundness,
- borderTopRightRadius: theme.roundness,
+ borderTopLeftRadius: roundness,
+ borderTopRightRadius: roundness,
};
const labelScale = MINIMIZED_LABEL_FONT_SIZE / fontSize;
diff --git a/src/components/TextInput/TextInputOutlined.tsx b/src/components/TextInput/TextInputOutlined.tsx
index 63efb7f14b..aa563cf55f 100644
--- a/src/components/TextInput/TextInputOutlined.tsx
+++ b/src/components/TextInput/TextInputOutlined.tsx
@@ -81,7 +81,8 @@ const TextInputOutlined = ({
}: ChildTextInputProps) => {
const adornmentConfig = getAdornmentConfig({ left, right });
- const { colors, roundness } = theme;
+ const { colors } = theme;
+ const roundness = theme.shapes.corner.extraSmall;
const font = theme.fonts.bodyLarge;
const hasActiveOutline = parentState.focused || error;
diff --git a/src/components/ToggleButton/ToggleButton.tsx b/src/components/ToggleButton/ToggleButton.tsx
index ba4bd138a3..71bc5bad9c 100644
--- a/src/components/ToggleButton/ToggleButton.tsx
+++ b/src/components/ToggleButton/ToggleButton.tsx
@@ -108,7 +108,7 @@ const ToggleButton = forwardRef(
ref
) => {
const theme = useInternalTheme(themeOverrides);
- const borderRadius = theme.roundness;
+ const borderRadius = theme.shapes.corner.extraSmall;
return (
diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx
index fdfef8571f..a3d199e879 100644
--- a/src/components/Tooltip/Tooltip.tsx
+++ b/src/components/Tooltip/Tooltip.tsx
@@ -209,7 +209,7 @@ const Tooltip = ({
measurement as Measurement,
children as React.ReactElement
),
- borderRadius: theme.roundness,
+ borderRadius: theme.shapes.corner.extraSmall,
...(measurement.measured ? styles.visible : styles.hidden),
},
]}
diff --git a/src/components/__tests__/Card/Card.test.tsx b/src/components/__tests__/Card/Card.test.tsx
index fb61ca9602..ac4eabfa11 100644
--- a/src/components/__tests__/Card/Card.test.tsx
+++ b/src/components/__tests__/Card/Card.test.tsx
@@ -220,7 +220,7 @@ describe('getCardCoverStyle - border radius', () => {
theme: getTheme(),
borderRadiusStyles: {},
})
- ).toMatchObject({ borderRadius: 3 * getTheme().roundness });
+ ).toMatchObject({ borderRadius: getTheme().shapes.corner.medium });
});
});
diff --git a/src/components/__tests__/Chip.test.tsx b/src/components/__tests__/Chip.test.tsx
index 82841001ff..4ed5cad4ea 100644
--- a/src/components/__tests__/Chip.test.tsx
+++ b/src/components/__tests__/Chip.test.tsx
@@ -83,7 +83,7 @@ it('renders active chip if only onLongPress handler is passed', () => {
it('renders chip with zero border radius', () => {
const { getByTestId } = render(
-
+
Active chip
);
diff --git a/src/components/__tests__/FAB.test.tsx b/src/components/__tests__/FAB.test.tsx
index 9fc9c12e98..91b54e22be 100644
--- a/src/components/__tests__/FAB.test.tsx
+++ b/src/components/__tests__/FAB.test.tsx
@@ -131,7 +131,12 @@ it('renders FAB with custom border radius', () => {
it('renders FAB with zero border radius', () => {
const { getByTestId } = render(
- {}} icon="plus" testID="fab" />
+ {}}
+ icon="plus"
+ testID="fab"
+ />
);
expect(getByTestId('fab-container')).toHaveStyle({ borderRadius: 0 });
diff --git a/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap b/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap
index 80b6cc6c20..fe96dc80e6 100644
--- a/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap
+++ b/src/components/__tests__/__snapshots__/ListSection.test.tsx.snap
@@ -187,7 +187,18 @@ exports[`renders list section with custom title style 1`] = `
"lineHeight": 20,
},
},
- "roundness": 4,
+ "shapes": {
+ "corner": {
+ "extraExtraLarge": 48,
+ "extraLarge": 28,
+ "extraLargeIncreased": 32,
+ "extraSmall": 4,
+ "large": 16,
+ "largeIncreased": 20,
+ "medium": 12,
+ "small": 8,
+ },
+ },
}
}
>
@@ -729,7 +740,18 @@ exports[`renders list section with subheader 1`] = `
"lineHeight": 20,
},
},
- "roundness": 4,
+ "shapes": {
+ "corner": {
+ "extraExtraLarge": 48,
+ "extraLarge": 28,
+ "extraLargeIncreased": 32,
+ "extraSmall": 4,
+ "large": 16,
+ "largeIncreased": 20,
+ "medium": 12,
+ "small": 8,
+ },
+ },
}
}
>
@@ -1269,7 +1291,18 @@ exports[`renders list section without subheader 1`] = `
"lineHeight": 20,
},
},
- "roundness": 4,
+ "shapes": {
+ "corner": {
+ "extraExtraLarge": 48,
+ "extraLarge": 28,
+ "extraLargeIncreased": 32,
+ "extraSmall": 4,
+ "large": 16,
+ "largeIncreased": 20,
+ "medium": 12,
+ "small": 8,
+ },
+ },
}
}
>
diff --git a/src/theme/schemes/DarkTheme.tsx b/src/theme/schemes/DarkTheme.tsx
index 85ca245e57..ab49b62400 100644
--- a/src/theme/schemes/DarkTheme.tsx
+++ b/src/theme/schemes/DarkTheme.tsx
@@ -1,6 +1,7 @@
import { baseTheme } from './base';
import { tokens } from '../tokens';
import { buildScheme } from '../tokens/sys/color/roles';
+import { defaultShapes } from '../tokens/sys/shape';
import type { Theme } from '../types';
export const DarkTheme: Theme = {
@@ -8,4 +9,5 @@ export const DarkTheme: Theme = {
dark: true,
mode: 'adaptive',
colors: buildScheme(tokens.md.ref.palette, tokens.md.ref, { mode: 'dark' }),
+ shapes: defaultShapes,
};
diff --git a/src/theme/schemes/LightTheme.tsx b/src/theme/schemes/LightTheme.tsx
index d60f1a7709..b5d97a9cae 100644
--- a/src/theme/schemes/LightTheme.tsx
+++ b/src/theme/schemes/LightTheme.tsx
@@ -1,10 +1,12 @@
import { baseTheme } from './base';
import { tokens } from '../tokens';
import { buildScheme } from '../tokens/sys/color/roles';
+import { defaultShapes } from '../tokens/sys/shape';
import type { Theme } from '../types';
export const LightTheme: Theme = {
...baseTheme,
dark: false,
colors: buildScheme(tokens.md.ref.palette, tokens.md.ref, { mode: 'light' }),
+ shapes: defaultShapes,
};
diff --git a/src/theme/schemes/base.ts b/src/theme/schemes/base.ts
index 68cf999cee..4601d7dc83 100644
--- a/src/theme/schemes/base.ts
+++ b/src/theme/schemes/base.ts
@@ -1,7 +1,6 @@
import configureFonts from '../fonts';
export const baseTheme = {
- roundness: 4,
fonts: configureFonts(),
animation: {
scale: 1.0,
diff --git a/src/theme/tokens/sys/shape.ts b/src/theme/tokens/sys/shape.ts
new file mode 100644
index 0000000000..6610004481
--- /dev/null
+++ b/src/theme/tokens/sys/shape.ts
@@ -0,0 +1,17 @@
+import type { ThemeShapes } from '../../types';
+
+export const cornerNone = 0;
+export const cornerFull = 9999;
+
+export const defaultShapes: ThemeShapes = {
+ corner: {
+ extraSmall: 4,
+ small: 8,
+ medium: 12,
+ large: 16,
+ largeIncreased: 20,
+ extraLarge: 28,
+ extraLargeIncreased: 32,
+ extraExtraLarge: 48,
+ },
+};
diff --git a/src/theme/types/index.ts b/src/theme/types/index.ts
index 2207ed0526..e62ef4ad45 100644
--- a/src/theme/types/index.ts
+++ b/src/theme/types/index.ts
@@ -1,6 +1,7 @@
export * from './color';
export * from './elevation';
export * from './navigation';
+export * from './shape';
export * from './theme';
export * from './typography';
export * from './utils';
diff --git a/src/theme/types/shape.ts b/src/theme/types/shape.ts
new file mode 100644
index 0000000000..78d16d2285
--- /dev/null
+++ b/src/theme/types/shape.ts
@@ -0,0 +1,14 @@
+export type ThemeShapeCorners = {
+ extraSmall: number;
+ small: number;
+ medium: number;
+ large: number;
+ largeIncreased: number;
+ extraLarge: number;
+ extraLargeIncreased: number;
+ extraExtraLarge: number;
+};
+
+export type ThemeShapes = {
+ corner: ThemeShapeCorners;
+};
diff --git a/src/theme/types/theme.ts b/src/theme/types/theme.ts
index 431b4ecfcf..dac2946cc9 100644
--- a/src/theme/types/theme.ts
+++ b/src/theme/types/theme.ts
@@ -1,6 +1,7 @@
import type { $DeepPartial } from '@callstack/react-theme-provider';
import type { ThemeColors } from './color';
+import type { ThemeShapes } from './shape';
import type { Typescale } from './typography';
type Mode = 'adaptive' | 'exact';
@@ -8,7 +9,6 @@ type Mode = 'adaptive' | 'exact';
export type ThemeBase = {
dark: boolean;
mode?: Mode;
- roundness: number;
animation: {
scale: number;
defaultAnimationDuration?: number;
@@ -18,6 +18,7 @@ export type ThemeBase = {
export type Theme = ThemeBase & {
colors: ThemeColors;
fonts: Typescale;
+ shapes: ThemeShapes;
};
export type InternalTheme = Theme;