-
-
Notifications
You must be signed in to change notification settings - Fork 113
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
feat: implement 'LoadingShape' component #1866
Changes from all commits
69d5e6f
b9f2e89
80b3d0e
1cb2713
b682fe1
40df08b
056f6d5
1166ed9
b6c67e4
ab5f907
5d31d50
4cb2c13
9c37430
5929055
5fc757f
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 |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React from 'react'; | ||
import { mount } from 'enzyme'; | ||
import LoadingShape from '../'; | ||
import { StyledImageIcon, StyledAvatarIcon } from '../styled'; | ||
|
||
describe('<LoadingShape', () => { | ||
it('should have "rounded-rect" as default shape', () => { | ||
const component = mount(<LoadingShape />); | ||
expect(component.prop('shape')).toBe('rounded-rect'); | ||
}); | ||
|
||
it('should render the image icon when variant is "image"', () => { | ||
const component = mount(<LoadingShape shape="square" variant="image" />); | ||
expect(component.find(StyledImageIcon).length).toBe(1); | ||
}); | ||
|
||
it('should render the user icon when variant is "avatar"', () => { | ||
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. Similar blocks of code found in 2 locations. Consider refactoring. |
||
const component = mount(<LoadingShape shape="square" variant="avatar" />); | ||
expect(component.find(StyledAvatarIcon).length).toBe(1); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const AvatarIcon = props => { | ||
const { className, style } = props; | ||
return ( | ||
<svg className={className} style={style} viewBox="0 0 16 15"> | ||
<g id="pages" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd"> | ||
<g | ||
id="LoadingShape" | ||
transform="translate(-17.000000, -26.000000)" | ||
fill="currentColor" | ||
fillRule="nonzero" | ||
> | ||
<path | ||
d="M25.068222,36.5848519 C27.4635119,36.6218105 29.6594293,37.459896 31.510255,39.0703466 L31.798535,39.3297809 C31.8788598,39.4037189 31.923862,39.4516656 31.9669085,39.5201038 C32.115079,39.7551597 32.0895537,40.0227671 31.894073,40.2207242 C31.6962266,40.4210631 31.4265204,40.4461339 31.1906602,40.2934083 C31.1497529,40.2669957 31.1173204,40.2421601 31.0766838,40.2064948 L30.969131,40.1076769 C29.1418644,38.4358698 26.9952296,37.6405856 24.5436151,37.7328582 C22.4131652,37.8130139 20.5342407,38.5853842 18.9237442,40.0339916 L18.7420987,40.2011232 L18.700019,40.2371933 L18.700019,40.2371933 C18.4537878,40.4424112 18.1589643,40.447963 17.9235165,40.2262262 C17.6821833,39.9986643 17.6936848,39.6247126 17.9507826,39.3975206 L18.4165209,38.9857613 L18.6515606,38.7855074 L18.8565771,38.6210429 L19.0579085,38.4715087 C20.702822,37.2944139 22.5314859,36.6802027 24.6595598,36.5946968 L25.0621105,36.5848519 L25.068222,36.5848519 Z M24.9041939,26.7500005 C27.1467628,26.754525 28.9473281,28.5637448 28.9433061,30.8082829 C28.9392532,33.0282033 27.1203557,34.8282985 24.8857994,34.8256139 C22.6793483,34.8229141 20.8623915,32.9977879 20.8678499,30.7898076 C20.8731866,28.6268271 22.5766456,26.8558857 24.7035846,26.7545685 L24.9041939,26.7500005 Z M24.9062395,27.8827433 C23.3222486,27.8773031 22.0046832,29.18513 22.0013536,30.7656886 C21.998043,32.3751983 23.28938,33.6846464 24.8843891,33.691083 C26.4946751,33.6974327 27.8010762,32.4100083 27.8097095,30.8095749 C27.8181812,29.1951631 26.5219712,27.8884263 24.9062395,27.8827433 Z" | ||
id="Combined-Shape" | ||
/> | ||
</g> | ||
</g> | ||
</svg> | ||
); | ||
}; | ||
|
||
AvatarIcon.propTypes = { | ||
className: PropTypes.string, | ||
style: PropTypes.object, | ||
}; | ||
|
||
AvatarIcon.defaultProps = { | ||
className: undefined, | ||
style: undefined, | ||
}; | ||
|
||
export default AvatarIcon; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const ImageIcon = props => { | ||
const { className, style } = props; | ||
return ( | ||
<svg viewBox="0 0 37 32" className={className} style={style}> | ||
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. Similar blocks of code found in 2 locations. Consider refactoring. |
||
<g id="components" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd"> | ||
<g | ||
id="LoadingShape" | ||
transform="translate(-703.000000, -1054.000000)" | ||
fill="currentColor" | ||
fillRule="nonzero" | ||
> | ||
<g id="Group-18" transform="translate(697.000000, 1044.000000)"> | ||
<path | ||
d="M18.0666502,21.5128497 L27.1441111,33.3756385 C28.0269375,34.5294218 29.5699898,34.6275853 30.5912767,33.5938869 L32.8119632,31.3451538 C33.8324441,30.3114554 35.3360054,30.4394387 36.1688635,31.629167 L41.9192438,39.843144 C42.7504901,41.0346453 42.2490344,42 40.7962473,42 L7.70049162,42 C6.24770458,42 5.60069613,40.9488933 6.25560279,39.6521362 L15.2830954,21.7715564 C15.9371961,20.4749605 17.1838238,20.3592275 18.0666502,21.5128497 Z M30.9333175,10 C33.8379245,10 36.1935253,12.355762 36.1935253,15.2602077 C36.1935253,18.1646535 33.8377633,20.5204155 30.9333175,20.5204155 C28.0279047,20.5204155 25.6731098,18.1646535 25.6731098,15.2602077 C25.6731098,12.355762 28.0279047,10 30.9333175,10 Z" | ||
id="Combined-Shape" | ||
/> | ||
</g> | ||
</g> | ||
</g> | ||
</svg> | ||
); | ||
}; | ||
|
||
ImageIcon.propTypes = { | ||
className: PropTypes.string, | ||
style: PropTypes.object, | ||
}; | ||
|
||
ImageIcon.defaultProps = { | ||
className: undefined, | ||
style: undefined, | ||
}; | ||
|
||
export default ImageIcon; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { BaseProps } from '../types'; | ||
|
||
export interface LoadingShapeProps extends BaseProps { | ||
variant?: 'solid' | 'image' | 'avatar'; | ||
shape?: 'circle' | 'rect' | 'rounded-rect' | 'square'; | ||
} | ||
|
||
export default function(props: LoadingShapeProps): JSX.Element | null; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React, { useEffect, useRef } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import RenderIf from '../RenderIf'; | ||
import { | ||
StyledShapeContainer, | ||
StyledLoadingShape, | ||
StyledImageIcon, | ||
StyledAvatarIcon, | ||
} from './styled'; | ||
|
||
HellWolf93 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** | ||
* LoadingShape can be used to display a placeholder where content | ||
* is being loaded asynchronously. | ||
*/ | ||
const LoadingShape = props => { | ||
const { className, style, shape, variant } = props; | ||
const shapeRef = useRef(); | ||
const isImage = variant === 'image'; | ||
const isAvatar = variant === 'avatar'; | ||
|
||
useEffect(() => { | ||
const el = shapeRef.current; | ||
if (shape === 'square' || shape === 'circle') { | ||
el.style.width = `${el.offsetHeight}px`; | ||
} else { | ||
el.style.width = '100%'; | ||
} | ||
}); | ||
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. can we use an array of dependencies here? with the shape prop, thus it will run only when the shape prop changes |
||
|
||
return ( | ||
<StyledShapeContainer className={className} style={style}> | ||
<StyledLoadingShape shape={shape} variant={variant} ref={shapeRef}> | ||
yvmunayev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<RenderIf isTrue={isImage}> | ||
<StyledImageIcon shape={shape} /> | ||
</RenderIf> | ||
<RenderIf isTrue={isAvatar}> | ||
<StyledAvatarIcon shape={shape} /> | ||
</RenderIf> | ||
</StyledLoadingShape> | ||
</StyledShapeContainer> | ||
); | ||
}; | ||
|
||
LoadingShape.propTypes = { | ||
/** A CSS class for the outer element, in addition to the component's base classes. */ | ||
className: PropTypes.string, | ||
/** An object with custom style applied to the outer element. */ | ||
style: PropTypes.object, | ||
/** The shape of the loading placeholder */ | ||
shape: PropTypes.oneOf(['circle', 'rect', 'rounded-rect', 'square']), | ||
/** The variant of the loading placeholder */ | ||
variant: PropTypes.oneOf(['solid', 'image', 'avatar']), | ||
}; | ||
|
||
LoadingShape.defaultProps = { | ||
className: undefined, | ||
style: undefined, | ||
shape: 'rounded-rect', | ||
variant: 'solid', | ||
}; | ||
|
||
export default LoadingShape; |
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.
Similar blocks of code found in 2 locations. Consider refactoring.