FormatBalance.tsx 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2017-2020 @polkadot/react-query authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import BN from 'bn.js';
  5. import React, { useState } from 'react';
  6. import styled from 'styled-components';
  7. import { Compact } from '@polkadot/types';
  8. import { formatBalance } from '@polkadot/util';
  9. import { useTranslation } from './translate';
  10. interface Props {
  11. children?: React.ReactNode;
  12. className?: string;
  13. isShort?: boolean;
  14. label?: React.ReactNode;
  15. labelPost?: string;
  16. value?: Compact<any> | BN | string | null | 'all';
  17. withCurrency?: boolean;
  18. withSi?: boolean;
  19. }
  20. // for million, 2 * 3-grouping + comma
  21. const M_LENGTH = 6 + 1;
  22. const K_LENGTH = 3 + 1;
  23. function format (value: Compact<any> | BN | string, currency: string | null, withSi?: boolean, _isShort?: boolean, labelPost?: string): React.ReactNode {
  24. const [prefix, postfix] = formatBalance(value, { forceUnit: '-', withSi: false }).split('.');
  25. const isShort = _isShort || (withSi && prefix.length >= K_LENGTH);
  26. if (prefix.length > M_LENGTH) {
  27. // TODO Format with balance-postfix
  28. return `${formatBalance(value, { withUnit: !!currency })}${labelPost || ''}`;
  29. }
  30. return <>{`${prefix}${isShort ? '' : '.'}`}{!isShort && (<><span className='ui--FormatBalance-postfix'>{`000${postfix || ''}`.slice(-3)}</span></>)}{`${currency ? ` ${currency}` : ''}${labelPost || ''}`}</>;
  31. }
  32. function FormatBalance ({ children, className = '', isShort, label, labelPost, value, withCurrency = true, withSi }: Props): React.ReactElement<Props> {
  33. const { t } = useTranslation();
  34. const [currency] = useState(withCurrency ? formatBalance.getDefaults().unit : null);
  35. // labelPost here looks messy, however we ensure we have one less text node
  36. return (
  37. <div className={`ui--FormatBalance ${className}`}>
  38. {label || ''}<span className='ui--FormatBalance-value'>{
  39. value
  40. ? value === 'all'
  41. ? t<string>('everything{{labelPost}}', { replace: { labelPost } })
  42. : format(value, currency, withSi, isShort, labelPost)
  43. : `-${labelPost || ''}`
  44. }</span>{children}
  45. </div>
  46. );
  47. }
  48. export default React.memo(styled(FormatBalance)`
  49. display: inline-block;
  50. vertical-align: baseline;
  51. white-space: nowrap;
  52. * {
  53. vertical-align: baseline !important;
  54. }
  55. > label,
  56. > .label {
  57. display: inline-block;
  58. margin-right: 0.25rem;
  59. vertical-align: baseline;
  60. }
  61. .ui--FormatBalance-value {
  62. text-align: right;
  63. > .ui--FormatBalance-postfix {
  64. font-weight: 100;
  65. opacity: 0.75;
  66. vertical-align: baseline;
  67. }
  68. }
  69. .ui--Icon {
  70. margin-top: 0.25rem;
  71. margin-bottom: -0.25rem;
  72. }
  73. .ui--Icon+.ui--FormatBalance-value {
  74. margin-left: 0.375rem;
  75. }
  76. `);