Skip to content

Commit

Permalink
fix typing with static members of functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Hamilton committed Feb 16, 2021
1 parent 9bbddb7 commit ce8aa3b
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 218 deletions.
190 changes: 98 additions & 92 deletions src/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,100 +50,107 @@ export type AvatarProps = {
ImageComponent?: React.ComponentClass;
};

const AvatarComponent: React.FunctionComponent<AvatarProps> = ({
onPress,
onLongPress,
Component = onPress || onLongPress ? TouchableOpacity : View,
containerStyle,
icon,
iconStyle,
source,
size = 'small',
avatarStyle,
rounded,
title,
titleStyle,
overlayContainerStyle,
imageProps,
placeholderStyle,
renderPlaceholderContent,
ImageComponent = RNImage,
children,
...attributes
}) => {
const width =
typeof size === 'number' ? size : avatarSizes[size] || avatarSizes.small;
const height = width;
const titleSize = width / 2;
const iconSize = width / 2;
const PlaceholderContent =
(renderPlaceholderContent &&
renderNode(undefined, renderPlaceholderContent)) ||
(title && (
<Text
style={StyleSheet.flatten([
styles.title,
{ fontSize: titleSize },
titleStyle,
])}
>
{title}
</Text>
)) ||
(icon && (
<Icon
style={iconStyle && iconStyle}
color={icon.color || 'white'}
name={icon.name || 'user'}
size={icon.size || iconSize}
type={icon.type && icon.type}
/>
));
// Remove placeholder styling if we're not using image
const hidePlaceholder = !(source && source.uri);
// Merge image container style
const imageContainerStyle = StyleSheet.flatten([
styles.overlayContainer,
rounded && { borderRadius: width / 2, overflow: 'hidden' },
interface Avatar extends React.FunctionComponent<AvatarProps> {
Accessory: typeof Accessory;
}

const AvatarComponent: Avatar = Object.assign(
({
onPress,
onLongPress,
Component = onPress || onLongPress ? TouchableOpacity : View,
containerStyle,
icon,
iconStyle,
source,
size = 'small',
avatarStyle,
rounded,
title,
titleStyle,
overlayContainerStyle,
imageProps && imageProps.containerStyle,
]);
if (imageProps && imageProps.containerStyle) {
delete imageProps.containerStyle;
}
return (
<Component
onPress={onPress}
onLongPress={onLongPress}
style={StyleSheet.flatten([
styles.container,
{ height, width },
rounded && { borderRadius: width / 2 },
containerStyle,
])}
{...attributes}
>
<Image
placeholderStyle={StyleSheet.flatten([
placeholderStyle,
hidePlaceholder && styles.hiddenPlaceholderStyle,
])}
PlaceholderContent={PlaceholderContent}
containerStyle={imageContainerStyle}
source={source}
borderRadius={rounded ? width / 2 : undefined}
{...imageProps}
imageProps,
placeholderStyle,
renderPlaceholderContent,
ImageComponent = RNImage,
children,
...attributes
}: React.PropsWithChildren<AvatarProps>) => {
const width =
typeof size === 'number' ? size : avatarSizes[size] || avatarSizes.small;
const height = width;
const titleSize = width / 2;
const iconSize = width / 2;
const PlaceholderContent =
(renderPlaceholderContent &&
renderNode(undefined, renderPlaceholderContent)) ||
(title && (
<Text
style={StyleSheet.flatten([
styles.title,
{ fontSize: titleSize },
titleStyle,
])}
>
{title}
</Text>
)) ||
(icon && (
<Icon
style={iconStyle && iconStyle}
color={icon.color || 'white'}
name={icon.name || 'user'}
size={icon.size || iconSize}
type={icon.type && icon.type}
/>
));
// Remove placeholder styling if we're not using image
const hidePlaceholder = !(source && source.uri);
// Merge image container style
const imageContainerStyle = StyleSheet.flatten([
styles.overlayContainer,
rounded && { borderRadius: width / 2, overflow: 'hidden' },
overlayContainerStyle,
imageProps && imageProps.containerStyle,
]);
if (imageProps && imageProps.containerStyle) {
delete imageProps.containerStyle;
}
return (
<Component
onPress={onPress}
onLongPress={onLongPress}
style={StyleSheet.flatten([
styles.avatar,
imageProps && imageProps.style,
avatarStyle,
styles.container,
{ height, width },
rounded && { borderRadius: width / 2 },
containerStyle,
])}
ImageComponent={ImageComponent}
/>
{children}
</Component>
);
};
{...attributes}
>
<Image
placeholderStyle={StyleSheet.flatten([
placeholderStyle,
hidePlaceholder && styles.hiddenPlaceholderStyle,
])}
PlaceholderContent={PlaceholderContent}
containerStyle={imageContainerStyle}
source={source}
borderRadius={rounded ? width / 2 : undefined}
{...imageProps}
style={StyleSheet.flatten([
styles.avatar,
imageProps && imageProps.style,
avatarStyle,
])}
ImageComponent={ImageComponent}
/>
{children}
</Component>
);
},
{ Accessory: Accessory }
);

