mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
commit
33533ff22c
@ -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<WaveProps> = (props) => {
|
||||
|
@ -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';
|
||||
|
@ -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<HTMLElement>,
|
||||
className: string,
|
||||
component?: 'Tag' | 'Button' | 'Checkbox' | 'Radio' | 'Switch',
|
||||
component?: WaveComponent,
|
||||
) => {
|
||||
const { wave } = React.useContext(ConfigContext);
|
||||
const [, token, hashId] = useToken();
|
||||
|
@ -145,7 +145,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token) => {
|
||||
iconCls,
|
||||
antCls,
|
||||
badgeShadowSize,
|
||||
motionDurationSlow,
|
||||
textFontSize,
|
||||
textFontSizeSM,
|
||||
statusSize,
|
||||
@ -231,9 +230,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (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,
|
||||
|
@ -227,7 +227,6 @@ const genBaseStyle: GenerateStyle<DropdownToken> = (token) => {
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
whiteSpace: 'nowrap',
|
||||
},
|
||||
|
||||
[`${menuCls}-item-icon`]: {
|
||||
|
@ -686,8 +686,6 @@ const genSearchInputStyle: GenerateStyle<InputToken> = (token: InputToken) => {
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
borderStartStartRadius: 0,
|
||||
borderStartEndRadius: token.borderRadius,
|
||||
borderEndEndRadius: token.borderRadius,
|
||||
borderEndStartRadius: 0,
|
||||
boxShadow: 'none',
|
||||
},
|
||||
|
@ -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<HTMLDivElement, RadioGroupProps>((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<HTMLDivElement, RadioGroupProps>((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<HTMLDivElement, RadioGroupProps>((props, ref
|
||||
cssVarCls,
|
||||
rootCls,
|
||||
);
|
||||
|
||||
const memoizedValue = React.useMemo<RadioGroupContextProps>(
|
||||
() => ({ onChange: onRadioChange, value, disabled, name, optionType }),
|
||||
[onRadioChange, value, disabled, name, optionType],
|
||||
);
|
||||
|
||||
return wrapCSSVar(
|
||||
<div
|
||||
{...pickAttrs(props, { aria: true, data: true })}
|
||||
@ -117,15 +136,7 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>((props, ref
|
||||
id={id}
|
||||
ref={ref}
|
||||
>
|
||||
<RadioGroupContextProvider
|
||||
value={{
|
||||
onChange: onRadioChange,
|
||||
value,
|
||||
disabled: props.disabled,
|
||||
name: props.name,
|
||||
optionType: props.optionType,
|
||||
}}
|
||||
>
|
||||
<RadioGroupContextProvider value={memoizedValue}>
|
||||
{childrenToRender}
|
||||
</RadioGroupContextProvider>
|
||||
</div>,
|
||||
|
@ -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 | `<DownOutlined />` | |
|
||||
| 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\[] \| <br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
|
||||
| variant | Variants of selector | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
|
||||
|
@ -119,7 +119,7 @@ return (
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| suffixIcon | 自定义的选择框后缀图标。以防止图标被用于其他交互,替换的图标默认不会响应展开、收缩事件,可以通过添加 `pointer-events: none` 样式透传。 | ReactNode | `<DownOutlined />` | |
|
||||
| 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\[] \| <br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
|
||||
| variant | 形态变体 | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
|
||||
|
@ -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 }) => <tr {...props} />;
|
||||
|
||||
const EditableCell: React.FC<React.PropsWithChildren<any>> = ({ children, ...restProps }) => (
|
||||
<td {...restProps}>{children}</td>
|
||||
);
|
||||
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
|
||||
const { container } = render(
|
||||
<Table
|
||||
virtual
|
||||
components={components}
|
||||
scroll={{ y: 100 }}
|
||||
columns={[
|
||||
{
|
||||
dataIndex: 'key',
|
||||
},
|
||||
]}
|
||||
dataSource={[
|
||||
{
|
||||
key: 'bamboo',
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
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<HTMLElement>(
|
||||
'.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 <Table columns={columns} dataSource={data} pagination={false} />;
|
||||
};
|
||||
const { container } = render(
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
dataIndex: 'key',
|
||||
},
|
||||
]}
|
||||
expandable={{ expandedRowRender, defaultExpandedRowKeys: ['0'] }}
|
||||
dataSource={[
|
||||
{
|
||||
key: '0',
|
||||
},
|
||||
]}
|
||||
size="middle"
|
||||
virtual
|
||||
scroll={{ y: 200 }}
|
||||
/>,
|
||||
);
|
||||
|
||||
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<HTMLElement>(
|
||||
'.ant-table-tbody-virtual-holder .ant-table-expanded-row .ant-table-row',
|
||||
)!,
|
||||
);
|
||||
expect(styleMap.display).toEqual('table-row');
|
||||
});
|
||||
});
|
||||
|
@ -89,7 +89,6 @@ const columns: TableProps<RecordType>['columns'] = [
|
||||
{
|
||||
title: 'LastName',
|
||||
dataIndex: 'lastName',
|
||||
width: 120,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -15,10 +15,15 @@ const genVirtualStyle: GenerateStyle<TableToken, CSSObject> = (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`]: {
|
||||
|
Loading…
Reference in New Issue
Block a user