@startupjs-ui/avatar 0.1.3

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/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ ## [0.1.3](https://github.com/startupjs/startupjs-ui/compare/v0.1.2...v0.1.3) (2025-12-29)
7
+
8
+ **Note:** Version bump only for package @startupjs-ui/avatar
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.1.2](https://github.com/startupjs/startupjs-ui/compare/v0.1.1...v0.1.2) (2025-12-29)
15
+
16
+
17
+ ### Features
18
+
19
+ * add mdx and docs packages. Refactor docs to get rid of any @startupjs/ui usage and use startupjs-ui instead ([703c926](https://github.com/startupjs/startupjs-ui/commit/703c92636efb0421ffd11783f692fc892b74018f))
20
+ * **avatar:** refactor Avatar component ([768b74f](https://github.com/startupjs/startupjs-ui/commit/768b74f47dde3b7fcfe2804d340c69fb31ab7ce0))
package/README.mdx ADDED
@@ -0,0 +1,152 @@
1
+ import { useState, useCallback } from 'react'
2
+ import { pug, styl } from 'startupjs'
3
+ import Avatar, { _PropsJsonSchema as AvatarPropsJsonSchema } from './index'
4
+ import Div from '@startupjs-ui/div'
5
+ import Span from '@startupjs-ui/span'
6
+ import Br from '@startupjs-ui/br'
7
+ import { Sandbox } from '@startupjs-ui/docs'
8
+
9
+ # Avatar
10
+
11
+ Avatars can be used to represent people. When used with a specific logo, avatars can also be used to represent a brand. They also can be a placeholder when there is no image or image can't be loaded by some reason to be shown, showing an alternative in this case.
12
+
13
+ ```js
14
+ import { Avatar } from 'startupjs-ui'
15
+ ```
16
+
17
+ ## Simple example
18
+
19
+ ```jsx example
20
+ return pug`
21
+ Avatar(src='/img/avatar1.jpeg')
22
+ `
23
+ ```
24
+
25
+ ## Sizes
26
+ Size is `m` by default. It can be changed by changing the `size` property by setting it to one of the values ​​('s', 'm', 'l') or by specifying the size in pixels.
27
+
28
+ ```jsx example
29
+ return pug`
30
+ Div(row)
31
+ Div
32
+ Avatar(
33
+ size='s'
34
+ src='/img/avatar2.jpeg'
35
+ )
36
+ Div(pushed)
37
+ Avatar(
38
+ size='m'
39
+ src='/img/avatar3.jpeg'
40
+ )
41
+ Div(pushed)
42
+ Avatar(
43
+ size='l'
44
+ src='/img/avatar1.jpeg'
45
+ )
46
+ Div(pushed)
47
+ Avatar(
48
+ size=60
49
+ src='/img/avatar3.jpeg'
50
+ )
51
+ `
52
+ ```
53
+
54
+ ## User status
55
+ Avatars can be used to display user online status. It can be set by passing string `online` or `away` to property `status`.
56
+
57
+ ```jsx example
58
+ return pug`
59
+ Div(row)
60
+ Div
61
+ Avatar(
62
+ status='online'
63
+ src='/img/avatar1.jpeg'
64
+ )
65
+ Div(pushed)
66
+ Avatar(
67
+ status='away'
68
+ src='/img/avatar2.jpeg'
69
+ )
70
+ `
71
+ ```
72
+
73
+ Also you can provide custom components for the status icon using `statusComponents` prop.
74
+
75
+ ```jsx example
76
+ const AbsentStatus = useCallback(({ style }) => (
77
+ <Div style={style} styleName='absent'>
78
+ <Div styleName='absent-line absent-line-1' />
79
+ <Div styleName='absent-line absent-line-2' />
80
+ </Div>
81
+ ))
82
+
83
+ return pug`
84
+ Avatar(
85
+ pushed
86
+ src='/img/avatar2.jpeg'
87
+ status='absent'
88
+ statusComponents={
89
+ absent: AbsentStatus
90
+ }
91
+ )
92
+ `
93
+
94
+ styl`
95
+ .absent
96
+ background-color white
97
+ justify-content center
98
+ &-line
99
+ position absolute
100
+ height 2px
101
+ left 0
102
+ right 0
103
+ background-color red
104
+ &-1
105
+ transform rotate(45deg)
106
+ &-2
107
+ transform rotate(-45deg)
108
+ `
109
+ ```
110
+
111
+ ## Fallback string
112
+ If `url` prop is not provided or if there is an error loading the avatar image, the component using an alternative. The alternative is initials of two first words of `children` string if provided and `?` if not. In the example below alternative is 'John Doe' therefore 'JD' will be displayed.
113
+
114
+ ```jsx example
115
+ return pug`
116
+ Div(row)
117
+ Div
118
+ Avatar(src='/img/non-existen-image.jpeg')
119
+ Div(pushed)
120
+ Avatar(
121
+ src='/img/non-existen-image.jpeg'
122
+ ) John Doe
123
+ `
124
+ ```
125
+
126
+ ## Actions
127
+
128
+ Passed handler to `onPress` property will be called when the user taps the component.
129
+
130
+ ```jsx example
131
+ const [counter, setCounter] = useState(0)
132
+
133
+ return pug`
134
+ Div
135
+ Avatar(
136
+ src='/img/avatar1.jpeg'
137
+ onPress=()=> setCounter(counter + 1)
138
+ )
139
+ Br
140
+ Span= 'Clicked ' + counter + ' times'
141
+ `
142
+ ```
143
+
144
+ ## Sandbox
145
+
146
+ <Sandbox
147
+ Component={Avatar}
148
+ propsJsonSchema={AvatarPropsJsonSchema}
149
+ props={{
150
+ onPress: () => alert('"onPress" event on "Avatar" component'),
151
+ }}
152
+ />
@@ -0,0 +1,62 @@
1
+ $this = merge(
2
+ {
3
+ avatarSizes: {
4
+ s: 4u,
5
+ m: 5u,
6
+ l: 6u,
7
+ },
8
+ statusSizes: {
9
+ s: 1.25u,
10
+ m: 1.5u,
11
+ l: 1.75u,
12
+ },
13
+ fallbackSizes: {
14
+ s: 1.5u,
15
+ m: 1.75u,
16
+ l: 2u,
17
+ }
18
+ },
19
+ $UI.Avatar,
20
+ true
21
+ )
22
+
23
+ .root
24
+ +web()
25
+ user-select none
26
+
27
+ .avatarWrapper
28
+ height 100%
29
+ overflow hidden
30
+
31
+ .avatar
32
+ justify-content center
33
+ align-items center
34
+ height 100%
35
+
36
+ .fallback
37
+ color var(--color-text-on-color)
38
+
39
+ .status
40
+ position absolute
41
+ z-index 1
42
+ border-width 2px
43
+ border-color var(--color-border-main-strong)
44
+ radius(circle)
45
+
46
+ &.circle
47
+ right 0
48
+ bottom 0
49
+
50
+ &.squared
51
+ &.rounded
52
+ bottom -0.25u
53
+ right @bottom
54
+
55
+ &.online
56
+ background-color var(--color-bg-success)
57
+
58
+ &.away
59
+ background-color var(--color-bg-warning)
60
+
61
+ :export
62
+ config: $this
package/index.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ /* eslint-disable */
2
+ // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
+
4
+ import { type ComponentType } from 'react';
5
+ import { type StyleProp, type ViewStyle } from 'react-native';
6
+ import { type DivProps } from '@startupjs-ui/div';
7
+ declare const _default: ComponentType<AvatarProps>;
8
+ export default _default;
9
+ export declare const _PropsJsonSchema: {};
10
+ export interface AvatarProps extends DivProps {
11
+ /** Custom styles applied to the root view */
12
+ style?: StyleProp<ViewStyle>;
13
+ /** Avatar image source URL */
14
+ src?: string;
15
+ /** Size preset or explicit pixel value @default 'm' */
16
+ size?: 's' | 'm' | 'l' | number;
17
+ /** Status indicator name */
18
+ status?: 'online' | 'away' | string;
19
+ /** Avatar shape variant @default 'circle' */
20
+ shape?: DivProps['shape'];
21
+ /** Text used to build fallback initials @default '?' */
22
+ children?: string;
23
+ /** Custom components for status indicators keyed by status */
24
+ statusComponents?: Record<string, ComponentType<any>>;
25
+ }
package/index.tsx ADDED
@@ -0,0 +1,105 @@
1
+ import { useState, type ComponentType, type ReactNode } from 'react'
2
+ import { Image, type StyleProp, type ViewStyle } from 'react-native'
3
+ import { pug, observer, useDidUpdate } from 'startupjs'
4
+ import { themed } from '@startupjs-ui/core'
5
+ import Div, { type DivProps } from '@startupjs-ui/div'
6
+ import Span from '@startupjs-ui/span'
7
+ import randomcolor from 'randomcolor'
8
+ import STYLES from './index.cssx.styl'
9
+
10
+ const { config } = STYLES
11
+
12
+ const DEFAULT_STATUSES = ['online', 'away']
13
+
14
+ export default observer(themed('Avatar', Avatar))
15
+
16
+ export const _PropsJsonSchema = {/* AvatarProps */}
17
+
18
+ export interface AvatarProps extends DivProps {
19
+ /** Custom styles applied to the root view */
20
+ style?: StyleProp<ViewStyle>
21
+ /** Avatar image source URL */
22
+ src?: string
23
+ /** Size preset or explicit pixel value @default 'm' */
24
+ size?: 's' | 'm' | 'l' | number
25
+ /** Status indicator name */
26
+ status?: 'online' | 'away' | string
27
+ /** Avatar shape variant @default 'circle' */
28
+ shape?: DivProps['shape']
29
+ /** Text used to build fallback initials @default '?' */
30
+ children?: string
31
+ /** Custom components for status indicators keyed by status */
32
+ statusComponents?: Record<string, ComponentType<any>>
33
+ }
34
+
35
+ function Avatar ({
36
+ src,
37
+ size = 'm',
38
+ status,
39
+ shape = 'circle',
40
+ children = '?',
41
+ statusComponents,
42
+ disabled = false,
43
+ ...props
44
+ }: AvatarProps): ReactNode {
45
+ const [error, setError] = useState<boolean>()
46
+ useDidUpdate(() => {
47
+ setError(undefined)
48
+ }, [src])
49
+
50
+ const _size = config.avatarSizes?.[size] ?? size
51
+ const _rootStyle = { width: _size, height: _size }
52
+ const _statusSize = config.statusSizes?.[size] ?? Math.round(Number(size) / 4)
53
+ const _statusStyle = { width: _statusSize, height: _statusSize }
54
+ const _fallbackFontSize = config.fallbackSizes?.[size] ?? Math.round(Number(size) / 2.5)
55
+ const _fallbackStyle = { fontSize: _fallbackFontSize, lineHeight: _fallbackFontSize }
56
+
57
+ const StatusComponent = getStatusComponent(statusComponents, status)
58
+
59
+ return pug`
60
+ Div.root(
61
+ part='root'
62
+ style=_rootStyle
63
+ disabled=disabled
64
+ ...props
65
+ )
66
+ Div.avatarWrapper(shape=shape)
67
+ if src && !error
68
+ Image.avatar(
69
+ source={ uri: src }
70
+ onError=() => {
71
+ setError(true)
72
+ }
73
+ )
74
+ else
75
+ - const _fallback = children.trim()
76
+ - const [firstName, lastName] = _fallback.split(' ')
77
+ - const initials = (firstName ? firstName[0].toUpperCase() : '') + (lastName ? lastName[0].toUpperCase() : '')
78
+ Div.avatar(
79
+ style={backgroundColor: randomcolor({
80
+ luminosity: 'bright',
81
+ seed: _fallback
82
+ })}
83
+ )
84
+ Span.fallback(part='fallback' bold style=_fallbackStyle)
85
+ = initials
86
+ if status
87
+ StatusComponent.status(part='status' styleName=[status, shape] style=_statusStyle)
88
+ `
89
+ }
90
+
91
+ function getStatusComponent (
92
+ statusComponents?: AvatarProps['statusComponents'],
93
+ status?: AvatarProps['status']
94
+ ) {
95
+ if (!status) return Div
96
+
97
+ if (!DEFAULT_STATUSES.includes(status) && !statusComponents?.[status]) {
98
+ console.error(
99
+ "[@dmapper/ui -> Avatar] Custom component for status '" +
100
+ status +
101
+ "' is not specified. Use 'statusComponents' to specify it."
102
+ )
103
+ }
104
+ return statusComponents?.[status] ?? Div
105
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@startupjs-ui/avatar",
3
+ "version": "0.1.3",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "main": "index.tsx",
8
+ "types": "index.d.ts",
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@startupjs-ui/core": "^0.1.3",
12
+ "@startupjs-ui/div": "^0.1.3",
13
+ "@startupjs-ui/span": "^0.1.3",
14
+ "randomcolor": "^0.5.4"
15
+ },
16
+ "peerDependencies": {
17
+ "react": "*",
18
+ "react-native": "*",
19
+ "startupjs": "*"
20
+ },
21
+ "gitHead": "fd964ebc3892d3dd0a6c85438c0af619cc50c3f0"
22
+ }