/** * 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 * @author Edd * @author John */ 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 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(value: T): T | undefined { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); return ref.current; } export const FlashCell = memo(({ children, value }: FlashCellProps) => { const ref = useRef(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 ( {splitText[0]} {splitText[1]} ); });