Skip to content

Commit

Permalink
Merge pull request #6902 from Sage/FE-6752_video-killed-the-loader-star
Browse files Browse the repository at this point in the history
feat(loader-star): create new loader-star component - FE-6752
  • Loading branch information
DipperTheDan authored Aug 27, 2024
2 parents 27d5cdb + 5ffe0e4 commit 4833d68
Show file tree
Hide file tree
Showing 19 changed files with 563 additions and 0 deletions.
19 changes: 19 additions & 0 deletions playwright/components/loader-star/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Page } from "@playwright/test";
import {
LOADER_STAR_HIDDEN_LABEL,
LOADER_STAR_SVG,
LOADER_STAR_VISIBLE_LABEL,
LOADER_STAR_WRAPPER,
} from "./locators";

// component preview locators
export const loaderStarWrapper = (page: Page) =>
page.locator(LOADER_STAR_WRAPPER);

export const loaderStarSvg = (page: Page) => page.locator(LOADER_STAR_SVG);

export const loaderStarHiddenLabel = (page: Page) =>
page.locator(LOADER_STAR_HIDDEN_LABEL);

export const loaderStarVisibleLabel = (page: Page) =>
page.locator(LOADER_STAR_VISIBLE_LABEL);
4 changes: 4 additions & 0 deletions playwright/components/loader-star/locators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const LOADER_STAR_WRAPPER = '[data-component="loader-star"]';
export const LOADER_STAR_SVG = '[data-component="star"]';
export const LOADER_STAR_VISIBLE_LABEL = '[data-role="visible-label"]';
export const LOADER_STAR_HIDDEN_LABEL = '[data-role="hidden-label"]';
8 changes: 8 additions & 0 deletions src/components/loader-star/components.test-pw.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import LoaderStar, { LoaderStarProps } from "./loader-star.component";

const DefaultLoaderStar = (props: LoaderStarProps) => {
return <LoaderStar {...props} />;
};

export default DefaultLoaderStar;
2 changes: 2 additions & 0 deletions src/components/loader-star/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default } from "./loader-star.component";
export type { LoaderStarProps } from "./loader-star.component";
48 changes: 48 additions & 0 deletions src/components/loader-star/internal/star.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from "react";

import {
GradientStopBottom,
GradientStopTop,
StyledLoaderStarContainer,
StyledStarSVG,
} from "./star.style";

interface StarProps {
starContainerClassName: "star-1" | "star-2" | "star-3";
gradientId: "gradient1" | "gradient2" | "gradient3";
}

const Star = ({
starContainerClassName,
gradientId,
}: StarProps): JSX.Element => {
return (
<StyledLoaderStarContainer
data-component="star"
role="presentation"
className={starContainerClassName}
>
<StyledStarSVG
className="ai-star-svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 217 216"
>
<path
className="ai-star-path"
fill="#000"
fillRule="evenodd"
d="M108.502 215.994c-.166.006-.334.006-.502.006-7.218 0-11.975-3.217-15.497-8.335-4.396-5.656-7.56-13.591-10.338-21.896l-.597-1.807-.667-2.063-.91-2.87-1.225-3.904c-1.831-5.82-3.65-11.42-5.751-16.135-1.456-2.661-3.075-5.078-4.921-7.146-.356-.391-.72-.777-1.094-1.156-4.054-4.038-9.808-7.093-16.262-9.726-14.49-4.937-33.33-8.698-43.486-17.634C2.766 119.712 0 114.918 0 108l.003-.413c.108-6.697 2.852-11.372 7.25-14.916 10.155-8.935 28.995-12.696 43.485-17.633C57.192 72.405 62.946 69.35 67 65.312c.373-.38.738-.765 1.094-1.156 1.846-2.068 3.465-4.485 4.922-7.145 2.567-5.764 4.713-12.849 6.976-20.04l.91-2.87.666-2.063.338-1.028c2.84-8.586 6.063-16.843 10.598-22.675C95.954 3.32 100.592.13 107.57.004L108 0c.168 0 .336 0 .502.006L109 0l.405.003c6.999.119 11.645 3.316 15.102 8.347 5.071 6.529 8.5 16.09 11.592 25.75l.335 1.054 2.362 7.501c1.645 5.178 3.304 10.125 5.19 14.358 1.456 2.66 3.074 5.075 4.92 7.142.356.392.72.778 1.094 1.157 4.054 4.038 9.808 7.093 16.262 9.726 14.49 4.937 33.33 8.698 43.486 17.634C214.234 96.288 217 101.082 217 108c0 6.918-2.766 11.712-7.252 15.328-10.156 8.936-28.996 12.697-43.486 17.634-6.454 2.633-12.208 5.688-16.262 9.726-.373.38-.738.765-1.094 1.157-1.846 2.067-3.464 4.482-4.92 7.142-1.886 4.233-3.545 9.18-5.19 14.358l-2.362 7.5-.335 1.054c-3.091 9.66-6.521 19.222-11.592 25.751-3.524 5.127-8.282 8.35-15.507 8.35l-.498-.006Z"
/>
<defs>
<linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="100%">
<GradientStopTop offset="0%" />
<GradientStopBottom offset="100%" />
</linearGradient>
</defs>
</StyledStarSVG>
</StyledLoaderStarContainer>
);
};

