Skip to content

Commit 7db1588

Browse files
authored
Merge pull request #79 from adaptui/refactoring-components
> Tag Component 1. add web-based callback functions 2. add hover and focus styles 3. add a11y props > Button Component 1. move button props type to the component file itself > Avatar Component 1. remove usage of the useAvatarProps hook, move Avatar Props into the component file and pass through required props into children's components
2 parents 5527684 + 7c3fad6 commit 7db1588

File tree

17 files changed

+315
-233
lines changed

17 files changed

+315
-233
lines changed
Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,66 @@
1-
import React from "react";
1+
import React, { useState } from "react";
22
import {
33
Box,
4-
CaretRight,
4+
Checkbox,
5+
CheckboxGroup,
56
Icon,
6-
Info,
7+
Slot,
78
Tag,
9+
TagSizes,
10+
TagTheme,
11+
TagVariant,
812
useTheme,
913
} from "@adaptui/react-native-tailwind";
1014

1115
export const TagScreen = () => {
1216
const tailwind = useTheme();
17+
const sizes: TagSizes[] = ["sm", "md", "lg", "xl"];
18+
const themeColors: TagTheme[] = ["base", "primary"];
19+
const variants: TagVariant[] = ["solid", "subtle", "outline"];
20+
const [value, setValue] = useState<string[]>([]);
21+
1322
return (
1423
<Box
1524
style={tailwind.style("flex-1 justify-center items-center bg-white-900")}
1625
>
17-
<Tag style={tailwind.style("my-1")}>Default</Tag>
18-
<Tag
19-
style={tailwind.style("my-1")}
20-
prefix={<Icon icon={<Info />} />}
21-
variant="outline"
22-
>
23-
Default Outline
24-
</Tag>
25-
<Tag style={tailwind.style("my-1")} variant="subtle">
26-
Default Subtle
27-
</Tag>
28-
<Tag style={tailwind.style("my-1")} themeColor="primary">
29-
Primary Solid
30-
</Tag>
31-
32-
<Tag
33-
prefix={<Icon icon={<Info />} />}
34-
style={tailwind.style("my-1")}
35-
themeColor="primary"
36-
variant="outline"
37-
>
38-
Primary Outline
39-
</Tag>
40-
<Tag
41-
suffix={<Icon icon={<CaretRight />} />}
42-
style={tailwind.style("my-1")}
43-
themeColor="primary"
44-
variant="subtle"
45-
closable
46-
>
47-
Primary Subtle
48-
</Tag>
49-
<Tag closable style={tailwind.style("my-1")} themeColor="primary">
50-
Close
51-
</Tag>
26+
<CheckboxGroup value={value} onChange={setValue}>
27+
<Checkbox label="Closable" value="closable" />
28+
<Checkbox label="Show Prefix" value="showprefix" />
29+
</CheckboxGroup>
30+
{sizes.map((size, index) => {
31+
return (
32+
<Box style={tailwind.style("flex-col my-1")} key={size + index}>
33+
{variants.map((variant, variantIndex) => {
34+
return (
35+
<Box
36+
style={tailwind.style("flex-row my-1")}
37+
key={variant + variantIndex}
38+
>
39+
{themeColors.map((theme, themeIndex) => {
40+
return (
41+
<Tag
42+
style={tailwind.style("mx-1")}
43+
size={size}
44+
key={theme + themeIndex}
45+
variant={variant}
46+
themeColor={theme}
47+
closable={value.includes("closable")}
48+
prefix={
49+
value.includes("showprefix") ? (
50+
<Icon icon={<Slot />} />
51+
) : null
52+
}
53+
>
54+
Continue
55+
</Tag>
56+
);
57+
})}
58+
</Box>
59+
);
60+
})}
61+
</Box>
62+
);
63+
})}
5264
</Box>
5365
);
5466
};

src/components/avatar-group/AvatarGroup.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { isUndefined } from "lodash";
44
import { Box, BoxProps } from "../../primitives";
55
import { useTheme } from "../../theme";
66
import { createContext, getValidChildren } from "../../utils";
7-
import { Avatar } from "../avatar/Avatar";
8-
import { AvatarProps } from "../avatar/avatarPropTypes";
7+
import { Avatar, AvatarProps } from "../avatar";
98

