Files
goodgo-platform/apps/web/components/design-system/numeric.tsx
Ho Ngoc Hai 7d6fcb4d8d feat(web): design tokens, Tailwind config, base components (TEC-3057)
- Add chart palette, motion, and z-index CSS vars to globals.css
- Replace custom theme-provider with next-themes (dark default)
- Extend tailwind.config.ts with heading fonts, spacing (row-compact,
  row-roomy, sidebar), chart colors, elevation shadows, glow shadows,
  transition timing, pill border-radius, z-index scale
- Update tick-flash animations to match design token spec (480ms)
- Add prefers-reduced-motion support for all animations
- Create base design-system components:
  Surface, SurfaceElevated, Divider, DensityProvider/useDensity,
  Numeric (VND/percent/compact formatting), Signal (up/down/neutral pill)
- Add dev-only /dev/tokens showcase route (404 in production)
- Update theme-provider tests to match next-themes integration

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-21 03:19:40 +07:00

65 lines
1.6 KiB
TypeScript

import { cn } from '@/lib/utils';
export interface NumericProps extends React.HTMLAttributes<HTMLSpanElement> {
/** The numeric value to display. */
value: number;
/** Format style. Default 'vnd'. */
format?: 'vnd' | 'percent' | 'decimal' | 'compact';
/** Number of fraction digits for percent/decimal. Default 1 for percent, 0 for vnd. */
fractionDigits?: number;
}
const vndFormatter = new Intl.NumberFormat('vi-VN', {
style: 'currency',
currency: 'VND',
maximumFractionDigits: 0,
});
const compactFormatter = new Intl.NumberFormat('vi-VN', {
notation: 'compact',
maximumFractionDigits: 1,
});
function formatValue(
value: number,
format: NumericProps['format'],
fractionDigits?: number,
): string {
switch (format) {
case 'percent':
return `${value >= 0 ? '+' : ''}${value.toFixed(fractionDigits ?? 1)}%`;
case 'decimal':
return new Intl.NumberFormat('vi-VN', {
minimumFractionDigits: fractionDigits ?? 0,
maximumFractionDigits: fractionDigits ?? 2,
}).format(value);
case 'compact':
return compactFormatter.format(value);
case 'vnd':
default:
return vndFormatter.format(value);
}
}
/**
* Numeric display — right-aligned, tabular-nums, formatted for VND/percent.
* Automatically sets `data-numeric` for global tabular-nums styling.
*/
export function Numeric({
value,
format = 'vnd',
fractionDigits,
className,
...props
}: NumericProps) {
return (
<span
data-numeric
className={cn('text-right font-mono tabular-nums', className)}
{...props}
>
{formatValue(value, format, fractionDigits)}
</span>
);
}