Merge remote-tracking branch 'origin/master' into next

This commit is contained in:
zombiej 2022-03-01 18:46:33 +08:00
commit d4ea3b6b23
59 changed files with 912 additions and 662 deletions

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: check-inactive
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'check-inactive'
inactive-label: 'Inactive'

View File

@ -9,14 +9,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: need reproduce
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '🤔 Need Reproduce'
inactive-day: 3
- name: needs more info
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: 'needs-more-info'

View File

@ -12,7 +12,7 @@ jobs:
steps:
- name: help wanted
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
@ -26,7 +26,7 @@ jobs:
- name: 🤔 Need Reproduce
if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
@ -40,7 +40,7 @@ jobs:
- name: Usage
if: github.event.label.name == 'Usage' || github.event.label.name == 'Question'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
@ -52,7 +52,7 @@ jobs:
- name: 3.x
if: github.event.label.name == '3.x'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
@ -64,7 +64,7 @@ jobs:
- name: invalid
if: github.event.label.name == 'Invalid'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
@ -76,7 +76,7 @@ jobs:
- name: rtl
if: github.event.label.name == 'rtl'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'add-assignees'
assignees: 'xrkffgg'

View File

@ -16,7 +16,7 @@ jobs:
- name: check invalid
if: (contains(github.event.issue.body, 'ant-design-issue-helper') == false) && (steps.checkUser.outputs.result == 'false')
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,add-labels,close-issue'
issue-number: ${{ github.event.issue.number }}
@ -27,7 +27,7 @@ jobs:
你好 @${{ github.event.issue.user.login }},为了能够进行高效沟通,我们对 issue 有一定的格式要求,你的 issue 因为不符合要求而被自动关闭。你可以通过 [issue 助手](http://new-issue.ant.design) 来创建 issue 以方便我们定位错误。谢谢配合!
- name: check website
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
id: checkid
with:
actions: 'check-issue'
@ -37,7 +37,7 @@ jobs:
- name: deal website
if: steps.checkid.outputs.check-result == 'true'
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
issue-number: ${{ github.event.issue.number }}
@ -63,7 +63,7 @@ jobs:
- name: check ie
if: contains(github.event.issue.body, 'ant-design-issue-helper') == true && contains(github.event.issue.title, 'IE9') == true || contains(github.event.issue.title, 'IE 9') == true || contains(github.event.issue.title, 'IE10') == true || contains(github.event.issue.title, 'IE 10') == true || contains(github.event.issue.title, 'IE11') == true || contains(github.event.issue.title, 'IE 11') == true || contains(github.event.issue.title, 'Internet Explorer') == true || contains(github.event.issue.body, 'IE9') == true || contains(github.event.issue.body, 'IE 9') == true || contains(github.event.issue.body, 'IE10') == true || contains(github.event.issue.body, 'IE 10') == true || contains(github.event.issue.body, 'IE11') == true || contains(github.event.issue.body, 'IE 11') == true || contains(github.event.issue.body, 'Internet Explorer') == true
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'add-labels'
issue-number: ${{ github.event.issue.number }}
@ -71,7 +71,7 @@ jobs:
- name: check ie
if: contains(github.event.issue.body, 'ant-design-issue-helper') == true && contains(github.event.issue.title, 'IE9') == true || contains(github.event.issue.title, 'IE 9') == true || contains(github.event.issue.title, 'IE10') == true || contains(github.event.issue.title, 'IE 10') == true || contains(github.event.issue.title, 'IE11') == true || contains(github.event.issue.title, 'IE 11') == true || contains(github.event.issue.title, 'Internet Explorer') == true || contains(github.event.issue.body, 'IE9') == true || contains(github.event.issue.body, 'IE 9') == true || contains(github.event.issue.body, 'IE10') == true || contains(github.event.issue.body, 'IE 10') == true
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.issue.number }}

View File

@ -12,7 +12,7 @@ jobs:
steps:
- name: remove inactive
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
uses: actions-cool/issues-helper@v2
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
issue-number: ${{ github.event.issue.number }}

View File

@ -13,7 +13,7 @@ jobs:
with:
filter-label: 'BranchAutoMerge'
filter-creator-authority: 'write'
filter-head-ref: 'master, feature, master-merge-feature, feature-merge-master'
filter-head-ref: 'master, feature, next, master-merge-feature, feature-merge-master, next-merge-master'
filter-support-fork: false
skip-run-names: 'deploy preview, pr-check-ci, build preview failed, suggest-related-links'
conflict-review-body: '😅 This branch has conflicts that must be resolved!'

View File

@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
if: (github.event.pull_request.head.ref == 'feature' || github.event.pull_request.head.ref == 'master') && github.event.pull_request.head.user.login == 'ant-design'
steps:
- uses: actions-cool/issues-helper@v2
- uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
issue-number: ${{ github.event.number }}

View File

@ -16,25 +16,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: make release
uses: actions-cool/release-helper@v1
uses: actions-cool/release-helper@v2
with:
triger: 'tag'
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
branch: 'master'
dingding-token: ${{ secrets.DINGDING_BOT_TOKEN }}
dingding-msg: 'CHANGELOG.zh-CN.md'
msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ'
msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志'
prettier: true
prerelease-filter: '-, a, b, A, B'
- name: make release - Bigfish
uses: actions-cool/release-helper@v1
with:
triger: 'tag'
changelogs: 'CHANGELOG.en-US.md, CHANGELOG.zh-CN.md'
branch: 'master'
dingding-token: ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }}
dingding-token: ${{ secrets.DINGDING_BOT_TOKEN }} ${{ secrets.DINGDING_BOT_BIGFISH_TOKEN }}
dingding-msg: 'CHANGELOG.zh-CN.md'
msg-poster: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*zx7LTI_ECSAAAAAAAAAAAABkARQnAQ'
msg-footer: '💬 前往 [**Ant Design Releases**]({{url}}) 查看更新日志'

View File

@ -14,7 +14,7 @@ jobs:
forbid-paths: '.github/, scripts/'
forbid-files: 'CHANGELOG.zh-CN.md, CHANGELOG.en-US.md, LICENSE'
skip-verify-authority: 'write'
assignees: 'afc163, zombieJ, xrkffgg'
assignees: 'afc163, zombieJ, xrkffgg, MadCcc'
comment: |
Hi @${{ github.event.pull_request.user.login }}. Thanks for your contribution. The path `.github/` or `scripts/` and `CHANGELOG` `package.json` is only maintained by team members. This current PR will be closed and team members will help on this.
close: true

View File

