mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 12:39:49 +08:00
Merge branch 'feature' into feature/add-variant-underlined
This commit is contained in:
commit
e9e16945ca
@ -430,12 +430,14 @@ exports[`renders components/collapse/demo/collapsible.tsx extend context correct
|
||||
class="ant-collapse-item ant-collapse-item-active"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header ant-collapse-header-collapsible-only"
|
||||
class="ant-collapse-header ant-collapse-collapsible-header"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-expand-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="expanded"
|
||||
@ -459,7 +461,11 @@ exports[`renders components/collapse/demo/collapsible.tsx extend context correct
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header-text"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
This panel can only be collapsed by clicking text
|
||||
</span>
|
||||
@ -490,12 +496,14 @@ exports[`renders components/collapse/demo/collapsible.tsx extend context correct
|
||||
class="ant-collapse-item ant-collapse-item-active"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header ant-collapse-icon-collapsible-only"
|
||||
class="ant-collapse-header ant-collapse-collapsible-icon"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-expand-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="expanded"
|
||||
@ -552,7 +560,7 @@ exports[`renders components/collapse/demo/collapsible.tsx extend context correct
|
||||
<div
|
||||
aria-disabled="true"
|
||||
aria-expanded="false"
|
||||
class="ant-collapse-header"
|
||||
class="ant-collapse-header ant-collapse-collapsible-disabled"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
|
@ -424,12 +424,14 @@ exports[`renders components/collapse/demo/collapsible.tsx correctly 1`] = `
|
||||
class="ant-collapse-item ant-collapse-item-active"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header ant-collapse-header-collapsible-only"
|
||||
class="ant-collapse-header ant-collapse-collapsible-header"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-expand-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="expanded"
|
||||
@ -453,7 +455,11 @@ exports[`renders components/collapse/demo/collapsible.tsx correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header-text"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
This panel can only be collapsed by clicking text
|
||||
</span>
|
||||
@ -484,12 +490,14 @@ exports[`renders components/collapse/demo/collapsible.tsx correctly 1`] = `
|
||||
class="ant-collapse-item ant-collapse-item-active"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-header ant-collapse-icon-collapsible-only"
|
||||
class="ant-collapse-header ant-collapse-collapsible-icon"
|
||||
>
|
||||
<div
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
class="ant-collapse-expand-icon"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
aria-label="expanded"
|
||||
@ -546,7 +554,7 @@ exports[`renders components/collapse/demo/collapsible.tsx correctly 1`] = `
|
||||
<div
|
||||
aria-disabled="true"
|
||||
aria-expanded="false"
|
||||
class="ant-collapse-header"
|
||||
class="ant-collapse-header ant-collapse-collapsible-disabled"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
|
@ -149,7 +149,15 @@ export const genBaseStyle: GenerateStyle<CollapseToken> = (token) => {
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-icon-collapsible-only`]: {
|
||||
[`${componentCls}-collapsible-header`]: {
|
||||
cursor: 'default',
|
||||
[`${componentCls}-header-text`]: {
|
||||
flex: 'none',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
|
||||
[`${componentCls}-collapsible-icon`]: {
|
||||
cursor: 'unset',
|
||||
|
||||
[`${componentCls}-expand-icon`]: {
|
||||
|
@ -141,6 +141,112 @@ exports[`renders components/descriptions/demo/basic.tsx extend context correctly
|
||||
|
||||
exports[`renders components/descriptions/demo/basic.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/descriptions/demo/block.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-descriptions ant-descriptions-bordered"
|
||||
>
|
||||
<div
|
||||
class="ant-descriptions-header"
|
||||
>
|
||||
<div
|
||||
class="ant-descriptions-title"
|
||||
>
|
||||
User Info
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-descriptions-view"
|
||||
>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
UserName
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Zhou Maomao
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Live
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Hangzhou, Zhejiang
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Remark
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
empty
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Address
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/descriptions/demo/block.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/descriptions/demo/border.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-descriptions ant-descriptions-bordered"
|
||||
|
@ -127,6 +127,106 @@ exports[`renders components/descriptions/demo/basic.tsx correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/descriptions/demo/block.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-descriptions ant-descriptions-bordered"
|
||||
>
|
||||
<div
|
||||
class="ant-descriptions-header"
|
||||
>
|
||||
<div
|
||||
class="ant-descriptions-title"
|
||||
>
|
||||
User Info
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-descriptions-view"
|
||||
>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
UserName
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Zhou Maomao
|
||||
</span>
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Live
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="3"
|
||||
>
|
||||
<span>
|
||||
Hangzhou, Zhejiang
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Remark
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="5"
|
||||
>
|
||||
<span>
|
||||
empty
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
<span>
|
||||
Address
|
||||
</span>
|
||||
</th>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="5"
|
||||
>
|
||||
<span>
|
||||
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/descriptions/demo/border.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-descriptions ant-descriptions-bordered"
|
||||
|
@ -78,6 +78,30 @@ describe('Descriptions', () => {
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[2]).toHaveAttribute('colSpan', '1');
|
||||
});
|
||||
|
||||
it('span = filled', () => {
|
||||
const { container } = render(
|
||||
<Descriptions
|
||||
column={3}
|
||||
items={[
|
||||
{ label: '0', children: '', span: 2 },
|
||||
{ label: '1', children: '' },
|
||||
{ label: '2', children: '' },
|
||||
{ label: '3', children: '', span: 'filled' },
|
||||
{ label: '4', children: '', span: 'filled' },
|
||||
{ label: '5', children: '' },
|
||||
{ label: '6', children: '', span: 1 },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[0]).toHaveAttribute('colSpan', '2');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[1]).toHaveAttribute('colSpan', '1');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[2]).toHaveAttribute('colSpan', '1');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[3]).toHaveAttribute('colSpan', '2');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[4]).toHaveAttribute('colSpan', '3');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[5]).toHaveAttribute('colSpan', '1');
|
||||
expect(container.querySelectorAll('.ant-descriptions-item')[6]).toHaveAttribute('colSpan', '2');
|
||||
});
|
||||
|
||||
it('column is number', () => {
|
||||
const wrapper = render(
|
||||
<Descriptions column={3}>
|
||||
|
7
components/descriptions/demo/block.md
Normal file
7
components/descriptions/demo/block.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
整行的展示。
|
||||
|
||||
## en-US
|
||||
|
||||
Display of the entire line.
|
29
components/descriptions/demo/block.tsx
Normal file
29
components/descriptions/demo/block.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { Descriptions } from 'antd';
|
||||
import type { DescriptionsProps } from 'antd';
|
||||
|
||||
const items: DescriptionsProps['items'] = [
|
||||
{
|
||||
label: 'UserName',
|
||||
children: 'Zhou Maomao',
|
||||
},
|
||||
{
|
||||
label: 'Live',
|
||||
span: 'filled', // span = 2
|
||||
children: 'Hangzhou, Zhejiang',
|
||||
},
|
||||
{
|
||||
label: 'Remark',
|
||||
span: 'filled', // span = 3
|
||||
children: 'empty',
|
||||
},
|
||||
{
|
||||
label: 'Address',
|
||||
span: 1, // span will be 3 and warning for span is not align to the end
|
||||
children: 'No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China',
|
||||
},
|
||||
];
|
||||
|
||||
const App: React.FC = () => <Descriptions bordered title="User Info" items={items} />;
|
||||
|
||||
export default App;
|
@ -1,7 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
带边框和背景颜色列表。
|
||||
复杂文本的情况。
|
||||
|
||||
## en-US
|
||||
|
||||
Descriptions with border and background color.
|
||||
The situation of complex text.
|
||||
|
@ -23,10 +23,15 @@ export default function useItems(
|
||||
|
||||
const responsiveItems = React.useMemo<InternalDescriptionsItemType[]>(
|
||||
() =>
|
||||
mergedItems.map(({ span, ...restItem }) => ({
|
||||
...restItem,
|
||||
span: typeof span === 'number' ? span : matchScreen(screens, span),
|
||||
})),
|
||||
mergedItems.map(({ span, ...restItem }) => {
|
||||
if (span === 'filled') {
|
||||
return { ...restItem, filled: true };
|
||||
}
|
||||
return {
|
||||
...restItem,
|
||||
span: typeof span === 'number' ? span : matchScreen(screens, span),
|
||||
};
|
||||
}),
|
||||
[mergedItems, screens],
|
||||
);
|
||||
|
||||
|
@ -3,65 +3,61 @@ import { useMemo } from 'react';
|
||||
import type { InternalDescriptionsItemType } from '..';
|
||||
import { devUseWarning } from '../../_util/warning';
|
||||
|
||||
function getFilledItem(
|
||||
rowItem: InternalDescriptionsItemType,
|
||||
rowRestCol: number,
|
||||
span?: number,
|
||||
): [item: InternalDescriptionsItemType, exceed: boolean] {
|
||||
let clone = rowItem;
|
||||
let exceed = false;
|
||||
|
||||
if (span === undefined || span > rowRestCol) {
|
||||
clone = {
|
||||
...rowItem,
|
||||
span: rowRestCol,
|
||||
};
|
||||
|
||||
exceed = span !== undefined;
|
||||
}
|
||||
return [clone, exceed];
|
||||
}
|
||||
|
||||
// Calculate the sum of span in a row
|
||||
function getCalcRows(
|
||||
rowItems: InternalDescriptionsItemType[],
|
||||
mergedColumn: number,
|
||||
): [rows: InternalDescriptionsItemType[][], exceed: boolean] {
|
||||
const rows: InternalDescriptionsItemType[][] = [];
|
||||
let rows: InternalDescriptionsItemType[][] = [];
|
||||
let tmpRow: InternalDescriptionsItemType[] = [];
|
||||
let rowRestCol = mergedColumn;
|
||||
let exceed = false;
|
||||
let count = 0;
|
||||
|
||||
rowItems
|
||||
.filter((n) => n)
|
||||
.forEach((rowItem, index) => {
|
||||
const span = rowItem?.span;
|
||||
const mergedSpan = span || 1;
|
||||
.forEach((rowItem) => {
|
||||
const { filled, ...restItem } = rowItem;
|
||||
|
||||
// Additional handle last one
|
||||
if (index === rowItems.length - 1) {
|
||||
const [item, itemExceed] = getFilledItem(rowItem, rowRestCol, span);
|
||||
exceed = exceed || itemExceed;
|
||||
|
||||
tmpRow.push(item);
|
||||
if (filled) {
|
||||
tmpRow.push(restItem);
|
||||
rows.push(tmpRow);
|
||||
// reset
|
||||
tmpRow = [];
|
||||
count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mergedSpan < rowRestCol) {
|
||||
rowRestCol -= mergedSpan;
|
||||
tmpRow.push(rowItem);
|
||||
} else {
|
||||
const [item, itemExceed] = getFilledItem(rowItem, rowRestCol, mergedSpan);
|
||||
exceed = exceed || itemExceed;
|
||||
|
||||
tmpRow.push(item);
|
||||
const restSpan = mergedColumn - count;
|
||||
count += rowItem.span || 1;
|
||||
if (count >= mergedColumn) {
|
||||
if (count > mergedColumn) {
|
||||
exceed = true;
|
||||
tmpRow.push({ ...restItem, span: restSpan });
|
||||
} else {
|
||||
tmpRow.push(restItem);
|
||||
}
|
||||
rows.push(tmpRow);
|
||||
rowRestCol = mergedColumn;
|
||||
// reset
|
||||
tmpRow = [];
|
||||
count = 0;
|
||||
} else {
|
||||
tmpRow.push(restItem);
|
||||
}
|
||||
});
|
||||
|
||||
if (tmpRow.length > 0) {
|
||||
rows.push(tmpRow);
|
||||
}
|
||||
|
||||
rows = rows.map((rows) => {
|
||||
const count = rows.reduce((acc, item) => acc + (item.span || 1), 0);
|
||||
if (count < mergedColumn) {
|
||||
// If the span of the last element in the current row is less than the column, then add its span to the remaining columns
|
||||
const last = rows[rows.length - 1];
|
||||
last.span = mergedColumn - count + 1;
|
||||
return rows;
|
||||
}
|
||||
return rows;
|
||||
});
|
||||
return [rows, exceed];
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ const items: DescriptionsProps['items'] = [
|
||||
<code src="./demo/style.tsx" debug>Customize label & wrapper style</code>
|
||||
<code src="./demo/jsx.tsx" debug>JSX demo</code>
|
||||
<code src="./demo/component-token.tsx" debug>Component Token</code>
|
||||
<code src="./demo/block.tsx">row</code>
|
||||
|
||||
## API
|
||||
|
||||
@ -98,7 +99,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| contentStyle | Customize content style | CSSProperties | - | 4.9.0 |
|
||||
| label | The description of the content | ReactNode | - | |
|
||||
| labelStyle | Customize label style | CSSProperties | - | 4.9.0 |
|
||||
| span | The number of columns included | number \| [Screens](/components/grid#col) | 1 | `screens: 5.9.0` |
|
||||
| span | The number of columns included(`filled` Fill the remaining part of the current row) | number \| `filled` \| [Screens](/components/grid#col) | 1 | `screens: 5.9.0`, `filled: 5.22.0` |
|
||||
|
||||
> The number of span Description.Item. Span={2} takes up the width of two DescriptionItems. When both `style` and `labelStyle`(or `contentStyle`) configured, both of them will work. And next one will overwrite first when conflict.
|
||||
|
||||
|
@ -22,10 +22,12 @@ interface CompoundedComponent {
|
||||
|
||||
export interface InternalDescriptionsItemType extends DescriptionsItemProps {
|
||||
key?: React.Key;
|
||||
filled?: boolean;
|
||||
}
|
||||
|
||||
export interface DescriptionsItemType extends Omit<InternalDescriptionsItemType, 'span'> {
|
||||
span?: number | { [key in Breakpoint]?: number };
|
||||
export interface DescriptionsItemType
|
||||
extends Omit<InternalDescriptionsItemType, 'span' | 'filled'> {
|
||||
span?: number | 'filled' | { [key in Breakpoint]?: number };
|
||||
}
|
||||
|
||||
export interface DescriptionsProps {
|
||||
|
@ -72,6 +72,7 @@ const items: DescriptionsProps['items'] = [
|
||||
<code src="./demo/style.tsx" debug>自定义 label & wrapper 样式</code>
|
||||
<code src="./demo/jsx.tsx" debug>JSX demo</code>
|
||||
<code src="./demo/component-token.tsx" debug>组件 Token</code>
|
||||
<code src="./demo/block.tsx">整行</code>
|
||||
|
||||
## API
|
||||
|
||||
@ -99,7 +100,7 @@ const items: DescriptionsProps['items'] = [
|
||||
| contentStyle | 自定义内容样式 | CSSProperties | - | 4.9.0 |
|
||||
| label | 内容的描述 | ReactNode | - | |
|
||||
| labelStyle | 自定义标签样式 | CSSProperties | - | 4.9.0 |
|
||||
| span | 包含列的数量 | number \| [Screens](/components/grid-cn#col) | 1 | `screens: 5.9.0` |
|
||||
| span | 包含列的数量(`filled` 铺满当前行剩余部分) | number\| `filled` \| [Screens](/components/grid-cn#col) | 1 | `screens: 5.9.0`,`filled: 5.22.0` |
|
||||
|
||||
> span 是 Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。当同时配置 `style` 和 `labelStyle`(或 `contentStyle`)时,两者会同时作用。样式冲突时,后者会覆盖前者。
|
||||
|
||||
|
@ -24,7 +24,8 @@ export interface OTPRef {
|
||||
nativeElement: HTMLDivElement;
|
||||
}
|
||||
|
||||
export interface OTPProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
||||
export interface OTPProps
|
||||
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'onInput'> {
|
||||
prefixCls?: string;
|
||||
length?: number;
|
||||
|
||||
@ -48,6 +49,8 @@ export interface OTPProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'on
|
||||
mask?: boolean | string;
|
||||
|
||||
type?: React.HTMLInputTypeAttribute;
|
||||
|
||||
onInput?: (value: string[]) => void;
|
||||
}
|
||||
|
||||
function strToArr(str: string) {
|
||||
@ -69,6 +72,7 @@ const OTP = React.forwardRef<OTPRef, OTPProps>((props, ref) => {
|
||||
autoFocus,
|
||||
mask,
|
||||
type,
|
||||
onInput,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -146,6 +150,10 @@ const OTP = React.forwardRef<OTPRef, OTPProps>((props, ref) => {
|
||||
const triggerValueCellsChange = useEvent((nextValueCells: string[]) => {
|
||||
setValueCells(nextValueCells);
|
||||
|
||||
if (onInput) {
|
||||
onInput(nextValueCells);
|
||||
}
|
||||
|
||||
// Trigger if all cells are filled
|
||||
if (
|
||||
onChange &&
|
||||
|
@ -172,4 +172,23 @@ describe('Input.OTP', () => {
|
||||
const { container } = render(<OTP type="number" />);
|
||||
expect(container.querySelector('input')).toHaveAttribute('type', 'number');
|
||||
});
|
||||
|
||||
it('should call onInput with a string array when input changes', () => {
|
||||
const onInput = jest.fn();
|
||||
const { container } = render(<OTP length={4} onInput={onInput} />);
|
||||
|
||||
const inputs = Array.from(container.querySelectorAll('input'));
|
||||
|
||||
fireEvent.input(inputs[0], { target: { value: '1' } });
|
||||
expect(onInput).toHaveBeenCalledWith(['1']);
|
||||
|
||||
fireEvent.input(inputs[2], { target: { value: '3' } });
|
||||
expect(onInput).toHaveBeenCalledWith(['1', '', '3']);
|
||||
|
||||
fireEvent.input(inputs[1], { target: { value: '2' } });
|
||||
expect(onInput).toHaveBeenCalledWith(['1', '2', '3']);
|
||||
|
||||
fireEvent.input(inputs[3], { target: { value: '4' } });
|
||||
expect(onInput).toHaveBeenCalledWith(['1', '2', '3', '4']);
|
||||
});
|
||||
});
|
||||
|
@ -11,8 +11,13 @@ const App: React.FC = () => {
|
||||
console.log('onChange:', text);
|
||||
};
|
||||
|
||||
const onInput: OTPProps['onInput'] = (value) => {
|
||||
console.log('onInput:', value);
|
||||
};
|
||||
|
||||
const sharedProps: OTPProps = {
|
||||
onChange,
|
||||
onInput,
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -140,7 +140,8 @@ Added in `5.16.0`.
|
||||
| size | The size of the input box | `small` \| `middle` \| `large` | `middle` | |
|
||||
| variant | Variants of Input | `outlined` \| `borderless` \| `filled` | `outlined` | |
|
||||
| value | The input content value | string | - | |
|
||||
| onChange | Trigger when all the fields are filled | function(value: string) | - | |
|
||||
| onChange | Trigger when all the fields are filled | (value: string) => void | - | |
|
||||
| onInput | Trigger when the input value changes | (value: string[]) => void | - | `5.22.0` |
|
||||
|
||||
#### VisibilityToggle
|
||||
|
||||
|
@ -141,7 +141,8 @@ interface CountConfig {
|
||||
| size | 输入框大小 | `small` \| `middle` \| `large` | `middle` | |
|
||||
| variant | 形态变体 | `outlined` \| `borderless` \| `filled` | `outlined` | |
|
||||
| value | 输入框内容 | string | - | |
|
||||
| onChange | 当输入框内容全部填充时触发回调 | function(value: string) | - | |
|
||||
| onChange | 当输入框内容全部填充时触发回调 | (value: string) => void | - | |
|
||||
| onInput | 输入值变化时触发的回调 | (value: string[]) => void | - | `5.22.0` |
|
||||
|
||||
#### VisibilityToggle
|
||||
|
||||
|
@ -47,7 +47,9 @@ const App: React.FC = () => {
|
||||
components: {
|
||||
Tree: {
|
||||
nodeHoverBg: '#fff2f0',
|
||||
nodeHoverColor: '#1677ff',
|
||||
nodeSelectedBg: '#ffa39e',
|
||||
nodeSelectedColor: '#fff',
|
||||
indentSize: 80,
|
||||
},
|
||||
},
|
||||
|
@ -23,11 +23,21 @@ export interface TreeSharedToken {
|
||||
* @descEN Background color of hovered node
|
||||
*/
|
||||
nodeHoverBg: string;
|
||||
/**
|
||||
* @desc 节点悬浮态态文字颜色
|
||||
* @descEN Text color of hovered node
|
||||
*/
|
||||
nodeHoverColor: string;
|
||||
/**
|
||||
* @desc 节点选中态背景色
|
||||
* @descEN Background color of selected node
|
||||
*/
|
||||
nodeSelectedBg: string;
|
||||
/**
|
||||
* @desc 节点选中态文字颜色
|
||||
* @descEN Text color of selected node
|
||||
*/
|
||||
nodeSelectedColor: string;
|
||||
}
|
||||
|
||||
export interface ComponentToken extends TreeSharedToken {
|
||||
@ -194,6 +204,16 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
|
||||
},
|
||||
},
|
||||
|
||||
// not disable
|
||||
[`&:not(${treeNodeCls}-disabled)`]: {
|
||||
// >>> Title
|
||||
[`${treeCls}-node-content-wrapper`]: {
|
||||
'&:hover': {
|
||||
color: token.nodeHoverColor,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
[`&-active ${treeCls}-node-content-wrapper`]: {
|
||||
background: token.controlItemBgHover,
|
||||
},
|
||||
@ -354,6 +374,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject =>
|
||||
},
|
||||
|
||||
[`&${treeCls}-node-selected`]: {
|
||||
color: token.nodeSelectedColor,
|
||||
backgroundColor: nodeSelectedBg,
|
||||
},
|
||||
|
||||
@ -558,7 +579,9 @@ export const initComponentToken = (token: AliasToken): TreeSharedToken => {
|
||||
titleHeight,
|
||||
indentSize: titleHeight,
|
||||
nodeHoverBg: controlItemBgHover,
|
||||
nodeHoverColor: token.colorText,
|
||||
nodeSelectedBg: controlItemBgActive,
|
||||
nodeSelectedColor: token.colorText,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -122,7 +122,7 @@
|
||||
"dayjs": "^1.11.11",
|
||||
"rc-cascader": "~3.29.0",
|
||||
"rc-checkbox": "~3.3.0",
|
||||
"rc-collapse": "~3.8.0",
|
||||
"rc-collapse": "~3.9.0",
|
||||
"rc-dialog": "~9.6.0",
|
||||
"rc-drawer": "~7.2.0",
|
||||
"rc-dropdown": "~4.2.0",
|
||||
@ -344,4 +344,4 @@
|
||||
"tnpm": {
|
||||
"mode": "npm"
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user