Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

fix(Avatar): fixing issues for the height of the element and the initials generation #38

Merged
merged 16 commits into from
Aug 7, 2018
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Fixes
- Remove unused dependencies and move development dependencies to devDependencies @levithomason ([#51](https://github.com/stardust-ui/react/pull/51))
- Fixed issues ([#31](https://github.com/stardust-ui/react/issues/31)) and ([#32](https://github.com/stardust-ui/react/issues/32)) @mnajdova ([#38](https://github.com/stardust-ui/react/pull/38))

### Features
- Update styles for Menu underlined primary @miroslavstastny ([#20](https://github.com/stardust-ui/react/pull/20))
- Add Avatar `getInitials` prop and `presenceIndicatorBackground` variable @mnajdova ([#38](https://github.com/stardust-ui/react/pull/38))

<!--------------------------------[ v0.2.5 ]------------------------------- -->
## [v0.2.5](https://github.com/stardust-ui/react/tree/v0.2.5) (2018-08-03)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { Avatar } from '@stardust-ui/react'

const AvatarExampleShorthand = () => (
<div style={{ background: 'white' }}>
<div>
<Avatar name="John Doe" />
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react'
import { Avatar } from '@stardust-ui/react'

const AvatarExampleExcludedInitialsShorthand = () => (
<div>
<Avatar name="John Doe (Software Developer)" status="Available" />
&emsp;
<Avatar name="John Doe {Software Developer}" status="Available" />
&emsp;
<Avatar name="John Doe [Software Developer]" status="Available" />
&emsp;
<Avatar name="John A B Doe" status="Available" />
</div>
)

export default AvatarExampleExcludedInitialsShorthand
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import { Avatar } from '@stardust-ui/react'

const getInitials = name => name.split(' ').map(word => `${word[0]}.`)

const AvatarExampleGetInitialsShorthand = () => (
<Avatar status="Available" name="John Doe" getInitials={getInitials} />
)

export default AvatarExampleGetInitialsShorthand
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import { Avatar } from '@stardust-ui/react'

const AvatarExamplePresenceIndicatorCustomizationShorthand = () => (
<Avatar
src="/public/images/avatar/small/matt.jpg"
alt="Profile picture of Matt"
status="Available"
variables={{ presenceIndicatorBackground: '#d3d3d3' }}
/>
)

export default AvatarExamplePresenceIndicatorCustomizationShorthand
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import { Avatar } from '@stardust-ui/react'
const AvatarExampleSizeShorthand = () =>
_.times(10, i => {
const size = i + 1

return (
<div style={{ background: 'white' }}>
<Avatar
key={size}
size={size}
src="/public/images/avatar/small/matt.jpg"
status="Available"
/>
<div key={size}>
<Avatar size={size} src="public/images/avatar/small/matt.jpg" status="Available" />
&emsp;
<Avatar size={size} name="John Doe" status="Available" />
&emsp;
<Avatar size={size} src="public/images/avatar/small/matt.jpg" />
</div>
)
})
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
import { Avatar } from '@stardust-ui/react'

const AvatarExampleSrc = () => <Avatar src="public/images/avatar/small/matt.jpg" />

export default AvatarExampleSrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,21 @@ import React from 'react'
import { Avatar } from '@stardust-ui/react'

const AvatarExampleStatusShorthand = () => (
<div style={{ background: 'white' }}>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="Available"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="Busy"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="DoNotDisturb"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="Away"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="BeRightBack"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="Offline"
style={{ marginRight: '15px' }}
/>
<Avatar
src="/public/images/avatar/small/matt.jpg"
status="PresenceUnknown"
style={{ marginRight: '15px' }}
/>
<div>
<Avatar src="public/images/avatar/small/matt.jpg" status="Available" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="Busy" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="DoNotDisturb" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="Away" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="BeRightBack" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="Offline" />
&emsp;
<Avatar src="public/images/avatar/small/matt.jpg" status="PresenceUnknown" />
&emsp;
</div>
)

Expand Down
15 changes: 15 additions & 0 deletions docs/src/examples/components/Avatar/Variations/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ const Variations = () => (
description="An Avatar can have initials shown from the name prop, if no image is provided"
examplePath="components/Avatar/Variations/AvatarExampleName"
/>
<ComponentExample
title="Excluded Initials"
description="Avatar initials exclude content in parens, braces, and brackets, as well as all middle names."
examplePath="components/Avatar/Variations/AvatarExampleExcludedInitials"
/>
<ComponentExample
title="Get initials"
description="An Avatar can be provided with custom logic for generating the initials shown in the label."
examplePath="components/Avatar/Variations/AvatarExampleGetInitials"
/>
<ComponentExample
title="Presence indicator customization"
description="The presence indicator inside the Avatar can be customize to show different background."
examplePath="components/Avatar/Variations/AvatarExamplePresenceIndicatorCustomization"
/>
<ComponentExample
title="Size"
description="An Avatar can have different sizes."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Icon } from '@stardust-ui/react'

const IconExampleSize = () => (
<div>
<Icon name="home" size="micro" />
<Icon name="home" size="mini" />
<Icon name="home" size="tiny" />
<Icon name="home" size="small" />
Expand Down
74 changes: 43 additions & 31 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Avatar extends UIComponent<any, any> {

static displayName = 'Avatar'

static handledProps = ['alt', 'as', 'className', 'name', 'size', 'src', 'status']
static handledProps = ['alt', 'as', 'className', 'getInitials', 'name', 'size', 'src', 'status']

static rules = avatarRules

Expand Down Expand Up @@ -51,10 +51,34 @@ class Avatar extends UIComponent<any, any> {
'Offline',
'PresenceUnknown',
]),

/** Custom method for generating the initials from the name property, shown in the avatar if there is no image provided. */
getInitials: PropTypes.func,
}

static defaultProps = {
size: 5,
getInitials(name: string) {
if (!name) {
return ''
}

const reducedName = name
.replace(/\s*\(.*?\)\s*/g, ' ')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit worrying about performance implications of this - in general, we could have a linear complexity algorithm to achieve the same goal, while currently, because of regexp, we would use an algorithm of polynomial complexity (cubic at best). Taking the following things into account:

  • this is a logic that could be called quite often, on component's rendering
  • it could be the case that quite long string will be provided to the component, maybe even accidentally by setting wrong string variable as a value
<Avatar name={someWrongVariableWithLongLongText} ... />

I would rather suggest to address this issue by introducing linear algorithm for handling this aspect and not introduce possibility for bottlenecks that could surprise client of the library.

So, maybe we should create an issue and address it by means of dedicated PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, maybe we should create an issue and address it by means of dedicated PR

👍 to separate PR. would be good to see data before making changes.

.replace(/\s*{.*?}\s*/g, ' ')
.replace(/\s*\[.*?]\s*/g, ' ')

const initials = reducedName
.split(' ')
.filter(item => item !== '')
.map(name => name.charAt(0))
.reduce((accumulator, currentValue) => accumulator + currentValue)

if (initials.length > 2) {
return initials.charAt(0) + initials.charAt(initials.length - 1)
}
return initials
},
}

static statusToIcon = {
Expand Down Expand Up @@ -89,55 +113,43 @@ class Avatar extends UIComponent<any, any> {
}

renderComponent({ ElementType, classes, rest }) {
const { src, alt, name, status } = this.props
const { src, alt, name, status, getInitials, size } = this.props
const { icon = '', color = '' } = Avatar.statusToIcon[status] || {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to not forget - there is a problem here that colors are defined based on status, and thus

  • there is no way to customize these colors by theming
  • there is no way to decouple Avatar component from the 'presenceStatus' concept - while status aspect of Avatar could be seen as something more general, not about just providing 'presence' status - it could be about providing 'role' status of the person, as a simple example.

Both these issues should be addressed by means of dedicated PRs - there is a corresponding issue created to track this work: #52

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! Will try to create issues for the other things that are not part of this PR


const iconVariables = {
color: 'white',
backgroundColor: color,
}

return (
<ElementType {...rest} className={classes.root}>
{src ? (
<Image className={classes.imageAvatar} avatar src={src} alt={alt} title={name} />
) : (
<Label
className={classes.avatarLabel}
className={classes.avatarNameContainer}
as="div"
content={this.getInitials(name)}
content={getInitials(name)}
variables={{ padding: '0px' }}
circular
title={name}
/>
)}
{status && (
<span className={classes.presenceSpan}>
<Label
className={classes.presenceIconLabel}
as="div"
variables={{ padding: '0px' }}
style={{ background: color }}
<div className={classes.presenceIndicatorWrapper}>
<Icon
className={classes.presenceIndicator}
size={size < 4 ? 'micro' : size < 6 ? 'mini' : 'tiny'}
circular
title={name}
>
<Icon
size="mini"
name={icon}
color="white"
style={avatarRules.presenceIcon()}
title={status}
/>
</Label>
</span>
name={icon}
variables={iconVariables}
title={status}
/>
</div>
)}
</ElementType>
)
}

getInitials(name: string): string {
if (!name) {
return ''
}
const names = name.split(' ')
return names
.map(name => (name.length ? name.charAt(0) : ''))
.reduce((accumulator, currentValue) => accumulator + currentValue)
}
}

export default Avatar
Loading