-
Notifications
You must be signed in to change notification settings - Fork 53
chore(Box|Button|Image|Avatar): converting components with hooks #2238
Changes from all commits
327a755
cbe0c44
1dad61e
6cc8543
1deef88
ca915a1
b4453b8
76d1be4
ad41491
31f7015
b4768dd
6ff264c
78c6234
6d9c605
c0d2eb7
c065a08
643af73
77397b0
4a231df
bde4b3a
bf22378
7605698
331adcc
7786bd0
e46ab21
c31d3f4
118624d
bed3659
d67e9a7
e2108eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,34 @@ | ||
import { Accessibility } from '@fluentui/accessibility' | ||
import { | ||
getElementType, | ||
getUnhandledProps, | ||
useAccessibility, | ||
useStyles, | ||
useTelemetry, | ||
} from '@fluentui/react-bindings' | ||
import * as customPropTypes from '@fluentui/react-proptypes' | ||
import * as PropTypes from 'prop-types' | ||
import * as React from 'react' | ||
// @ts-ignore | ||
import { ThemeContext } from 'react-fela' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avatar.tsx should not refer to fela specifics directly. @jdhuntington for heads up here. We should expect the base component to simply take in a Then createComponent can abstract how classes gets injected. export const Avatar = createComponent(AvatarBase, { stuff to build `classes` attribute }); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not Fela specifics. We use this context only by historical reasons. We should use own context instead. |
||
|
||
import Image, { ImageProps } from '../Image/Image' | ||
import Label, { LabelProps } from '../Label/Label' | ||
import Status, { StatusProps } from '../Status/Status' | ||
import { WithAsProp, ShorthandValue, withSafeTypeForAs } from '../../types' | ||
import { | ||
createShorthandFactory, | ||
UIComponent, | ||
UIComponentProps, | ||
commonPropTypes, | ||
SizeValue, | ||
ShorthandFactory, | ||
} from '../../utils' | ||
WithAsProp, | ||
ShorthandValue, | ||
withSafeTypeForAs, | ||
FluentComponentStaticProps, | ||
ProviderContextPrepared, | ||
} from '../../types' | ||
import { createShorthandFactory, UIComponentProps, commonPropTypes, SizeValue } from '../../utils' | ||
|
||
export interface AvatarProps extends UIComponentProps { | ||
/** | ||
* Accessibility behavior if overridden by the user. | ||
*/ | ||
accessibility?: Accessibility | ||
accessibility?: Accessibility<never> | ||
|
||
/** Shorthand for the image. */ | ||
image?: ShorthandValue<ImageProps> | ||
|
@@ -40,87 +49,121 @@ export interface AvatarProps extends UIComponentProps { | |
getInitials?: (name: string) => string | ||
} | ||
|
||
class Avatar extends UIComponent<WithAsProp<AvatarProps>, any> { | ||
static create: ShorthandFactory<AvatarProps> | ||
|
||
static className = 'ui-avatar' | ||
const Avatar: React.FC<WithAsProp<AvatarProps>> & | ||
FluentComponentStaticProps<AvatarProps> = props => { | ||
const context: ProviderContextPrepared = React.useContext(ThemeContext) | ||
const { setStart, setEnd } = useTelemetry(Avatar.displayName, context.telemetry) | ||
setStart() | ||
|
||
const { | ||
accessibility, | ||
className, | ||
design, | ||
getInitials, | ||
label, | ||
image, | ||
name, | ||
size, | ||
status, | ||
styles, | ||
variables, | ||
} = props | ||
|
||
const getA11Props = useAccessibility(accessibility, { | ||
debugName: Avatar.displayName, | ||
rtl: context.rtl, | ||
}) | ||
const { classes, styles: resolvedStyles } = useStyles(Avatar.displayName, { | ||
className: Avatar.className, | ||
mapPropsToStyles: () => ({ size }), | ||
mapPropsToInlineStyles: () => ({ | ||
className, | ||
design, | ||
styles, | ||
variables, | ||
}), | ||
}) | ||
|
||
static displayName = 'Avatar' | ||
const ElementType = getElementType(props) | ||
const unhandledProps = getUnhandledProps(Avatar.handledProps, props) | ||
|
||
static propTypes = { | ||
...commonPropTypes.createCommon({ | ||
children: false, | ||
content: false, | ||
}), | ||
name: PropTypes.string, | ||
image: customPropTypes.itemShorthandWithoutJSX, | ||
label: customPropTypes.itemShorthand, | ||
size: customPropTypes.size, | ||
status: customPropTypes.itemShorthand, | ||
getInitials: PropTypes.func, | ||
} | ||
|
||
static defaultProps = { | ||
size: 'medium', | ||
getInitials(name: string) { | ||
if (!name) { | ||
return '' | ||
} | ||
|
||
const reducedName = name | ||
.replace(/\s*\(.*?\)\s*/g, ' ') | ||
.replace(/\s*{.*?}\s*/g, ' ') | ||
.replace(/\s*\[.*?]\s*/g, ' ') | ||
|
||
const initials = reducedName | ||
.split(' ') | ||
.filter(item => item !== '') | ||
.map(item => item.charAt(0)) | ||
.reduce((accumulator, currentValue) => accumulator + currentValue) | ||
|
||
if (initials.length > 2) { | ||
return initials.charAt(0) + initials.charAt(initials.length - 1) | ||
} | ||
return initials | ||
}, | ||
} as AvatarProps | ||
|
||
renderComponent({ accessibility, ElementType, classes, unhandledProps, styles, variables }) { | ||
const { name, status, image, label, getInitials, size } = this.props as AvatarProps | ||
|
||
return ( | ||
<ElementType {...accessibility.attributes.root} {...unhandledProps} className={classes.root}> | ||
{Image.create(image, { | ||
defaultProps: () => ({ | ||
const result = ( | ||
<ElementType {...getA11Props('root', { className: classes.root, ...unhandledProps })}> | ||
{Image.create(image, { | ||
defaultProps: () => | ||
getA11Props('image', { | ||
fluid: true, | ||
avatar: true, | ||
title: name, | ||
styles: styles.image, | ||
styles: resolvedStyles.image, | ||
}), | ||
})} | ||
{!image && | ||
Label.create(label || {}, { | ||
defaultProps: () => ({ | ||
})} | ||
{!image && | ||
Label.create(label || {}, { | ||
defaultProps: () => | ||
getA11Props('label', { | ||
content: getInitials(name), | ||
circular: true, | ||
title: name, | ||
styles: styles.label, | ||
styles: resolvedStyles.label, | ||
}), | ||
})} | ||
{Status.create(status, { | ||
defaultProps: () => ({ | ||
})} | ||
{Status.create(status, { | ||
defaultProps: () => | ||
getA11Props('status', { | ||
size, | ||
styles: styles.status, | ||
variables: { | ||
borderColor: variables.statusBorderColor, | ||
borderWidth: variables.statusBorderWidth, | ||
}, | ||
styles: resolvedStyles.status, | ||
}), | ||
})} | ||
</ElementType> | ||
) | ||
} | ||
})} | ||
</ElementType> | ||
) | ||
|
||
setEnd() | ||
|
||
return result | ||
} | ||
|
||
Avatar.className = 'ui-avatar' | ||
Avatar.displayName = 'Avatar' | ||
|
||
Avatar.defaultProps = { | ||
size: 'medium', | ||
getInitials(name: string) { | ||
if (!name) { | ||
return '' | ||
} | ||
|
||
const reducedName = name | ||
.replace(/\s*\(.*?\)\s*/g, ' ') | ||
.replace(/\s*{.*?}\s*/g, ' ') | ||
.replace(/\s*\[.*?]\s*/g, ' ') | ||
|
||
const initials = reducedName | ||
.split(' ') | ||
.filter(item => item !== '') | ||
.map(item => item.charAt(0)) | ||
.reduce((accumulator, currentValue) => accumulator + currentValue) | ||
|
||
if (initials.length > 2) { | ||
return initials.charAt(0) + initials.charAt(initials.length - 1) | ||
} | ||
return initials | ||
}, | ||
} | ||
|
||
Avatar.propTypes = { | ||
...commonPropTypes.createCommon({ | ||
children: false, | ||
content: false, | ||
}), | ||
name: PropTypes.string, | ||
image: customPropTypes.itemShorthandWithoutJSX, | ||
label: customPropTypes.itemShorthand, | ||
size: customPropTypes.size, | ||
status: customPropTypes.itemShorthand, | ||
getInitials: PropTypes.func, | ||
} | ||
Avatar.handledProps = Object.keys(Avatar.propTypes) as any | ||
|
||
Avatar.create = createShorthandFactory({ Component: Avatar, mappedProp: 'name' }) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.