Skip to content
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

Merged
merged 15 commits into from
Oct 4, 2020
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
34 changes: 12 additions & 22 deletions assets/images/componentsThumbs/LoadingShape.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions src/components/LoadingShape/__test__/loadingShape.spec.js
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"', () => {
Copy link

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.

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"', () => {
Copy link

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.

const component = mount(<LoadingShape shape="square" variant="avatar" />);
expect(component.find(StyledAvatarIcon).length).toBe(1);
});
});
35 changes: 35 additions & 0 deletions src/components/LoadingShape/icons/avatar.js
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;
37 changes: 37 additions & 0 deletions src/components/LoadingShape/icons/image.js
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}>
Copy link

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.

<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;
8 changes: 8 additions & 0 deletions src/components/LoadingShape/index.d.ts
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;
62 changes: 62 additions & 0 deletions src/components/LoadingShape/index.js
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%';
}
});

Choose a reason for hiding this comment

The 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;
Loading