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

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,
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