@tamagui/avatar 1.0.1-beta.59 → 1.0.1-beta.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tamagui/avatar",
3
- "version": "1.0.1-beta.59",
3
+ "version": "1.0.1-beta.60",
4
4
  "sideEffects": true,
5
5
  "source": "src/index.ts",
6
6
  "types": "./types/index.d.ts",
@@ -8,6 +8,7 @@
8
8
  "module": "dist/esm",
9
9
  "module:jsx": "dist/jsx",
10
10
  "files": [
11
+ "src",
11
12
  "types",
12
13
  "dist"
13
14
  ],
@@ -19,10 +20,10 @@
19
20
  },
20
21
  "dependencies": {
21
22
  "@radix-ui/react-use-callback-ref": "^0.1.0",
22
- "@tamagui/core": "^1.0.1-beta.59",
23
- "@tamagui/image": "^1.0.1-beta.59",
24
- "@tamagui/shapes": "^1.0.1-beta.59",
25
- "@tamagui/text": "^1.0.1-beta.59"
23
+ "@tamagui/core": "^1.0.1-beta.60",
24
+ "@tamagui/image": "^1.0.1-beta.60",
25
+ "@tamagui/shapes": "^1.0.1-beta.60",
26
+ "@tamagui/text": "^1.0.1-beta.60"
26
27
  },
27
28
  "peerDependencies": {
28
29
  "react": "*",
@@ -30,7 +31,7 @@
30
31
  "react-native": "*"
31
32
  },
