Skip to content

Commit

Permalink
feat(loader-bar): create loader-bar
Browse files Browse the repository at this point in the history
  • Loading branch information
rdzielakpgs committed Aug 20, 2021
1 parent df52752 commit 11a8e79
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/components/loader/index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from "./loader";
export { default as LoaderBar } from "./loader-bar";
1 change: 1 addition & 0 deletions src/components/loader/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default } from "./loader.component";
export { default as LoaderBar } from "./loader-bar.component";
33 changes: 33 additions & 0 deletions src/components/loader/loader-bar.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import PropTypes from "prop-types";
import styledSystemPropTypes from "@styled-system/prop-types";
import tagComponent from "../../utils/helpers/tags";
import StyledLoader from "./loader.style";
import StyledLoaderBar, { InnerBar } from "./loader-bar.style";
import { filterStyledSystemMarginProps } from "../../style/utils";

const marginPropTypes = filterStyledSystemMarginProps(
styledSystemPropTypes.space
);

const LoaderBar = ({ size, ...rest }) => {
return (
<StyledLoader {...rest} {...tagComponent("loader-bar", rest)}>
<StyledLoaderBar size={size}>
<InnerBar size={size} />
</StyledLoaderBar>
</StyledLoader>
);
};

LoaderBar.defaultProps = {
size: "medium",
};

LoaderBar.propTypes = {
...marginPropTypes,
/** Size of the loader. */
size: PropTypes.oneOf(["small", "medium", "large"]),
};

export default LoaderBar;
2 changes: 2 additions & 0 deletions src/components/loader/loader-bar.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line import/prefer-default-export
export const LOADER_BAR_SIZES = ["small", "medium", "large"];
10 changes: 10 additions & 0 deletions src/components/loader/loader-bar.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { MarginProps } from "styled-system";

export interface LoaderBarProps extends MarginProps {
/** Size of the loaderBar. */
size?: "small" | "medium" | "large";
}

declare function LoaderBar(props: LoaderBarProps): JSX.Element;

export default LoaderBar;
78 changes: 78 additions & 0 deletions src/components/loader/loader-bar.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from "react";
import { mount } from "enzyme";
import StyledLoaderBar, { InnerBar } from "./loader-bar.style";
import { assertStyleMatch } from "../../__spec_helper__/test-utils";
import baseTheme from "../../style/themes/base";
import LoaderBar from "./loader-bar.component";

describe("LoaderBar", () => {
let wrapper;
it("renders component as expected", () => {
wrapper = mount(<LoaderBar />);
const innerBar = wrapper.find(InnerBar);
expect(innerBar).toBeTruthy();
});

describe("when size is not specified", () => {
beforeEach(() => {
wrapper = mount(<LoaderBar />);
});
it("renders outer bar as expected", () => {
assertStyleMatch(
{
backgroundColor: baseTheme.colors.loadingBarBackground,
width: "256px",
height: "8px",
},
wrapper.find(StyledLoaderBar)
);
});
it("renders inner bar as expected", () => {
assertStyleMatch(
{
backgroundColor: baseTheme.colors.primary,
width: "128px",
height: "8px",
},
wrapper.find(InnerBar)
);
});
});

describe("when size is set to small", () => {
beforeEach(() => {
wrapper = mount(<LoaderBar size="small" />);
});
it("applies proper width and height to outer bar", () => {
assertStyleMatch(
{ width: "256px", height: "4px" },
wrapper.find(StyledLoaderBar)
);
});

it("applies proper width and height to inner bar", () => {
assertStyleMatch(
{ width: "128px", height: "4px" },
wrapper.find(InnerBar)
);
});
});
describe("when size is set to large", () => {
beforeEach(() => {
wrapper = mount(<LoaderBar size="large" />);
});
it("applies proper width and height to outer bar", () => {
assertStyleMatch(
{ width: "256px", height: "16px" },
wrapper.find(StyledLoaderBar)
);
});

it("applies proper width and height to inner bar", () => {
assertStyleMatch(
{ width: "128px", height: "16px" },
wrapper.find(InnerBar)
);
});
});
});
65 changes: 65 additions & 0 deletions src/components/loader/loader-bar.style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import styled, { css, keyframes } from "styled-components";
import PropTypes from "prop-types";
import baseTheme from "../../style/themes/base";
import { LOADER_BAR_SIZES } from "./loader-bar.config";

const INNER_BAR_LENGTH = "128px";
const OUTER_BAR_LENGTH = "256px";

const innerBarAnimation = keyframes`
0% {
left: -${INNER_BAR_LENGTH}
}
100% {
left: ${OUTER_BAR_LENGTH}
}
`;

const StyledLoaderBar = styled.div`
${({ size, theme }) => css`
display: inline-block;
height: ${getHeight(size)};
width: ${OUTER_BAR_LENGTH};
background-color: ${theme.colors.loadingBarBackground};
overflow: hidden;
position: relative;
`}
`;

