Skip to content

Commit 00c2940

Browse files
committed
Add new Pulse loader
Add text util Edit Twist to use Text util for loader msg
1 parent 729609d commit 00c2940

File tree

9 files changed

+251
-17
lines changed

9 files changed

+251
-17
lines changed

src/indicators/Pulse/Pulse.scss

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@use "../../scss/variables" as defaults;
2+
3+
.pulse-bounding-box {
4+
font-size: defaults.$fontSizer;
5+
isolation: isolate;
6+
7+
.pulse-loader {
8+
color: defaults.$defaultColor;
9+
position: relative;
10+
11+
.pulse-text {
12+
color: currentColor;
13+
mix-blend-mode: difference;
14+
15+
position: absolute;
16+
top: 100%;
17+
left: 50%;
18+
transform: translateX(-50%);
19+
20+
z-index: -2;
21+
}
22+
}
23+
24+
.pulse-loader svg.rli-pulse-svg {
25+
visibility: hidden;
26+
}
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from "react";
2+
import { ComponentStory, ComponentMeta } from "@storybook/react";
3+
import { Pulse } from "./Pulse";
4+
5+
export default {
6+
title: "rli/Pulse",
7+
component: Pulse
8+
} as ComponentMeta<typeof Pulse>;
9+
10+
const Template: ComponentStory<typeof Pulse> = args => <Pulse {...args} />;
11+
12+
export const Primary = Template.bind({});
13+
14+
export const Secondary = Template.bind({});
15+
Secondary.args = {
16+
color: "#b7ac9a",
17+
text: true
18+
};
19+
20+
export const Small = Template.bind({});
21+
Small.args = {
22+
size: "small"
23+
};
24+
25+
export const Medium = Template.bind({});
26+
Medium.args = {
27+
size: "medium"
28+
};
29+
30+
export const Large = Template.bind({});
31+
Large.args = {
32+
size: "large"
33+
};

src/indicators/Pulse/Pulse.tsx

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
"use strict";
2+
3+
import React, { useRef, useEffect } from "react";
4+
5+
import { PulseProps } from "./Pulse.types";
6+
import "./Pulse.scss";
7+
import useFontsizeMapper from "../../hooks/useFontsizeMapper";
8+
import Text from "../../utils/Text";
9+
10+
const Pulse = (props: PulseProps) => {
11+
const svgPathRef = useRef<SVGPathElement>(null);
12+
13+
// Styles
14+
let styles: React.CSSProperties = Object(props?.style);
15+
16+
/* Size SETTINGS */
17+
let fontSize: string | number = useFontsizeMapper(props?.size);
18+
19+
// Setting size by specifying font-size in style attr
20+
// and modifying styles to exclude fontSize
21+
if (props?.style?.fontSize) {
22+
const { fontSize: cssFontSize, ...css } = props?.style;
23+
24+
styles = css;
25+
fontSize = cssFontSize;
26+
}
27+
28+
/* Color SETTINGS */
29+
// If Color property is a string, that is the color of all rings
30+
// If color property is an array, that is color for each rings
31+
const pulseColor: string | string[] = props?.color ?? "";
32+
const pulseColorStyles: React.CSSProperties =
33+
pulseColor instanceof Array
34+
? { ...genStyleFromColorArr(pulseColor) }
35+
: { ...genStyleFromColorStr(pulseColor) };
36+
37+
useEffect(() => {
38+
if (svgPathRef.current) {
39+
const pathEl: SVGPathElement = svgPathRef.current;
40+
const parentSvgEl: HTMLElement | null = pathEl.parentElement;
41+
const pathLength: number = pathEl.getTotalLength();
42+
console.log("SVG PATH LENGTH: ", pathLength);
43+
44+
const pathLengthRepeats = pathLength / 2;
45+
const dashArray = pathLengthRepeats * 0.94;
46+
const dashArrayGap = pathLengthRepeats * 0.06;
47+
48+
pathEl.style.strokeDasharray = `${dashArray} ${dashArrayGap}`;
49+
pathEl.style.strokeDashoffset = `${pathLength}`;
50+
parentSvgEl && (parentSvgEl.style.visibility = "visible");
51+
52+
// Trigger a layout so styles are calculated & the browser
53+
// picks up the starting position before animating
54+
pathEl.getBoundingClientRect();
55+
56+
const pulseKeyframes = new KeyframeEffect(
57+
pathEl, // element to animate
58+
[{ strokeDashoffset: `${pathLength}` }, { strokeDashoffset: `0` }],
59+
{ duration: 2000, iterations: Infinity, easing: "linear" }
60+
);
61+
62+
const pulseAnimation = new Animation(pulseKeyframes, document.timeline);
63+
64+
// Play pulse animation
65+
pulseAnimation.play();
66+
}
67+
}, []);
68+
69+
return (
70+
<span
71+
className="rli-d-i-b pulse-bounding-box"
72+
style={{ ...(fontSize && { fontSize }) }}
73+
>
74+
<span
75+
className="rli-d-i-b pulse-loader"
76+
style={{ ...pulseColorStyles, ...styles }}
77+
>
78+
{/* Original size SVG */}
79+
{/* <svg
80+
width="16em" // ratio -> 2.947368421
81+
height="5.428571429em"
82+
xmlns="http://www.w3.org/2000/svg"
83+
version="1.2"
84+
viewBox="0 0 550 190"
85+
preserveAspectRatio="xMinYMin meet"
86+
>
87+
<path
88+
ref={svgPathRef}
89+
stroke="currentColor"
90+
fill="none"
91+
strokeWidth="2"
92+
strokeLinejoin="round"
93+
d="M0 70h250q7-30 12-3t5 8 3-7 3 4 6 35 7-60 4 60 7-20s2-11 10-10 1 1 8-10l4 8c6 4 8-6 10-17s2 10 9 11h210"
94+
/>
95+
</svg> */}
96+
97+
{/* Zoomed in SVG */}
98+
<svg
99+
width="14em" // ratio -> 2.051282051
100+
height="6.825000001em"
101+
xmlns="http://www.w3.org/2000/svg"
102+
version="1.2"
103+
viewBox="0 0 400 50"
104+
preserveAspectRatio="xMinYMin meet"
105+
className="rli-pulse-svg"
106+
>
107+
<path
108+
ref={svgPathRef}
109+
stroke="currentColor"
110+
fill="none"
111+
strokeWidth="2"
112+
strokeLinejoin="round"
113+
d="M-80 70h250q7-30 12-3t5 8 3-7 3 4 6 35 7-60 4 60 7-20s2-11 10-10 1 1 8-10l4 8c6 4 8-6 10-17s2 10 9 11h210"
114+
></path>
115+
</svg>
116+
117+
<Text
118+
className="pulse-text"
119+
text={props?.text}
120+
textColor={props?.textColor}
121+
/>
122+
</span>
123+
</span>
124+
);
125+
};
126+
127+
export { Pulse };
128+
129+
function genStyleFromColorStr(
130+
colorStr: string | undefined
131+
): React.CSSProperties {
132+
colorStr = colorStr ?? "";
133+
134+
const stylesObject: any = {};
135+
136+
stylesObject["color"] = colorStr;
137+
138+
return stylesObject;
139+
}
140+
141+
function genStyleFromColorArr(colorArr: string[]): React.CSSProperties {
142+
const stylesObject: any = {};
143+
144+
// NOT supporting Individual coloring
145+
const [color] = colorArr;
146+
147+
stylesObject["color"] = color;
148+
149+
return stylesObject;
150+
}

src/indicators/Pulse/Pulse.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { CommonProps } from "../common.types";
2+
export interface PulseProps extends CommonProps {}

src/indicators/Pulse/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Pulse } from "./Pulse";

