diff --git a/components/_util/wave/index.ts b/components/_util/wave/index.ts index 5b4f4a5107..4dcb7ce25a 100644 --- a/components/_util/wave/index.ts +++ b/components/_util/wave/index.ts @@ -6,13 +6,14 @@ import { composeRef, supportRef } from 'rc-util/lib/ref'; import type { ConfigConsumerProps } from '../../config-provider'; import { ConfigContext } from '../../config-provider'; import { cloneElement } from '../reactNode'; +import type { WaveComponent } from './interface'; import useStyle from './style'; import useWave from './useWave'; export interface WaveProps { disabled?: boolean; children?: React.ReactNode; - component?: 'Tag' | 'Button' | 'Checkbox' | 'Radio' | 'Switch'; + component?: WaveComponent; } const Wave: React.FC = (props) => { diff --git a/components/_util/wave/interface.ts b/components/_util/wave/interface.ts index 952d98ffe6..12e8225cf6 100644 --- a/components/_util/wave/interface.ts +++ b/components/_util/wave/interface.ts @@ -8,10 +8,12 @@ export type ShowWaveEffect = ( info: { className: string; token: GlobalToken; - component?: string; + component?: WaveComponent; event: MouseEvent; hashId: string; }, ) => void; export type ShowWave = (event: MouseEvent) => void; + +export type WaveComponent = 'Tag' | 'Button' | 'Checkbox' | 'Radio' | 'Switch'; diff --git a/components/_util/wave/useWave.ts b/components/_util/wave/useWave.ts index 57469674c7..09e944f9ed 100644 --- a/components/_util/wave/useWave.ts +++ b/components/_util/wave/useWave.ts @@ -5,13 +5,13 @@ import raf from 'rc-util/lib/raf'; import { ConfigContext } from '../../config-provider'; import useToken from '../../theme/useToken'; import { TARGET_CLS } from './interface'; -import type { ShowWave } from './interface'; +import type { ShowWave, WaveComponent } from './interface'; import showWaveEffect from './WaveEffect'; const useWave = ( nodeRef: React.RefObject, className: string, - component?: 'Tag' | 'Button' | 'Checkbox' | 'Radio' | 'Switch', + component?: WaveComponent, ) => { const { wave } = React.useContext(ConfigContext); const [, token, hashId] = useToken(); diff --git a/components/badge/style/index.ts b/components/badge/style/index.ts index cb97d8af30..10cd60e1c9 100644 --- a/components/badge/style/index.ts +++ b/components/badge/style/index.ts @@ -145,7 +145,6 @@ const genSharedBadgeStyle: GenerateStyle = (token) => { iconCls, antCls, badgeShadowSize, - motionDurationSlow, textFontSize, textFontSizeSM, statusSize, @@ -231,9 +230,6 @@ const genSharedBadgeStyle: GenerateStyle = (token) => { borderRadius: '100%', boxShadow: `0 0 0 ${unit(badgeShadowSize)} ${token.badgeShadowColor}`, }, - [`${componentCls}-dot${numberPrefixCls}`]: { - transition: `background ${motionDurationSlow}`, - }, [`${componentCls}-count, ${componentCls}-dot, ${numberPrefixCls}-custom-component`]: { position: 'absolute', top: 0, diff --git a/components/dropdown/style/index.ts b/components/dropdown/style/index.ts index d874bca624..79f2ac9a25 100644 --- a/components/dropdown/style/index.ts +++ b/components/dropdown/style/index.ts @@ -227,7 +227,6 @@ const genBaseStyle: GenerateStyle = (token) => { position: 'relative', display: 'flex', alignItems: 'center', - whiteSpace: 'nowrap', }, [`${menuCls}-item-icon`]: { diff --git a/components/input/style/index.ts b/components/input/style/index.ts index 252969e13c..92ca32a78d 100644 --- a/components/input/style/index.ts +++ b/components/input/style/index.ts @@ -686,8 +686,6 @@ const genSearchInputStyle: GenerateStyle = (token: InputToken) => { paddingTop: 0, paddingBottom: 0, borderStartStartRadius: 0, - borderStartEndRadius: token.borderRadius, - borderEndEndRadius: token.borderRadius, borderEndStartRadius: 0, boxShadow: 'none', }, diff --git a/components/radio/group.tsx b/components/radio/group.tsx index 28e81971ee..8319773943 100644 --- a/components/radio/group.tsx +++ b/components/radio/group.tsx @@ -7,29 +7,18 @@ import { ConfigContext } from '../config-provider'; import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import useSize from '../config-provider/hooks/useSize'; import { RadioGroupContextProvider } from './context'; -import type { RadioChangeEvent, RadioGroupButtonStyle, RadioGroupProps } from './interface'; +import type { + RadioChangeEvent, + RadioGroupButtonStyle, + RadioGroupContextProps, + RadioGroupProps, +} from './interface'; import Radio from './radio'; import useStyle from './style'; const RadioGroup = React.forwardRef((props, ref) => { const { getPrefixCls, direction } = React.useContext(ConfigContext); - const [value, setValue] = useMergedState(props.defaultValue, { - value: props.value, - }); - - const onRadioChange = (ev: RadioChangeEvent) => { - const lastValue = value; - const val = ev.target.value; - if (!('value' in props)) { - setValue(val); - } - const { onChange } = props; - if (onChange && val !== lastValue) { - onChange(ev); - } - }; - const { prefixCls: customizePrefixCls, className, @@ -41,11 +30,35 @@ const RadioGroup = React.forwardRef((props, ref size: customizeSize, style, id, + optionType, + name, + defaultValue, + value: customizedValue, + onChange, onMouseEnter, onMouseLeave, onFocus, onBlur, } = props; + + const [value, setValue] = useMergedState(defaultValue, { + value: customizedValue, + }); + + const onRadioChange = React.useCallback( + (event: RadioChangeEvent) => { + const lastValue = value; + const val = event.target.value; + if (!('value' in props)) { + setValue(val); + } + if (val !== lastValue) { + onChange?.(event); + } + }, + [value, setValue, onChange], + ); + const prefixCls = getPrefixCls('radio', customizePrefixCls); const groupPrefixCls = `${prefixCls}-group`; @@ -105,6 +118,12 @@ const RadioGroup = React.forwardRef((props, ref cssVarCls, rootCls, ); + + const memoizedValue = React.useMemo( + () => ({ onChange: onRadioChange, value, disabled, name, optionType }), + [onRadioChange, value, disabled, name, optionType], + ); + return wrapCSSVar(
((props, ref id={id} ref={ref} > - + {childrenToRender}
, diff --git a/components/select/index.en-US.md b/components/select/index.en-US.md index a8ef2cc811..c332e448ae 100644 --- a/components/select/index.en-US.md +++ b/components/select/index.en-US.md @@ -118,7 +118,7 @@ Common props ref:[Common props](/docs/react/common-props) | status | Set validation status | 'error' \| 'warning' | - | 4.19.0 | | suffixIcon | The custom suffix icon. Customize icon will not response click open to avoid icon designed to do other interactive. You can use `pointer-events: none` style to bypass | ReactNode | `` | | | tagRender | Customize tag render, only applies when `mode` is set to `multiple` or `tags` | (props) => ReactNode | - | | -| labelRender | Customize selected label render | (label: ReactNode) => ReactNode | - | 5.15.0 | +| labelRender | Customize selected label render (LabelInValueType definition see [LabelInValueType](https://github.com/react-component/select/blob/b39c28aa2a94e7754ebc570f200ab5fd33bd31e7/src/Select.tsx#L70)) | (props: LabelInValueType) => ReactNode | - | 5.15.0 | | tokenSeparators | Separator used to tokenize, only applies when `mode="tags"` | string\[] | - | | | value | Current selected option (considered as a immutable array) | string \| string\[] \|
number \| number\[] \|
LabeledValue \| LabeledValue\[] | - | | | variant | Variants of selector | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 | diff --git a/components/select/index.zh-CN.md b/components/select/index.zh-CN.md index 46c5f5b26b..d6d6d2611d 100644 --- a/components/select/index.zh-CN.md +++ b/components/select/index.zh-CN.md @@ -119,7 +119,7 @@ return ( | status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 | | suffixIcon | 自定义的选择框后缀图标。以防止图标被用于其他交互,替换的图标默认不会响应展开、收缩事件,可以通过添加 `pointer-events: none` 样式透传。 | ReactNode | `` | | | tagRender | 自定义 tag 内容 render,仅在 `mode` 为 `multiple` 或 `tags` 时生效 | (props) => ReactNode | - | | -| labelRender | 自定义当前选中的 label 内容 render | (label: ReactNode) => ReactNode | - | 5.15.0 | +| labelRender | 自定义当前选中的 label 内容 render (LabelInValueType的定义见 [LabelInValueType](https://github.com/react-component/select/blob/b39c28aa2a94e7754ebc570f200ab5fd33bd31e7/src/Select.tsx#L70)) | (props: LabelInValueType) => ReactNode | - | 5.15.0 | | tokenSeparators | 自动分词的分隔符,仅在 `mode="tags"` 时生效 | string\[] | - | | | value | 指定当前选中的条目,多选时为一个数组。(value 数组引用未变化时,Select 不会更新) | string \| string\[] \|
number \| number\[] \|
LabeledValue \| LabeledValue\[] | - | | | variant | 形态变体 | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 | diff --git a/components/table/__tests__/Table.virtual.test.tsx b/components/table/__tests__/Table.virtual.test.tsx index a9404d13b5..251bae09a0 100644 --- a/components/table/__tests__/Table.virtual.test.tsx +++ b/components/table/__tests__/Table.virtual.test.tsx @@ -43,4 +43,111 @@ describe('Table.Virtual', () => { expect(errSpy).toHaveBeenCalledWith('Warning: `scroll.y` in virtual table must be number.'); errSpy.mockRestore(); }); + + it('should work with edit cell', () => { + const EditableRow: React.FC = ({ ...props }) => ; + + const EditableCell: React.FC> = ({ children, ...restProps }) => ( + {children} + ); + + const components = { + body: { + row: EditableRow, + cell: EditableCell, + }, + }; + + const { container } = render( + , + ); + + expect( + container.querySelectorAll('.ant-table-wrapper .ant-table-tbody-virtual .ant-table-row'), + ).toHaveLength(1); + expect( + container.querySelectorAll('.ant-table-tbody-virtual-holder .ant-table-cell'), + ).toHaveLength(1); + expect( + container.querySelector('.ant-table-tbody-virtual-holder .ant-table-cell')?.textContent, + ).toEqual('bamboo'); + const styleMap = getComputedStyle( + container.querySelector( + '.ant-table-wrapper .ant-table-tbody-virtual .ant-table-row', + )!, + ); + expect(styleMap.display).toEqual('flex'); + }); + + it('should work with sub table', () => { + const expandedRowRender = () => { + const columns = [ + { title: 'Date', dataIndex: 'date', key: 'date' }, + { title: 'Name', dataIndex: 'name', key: 'name' }, + { title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' }, + ]; + const data = []; + for (let i = 0; i < 3; ++i) { + data.push({ + key: i.toString(), + date: '2014-12-24 23:12:00', + name: 'This is production name', + upgradeNum: 'Upgraded: 56', + }); + } + return
; + }; + const { container } = render( +
, + ); + + expect( + container.querySelectorAll('.ant-table-tbody-virtual-holder-inner > div > .ant-table-row'), + ).toHaveLength(1); + expect( + container.querySelectorAll( + '.ant-table-tbody-virtual-holder-inner > div > .ant-table-row > .ant-table-cell', + )?.[1]?.textContent, + ).toEqual('0'); + + expect( + container.querySelectorAll('.ant-table-tbody-virtual-holder .ant-table-expanded-row'), + ).toHaveLength(1); + + const styleMap = getComputedStyle( + container.querySelector( + '.ant-table-tbody-virtual-holder .ant-table-expanded-row .ant-table-row', + )!, + ); + expect(styleMap.display).toEqual('table-row'); + }); }); diff --git a/components/table/demo/virtual-list.tsx b/components/table/demo/virtual-list.tsx index 6fd1190a9a..9cda57dac7 100644 --- a/components/table/demo/virtual-list.tsx +++ b/components/table/demo/virtual-list.tsx @@ -89,7 +89,6 @@ const columns: TableProps['columns'] = [ { title: 'LastName', dataIndex: 'lastName', - width: 120, }, ]; diff --git a/components/table/style/virtual.ts b/components/table/style/virtual.ts index 61c2e659d4..38978211df 100644 --- a/components/table/style/virtual.ts +++ b/components/table/style/virtual.ts @@ -15,10 +15,15 @@ const genVirtualStyle: GenerateStyle = (token) => { [`${componentCls}-wrapper`]: { // ========================== Row ========================== [`${componentCls}-tbody-virtual`]: { - [`${componentCls}-row:not(tr)`]: { - display: 'flex', - boxSizing: 'border-box', - width: '100%', + [`${componentCls}-tbody-virtual-holder-inner`]: { + [` + & > ${componentCls}-row, + & > div:not(${componentCls}-row) > ${componentCls}-row + `]: { + display: 'flex', + boxSizing: 'border-box', + width: '100%', + }, }, [`${componentCls}-cell`]: {