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

TUI-90: new loader component #390

Merged
merged 2 commits into from
Oct 8, 2024
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: 1 addition & 1 deletion lib/index.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/index.css.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.css.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/tyk-ui.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tyk-technologies/tyk-ui",
"version": "4.4.2",
"version": "4.4.3",
"description": "Tyk UI - ui reusable components",
"main": "src/index.js",
"scripts": {
Expand Down
141 changes: 97 additions & 44 deletions src/components/Loader/Loader.css
Original file line number Diff line number Diff line change
@@ -1,73 +1,126 @@
:root {
--loader-size: 16px;
--loader-color: var(--color-primary-base);
}

.tyk-loading__wrapper {
background: rgba(255 255 255 / 60%);
position: absolute;
inset: 0;
z-index: 99;
}

.loader-wrapper {
min-block-size: 100px;
position: relative;
}

.loading {
position: absolute;
inset-block-start: calc(50% - var(--spacing-sm));
inset-inline-start: 50%;
inline-size: var(--loader-size);
block-size: var(--loader-size);
box-sizing: border-box;

&.absolute {
position: absolute;
inset-inline-start: calc(50% - var(--loader-size) / 2);
inset-block-start: calc(50% - var(--loader-size) / 2);
}

&.relative {
inset-inline-start: auto;
padding: 25px;
position: relative;
text-align: center;
inset-block-start: auto;
inline-size: 100%;
inset-inline-start: auto;
margin-inline: auto;
}
}

.loading-bar {
display: inline-block;
inline-size: 4px;
block-size: var(--spacing-md);
border-radius: 4px;
animation: loading 1s ease-in-out infinite;
margin-inline-start: 2px;
}
.loader-type-circular {
--loader-thickness: calc(var(--loader-size) / 6);

.loading-bar:nth-child(1) {
animation-delay: 0;
background-color: var(--color-primary-base);
opacity: 1;
}
animation: loader-spin 1.5s linear infinite;

&::before {
content: '';
position: absolute;
inset: 0;
background-color: var(--loader-color);
inline-size: 100%;
padding: var(--loader-thickness);
border-radius: 50%;
mask:
conic-gradient(#0000, #000) subtract,
linear-gradient(#000 0 0) content-box;
box-sizing: border-box;
}

&::after {
content: '';
position: absolute;
inline-size: var(--loader-thickness);
background: var(--loader-color);
aspect-ratio: 1;
inset-block-start: 0;
inset-inline-start: calc(50% - var(--loader-thickness) / 2);
border-radius: 50%;
}

&.loader-size-small {
--loader-size: 16px;
}

.loading-bar:nth-child(2) {
animation-delay: 0.09s;
background-color: var(--color-primary-base);
opacity: 0.80;
&.loader-size-big {
--loader-size: 80px;
}
}

.loading-bar:nth-child(3) {
animation-delay: .18s;
background-color: var(--color-primary-base);
opacity: 0.60;
@keyframes loader-spin {
to {
transform: rotate(1turn);
}
}

.loading-bar:nth-child(4) {
animation-delay: .27s;
background-color: var(--color-primary-base);
opacity: 0.40;
.loader-type-linear {
--height: 10px;

display: flex;
position: relative;
inline-size: 100%;
block-size: var(--height);
background-color: transparent;
border-radius: calc(var(--height) / 2);
border: 2px solid var(--color-secondary-base);
color: white;
justify-content: center;
align-items: center;

&::before {
content: '';
position: absolute;
block-size: calc(100% - 4px);
border-radius: calc(var(--height) / 2);
background: linear-gradient(91.13deg, #03031C 14.54%, var(--color-primary-base) 92.52%, var(--color-primary-light) 107.54%);
}

&.is-loaded::before {
inset-inline-start: 2px;
inline-size: calc(100% - 4px);
}

&:not(.is-loaded)::before {
animation-name: loader-linear-animation;
animation-duration: 3s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
}

@keyframes loading {
@keyframes loader-linear-animation {
0% {
transform: scale(1);
inset-inline-start: 2px;
inline-size: 2px;
}

20% {
transform: scale(1, 2.2);
25% {
inset-inline-start: 33%;
inline-size: 33%;
}

40% {
transform: scale(1);
50% {
inset-inline-start: calc(100% - 2px);
inline-size: 0;
}
}
44 changes: 41 additions & 3 deletions src/components/Loader/Loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,58 @@ import React from 'react';
import Loader from './index';

describe('Loader', () => {
const classes = {
typeCircular: 'loader-type-circular',
typeLinear: 'loader-type-linear',
sizeBig: 'loader-size-big',
sizeSmall: 'loader-size-small',
isLoaded: 'is-loaded',
};
const selectors = {
loader: '.loading',
wrapper: '.tyk-loading__wrapper',
};

it('renders the loader component, by default with position relative and no wrapper', () => {
cy.mount(<Loader />)
.get(selectors.loader)
it('renders the loader component, by default with type circular, size big, position relative and no wrapper', () => {
cy.mount(<Loader />);

cy.get(selectors.loader)
.should('exist')
.and('have.class', classes.typeCircular)
.and('have.class', classes.sizeBig)
.and('have.css', 'position', 'relative')
.get(selectors.wrapper)
.should('not.exist');
});

it('the size of the circular loader can be small or it can be custom', () => {
cy.mount(<Loader size="small" />);

cy.get(selectors.loader)
.should('have.class', classes.sizeSmall);

const customSize = '100px';
cy.mount(<Loader size={customSize} />);

cy.get(selectors.loader)
.should('have.css', '--loader-size', customSize);
});

it('the type of the loader can be "linear"', () => {
cy.mount(<Loader type="linear" />);

cy.get(selectors.loader)
.should('have.class', classes.typeLinear);
});

it('the linear loader can be in a loaded state', () => {
cy.mount(<Loader type="linear" isLoaded />);

cy.get(selectors.loader)
.should('have.class', classes.typeLinear)
.and('have.class', classes.isLoaded);
});

it('the position can be configured', () => {
cy.mount(<Loader position="absolute" />)
.get(selectors.loader)
Expand Down
33 changes: 32 additions & 1 deletion src/components/Loader/Readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
**Circular loader**
```js
<Loader position="relative" />
<Loader />
```
**Circular loader size small**
```js
<Loader size="small" />
```
**Circular loader custom size**
```js
<Loader size="100px" />
```
A custom size can also be added from css. Just add a css class to the component (e.g. `<Loader className="my-loader" />`) and overwrite the `--loader-size` variable for that class.
```css
.loader-type-circular.my-loader {
--loader-size: 100px;
}
```
**Loader with background**
```js
<div style={{ position: 'relative' }}>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<Loader withbackground />
</div>
```

**Linear loader**
```js
<Loader type="linear" />
```
**Linear loader in the loaded state**
```js
<Loader type="linear" isLoaded />
```
29 changes: 17 additions & 12 deletions src/components/Loader/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
import React from 'react';
import PropTypes from 'prop-types';

function Loader({ className, position = 'relative', withbackground = false }) {
function Loader({
className, type = 'circular', size = 'big', position = 'relative', withbackground = false, isLoaded = false,
}) {
const isKeywordSize = ['big', 'small'].includes(size);
const classes = [
'loading',
`loader-type-${type}`,
isKeywordSize && `loader-size-${size}`,
position,
className,
isLoaded && 'is-loaded',
].filter(Boolean).join(' ');

const loader = (
<div className={classes}>
<div className="loading-bar" />
<div className="loading-bar" />
<div className="loading-bar" />
<div className="loading-bar" />
</div>
);
const loader = <div className={classes} {...(isKeywordSize ? {} : { style: { '--loader-size': size } })} />;

return withbackground
? <div className="tyk-loading__wrapper">{loader}</div>
: loader;
}

Loader.propTypes = {
/** add a class to loader */
/** Add a class to loader */
className: PropTypes.string,
/** position of loader (absolute / relative) */
/** The type of the loader (linear || circular || brand) */
type: PropTypes.string,
/** The size of the loader (small || big). Only applicable to the circular loader. */
size: PropTypes.string,
/** Position of the loader (absolute || relative) */
position: PropTypes.string,
/** defines weather loader should be renders with or without background */
/** Defines whether loader should be rendered with or without background */
withbackground: PropTypes.bool,
/** Only applicable to the linear loader. Stops the animation and fills the entire bar. */
isLoaded: PropTypes.bool,
};

export default Loader;
Loading