const InnerBar = styled.div`
${({ theme, size }) => css`
position: absolute;
background-color: ${theme.colors.primary};
width: ${INNER_BAR_LENGTH};
height: ${getHeight(size)}
animation: 2s ${innerBarAnimation} linear 0s infinite normal none running;
`}
`;

function getHeight(size) {
switch (size) {
case "small":
return "4px";
case "large":
return "16px";
default:
return "8px";
}
}

StyledLoaderBar.defaultProps = {
theme: baseTheme,
size: "medium",
};

InnerBar.defaultProps = {
theme: baseTheme,
size: "medium",
};

StyledLoaderBar.propTypes = {
size: PropTypes.oneOf(LOADER_BAR_SIZES),
};

export { InnerBar };
export default StyledLoaderBar;
66 changes: 55 additions & 11 deletions src/components/loader/loader.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
import { useState } from 'react';
import { Meta, Story, Preview, Props } from '@storybook/addon-docs/blocks';
import Loader from '.';
import Button from '../button';
import { useState } from "react";
import { Meta, Story, Preview, Props } from "@storybook/addon-docs/blocks";
import Loader, { LoaderBar } from ".";
import Button from "../button";
import StyledSystemProps from "../../../.storybook/utils/styled-system-props";

<Meta title="Design System/Loader" parameters={{ info: { disable: true }, chromatic: { disable: true }}} />
<Meta
title="Design System/Loader"
parameters={{ info: { disable: true }, chromatic: { disable: true } }}
/>

# Loader

Use the Loader component to let users know a task or loading data is still in progress.
Showing a Loader helps the user to understand that they should wait, rather than reload the page or abandon a process.
In general, place a Loader in the centre and middle of the page or container it relates to.
Like many Design System elements, Loaders are made of square elements. They usually take the accent colour of the product they're in.

## Contents

- [Quick Start](#quick-start)
- [Examples](#examples)
- [Props](#props)

## Quick Start

Import `Loader` into the project.

```javascript
Expand All @@ -27,6 +33,7 @@ import Loader from "carbon-react/lib/components/loader";
## Examples

### Default

This example of the Loader component demonstrates how it will appear as default.

<Preview>
Expand All @@ -36,38 +43,75 @@ This example of the Loader component demonstrates how it will appear as default.
</Preview>

### Small

This is an example of a small Loader component.

<Preview>
<Story name="small">
<Loader size='small' />
<Loader size="small" />
</Story>
</Preview>

### Large

This is an example of the large Loader component. The larger size is only used when a whole page is loading.

<Preview>
<Story name="large">
<Loader size='large' />
<Loader size="large" />
</Story>
</Preview>


### Inside Buttons

This is an example of the Loader nested inside of a Button component. When used inside a primary button the colour of the squares will be white.
To ensure that the correct styling is applied to the `Loader` component when it is nested inside of the `Button` component,
please remember to pass the `isInsideButton` prop to the `Loader` component.

<Preview>
<Story name="inside Buttons">
<Button buttonType='primary'>
<Loader isInsideButton/>
<Button buttonType="primary">
<Loader isInsideButton />
</Button>
</Story>
</Preview>

## LoaderBar

This example of the LoaderBar component demonstrates how it will appear as default.

<Preview>
<Story name="default bar">
<LoaderBar mt={2} />
</Story>
</Preview>

### Small

This is an example of a small LoaderBar component.

<Preview>
<Story name="small bar">
<LoaderBar size="small" />
</Story>
</Preview>

### Large

This is an example of a large LoaderBar component.

<Preview>
<Story name="large bar">
<LoaderBar size="large" mt={2} />
</Story>
</Preview>

## Props

### Loader
<StyledSystemProps of={Loader} noHeader margin />

<StyledSystemProps of={Loader} noHeader margin />

### LoaderBar

<Props of={LoaderBar} />
2 changes: 2 additions & 0 deletions src/components/loader/loader.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const StyledLoader = styled.div`
${margin}
text-align: center;
white-space: nowrap;
line-height: 0;
font-size: 0;
`;

StyledLoader.defaultProps = {
Expand Down
1 change: 1 addition & 0 deletions src/style/themes/aegean/aegean-theme.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default (palette) => {
withOpacity: baseWithOpacity(0.55),
hoveredTabKeyline: palette.productBlueTint(30),
disabled: palette.productBlueTint(40),
loadingBarBackground: palette.productBlueTint(70),
},

stepSequence: {
Expand Down
1 change: 1 addition & 0 deletions src/style/themes/base/base-theme.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default (palette) => {
disabled: palette.genericGreenTint(40),
whiteMix: palette.genericGreenTint(90),
withOpacity: baseWithOpacity(0.55),
loadingBarBackground: palette.genericGreenTint(70),

// generic
black: "#000000",
Expand Down
1 change: 1 addition & 0 deletions src/style/themes/mint/mint-theme.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default (palette) => {
whiteMix: palette.productGreenTint(90),
hoveredTabKeyline: palette.productGreenTint(30),
disabled: palette.productGreenTint(40),
loadingBarBackground: palette.productGreenTint(70),
},

stepSequence: {
Expand Down

0 comments on commit 11a8e79

Please sign in to comment.