32
33
  "devDependencies": {
33
- "@tamagui/build": "^1.0.1-beta.59",
34
+ "@tamagui/build": "^1.0.1-beta.60",
34
35
  "@types/react-dom": "^18.0.3",
35
36
  "@types/react-native": "^0.67.3",
36
37
  "react": "*",
package/src/Avatar.tsx ADDED
@@ -0,0 +1,162 @@
1
+ // forked from radix https://github.com/radix-ui/primitives/blob/main/packages/react/avatar/src/Avatar.tsx
2
+
3
+ import {
4
+ GetProps,
5
+ SizeTokens,
6
+ TamaguiElement,
7
+ getVariableValue,
8
+ getVariantExtras,
9
+ styled,
10
+ withStaticProperties,
11
+ } from '@tamagui/core'
12
+ import { Scope, createContextScope } from '@tamagui/create-context'
13
+ import { Image, ImageProps } from '@tamagui/image'
14
+ import { Square, getShapeSize } from '@tamagui/shapes'
15
+ import { YStack } from '@tamagui/stacks'
16
+ import * as React from 'react'
17
+
18
+ const AVATAR_NAME = 'Avatar'
19
+
20
+ type ScopedProps<P> = P & { __scopeAvatar?: Scope }
21
+ const [createAvatarContext, createAvatarScope] = createContextScope(AVATAR_NAME)
22
+
23
+ type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error'
24
+
25
+ type AvatarContextValue = {
26
+ size: SizeTokens
27
+ imageLoadingStatus: ImageLoadingStatus
28
+ onImageLoadingStatusChange(status: ImageLoadingStatus): void
29
+ }
30
+
31
+ const [AvatarProvider, useAvatarContext] = createAvatarContext<AvatarContextValue>(AVATAR_NAME)
32
+
33
+ /* -------------------------------------------------------------------------------------------------
34
+ * AvatarImage
35
+ * -----------------------------------------------------------------------------------------------*/
36
+
37
+ const IMAGE_NAME = 'AvatarImage'
38
+
39
+ type AvatarImageProps = Partial<ImageProps> & {
40
+ onLoadingStatusChange?: (status: ImageLoadingStatus) => void
41
+ }
42
+
43
+ const AvatarImage = React.forwardRef<TamaguiElement, AvatarImageProps>(
44
+ (props: ScopedProps<AvatarImageProps>, forwardedRef) => {
45
+ const { __scopeAvatar, src, onLoadingStatusChange = () => {}, ...imageProps } = props
46
+ const context = useAvatarContext(IMAGE_NAME, __scopeAvatar)
47
+ const [status, setStatus] = React.useState<ImageLoadingStatus>('idle')
48
+ const extras = getVariantExtras(props)
49
+ const shapeSize = getVariableValue(getShapeSize(context.size, extras)?.width)
50
+
51
+ React.useEffect(() => {
52
+ setStatus('idle')
53
+ }, [JSON.stringify(src)])
54
+
55
+ React.useEffect(() => {
56
+ onLoadingStatusChange(status)
57
+ context.onImageLoadingStatusChange(status)
58
+ }, [status])
59
+
60
+ return (
61
+ <YStack fullscreen zIndex={1}>
62
+ <Image
63
+ fullscreen
64
+ {...imageProps}
65
+ // @ts-ignore
66
+ ref={forwardedRef}
67
+ // @ts-ignore
68
+ src={src}
69
+ onLoadStart={() => {
70
+ // setStatus('loading')
71
+ }}
72
+ onError={() => {
73
+ setStatus('error')
74
+ }}
75
+ onLoad={() => {
76
+ setStatus('loaded')
77
+ }}
78
+ />
79
+ </YStack>
80
+ )
81
+ }
82
+ )
83
+
84
+ AvatarImage.displayName = IMAGE_NAME
85
+
86
+ /* -------------------------------------------------------------------------------------------------
87
+ * AvatarFallback
88
+ * -----------------------------------------------------------------------------------------------*/
89
+
90
+ const FALLBACK_NAME = 'AvatarFallback'
91
+
92
+ const AvatarFallbackFrame = styled(YStack, {
93
+ name: FALLBACK_NAME,
94
+ position: 'absolute',
95
+ fullscreen: true,
96
+ zIndex: 0,
97
+ })
98
+
99
+ type AvatarFallbackProps = GetProps<typeof AvatarFallbackFrame> & {
100
+ delayMs?: number
101
+ }
102
+
103
+ const AvatarFallback = AvatarFallbackFrame.extractable(
104
+ React.forwardRef<TamaguiElement, AvatarFallbackProps>(
105
+ (props: ScopedProps<AvatarFallbackProps>, forwardedRef) => {
106
+ const { __scopeAvatar, delayMs, ...fallbackProps } = props
107
+ const context = useAvatarContext(FALLBACK_NAME, __scopeAvatar)
108
+ const [canRender, setCanRender] = React.useState(delayMs === undefined)
109
+
110
+ React.useEffect(() => {
111
+ if (delayMs !== undefined) {
112
+ const timerId = setTimeout(() => setCanRender(true), delayMs)
113
+ return () => clearTimeout(timerId)
114
+ }
115
+ }, [delayMs])
116
+
117
+ return canRender && context.imageLoadingStatus !== 'loaded' ? (
118
+ <AvatarFallbackFrame {...fallbackProps} ref={forwardedRef} />
119
+ ) : null
120
+ }
121
+ )
122
+ )
123
+
124
+ AvatarFallback.displayName = FALLBACK_NAME
125
+
126
+ /* -------------------------------------------------------------------------------------------------
127
+ * Avatar
128
+ * -----------------------------------------------------------------------------------------------*/
129
+
130
+ export const AvatarFrame = styled(Square, {
131
+ name: AVATAR_NAME,
132
+ position: 'relative',
133
+ overflow: 'hidden',
134
+ })
135
+
136
+ type AvatarProps = GetProps<typeof AvatarFrame>
137
+
138
+ const Avatar = withStaticProperties(
139
+ React.forwardRef<TamaguiElement, AvatarProps>((props: ScopedProps<AvatarProps>, forwardedRef) => {
140
+ const { __scopeAvatar, size = '$4', ...avatarProps } = props
141
+ const [imageLoadingStatus, setImageLoadingStatus] = React.useState<ImageLoadingStatus>('idle')
142
+ return (
143
+ <AvatarProvider
144
+ size={size}
145
+ scope={__scopeAvatar}
146
+ imageLoadingStatus={imageLoadingStatus}
147
+ onImageLoadingStatusChange={setImageLoadingStatus}
148
+ >
149
+ <AvatarFrame size={size} {...avatarProps} ref={forwardedRef} />
150
+ </AvatarProvider>
151
+ )
152
+ }),
153
+ {
154
+ Image: AvatarImage,
155
+ Fallback: AvatarFallback,
156
+ }
157
+ )
158
+
159
+ Avatar.displayName = AVATAR_NAME
160
+
161
+ export { createAvatarScope, Avatar, AvatarImage, AvatarFallback }
162
+ export type { AvatarProps, AvatarImageProps, AvatarFallbackProps }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './Avatar'