Merge pull request #29104 from ant-design/master

This commit is contained in:
Ant Design GitHub Bot 2021-01-29 10:16:25 +08:00 committed by GitHub
commit 074f2228cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 101 additions and 31 deletions

View File

@ -8,6 +8,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: make release
if: github.event.ref_type == 'tag'
uses: actions-cool/release-helper@v1
with:
token: ${{ secrets.ANT_BOT_TOKEN }}

View File

@ -9,7 +9,7 @@ Wrap Affix around another component to make it stick the viewport.
## When To Use
On longer web pages, its helpful for some content to stick to the viewport. This is common for menus and actions.
On longer web pages, it's helpful to stick component into the viewport. This is common for menus and actions.
Please note that Affix should not cover other content on the page, especially when the size of the viewport is small.

View File

@ -38,6 +38,7 @@ function renderNumberList(position: number, className: string) {
export interface ScrollNumberProps {
prefixCls?: string;
className?: string;
motionClassName?: string;
count?: string | number | null;
children?: React.ReactElement<HTMLElement>;
component?: string;
@ -56,6 +57,7 @@ const ScrollNumber: React.FC<ScrollNumberProps> = ({
prefixCls: customizePrefixCls,
count: customizeCount,
className,
motionClassName,
style,
title,
show,
@ -124,7 +126,7 @@ const ScrollNumber: React.FC<ScrollNumberProps> = ({
...restProps,
'data-show': show,
style,
className: classNames(prefixCls, className),
className: classNames(prefixCls, className, motionClassName),
title: title as string,
};
@ -173,7 +175,7 @@ const ScrollNumber: React.FC<ScrollNumberProps> = ({
}
if (children) {
return cloneElement(children, oriProps => ({
className: classNames(`${prefixCls}-custom-component`, oriProps?.className),
className: classNames(`${prefixCls}-custom-component`, oriProps?.className, motionClassName),
}));
}
return React.createElement(component as any, newProps, numberNode);

View File

@ -1337,6 +1337,38 @@ exports[`renders ./components/badge/demo/no-wrapper.md correctly 1`] = `
</sup>
</span>
</div>
<div
class="ant-space-item"
style="margin-right:8px"
>
<span
class="ant-badge ant-badge-not-a-wrapper"
>
<span
aria-label="clock-circle"
class="anticon anticon-clock-circle ant-scroll-number-custom-component"
role="img"
style="color:#f5222d"
>
<svg
aria-hidden="true"
data-icon="clock-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-space-item"
style="margin-right:8px"

View File

@ -17,6 +17,7 @@ Used in standalone when children is empty.
```jsx
import { Badge, Space, Switch } from 'antd';
import { ClockCircleOutlined } from '@ant-design/icons';
const Demo = () => {
const [show, setShow] = React.useState(true);
@ -30,6 +31,7 @@ const Demo = () => {
}}
/>
<Badge count={show ? 25 : 0} />
<Badge count={show ? <ClockCircleOutlined style={{ color: '#f5222d' }} /> : 0} />
<Badge count={show ? 4 : 0} className="site-badge-count-4" />
<Badge
className="site-badge-count-109"
@ -45,8 +47,8 @@ ReactDOM.render(<Demo />, mountNode);
```css
.site-badge-count-4 .ant-badge-count {
background-color: #fff;
color: #999;
background-color: #fff;
box-shadow: 0 0 0 1px #d9d9d9 inset;
}
```

View File

@ -76,6 +76,13 @@ const Badge: CompoundedComponent = ({
return (isEmpty || (isZero && !showZero)) && !showAsDot;
}, [mergedCount, isZero, showZero, showAsDot]);
// Count should be cache in case hidden change it
const countRef = useRef(count);
if (!isHidden) {
countRef.current = count;
}
const livingCount = countRef.current;
// We need cache count since remove motion should not change count display
const displayCountRef = useRef(mergedCount);
if (!isHidden) {
@ -111,7 +118,8 @@ const Badge: CompoundedComponent = ({
// =============================== Render ===============================
// >>> Title
const titleNode =
title ?? (typeof count === 'string' || typeof count === 'number' ? count : undefined);
title ??
(typeof livingCount === 'string' || typeof livingCount === 'number' ? livingCount : undefined);
// >>> Status Text
const statusTextNode =
@ -119,9 +127,9 @@ const Badge: CompoundedComponent = ({
// >>> Display Component
const displayNode =
!count || typeof count !== 'object'
!livingCount || typeof livingCount !== 'object'
? undefined
: cloneElement(count, oriProps => ({
: cloneElement(livingCount, oriProps => ({
style: {
...mergedStyle,
...oriProps.style,
@ -192,11 +200,14 @@ const Badge: CompoundedComponent = ({
scrollNumberStyle.background = color;
}
console.log('===>', isDot, scrollNumberCls);
return (
<ScrollNumber
prefixCls={scrollNumberPrefixCls}
show={!isHidden}
className={classNames(motionClassName, scrollNumberCls)}
motionClassName={motionClassName}
className={scrollNumberCls}
count={displayCount}
title={titleNode}
style={scrollNumberStyle}

View File

@ -148,6 +148,11 @@
vertical-align: middle;
}
.@{number-prefix-cls}-custom-component {
transform: none;
}
.@{number-prefix-cls}-custom-component,
.@{ant-prefix}-scroll-number {
position: relative;
top: auto;

View File

@ -236,7 +236,7 @@ Provide linkage between forms. If a sub form with `name` prop update, it will au
| getFieldError | Get the error messages by the field name | (name: [NamePath](#NamePath)) => string\[] | |
| getFieldInstance | Get field instance | (name: [NamePath](#NamePath)) => any | 4.4.0 |
| getFieldsError | Get the error messages by the fields name. Return as an array | (nameList?: [NamePath](#NamePath)\[]) => FieldError\[] | |
| getFieldsValue | Get values by a set of field names. Return according to the corresponding structure | (nameList?: [NamePath](#NamePath)\[], filterFunc?: (meta: { touched: boolean, validating: boolean }) => boolean) => any | |
| getFieldsValue | Get values by a set of field names. Return according to the corresponding structure. Default return mounted field value, but you can use `getFieldsValue(true)` to get all values | (nameList?: [NamePath](#NamePath)\[], filterFunc?: (meta: { touched: boolean, validating: boolean }) => boolean) => any | |
| getFieldValue | Get the value by the field name | (name: [NamePath](#NamePath)) => any | |
| isFieldsTouched | Check if fields have been operated. Check if all fields is touched when `allTouched` is `true` | (nameList?: [NamePath](#NamePath)\[], allTouched?: boolean) => boolean | |
| isFieldTouched | Check if a field has been operated | (name: [NamePath](#NamePath)) => boolean | |

View File

@ -235,7 +235,7 @@ Form.List 渲染表单相关操作函数。
| getFieldError | 获取对应字段名的错误信息 | (name: [NamePath](#NamePath)) => string\[] | |
| getFieldInstance | 获取对应字段实例 | (name: [NamePath](#NamePath)) => any | 4.4.0 |
| getFieldsError | 获取一组字段名对应的错误信息,返回为数组形式 | (nameList?: [NamePath](#NamePath)\[]) => FieldError\[] | |
| getFieldsValue | 获取一组字段名对应的值,会按照对应结构返回 | (nameList?: [NamePath](#NamePath)\[], filterFunc?: (meta: { touched: boolean, validating: boolean }) => boolean) => any | |
| getFieldsValue | 获取一组字段名对应的值,会按照对应结构返回。默认返回现存字段值,当调用 `getFieldsValue(true)` 时返回所有值 | (nameList?: [NamePath](#NamePath)\[], filterFunc?: (meta: { touched: boolean, validating: boolean }) => boolean) => any | |
| getFieldValue | 获取对应字段名的值 | (name: [NamePath](#NamePath)) => any | |
| isFieldsTouched | 检查一组字段是否被用户操作过,`allTouched` 为 `true` 时检查是否所有字段都被操作过 | (nameList?: [NamePath](#NamePath)\[], allTouched?: boolean) => boolean | |
| isFieldTouched | 检查对应字段是否被用户操作过 | (name: [NamePath](#NamePath)) => boolean | |

View File

@ -17,7 +17,6 @@ export interface TextAreaProps extends RcTextAreaProps {
allowClear?: boolean;
bordered?: boolean;
showCount?: boolean | ShowCountProps;
maxLength?: number;
size?: SizeType;
}
@ -130,7 +129,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
// Only show text area wrapper when needed
if (showCount) {
const valueLength = [...val].length;
const valueLength = Math.min(val.length, maxLength ?? Infinity);
let dataCount = '';
if (typeof showCount === 'object') {

View File

@ -144,6 +144,18 @@ describe('TextArea', () => {
expect(textarea.prop('data-count')).toBe('5 / 5');
});
it('should minimize value between emoji length and maxLength', () => {
const wrapper = mount(<TextArea maxLength={1} showCount value="👀" />);
const textarea = wrapper.find('.ant-input-textarea');
expect(wrapper.find('textarea').prop('value')).toBe('👀');
expect(textarea.prop('data-count')).toBe('1 / 1');
// fix: 当 maxLength 长度为 2 的时候,输入 emoji 之后 showCount 会显示 1/2但是不能再输入了
const wrapper1 = mount(<TextArea maxLength={2} showCount value="👀" />);
const textarea1 = wrapper1.find('.ant-input-textarea');
expect(textarea1.prop('data-count')).toBe('2 / 2');
});
// 修改TextArea value截取规则后新增单测
it('slice emoji', () => {
const wrapper = mount(<TextArea maxLength={5} showCount value="1234😂" />);

View File

@ -153,7 +153,7 @@ function Table<RecordType extends object = any>(props: TableProps<RecordType>) {
);
const mergedSize = customizeSize || size;
const tableLocale = { ...contextLocale.Table, ...locale } as TableLocale;
const rawData: RecordType[] = dataSource || EMPTY_LIST;
const rawData: readonly RecordType[] = dataSource || EMPTY_LIST;
const { getPrefixCls } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('table', customizePrefixCls);

View File

@ -2,14 +2,14 @@ import * as React from 'react';
import { Key, GetRowKey } from '../interface';
interface MapCache<RecordType> {
data?: RecordType[];
data?: readonly RecordType[];
childrenColumnName?: string;
kvMap?: Map<Key, RecordType>;
getRowKey?: Function;
}
export default function useLazyKVMap<RecordType>(
data: RecordType[],
data: readonly RecordType[],
childrenColumnName: string,
getRowKey: GetRowKey<RecordType>,
) {
@ -25,7 +25,7 @@ export default function useLazyKVMap<RecordType>(
const kvMap = new Map<Key, RecordType>();
/* eslint-disable no-inner-declarations */
function dig(records: RecordType[]) {
function dig(records: readonly RecordType[]) {
records.forEach((record, index) => {
const rowKey = getRowKey(record, index);
kvMap.set(rowKey, record);

View File

@ -245,7 +245,7 @@ function generateSorterInfo<RecordType>(
}
export function getSortData<RecordType>(
data: RecordType[],
data: readonly RecordType[],
sortStates: SortState<RecordType>[],
childrenColumnName: string,
): RecordType[] {

View File

@ -83,7 +83,7 @@ const columns = [
| tableLayout | The [table-layout](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout) attribute of table element | - \| `auto` \| `fixed` | -<hr />`fixed` when header/columns are fixed, or using `column.ellipsis` | |
| title | Table title renderer | function(currentPageData) | - | |
| onChange | Callback executed when pagination, filters or sorter is changed | function(pagination, filters, sorter, extra: { currentDataSource: \[], action: `paginate` \| `sort` \| `filter` }) | - | |
| onHeaderRow | Set props on per header row | function(column, index) | - | |
| onHeaderRow | Set props on per header row | function(columns, index) | - | |
| onRow | Set props on per row | function(record, index) | - | |
#### onRow usage
@ -101,7 +101,7 @@ Same as `onRow` `onHeaderRow` `onCell` `onHeaderCell`
onMouseLeave: event => {}, // mouse leave row
};
}}
onHeaderRow={column => {
onHeaderRow={(columns, index) => {
return {
onClick: () => {}, // click header row
};

View File

@ -90,7 +90,7 @@ const columns = [
| tableLayout | 表格元素的 [table-layout](https://developer.mozilla.org/zh-CN/docs/Web/CSS/table-layout) 属性,设为 `fixed` 表示内容不会影响列的布局 | - \| `auto` \| `fixed` | 无<hr />固定表头/列或使用了 `column.ellipsis` 时,默认值为 `fixed` | |
| title | 表格标题 | function(currentPageData) | - | |
| onChange | 分页、排序、筛选变化时触发 | function(pagination, filters, sorter, extra: { currentDataSource: \[], action: `paginate` \| `sort` \| `filter` }) | - | |
| onHeaderRow | 设置头部行属性 | function(column, index) | - | |
| onHeaderRow | 设置头部行属性 | function(columns, index) | - | |
| onRow | 设置行属性 | function(record, index) | - | |
#### onRow 用法
@ -108,7 +108,7 @@ const columns = [
onMouseLeave: event => {},
};
}}
onHeaderRow={column => {
onHeaderRow={(columns, index) => {
return {
onClick: () => {}, // 点击表头行
};

View File

@ -176,7 +176,7 @@ export interface TableCurrentDataSource<RecordType> {
export interface SorterResult<RecordType> {
column?: ColumnType<RecordType>;
order?: SortOrder;
field?: Key | Key[];
field?: Key | readonly Key[];
columnKey?: Key;
}

View File

@ -6,7 +6,7 @@ export function getColumnKey<RecordType>(column: ColumnType<RecordType>, default
return column.key;
}
if (column.dataIndex) {
return Array.isArray(column.dataIndex) ? column.dataIndex.join('.') : column.dataIndex;
return (Array.isArray(column.dataIndex) ? column.dataIndex.join('.') : column.dataIndex) as Key;
}
return defaultKey;

View File

@ -109,6 +109,7 @@ Basic text writing, including headings, body text, lists, and more.
expandable: boolean,
suffix: string,
symbol: ReactNode,
tooltip: boolean | ReactNode,
onExpand: function(event),
onEllipsis: function(ellipsis),
}
@ -117,8 +118,8 @@ Basic text writing, including headings, body text, lists, and more.
| --- | --- | --- | --- | --- |
| expandable | Whether to be expandable | boolean | - | |
| rows | Max rows of content | number | - | |
| suffix | Suffix of ellipsis content | ReactNode | - | |
| symbol | Custom `...` symbol of ellipsis | ReactNode | `...` | |
| suffix | Suffix of ellipsis content | string | - | |
| symbol | Custom description of ellipsis | ReactNode | `Expand` | |
| tooltip | Show tooltip when ellipsis | boolean \| ReactNode | - | 4.11.0 |
| onEllipsis | Called when enter or leave ellipsis state | function(ellipsis) | - | 4.2.0 |
| onExpand | Called when expand content | function(event) | - | |

View File

@ -109,6 +109,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg
expandable: boolean,
suffix: string,
symbol: ReactNode,
tooltip: boolean | ReactNode,
onExpand: function(event),
onEllipsis: function(ellipsis),
}
@ -117,8 +118,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/GOM1KQ24O/Typography.svg
| ---------- | -------------------- | -------------------- | ------ | ------ |
| expandable | 是否可展开 | boolean | - | |
| rows | 最多显示的行数 | number | - | |
| suffix | 自定义省略内容后缀 | ReactNode | - | |
| symbol | 自定义省略符号 | ReactNode | `...` | |
| suffix | 自定义省略内容后缀 | string | - | |
| symbol | 自定义展开描述文案 | ReactNode | `展开` | |
| tooltip | 省略时,展示提示信息 | boolean \| ReactNode | - | 4.11.0 |
| onEllipsis | 触发省略时的回调 | function(ellipsis) | - | 4.2.0 |
| onExpand | 点击展开时的回调 | function(event) | - | |

View File

@ -97,7 +97,9 @@ ReactDOM.render(<LinksList />, mountNode);
- Hacknews: [Show HN: Antd A set of high-quality React components](https://news.ycombinator.com/item?id=13053137)
- Alligator: [Crafting Beautiful UIs in React Using Ant Design](https://alligator.io/react/beautiful-uis-ant-design/)
- Hackernoon: [Interesting JavaScript Libraries born in China](https://hackernoon.com/interesting-javascript-libraries-born-in-china-d50d1bb81355)
- [Introduction to Ant Design](https://blog.logrocket.com/introduction-to-ant-design/)
- [Build a React App with Ant Design Principles](https://developer.okta.com/blog/2020/09/16/ant-design-react-app)
- [Meet Antd, an enterprise React UI library](https://medium.com/javascript-in-plain-english/antd-library-what-why-useful-or-not-5fec225b639d)
## How to Contribute

View File

@ -98,8 +98,10 @@ ReactDOM.render(<LinksList />, mountNode);
- 知乎:[如何评价 Ant Design 这个项目?](https://www.zhihu.com/question/33629737)
- Hacknews: [Show HN: Antd A set of high-quality React components](https://news.ycombinator.com/item?id=13053137)
- Alligator: [Crafting Beautiful UIs in React Using Ant Design](https://alligator.io/react/beautiful-uis-ant-design/)
- Hackernoon: [Interesting JavaScript Libraries born in China](https://hackernoon.com/interesting-javascript-libraries-born-in-china-d50d1bb81355)
- [漫谈 Material Design & Ant Design](http://dwbbb.com/blog/MaterialDesignAntDesign/)
- [Introduction to Ant Design](https://blog.logrocket.com/introduction-to-ant-design/)
- [Build a React App with Ant Design Principles](https://developer.okta.com/blog/2020/09/16/ant-design-react-app)
- [Meet Antd, an enterprise React UI library](https://medium.com/javascript-in-plain-english/antd-library-what-why-useful-or-not-5fec225b639d)
## 如何贡献

View File

@ -112,7 +112,7 @@
"@ant-design/colors": "^5.0.0",
"@ant-design/icons": "^4.4.0",
"@ant-design/react-slick": "~0.28.1",
"@babel/runtime": "^7.11.2",
"@babel/runtime": "^7.12.5",
"array-tree-filter": "^2.1.0",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
@ -140,7 +140,7 @@
"rc-slider": "~9.7.1",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
"rc-table": "~7.12.0",
"rc-table": "~7.13.0",
"rc-tabs": "~11.7.0",
"rc-textarea": "~0.3.0",
"rc-tooltip": "~5.0.0",