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
59 changes: 26 additions & 33 deletions src/components/List/ListAccordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import type {
} from 'react-native';

import { ListAccordionGroupContext } from './ListAccordionGroup';
import { ListTokens } from './tokens';
import type { ListChildProps, Style } from './utils';
import { getAccordionColors, getLeftStyles } from './utils';
import { getLeftStyles } from './utils';
import { useLocale } from '../../core/locale';
import { useInternalTheme } from '../../core/theming';
import type { ThemeProp } from '../../types';
Expand Down Expand Up @@ -232,20 +233,24 @@ const ListAccordion = ({
? groupContext.expandedId === id
: expandedInternal;

const { descriptionColor, titleTextColor } = getAccordionColors({
theme,
isExpanded,
});
const titleTextColor = theme.colors[ListTokens.headlineColor];
const descriptionColor = theme.colors[ListTokens.supportingTextColor];

const handlePress =
groupContext && id !== undefined
? () => groupContext.onAccordionPress(id)
: handlePressAction;
return (
<View>
<View style={{ backgroundColor: theme?.colors?.background }}>
<View
style={{ backgroundColor: theme.colors[ListTokens.containerColor] }}
>
<TouchableRipple
style={[styles.container, style]}
style={[
styles.container,
description ? styles.containerTwoLine : styles.containerOneLine,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

style,
]}
onPress={handlePress}
onLongPress={onLongPress}
delayLongPress={delayLongPress}
Expand All @@ -264,16 +269,16 @@ const ListAccordion = ({
>
{left
? left({
color: isExpanded ? theme.colors?.primary : descriptionColor,
color: theme.colors[ListTokens.leadingIconColor],
style: getLeftStyles(alignToTop, description),
})
: null}
<View style={[styles.contentItem, styles.content, contentStyle]}>
<Text
variant="bodyLarge"
selectable={false}
numberOfLines={titleNumberOfLines}
style={[
styles.title,
{
color: titleTextColor,
},
Expand All @@ -285,10 +290,10 @@ const ListAccordion = ({
</Text>
{description ? (
<Text
variant="bodyMedium"
selectable={false}
numberOfLines={descriptionNumberOfLines}
style={[
styles.description,
{
color: descriptionColor,
},
Expand All @@ -301,20 +306,15 @@ const ListAccordion = ({
</Text>
Comment on lines 277 to 306

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

) : null}
</View>
<View
style={[
styles.trailingItem,
description ? styles.multiline : undefined,
]}
>
<View style={styles.trailingItem}>
{right ? (
right({
isExpanded: isExpanded,
})
) : (
<MaterialCommunityIcon
name={isExpanded ? 'chevron-up' : 'chevron-down'}
color={descriptionColor}
color={theme.colors[ListTokens.trailingIconColor]}
size={24}
direction={direction}
/>
Expand Down Expand Up @@ -349,29 +349,22 @@ ListAccordion.displayName = 'List.Accordion';

const styles = StyleSheet.create({
container: {
paddingVertical: 8,
paddingRight: 24,
paddingRight: ListTokens.trailingSpace,
},
row: {
flexDirection: 'row',
marginVertical: 6,
},
multiline: {
height: 40,
alignItems: 'center',
justifyContent: 'center',
containerOneLine: {
paddingVertical: ListTokens.oneLineVerticalPadding,
},
title: {
fontSize: 16,
containerTwoLine: {
paddingVertical: ListTokens.twoLineVerticalPadding,
},
description: {
fontSize: 14,
row: {
flexDirection: 'row',
},
contentItem: {
paddingLeft: 16,
paddingLeft: ListTokens.leadingSpace,
},
trailingItem: {
marginVertical: 6,
alignSelf: 'center',
paddingLeft: 8,
},
child: {
Expand Down
43 changes: 22 additions & 21 deletions src/components/List/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
ViewStyle,
} from 'react-native';

import { ListTokens } from './tokens';
import { getLeftStyles, getRightStyles } from './utils';
import type { Style } from './utils';
import { useInternalTheme } from '../../core/theming';
Expand Down Expand Up @@ -179,18 +180,15 @@ const ListItem = ({
selectable: false,
ellipsizeMode: descriptionEllipsizeMode,
color: descriptionColor,
fontSize: styles.description.fontSize,
fontSize: theme.fonts.bodyMedium.fontSize,
})
) : (
<Text
variant="bodyMedium"
selectable={false}
numberOfLines={descriptionNumberOfLines}
ellipsizeMode={descriptionEllipsizeMode}
style={[
styles.description,
{ color: descriptionColor },
descriptionStyle,
]}
style={[{ color: descriptionColor }, descriptionStyle]}
onTextLayout={onDescriptionTextLayout}
maxFontSizeMultiplier={descriptionMaxFontSizeMultiplier}
>
Comment on lines 186 to 194

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what about passing resolved theme to these Text components?

<Text theme={theme} variant="bodyMedium" ... >

in current implementation component-level font overrides are used for render-prop titles & descriptions, but plain text still reads typography from the surrounding provider

Expand All @@ -200,35 +198,40 @@ const ListItem = ({
};

const renderTitle = () => {
const titleColor = theme.colors.onSurface;
const titleColor = theme.colors[ListTokens.headlineColor];

return typeof title === 'function' ? (
title({
selectable: false,
ellipsizeMode: titleEllipsizeMode,
color: titleColor,
fontSize: styles.title.fontSize,
fontSize: theme.fonts.bodyLarge.fontSize,
})
) : (
<Text
variant="bodyLarge"
selectable={false}
ellipsizeMode={titleEllipsizeMode}
numberOfLines={titleNumberOfLines}
style={[styles.title, { color: titleColor }, titleStyle]}
style={[{ color: titleColor }, titleStyle]}
maxFontSizeMultiplier={titleMaxFontSizeMultiplier}
>
{title}
</Text>
Comment on lines 211 to 220

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

);
};

const descriptionColor = theme.colors.onSurfaceVariant;
const descriptionColor = theme.colors[ListTokens.supportingTextColor];

return (
<TouchableRipple
{...rest}
ref={ref}
style={[styles.container, style]}
style={[
styles.container,
description ? styles.containerTwoLine : styles.containerOneLine,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what about descriptions with 2+ lines? they currently keep 14dp 2-line padding, resulting in 92dp item instead of MD3 88dp minimum (source)
so can we use 12dp vertical padding (multilineVerticalPadding: 12) whenever lines.length >= 2?

Suggested change
description ? styles.containerTwoLine : styles.containerOneLine,
description
? isDescriptionMultiline
? styles.containerMultiline
: styles.containerTwoLine
: styles.containerOneLine

style,
]}
onPress={onPress}
theme={theme}
testID={testID}
Expand Down Expand Up @@ -265,22 +268,20 @@ ListItem.displayName = 'List.Item';

const styles = StyleSheet.create({
container: {
paddingVertical: 8,
paddingRight: 24,
paddingRight: ListTokens.trailingSpace,
},
containerOneLine: {
paddingVertical: ListTokens.oneLineVerticalPadding,
},
containerTwoLine: {
paddingVertical: ListTokens.twoLineVerticalPadding,
},
row: {
width: '100%',
flexDirection: 'row',
marginVertical: 6,
},
title: {
fontSize: 16,
},
description: {
fontSize: 14,
},
item: {
paddingLeft: 16,
paddingLeft: ListTokens.leadingSpace,
},
content: {
flexShrink: 1,
Expand Down
18 changes: 18 additions & 0 deletions src/components/List/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { ColorRole } from '../../theme/types';

const sizes = {
oneLineVerticalPadding: 16,
twoLineVerticalPadding: 14,
leadingSpace: 16,
trailingSpace: 24,
} as const;

const colors = {
containerColor: 'surface',
headlineColor: 'onSurface',
supportingTextColor: 'onSurfaceVariant',
leadingIconColor: 'onSurfaceVariant',
trailingIconColor: 'onSurfaceVariant',
} as const satisfies Record<string, ColorRole>;

export const ListTokens = { ...sizes, ...colors };
85 changes: 12 additions & 73 deletions src/components/List/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StyleSheet } from 'react-native';
import type { StyleProp, ViewStyle } from 'react-native';

import type { EllipsizeProp, InternalTheme, ThemeProp } from '../../types';
import { ListTokens } from './tokens';
import type { EllipsizeProp, ThemeProp } from '../../types';

type Description =
| React.ReactNode
Expand All @@ -26,82 +26,21 @@ export type Style = {
alignSelf?: 'flex-start' | 'center';
};

const stylesV3Left = {
marginRight: 0,
marginLeft: 16,
};

const stylesV3Right = {
marginLeft: 16,
};

export const getLeftStyles = (
alignToTop: boolean,
description: Description
) => {
const stylesV3: Style = {
...stylesV3Left,
alignSelf: alignToTop ? 'flex-start' : 'center',
};

if (!description) {
return {
...styles.iconMarginLeft,
...styles.marginVerticalNone,
...stylesV3,
};
}

return {
...styles.iconMarginLeft,
...stylesV3,
};
};

export const getRightStyles = (
const getAccessoryStyles = (
alignToTop: boolean,
description: Description
) => {
const stylesV3: Style = {
...stylesV3Right,
): Style => {
const style: Style = {
marginLeft: ListTokens.leadingSpace,
marginRight: 0,
alignSelf: alignToTop ? 'flex-start' : 'center',
};

if (!description) {
return {
...styles.iconMarginRight,
...styles.marginVerticalNone,
...stylesV3,
};
}

return {
...styles.iconMarginRight,
...stylesV3,
};
return description ? style : { ...style, marginVertical: 0 };
};

const styles = StyleSheet.create({
marginVerticalNone: { marginVertical: 0 },
iconMarginLeft: { marginLeft: 0, marginRight: 16 },
iconMarginRight: { marginRight: 0 },
});
export const getLeftStyles = (alignToTop: boolean, description: Description) =>
getAccessoryStyles(alignToTop, description);

export const getAccordionColors = ({
theme,
isExpanded,
}: {
theme: InternalTheme;
isExpanded?: boolean;
}) => {
const titleColor = theme.colors.onSurface;

const descriptionColor = theme.colors.onSurfaceVariant;

const titleTextColor = isExpanded ? theme.colors?.primary : titleColor;

return {
descriptionColor,
titleTextColor,
};
};
export const getRightStyles = (alignToTop: boolean, description: Description) =>
getAccessoryStyles(alignToTop, description);
Loading