src/indicators/Twist/Twist.tsx

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React from "react";
55
import { TwistProps } from "./Twist.types";
66
import "./Twist.scss";
77
import useFontsizeMapper from "../../hooks/useFontsizeMapper";
8+
import Text from "../../utils/Text";
89

910
const Twist = (props: TwistProps) => {
1011
// Styles
@@ -47,21 +48,11 @@ const Twist = (props: TwistProps) => {
4748
<span className="blade"></span>
4849
</span>
4950

50-
<span
51-
className="rli-d-i-b rli-text-format twist-text"
52-
style={{
53-
...(props?.textColor && {
54-
color: props?.textColor,
55-
mixBlendMode: "unset"
56-
})
57-
}}
58-
>
59-
{props?.text
60-
? typeof props?.text === "string" && props?.text.length
61-
? props?.text
62-
: "loading"
63-
: null}
64-
</span>
51+
<Text
52+
className="twist-text"
53+
text={props?.text}
54+
textColor={props?.textColor}
55+
/>
6556
</span>
6657
);
6758
};
@@ -83,7 +74,7 @@ function genStyleFromColorStr(
8374
function genStyleFromColorArr(colorArr: string[]): React.CSSProperties {
8475
const stylesObject: any = {};
8576

86-
// NOT supporting Individual bubble coloring
77+
// NOT supporting Individual blade coloring
8778
const [color] = colorArr;
8879

8980
stylesObject["color"] = color;

src/indicators/common.types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
export interface CommonProps {
32
color?: string | string[];
43
size?: "small" | "medium" | "large";

src/indicators/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export * from "./Seek";
1010
export * from "./GlidingBlink";
1111
export * from "./Twist";
1212
export * from "./Slab";
13+
export * from "./Pulse";
1314

1415
export { CircularProgress as default };

src/utils/Text.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from "react";
2+
3+
interface TextProps {
4+
className?: string;
5+
text?: string | boolean;
6+
textColor?: string;
7+
}
8+
9+
const Text = (props: TextProps): JSX.Element => {
10+
const { className, text, textColor } = props;
11+
return (
12+
<span
13+
className={`rli-d-i-b rli-text-format ${className}`}
14+
style={{
15+
...(textColor && {
16+
color: textColor,
17+
mixBlendMode: "unset"
18+
})
19+
}}
20+
>
21+
{text
22+
? typeof text === "string" && text.length
23+
? text
24+
: "loading"
25+
: null}
26+
</span>
27+
);
28+
};
29+
30+
export default Text;

0 commit comments

Comments
 (0)