Star.displayName = "Star";
export default Star;
134 changes: 134 additions & 0 deletions src/components/loader-star/internal/star.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import styled, { keyframes } from "styled-components";

const animateStar = keyframes`
0% {
transform: translate3d(0px, 0px, 0px) scale(0.3);
opacity: 0;
}
10% {
transform: translate3d(0px, 0px, 0px) scale(0.3);
opacity: 0;
}
20% {
transform: translate3d(0px, 0px, 0px) scale(0.6);
opacity: 1;
}
35% {
transform: translate3d(0px, 0px, 0px) scale(0.6);
opacity: 1;
}
55% {
transform: translate3d(16px, -12px, 0px) scale(1.4);
opacity: 1;
}
60% {
transform: translate3d(16px, -12px, 0px) scale(1.4);
opacity: 1;
}
90% {
transform: translate3d(0px, -24px, 0px) scale(0.8);
opacity: 1;
}
100% {
transform: translate3d(0px, -24px, 0px) scale(0.6);
opacity: 0;
}
`;

const animateStopTop = keyframes`
0% { stop-color: #13a038; }
10% { stop-color: #13a038; }
50% { stop-color: #0092db; }
90% { stop-color: #8f49fe; }
100% { stop-color: #8f49fe; }
`;

const animateStopBottom = keyframes`
0% { stop-color: #13a038; }
10% { stop-color: #13a038; }
50% { stop-color: #13a038; }
90% { stop-color: #0092db; }
100% { stop-color: #0092db; }
`;

const time = "3s";

export const StyledStarSVG = styled.svg`
animation: ${animateStar} ${time} ease-in-out forwards infinite;
height: var(--sizing200);
opacity: 0;
width: var(--sizing200);
`;

export const GradientStopTop = styled.stop`
animation: ${animateStopTop} ${time} ease-in-out forwards infinite;
`;

export const GradientStopBottom = styled.stop`
animation: ${animateStopBottom} ${time} ease-in-out forwards infinite;
`;

export const StyledLoaderStarContainer = styled.div`
bottom: 0;
height: var(--sizing200);
left: 0;
position: absolute;
width: var(--sizing200);
&.star-1 {
.ai-star-path {
fill: url(#gradient1);
}
${StyledStarSVG} {
animation-delay: -2s;
}
#gradient1 {
${GradientStopTop} {
animation-delay: -2s;
}
${GradientStopBottom} {
animation-delay: -2s;
}
}
}
&.star-2 {
.ai-star-path {
fill: url(#gradient2);
}
${StyledStarSVG} {
animation-delay: -1s;
}
#gradient2 {
${GradientStopTop} {
animation-delay: -1s;
}
${GradientStopBottom} {
animation-delay: -1s;
}
}
}
&.star-3 {
.ai-star-path {
fill: url(#gradient3);
}
${StyledStarSVG} {
animation-delay: 0s;
}
#gradient3 {
${GradientStopTop} {
animation-delay: 0s;
}
${GradientStopBottom} {
animation-delay: 0s;
}
}
}
`;
29 changes: 29 additions & 0 deletions src/components/loader-star/loader-star-test.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import Box from "../box";
import LoaderStar, { LoaderStarProps } from ".";

