vcc-ui
Version:
VCC UI is a collection of React UI Components that can be used for developing front-end applications at Volvo Car Corporation.
137 lines (116 loc) • 3.01 kB
JavaScript
import React, { useContext, useEffect, useRef, useState } from "react";
import { Block } from "../block";
import { LineTransitionContext } from "./";
import { useFela } from "react-fela";
const ActiveLineWithTransition = () => {
const [transitionFinished, setTransitionFinished] = useState(false);
const { activeIndex, itemsDimensions } = useContext(LineTransitionContext);
const [lastActiveIndex, setLastActiveIndex] = useState(activeIndex);
const activeIndicator = useRef();
const {
theme: { colors, direction }
} = useFela();
const isRtl = direction === "rtl";
const goingRight = activeIndex >= lastActiveIndex;
const onTransitionEndEvent = e => {
if (
(goingRight && e.propertyName === "width") ||
(isRtl && !goingRight && e.propertyName === "width") ||
(!goingRight && e.propertyName === "left")
) {
setTransitionFinished(true);
}
};
useEffect(() => {
if (activeIndicator && activeIndicator.current) {
activeIndicator.current.addEventListener(
transitionEndEvent,
onTransitionEndEvent
);
return () => {
activeIndicator.current.removeEventListener(
transitionEndEvent,
onTransitionEndEvent
);
};
}
});
useEffect(() => {
if (transitionFinished) {
setTransitionFinished(false);
setLastActiveIndex(activeIndex);
}
});
if (!itemsDimensions) {
return null;
}
const activeItem = itemsDimensions[activeIndex];
const prevItem = itemsDimensions[lastActiveIndex];
const getWidth = () => {
if (transitionFinished) {
return activeItem.width;
} else if (goingRight) {
return activeItem.x - prevItem.x + activeItem.width;
} else {
return prevItem.x - activeItem.x + prevItem.width;
}
};
const getX = () => {
if (transitionFinished) {
return activeItem.x;
} else if (goingRight) {
return prevItem.x;
} else {
return activeItem.x;
}
};
const width = getWidth();
const x = getX();
return (
<Block
extend={styles({
width,
x,
colors,
isRtl
})}
innerRef={activeIndicator}
/>
);
};
const transitionBezier = "ease-out";
const transitionTime = "200ms";
const styles = ({ width, x, colors: { primary }, isRtl }) => ({
position: "absolute",
bottom: 0,
zIndex: 10,
transition: `width ${transitionTime} ${transitionBezier}, ${
isRtl ? "right" : "left"
} ${transitionTime} ${transitionBezier}`,
left: x,
width,
height: 3,
background: primary
});
const createElement = type => {
return typeof document !== "undefined" && document.createElement(type);
};
const transitionEndEvent = (() => {
if (typeof document === "undefined") {
return "";
}
const el = createElement("fakeelement");
const transitions = {
transition: "transitionend",
OTransition: "oTransitionEnd",
MozTransition: "transitionend",
WebkitTransition: "webkitTransitionEnd"
};
for (let t in transitions) {
if (String(el.style[t]) !== "undefined") {
return transitions[t];
}
}
return transitions.transition;
})();
export default ActiveLineWithTransition;