109
import { AvatarGroupWrapper } from "./AvatarGroupWrapper";
1110

src/components/avatar-group/AvatarGroupWrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import React from "react";
33
import { Box, BoxProps } from "../../primitives";
44
import { useTheme } from "../../theme";
55
import { styleAdapter } from "../../utils";
6-
import { AvatarSizes } from "../avatar/avatarPropTypes";
6+
import { AvatarSizes } from "../avatar";
77

88
export interface AvatarGroupWrapperProps extends BoxProps {
99
size?: AvatarSizes;

src/components/avatar/Avatar.tsx

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import React, { forwardRef, useState } from "react";
2+
import { ImageProps, ImageSourcePropType } from "react-native";
23

34
import { DefaultUser } from "../../icons";
4-
import { Box, Text } from "../../primitives";
5+
import { Box, BoxProps, Text } from "../../primitives";
56
import { useTheme } from "../../theme";
6-
import { createComponent, cx, styleAdapter } from "../../utils";
7+
import { createComponent, cx, isUndefined, styleAdapter } from "../../utils";
8+
import { useAvatarGroup } from "../avatar-group";
79
import { Icon } from "../icon";
810

911
import { AvatarImage } from "./AvatarImage";
10-
import { useAvatarProps } from "./AvatarProps";
11-
import type { AvatarProps, AvatarSizes } from "./avatarPropTypes";
1212
import { AvatarStatus } from "./AvatarStatus";
1313

1414
function getInitials(name: string, size: AvatarSizes) {
@@ -28,63 +28,126 @@ function getInitials(name: string, size: AvatarSizes) {
2828
: initials.toUpperCase();
2929
}
3030

31+
export type AvatarSizes = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl";
32+
export type AvatarStatusType = "active" | "away" | "sleep" | "typing" | null;
33+
34+
export interface AvatarProps extends BoxProps {
35+
/**
36+
* React Native Image component Props, except for source
37+
*/
38+
imageProps: Omit<ImageProps, "source">;
39+
/**
40+
* The image source (either a remote URL or a local file resource).
41+
* Check https://reactnative.dev/docs/image#imagesource
42+
*/
43+
src: ImageSourcePropType;
44+
/**
45+
* How large should avatar be?
46+
*
47+
* @default xl
48+
*/
49+
size: AvatarSizes;
50+
/**
51+
* If `true`, Avatar looks like a squared.
52+
*
53+
* @default false
54+
*/
55+
squared: boolean;
56+
/**
57+
* Name prop used for `alt` & calculate placeholder initials.
58+
*/
59+
name: string;
60+
/**
61+
* Shows AvatarBadge with the given type
62+
*
63+
* @default none
64+
*/
65+
status: AvatarStatusType;
66+
/**
67+
* StatusIndicator's Background Color & StatusIndicator Ring Color.
68+
*
69+
* @default ["bg-white-900", "ring-white-900"]"
70+
*/
71+
parentsBackground: string;
72+
}
73+
3174
const RNAvatar: React.FC<Partial<AvatarProps>> = forwardRef<
3275
typeof Box,
3376
Partial<AvatarProps>
3477
>((props, ref) => {
3578
const tailwind = useTheme();
3679
const avatarTheme = useTheme("avatar");
37-
const { _imageProps, _basicProps, _otherProps, _statusProps } =
38-
useAvatarProps(props);
39-
const { name, style, ...boxProps } = _otherProps;
40-
const isSourceAvailable = React.useMemo(
41-
() => (_imageProps?.src ? true : false),
42-
[_imageProps?.src],
43-
);
80+
81+
const avatarGroupProps = useAvatarGroup();
82+
83+
const {
84+
size = avatarGroupProps?.size || "xl",
85+
squared = false,
86+
name,
87+
style,
88+
src,
89+
status,
90+
parentsBackground = "text-white-900",
91+
imageProps = {},
92+
...boxProps
93+
} = props;
94+
95+
const isSquared = isUndefined(avatarGroupProps)
96+
? squared
97+
: avatarGroupProps.squared;
98+
99+
const isSourceAvailable = React.useMemo(() => (src ? true : false), [src]);
44100
const [imageAvailable, setImageAvailable] = useState(isSourceAvailable);
45101
const loadFallback = () => setImageAvailable(false);
46102

47103
return (
48104
<Box
49105
style={[
50-
avatarTheme.borderRadius.size[_basicProps.size],
106+
avatarTheme.borderRadius.size[size],
51107
tailwind.style(
52108
cx(
53109
avatarTheme.base,
54-
avatarTheme.size[_basicProps.size],
55-
!_basicProps.squared ? avatarTheme.circular : "",
110+
avatarTheme.size[size],
111+
!isSquared ? avatarTheme.circular : "",
56112
),
57113
),
58114
styleAdapter(style),
59115
]}
60116
ref={ref}
61117
{...boxProps}
62118
>
63-
{imageAvailable && _imageProps.src ? (
64-
<AvatarImage {..._imageProps} handleFallback={loadFallback} />
119+
{imageAvailable && src ? (
120+
<AvatarImage
121+
size={size}
122+
imageProps={imageProps}
123+
src={src}
124+
squared={isSquared}
125+
handleFallback={loadFallback}
126+
/>
65127
) : name ? (
66128
<Text
67129
style={tailwind.style(
68-
cx(
69-
avatarTheme.initials.base,
70-
avatarTheme.initials.size[_basicProps.size],
71-
),
130+
cx(avatarTheme.initials.base, avatarTheme.initials.size[size]),
72131
)}
73132
adjustsFontSizeToFit
74133
allowFontScaling={false}
75134
>
76-
{getInitials(name, _basicProps.size)}
135+
{getInitials(name, size)}
77136
</Text>
78137
) : (
79138
<Icon
80139
icon={<DefaultUser />}
81-
style={tailwind.style(
82-
cx(avatarTheme.defaultUserIcon[_basicProps.size]),
83-
)}
140+
style={tailwind.style(cx(avatarTheme.defaultUserIcon[size]))}
84141
color={tailwind.getColor("text-gray-800")}
85142
/>
86143
)}
87-
{_statusProps.status && <AvatarStatus {..._statusProps} />}
144+
{status && (
145+
<AvatarStatus
146+
parentsBackground={parentsBackground}
147+
size={size}
148+
status={status}
149+
/>
150+
)}
88151
</Box>
89152
);
90153
});

src/components/avatar/AvatarImage.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,19 @@ import { Image } from "react-native";
44
import { useTheme } from "../../theme";
55
import { cx } from "../../utils";
66

7-
import { AvatarImageProps } from "./avatarPropTypes";
7+
import { AvatarProps } from "./Avatar";
88

9-
interface CAvatarImageProps extends AvatarImageProps {
9+
interface AvatarImageProps
10+
extends Pick<AvatarProps, "imageProps" | "src" | "squared" | "size"> {
1011
handleFallback: () => void;
1112
}
1213

13-
export const AvatarImage: React.FC<CAvatarImageProps> = ({
14+
export const AvatarImage: React.FC<AvatarImageProps> = ({
1415
imageProps,
1516
src,
16-
handleFallback,
1717
squared,
1818
size,
19+
handleFallback,
1920
}) => {
2021
const tailwind = useTheme();
2122
const avatarTheme = useTheme("avatar");

src/components/avatar/AvatarProps.tsx

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/components/avatar/AvatarStatus.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { AnimatedBox, Box } from "../../primitives";
1414
import { useTheme } from "../../theme";
1515
import { cx } from "../../utils";
1616

17-
import { AvatarSizes, AvatarStatusProps } from "./avatarPropTypes";
17+
import { AvatarProps, AvatarSizes } from "./Avatar";
1818

1919
interface TypingStatusProps {
2020
size: Partial<AvatarSizes>;
@@ -100,11 +100,9 @@ const TypingComponent: React.FC<TypingStatusProps> = ({
100100
);
101101
};
102102

103-
export const AvatarStatus: React.FC<AvatarStatusProps> = ({
104-
status,
105-
size = "xl",
106-
parentsBackground = "text-white-900",
107-
}) => {
103+
export const AvatarStatus: React.FC<
104+
Pick<AvatarProps, "status" | "size" | "parentsBackground">
105+
> = ({ status, size, parentsBackground }) => {
108106
const tailwind = useTheme();
109107
const avatarStatusTheme = useTheme("avatar");
110108
switch (status) {

0 commit comments

Comments
 (0)