export default {
title: "Loader Star/Test",
includeStories: ["Default"],
parameters: {
info: { disable: true },
chromatic: {
disableSnapshot: true,
},
},
argTypes: {
loaderStarLabel: {
control: {
type: "text",
},
},
},
};

export const Default = (props: Partial<LoaderStarProps>) => (
<Box m={3} width="100%" height="200px">
<LoaderStar {...props} />
</Box>
);

Default.storyName = "default";
63 changes: 63 additions & 0 deletions src/components/loader-star/loader-star.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from "react";
import tagComponent, {
TagProps,
} from "../../__internal__/utils/helpers/tags/tags";
import {
StyledLoaderStarWrapper,
StyledLabel,
StyledStars,
} from "./loader-star.style";
import useLocale from "../../hooks/__internal__/useLocale";
import useMediaQuery from "../../hooks/useMediaQuery";
import Star from "./internal/star.component";
import Typography from "../typography";

export interface LoaderStarProps extends Omit<TagProps, "data-component"> {
/**
* The loaderStarLabel prop allows a specific label to be set.
* This label will be present if the user has `reduce-motion` enabled and will also be available to assistive technologies.
* By default the label will be `Loading...`.
*/
loaderStarLabel?: string;
}
const LoaderStar = ({
loaderStarLabel,
...rest
}: LoaderStarProps): JSX.Element => {
const locale = useLocale();

const reduceMotion = !useMediaQuery(
"screen and (prefers-reduced-motion: no-preference)"
);

const label = (
<StyledLabel data-role="visible-label" variant="span" fontWeight="500">
{loaderStarLabel || locale.loaderStar.loading()}
</StyledLabel>
);

return (
<StyledLoaderStarWrapper
role="status"
{...tagComponent("loader-star", rest)}
>
{reduceMotion ? (
label
) : (
<>
<StyledStars>
<Star starContainerClassName="star-1" gradientId="gradient1" />
<Star starContainerClassName="star-2" gradientId="gradient2" />
<Star starContainerClassName="star-3" gradientId="gradient3" />
</StyledStars>
<Typography data-role="hidden-label" variant="span" screenReaderOnly>
{loaderStarLabel || locale.loaderStar.loading()}
</Typography>
</>
)}
</StyledLoaderStarWrapper>
);
};

LoaderStar.displayName = "LoaderStar";
export default LoaderStar;
56 changes: 56 additions & 0 deletions src/components/loader-star/loader-star.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Meta, ArgTypes, Canvas } from "@storybook/blocks";
import TranslationKeysTable from "../../../.storybook/utils/translation-keys-table";

import * as LoaderStarStories from "./loader-star.stories";

<Meta of={LoaderStarStories} />

# Loader Star

Use the Loader Star component to let users know a task or loading data is still in progress.

## Contents

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

## Quick Start

Import `LoaderStar` into the project.

```javascript
import LoaderStar from "carbon-react/lib/components/loader-star";
```

## Examples

### Default

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

<Canvas of={LoaderStarStories.Default} />

## Props

### Loader Star

<ArgTypes of={LoaderStarStories} />

## Translation keys

The following keys are available to override the translations for this component by passing in a custom locale object
to the [i18nProvider](../?path=/docs/documentation-i18n--docs).

<TranslationKeysTable
translationData={[
{
name: "loaderStar.loading",
description:
"An accessible name for `LoaderStar`. This will also be used as alternative text to replace the loading animation - if the user requests for minimal motion-based animation (via their OS accessibility settings).",
type: "func",
returnType: "string",
},
]}
/>
Loading

0 comments on commit 4833d68

Please sign in to comment.