const styles = StyleSheet.create({
container: {
Expand Down Expand Up @@ -171,5 +178,4 @@ const Avatar = React.memo(AvatarComponent, isEqual);
export { Avatar };
const ThemedAvatar = withTheme(Avatar, 'Avatar');

ThemedAvatar.Accessory = Accessory;
export default ThemedAvatar;
104 changes: 58 additions & 46 deletions src/card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,52 +14,69 @@ export type CardProps = {
theme?: Theme;
};

const Card: React.FunctionComponent<CardProps> = (props) => {
const {
children,
containerStyle,
wrapperStyle,
theme,
...attributes
} = props;
interface Card extends React.FunctionComponent<CardProps> {
Divider: typeof CardDivider;
Image: typeof CardImage;
Title: typeof CardTitle;
FeaturedTitle: typeof CardFeaturedTitle;
FeaturedSubtitle: typeof CardFeaturedSubtitle;
}

return (
<View
{...attributes}
style={StyleSheet.flatten([
{
backgroundColor: theme.colors.white,
borderWidth: 1,
padding: 15,
margin: 15,
marginBottom: 0,
borderColor: theme.colors.grey5,
...Platform.select({
android: {
elevation: 1,
},
default: {
shadowColor: 'rgba(0,0,0, .2)',
shadowOffset: { height: 0, width: 0 },
shadowOpacity: 1,
shadowRadius: 1,
},
}),
},
containerStyle && containerStyle,
])}
>
const Card: Card = Object.assign(
(props) => {
const {
children,
containerStyle,
wrapperStyle,
theme,
...attributes
} = props;

return (
<View
{...attributes}
style={StyleSheet.flatten([
styles.wrapper,
wrapperStyle && wrapperStyle,
{
backgroundColor: theme.colors.white,
borderWidth: 1,
padding: 15,
margin: 15,
marginBottom: 0,
borderColor: theme.colors.grey5,
...Platform.select({
android: {
elevation: 1,
},
default: {
shadowColor: 'rgba(0,0,0, .2)',
shadowOffset: { height: 0, width: 0 },
shadowOpacity: 1,
shadowRadius: 1,
},
}),
},
containerStyle && containerStyle,
])}
>
{children}
<View
style={StyleSheet.flatten([
styles.wrapper,
wrapperStyle && wrapperStyle,
])}
>
{children}
</View>
</View>
</View>
);
};
);
},
{
Divider: CardDivider,
Image: CardImage,
Title: CardTitle,
FeaturedTitle: CardFeaturedTitle,
FeaturedSubtitle: CardFeaturedSubtitle,
}
);

const styles = StyleSheet.create({
wrapper: {
Expand All @@ -69,10 +86,5 @@ const styles = StyleSheet.create({

export { Card };

const ThemedCard: ThemedCard = withTheme(Card, 'Card');
ThemedCard.Divider = CardDivider;
ThemedCard.Image = CardImage;
ThemedCard.Title = CardTitle;
ThemedCard.FeaturedTitle = CardFeaturedTitle;
ThemedCard.FeaturedSubtitle = CardFeaturedSubtitle;
const ThemedCard = withTheme(Card, 'Card');
export default ThemedCard;
1 change: 1 addition & 0 deletions src/config/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface ThemeProps<T> {
replaceTheme: (updates: RecursivePartial<FullTheme>) => void;
}

// @ts-ignore
export const ThemeContext: React.Context<ThemeProps<{}>> = React.createContext({
theme: {
colors,
Expand Down
6 changes: 5 additions & 1 deletion src/config/withTheme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const isClassComponent = (Component: any) =>

const withTheme = (WrappedComponent: any, themeKey: string) => {
class ThemedComponent extends React.Component {
static displayName: string;

render() {
// @ts-ignore
const { forwardedRef, children, ...rest } = this.props;

return (
Expand All @@ -29,6 +32,7 @@ const withTheme = (WrappedComponent: any, themeKey: string) => {
theme,
updateTheme,
replaceTheme,
// @ts-ignore
...deepmerge((themeKey && theme[themeKey]) || {}, rest, {
clone: false,
}),
Expand Down Expand Up @@ -57,7 +61,7 @@ const withTheme = (WrappedComponent: any, themeKey: string) => {
return hoistNonReactStatics(React.forwardRef(forwardRef), WrappedComponent);
}
ThemedComponent.displayName = name;
return ThemedComponent;
return hoistNonReactStatics(ThemedComponent, WrappedComponent);
};

export default withTheme;

0 comments on commit ce8aa3b

Please sign in to comment.