* 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
99 lines
2.6 KiB
TypeScript
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>
|
|
);
|
|
});
|