@ -8,6 +8,25 @@
"plugins": ["stylelint-declaration-block-no-ignored-properties"],
"rules": {
"function-name-case": ["lower", { "ignoreFunctions": ["/colorPalette/"] }],
"function-no-unknown": [
true,
{
"ignoreFunctions": [
"fade",
"tint",
"darken",
"ceil",
"fadein",
"floor",
"unit",
"shade",
"lighten",
"percentage",
"-",
"~`colorPalette"
]
}
],
"no-descending-specificity": null,
"no-invalid-position-at-import-rule": null,
"declaration-empty-line-before": null,

View File

@ -15,6 +15,32 @@ timeline: true
---
## 4.18.9
`2022-02-28`
- 🆕 New theme less variable for Radio, Divider, Modal, Dropdown, Drawer. [#34194](https://github.com/ant-design/ant-design/pull/34194) [#34187](https://github.com/ant-design/ant-design/pull/34187) [#34191](https://github.com/ant-design/ant-design/pull/34191) [#34189](https://github.com/ant-design/ant-design/pull/34189) [#34188](https://github.com/ant-design/ant-design/pull/34188) [@qdzhaoxiaodao](https://github.com/qdzhaoxiaodao)
- 💄 Fix Dropdown item wrap style when text is too long. [#34177](https://github.com/ant-design/ant-design/pull/34177)
- TypeScript
- 🐞 Fix Upload `onChange` parameter generic passing. [#34161](https://github.com/ant-design/ant-design/pull/34161) [@wangcch](https://github.com/wangcch)
## 4.18.8
`2022-02-21`
- 🐞 Fix `getContainer` config not working bug when called multi-times via `message.config`. [#34123](https://github.com/ant-design/ant-design/pull/34123) [@TrickyPi](https://github.com/TrickyPi)
- 🐞 Fix invalid context value cache in Menu component. [#34121](https://github.com/ant-design/ant-design/pull/34121) [@mrwd2009](https://github.com/mrwd2009)
- 🐞 Fix ConfigProvider config theme on server side crash, and warning for useless in SSR instead. [#34118](https://github.com/ant-design/ant-design/pull/34118)
- Table
- ⚡️ Fix Table render twice on first mount. [#34106](https://github.com/ant-design/ant-design/pull/34106)
- ⚡️ Optimized Table rendering performance, now will skip useless rendering when deprecated `column.render: () => { children, props }` method is not used. [#34075](https://github.com/ant-design/ant-design/pull/34075)
- 🐞 Fix incorrect copy text of Typography after children is updated when enable `copyable`. [#34034](https://github.com/ant-design/ant-design/pull/34034) [@opopeieie](https://github.com/opopeieie)
- ⚡️ Optimize Avatar, List, Pagination, Steps to avoid additional render on mount if unnecessary. [34122](https://github.com/ant-design/ant-design/pull/34122)
- 💄 Fix Form broken style when Select item is too long in horizontal layout. [#34117](https://github.com/ant-design/ant-design/pull/34117)
- 🇸🇰 Improve texts for Table, Form and Modal in `sk_SK`. [#34061](https://github.com/ant-design/ant-design/pull/34061) [@xseman](https://github.com/xseman)
- TypeScript
- 🤖 Export `SiderProps` type from Layout component. [#34137](https://github.com/ant-design/ant-design/pull/34137) [@Picsong](https://github.com/Picsong)
## 4.18.7
`2022-02-14`

View File

@ -15,6 +15,33 @@ timeline: true
---
## 4.18.9
`2022-02-28`
- 🆕 新增 Radio、Divider、Modal、Dropdown、Drawer 主题变量。[#34194](https://github.com/ant-design/ant-design/pull/34194) [#34187](https://github.com/ant-design/ant-design/pull/34187) [#34191](https://github.com/ant-design/ant-design/pull/34191) [#34189](https://github.com/ant-design/ant-design/pull/34189) [#34188](https://github.com/ant-design/ant-design/pull/34188) [@qdzhaoxiaodao](https://github.com/qdzhaoxiaodao)
- 🐞 修复 Form 组件当 `preserve``false``initialValues` 会被更改的问题。[#34153](https://github.com/ant-design/ant-design/pull/34153)
- 💄 修复 Dropdown 菜单项文本太长没有换行的问题。[#34177](https://github.com/ant-design/ant-design/pull/3417)
- TypeScript
- 🐞 修复 Upload `onChange` 参数泛型传递。[#34161](https://github.com/ant-design/ant-design/pull/34161) [@wangcch](https://github.com/wangcch)
## 4.18.8
`2022-02-21`
- 🐞 修复 `message.config` 多次配置 `getContainer` 时无法生效的问题。[#34123](https://github.com/ant-design/ant-design/pull/34123) [@TrickyPi](https://github.com/TrickyPi)
- 🐞 修复 Menu 组件中无效的缓存逻辑。[#34121](https://github.com/ant-design/ant-design/pull/34121) [@mrwd2009](https://github.com/mrwd2009)
- 🐞 修复 ConfigProvider 在服务端配置主题会崩溃的问题,同时现在会提示动态主题于 SSR 上无效。[#34118](https://github.com/ant-design/ant-design/pull/34118)
- Table
- ⚡️ 修复 Table 在首次加载时会渲染两次的问题。[#34106](https://github.com/ant-design/ant-design/pull/34106)
- ⚡️ 优化 Table 渲染性能,现在不使用废弃 `column.render: () => { children, props }` 方法时默认会跳过无用渲染。[#34075](https://github.com/ant-design/ant-design/pull/34075)
- 🐞 修复 Typography 启用 `copyable``children` 内容变化后复制内容没变的问题。[#34034](https://github.com/ant-design/ant-design/pull/34034) [@opopeieie](https://github.com/opopeieie)
- ⚡️ 优化 Avatar、List、Pagination、Steps 以防止初始化时非必要的额外渲染。[34122](https://github.com/ant-design/ant-design/pull/34122)
- 💄 修复 Form 下 Select 内容太长导致布局换行的问题。[#34117](https://github.com/ant-design/ant-design/pull/34117)
- 🇸🇰 完善 `sk-SK` 中 Table、Form、Modal 的文案。[#34061](https://github.com/ant-design/ant-design/pull/34061) [@xseman](https://github.com/xseman)
- TypeScript
- 🤖 导出 Layout 组件的 `SiderProps` 类型。[#34137](https://github.com/ant-design/ant-design/pull/34137) [@Picsong](https://github.com/Picsong)
## 4.18.7
`2022-02-14`

View File

@ -102,7 +102,10 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
const size = customSize === 'default' ? groupSize : customSize;
const screens = useBreakpoint();
const needResponsive = Object.keys(typeof size === 'object' ? size || {} : {}).some(key =>
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key),
);
const screens = useBreakpoint(needResponsive);
const responsiveSizeStyle: React.CSSProperties = React.useMemo(() => {
if (typeof size !== 'object') {
return {};

View File

@ -28,7 +28,7 @@ Cascade selection box.
| className | The additional css class | string | - | |
| defaultValue | Initial selected value | string\[] \| number\[] | \[] | |
| disabled | Whether disabled select | boolean | false | |
| displayRender | The render function of displaying single selected options. You can use tagRender for multiple mode | (label, selectedOptions) => ReactNode | label => label.join(`/`) | |
| displayRender | The render function of displaying selected options | (label, selectedOptions) => ReactNode | label => label.join(`/`) | `multiple`: 4.18.0 |
| dropdownClassName | The additional className of popup overlay | string | - | 4.17.0 |
| dropdownRender | Customize dropdown content | (menus: ReactNode) => ReactNode | - | 4.4.0 |
| expandIcon | Customize the current item expand icon | ReactNode | - | 4.4.0 |
@ -75,6 +75,10 @@ interface Option {
label?: React.ReactNode;
disabled?: boolean;
children?: Option[];
// Determines if this is a leaf node(effective when `loadData` is specified).
// `false` will force trade TreeNode as a parent node.
// Show expand icon even if the current node has no children.
isLeaf?: boolean;
}
```

View File

@ -29,7 +29,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg
| className | 自定义类名 | string | - | |
| defaultValue | 默认的选中项 | string\[] \| number\[] | \[] | |
| disabled | 禁用 | boolean | false | |
| displayRender | 单选模式下选择后展示的渲染函数,多选请使用 tagRender | (label, selectedOptions) => ReactNode | label => label.join(`/`) | |
| displayRender | 选择后展示的渲染函数 | (label, selectedOptions) => ReactNode | label => label.join(`/`) | `multiple`: 4.18.0 |
| dropdownClassName | 自定义浮层类名 | string | - | 4.17.0 |
| dropdownRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | 4.4.0 |
| expandIcon | 自定义次级菜单展开图标 | ReactNode | - | 4.4.0 |
@ -77,6 +77,9 @@ interface Option {
label?: React.ReactNode;
disabled?: boolean;
children?: Option[];
// 标记是否为叶子节点,设置了 `loadData` 时有效
// 设为 `false` 时会强制标记为父节点,即使当前节点没有 children也会显示展开图标
isLeaf?: boolean;
}
```

View File

@ -1,7 +1,17 @@
import { kebabCase } from 'lodash';
import canUseDom from 'rc-util/lib/Dom/canUseDom';
import ConfigProvider from '..';
import { resetWarned } from '../../_util/devWarning';
let mockCanUseDom = true;
jest.mock('rc-util/lib/Dom/canUseDom', () => () => mockCanUseDom);
describe('ConfigProvider.Theme', () => {
beforeEach(() => {
mockCanUseDom = true;
});
const colorList = ['primaryColor', 'successColor', 'warningColor', 'errorColor', 'infoColor'];
colorList.forEach(colorName => {
@ -22,4 +32,21 @@ describe('ConfigProvider.Theme', () => {
expect(themeStyle.innerHTML).toContain(`--bamboo-${kebabCase(colorName)}: rgb(0, 0, 255)`);
});
});
it('warning for SSR', () => {
resetWarned();
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mockCanUseDom = false;
expect(canUseDom()).toBeFalsy();
ConfigProvider.config({
theme: {},
});
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: ConfigProvider] SSR do not support dynamic theme with css variables.',
);
errorSpy.mockRestore();
});
});

View File

@ -1,9 +1,11 @@
/* eslint-disable import/prefer-default-export, prefer-destructuring */
import { updateCSS } from 'rc-util/lib/Dom/dynamicCSS';
import canUseDom from 'rc-util/lib/Dom/canUseDom';
import { TinyColor } from '@ctrl/tinycolor';
import { generate } from '@ant-design/colors';
import { Theme } from './context';
import devWarning from '../_util/devWarning';
const dynamicStyleMark = `-ant-${Date.now()}-${Math.random()}`;
@ -86,12 +88,16 @@ export function registerTheme(globalPrefixCls: string, theme: Theme) {
key => `--${globalPrefixCls}-${key}: ${variables[key]};`,
);
updateCSS(
`
if (canUseDom()) {
updateCSS(
`
:root {
${cssList.join('\n')}
}
`,
`${dynamicStyleMark}-dynamic-theme`,
);
`${dynamicStyleMark}-dynamic-theme`,
);
} else {
devWarning(false, 'ConfigProvider', 'SSR do not support dynamic theme with css variables.');
}
}

View File

@ -13,7 +13,7 @@
top: -0.06em;
display: inline-block;
height: 0.9em;
margin: 0 8px;
margin: 0 @divider-vertical-gutter;
vertical-align: middle;
border-top: 0;
border-left: @border-width-base solid @divider-color;

View File

@ -134,8 +134,8 @@
margin: 0;
color: @heading-color;
font-weight: 500;
font-size: @font-size-lg;
line-height: 22px;
font-size: @drawer-title-font-size;
line-height: @drawer-title-line-height;
}
&-content {

View File

@ -199,7 +199,6 @@
font-weight: normal;
font-size: @dropdown-font-size;
line-height: @dropdown-line-height;
white-space: nowrap;
cursor: pointer;
transition: all @animation-duration-slow;
@ -217,7 +216,7 @@
&-selected {
color: @dropdown-selected-color;
background-color: @item-active-bg;
background-color: @dropdown-selected-bg;
}
&:hover {

View File

@ -76,13 +76,148 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input"
id="advanced_search_field-1"
placeholder="placeholder"
type="text"
value=""
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="advanced_search_field-1_list_0"
aria-autocomplete="list"
aria-controls="advanced_search_field-1_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-1_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-1"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</span>
</div>
<div>
<div
class="ant-select-dropdown"
style="opacity:0;pointer-events:none"
>
<div>
<div
id="advanced_search_field-1_list"
role="listbox"
style="height:0;width:0;overflow:hidden"
>
<div
aria-label="1"
aria-selected="false"
id="advanced_search_field-1_list_0"
role="option"
>
1
</div>
<div
aria-label="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
aria-selected="true"
id="advanced_search_field-1_list_1"
role="option"
>
2
</div>
</div>
<div
class="rc-virtual-list"
style="position:relative"
>
<div
class="rc-virtual-list-holder"
style="max-height:256px;overflow-y:auto;overflow-anchor:none"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display:flex;flex-direction:column"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
title="1"
>
<div
class="ant-select-item-option-content"
>
1
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
/>
</div>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-selected"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
<div
class="ant-select-item-option-content"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
</div>
@ -193,13 +328,148 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input"
id="advanced_search_field-4"
placeholder="placeholder"
type="text"
value=""
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="advanced_search_field-4_list_0"
aria-autocomplete="list"
aria-controls="advanced_search_field-4_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-4_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-4"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</span>
</div>
<div>
<div
class="ant-select-dropdown"
style="opacity:0;pointer-events:none"
>
<div>
<div
id="advanced_search_field-4_list"
role="listbox"
style="height:0;width:0;overflow:hidden"
>
<div
aria-label="1"
aria-selected="false"
id="advanced_search_field-4_list_0"
role="option"
>
1
</div>
<div
aria-label="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
aria-selected="true"
id="advanced_search_field-4_list_1"
role="option"
>
2
</div>
</div>
<div
class="rc-virtual-list"
style="position:relative"
>
<div
class="rc-virtual-list-holder"
style="max-height:256px;overflow-y:auto;overflow-anchor:none"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display:flex;flex-direction:column"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
title="1"
>
<div
class="ant-select-item-option-content"
>
1
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
/>
</div>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-selected"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
<div
class="ant-select-item-option-content"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
</div>

View File

@ -76,13 +76,66 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input"
id="advanced_search_field-1"
placeholder="placeholder"
type="text"
value=""
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="advanced_search_field-1_list_0"
aria-autocomplete="list"
aria-controls="advanced_search_field-1_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-1_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-1"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
</div>
@ -193,13 +246,66 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input"
id="advanced_search_field-4"
placeholder="placeholder"
type="text"
value=""
/>
<div
class="ant-select ant-select-single ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-activedescendant="advanced_search_field-4_list_0"
aria-autocomplete="list"
aria-controls="advanced_search_field-4_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-4_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-4"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong"
>
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
</div>

View File

@ -21,9 +21,11 @@ Because the width of label is not fixed, you may need to adjust it by customizin
```tsx
import React, { useState } from 'react';
import { Form, Row, Col, Input, Button } from 'antd';
import { Form, Row, Col, Input, Button, Select } from 'antd';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
const { Option } = Select;
const AdvancedSearchForm = () => {
const [expand, setExpand] = useState(false);
const [form] = Form.useForm();
@ -44,7 +46,16 @@ const AdvancedSearchForm = () => {
},
]}
>
<Input placeholder="placeholder" />
{i % 3 !== 1 ? (
<Input placeholder="placeholder" />
) : (
<Select defaultValue="2">
<Option value="1">1</Option>
<Option value="2">
longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong
</Option>
</Select>
)}
</Form.Item>
</Col>,
);

View File

@ -9,10 +9,12 @@
}
.@{form-item-prefix-cls}-control {
flex: 1 1 0;
}
// https://github.com/ant-design/ant-design/issues/32980
.@{form-item-prefix-cls}-control:not(.@{ant-prefix}-col) {
// https://github.com/ant-design/ant-design/issues/32777
// https://github.com/ant-design/ant-design/issues/33773
min-width: 0;
}
// https://github.com/ant-design/ant-design/issues/32980
.@{form-item-prefix-cls}-label.@{ant-prefix}-col-24 + .@{form-item-prefix-cls}-control {
min-width: unset;
}
}

View File

@ -1,18 +1,23 @@
import { useEffect, useState } from 'react';
import { useEffect, useRef } from 'react';
import useForceUpdate from '../../_util/hooks/useForceUpdate';
import ResponsiveObserve, { ScreenMap } from '../../_util/responsiveObserve';
function useBreakpoint(): ScreenMap {
const [screens, setScreens] = useState<ScreenMap>({});
function useBreakpoint(refreshOnChange: boolean = true): ScreenMap {
const screensRef = useRef<ScreenMap>({});
const forceUpdate = useForceUpdate();
useEffect(() => {
const token = ResponsiveObserve.subscribe(supportScreens => {
setScreens(supportScreens);
screensRef.current = supportScreens;
if (refreshOnChange) {
forceUpdate();
}
});
return () => ResponsiveObserve.unsubscribe(token);
}, []);
return screens;
return screensRef.current;
}
export default useBreakpoint;

View File

@ -1,6 +1,11 @@
import Row from './row';
import Col from './col';
import useBreakpoint from './hooks/useBreakpoint';
import useInternalBreakpoint from './hooks/useBreakpoint';
// Do not export params
function useBreakpoint() {
return useInternalBreakpoint();
}
export { RowProps } from './row';

View File

@ -101,7 +101,7 @@ export { default as Image } from './image';
export type { InputNumberProps } from './input-number';
export { default as InputNumber } from './input-number';
export type { LayoutProps } from './layout';
export type { LayoutProps, SiderProps } from './layout';
export { default as Layout } from './layout';
export type { ListProps } from './list';

View File

@ -1,5 +1,5 @@
import { imageDemoTest } from '../../../tests/shared/imageTest';
describe('Layout image', () => {
imageDemoTest('layout', { skip: ['countdown.md '] });
imageDemoTest('layout', { skip: ['fixed-sider.md'] });
});

View File

@ -213,7 +213,10 @@ function List<T>({
}
}
const screens = useBreakpoint();
const needResponsive = Object.keys(grid || {}).some(key =>
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key),
);
const screens = useBreakpoint(needResponsive);
const currentBreakpoint = React.useMemo(() => {
for (let i = 0; i < responsiveArray.length; i += 1) {
const breakpoint: Breakpoint = responsiveArray[i];

View File

@ -15,7 +15,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/5FrZKStG_/List.svg
## API
另外我们封装了 [ProList](https://prolist.ant.design/),在 `antd` List 之上扩展了更多便捷易用的功能,比如多选,展开等功能,使用体验贴近 Table欢迎尝试使用。
另外我们封装了 [ProList](https://procomponents.ant.design/components/list),在 `antd` List 之上扩展了更多便捷易用的功能,比如多选,展开等功能,使用体验贴近 Table欢迎尝试使用。
### List

View File

@ -1,9 +1,12 @@
/* eslint-disable no-template-curly-in-string */
import Pagination from 'rc-pagination/lib/locale/sk_SK';
import DatePicker from '../date-picker/locale/sk_SK';
import TimePicker from '../time-picker/locale/sk_SK';
import Calendar from '../calendar/locale/sk_SK';
import { Locale } from '../locale-provider';
const typeTemplate = '${label} nie je platný ${type}';
const localeValues: Locale = {
locale: 'sk',
Pagination,
@ -11,17 +14,26 @@ const localeValues: Locale = {
TimePicker,
Calendar,
global: {
placeholder: 'Prosím vyberte',
placeholder: 'Prosím vyber',
},
Table: {
filterTitle: 'Filter',
filterConfirm: 'OK',
filterReset: 'Obnoviť',
selectAll: 'Vybrať všetko',
selectInvert: 'Vybrať opačné',
filterEmptyText: 'Žiadne filtre',
filterCheckall: 'Vyber všetky položky',
filterSearchPlaceholder: 'Vyhľadaj vo filtroch',
emptyText: 'Žiadne dáta',
selectAll: 'Označ všetky položky',
selectInvert: 'Opačný výber položiek',
selectNone: 'Odznač všetko',
selectionAll: 'Označ všetko',
sortTitle: 'Zoradiť',
expand: 'Rozbaliť riadok',
collapse: 'Zbaliť riadok',
triggerDesc: 'Kliknutím zoradíš zostupne',
triggerAsc: 'Kliknutím zoradíš vzostupne',
cancelSort: 'Kliknutím zrušíš zoradenie',
},
Modal: {
okText: 'OK',
@ -37,6 +49,12 @@ const localeValues: Locale = {
searchPlaceholder: 'Vyhľadávanie',
itemUnit: 'položka',
itemsUnit: 'položiek',
remove: 'Odstráň',
selectCurrent: 'Vyber aktuálnu stranu',
removeCurrent: 'Zmaž aktuálnu stranu',
selectAll: 'Označ všetko',
removeAll: 'Odznač všetko',
selectInvert: 'Opačný výber',
},
Upload: {
uploading: 'Nahrávanie...',
@ -60,6 +78,59 @@ const localeValues: Locale = {
PageHeader: {
back: 'Späť',
},
Form: {
optional: '(nepovinné)',
defaultValidateMessages: {
default: 'Validačná chyba poľa pre ${label}',
required: 'Prosím vlož ${label}',
enum: '${label} musí byť jeden z [${enum}]',
whitespace: '${label} nemôže byť prázdny znak',
date: {
format: '${label} formát dátumu je neplatný',
parse: '${label} nie je možné konvertovať na dátum',
invalid: '${label} je neplatný dátum',
},
types: {
string: typeTemplate,
method: typeTemplate,
array: typeTemplate,
object: typeTemplate,
number: typeTemplate,
date: typeTemplate,
boolean: typeTemplate,
integer: typeTemplate,
float: typeTemplate,
regexp: typeTemplate,
email: typeTemplate,
url: typeTemplate,
hex: typeTemplate,
},
string: {
len: '${label} musí byť ${len} znakov',
min: '${label} musí byť aspoň ${min} znakov',
max: '${label} musí byť do ${max} znakov',
range: '${label} musí byť medzi ${min}-${max} znakmi',
},
number: {
len: '${label} musí byť rovnaký ako ${len}',
min: '${label} musí byť minimálne ${min}',
max: '${label} musí byť maximálne ${max}',
range: '${label} musí byť medzi ${min}-${max}',
},
array: {
len: 'Musí byť ${len} ${label}',
min: 'Aspoň ${min} ${label}',
max: 'Najviac ${max} ${label}',
range: 'Počet ${label} musí byť medzi ${min}-${max}',
},
pattern: {
mismatch: '${label} nezodpovedá vzoru ${pattern}',
},
},
},
Image: {
preview: 'Náhľad',
},
};
export default localeValues;

View File

@ -0,0 +1,55 @@
import React, { memo, useState, useRef, useContext } from 'react';
import { mount } from 'enzyme';
import Menu from '../index';
import MenuContext from '../MenuContext';
// we use'memo' here in order to only render inner component while context changed.
const CacheInner = memo(() => {
const countRef = useRef(0);
countRef.current++;
// subscribe anchor context
useContext(MenuContext);
return (
<div>
Child Rendering Count: <span id="child_count">{countRef.current}</span>
</div>
);
});
const CacheOuter = () => {
// We use 'useState' here in order to trigger parent component rendering.
const [count, setCount] = useState(1);
const handleClick = () => {
setCount(count + 1);
};
// During each rendering phase, the cached context value returned from method 'Menu#getMemoizedContextValue' will take effect.
// So 'CacheInner' component won't rerender.
return (
<div>
<button type="button" onClick={handleClick} id="parent_btn">
Click
</button>
Parent Rendering Count: <span id="parent_count">{count}</span>
<Menu>
<Menu.Item key="test">
<CacheInner />
</Menu.Item>
</Menu>
</div>
);
};
it("Rendering on Menu without changed MenuContext won't trigger rendering on child component.", () => {
const wrapper = mount(<CacheOuter />);
const childCount = wrapper.find('#child_count').text();
wrapper.find('#parent_btn').at(0).simulate('click');
expect(wrapper.find('#parent_count').text()).toBe('2');
// child component won't rerender
expect(wrapper.find('#child_count').text()).toBe(childCount);
wrapper.find('#parent_btn').at(0).simulate('click');
expect(wrapper.find('#parent_count').text()).toBe('3');
// child component won't rerender
expect(wrapper.find('#child_count').text()).toBe(childCount);
// in order to depress warning "Warning: An update to Menu inside a test was not wrapped in act(...)."
wrapper.unmount();
});

View File

@ -6,12 +6,12 @@ import EllipsisOutlined from '@ant-design/icons/EllipsisOutlined';
import memoize from 'memoize-one';
import SubMenu, { SubMenuProps } from './SubMenu';
import Item, { MenuItemProps } from './MenuItem';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps, DirectionType } from '../config-provider';
import devWarning from '../_util/devWarning';
import { SiderContext, SiderContextProps } from '../layout/Sider';
import collapseMotion from '../_util/motion';
import { cloneElement } from '../_util/reactNode';
import MenuContext, { MenuTheme } from './MenuContext';
import MenuContext, { MenuTheme, MenuContextProps } from './MenuContext';
import MenuDivider from './MenuDivider';
export { MenuDividerProps } from './MenuDivider';
@ -66,6 +66,23 @@ class InternalMenu extends React.Component<InternalMenuProps> {
return inlineCollapsed;
}
getMemoizedContextValue = memoize(
(
cls: string,
collapsed: boolean | undefined,
the: MenuTheme | undefined,
dir: DirectionType,
disableMenuItemTitleTooltip: boolean | undefined,
): MenuContextProps => ({
prefixCls: cls,
inlineCollapsed: collapsed || false,
antdMenuTheme: the,
direction: dir,
firstLevel: true,
disableMenuItemTitleTooltip,
}),
);
renderMenu = ({ getPopupContainer, getPrefixCls, direction }: ConfigConsumerProps) => {
const rootPrefixCls = getPrefixCls();
@ -91,14 +108,13 @@ class InternalMenu extends React.Component<InternalMenuProps> {
const menuClassName = classNames(`${prefixCls}-${theme}`, className);
// TODO: refactor menu with function component
const contextValue = memoize((cls, collapsed, the, dir, disableMenuItemTitleTooltip) => ({
prefixCls: cls,
inlineCollapsed: collapsed || false,
antdMenuTheme: the,
direction: dir,
firstLevel: true,
disableMenuItemTitleTooltip,
}))(prefixCls, inlineCollapsed, theme, direction, _internalDisableMenuItemTitleTooltip);
const contextValue = this.getMemoizedContextValue(
prefixCls,
inlineCollapsed,
theme,
direction,
_internalDisableMenuItemTitleTooltip,
);
return (
<MenuContext.Provider value={contextValue}>

View File

@ -125,4 +125,35 @@ describe('message.config', () => {
transitionName: 'ant-move-up',
});
});
it('should be able to config getContainer, although messageInstance already exists', () => {
function createContainer() {
const container = document.createElement('div');
document.body.appendChild(container);
return [
container,
() => {
document.body.removeChild(container);
},
];
}
const [container1, removeContainer1] = createContainer();
const [container2, removeContainer2] = createContainer();
expect(container1.querySelector('.ant-message-notice')).toBeFalsy();
expect(container2.querySelector('.ant-message-notice')).toBeFalsy();
message.config({
getContainer: () => container1,
});
const messageText1 = 'mounted in container1';
message.info(messageText1);
expect(container1.querySelector('.ant-message-notice').textContent).toEqual(messageText1);
message.config({
getContainer: () => container2,
});
const messageText2 = 'mounted in container2';
message.info(messageText2);
expect(container2.querySelector('.ant-message-notice').textContent).toEqual(messageText2);
removeContainer1();
removeContainer2();
});
});

View File

@ -54,6 +54,7 @@ function setMessageConfig(options: ConfigOptions) {
}
if (options.getContainer !== undefined) {
getContainer = options.getContainer;
messageInstance = null; // delete messageInstance for new getContainer
}
if (options.transitionName !== undefined) {
transitionName = options.transitionName;

View File

@ -23,7 +23,7 @@
overflow: hidden;
color: @heading-color;
font-weight: 500;
font-size: @font-size-lg;
font-size: @modal-confirm-title-font-size;
line-height: 1.4;
}

View File

@ -39,9 +39,10 @@ const Pagination: React.FC<PaginationProps> = ({
size,
locale: customLocale,
selectComponentClass,
responsive,
...restProps
}) => {
const { xs } = useBreakpoint();
const { xs } = useBreakpoint(responsive);
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('pagination', customizePrefixCls);
@ -91,7 +92,7 @@ const Pagination: React.FC<PaginationProps> = ({
const renderPagination = (contextLocale: PaginationLocale) => {
const locale = { ...contextLocale, ...customLocale };
const isSmall = size === 'small' || !!(xs && !size && restProps.responsive);
const isSmall = size === 'small' || !!(xs && !size && responsive);
const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls);
const extendedClassName = classNames(
{

View File

@ -174,7 +174,7 @@ span.@{radio-prefix-cls} + * {
display: inline-block;
height: @btn-height-base;
margin: 0;
padding: 0 @padding-md - 1px;
padding: 0 @radio-button-padding-horizontal;
color: @radio-button-color;
font-size: @font-size-base;
line-height: @btn-height-base - 2px;

View File

@ -1,5 +1,4 @@
import * as React from 'react';
import omit from 'rc-util/lib/omit';
import RcSteps from 'rc-steps';
import type { ProgressDotRender } from 'rc-steps/lib/Steps';
import CheckOutlined from '@ant-design/icons/CheckOutlined';
@ -44,8 +43,8 @@ interface StepsType extends React.FC<StepsProps> {
}
const Steps: StepsType = props => {
const { percent, size, className, direction, responsive } = props;
const { xs } = useBreakpoint();
const { percent, size, className, direction, responsive, ...restProps } = props;
const { xs } = useBreakpoint(responsive);
const { getPrefixCls, direction: rtlDirection } = React.useContext(ConfigContext);
const getDirection = React.useCallback(
@ -98,7 +97,8 @@ const Steps: StepsType = props => {
return (
<RcSteps
icons={icons}
{...omit(props, ['percent', 'responsive'])}
{...restProps}
size={size}
direction={getDirection()}
stepIcon={stepIconRender}
prefixCls={prefixCls}

View File

@ -283,10 +283,12 @@
@divider-text-padding: 1em;
@divider-orientation-margin: 5%;
@divider-color: rgba(0, 0, 0, 6%);
@divider-vertical-gutter: 8px;
// Dropdown
@dropdown-selected-color: @primary-color;
@dropdown-menu-submenu-disabled-bg: @component-background;
@dropdown-selected-bg: @item-active-bg;
// Empty
@empty-font-size: @font-size-base;
@ -306,6 +308,7 @@
@radio-button-color: @btn-default-color;
@radio-button-hover-color: @primary-5;
@radio-button-active-color: @primary-7;
@radio-button-padding-horizontal: @padding-md - 1px;
@radio-disabled-button-checked-bg: @disabled-active-bg;
@radio-disabled-button-checked-color: @disabled-color;
@radio-wrapper-margin-right: 8px;
@ -563,6 +566,7 @@
@modal-footer-border-width: @border-width-base;
@modal-mask-bg: fade(@black, 45%);
@modal-confirm-body-padding: 32px 32px 24px;
@modal-confirm-title-font-size: @font-size-lg;
// Progress
// --
@ -989,6 +993,8 @@
@drawer-footer-padding-vertical: @modal-footer-padding-vertical;
@drawer-footer-padding-horizontal: @modal-footer-padding-horizontal;
@drawer-header-close-size: 56px;
@drawer-title-font-size: @font-size-lg;
@drawer-title-line-height: 22px;
// Timeline
// ---

View File

@ -338,10 +338,12 @@ html {
@divider-text-padding: 1em;
@divider-orientation-margin: 5%;
@divider-color: rgba(0, 0, 0, 6%);
@divider-vertical-gutter: 8px;
// Dropdown
@dropdown-selected-color: @primary-color;
@dropdown-menu-submenu-disabled-bg: @component-background;
@dropdown-selected-bg: @item-active-bg;
// Empty
@empty-font-size: @font-size-base;
@ -361,6 +363,7 @@ html {
@radio-button-color: @btn-default-color;
@radio-button-hover-color: @primary-5;
@radio-button-active-color: @primary-7;
@radio-button-padding-horizontal: @padding-md - 1px;
@radio-disabled-button-checked-bg: @disabled-active-bg;
@radio-disabled-button-checked-color: @disabled-color;
@radio-wrapper-margin-right: 8px;
@ -618,6 +621,7 @@ html {
@modal-footer-border-width: @border-width-base;
@modal-mask-bg: fade(@black, 45%);
@modal-confirm-body-padding: 32px 32px 24px;
@modal-confirm-title-font-size: @font-size-lg;
// Progress
// --
@ -1044,6 +1048,8 @@ html {
@drawer-footer-padding-vertical: @modal-footer-padding-vertical;
@drawer-footer-padding-horizontal: @modal-footer-padding-horizontal;
@drawer-header-close-size: 56px;
@drawer-title-font-size: @font-size-lg;
@drawer-title-line-height: 22px;
// Timeline
// ---

View File

@ -139,15 +139,25 @@ function InternalTable<RecordType extends object = any>(
'`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.',
);
const screens = useBreakpoint();
const baseColumns = React.useMemo(
() => columns || convertChildrenToColumns(children),
[columns, children],
);
const needResponsive = React.useMemo(
() => baseColumns.some((col: ColumnType<RecordType>) => col.responsive),
[baseColumns],
);
const screens = useBreakpoint(needResponsive);
const mergedColumns = React.useMemo(() => {
const matched = new Set(Object.keys(screens).filter((m: Breakpoint) => screens[m]));
return (columns || convertChildrenToColumns(children)).filter(
return baseColumns.filter(
(c: ColumnType<RecordType>) =>
!c.responsive || c.responsive.some((r: Breakpoint) => matched.has(r)),
);
}, [children, columns, screens]);
}, [baseColumns, screens]);
const tableProps = omit(props, ['className', 'style', 'columns']) as TableProps<RecordType>;

View File

@ -1100,7 +1100,7 @@ describe('Table.filter', () => {
it('should support getPopupContainer', () => {
const getPopupContainer = jest.fn(node => node.parentNode);
const wrapper = mount(
mount(
createTable({
columns: [
{
@ -1111,13 +1111,14 @@ describe('Table.filter', () => {
getPopupContainer,
}),
);
expect(wrapper.render()).toMatchSnapshot();
expect(getPopupContainer).toHaveBeenCalled();
});
it('should support getPopupContainer from ConfigProvider', () => {
const wrapper = mount(
<ConfigProvider getPopupContainer={node => node.parentNode}>
const getPopupContainer = jest.fn(node => node.parentNode);
mount(
<ConfigProvider getPopupContainer={getPopupContainer}>
{createTable({
columns: [
{
@ -1128,7 +1129,7 @@ describe('Table.filter', () => {
})}
</ConfigProvider>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(getPopupContainer).toHaveBeenCalled();
});
it('pass visible prop to filterDropdown', () => {

View File

@ -509,507 +509,3 @@ exports[`Table.filter renders filter correctly 1`] = `
exports[`Table.filter renders menu correctly 1`] = `<div />`;
exports[`Table.filter renders radio filter correctly 1`] = `<div />`;
exports[`Table.filter should support getPopupContainer 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
>
<div
class="ant-table-filter-column"
>
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-dropdown-trigger ant-table-filter-trigger ant-dropdown-open"
role="button"
tabindex="-1"
>
<span
aria-label="filter"
class="anticon anticon-filter"
role="img"
>
<svg
aria-hidden="true"
data-icon="filter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M349 838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V642H349v196zm531.1-684H143.9c-24.5 0-39.8 26.7-27.5 48l221.3 376h348.8l221.3-376c12.1-21.3-3.2-48-27.7-48z"
/>
</svg>
</span>
</span>
<div>
<div
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none;"
>
<div
class="ant-table-filter-dropdown"
>
<ul
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
data-menu-list="true"
role="menu"
tabindex="0"
>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-boy"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Boy
</span>
</span>
</li>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-girl"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Girl
</span>
</span>
</li>
<li
class="ant-dropdown-menu-submenu ant-dropdown-menu-submenu-vertical"
role="none"
>
<div
aria-controls="rc-menu-uuid-test-title-popup"
aria-expanded="false"
aria-haspopup="true"
class="ant-dropdown-menu-submenu-title"
data-menu-id="rc-menu-uuid-test-title"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
Title
</span>
<i
class="ant-dropdown-menu-submenu-arrow"
/>
</div>
</li>
</ul>
<div
aria-hidden="true"
style="display: none;"
/>
<div
class="ant-table-filter-dropdown-btns"
>
<button
class="ant-btn ant-btn-link ant-btn-sm"
disabled=""
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-sm"
type="button"
>
<span>
OK
</span>
</button>
</div>
</div>
</div>
</div>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
</div>
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="0"
>
<td
class="ant-table-cell"
>
Jack
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
>
Lucy
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
>
Tom
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
>
Jerry
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Table.filter should support getPopupContainer from ConfigProvider 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
>
<div
class="ant-table-filter-column"
>
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-dropdown-trigger ant-table-filter-trigger ant-dropdown-open"
role="button"
tabindex="-1"
>
<span
aria-label="filter"
class="anticon anticon-filter"
role="img"
>
<svg
aria-hidden="true"
data-icon="filter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M349 838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V642H349v196zm531.1-684H143.9c-24.5 0-39.8 26.7-27.5 48l221.3 376h348.8l221.3-376c12.1-21.3-3.2-48-27.7-48z"
/>
</svg>
</span>
</span>
<div>
<div
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none;"
>
<div
class="ant-table-filter-dropdown"
>
<ul
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
data-menu-list="true"
role="menu"
tabindex="0"
>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-boy"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Boy
</span>
</span>
</li>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-girl"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Girl
</span>
</span>
</li>
<li
class="ant-dropdown-menu-submenu ant-dropdown-menu-submenu-vertical"
role="none"
>
<div
aria-controls="rc-menu-uuid-test-title-popup"
aria-expanded="false"
aria-haspopup="true"
class="ant-dropdown-menu-submenu-title"
data-menu-id="rc-menu-uuid-test-title"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
Title
</span>
<i
class="ant-dropdown-menu-submenu-arrow"
/>
</div>
</li>
</ul>
<div
aria-hidden="true"
style="display: none;"
/>
<div
class="ant-table-filter-dropdown-btns"
>
<button
class="ant-btn ant-btn-link ant-btn-sm"
disabled=""
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-sm"
type="button"
>
<span>
OK
</span>
</button>
</div>
</div>
</div>
</div>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
</div>
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="0"
>
<td
class="ant-table-cell"
>
Jack
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
>
Lucy
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
>
Tom
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
>
Jerry
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -33,6 +33,8 @@ export const SELECTION_ALL = 'SELECT_ALL' as const;
export const SELECTION_INVERT = 'SELECT_INVERT' as const;
export const SELECTION_NONE = 'SELECT_NONE' as const;
const EMPTY_LIST: React.Key[] = [];
interface UseSelectionConfig<RecordType> {
prefixCls: string;
pageData: RecordType[];
@ -108,7 +110,7 @@ export default function useSelection<RecordType>(
// ========================= Keys =========================
const [mergedSelectedKeys, setMergedSelectedKeys] = useMergedState(
selectedRowKeys || defaultSelectedRowKeys || [],
selectedRowKeys || defaultSelectedRowKeys || EMPTY_LIST,
{
value: selectedRowKeys,
},
@ -215,7 +217,7 @@ export default function useSelection<RecordType>(
// Reset if rowSelection reset
React.useEffect(() => {
if (!rowSelection) {
setMergedSelectedKeys([]);
setMergedSelectedKeys(EMPTY_LIST);
}
}, [!!rowSelection]);

View File

@ -197,10 +197,7 @@ const Base = React.forwardRef((props: InternalBlockProps, ref: any) => {
e?.preventDefault();
e?.stopPropagation();
if (copyConfig.text === undefined) {
copyConfig.text = String(children);
}
copy(copyConfig.text || '');
copy(copyConfig.text || String(children) || '');
setCopied(true);

View File

@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { SmileOutlined, LikeOutlined } from '@ant-design/icons';
import * as copyObj from 'copy-to-clipboard';
import Base from '../Base';
@ -206,5 +207,34 @@ describe('Typography copy', () => {
wrapper.find('.ant-typography-copy').first().simulate('click');
expect(onDivClick).not.toBeCalled();
});
it('copy to clipboard', done => {
const spy = jest.spyOn(copyObj, 'default');
const originText = 'origin text.';
const nextText = 'next text.';
const Test = () => {
const [dynamicText, setDynamicText] = React.useState(originText);
React.useEffect(() => {
setTimeout(() => {
setDynamicText(nextText);
}, 500);
});
return (
<Base component="p" copyable>
{dynamicText}
</Base>
);
};
const wrapper = mount(<Test />);
const copyBtn = wrapper.find('.ant-typography-copy').first();
copyBtn.simulate('click');
expect(spy.mock.calls[0][0]).toEqual(originText);
setTimeout(() => {
spy.mockReset();
copyBtn.simulate('click');
expect(spy.mock.calls[0][0]).toEqual(nextText);
done();
}, 500);
});
});
});

View File

@ -21,6 +21,20 @@ describe('Upload.typescript', () => {
expect(upload).toBeTruthy();
});
it('onChange params', () => {
type IFile = {
customFile: File;
};
const upload = (
<Upload<IFile> onChange={({ file }) => file.response?.customFile}>
<span>click to upload</span>
</Upload>
);
expect(upload).toBeTruthy();
});
it('onChange in UploadProps', () => {
const uploadProps: UploadProps<File> = {
onChange: ({ file }) => file,

View File

@ -104,7 +104,7 @@ export interface UploadProps<T = any> extends Pick<RcUploadProps, 'capture'> {
file: RcFile,
FileList: RcFile[],
) => BeforeUploadValueType | Promise<BeforeUploadValueType>;
onChange?: (info: UploadChangeParam<T>) => void;
onChange?: (info: UploadChangeParam<UploadFile<T>>) => void;
onDrop?: (event: React.DragEvent<HTMLDivElement>) => void;
listType?: UploadListType;
className?: string;

View File

@ -76,6 +76,6 @@ lessc --js --modify-var="ant-prefix=custom" antd/dist/antd.variable.less modifie
### 相关变更
为了实现 CSS Variable 并保持原始用法兼容性,我们于 `dist/antd.xxx.less` 文件中添加了 `@root-entry-name: xxx;` 入口注入以支持 less 动态加载对应的 less 文件。一般情况下,你不需要关注该变化。但是,如果你的项目中直接引用了 `lib|es` 目录下的 less 文件你需要在 less 入口处配置 `@root-entry-name: default;` (或者 `@root-entry-name: variable;`)以使 less 可以找到正确的入口。
为了实现 CSS Variable 并保持原始用法兼容性,我们于 `dist/antd.xxx.less` 文件中添加了 `@root-entry-name: xxx;` 入口注入以支持 less 动态加载对应的 less 文件。一般情况下,你不需要关注该变化。但是,如果你的项目中直接引用了 `lib|es` 目录下的 less 文件,那么你需要在 less 入口处配置 `@root-entry-name: default;` (或者 `@root-entry-name: variable;`)以使 less 可以找到正确的入口。
此外,我们将 `lib|es/style/minxins/index.less` 中的 `@import 'motion'``@import 'reset'` 迁移至了 `lib|es/style/themes/xxx.less` 中,因为这两个文件依赖了主题相关变量。如果你使用了相关内部方法,请自行调整。当然,我们还是建议直接使用 `dist` 目录下的 `antd.less` 文件而非调用内部文件,因为它们经常会受重构影响。

View File

@ -3,13 +3,13 @@ order: 3
title: Real project with umi
---
In real project development, you may need data flow solutions such as Redux or MobX. Ant Design React is a UI library that can be used with data flow solutions and application frameworks in any React ecosystem. Based on the business scenario, we launched a pluggable enterprise-level application framework umi, which is recommended for use in the project.
In real project development, you may need data flow solutions such as Redux or MobX. Ant Design React is a UI library that can be used with data flow solutions and application frameworks in any React ecosystem. Based on the business scenario, we launched a pluggable enterprise-level application framework [Umi](https://umijs.org), which is recommended for use in the project.
And [umi](https://umijs.org) is a routing-based framework that supports [next.js-like conventional routing](https://umijs.org/docs/convention-routing) and various advanced routing functions, such as [routing-level on-demand loading](https://umijs.org/config#dynamicimport). With a complete [plugin system](https://umijs.org/plugins/api) that covers every life cycle from source code to build product, umi is able to support various functional extensions and business needs; meanwhile [Umi UI](https://umijs.org/docs/use-umi-ui) is provided to enhance the development experience and development efficiency through Visual Aided Programming (VAP).
And [Umi](https://umijs.org) is a routing-based framework that supports [next.js-like conventional routing](https://umijs.org/docs/convention-routing) and various advanced routing functions, such as [routing-level on-demand loading](https://umijs.org/config#dynamicimport). With a complete [plugin system](https://umijs.org/plugins/api) that covers every life cycle from source code to build product, Umi is able to support various functional extensions and business needs; meanwhile [Umi UI](https://umijs.org/docs/use-umi-ui) is provided to enhance the development experience and development efficiency through Visual Aided Programming (VAP).
> You may also be interested in [Ant Design Pro](https://pro.ant.design/), an Out-of-box UI solution for enterprise applications based on umi, dva and ant design.
> You may also be interested in [Ant Design Pro](https://pro.ant.design/), an Out-of-box UI solution for enterprise applications based on Umi and antd.
This article will guide you to create a simple application from zero using Umi, dva and antd.
This article will guide you to create a simple application from zero using Umi and antd.
## Install Umi
@ -62,7 +62,7 @@ run `yarn start` then open [http://localhost:8000/products](http://localhost:800
## Write UI Components
As your application grows and you notice you are sharing UI elements between multiple pages (or using them multiple times on the same page), in umi it's called reusable components.
As your application grows and you notice you are sharing UI elements between multiple pages (or using them multiple times on the same page), in Umi it's called reusable components.
Let's create a `ProductList` component that we can use in multiple places to show a list of products.
@ -210,7 +210,7 @@ export default (
);
```
Click here [Quick Start](https://prolayout.ant.design/getting-started).
Click here [Quick Start](https://procomponents.ant.design/en-US/components/layout).
## ProTable
@ -263,7 +263,7 @@ const Products = () => {
};
```
ProTable provides preset logic to handle loading, pagination and search forms, which can greatly reduce the amount of code, click here [Quick Start](https://protable.ant.design/getting-started).
ProTable provides preset logic to handle loading, pagination and search forms, which can greatly reduce the amount of code, click here [ProTable](https://procomponents.ant.design/en-US/components/table).
## Build
@ -289,9 +289,9 @@ We have completed a simple application, but you may still have lots of questions
You can:
- Visit [umi official website](https://umijs.org/) and [dva official website](https://dvajs.com/)
- Know [the umi routes](https://umijs.org/zh/guide/router.html)
- Know [how to deploy umi application](https://umijs.org/zh/guide/deploy.html)
- Visit [Umi official website](https://umijs.org/)
- Know [Umi routes](https://umijs.org/docs/routing)
- Know [how to deploy Umi application](https://umijs.org/docs/deployment)
- Scaffolding out of the box [Ant Design Pro](https://pro.ant.design)
- Advanced Layout [ProLayout](https://prolayout.ant.design)
- Advanced Table [ProTable](https://protable.ant.design)
- Advanced Layout [ProLayout](https://procomponents.ant.design/en-US/components/layout)
- Advanced Table [ProTable](https://procomponents.ant.design/en-US/components/table)

View File

@ -5,11 +5,11 @@ title: 项目实战
在真实项目开发中,你可能会需要 Redux 或者 MobX 这样的数据流方案Ant Design React 作为一个 UI 库,可以和任何 React 生态圈内的数据流方案以及应用框架搭配使用。我们基于业务场景的场景,推出了可插拔的企业级应用框架 umi推荐你在项目中使用。
[umi](https://umijs.org/zh-CN) 则是一个可插拔的企业级 react 应用框架。umi 以路由为基础的,支持[类 next.js 的约定式路由](https://umijs.org/zh-CN/docs/convention-routing),以及各种进阶的路由功能,并以此进行功能扩展,比如[支持路由级的按需加载](https://umijs.org/zh-CN/config#dynamicimport)。然后配以完善的[插件体系](https://umijs.org/zh-CN/plugins/api),覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求,同时提供 [Umi UI](https://umijs.org/zh-CN/docs/use-umi-ui) 通过可视化辅助编程VAP提高开发体验和研发效率。
[umi](https://umijs.org/zh-CN) 则是一个可插拔的企业级 react 应用框架。Umi 以路由为基础的,支持[类 next.js 的约定式路由](https://umijs.org/zh-CN/docs/convention-routing),以及各种进阶的路由功能,并以此进行功能扩展,比如[支持路由级的按需加载](https://umijs.org/zh-CN/config#dynamicimport)。然后配以完善的[插件体系](https://umijs.org/zh-CN/plugins/api),覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求,同时提供 [Umi UI](https://umijs.org/zh-CN/docs/use-umi-ui) 通过可视化辅助编程VAP提高开发体验和研发效率。
> 你可能也会对 [Ant Design Pro](https://pro.ant.design/) 感兴趣,这是一个基于 umi、dva 和 ant design 的开箱即用的中台前端/设计解决方案。
> 你可能也会对 [Ant Design Pro](https://pro.ant.design/) 感兴趣,这是一个基于 Umi 和 antd 的开箱即用的中台前端/设计解决方案。
本文会引导你使用 Umi、dva 和 antd 从 0 开始创建一个简单应用。
本文会引导你使用 Umi 和 antd 从 0 开始创建一个简单应用。
## 安装 Umi
@ -56,7 +56,7 @@ export default defineConfig({
## 编写 UI Component
随着应用的发展,你会需要在多个页面分享 UI 元素 (或在一个页面使用多次),在 umi 里你可以把这部分抽成 component 。
随着应用的发展,你会需要在多个页面分享 UI 元素 (或在一个页面使用多次),在 Umi 里你可以把这部分抽成 component 。
我们来编写一个 `ProductList` component这样就能在不同的地方显示产品列表了。
@ -213,7 +213,7 @@ export default (
);
```
点击这里[快速开始](https://prolayout.ant.design/getting-started)。
点击这里[快速开始](https://procomponents.ant.design/components/layout)。
## ProTable
@ -266,7 +266,7 @@ const Products = () => {
};
```
ProTable 提供了预设逻辑来处理 loading分页 和搜索表单,可以大大减少代码量,点击这里[快速开始](https://protable.ant.design/getting-started)。
ProTable 提供了预设逻辑来处理 loading分页 和搜索表单,可以大大减少代码量,点击这里[快速开始](https://procomponents.ant.design/components/table)。
## 构建应用
@ -292,9 +292,9 @@ $ yarn build
你可以:
- 访问 [umi 官网](https://umijs.org/)和 [dva 官网](https://dvajs.com/)
- 理解 [umi 的路由](https://umijs.org/zh/guide/router.html)
- 理解 [如何部署 umi 应用](https://umijs.org/zh/guide/deploy.html)
- 访问 [Umi 官网](https://umijs.org/)
- 理解 [Umi 的路由](https://umijs.org/zh-CN/docs/routing)
- 理解 [如何部署 Umi 应用](https://umijs.org/zh-CN/docs/deployment)
- 开箱即用的脚手架 [Ant Design Pro](https://pro.ant.design)
- 高级布局 [ProLayout](https://prolayout.ant.design)
- 高级表格 [ProTable](https://protable.ant.design)
- 高级布局 [ProLayout](https://procomponents.ant.design/components/layout)
- 高级表格 [ProTable](https://procomponents.ant.design/components/table)

View File

@ -74,6 +74,10 @@ Please find below some of the design resources and tools about Ant Design that w
- https://user-images.githubusercontent.com/7129/149994038-76214796-cd6a-4e80-b0a4-117e8edac050.png
- Drag/drop live Ant components and manipulate props in this React visual builder
- https://www.plasmic.app/ant-design
- MasterGo
- https://mastergo-local-default.oss-cn-beijing.aliyuncs.com/ant-design-mastergo.svg
- Use fully components and templates on MasterGo
- https://mastergo.com/community/?utm_source=antdesign&utm_medium=link&utm_campaign=resource&cata_name=AntDesign
## Articles

View File

@ -66,6 +66,10 @@ toc: false
- https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*dxzdQYWlmjMAAAAAAAAAAAAAARQnAQ
- 可在「即时设计」在线免费使用的全套组件和模板
- https://js.design/antd
- MasterGo 组件包
- https://mastergo-local-default.oss-cn-beijing.aliyuncs.com/ant-design-mastergo.svg
- 可在「MasterGo」在线免费使用的全套组件和模板
- https://mastergo.com/community/?utm_source=antdesign&utm_medium=link&utm_campaign=resource&cata_name=AntDesign
## 文章

View File

@ -142,7 +142,7 @@ title: 文案
## 语气
语言定义的是内容,而情绪和气氛更多是通过语气来表达,并且同样的内容面对不同的用户我们可以使用不同的语气来表达;例如,我们对应专业的运维人员和小白用户应有不同的表达方式。
语言定义的是内容,而情绪和气氛更多是通过语气来表达,并且同样的内容面对不同的用户我们可以使用不同的语气来表达;例如,我们对应专业的运维人员和小白用户应有不同的表达方式。
### 拉近彼此的距离
@ -211,7 +211,7 @@ title: 文案
<img class="preview-img no-padding good" align="right" src="https://gw.alipayobjects.com/zos/rmsportal/QGpLpUFgZnTDzYJCeuun.png" alt="正确示范">
<img class="preview-img no-padding bad" align="right" src="https://gw.alipayobjects.com/zos/rmsportal/fQhiFpjLcHJtJJGzElUT.png" alt="错误示范">
为了帮助用户更加高效扫视文本内容,可以省略不必要的断句点。
为了帮助用户更加高效扫视文本内容,可以省略不必要的断句点。
以下元素单独出现时可以省略标点:
@ -279,6 +279,6 @@ title: 文案
</tr>
</table>
正确使用标点符号会让句子看起来更清晰和具有可读性。
正确使用标点符号会让句子看起来更清晰和具有可读性。
具体使用请参考 1995 年中国标准出版社出版的[《标点符号用法》](http://www.moe.gov.cn/ewebeditor/uploadfile/2015/01/13/20150113091548267.pdf),右图为重点列出的在设计中需要注意的部分。

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "4.18.7",
"version": "4.18.9",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@ -129,7 +129,7 @@
"rc-dialog": "~8.6.0",
"rc-drawer": "~4.4.2",
"rc-dropdown": "~3.2.5",
"rc-field-form": "~1.22.0-2",
"rc-field-form": "~1.23.0",
"rc-image": "~5.2.5",
"rc-input-number": "~7.3.0",
"rc-mentions": "~1.6.1",
@ -145,7 +145,7 @@
"rc-slider": "~9.7.4",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
"rc-table": "~7.22.2",
"rc-table": "~7.23.0",
"rc-tabs": "~11.10.0",
"rc-textarea": "~0.3.0",
"rc-tooltip": "~5.1.1",
@ -211,9 +211,9 @@
"eslint-plugin-jest": "^26.0.0",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-markdown": "^2.0.0",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.1.2",
"eslint-plugin-unicorn": "^40.0.0",
"eslint-plugin-unicorn": "^41.0.0",
"fetch-jsonp": "^1.1.3",
"fs-extra": "^10.0.0",
"full-icu": "^1.3.0",
@ -279,7 +279,7 @@
"stylelint": "^14.0.0",
"stylelint-config-prettier": "^9.0.2",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-standard": "^24.0.0",
"stylelint-config-standard": "^25.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^5.0.0",
"theme-switcher": "^1.0.2",

View File

@ -35,6 +35,7 @@ const MAINTAINERS = [
'Rustin-Liu',
'fireairforce',
'kerm1it',
'MadCcc',
].map(author => author.toLowerCase());
const cwd = process.cwd();

View File

@ -443,7 +443,7 @@ class MainContent extends Component {
meta: {
category: 'Components',
cover: 'https://gw.alipayobjects.com/zos/antfincdn/N3eU432oA/bianzu%2525209.svg',
filename: 'https://procomponents.ant.design/components/list',
filename: 'https://procomponents.ant.design/components/editable-table',
subtitle: '可编辑表格',
title: 'EditableProTable',
type,

View File

@ -185,6 +185,7 @@ const SearchBar = ({
initialQuery={searchModalQuery}
placeholder={searchPlaceholder}
hitComponent={Hit}
appId={algoliaConfig.appId}
apiKey={algoliaConfig.apiKey}
indexName={algoliaConfig.indexName}
transformItems={algoliaConfig.transformData}