mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 12:39:49 +08:00
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:
parent
119f8aaf79
commit
2aca1fff22
5
components/_util/aria-data-attrs.ts
Normal file
5
components/_util/aria-data-attrs.ts
Normal 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'>;
|
@ -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);
|
||||
|
@ -3,6 +3,7 @@ import type { FormatConfig, valueType } from './utils';
|
||||
|
||||
interface NumberProps extends FormatConfig {
|
||||
value: valueType;
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
const StatisticNumber: React.FC<NumberProps> = (props) => {
|
||||
|
@ -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}
|
||||
|
@ -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()
|
||||
|
@ -15,7 +15,6 @@ export interface FormatConfig {
|
||||
decimalSeparator?: string;
|
||||
groupSeparator?: string;
|
||||
precision?: number;
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
export interface CountdownFormatConfig extends FormatConfig {
|
||||
|
Loading…
Reference in New Issue
Block a user