-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Avatar] Use variants api #40324
Merged
Merged
[Avatar] Use variants api #40324
Changes from 6 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b8992fa
wip
mnajdova ce38384
prettier
mnajdova 36df476
Merge remote-tracking branch 'upstream/master' into avatar/use-varian…
mnajdova fc09ede
Add zero-runtime example
mnajdova 9acc018
remove background from pages other than home
mnajdova 2e59037
applyDarkStyles proposal
mnajdova 9953676
fix tests
mnajdova aa72813
remove applyDarkMode from next.config.js
mnajdova 2458ed3
fixes
mnajdova cda5ce4
Trigger CI
mnajdova 906693d
lint issue
mnajdova File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import * as React from 'react'; | ||
import Avatar from '@/components/Avatar/Avatar'; | ||
import Stack from '@mui/material/Stack'; | ||
|
||
export default function Avatars() { | ||
return ( | ||
<Stack direction="row" spacing={2}> | ||
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" /> | ||
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" /> | ||
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" /> | ||
</Stack> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
272 changes: 272 additions & 0 deletions
272
apps/zero-runtime-next-app/src/components/Avatar/Avatar.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
'use client'; | ||
import * as React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import clsx from 'clsx'; | ||
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses'; | ||
import { styled } from '@mui/zero-runtime'; | ||
import { useThemeProps } from '@mui/material/styles'; | ||
/* eslint-disable-next-line no-restricted-imports */ | ||
import Person from '@mui/material/internal/svg-icons/Person'; | ||
import { getAvatarUtilityClass } from '@mui/material/Avatar'; | ||
|
||
const useUtilityClasses = (ownerState) => { | ||
const { classes, variant, colorDefault } = ownerState; | ||
|
||
const slots = { | ||
root: ['root', variant, colorDefault && 'colorDefault'], | ||
img: ['img'], | ||
fallback: ['fallback'], | ||
}; | ||
|
||
return composeClasses(slots, getAvatarUtilityClass, classes); | ||
}; | ||
|
||
const AvatarRoot = styled('div', { | ||
name: 'MuiAvatar', | ||
slot: 'Root', | ||
overridesResolver: (props, styles) => { | ||
const { ownerState } = props; | ||
|
||
return [ | ||
styles.root, | ||
styles[ownerState.variant], | ||
ownerState.colorDefault && styles.colorDefault, | ||
]; | ||
}, | ||
})(({ theme }) => ({ | ||
position: 'relative', | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
flexShrink: 0, | ||
width: 40, | ||
height: 40, | ||
fontFamily: theme.typography.fontFamily, | ||
fontSize: theme.typography.pxToRem(20), | ||
lineHeight: 1, | ||
borderRadius: '50%', | ||
overflow: 'hidden', | ||
userSelect: 'none', | ||
variants: [ | ||
{ | ||
props: { variant: 'rounded' }, | ||
style: { | ||
borderRadius: (theme.vars || theme).shape.borderRadius, | ||
}, | ||
}, | ||
{ | ||
props: { variant: 'square' }, | ||
style: { | ||
borderRadius: 0, | ||
}, | ||
}, | ||
{ | ||
props: { colorDefault: true }, | ||
style: { | ||
color: (theme.vars || theme).palette.background.default, | ||
...(theme.vars | ||
? { | ||
backgroundColor: theme.vars.palette.Avatar.defaultBg, | ||
} | ||
: { | ||
backgroundColor: theme.palette.grey[400], | ||
...theme.applyDarkStyles({ backgroundColor: theme.palette.grey[600] }), | ||
mnajdova marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}), | ||
}, | ||
}, | ||
], | ||
})); | ||
|
||
const AvatarImg = styled('img', { | ||
name: 'MuiAvatar', | ||
slot: 'Img', | ||
overridesResolver: (props, styles) => styles.img, | ||
})({ | ||
width: '100%', | ||
height: '100%', | ||
textAlign: 'center', | ||
// Handle non-square image. The property isn't supported by IE11. | ||
objectFit: 'cover', | ||
// Hide alt text. | ||
color: 'transparent', | ||
// Hide the image broken icon, only works on Chrome. | ||
textIndent: 10000, | ||
}); | ||
|
||
const AvatarFallback = styled(Person, { | ||
name: 'MuiAvatar', | ||
slot: 'Fallback', | ||
overridesResolver: (props, styles) => styles.fallback, | ||
})({ | ||
width: '75%', | ||
height: '75%', | ||
}); | ||
|
||
function useLoaded({ crossOrigin, referrerPolicy, src, srcSet }) { | ||
const [loaded, setLoaded] = React.useState(false); | ||
|
||
React.useEffect(() => { | ||
if (!src && !srcSet) { | ||
return undefined; | ||
} | ||
|
||
setLoaded(false); | ||
|
||
let active = true; | ||
const image = new Image(); | ||
image.onload = () => { | ||
if (!active) { | ||
return; | ||
} | ||
setLoaded('loaded'); | ||
}; | ||
image.onerror = () => { | ||
if (!active) { | ||
return; | ||
} | ||
setLoaded('error'); | ||
}; | ||
image.crossOrigin = crossOrigin; | ||
image.referrerPolicy = referrerPolicy; | ||
image.src = src; | ||
if (srcSet) { | ||
image.srcset = srcSet; | ||
} | ||
|
||
return () => { | ||
active = false; | ||
}; | ||
}, [crossOrigin, referrerPolicy, src, srcSet]); | ||
|
||
return loaded; | ||
} | ||
|
||
const Avatar = React.forwardRef(function Avatar(inProps, ref) { | ||
const props = useThemeProps({ props: inProps, name: 'MuiAvatar' }); | ||
const { | ||
alt, | ||
children: childrenProp, | ||
className, | ||
component = 'div', | ||
imgProps, | ||
sizes, | ||
src, | ||
srcSet, | ||
variant = 'circular', | ||
...other | ||
} = props; | ||
|
||
let children = null; | ||
|
||
// Use a hook instead of onError on the img element to support server-side rendering. | ||
const loaded = useLoaded({ ...imgProps, src, srcSet }); | ||
const hasImg = src || srcSet; | ||
const hasImgNotFailing = hasImg && loaded !== 'error'; | ||
|
||
const ownerState = { | ||
...props, | ||
colorDefault: !hasImgNotFailing, | ||
component, | ||
variant, | ||
}; | ||
|
||
const classes = useUtilityClasses(ownerState); | ||
|
||
if (hasImgNotFailing) { | ||
children = ( | ||
<AvatarImg | ||
alt={alt} | ||
srcSet={srcSet} | ||
src={src} | ||
sizes={sizes} | ||
ownerState={ownerState} | ||
className={classes.img} | ||
{...imgProps} | ||
/> | ||
); | ||
} else if (childrenProp != null) { | ||
children = childrenProp; | ||
} else if (hasImg && alt) { | ||
children = alt[0]; | ||
} else { | ||
children = <AvatarFallback ownerState={ownerState} className={classes.fallback} />; | ||
} | ||
|
||
return ( | ||
<AvatarRoot | ||
as={component} | ||
ownerState={ownerState} | ||
className={clsx(classes.root, className)} | ||
ref={ref} | ||
{...other} | ||
> | ||
{children} | ||
</AvatarRoot> | ||
); | ||
}); | ||
|
||
Avatar.propTypes /* remove-proptypes */ = { | ||
// ┌────────────────────────────── Warning ──────────────────────────────┐ | ||
// │ These PropTypes are generated from the TypeScript type definitions. │ | ||
// │ To update them, edit the d.ts file and run `pnpm proptypes`. │ | ||
// └─────────────────────────────────────────────────────────────────────┘ | ||
/** | ||
* Used in combination with `src` or `srcSet` to | ||
* provide an alt attribute for the rendered `img` element. | ||
*/ | ||
alt: PropTypes.string, | ||
/** | ||
* Used to render icon or text elements inside the Avatar if `src` is not set. | ||
* This can be an element, or just a string. | ||
*/ | ||
children: PropTypes.node, | ||
/** | ||
* Override or extend the styles applied to the component. | ||
*/ | ||
classes: PropTypes.object, | ||
/** | ||
* @ignore | ||
*/ | ||
className: PropTypes.string, | ||
/** | ||
* The component used for the root node. | ||
* Either a string to use a HTML element or a component. | ||
*/ | ||
component: PropTypes.elementType, | ||
/** | ||
* [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attributes) applied to the `img` element if the component is used to display an image. | ||
* It can be used to listen for the loading error event. | ||
*/ | ||
imgProps: PropTypes.object, | ||
/** | ||
* The `sizes` attribute for the `img` element. | ||
*/ | ||
sizes: PropTypes.string, | ||
/** | ||
* The `src` attribute for the `img` element. | ||
*/ | ||
src: PropTypes.string, | ||
/** | ||
* The `srcSet` attribute for the `img` element. | ||
* Use this attribute for responsive image display. | ||
*/ | ||
srcSet: PropTypes.string, | ||
/** | ||
* The system prop that allows defining system overrides as well as additional CSS styles. | ||
*/ | ||
sx: PropTypes.oneOfType([ | ||
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), | ||
PropTypes.func, | ||
PropTypes.object, | ||
]), | ||
/** | ||
* The shape of the avatar. | ||
* @default 'circular' | ||
*/ | ||
variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ | ||
PropTypes.oneOf(['circular', 'rounded', 'square']), | ||
PropTypes.string, | ||
]), | ||
}; | ||
|
||
export default Avatar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
This leaking on other pages would complicate our testing, so I moved it to the home page only.