feat: make statistic component support html role and data-* and aria-* attributes (#47149)

* feat: make statistic component support html attributes

* fix: types

* chore: improve

* feat: use pickAttrs for data-* and aria-* and role
This commit is contained in:
vagusX 2024-01-26 15:27:02 +08:00 committed by GitHub
parent 119f8aaf79
commit 2aca1fff22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 9 deletions

View File

@ -0,0 +1,5 @@
import type * as React from 'react';
export type HTMLAriaDataAttributes = React.AriaAttributes & {
[key: `data-${string}`]: unknown;
} & Pick<React.HTMLAttributes<HTMLDivElement>, 'role'>;

View File

@ -9,7 +9,6 @@ import { formatCountdown } from './utils';
const REFRESH_INTERVAL = 1000 / 30;
export interface CountdownProps extends StatisticProps {
value?: valueType;
format?: string;
onFinish?: () => void;
onChange?: (value?: valueType) => void;
@ -20,7 +19,7 @@ function getTime(value?: valueType) {
}
const Countdown: React.FC<CountdownProps> = (props) => {
const { value, format = 'HH:mm:ss', onChange, onFinish } = props;
const { value, format = 'HH:mm:ss', onChange, onFinish, ...rest } = props;
const forceUpdate = useForceUpdate();
@ -63,7 +62,7 @@ const Countdown: React.FC<CountdownProps> = (props) => {
const valueRender = (node: React.ReactElement<HTMLDivElement>) =>
cloneElement(node, { title: undefined });
return <Statistic {...props} valueRender={valueRender} formatter={formatter} />;
return <Statistic {...rest} value={value} valueRender={valueRender} formatter={formatter} />;
};
export default React.memo(Countdown);

View File

@ -3,6 +3,7 @@ import type { FormatConfig, valueType } from './utils';
interface NumberProps extends FormatConfig {
value: valueType;
prefixCls?: string;
}
const StatisticNumber: React.FC<NumberProps> = (props) => {

View File

@ -1,13 +1,16 @@
import classNames from 'classnames';
import * as React from 'react';
import pickAttrs from 'rc-util/lib/pickAttrs';
import type { ConfigConsumerProps } from '../config-provider';
import { ConfigContext } from '../config-provider';
import Skeleton from '../skeleton';
import StatisticNumber from './Number';
import useStyle from './style';
import type { FormatConfig, valueType } from './utils';
import type { HTMLAriaDataAttributes } from '../_util/aria-data-attrs';
export interface StatisticProps extends FormatConfig {
interface StatisticReactProps extends FormatConfig {
prefixCls?: string;
className?: string;
rootClassName?: string;
@ -23,7 +26,9 @@ export interface StatisticProps extends FormatConfig {
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
}
const Statistic: React.FC<StatisticProps> = (props) => {
export type StatisticProps = HTMLAriaDataAttributes & StatisticReactProps;
const Statistic: React.FC<StatisticProps & HTMLAriaDataAttributes> = (props) => {
const {
prefixCls: customizePrefixCls,
className,
@ -36,10 +41,15 @@ const Statistic: React.FC<StatisticProps> = (props) => {
prefix,
suffix,
loading = false,
onMouseEnter,
onMouseLeave,
/* --- FormatConfig starts --- */
formatter,
precision,
decimalSeparator = '.',
groupSeparator = ',',
/* --- FormatConfig starts --- */
onMouseEnter,
onMouseLeave,
...rest
} = props;
const { getPrefixCls, direction, statistic } =
@ -54,7 +64,8 @@ const Statistic: React.FC<StatisticProps> = (props) => {
decimalSeparator={decimalSeparator}
groupSeparator={groupSeparator}
prefixCls={prefixCls}
{...props}
formatter={formatter}
precision={precision}
value={value}
/>
);
@ -71,8 +82,11 @@ const Statistic: React.FC<StatisticProps> = (props) => {
cssVarCls,
);
const restProps = pickAttrs(rest, { aria: true, data: true });
return wrapCSSVar(
<div
{...restProps}
className={cls}
style={{ ...statistic?.style, ...style }}
onMouseEnter={onMouseEnter}

View File

@ -81,6 +81,28 @@ describe('Statistic', () => {
expect(container.querySelectorAll('.ant-statistic-content')).toHaveLength(0);
});
it('data attrs', () => {
const { container } = render(
<Statistic value={1128} data-abc="1" aria-label="2" role="status" />,
);
expect(container.querySelector('.ant-statistic')!.getAttribute('data-abc')).toEqual('1');
expect(container.querySelector('.ant-statistic')!.getAttribute('aria-label')).toEqual('2');
expect(container.querySelector('.ant-statistic')!.getAttribute('role')).toEqual('status');
const { container: countdownContainer } = render(
<Statistic.Countdown data-xyz="x" aria-label="y" role="contentinfo" />,
);
expect(countdownContainer.querySelector('.ant-statistic')!.getAttribute('data-xyz')).toEqual(
'x',
);
expect(countdownContainer.querySelector('.ant-statistic')!.getAttribute('aria-label')).toEqual(
'y',
);
expect(countdownContainer.querySelector('.ant-statistic')!.getAttribute('role')).toEqual(
'contentinfo',
);
});
describe('Countdown', () => {
it('render correctly', () => {
const now = dayjs()

View File

@ -15,7 +15,6 @@ export interface FormatConfig {
decimalSeparator?: string;
groupSeparator?: string;
precision?: number;
prefixCls?: string;
}
export interface CountdownFormatConfig extends FormatConfig {