vega-frontend-monorepo/libs/react-helpers/src/lib/grid/flash-cell.tsx
Bartłomiej Głownia 72f94d2e6d
feat(#500): colors fixes (#512)
* feat(#500): mute price decimal places

* feat(colors): remove alpha chanel from shades of gray

* feat(colors): simplify intent colors

* feat(colors): fix intent mapping

* feat(colors): fix lint issues

* feat(colors): fix lint issues
2022-06-10 16:07:44 +01:00

99 lines
2.6 KiB
TypeScript

/**
* A component that will display a number, and when it is updated will use animation to
* highlight the direction of change. This defaults to red for downwards, and green for
* upwards.
*
* @author Matt <matt@vega.xyz>
* @author Edd <edd@vega.xyz>
* @author John <john.walley@mulberryhousesoftware.com>
*/
import { memo, useRef, useEffect } from 'react';
import { theme } from '@vegaprotocol/tailwindcss-config';
import { splitAt } from '../format';
const FLASH_DURATION = 800; // Duration of flash animation in milliseconds
export interface FlashCellProps {
/**
* The string representation of value. It can be formatted in bespoke ways,
* so we can't simply convert value
*/
children: string;
/** The numeric representation of 'children' */
value: number;
}
/**
* Given two strings, finds the index first character that has changed in string 2
*
* Used by <FlashCell /> to highlight substrings to highlight the portion of a number that has changed
* From: https://stackoverflow.com/questions/32858626/detect-position-of-first-difference-in-2-strings
*
* @param a String to diff
* @param b Second string to diff
* @return number Index of first different character, or -1
*/
export function findFirstDiffPos(a: string, b: string): number {
let i = 0;
if (a === b) return -1;
if (!a || !b) return -1;
while (a[i] === b[i]) i++;
return i;
}
/**
* Get value from previous render
*/
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T | undefined>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
export const FlashCell = memo(({ children, value }: FlashCellProps) => {
const ref = useRef<HTMLSpanElement | null>(null);
const previousLabel = usePrevious(children);
const previousValue = usePrevious(value);
const indexOfChange = previousLabel
? findFirstDiffPos(previousLabel, children)
: 0;
const splitText = splitAt(indexOfChange)(children);
if (indexOfChange !== -1 && previousValue !== undefined) {
if (value < previousValue) {
ref.current?.animate(
[
{ color: theme.colors.vega.pink },
{ color: theme.colors.vega.pink, offset: 0.8 },
{ color: 'inherit' },
],
FLASH_DURATION
);
} else if (value > previousValue) {
ref.current?.animate(
[
{ color: theme.colors.vega.green },
{ color: theme.colors.vega.green, offset: 0.8 },
{ color: 'inherit' },
],
FLASH_DURATION
);
}
}
return (
<span data-testid="flash-cell">
{splitText[0]}
<span ref={ref}>{splitText[1]}</span>
</span>
);
});