mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-06 16:06:28 +08:00
Merge pull request #24597 from ant-design/master
chore: Merge master into feature
This commit is contained in:
commit
75d84b2041
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
13
.github/workflows/mirror.yml
vendored
13
.github/workflows/mirror.yml
vendored
@ -5,11 +5,10 @@ on: [push]
|
||||
jobs:
|
||||
to_gitee:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'ant-design/ant-design'
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: pixta-dev/repository-mirroring-action@v1
|
||||
with:
|
||||
target_repo_url:
|
||||
git@gitee.com:ant-design/ant-design.git
|
||||
ssh_private_key:
|
||||
${{ secrets.GITEE_SSH_PRIVATE_KEY }}
|
||||
- uses: actions/checkout@v1
|
||||
- uses: pixta-dev/repository-mirroring-action@v1
|
||||
with:
|
||||
target_repo_url: git@gitee.com:ant-design/ant-design.git
|
||||
ssh_private_key: ${{ secrets.GITEE_SSH_PRIVATE_KEY }}
|
||||
|
31
.github/workflows/ui-ci.yml
vendored
31
.github/workflows/ui-ci.yml
vendored
@ -1,31 +0,0 @@
|
||||
name: UI-TEST
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
ui:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/ui')
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: install
|
||||
run: npm install
|
||||
|
||||
- name: dist
|
||||
run: npm run dist
|
||||
|
||||
- name: test
|
||||
run: npm run test:image
|
||||
|
||||
- name: VERCEL Now Deployment
|
||||
uses: amondnet/now-deployment@v2.0.3
|
||||
with:
|
||||
zeit-token: ${{ secrets.VERCEL_TOKEN }}
|
||||
now-project-id: ${{ secrets.VERCEL_PROJECT_ID}}
|
||||
now-org-id: ${{ secrets.VERCEL_ORG_ID}}
|
||||
working-directory: ./jest-stare
|
||||
if: failure()
|
7
Dockerfile.ui-test
Normal file
7
Dockerfile.ui-test
Normal file
@ -0,0 +1,7 @@
|
||||
FROM buildkite/puppeteer:latest
|
||||
RUN mkdir /app
|
||||
WORKDIR /app
|
||||
COPY package.json ./
|
||||
RUN npm install
|
||||
ENV PATH="${PATH}:/app/node_modules/.bin"
|
||||
COPY . .
|
@ -112,6 +112,7 @@ Veja [i18n](https://ant.design/docs/react/i18n).
|
||||
- [Página inicial](https://ant.design/)
|
||||
- [Componentes](https://ant.design/components/button)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Ant Design Charts](https://charts.ant.design)
|
||||
- [Change Log](CHANGELOG.en-US.md)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
|
@ -116,6 +116,7 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
|
||||
- [首页](https://ant.design/)
|
||||
- [组件库](https://ant.design/docs/react/introduce)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Ant Design Charts](https://charts.ant.design)
|
||||
- [更新日志](CHANGELOG.en-US.md)
|
||||
- [React 底层基础组件](http://react-component.github.io/)
|
||||
- [移动端组件](http://mobile.ant.design)
|
||||
|
@ -112,6 +112,7 @@ Dozens of languages supported in `antd`, see [i18n](https://ant.design/docs/reac
|
||||
- [Home page](https://ant.design/)
|
||||
- [Components](https://ant.design/components/button/)
|
||||
- [Ant Design Pro](http://pro.ant.design/)
|
||||
- [Ant Design Charts](https://charts.ant.design)
|
||||
- [Change Log](CHANGELOG.en-US.md)
|
||||
- [rc-components](http://react-component.github.io/)
|
||||
- [Mobile UI](http://mobile.ant.design)
|
||||
|
@ -12,50 +12,106 @@ pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
stages:
|
||||
- stage: site
|
||||
jobs:
|
||||
- job: Build_Site
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.13.1'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js "[](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Comment on github'
|
||||
- script: npm run site
|
||||
displayName: 'Build sites'
|
||||
- script: ls -al _site/
|
||||
displayName: 'List build'
|
||||
- script: |
|
||||
export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
|
||||
echo "Deploy to $DEPLOY_DOMAIN"
|
||||
npx surge --project ./_site --domain $DEPLOY_DOMAIN
|
||||
displayName: 'Deploy Site'
|
||||
- script: |
|
||||
export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
|
||||
node ./scripts/azure-github-comment.js "[<img width="306" src="https://user-images.githubusercontent.com/5378891/72400743-23dbb200-3785-11ea-9d13-1a2d92743846.png">]($DEPLOY_DOMAIN)"
|
||||
displayName: 'Update comment on github'
|
||||
- job: Build_Site_Failed
|
||||
dependsOn: Build_Site
|
||||
condition: failed()
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.13.1'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js "[<img width="534" src="https://user-images.githubusercontent.com/5378891/75333447-1e63a280-58c1-11ea-975d-235367fd1522.png">](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Comment on github'
|
||||
- stage: site
|
||||
jobs:
|
||||
- job: Build_Site
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.13.1'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js "[](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Comment on github'
|
||||
- script: npm run site
|
||||
displayName: 'Build sites'
|
||||
- script: ls -al _site/
|
||||
displayName: 'List build'
|
||||
- script: |
|
||||
export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
|
||||
echo "Deploy to $DEPLOY_DOMAIN"
|
||||
npx surge --project ./_site --domain $DEPLOY_DOMAIN
|
||||
displayName: 'Deploy Site'
|
||||
- script: |
|
||||
export DEPLOY_DOMAIN=https://preview-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
|
||||
node ./scripts/azure-github-comment.js "[<img width="306" src="https://user-images.githubusercontent.com/5378891/72400743-23dbb200-3785-11ea-9d13-1a2d92743846.png">]($DEPLOY_DOMAIN)"
|
||||
displayName: 'Update comment on github'
|
||||
- job: Build_Site_Failed
|
||||
dependsOn: Build_Site
|
||||
condition: failed()
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.13.1'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js "[<img width="534" src="https://user-images.githubusercontent.com/5378891/75333447-1e63a280-58c1-11ea-975d-235367fd1522.png">](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Comment on github'
|
||||
- stage: ui
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- job: UI_Test
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.16.3'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js -ui "[](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Comment on github'
|
||||
- script: npm run test-image
|
||||
displayName: 'UI Test'
|
||||
- task: PublishPipelineArtifact@1
|
||||
inputs:
|
||||
targetPath: $(System.DefaultWorkingDirectory)/jest-stare
|
||||
artifactName: jestStare
|
||||
condition: failed()
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js -ui "[<img width="306" src="https://user-images.githubusercontent.com/14831261/82744259-6e5ee200-9da8-11ea-8479-685f6e280b77.jpg">](https://dev.azure.com/ant-design/ant-design/_build/results?buildId=$(Build.BuildId))"
|
||||
displayName: 'Update comment on github'
|
||||
- job: UI_Test_Failed
|
||||
dependsOn: UI_Test
|
||||
condition: failed()
|
||||
steps:
|
||||
- checkout: self
|
||||
displayName: 'Checkout'
|
||||
clean: true
|
||||
fetchDepth: 1
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '12.13.1'
|
||||
- script: npm install
|
||||
displayName: 'Install modules'
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: jestStare
|
||||
path: './jest-stare'
|
||||
- script: ls -al ./jest-stare
|
||||
displayName: 'List report'
|
||||
- script: |
|
||||
export DEPLOY_DOMAIN=https://ui-test-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh
|
||||
echo "Deploy to $DEPLOY_DOMAIN"
|
||||
npx surge --project ./jest-stare --domain $DEPLOY_DOMAIN
|
||||
displayName: 'Deploy Report Site'
|
||||
- script: |
|
||||
node ./scripts/azure-github-comment.js -ui "[<img width="306" src="https://user-images.githubusercontent.com/14831261/82744257-6dc64b80-9da8-11ea-80cf-05b2279a5602.jpg">](https://ui-test-${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}-ant-design.surge.sh)"
|
||||
displayName: 'Update comment on github'
|
||||
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import TransitionEvents from '@ant-design/css-animation/lib/Event';
|
||||
import raf from './raf';
|
||||
import { ConfigConsumer, ConfigConsumerProps, CSPConfig } from '../config-provider';
|
||||
import { ConfigConsumer, ConfigConsumerProps, CSPConfig, ConfigContext } from '../config-provider';
|
||||
|
||||
let styleForPesudo: HTMLStyleElement | null;
|
||||
|
||||
@ -24,6 +24,8 @@ function isNotGrey(color: string) {
|
||||
}
|
||||
|
||||
export default class Wave extends React.Component<{ insertExtraNode?: boolean }> {
|
||||
static contextType = ConfigContext;
|
||||
|
||||
private instance?: {
|
||||
cancel: () => void;
|
||||
};
|
||||
@ -40,6 +42,8 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
|
||||
private csp?: CSPConfig;
|
||||
|
||||
context: ConfigConsumerProps;
|
||||
|
||||
componentDidMount() {
|
||||
const node = findDOMNode(this) as HTMLElement;
|
||||
if (!node || node.nodeType !== 1) {
|
||||
@ -66,7 +70,8 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
const { insertExtraNode } = this.props;
|
||||
this.extraNode = document.createElement('div');
|
||||
const { extraNode } = this;
|
||||
extraNode.className = 'ant-click-animating-node';
|
||||
const { getPrefixCls } = this.context;
|
||||
extraNode.className = `${getPrefixCls('')}-click-animating-node`;
|
||||
const attributeName = this.getAttributeName();
|
||||
node.setAttribute(attributeName, 'true');
|
||||
// Not white or transparnt or grey
|
||||
@ -86,7 +91,9 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
|
||||
extraNode.style.borderColor = waveColor;
|
||||
styleForPesudo.innerHTML = `
|
||||
[ant-click-animating-without-extra-node='true']::after, .ant-click-animating-node {
|
||||
[${getPrefixCls('')}-click-animating-without-extra-node='true']::after, .${getPrefixCls(
|
||||
'',
|
||||
)}-click-animating-node {
|
||||
--antd-wave-shadow-color: ${waveColor};
|
||||
}`;
|
||||
if (!document.body.contains(styleForPesudo)) {
|
||||
@ -121,8 +128,11 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }>
|
||||
};
|
||||
|
||||
getAttributeName() {
|
||||
const { getPrefixCls } = this.context;
|
||||
const { insertExtraNode } = this.props;
|
||||
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
|
||||
return insertExtraNode
|
||||
? `${getPrefixCls('')}-click-animating`
|
||||
: `${getPrefixCls('')}-click-animating-without-extra-node`;
|
||||
}
|
||||
|
||||
bindAnimationEvent = (node: HTMLElement) => {
|
||||
|
@ -76,7 +76,7 @@
|
||||
&-close-icon {
|
||||
position: absolute;
|
||||
top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2;
|
||||
right: 16px;
|
||||
right: @padding-md;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
font-size: @font-size-sm;
|
||||
@ -124,8 +124,8 @@
|
||||
|
||||
&-with-description &-close-icon {
|
||||
position: absolute;
|
||||
top: @padding-xs;
|
||||
right: @padding-xs;
|
||||
top: @padding-md;
|
||||
right: @padding-md;
|
||||
font-size: @font-size-base;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
&-icon {
|
||||
.@{alert-prefix-cls}-rtl & {
|
||||
right: 16px;
|
||||
right: @padding-md;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
@ -39,14 +39,16 @@
|
||||
&-close-icon {
|
||||
.@{alert-prefix-cls}-rtl & {
|
||||
right: auto;
|
||||
left: 16px;
|
||||
left: @padding-md;
|
||||
}
|
||||
}
|
||||
|
||||
&-with-description,
|
||||
&-with-description&-closable {
|
||||
.@{alert-prefix-cls}.@{alert-prefix-cls}-rtl& {
|
||||
padding: 15px 64px 15px 15px;
|
||||
padding: @alert-with-description-padding-vertical @alert-with-description-icon-size * 2 +
|
||||
@alert-with-description-padding-vertical @alert-with-description-no-icon-padding-vertical
|
||||
15px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@
|
||||
|
||||
&-with-description &-icon {
|
||||
.@{alert-prefix-cls}-rtl& {
|
||||
right: 24px;
|
||||
right: @alert-with-description-icon-size;
|
||||
left: auto;
|
||||
}
|
||||
}
|
||||
@ -66,7 +68,7 @@
|
||||
&-with-description &-close-icon {
|
||||
.@{alert-prefix-cls}-rtl& {
|
||||
right: auto;
|
||||
left: 16px;
|
||||
left: @padding-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,4 +142,16 @@ describe('Avatar Render', () => {
|
||||
);
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('support size is number', () => {
|
||||
const wrapper = mount(<Avatar size={100}>TestString</Avatar>);
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
|
||||
it('support onMouseEnter', () => {
|
||||
const onMouseEnter = jest.fn();
|
||||
const wrapper = mount(<Avatar onMouseEnter={onMouseEnter}>TestString</Avatar>);
|
||||
wrapper.simulate('mouseenter');
|
||||
expect(onMouseEnter).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -10,3 +10,17 @@ exports[`Avatar Render rtl render component should be rendered correctly in RTL
|
||||
/>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Avatar Render support size is number 1`] = `
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width:100px;height:100px;line-height:100px;font-size:18px"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
style="opacity:0"
|
||||
>
|
||||
TestString
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<span
|
||||
class="avatar-item"
|
||||
>
|
||||
@ -194,7 +194,7 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
</span>
|
||||
</sup>
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span>
|
||||
<span
|
||||
class="ant-badge"
|
||||
@ -228,12 +228,12 @@ exports[`renders ./components/avatar/demo/badge.md correctly 1`] = `
|
||||
data-show="true"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/basic.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
@ -332,7 +332,7 @@ exports[`renders ./components/avatar/demo/basic.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-square ant-avatar-icon"
|
||||
@ -431,12 +431,12 @@ exports[`renders ./components/avatar/demo/basic.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<span
|
||||
class="ant-avatar ant-avatar-lg ant-avatar-circle"
|
||||
style="background-color:#f56a00;vertical-align:middle"
|
||||
@ -447,7 +447,7 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
|
||||
>
|
||||
U
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<button
|
||||
class="ant-btn ant-btn-sm"
|
||||
style="margin:0 16px;vertical-align:middle"
|
||||
@ -456,7 +456,7 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
|
||||
<span>
|
||||
ChangeUser
|
||||
</span>
|
||||
</button>
|
||||
</button>,
|
||||
<button
|
||||
class="ant-btn ant-btn-sm"
|
||||
style="vertical-align:middle"
|
||||
@ -465,12 +465,12 @@ exports[`renders ./components/avatar/demo/dynamic.md correctly 1`] = `
|
||||
<span>
|
||||
changeGap
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -478,7 +478,7 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
<span>
|
||||
Toggle Avatar visibility
|
||||
</span>
|
||||
</button>
|
||||
</button>,
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -486,7 +486,7 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
<span>
|
||||
Toggle Avatar size
|
||||
</span>
|
||||
</button>
|
||||
</button>,
|
||||
<button
|
||||
class="ant-btn"
|
||||
type="button"
|
||||
@ -494,9 +494,9 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
<span>
|
||||
Change Avatar scale
|
||||
</span>
|
||||
</button>
|
||||
<br />
|
||||
<br />
|
||||
</button>,
|
||||
<br />,
|
||||
<br />,
|
||||
<div
|
||||
style="text-align:center;transform:scale(1);margin-top:24px"
|
||||
>
|
||||
@ -542,12 +542,12 @@ exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
@ -571,7 +571,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
>
|
||||
@ -581,9 +581,10 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
>
|
||||
U
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="width:40px;height:40px;line-height:40px;font-size:18px"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar-string"
|
||||
@ -591,14 +592,14 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
>
|
||||
USER
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
|
||||
/>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle"
|
||||
style="color:#f56a00;background-color:#fde3cf"
|
||||
@ -609,7 +610,7 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
>
|
||||
U
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
style="background-color:#87d068"
|
||||
@ -634,6 +635,6 @@ exports[`renders ./components/avatar/demo/type.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
@ -18,7 +18,7 @@ import { Avatar, Badge } from 'antd';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<span className="avatar-item">
|
||||
<Badge count={1}>
|
||||
<Avatar shape="square" icon={<UserOutlined />} />
|
||||
@ -29,7 +29,7 @@ ReactDOM.render(
|
||||
<Avatar shape="square" icon={<UserOutlined />} />
|
||||
</Badge>
|
||||
</span>
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -18,7 +18,7 @@ import { Avatar } from 'antd';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<div>
|
||||
<Avatar size={64} icon={<UserOutlined />} />
|
||||
<Avatar size="large" icon={<UserOutlined />} />
|
||||
@ -31,7 +31,7 @@ ReactDOM.render(
|
||||
<Avatar shape="square" icon={<UserOutlined />} />
|
||||
<Avatar shape="square" size="small" icon={<UserOutlined />} />
|
||||
</div>
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -35,7 +35,7 @@ const Autoset: React.FC = () => {
|
||||
setGap(index < GapList.length - 1 ? GapList[index + 1] : GapList[0]);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Avatar style={{ backgroundColor: color, verticalAlign: 'middle' }} size="large" gap={gap}>
|
||||
{user}
|
||||
</Avatar>
|
||||
@ -49,7 +49,7 @@ const Autoset: React.FC = () => {
|
||||
<Button size="small" style={{ verticalAlign: 'middle' }} onClick={changeGap}>
|
||||
changeGap
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ const App: React.FC = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Button onClick={toggle}>Toggle Avatar visibility</Button>
|
||||
<Button onClick={toggleSize}>Toggle Avatar size</Button>
|
||||
<Button onClick={changeScale}>Change Avatar scale</Button>
|
||||
@ -67,7 +67,7 @@ const App: React.FC = () => {
|
||||
</Avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -18,14 +18,14 @@ import { Avatar } from 'antd';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Avatar icon={<UserOutlined />} />
|
||||
<Avatar>U</Avatar>
|
||||
<Avatar>USER</Avatar>
|
||||
<Avatar size={40}>USER</Avatar>
|
||||
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||
<Avatar style={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>U</Avatar>
|
||||
<Avatar style={{ backgroundColor: '#87d068' }} icon={<UserOutlined />} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -202,8 +202,15 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The event is triggered twice from bubbling up the DOM tree.
|
||||
// see https://codesandbox.io/s/kind-snow-9lidz
|
||||
delete others.onError;
|
||||
delete others.gap;
|
||||
|
||||
return (
|
||||
<span
|
||||
{...others}
|
||||
style={{ ...sizeStyle, ...others.style }}
|
||||
className={classString}
|
||||
ref={(node: HTMLElement) => (this.avatarNode = node)}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import omit from 'omit.js';
|
||||
import BreadcrumbItem from './BreadcrumbItem';
|
||||
import BreadcrumbSeparator from './BreadcrumbSeparator';
|
||||
import Menu from '../menu';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { Omit } from '../_util/type';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
@ -49,41 +48,48 @@ function defaultItemRender(route: Route, params: any, routes: Route[], paths: st
|
||||
return isLastItem ? <span>{name}</span> : <a href={`#/${paths.join('/')}`}>{name}</a>;
|
||||
}
|
||||
|
||||
export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
static Item: typeof BreadcrumbItem;
|
||||
const getPath = (path: string, params: any) => {
|
||||
path = (path || '').replace(/^\//, '');
|
||||
Object.keys(params).forEach(key => {
|
||||
path = path.replace(`:${key}`, params[key]);
|
||||
});
|
||||
return path;
|
||||
};
|
||||
|
||||
static Separator: typeof BreadcrumbSeparator;
|
||||
const addChildPath = (paths: string[], childPath: string = '', params: any) => {
|
||||
const originalPaths = [...paths];
|
||||
const path = getPath(childPath, params);
|
||||
if (path) {
|
||||
originalPaths.push(path);
|
||||
}
|
||||
return originalPaths;
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
separator: '/',
|
||||
};
|
||||
interface BreadcrumbInterface extends React.FC<BreadcrumbProps> {
|
||||
Item: typeof BreadcrumbItem;
|
||||
Separator: typeof BreadcrumbSeparator;
|
||||
}
|
||||
|
||||
getPath = (path: string, params: any) => {
|
||||
path = (path || '').replace(/^\//, '');
|
||||
Object.keys(params).forEach(key => {
|
||||
path = path.replace(`:${key}`, params[key]);
|
||||
});
|
||||
return path;
|
||||
};
|
||||
const Breadcrumb: BreadcrumbInterface = ({
|
||||
prefixCls: customizePrefixCls,
|
||||
separator = '/',
|
||||
style,
|
||||
className,
|
||||
routes,
|
||||
children,
|
||||
itemRender = defaultItemRender,
|
||||
params = {},
|
||||
...restProps
|
||||
}) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
|
||||
addChildPath = (paths: string[], childPath: string = '', params: any) => {
|
||||
const originalPaths = [...paths];
|
||||
const path = this.getPath(childPath, params);
|
||||
if (path) {
|
||||
originalPaths.push(path);
|
||||
}
|
||||
return originalPaths;
|
||||
};
|
||||
|
||||
genForRoutes = ({
|
||||
routes = [],
|
||||
params = {},
|
||||
separator,
|
||||
itemRender = defaultItemRender,
|
||||
}: BreadcrumbProps) => {
|
||||
let crumbs;
|
||||
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
||||
if (routes && routes.length > 0) {
|
||||
// generated by route
|
||||
const paths: string[] = [];
|
||||
return routes.map(route => {
|
||||
const path = this.getPath(route.path, params);
|
||||
crumbs = routes.map(route => {
|
||||
const path = getPath(route.path, params);
|
||||
|
||||
if (path) {
|
||||
paths.push(path);
|
||||
@ -95,7 +101,7 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
<Menu>
|
||||
{route.children.map(child => (
|
||||
<Menu.Item key={child.path || child.breadcrumbName}>
|
||||
{itemRender(child, params, routes, this.addChildPath(paths, child.path, params))}
|
||||
{itemRender(child, params, routes, addChildPath(paths, child.path, params))}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
@ -108,58 +114,40 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
</BreadcrumbItem>
|
||||
);
|
||||
});
|
||||
};
|
||||
} else if (children) {
|
||||
crumbs = toArray(children).map((element: any, index) => {
|
||||
if (!element) {
|
||||
return element;
|
||||
}
|
||||
|
||||
renderBreadcrumb = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
let crumbs;
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
separator,
|
||||
style,
|
||||
className,
|
||||
routes,
|
||||
children,
|
||||
...restProps
|
||||
} = this.props;
|
||||
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
||||
if (routes && routes.length > 0) {
|
||||
// generated by route
|
||||
crumbs = this.genForRoutes(this.props);
|
||||
} else if (children) {
|
||||
crumbs = toArray(children).map((element: any, index) => {
|
||||
if (!element) {
|
||||
return element;
|
||||
}
|
||||
devWarning(
|
||||
element.type &&
|
||||
(element.type.__ANT_BREADCRUMB_ITEM === true ||
|
||||
element.type.__ANT_BREADCRUMB_SEPARATOR === true),
|
||||
'Breadcrumb',
|
||||
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
|
||||
);
|
||||
|
||||
devWarning(
|
||||
element.type &&
|
||||
(element.type.__ANT_BREADCRUMB_ITEM === true ||
|
||||
element.type.__ANT_BREADCRUMB_SEPARATOR === true),
|
||||
'Breadcrumb',
|
||||
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
|
||||
);
|
||||
|
||||
return cloneElement(element, {
|
||||
separator,
|
||||
key: index,
|
||||
});
|
||||
return cloneElement(element, {
|
||||
separator,
|
||||
key: index,
|
||||
});
|
||||
}
|
||||
const breadcrumbClassName = classNames(className, prefixCls, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
return (
|
||||
<div
|
||||
className={breadcrumbClassName}
|
||||
style={style}
|
||||
{...omit(restProps, ['itemRender', 'linkRender', 'nameRender', 'params'])}
|
||||
>
|
||||
{crumbs}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderBreadcrumb}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
|
||||
const breadcrumbClassName = classNames(className, prefixCls, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={breadcrumbClassName} style={style} {...restProps}>
|
||||
{crumbs}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Breadcrumb.Item = BreadcrumbItem;
|
||||
|
||||
Breadcrumb.Separator = BreadcrumbSeparator;
|
||||
|
||||
export default Breadcrumb;
|
||||
|
@ -1,9 +1,8 @@
|
||||
import * as React from 'react';
|
||||
import DownOutlined from '@ant-design/icons/DownOutlined';
|
||||
import omit from 'omit.js';
|
||||
|
||||
import DropDown, { DropDownProps } from '../dropdown/dropdown';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export interface BreadcrumbItemProps {
|
||||
prefixCls?: string;
|
||||
@ -13,53 +12,24 @@ export interface BreadcrumbItemProps {
|
||||
dropdownProps?: DropDownProps;
|
||||
onClick?: React.MouseEventHandler<HTMLAnchorElement | HTMLSpanElement>;
|
||||
}
|
||||
|
||||
export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps, any> {
|
||||
static __ANT_BREADCRUMB_ITEM = true;
|
||||
|
||||
static defaultProps = {
|
||||
separator: '/',
|
||||
};
|
||||
|
||||
renderBreadcrumbItem = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, separator, children, ...restProps } = this.props;
|
||||
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
||||
let link;
|
||||
if ('href' in this.props) {
|
||||
link = (
|
||||
<a className={`${prefixCls}-link`} {...omit(restProps, ['overlay'])}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
link = (
|
||||
<span className={`${prefixCls}-link`} {...omit(restProps, ['overlay'])}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// wrap to dropDown
|
||||
link = this.renderBreadcrumbNode(link, prefixCls);
|
||||
if (children) {
|
||||
return (
|
||||
<span>
|
||||
{link}
|
||||
{separator && separator !== '' && (
|
||||
<span className={`${prefixCls}-separator`}>{separator}</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
interface BreadcrumbItemInterface extends React.FC<BreadcrumbItemProps> {
|
||||
__ANT_BREADCRUMB_ITEM: boolean;
|
||||
}
|
||||
const BreadcrumbItem: BreadcrumbItemInterface = ({
|
||||
prefixCls: customizePrefixCls,
|
||||
separator,
|
||||
children,
|
||||
overlay,
|
||||
dropdownProps,
|
||||
...restProps
|
||||
}) => {
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
|
||||
/**
|
||||
* if overlay is have
|
||||
* Wrap a DropDown
|
||||
*/
|
||||
renderBreadcrumbNode = (breadcrumbItem: React.ReactNode, prefixCls: string) => {
|
||||
const { overlay, dropdownProps } = this.props;
|
||||
const renderBreadcrumbNode = (breadcrumbItem: React.ReactNode) => {
|
||||
if (overlay) {
|
||||
return (
|
||||
<DropDown overlay={overlay} placement="bottomCenter" {...dropdownProps}>
|
||||
@ -73,7 +43,36 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
|
||||
return breadcrumbItem;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderBreadcrumbItem}</ConfigConsumer>;
|
||||
let link;
|
||||
if ('href' in restProps) {
|
||||
link = (
|
||||
<a className={`${prefixCls}-link`} {...restProps}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
link = (
|
||||
<span className={`${prefixCls}-link`} {...restProps}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap to dropDown
|
||||
link = renderBreadcrumbNode(link);
|
||||
if (children) {
|
||||
return (
|
||||
<span>
|
||||
{link}
|
||||
{separator && separator !== '' && (
|
||||
<span className={`${prefixCls}-separator`}>{separator}</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
BreadcrumbItem.__ANT_BREADCRUMB_ITEM = true;
|
||||
|
||||
export default BreadcrumbItem;
|
||||
|
@ -1,17 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export default class BreadcrumbSeparator extends React.Component<any> {
|
||||
static __ANT_BREADCRUMB_SEPARATOR = true;
|
||||
|
||||
renderSeparator = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { children } = this.props;
|
||||
const prefixCls = getPrefixCls('breadcrumb');
|
||||
|
||||
return <span className={`${prefixCls}-separator`}>{children || '/'}</span>;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderSeparator}</ConfigConsumer>;
|
||||
}
|
||||
interface BreadcrumbSeparatorInterface extends React.FC {
|
||||
__ANT_BREADCRUMB_SEPARATOR: boolean;
|
||||
}
|
||||
|
||||
const BreadcrumbSeparator: BreadcrumbSeparatorInterface = ({ children }) => {
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('breadcrumb');
|
||||
|
||||
return <span className={`${prefixCls}-separator`}>{children || '/'}</span>;
|
||||
};
|
||||
|
||||
BreadcrumbSeparator.__ANT_BREADCRUMB_SEPARATOR = true;
|
||||
|
||||
export default BreadcrumbSeparator;
|
||||
|
@ -111,21 +111,6 @@ describe('Breadcrumb', () => {
|
||||
it('should accept undefined routes', () => {
|
||||
const wrapper = render(<Breadcrumb routes={undefined} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
})
|
||||
|
||||
it('props#linkRender and props#nameRender do not warn anymore', () => {
|
||||
const linkRender = jest.fn();
|
||||
const nameRender = jest.fn();
|
||||
mount(
|
||||
<Breadcrumb linkRender={linkRender} nameRender={nameRender}>
|
||||
<Breadcrumb.Item />
|
||||
<Breadcrumb.Item>xxx</Breadcrumb.Item>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
|
||||
expect(errorSpy.mock.calls.length).toBe(0);
|
||||
expect(linkRender).not.toHaveBeenCalled();
|
||||
expect(nameRender).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should support custom attribute', () => {
|
||||
|
@ -73,7 +73,6 @@ exports[`react router react router 3 1`] = `
|
||||
},
|
||||
]
|
||||
}
|
||||
separator="/"
|
||||
>
|
||||
<div
|
||||
className="ant-breadcrumb"
|
||||
|
@ -1,10 +1,6 @@
|
||||
import Breadcrumb from './Breadcrumb';
|
||||
import BreadcrumbItem from './BreadcrumbItem';
|
||||
import BreadcrumbSeparator from './BreadcrumbSeparator';
|
||||
|
||||
export { BreadcrumbProps } from './Breadcrumb';
|
||||
export { BreadcrumbItemProps } from './BreadcrumbItem';
|
||||
|
||||
Breadcrumb.Item = BreadcrumbItem;
|
||||
Breadcrumb.Separator = BreadcrumbSeparator;
|
||||
export default Breadcrumb;
|
||||
|
@ -38,7 +38,8 @@
|
||||
}
|
||||
|
||||
&-link {
|
||||
> .@{iconfont-css-prefix} + span {
|
||||
> .@{iconfont-css-prefix} + span,
|
||||
> .@{iconfont-css-prefix} + a {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,8 @@
|
||||
}
|
||||
|
||||
&-link {
|
||||
> .@{iconfont-css-prefix} + span {
|
||||
> .@{iconfont-css-prefix} + span,
|
||||
> .@{iconfont-css-prefix} + a {
|
||||
.@{breadcrumb-prefix-cls}-rtl & {
|
||||
margin-right: 4px;
|
||||
margin-left: 0;
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
@ -106,7 +106,7 @@ Array [
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
link
|
||||
Dashed
|
||||
</span>
|
||||
</button>,
|
||||
<button
|
||||
|
14
components/button/__tests__/image.test.js
Normal file
14
components/button/__tests__/image.test.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import Button from '..';
|
||||
import imageTest from '../../../tests/shared/imageTest';
|
||||
|
||||
describe('Button image', () => {
|
||||
imageTest(
|
||||
<>
|
||||
<Button type="primary">Primary</Button>
|
||||
<Button>Default</Button>
|
||||
<Button type="dashed">Dashed</Button>
|
||||
<Button type="link">Link</Button>
|
||||
</>,
|
||||
);
|
||||
});
|
@ -23,7 +23,7 @@ ReactDOM.render(
|
||||
</Button>
|
||||
<Button danger>Default</Button>
|
||||
<Button type="dashed" danger>
|
||||
link
|
||||
Dashed
|
||||
</Button>
|
||||
<Button type="link" danger>
|
||||
link
|
||||
|
@ -39,6 +39,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{calendar-prefix-cls}-date {
|
||||
&-content {
|
||||
.@{calendar-prefix-cls}-rtl& {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,11 +340,6 @@ exports[`renders ./components/card/demo/inner.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-card-body"
|
||||
>
|
||||
<p
|
||||
class="site-card-demo-inner-p"
|
||||
>
|
||||
Group title
|
||||
</p>
|
||||
<div
|
||||
class="ant-card ant-card-bordered ant-card-type-inner"
|
||||
>
|
||||
|
@ -18,7 +18,6 @@ import { Card } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<Card title="Card title">
|
||||
<p className="site-card-demo-inner-p">Group title</p>
|
||||
<Card type="inner" title="Inner Card title" extra={<a href="#">More</a>}>
|
||||
Inner Card content
|
||||
</Card>
|
||||
@ -34,18 +33,3 @@ ReactDOM.render(
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
||||
```css
|
||||
.site-card-demo-inner-p {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
margin-bottom: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
```
|
||||
|
||||
<style>
|
||||
[data-theme="dark"] .site-card-demo-inner-p {
|
||||
color: rgba(255,255,255,.85);
|
||||
}
|
||||
</style>
|
||||
|
@ -228,6 +228,10 @@
|
||||
position: absolute;
|
||||
right: @control-padding-horizontal;
|
||||
color: @text-color-secondary;
|
||||
|
||||
.@{cascader-prefix-cls}-menu-item-disabled& {
|
||||
color: @disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
& &-keyword {
|
||||
|
@ -51,15 +51,21 @@
|
||||
}
|
||||
|
||||
&-menu {
|
||||
&-rtl {
|
||||
&-rtl & {
|
||||
direction: rtl;
|
||||
border-right: none;
|
||||
border-left: @border-width-base @border-style-base @border-color-split;
|
||||
&:first-child {
|
||||
border-radius: 0 @border-radius-base @border-radius-base 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
margin-left: -1px;
|
||||
border-left-color: transparent;
|
||||
border-radius: 0 0 4px 4px;
|
||||
border-radius: @border-radius-base 0 0 @border-radius-base;
|
||||
}
|
||||
&:only-child {
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ export interface AbstractCheckboxProps<T> {
|
||||
children?: React.ReactNode;
|
||||
id?: string;
|
||||
autoFocus?: boolean;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface CheckboxProps extends AbstractCheckboxProps<CheckboxChangeEvent> {
|
||||
|
@ -4,7 +4,7 @@ import classNames from 'classnames';
|
||||
import RightOutlined from '@ant-design/icons/RightOutlined';
|
||||
|
||||
import CollapsePanel from './CollapsePanel';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import animation from '../_util/openAnimation';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
|
||||
@ -36,23 +36,25 @@ interface PanelProps {
|
||||
extra?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default class Collapse extends React.Component<CollapseProps, any> {
|
||||
static Panel = CollapsePanel;
|
||||
interface CollapseInterface extends React.FC<CollapseProps> {
|
||||
Panel: typeof CollapsePanel;
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
bordered: true,
|
||||
};
|
||||
const Collapse: CollapseInterface = props => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, className = '', bordered } = props;
|
||||
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
|
||||
|
||||
getIconPosition(direction: string = 'ltr') {
|
||||
const { expandIconPosition } = this.props;
|
||||
const getIconPosition = () => {
|
||||
const { expandIconPosition } = props;
|
||||
if (expandIconPosition !== undefined) {
|
||||
return expandIconPosition;
|
||||
}
|
||||
return direction === 'rtl' ? 'right' : 'left';
|
||||
}
|
||||
};
|
||||
|
||||
renderExpandIcon = (panelProps: PanelProps = {}, prefixCls: string) => {
|
||||
const { expandIcon } = this.props;
|
||||
const renderExpandIcon = (panelProps: PanelProps = {}) => {
|
||||
const { expandIcon } = props;
|
||||
const icon = (expandIcon ? (
|
||||
expandIcon(panelProps)
|
||||
) : (
|
||||
@ -64,32 +66,32 @@ export default class Collapse extends React.Component<CollapseProps, any> {
|
||||
}));
|
||||
};
|
||||
|
||||
renderCollapse = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, className = '', bordered } = this.props;
|
||||
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
|
||||
const iconPosition = this.getIconPosition(direction);
|
||||
const collapseClassName = classNames(
|
||||
{
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
[`${prefixCls}-icon-position-${iconPosition}`]: true,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
const openAnimation = { ...animation, appear() {} };
|
||||
const iconPosition = getIconPosition();
|
||||
const collapseClassName = classNames(
|
||||
{
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
[`${prefixCls}-icon-position-${iconPosition}`]: true,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
const openAnimation = { ...animation, appear() {} };
|
||||
|
||||
return (
|
||||
<RcCollapse
|
||||
openAnimation={openAnimation}
|
||||
{...this.props}
|
||||
expandIcon={(panelProps: PanelProps) => this.renderExpandIcon(panelProps, prefixCls)}
|
||||
prefixCls={prefixCls}
|
||||
className={collapseClassName}
|
||||
/>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<RcCollapse
|
||||
openAnimation={openAnimation}
|
||||
{...props}
|
||||
expandIcon={(panelProps: PanelProps) => renderExpandIcon(panelProps)}
|
||||
prefixCls={prefixCls}
|
||||
className={collapseClassName}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderCollapse}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
Collapse.Panel = CollapsePanel;
|
||||
|
||||
Collapse.defaultProps = {
|
||||
bordered: true,
|
||||
};
|
||||
|
||||
export default Collapse;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import RcCollapse from 'rc-collapse';
|
||||
import classNames from 'classnames';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
export interface CollapsePanelProps {
|
||||
key: string | number;
|
||||
@ -16,22 +16,17 @@ export interface CollapsePanelProps {
|
||||
extra?: React.ReactNode;
|
||||
}
|
||||
|
||||
export default class CollapsePanel extends React.Component<CollapsePanelProps, {}> {
|
||||
renderCollapsePanel = ({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, className = '', showArrow = true } = this.props;
|
||||
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
|
||||
const collapsePanelClassName = classNames(
|
||||
{
|
||||
[`${prefixCls}-no-arrow`]: !showArrow,
|
||||
},
|
||||
className,
|
||||
);
|
||||
return (
|
||||
<RcCollapse.Panel {...this.props} prefixCls={prefixCls} className={collapsePanelClassName} />
|
||||
);
|
||||
};
|
||||
const CollapsePanel: React.FC<CollapsePanelProps> = props => {
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, className = '', showArrow = true } = props;
|
||||
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
|
||||
const collapsePanelClassName = classNames(
|
||||
{
|
||||
[`${prefixCls}-no-arrow`]: !showArrow,
|
||||
},
|
||||
className,
|
||||
);
|
||||
return <RcCollapse.Panel {...props} prefixCls={prefixCls} className={collapsePanelClassName} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderCollapsePanel}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
export default CollapsePanel;
|
||||
|
@ -122,77 +122,70 @@ exports[`renders ./components/comment/demo/basic.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/comment/demo/editor.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="ant-comment"
|
||||
>
|
||||
<div
|
||||
class="ant-comment"
|
||||
class="ant-comment-inner"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-inner"
|
||||
class="ant-comment-avatar"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
alt="Han Solo"
|
||||
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-avatar"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
>
|
||||
<img
|
||||
alt="Han Solo"
|
||||
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<textarea
|
||||
class="ant-input"
|
||||
rows="4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<textarea
|
||||
class="ant-input"
|
||||
rows="4"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="submit"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Add Comment
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span>
|
||||
Add Comment
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,9 +10,6 @@ exports[`Comment rtl render component should be rendered correctly in RTL direct
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
/>
|
||||
@ -20,3 +17,41 @@ exports[`Comment rtl render component should be rendered correctly in RTL direct
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Comment should support empty actions 1`] = `
|
||||
<div
|
||||
class="ant-comment"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-inner"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
>
|
||||
<span
|
||||
class="ant-comment-content-author-name"
|
||||
>
|
||||
<a>
|
||||
Han Solo
|
||||
</a>
|
||||
</span>
|
||||
<span
|
||||
class="ant-comment-content-author-time"
|
||||
>
|
||||
YYYY-MM-DD HH:mm:ss
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
<p>
|
||||
We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Comment from '../index';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
@ -5,4 +7,22 @@ import rtlTest from '../../../tests/shared/rtlTest';
|
||||
describe('Comment', () => {
|
||||
mountTest(Comment);
|
||||
rtlTest(Comment);
|
||||
|
||||
it('should support empty actions', () => {
|
||||
const wrapper = mount(
|
||||
<Comment
|
||||
actions={[]}
|
||||
author={<a>Han Solo</a>}
|
||||
content={
|
||||
<p>
|
||||
We supply a series of design principles, practical patterns and high quality design
|
||||
resources (Sketch and Axure), to help people create their product prototypes beautifully
|
||||
and efficiently.
|
||||
</p>
|
||||
}
|
||||
datetime="YYYY-MM-DD HH:mm:ss"
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -45,7 +45,7 @@ const Demo = () => {
|
||||
</Tooltip>
|
||||
<span className="comment-action">{likes}</span>
|
||||
</span>,
|
||||
<span key=' key="comment-basic-dislike"'>
|
||||
<span key="comment-basic-dislike">
|
||||
<Tooltip title="Dislike">
|
||||
{React.createElement(action === 'disliked' ? DislikeFilled : DislikeOutlined, {
|
||||
onClick: dislike,
|
||||
@ -80,7 +80,7 @@ const Demo = () => {
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
```
|
||||
|
@ -29,7 +29,7 @@ const CommentList = ({ comments }) => (
|
||||
);
|
||||
|
||||
const Editor = ({ onChange, onSubmit, submitting, value }) => (
|
||||
<div>
|
||||
<>
|
||||
<Form.Item>
|
||||
<TextArea rows={4} onChange={onChange} value={value} />
|
||||
</Form.Item>
|
||||
@ -38,7 +38,7 @@ const Editor = ({ onChange, onSubmit, submitting, value }) => (
|
||||
Add Comment
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
class App extends React.Component {
|
||||
@ -84,7 +84,7 @@ class App extends React.Component {
|
||||
const { comments, submitting, value } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{comments.length > 0 && <CommentList comments={comments} />}
|
||||
<Comment
|
||||
avatar={
|
||||
@ -102,7 +102,7 @@ class App extends React.Component {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,6 @@ import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
|
||||
function getAction(actions: React.ReactNode[]) {
|
||||
if (!actions || !actions.length) {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
const actionList = actions.map((action, index) => <li key={`action-${index}`}>{action}</li>);
|
||||
return actionList;
|
||||
}
|
||||
|
||||
export interface CommentProps {
|
||||
/** List of action items rendered below the comment content */
|
||||
actions?: Array<React.ReactNode>;
|
||||
@ -40,7 +31,6 @@ const Comment: React.FC<CommentProps> = ({
|
||||
className,
|
||||
content,
|
||||
prefixCls: customizePrefixCls,
|
||||
style,
|
||||
datetime,
|
||||
...otherProps
|
||||
}) => {
|
||||
@ -60,10 +50,14 @@ const Comment: React.FC<CommentProps> = ({
|
||||
|
||||
const actionDom =
|
||||
actions && actions.length ? (
|
||||
<ul className={`${prefixCls}-actions`}>{getAction(actions)}</ul>
|
||||
<ul className={`${prefixCls}-actions`}>
|
||||
{actions.map((action, index) => (
|
||||
<li key={`action-${index}`}>{action}</li> // eslint-disable-line react/no-array-index-key
|
||||
))}
|
||||
</ul>
|
||||
) : null;
|
||||
|
||||
const authorContent = (
|
||||
const authorContent = (author || datetime) && (
|
||||
<div className={`${prefixCls}-content-author`}>
|
||||
{author && <span className={`${prefixCls}-content-author-name`}>{author}</span>}
|
||||
{datetime && <span className={`${prefixCls}-content-author-time`}>{datetime}</span>}
|
||||
@ -78,19 +72,16 @@ const Comment: React.FC<CommentProps> = ({
|
||||
</div>
|
||||
);
|
||||
|
||||
const comment = (
|
||||
<div className={`${prefixCls}-inner`}>
|
||||
{avatarDom}
|
||||
{contentDom}
|
||||
</div>
|
||||
);
|
||||
|
||||
const cls = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
return (
|
||||
<div {...otherProps} className={cls} style={style}>
|
||||
{comment}
|
||||
<div {...otherProps} className={cls}>
|
||||
<div className={`${prefixCls}-inner`}>
|
||||
{avatarDom}
|
||||
{contentDom}
|
||||
</div>
|
||||
{children ? renderNested(prefixCls, children) : null}
|
||||
</div>
|
||||
);
|
||||
|
@ -11446,9 +11446,6 @@ exports[`ConfigProvider components Comment configProvider 1`] = `
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11468,9 +11465,6 @@ exports[`ConfigProvider components Comment configProvider 1`] = `
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11493,9 +11487,6 @@ exports[`ConfigProvider components Comment configProvider componentSize large 1`
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11515,9 +11506,6 @@ exports[`ConfigProvider components Comment configProvider componentSize large 1`
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11540,9 +11528,6 @@ exports[`ConfigProvider components Comment configProvider componentSize middle 1
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11562,9 +11547,6 @@ exports[`ConfigProvider components Comment configProvider componentSize middle 1
|
||||
<div
|
||||
class="config-comment-content"
|
||||
>
|
||||
<div
|
||||
class="config-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="config-comment-content-detail"
|
||||
>
|
||||
@ -11587,9 +11569,6 @@ exports[`ConfigProvider components Comment configProvider virtual and dropdownMa
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
@ -11609,9 +11588,6 @@ exports[`ConfigProvider components Comment configProvider virtual and dropdownMa
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
@ -11634,9 +11610,6 @@ exports[`ConfigProvider components Comment normal 1`] = `
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
@ -11656,9 +11629,6 @@ exports[`ConfigProvider components Comment normal 1`] = `
|
||||
<div
|
||||
class="ant-comment-content"
|
||||
>
|
||||
<div
|
||||
class="ant-comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="ant-comment-content-detail"
|
||||
>
|
||||
@ -11681,9 +11651,6 @@ exports[`ConfigProvider components Comment prefixCls 1`] = `
|
||||
<div
|
||||
class="prefix-Comment-content"
|
||||
>
|
||||
<div
|
||||
class="prefix-Comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="prefix-Comment-content-detail"
|
||||
>
|
||||
@ -11703,9 +11670,6 @@ exports[`ConfigProvider components Comment prefixCls 1`] = `
|
||||
<div
|
||||
class="prefix-Comment-content"
|
||||
>
|
||||
<div
|
||||
class="prefix-Comment-content-author"
|
||||
/>
|
||||
<div
|
||||
class="prefix-Comment-content-detail"
|
||||
>
|
||||
|
@ -55,6 +55,10 @@ Some components use dynamic style to support wave effect. You can config `csp` p
|
||||
|
||||
## FAQ
|
||||
|
||||
#### How to contribute a new language?
|
||||
|
||||
See [<Adding new language>](/docs/react/i18n#Adding-newplanguage).
|
||||
|
||||
#### Does the locale problem still exist in DatePicker even if ConfigProvider `locale` is used?
|
||||
|
||||
Please make sure you set moment locale or that you don't have two different versions of moment.
|
||||
|
@ -56,6 +56,10 @@ return (
|
||||
|
||||
## FAQ
|
||||
|
||||
#### 如何增加一个新的语言包?
|
||||
|
||||
参考[《增加语言包》](/docs/react/i18n#%E5%A2%9E%E5%8A%A0%E8%AF%AD%E8%A8%80%E5%8C%85)。
|
||||
|
||||
#### 为什么我使用了 ConfigProvider `locale`,时间类组件的国际化还有问题?
|
||||
|
||||
请检查是否正确设置了 moment 语言包,或者是否有两个版本的 moment 共存。
|
||||
|
@ -271,7 +271,9 @@ exports[`MonthPicker and WeekPicker render WeekPicker 1`] = `
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th />
|
||||
<th
|
||||
aria-label="empty cell"
|
||||
/>
|
||||
<th>
|
||||
Su
|
||||
</th>
|
||||
|
@ -1,12 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DropdownButton rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<span
|
||||
class="ant-dropdown-trigger ant-dropdown-rtl"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`DropdownButton rtl render component should be rendered correctly in RTL direction 2`] = `
|
||||
<div
|
||||
class="ant-btn-group ant-btn-group-rtl ant-dropdown-button"
|
||||
>
|
||||
|
@ -0,0 +1,49 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Dropdown overlay is function and has custom transitionName 1`] = `
|
||||
Array [
|
||||
<button
|
||||
class="ant-dropdown-trigger"
|
||||
type="button"
|
||||
>
|
||||
button
|
||||
</button>,
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div>
|
||||
menu
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Dropdown overlay is string 1`] = `
|
||||
Array [
|
||||
<button
|
||||
class="ant-dropdown-trigger"
|
||||
type="button"
|
||||
>
|
||||
button
|
||||
</button>,
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
>
|
||||
<span>
|
||||
overlayNode
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Dropdown rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<span
|
||||
class="ant-dropdown-trigger ant-dropdown-rtl"
|
||||
/>
|
||||
`;
|
@ -6,18 +6,7 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
|
||||
describe('DropdownButton', () => {
|
||||
mountTest(() => (
|
||||
<Dropdown menu={<Menu />}>
|
||||
<span />
|
||||
</Dropdown>
|
||||
));
|
||||
mountTest(Dropdown.Button);
|
||||
|
||||
rtlTest(() => (
|
||||
<Dropdown menu={<Menu />}>
|
||||
<span />
|
||||
</Dropdown>
|
||||
));
|
||||
rtlTest(Dropdown.Button);
|
||||
|
||||
it('pass appropriate props to Dropdown', () => {
|
||||
|
38
components/dropdown/__tests__/index.test.js
Normal file
38
components/dropdown/__tests__/index.test.js
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Dropdown from '..';
|
||||
import Menu from '../../menu';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
|
||||
describe('Dropdown', () => {
|
||||
mountTest(() => (
|
||||
<Dropdown menu={<Menu />}>
|
||||
<span />
|
||||
</Dropdown>
|
||||
));
|
||||
|
||||
rtlTest(() => (
|
||||
<Dropdown menu={<Menu />}>
|
||||
<span />
|
||||
</Dropdown>
|
||||
));
|
||||
|
||||
it('overlay is function and has custom transitionName', () => {
|
||||
const wrapper = mount(
|
||||
<Dropdown overlay={() => <div>menu</div>} transitionName="move-up" visible>
|
||||
<button type="button">button</button>
|
||||
</Dropdown>,
|
||||
);
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
|
||||
it('overlay is string', () => {
|
||||
const wrapper = mount(
|
||||
<Dropdown overlay="string" visible>
|
||||
<button type="button">button</button>
|
||||
</Dropdown>,
|
||||
);
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
});
|
@ -85,7 +85,9 @@ const Dropdown: DropdownInterface = props => {
|
||||
} else {
|
||||
overlayNode = overlay;
|
||||
}
|
||||
overlayNode = React.Children.only(overlayNode) as React.ReactElement<any>;
|
||||
overlayNode = React.Children.only(
|
||||
typeof overlayNode === 'string' ? <span>overlayNode</span> : overlayNode,
|
||||
);
|
||||
|
||||
const overlayProps = overlayNode.props;
|
||||
|
||||
@ -108,7 +110,7 @@ const Dropdown: DropdownInterface = props => {
|
||||
|
||||
const fixedModeOverlay =
|
||||
typeof overlayNode.type === 'string'
|
||||
? overlay
|
||||
? overlayNode
|
||||
: cloneElement(overlayNode, {
|
||||
mode: 'vertical',
|
||||
selectable,
|
||||
|
@ -16,6 +16,11 @@
|
||||
}
|
||||
|
||||
&-menu {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-item-group-title {
|
||||
.@{dropdown-prefix-cls}-rtl & {
|
||||
direction: rtl;
|
||||
|
@ -71,7 +71,7 @@
|
||||
// ==============================================================
|
||||
&-label {
|
||||
display: inline-block;
|
||||
flex: none;
|
||||
flex-grow: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
|
@ -20,6 +20,10 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
> .@{form-item-prefix-cls}-label {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.@{form-prefix-cls}-text {
|
||||
display: inline-block;
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 6.7 KiB |
@ -101,6 +101,7 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
allowClear,
|
||||
direction,
|
||||
style,
|
||||
readOnly,
|
||||
} = this.props;
|
||||
const suffixNode = this.renderSuffix(prefixCls);
|
||||
if (!hasPrefixSuffix(this.props)) {
|
||||
@ -118,6 +119,7 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
[`${prefixCls}-affix-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-affix-wrapper-input-with-clear-btn`]: suffix && allowClear && value,
|
||||
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-affix-wrapper-readonly`]: readOnly,
|
||||
});
|
||||
return (
|
||||
<span
|
||||
|
@ -190,7 +190,7 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
|
||||
onFocus: React.FocusEventHandler<HTMLInputElement> = e => {
|
||||
const { onFocus } = this.props;
|
||||
this.setState({ focused: true });
|
||||
this.setState({ focused: true }, this.clearPasswordValueAttribute);
|
||||
if (onFocus) {
|
||||
onFocus(e);
|
||||
}
|
||||
@ -198,7 +198,7 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
|
||||
onBlur: React.FocusEventHandler<HTMLInputElement> = e => {
|
||||
const { onBlur } = this.props;
|
||||
this.setState({ focused: false });
|
||||
this.setState({ focused: false }, this.clearPasswordValueAttribute);
|
||||
if (onBlur) {
|
||||
onBlur(e);
|
||||
}
|
||||
|
@ -70,6 +70,23 @@ describe('Input.Password', () => {
|
||||
expect(wrapper.find('input').at('0').getDOMNode().getAttribute('value')).toBeFalsy();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/24526
|
||||
it('should not show value attribute in input element after blur it', async () => {
|
||||
const wrapper = mount(<Input.Password />);
|
||||
wrapper
|
||||
.find('input')
|
||||
.at('0')
|
||||
.simulate('change', { target: { value: 'value' } });
|
||||
await sleep();
|
||||
expect(wrapper.find('input').at('0').getDOMNode().getAttribute('value')).toBeFalsy();
|
||||
wrapper.find('input').at('0').simulate('blur');
|
||||
await sleep();
|
||||
expect(wrapper.find('input').at('0').getDOMNode().getAttribute('value')).toBeFalsy();
|
||||
wrapper.find('input').at('0').simulate('focus');
|
||||
await sleep();
|
||||
expect(wrapper.find('input').at('0').getDOMNode().getAttribute('value')).toBeFalsy();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/20541
|
||||
it('could be unmount without errors', () => {
|
||||
expect(() => {
|
||||
|
@ -259,11 +259,11 @@
|
||||
}
|
||||
|
||||
// Fix https://github.com/ant-design/ant-design/issues/5754
|
||||
&-lg .@{ant-prefix}-select-single .ant-select-selector {
|
||||
&-lg .@{ant-prefix}-select-single .@{ant-prefix}-select-selector {
|
||||
height: @input-height-lg;
|
||||
}
|
||||
|
||||
&-sm .@{ant-prefix}-select-single .ant-select-selector {
|
||||
&-sm .@{ant-prefix}-select-single .@{ant-prefix}-select-selector {
|
||||
height: @input-height-sm;
|
||||
}
|
||||
|
||||
|
@ -58,12 +58,19 @@ export interface ListItemTypeProps extends React.FC<ListItemProps> {
|
||||
Meta: typeof Meta;
|
||||
}
|
||||
|
||||
const Item: ListItemTypeProps = props => {
|
||||
const Item: ListItemTypeProps = ({
|
||||
prefixCls: customizePrefixCls,
|
||||
children,
|
||||
actions,
|
||||
extra,
|
||||
className,
|
||||
colStyle,
|
||||
...others
|
||||
}) => {
|
||||
const { grid, itemLayout } = React.useContext(ListContext);
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
const isItemContainsTextNodeAndNotSingular = () => {
|
||||
const { children } = props;
|
||||
let result;
|
||||
React.Children.forEach(children, (element: React.ReactElement<any>) => {
|
||||
if (typeof element === 'string') {
|
||||
@ -74,22 +81,12 @@ const Item: ListItemTypeProps = props => {
|
||||
};
|
||||
|
||||
const isFlexMode = () => {
|
||||
const { extra } = props;
|
||||
if (itemLayout === 'vertical') {
|
||||
return !!extra;
|
||||
}
|
||||
return !isItemContainsTextNodeAndNotSingular();
|
||||
};
|
||||
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
children,
|
||||
actions,
|
||||
extra,
|
||||
className,
|
||||
colStyle,
|
||||
...others
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('list', customizePrefixCls);
|
||||
const actionsContent = actions && actions.length > 0 && (
|
||||
<ul className={`${prefixCls}-item-action`} key="actions">
|
||||
|
@ -128,4 +128,54 @@ describe('List Item Layout', () => {
|
||||
);
|
||||
expect(render(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('rowKey could be string', () => {
|
||||
const dataWithId = [
|
||||
{
|
||||
id: 1,
|
||||
title: `ant design`,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: `ant design`,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: `ant design`,
|
||||
},
|
||||
];
|
||||
const wrapper = mount(
|
||||
<List
|
||||
dataSource={dataWithId}
|
||||
rowKey="id"
|
||||
renderItem={item => <List.Item>{item.title}</List.Item>}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('rowKey could be function', () => {
|
||||
const dataWithId = [
|
||||
{
|
||||
id: 1,
|
||||
title: `ant design`,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: `ant design`,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: `ant design`,
|
||||
},
|
||||
];
|
||||
const wrapper = mount(
|
||||
<List
|
||||
dataSource={dataWithId}
|
||||
rowKey={item => item.id}
|
||||
renderItem={item => <List.Item>{item.title}</List.Item>}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -57,6 +57,154 @@ exports[`List Item Layout horizontal itemLayout List should accept extra node 1`
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`List Item Layout rowKey could be function 1`] = `
|
||||
<List
|
||||
dataSource={
|
||||
Array [
|
||||
Object {
|
||||
"id": 1,
|
||||
"title": "ant design",
|
||||
},
|
||||
Object {
|
||||
"id": 2,
|
||||
"title": "ant design",
|
||||
},
|
||||
Object {
|
||||
"id": 3,
|
||||
"title": "ant design",
|
||||
},
|
||||
]
|
||||
}
|
||||
renderItem={[Function]}
|
||||
rowKey={[Function]}
|
||||
>
|
||||
<div
|
||||
className="ant-list ant-list-split"
|
||||
>
|
||||
<Spin
|
||||
size="default"
|
||||
spinning={false}
|
||||
wrapperClassName=""
|
||||
>
|
||||
<div
|
||||
className="ant-spin-nested-loading"
|
||||
>
|
||||
<div
|
||||
className="ant-spin-container"
|
||||
key="container"
|
||||
>
|
||||
<ul
|
||||
className="ant-list-items"
|
||||
>
|
||||
<Item
|
||||
key="1/.0"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
<Item
|
||||
key="2/.1"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
<Item
|
||||
key="3/.2"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</List>
|
||||
`;
|
||||
|
||||
exports[`List Item Layout rowKey could be string 1`] = `
|
||||
<List
|
||||
dataSource={
|
||||
Array [
|
||||
Object {
|
||||
"id": 1,
|
||||
"title": "ant design",
|
||||
},
|
||||
Object {
|
||||
"id": 2,
|
||||
"title": "ant design",
|
||||
},
|
||||
Object {
|
||||
"id": 3,
|
||||
"title": "ant design",
|
||||
},
|
||||
]
|
||||
}
|
||||
renderItem={[Function]}
|
||||
rowKey="id"
|
||||
>
|
||||
<div
|
||||
className="ant-list ant-list-split"
|
||||
>
|
||||
<Spin
|
||||
size="default"
|
||||
spinning={false}
|
||||
wrapperClassName=""
|
||||
>
|
||||
<div
|
||||
className="ant-spin-nested-loading"
|
||||
>
|
||||
<div
|
||||
className="ant-spin-container"
|
||||
key="container"
|
||||
>
|
||||
<ul
|
||||
className="ant-list-items"
|
||||
>
|
||||
<Item
|
||||
key="1/.0"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
<Item
|
||||
key="2/.1"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
<Item
|
||||
key="3/.2"
|
||||
>
|
||||
<li
|
||||
className="ant-list-item"
|
||||
>
|
||||
ant design
|
||||
</li>
|
||||
</Item>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
</List>
|
||||
`;
|
||||
|
||||
exports[`List Item Layout should render in RTL direction 1`] = `
|
||||
<div
|
||||
class="ant-list ant-list-split ant-list-rtl"
|
||||
|
@ -245,10 +245,17 @@ function List<T>({
|
||||
if (splitDataSource.length > 0) {
|
||||
const items = splitDataSource.map((item: any, index: number) => renderInnerItem(item, index));
|
||||
const childrenList = React.Children.map(items, (child: any, index) =>
|
||||
cloneElement(child, {
|
||||
key: keys[index],
|
||||
colStyle,
|
||||
}),
|
||||
cloneElement(
|
||||
child,
|
||||
grid
|
||||
? {
|
||||
key: keys[index],
|
||||
colStyle,
|
||||
}
|
||||
: {
|
||||
key: keys[index],
|
||||
},
|
||||
),
|
||||
);
|
||||
childrenContent = grid ? (
|
||||
<Row gutter={grid.gutter}>{childrenList}</Row>
|
||||
|
@ -1,9 +1,12 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import Pagination from 'rc-pagination/lib/locale/en_GB';
|
||||
import DatePicker from '../date-picker/locale/en_GB';
|
||||
import TimePicker from '../time-picker/locale/en_GB';
|
||||
import Calendar from '../calendar/locale/en_GB';
|
||||
import { Locale } from '../locale-provider';
|
||||
|
||||
const typeTemplate = '${label} is not a valid ${type}';
|
||||
|
||||
const localeValues: Locale = {
|
||||
locale: 'en-gb',
|
||||
Pagination,
|
||||
@ -41,6 +44,55 @@ const localeValues: Locale = {
|
||||
Empty: {
|
||||
description: 'No data',
|
||||
},
|
||||
Form: {
|
||||
defaultValidateMessages: {
|
||||
default: 'Field validation error ${label}',
|
||||
required: 'Please enter ${label}',
|
||||
enum: '${label} must be one of [${enum}]',
|
||||
whitespace: '${label} cannot be a blank character',
|
||||
date: {
|
||||
format: '${label} date format is invalid',
|
||||
parse: '${label} cannot be converted to a date',
|
||||
invalid: '${label} is an invalid date',
|
||||
},
|
||||
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} must be ${len} characters',
|
||||
min: '${label} at least ${min} characters',
|
||||
max: '${label} up to ${max} characters',
|
||||
range: '${label} must be between ${min}-${max} characters',
|
||||
},
|
||||
number: {
|
||||
len: '${label} must be equal to ${len}',
|
||||
min: '${label} minimum value is ${min}',
|
||||
max: '${label} maximum value is ${max}',
|
||||
range: '${label} must be between ${min}-${max}',
|
||||
},
|
||||
array: {
|
||||
len: 'Must be ${len} ${label}',
|
||||
min: 'At least ${min} ${label}',
|
||||
max: 'At most ${max} ${label}',
|
||||
range: 'The amount of ${label} must be between ${min}-${max}',
|
||||
},
|
||||
pattern: {
|
||||
mismatch: '${label} does not match the pattern ${pattern}',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
||||
|
@ -42,6 +42,12 @@ const localeValues: Locale = {
|
||||
Empty: {
|
||||
description: 'Ei kohteita',
|
||||
},
|
||||
Text: {
|
||||
edit: 'Muokkaa',
|
||||
copy: 'Kopioi',
|
||||
copied: 'Kopioitu',
|
||||
expand: 'Näytä lisää',
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
||||
|
@ -1,21 +1,35 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
|
||||
import Pagination from 'rc-pagination/lib/locale/pt_BR';
|
||||
import DatePicker from '../date-picker/locale/pt_BR';
|
||||
import TimePicker from '../time-picker/locale/pt_BR';
|
||||
import Calendar from '../calendar/locale/pt_BR';
|
||||
import { Locale } from '../locale-provider';
|
||||
|
||||
const typeTemplate = '${label} não é um ${type} válido';
|
||||
|
||||
const localeValues: Locale = {
|
||||
locale: 'pt-br',
|
||||
Pagination,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Por favor escolha',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtro',
|
||||
filterTitle: 'Menu de Filtro',
|
||||
filterConfirm: 'OK',
|
||||
filterReset: 'Resetar',
|
||||
selectAll: 'Selecionar página atual',
|
||||
selectInvert: 'Inverter seleção',
|
||||
selectionAll: 'Selecionar todo o conteúdo',
|
||||
sortTitle: 'Ordenar título',
|
||||
expand: 'Expandir linha',
|
||||
collapse: 'Colapsar linha',
|
||||
triggerDesc: 'Clique organiza por descendente',
|
||||
triggerAsc: 'Clique organiza por ascendente',
|
||||
cancelSort: 'Clique para cancelar organização',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
@ -41,12 +55,67 @@ const localeValues: Locale = {
|
||||
Empty: {
|
||||
description: 'Não há dados',
|
||||
},
|
||||
Icon: {
|
||||
icon: 'ícone',
|
||||
},
|
||||
Text: {
|
||||
edit: 'editar',
|
||||
copy: 'copiar',
|
||||
copied: 'copiado',
|
||||
expand: 'expandir',
|
||||
},
|
||||
PageHeader: {
|
||||
back: 'Retornar',
|
||||
},
|
||||
Form: {
|
||||
defaultValidateMessages: {
|
||||
default: 'Erro ${label} na validação de campo',
|
||||
required: 'Por favor, insira ${label}',
|
||||
enum: '${label} deve ser um dos seguinte: [${enum}]',
|
||||
whitespace: '${label} não pode ser um caractér vazio',
|
||||
date: {
|
||||
format: ' O formato de data ${label} é inválido',
|
||||
parse: '${label} não pode ser convertido para uma data',
|
||||
invalid: '${label} é uma data inválida',
|
||||
},
|
||||
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} deve possuir ${len} caracteres',
|
||||
min: '${label} deve possuir ao menos ${min} caracteres',
|
||||
max: '${label} deve possuir no máximo ${max} caracteres',
|
||||
range: '${label} deve possuir entre ${min} e ${max} caracteres',
|
||||
},
|
||||
number: {
|
||||
len: '${label} deve ser igual à ${len}',
|
||||
min: 'O valor mínimo de ${label} é ${min}',
|
||||
max: 'O valor máximo de ${label} é ${max}',
|
||||
range: '${label} deve estar entre ${min} e ${max}',
|
||||
},
|
||||
array: {
|
||||
len: 'Deve ser ${len} ${label}',
|
||||
min: 'No mínimo ${min} ${label}',
|
||||
max: 'No máximo ${max} ${label}',
|
||||
range: 'A quantidade de ${label} deve estar entre ${min} e ${max}',
|
||||
},
|
||||
pattern: {
|
||||
mismatch: '${label} não se encaixa no padrão ${pattern}',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default localeValues;
|
||||
|
@ -74,7 +74,7 @@ describe('Mentions', () => {
|
||||
expect(onBlur).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
focusTest(Mentions);
|
||||
focusTest(Mentions, { refFocus: true });
|
||||
mountTest(Mentions);
|
||||
rtlTest(Mentions);
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import RcMentions from 'rc-mentions';
|
||||
import { MentionsProps as RcMentionsProps } from 'rc-mentions/lib/Mentions';
|
||||
import Spin from '../spin';
|
||||
import { ConfigConsumer, ConfigConsumerProps, RenderEmptyHandler } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { composeRef } from '../_util/ref';
|
||||
|
||||
const { Option } = RcMentions;
|
||||
export const { Option } = RcMentions;
|
||||
|
||||
function loadingFilterOption() {
|
||||
return true;
|
||||
@ -38,75 +38,54 @@ interface MentionsEntity {
|
||||
value: string;
|
||||
}
|
||||
|
||||
class Mentions extends React.Component<MentionProps, MentionState> {
|
||||
static Option = Option;
|
||||
interface CompoundedComponent
|
||||
extends React.ForwardRefExoticComponent<MentionProps & React.RefAttributes<HTMLElement>> {
|
||||
Option: typeof Option;
|
||||
getMentions: (value: string, config?: MentionsConfig) => MentionsEntity[];
|
||||
}
|
||||
|
||||
static getMentions = (value: string = '', config?: MentionsConfig): MentionsEntity[] => {
|
||||
const { prefix = '@', split = ' ' } = config || {};
|
||||
const prefixList: string[] = Array.isArray(prefix) ? prefix : [prefix];
|
||||
const InternalMentions: React.ForwardRefRenderFunction<unknown, MentionProps> = (
|
||||
{
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
disabled,
|
||||
loading,
|
||||
filterOption,
|
||||
children,
|
||||
notFoundContent,
|
||||
...restProps
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const [focused, setFocused] = React.useState(false);
|
||||
const innerRef = React.useRef<HTMLElement>();
|
||||
const mergedRef = composeRef(ref, innerRef);
|
||||
const { getPrefixCls, renderEmpty, direction } = React.useContext(ConfigContext);
|
||||
|
||||
return value
|
||||
.split(split)
|
||||
.map((str = ''): MentionsEntity | null => {
|
||||
let hitPrefix: string | null = null;
|
||||
|
||||
prefixList.some(prefixStr => {
|
||||
const startStr = str.slice(0, prefixStr.length);
|
||||
if (startStr === prefixStr) {
|
||||
hitPrefix = prefixStr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (hitPrefix !== null) {
|
||||
return {
|
||||
prefix: hitPrefix,
|
||||
value: str.slice(hitPrefix!.length),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter((entity): entity is MentionsEntity => !!entity && !!entity.value);
|
||||
};
|
||||
|
||||
state = {
|
||||
focused: false,
|
||||
};
|
||||
|
||||
private rcMentions: any;
|
||||
|
||||
onFocus: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
|
||||
const { onFocus } = this.props;
|
||||
if (onFocus) {
|
||||
onFocus(...args);
|
||||
const onFocus: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
|
||||
if (restProps.onFocus) {
|
||||
restProps.onFocus(...args);
|
||||
}
|
||||
this.setState({
|
||||
focused: true,
|
||||
});
|
||||
setFocused(true);
|
||||
};
|
||||
|
||||
onBlur: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
|
||||
const { onBlur } = this.props;
|
||||
if (onBlur) {
|
||||
onBlur(...args);
|
||||
const onBlur: React.FocusEventHandler<HTMLTextAreaElement> = (...args) => {
|
||||
if (restProps.onBlur) {
|
||||
restProps.onBlur(...args);
|
||||
}
|
||||
this.setState({
|
||||
focused: false,
|
||||
});
|
||||
|
||||
setFocused(false);
|
||||
};
|
||||
|
||||
getNotFoundContent(renderEmpty: RenderEmptyHandler) {
|
||||
const { notFoundContent } = this.props;
|
||||
const getNotFoundContent = () => {
|
||||
if (notFoundContent !== undefined) {
|
||||
return notFoundContent;
|
||||
}
|
||||
|
||||
return renderEmpty('Select');
|
||||
}
|
||||
};
|
||||
|
||||
getOptions = () => {
|
||||
const { children, loading } = this.props;
|
||||
const getOptions = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<Option value="ANTD_SEARCHING" disabled>
|
||||
@ -118,59 +97,70 @@ class Mentions extends React.Component<MentionProps, MentionState> {
|
||||
return children;
|
||||
};
|
||||
|
||||
getFilterOption = (): any => {
|
||||
const { filterOption, loading } = this.props;
|
||||
const getFilterOption = (): any => {
|
||||
if (loading) {
|
||||
return loadingFilterOption;
|
||||
}
|
||||
return filterOption;
|
||||
};
|
||||
|
||||
saveMentions = (node: typeof RcMentions) => {
|
||||
this.rcMentions = node;
|
||||
};
|
||||
const prefixCls = getPrefixCls('mentions', customizePrefixCls);
|
||||
|
||||
focus() {
|
||||
this.rcMentions.focus();
|
||||
}
|
||||
const mergedClassName = classNames(className, {
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-focused`]: focused,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
blur() {
|
||||
this.rcMentions.blur();
|
||||
}
|
||||
return (
|
||||
<RcMentions
|
||||
prefixCls={prefixCls}
|
||||
notFoundContent={getNotFoundContent()}
|
||||
className={mergedClassName}
|
||||
disabled={disabled}
|
||||
direction={direction}
|
||||
{...restProps}
|
||||
filterOption={getFilterOption()}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
ref={mergedRef as any}
|
||||
>
|
||||
{getOptions()}
|
||||
</RcMentions>
|
||||
);
|
||||
};
|
||||
|
||||
renderMentions = ({ getPrefixCls, renderEmpty, direction }: ConfigConsumerProps) => {
|
||||
const { focused } = this.state;
|
||||
const { prefixCls: customizePrefixCls, className, disabled, ...restProps } = this.props;
|
||||
const prefixCls = getPrefixCls('mentions', customizePrefixCls);
|
||||
const mentionsProps = omit(restProps, ['loading']);
|
||||
const Mentions = React.forwardRef<unknown, MentionProps>(InternalMentions) as CompoundedComponent;
|
||||
Mentions.displayName = 'Mentions';
|
||||
Mentions.Option = Option;
|
||||
|
||||
const mergedClassName = classNames(className, {
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-focused`]: focused,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
Mentions.getMentions = (value: string = '', config?: MentionsConfig): MentionsEntity[] => {
|
||||
const { prefix = '@', split = ' ' } = config || {};
|
||||
const prefixList: string[] = Array.isArray(prefix) ? prefix : [prefix];
|
||||
|
||||
return (
|
||||
<RcMentions
|
||||
prefixCls={prefixCls}
|
||||
notFoundContent={this.getNotFoundContent(renderEmpty)}
|
||||
className={mergedClassName}
|
||||
disabled={disabled}
|
||||
direction={direction}
|
||||
{...mentionsProps}
|
||||
filterOption={this.getFilterOption()}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
ref={this.saveMentions}
|
||||
>
|
||||
{this.getOptions()}
|
||||
</RcMentions>
|
||||
);
|
||||
};
|
||||
return value
|
||||
.split(split)
|
||||
.map((str = ''): MentionsEntity | null => {
|
||||
let hitPrefix: string | null = null;
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderMentions}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
prefixList.some(prefixStr => {
|
||||
const startStr = str.slice(0, prefixStr.length);
|
||||
if (startStr === prefixStr) {
|
||||
hitPrefix = prefixStr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (hitPrefix !== null) {
|
||||
return {
|
||||
prefix: hitPrefix,
|
||||
value: str.slice(hitPrefix!.length),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter((entity): entity is MentionsEntity => !!entity && !!entity.value);
|
||||
};
|
||||
|
||||
export default Mentions;
|
||||
|
@ -40,11 +40,16 @@ export default class MenuItem extends React.Component<MenuItemProps> {
|
||||
this.menuItem = menuItem;
|
||||
};
|
||||
|
||||
renderItemChildren() {
|
||||
const { icon, children } = this.props;
|
||||
renderItemChildren(inlineCollapsed: boolean) {
|
||||
const { icon, children, level, rootPrefixCls } = this.props;
|
||||
// inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span
|
||||
// ref: https://github.com/ant-design/ant-design/pull/23456
|
||||
if (!icon || (isValidElement(children) && children.type === 'span')) {
|
||||
if (children && inlineCollapsed && level === 1 && typeof children === 'string') {
|
||||
return (
|
||||
<div className={`${rootPrefixCls}-inline-collapsed-noicon`}>{children.charAt(0)}</div>
|
||||
);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
return <span>{children}</span>;
|
||||
@ -91,7 +96,7 @@ export default class MenuItem extends React.Component<MenuItemProps> {
|
||||
ref={this.saveMenuItem}
|
||||
>
|
||||
{icon}
|
||||
{this.renderItemChildren()}
|
||||
{this.renderItemChildren(inlineCollapsed)}
|
||||
</Item>
|
||||
</Tooltip>
|
||||
);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import { SubMenu as RcSubMenu } from 'rc-menu';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
@ -15,6 +14,7 @@ export interface SubMenuProps {
|
||||
rootPrefixCls?: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
level?: number;
|
||||
title?: React.ReactNode;
|
||||
icon?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
@ -26,9 +26,7 @@ export interface SubMenuProps {
|
||||
}
|
||||
|
||||
class SubMenu extends React.Component<SubMenuProps, any> {
|
||||
static contextTypes = {
|
||||
antdMenuTheme: PropTypes.string,
|
||||
};
|
||||
static contextType = MenuContext;
|
||||
|
||||
// fix issue:https://github.com/ant-design/ant-design/issues/8666
|
||||
static isSubMenu = 1;
|
||||
@ -43,10 +41,14 @@ class SubMenu extends React.Component<SubMenuProps, any> {
|
||||
this.subMenu = subMenu;
|
||||
};
|
||||
|
||||
renderTitle() {
|
||||
const { icon, title } = this.props;
|
||||
renderTitle(inlineCollapsed: boolean) {
|
||||
const { icon, title, level, rootPrefixCls } = this.props;
|
||||
if (!icon) {
|
||||
return title;
|
||||
return inlineCollapsed && level === 1 && title && typeof title === 'string' ? (
|
||||
<div className={`${rootPrefixCls}-inline-collapsed-noicon`}>{title.charAt(0)}</div>
|
||||
) : (
|
||||
title
|
||||
);
|
||||
}
|
||||
// inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span
|
||||
// ref: https://github.com/ant-design/ant-design/pull/23456
|
||||
@ -63,10 +65,10 @@ class SubMenu extends React.Component<SubMenuProps, any> {
|
||||
const { rootPrefixCls, popupClassName } = this.props;
|
||||
return (
|
||||
<MenuContext.Consumer>
|
||||
{({ antdMenuTheme }: MenuContextProps) => (
|
||||
{({ inlineCollapsed, antdMenuTheme }: MenuContextProps) => (
|
||||
<RcSubMenu
|
||||
{...omit(this.props, ['icon'])}
|
||||
title={this.renderTitle()}
|
||||
title={this.renderTitle(inlineCollapsed)}
|
||||
ref={this.saveSubMenu}
|
||||
popupClassName={classNames(
|
||||
rootPrefixCls,
|
||||
|
@ -516,6 +516,16 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&-root&-inline-collapsed {
|
||||
.@{menu-prefix-cls}-item,
|
||||
.@{menu-prefix-cls}-submenu .@{menu-prefix-cls}-submenu-title {
|
||||
> .@{menu-prefix-cls}-inline-collapsed-noicon {
|
||||
font-size: @menu-icon-size-lg;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-sub&-inline {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
|
@ -1,37 +0,0 @@
|
||||
---
|
||||
order: 5
|
||||
title:
|
||||
zh-CN: 确认对话框
|
||||
en-US: Confirmation modal dialog
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
使用 `confirm()` 可以快捷地弹出确认框。onCancel/onOk 返回 promise 可以延迟关闭。
|
||||
|
||||
## en-US
|
||||
|
||||
Use `confirm()` to show a confirmation modal dialog. Let onCancel/onOk function return a promise object to delay closing the dialog.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button } from 'antd';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
function showConfirm() {
|
||||
confirm({
|
||||
title: 'Do you want to delete these items?',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: 'When clicked the OK button, this dialog will be closed after 1 second',
|
||||
onOk() {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
|
||||
}).catch(() => console.log('Oops errors!'));
|
||||
},
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
ReactDOM.render(<Button onClick={showConfirm}>Confirm</Button>, mountNode);
|
||||
```
|
@ -7,11 +7,11 @@ title:
|
||||
|
||||
## zh-CN
|
||||
|
||||
使用 `confirm()` 可以快捷地弹出确认框。
|
||||
使用 `confirm()` 可以快捷地弹出确认框。onCancel/onOk 返回 promise 可以延迟关闭。
|
||||
|
||||
## en-US
|
||||
|
||||
Use `confirm()` to show a confirmation modal dialog.
|
||||
Use `confirm()` to show a confirmation modal dialog. Let onCancel/onOk function return a promise object to delay closing the dialog.
|
||||
|
||||
```jsx
|
||||
import { Modal, Button, Space } from 'antd';
|
||||
@ -33,6 +33,20 @@ function showConfirm() {
|
||||
});
|
||||
}
|
||||
|
||||
function showPromiseConfirm() {
|
||||
confirm({
|
||||
title: 'Do you want to delete these items?',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: 'When clicked the OK button, this dialog will be closed after 1 second',
|
||||
onOk() {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
|
||||
}).catch(() => console.log('Oops errors!'));
|
||||
},
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
function showDeleteConfirm() {
|
||||
confirm({
|
||||
title: 'Are you sure delete this task?',
|
||||
@ -73,6 +87,7 @@ function showPropsConfirm() {
|
||||
ReactDOM.render(
|
||||
<Space>
|
||||
<Button onClick={showConfirm}>Confirm</Button>
|
||||
<Button onClick={showPromiseConfirm}>With promise</Button>
|
||||
<Button onClick={showDeleteConfirm} type="dashed">
|
||||
Delete
|
||||
</Button>
|
||||
|
@ -1,42 +1,36 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { ProgressProps, ProgressSize } from './progress';
|
||||
|
||||
interface StepsProps extends ProgressProps {
|
||||
steps: number;
|
||||
size?: ProgressSize;
|
||||
strokeColor?: string;
|
||||
}
|
||||
|
||||
const Steps: React.FC<StepsProps> = props => {
|
||||
const {
|
||||
size = 'default',
|
||||
steps,
|
||||
percent = 0,
|
||||
strokeWidth = 8,
|
||||
strokeColor,
|
||||
prefixCls,
|
||||
children,
|
||||
} = props;
|
||||
const getStyledSteps = () => {
|
||||
const current = Math.floor(steps * (percent / 100));
|
||||
const stepWidth = size === 'small' ? 2 : 14;
|
||||
const styleSteps = [];
|
||||
for (let i = 0; i < steps; i++) {
|
||||
let color;
|
||||
if (i <= current - 1) {
|
||||
color = strokeColor;
|
||||
}
|
||||
const stepStyle = {
|
||||
backgroundColor: `${color}`,
|
||||
width: `${stepWidth}px`,
|
||||
height: `${strokeWidth}px`,
|
||||
};
|
||||
styleSteps.push(<div key={i} className={`${prefixCls}-steps-item`} style={stepStyle} />);
|
||||
}
|
||||
return styleSteps;
|
||||
};
|
||||
const { size, steps, percent = 0, strokeWidth = 8, strokeColor, prefixCls, children } = props;
|
||||
const current = Math.floor(steps * (percent / 100));
|
||||
const stepWidth = size === 'small' ? 2 : 14;
|
||||
const styledSteps = [];
|
||||
for (let i = 0; i < steps; i += 1) {
|
||||
styledSteps.push(
|
||||
<div
|
||||
key={i}
|
||||
className={classNames(`${prefixCls}-steps-item`, {
|
||||
[`${prefixCls}-steps-item-active`]: i <= current - 1,
|
||||
})}
|
||||
style={{
|
||||
backgroundColor: i <= current - 1 ? strokeColor : undefined,
|
||||
width: stepWidth,
|
||||
height: strokeWidth,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className={`${prefixCls}-steps-outer`}>
|
||||
{getStyledSteps()}
|
||||
{styledSteps}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/progress/demo/circle.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -43,7 +43,7 @@ exports[`renders ./components/progress/demo/circle.md correctly 1`] = `
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-exception ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -103,7 +103,7 @@ exports[`renders ./components/progress/demo/circle.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -163,12 +163,12 @@ exports[`renders ./components/progress/demo/circle.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/circle-dynamic.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -210,7 +210,7 @@ exports[`renders ./components/progress/demo/circle-dynamic.md correctly 1`] = `
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-btn-group"
|
||||
>
|
||||
@ -268,12 +268,12 @@ exports[`renders ./components/progress/demo/circle-dynamic.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/circle-mini.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -315,7 +315,7 @@ exports[`renders ./components/progress/demo/circle-mini.md correctly 1`] = `
|
||||
30%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-exception ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -375,7 +375,7 @@ exports[`renders ./components/progress/demo/circle-mini.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -435,12 +435,12 @@ exports[`renders ./components/progress/demo/circle-mini.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/dashboard.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -482,7 +482,7 @@ exports[`renders ./components/progress/demo/dashboard.md correctly 1`] = `
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -524,12 +524,12 @@ exports[`renders ./components/progress/demo/dashboard.md correctly 1`] = `
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/dynamic.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -551,7 +551,7 @@ exports[`renders ./components/progress/demo/dynamic.md correctly 1`] = `
|
||||
>
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-btn-group"
|
||||
>
|
||||
@ -609,12 +609,12 @@ exports[`renders ./components/progress/demo/dynamic.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/format.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -656,7 +656,7 @@ exports[`renders ./components/progress/demo/format.md correctly 1`] = `
|
||||
75 Days
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -698,12 +698,12 @@ exports[`renders ./components/progress/demo/format.md correctly 1`] = `
|
||||
Done
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -725,7 +725,7 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
>
|
||||
99.9%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-active ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -747,7 +747,7 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
>
|
||||
99.9%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -807,7 +807,7 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
90%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -885,12 +885,12 @@ exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -912,7 +912,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
30%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-active ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -934,7 +934,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
>
|
||||
50%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-exception ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -974,7 +974,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-success ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1014,7 +1014,7 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-default"
|
||||
>
|
||||
@ -1030,8 +1030,8 @@ exports[`renders ./components/progress/demo/line.md correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
@ -1166,7 +1166,7 @@ exports[`renders ./components/progress/demo/line-mini.md correctly 1`] = `
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/linecap.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1188,7 +1188,7 @@ exports[`renders ./components/progress/demo/linecap.md correctly 1`] = `
|
||||
>
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1230,7 +1230,7 @@ exports[`renders ./components/progress/demo/linecap.md correctly 1`] = `
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1272,12 +1272,12 @@ exports[`renders ./components/progress/demo/linecap.md correctly 1`] = `
|
||||
75%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/segment.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1303,7 +1303,7 @@ exports[`renders ./components/progress/demo/segment.md correctly 1`] = `
|
||||
>
|
||||
60%
|
||||
</span>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1357,7 +1357,7 @@ exports[`renders ./components/progress/demo/segment.md correctly 1`] = `
|
||||
60%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1411,12 +1411,12 @@ exports[`renders ./components/progress/demo/segment.md correctly 1`] = `
|
||||
60%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div
|
||||
class="ant-progress ant-progress-steps ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1424,16 +1424,16 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
class="ant-progress-steps-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:14px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
@ -1442,8 +1442,8 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
50%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</div>,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-progress ant-progress-steps ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
@ -1451,24 +1451,24 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
class="ant-progress-steps-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:14px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:undefined;width:14px;height:8px"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
@ -1477,8 +1477,8 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
30%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
</div>,
|
||||
<br />,
|
||||
<div
|
||||
class="ant-progress ant-progress-steps ant-progress-status-success ant-progress-show-info ant-progress-small"
|
||||
>
|
||||
@ -1486,24 +1486,24 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
class="ant-progress-steps-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:2px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="background-color:#52c41a;width:2px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:2px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="background-color:#52c41a;width:2px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:2px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="background-color:#52c41a;width:2px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:2px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="background-color:#52c41a;width:2px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="background-color:#1890ff;width:2px;height:8px"
|
||||
class="ant-progress-steps-item ant-progress-steps-item-active"
|
||||
style="background-color:#52c41a;width:2px;height:8px"
|
||||
/>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
@ -1530,6 +1530,6 @@ exports[`renders ./components/progress/demo/steps.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
@ -550,3 +550,32 @@ exports[`Progress rtl render component should be rendered correctly in RTL direc
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Progress should support steps 1`] = `
|
||||
<div
|
||||
class="ant-progress ant-progress-steps ant-progress-status-normal ant-progress-show-info ant-progress-default"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-steps-outer"
|
||||
>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<div
|
||||
class="ant-progress-steps-item"
|
||||
style="width:14px;height:8px"
|
||||
/>
|
||||
<span
|
||||
class="ant-progress-text"
|
||||
title="0%"
|
||||
>
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -133,4 +133,30 @@ describe('Progress', () => {
|
||||
expect(wrapper.find('.ant-progress-status-success')).toHaveLength(1);
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should support steps', () => {
|
||||
const wrapper = mount(<Progress steps={3} />);
|
||||
expect(wrapper).toMatchRenderedSnapshot();
|
||||
});
|
||||
|
||||
it('steps should be changable', () => {
|
||||
const wrapper = mount(<Progress steps={5} percent={60} />);
|
||||
expect(wrapper.find('.ant-progress-steps-item-active').length).toBe(3);
|
||||
wrapper.setProps({ percent: 40 });
|
||||
expect(wrapper.find('.ant-progress-steps-item-active').length).toBe(2);
|
||||
});
|
||||
|
||||
it('steps should be changable when has strokeColor', () => {
|
||||
const wrapper = mount(<Progress steps={5} percent={60} strokeColor="#1890ff" />);
|
||||
expect(wrapper.find('.ant-progress-steps-item').at(0).getDOMNode().style.backgroundColor).toBe(
|
||||
'rgb(24, 144, 255)',
|
||||
);
|
||||
wrapper.setProps({ percent: 40 });
|
||||
expect(wrapper.find('.ant-progress-steps-item').at(2).getDOMNode().style.backgroundColor).toBe(
|
||||
'',
|
||||
);
|
||||
expect(wrapper.find('.ant-progress-steps-item').at(1).getDOMNode().style.backgroundColor).toBe(
|
||||
'rgb(24, 144, 255)',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -17,8 +17,6 @@ A dynamic progress bar is better.
|
||||
import { Progress, Button } from 'antd';
|
||||
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
const ButtonGroup = Button.Group;
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
percent: 0,
|
||||
@ -42,13 +40,13 @@ class App extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Progress type="circle" percent={this.state.percent} />
|
||||
<ButtonGroup>
|
||||
<Button.Group>
|
||||
<Button onClick={this.decline} icon={<MinusOutlined />} />
|
||||
<Button onClick={this.increase} icon={<PlusOutlined />} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Button.Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ A smaller circular progress bar.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress type="circle" percent={30} width={80} />
|
||||
<Progress type="circle" percent={70} width={80} status="exception" />
|
||||
<Progress type="circle" percent={100} width={80} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,11 +17,11 @@ A circular progress bar.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress type="circle" percent={75} />
|
||||
<Progress type="circle" percent={70} status="exception" />
|
||||
<Progress type="circle" percent={100} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,9 +17,10 @@ By setting `type=dashboard`, you can get a dashboard style of progress easily. M
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress type="dashboard" percent={75} />
|
||||
<Progress type="dashboard" percent={75} gapDegree={30} />
|
||||
</div>
|
||||
, mountNode);
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,8 +17,6 @@ A dynamic progress bar is better.
|
||||
import { Progress, Button } from 'antd';
|
||||
import { MinusOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
const ButtonGroup = Button.Group;
|
||||
|
||||
class App extends React.Component {
|
||||
state = {
|
||||
percent: 0,
|
||||
@ -42,13 +40,13 @@ class App extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Progress percent={this.state.percent} />
|
||||
<ButtonGroup>
|
||||
<Button.Group>
|
||||
<Button onClick={this.decline} icon={<MinusOutlined />} />
|
||||
<Button onClick={this.increase} icon={<PlusOutlined />} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Button.Group>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ You can set a custom text by setting the `format` prop.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress type="circle" percent={75} format={percent => `${percent} Days`} />
|
||||
<Progress type="circle" percent={100} format={() => 'Done'} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,7 +17,7 @@ A package of `linear-gradient`. It is recommended to only pass two colors.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
const Demo = () => (
|
||||
<div>
|
||||
<>
|
||||
<Progress
|
||||
strokeColor={{
|
||||
'0%': '#108ee9',
|
||||
@ -49,7 +49,7 @@ const Demo = () => (
|
||||
}}
|
||||
percent={100}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
ReactDOM.render(<Demo />, mountNode);
|
||||
|
@ -17,13 +17,13 @@ A standard progress bar.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress percent={30} />
|
||||
<Progress percent={50} status="active" />
|
||||
<Progress percent={70} status="exception" />
|
||||
<Progress percent={100} />
|
||||
<Progress percent={50} showInfo={false} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,11 +17,11 @@ By setting `strokeLinecap="square"`, you can change the linecaps from round to s
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Progress strokeLinecap="square" percent={75} />
|
||||
<Progress strokeLinecap="square" type="circle" percent={75} />
|
||||
<Progress strokeLinecap="square" type="dashboard" percent={75} />
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,7 +17,7 @@ A standard progress bar. Doesn't support trail color when `type="circle|dashboar
|
||||
import { Tooltip, Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<>
|
||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||
<Progress percent={60} successPercent={30} />
|
||||
</Tooltip>
|
||||
@ -29,7 +29,7 @@ ReactDOM.render(
|
||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||
<Progress percent={60} successPercent={30} type="dashboard" />
|
||||
</Tooltip>
|
||||
</div>,
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -17,13 +17,13 @@ A progress bar with steps.
|
||||
import { Progress } from 'antd';
|
||||
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Progress percent={50} steps={3} strokeColor="#1890ff" />
|
||||
<>
|
||||
<Progress percent={50} steps={3} />
|
||||
<br />
|
||||
<Progress percent={30} steps={5} strokeColor="#1890ff" />
|
||||
<Progress percent={30} steps={5} />
|
||||
<br />
|
||||
<Progress percent={100} steps={5} size="small" strokeColor="#1890ff" />
|
||||
</div>,
|
||||
<Progress percent={100} steps={5} size="small" strokeColor="#52c41a" />
|
||||
</>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
||||
|
@ -99,6 +99,7 @@ export default class Progress extends React.Component<ProgressProps> {
|
||||
type,
|
||||
steps,
|
||||
showInfo,
|
||||
strokeColor,
|
||||
...restProps
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('progress', customizePrefixCls);
|
||||
@ -108,7 +109,12 @@ export default class Progress extends React.Component<ProgressProps> {
|
||||
// Render progress shape
|
||||
if (type === 'line') {
|
||||
progress = steps ? (
|
||||
<Steps {...this.props} prefixCls={prefixCls} steps={steps}>
|
||||
<Steps
|
||||
{...this.props}
|
||||
strokeColor={typeof strokeColor === 'string' ? strokeColor : undefined}
|
||||
prefixCls={prefixCls}
|
||||
steps={steps}
|
||||
>
|
||||
{progressInfo}
|
||||
</Steps>
|
||||
) : (
|
||||
|
@ -26,6 +26,11 @@
|
||||
min-width: 2px;
|
||||
margin-right: 2px;
|
||||
background: @progress-steps-item-bg;
|
||||
transition: all 0.3s;
|
||||
|
||||
&-active {
|
||||
background: @progress-default-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,16 +35,10 @@ describe('Radio Group', () => {
|
||||
</RadioGroup>,
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('div')
|
||||
.at(0)
|
||||
.simulate('mouseenter');
|
||||
wrapper.find('div').at(0).simulate('mouseenter');
|
||||
expect(onMouseEnter).toHaveBeenCalled();
|
||||
|
||||
wrapper
|
||||
.find('div')
|
||||
.at(0)
|
||||
.simulate('mouseleave');
|
||||
wrapper.find('div').at(0).simulate('mouseleave');
|
||||
expect(onMouseLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -58,15 +52,10 @@ describe('Radio Group', () => {
|
||||
);
|
||||
const radios = wrapper.find('input');
|
||||
|
||||
// uncontrolled component
|
||||
wrapper.setState({ value: 'B' });
|
||||
radios.at(0).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
|
||||
// controlled component
|
||||
wrapper.setProps({ value: 'A' });
|
||||
radios.at(1).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(2);
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('both of radio and radioGroup will trigger onchange event when they exists', () => {
|
||||
@ -88,16 +77,10 @@ describe('Radio Group', () => {
|
||||
);
|
||||
const radios = wrapper.find('input');
|
||||
|
||||
// uncontrolled component
|
||||
wrapper.setState({ value: 'B' });
|
||||
radios.at(0).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
expect(onChangeRadioGroup.mock.calls.length).toBe(1);
|
||||
|
||||
// controlled component
|
||||
wrapper.setProps({ value: 'A' });
|
||||
radios.at(1).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(2);
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('Trigger onChange when both of radioButton and radioGroup exists', () => {
|
||||
@ -112,15 +95,10 @@ describe('Radio Group', () => {
|
||||
);
|
||||
const radios = wrapper.find('input');
|
||||
|
||||
// uncontrolled component
|
||||
wrapper.setState({ value: 'B' });
|
||||
radios.at(0).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
|
||||
// controlled component
|
||||
wrapper.setProps({ value: 'A' });
|
||||
radios.at(1).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(2);
|
||||
expect(onChange.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should only trigger once when in group with options', () => {
|
||||
@ -142,11 +120,6 @@ describe('Radio Group', () => {
|
||||
);
|
||||
const radios = wrapper.find('input');
|
||||
|
||||
// uncontrolled component
|
||||
wrapper.setState({ value: 'B' });
|
||||
radios.at(1).simulate('change');
|
||||
expect(onChange.mock.calls.length).toBe(0);
|
||||
|
||||
// controlled component
|
||||
wrapper.setProps({ value: 'A' });
|
||||
radios.at(0).simulate('change');
|
||||
@ -186,18 +159,23 @@ describe('Radio Group', () => {
|
||||
const wrapper = mount(
|
||||
<RadioGroup defaultValue="bamboo" value={undefined} options={options} />,
|
||||
);
|
||||
|
||||
expect(wrapper.state().value).toEqual('bamboo');
|
||||
expect(wrapper.find('.ant-radio-wrapper').at(0).hasClass('ant-radio-wrapper-checked')).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
[undefined, null].forEach(newValue => {
|
||||
it(`should set value back when value change back to ${newValue}`, () => {
|
||||
const options = [{ label: 'Bamboo', value: 'bamboo' }];
|
||||
const wrapper = mount(<RadioGroup value="bamboo" options={options} />);
|
||||
expect(wrapper.state().value).toEqual('bamboo');
|
||||
|
||||
expect(wrapper.find('.ant-radio-wrapper').at(0).hasClass('ant-radio-wrapper-checked')).toBe(
|
||||
true,
|
||||
);
|
||||
wrapper.setProps({ value: newValue });
|
||||
expect(wrapper.state().value).toEqual(newValue);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-radio-wrapper').at(0).hasClass('ant-radio-wrapper-checked')).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
|
||||
describe('Radio', () => {
|
||||
focusTest(Radio);
|
||||
focusTest(Radio, { refFocus: true });
|
||||
mountTest(Radio);
|
||||
mountTest(Group);
|
||||
mountTest(Button);
|
||||
|
@ -1,107 +1,72 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Radio from './radio';
|
||||
import {
|
||||
RadioGroupProps,
|
||||
RadioGroupState,
|
||||
RadioChangeEvent,
|
||||
RadioGroupButtonStyle,
|
||||
} from './interface';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { RadioGroupProps, RadioChangeEvent, RadioGroupButtonStyle } from './interface';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import SizeContext from '../config-provider/SizeContext';
|
||||
import { RadioGroupContextProvider } from './context';
|
||||
|
||||
function getCheckedValue(children: React.ReactNode) {
|
||||
let value = null;
|
||||
let matched = false;
|
||||
React.Children.forEach(children, (radio: any) => {
|
||||
if (radio && radio.props && radio.props.checked) {
|
||||
value = radio.props.value;
|
||||
matched = true;
|
||||
}
|
||||
});
|
||||
return matched ? { value } : undefined;
|
||||
}
|
||||
const RadioGroup: React.FC<RadioGroupProps> = props => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const size = React.useContext(SizeContext);
|
||||
|
||||
class RadioGroup extends React.PureComponent<RadioGroupProps, RadioGroupState> {
|
||||
static defaultProps = {
|
||||
buttonStyle: 'outline' as RadioGroupButtonStyle,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps: RadioGroupProps, prevState: RadioGroupState) {
|
||||
const newState: Partial<RadioGroupState> = {
|
||||
prevPropValue: nextProps.value,
|
||||
};
|
||||
|
||||
if (nextProps.value !== undefined || prevState.prevPropValue !== nextProps.value) {
|
||||
newState.value = nextProps.value;
|
||||
} else {
|
||||
const checkedValue = getCheckedValue(nextProps.children);
|
||||
if (checkedValue) {
|
||||
newState.value = checkedValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
return newState;
|
||||
let initValue;
|
||||
if (props.value !== undefined) {
|
||||
initValue = props.value;
|
||||
} else if (props.defaultValue !== undefined) {
|
||||
initValue = props.defaultValue;
|
||||
}
|
||||
const [value, setValue] = React.useState(initValue);
|
||||
const [prevPropValue, setPrevPropValue] = React.useState(props.value);
|
||||
|
||||
constructor(props: RadioGroupProps) {
|
||||
super(props);
|
||||
let value;
|
||||
if (props.value !== undefined) {
|
||||
value = props.value;
|
||||
} else if (props.defaultValue !== undefined) {
|
||||
value = props.defaultValue;
|
||||
} else {
|
||||
const checkedValue = getCheckedValue(props.children);
|
||||
value = checkedValue && checkedValue.value;
|
||||
React.useEffect(() => {
|
||||
setPrevPropValue(props.value);
|
||||
if (props.value !== undefined || prevPropValue !== props.value) {
|
||||
setValue(props.value);
|
||||
}
|
||||
this.state = {
|
||||
value,
|
||||
prevPropValue: props.value,
|
||||
};
|
||||
}
|
||||
}, [props.value]);
|
||||
|
||||
onRadioChange = (ev: RadioChangeEvent) => {
|
||||
const lastValue = this.state.value;
|
||||
const { value } = ev.target;
|
||||
if (!('value' in this.props)) {
|
||||
this.setState({
|
||||
value,
|
||||
});
|
||||
const onRadioChange = (ev: RadioChangeEvent) => {
|
||||
const lastValue = value;
|
||||
const val = ev.target.value;
|
||||
if (!('value' in props)) {
|
||||
setValue(val);
|
||||
}
|
||||
|
||||
const { onChange } = this.props;
|
||||
if (onChange && value !== lastValue) {
|
||||
const { onChange } = props;
|
||||
if (onChange && val !== lastValue) {
|
||||
onChange(ev);
|
||||
}
|
||||
};
|
||||
|
||||
renderGroup = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const { props } = this;
|
||||
const renderGroup = () => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className = '',
|
||||
options,
|
||||
buttonStyle,
|
||||
disabled,
|
||||
children,
|
||||
size: customizeSize,
|
||||
style,
|
||||
id,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
const groupPrefixCls = `${prefixCls}-group`;
|
||||
let { children } = props;
|
||||
|
||||
let childrenToRender = children;
|
||||
// 如果存在 options, 优先使用
|
||||
if (options && options.length > 0) {
|
||||
children = options.map(option => {
|
||||
childrenToRender = options.map(option => {
|
||||
if (typeof option === 'string') {
|
||||
// 此处类型自动推导为 string
|
||||
return (
|
||||
<Radio
|
||||
key={option}
|
||||
prefixCls={prefixCls}
|
||||
disabled={this.props.disabled}
|
||||
disabled={disabled}
|
||||
value={option}
|
||||
checked={this.state.value === option}
|
||||
checked={value === option}
|
||||
>
|
||||
{option}
|
||||
</Radio>
|
||||
@ -112,9 +77,9 @@ class RadioGroup extends React.PureComponent<RadioGroupProps, RadioGroupState> {
|
||||
<Radio
|
||||
key={`radio-group-value-options-${option.value}`}
|
||||
prefixCls={prefixCls}
|
||||
disabled={option.disabled || this.props.disabled}
|
||||
disabled={option.disabled || disabled}
|
||||
value={option.value}
|
||||
checked={this.state.value === option.value}
|
||||
checked={value === option.value}
|
||||
style={option.style}
|
||||
>
|
||||
{option.label}
|
||||
@ -123,50 +88,45 @@ class RadioGroup extends React.PureComponent<RadioGroupProps, RadioGroupState> {
|
||||
});
|
||||
}
|
||||
|
||||
const mergedSize = customizeSize || size;
|
||||
const classString = classNames(
|
||||
groupPrefixCls,
|
||||
`${groupPrefixCls}-${buttonStyle}`,
|
||||
{
|
||||
[`${groupPrefixCls}-${mergedSize}`]: mergedSize,
|
||||
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
return (
|
||||
<SizeContext.Consumer>
|
||||
{size => {
|
||||
const mergedSize = customizeSize || size;
|
||||
const classString = classNames(
|
||||
groupPrefixCls,
|
||||
`${groupPrefixCls}-${buttonStyle}`,
|
||||
{
|
||||
[`${groupPrefixCls}-${mergedSize}`]: mergedSize,
|
||||
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classString}
|
||||
style={props.style}
|
||||
onMouseEnter={props.onMouseEnter}
|
||||
onMouseLeave={props.onMouseLeave}
|
||||
id={props.id}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</SizeContext.Consumer>
|
||||
<div
|
||||
className={classString}
|
||||
style={style}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
id={id}
|
||||
>
|
||||
{childrenToRender}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<RadioGroupContextProvider
|
||||
value={{
|
||||
onChange: this.onRadioChange,
|
||||
value: this.state.value,
|
||||
disabled: this.props.disabled,
|
||||
name: this.props.name,
|
||||
}}
|
||||
>
|
||||
<ConfigConsumer>{this.renderGroup}</ConfigConsumer>
|
||||
</RadioGroupContextProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<RadioGroupContextProvider
|
||||
value={{
|
||||
onChange: onRadioChange,
|
||||
value,
|
||||
disabled: props.disabled,
|
||||
name: props.name,
|
||||
}}
|
||||
>
|
||||
{renderGroup()}
|
||||
</RadioGroupContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default RadioGroup;
|
||||
RadioGroup.defaultProps = {
|
||||
buttonStyle: 'outline' as RadioGroupButtonStyle,
|
||||
};
|
||||
|
||||
export default React.memo(RadioGroup);
|
||||
|
@ -18,11 +18,6 @@ export interface RadioGroupProps extends AbstractCheckboxGroupProps {
|
||||
buttonStyle?: RadioGroupButtonStyle;
|
||||
}
|
||||
|
||||
export interface RadioGroupState {
|
||||
value: any;
|
||||
prevPropValue: any;
|
||||
}
|
||||
|
||||
export interface RadioGroupContextProps {
|
||||
onChange: (e: RadioChangeEvent) => void;
|
||||
value: any;
|
||||
|
@ -4,77 +4,68 @@ import classNames from 'classnames';
|
||||
import RadioGroup from './group';
|
||||
import RadioButton from './radioButton';
|
||||
import { RadioProps, RadioChangeEvent } from './interface';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import RadioGroupContext from './context';
|
||||
import { composeRef } from '../_util/ref';
|
||||
|
||||
export default class Radio extends React.PureComponent<RadioProps, {}> {
|
||||
static Group: typeof RadioGroup;
|
||||
|
||||
static Button: typeof RadioButton;
|
||||
|
||||
static defaultProps = {
|
||||
type: 'radio',
|
||||
};
|
||||
|
||||
static contextType = RadioGroupContext;
|
||||
|
||||
private rcCheckbox: any;
|
||||
|
||||
saveCheckbox = (node: any) => {
|
||||
this.rcCheckbox = node;
|
||||
};
|
||||
|
||||
onChange = (e: RadioChangeEvent) => {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(e);
|
||||
}
|
||||
|
||||
if (this.context?.onChange) {
|
||||
this.context.onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
focus() {
|
||||
this.rcCheckbox.focus();
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.rcCheckbox.blur();
|
||||
}
|
||||
|
||||
renderRadio = ({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const { props, context } = this;
|
||||
const { prefixCls: customizePrefixCls, className, children, style, ...restProps } = props;
|
||||
const prefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
const radioProps: RadioProps = { ...restProps };
|
||||
if (context) {
|
||||
radioProps.name = context.name;
|
||||
radioProps.onChange = this.onChange;
|
||||
radioProps.checked = props.value === context.value;
|
||||
radioProps.disabled = props.disabled || context.disabled;
|
||||
}
|
||||
const wrapperClassString = classNames(className, {
|
||||
[`${prefixCls}-wrapper`]: true,
|
||||
[`${prefixCls}-wrapper-checked`]: radioProps.checked,
|
||||
[`${prefixCls}-wrapper-disabled`]: radioProps.disabled,
|
||||
[`${prefixCls}-wrapper-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||
<label
|
||||
className={wrapperClassString}
|
||||
style={style}
|
||||
onMouseEnter={props.onMouseEnter}
|
||||
onMouseLeave={props.onMouseLeave}
|
||||
>
|
||||
<RcCheckbox {...radioProps} prefixCls={prefixCls} ref={this.saveCheckbox} />
|
||||
{children !== undefined ? <span>{children}</span> : null}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderRadio}</ConfigConsumer>;
|
||||
}
|
||||
interface CompoundedComponent
|
||||
extends React.ForwardRefExoticComponent<RadioProps & React.RefAttributes<HTMLElement>> {
|
||||
Group: typeof RadioGroup;
|
||||
Button: typeof RadioButton;
|
||||
}
|
||||
|
||||
const InternalRadio: React.ForwardRefRenderFunction<unknown, RadioProps> = (props, ref) => {
|
||||
const context = React.useContext(RadioGroupContext);
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const innerRef = React.useRef<HTMLElement>();
|
||||
const mergedRef = composeRef(ref, innerRef);
|
||||
|
||||
const onChange = (e: RadioChangeEvent) => {
|
||||
if (props.onChange) {
|
||||
props.onChange(e);
|
||||
}
|
||||
|
||||
if (context?.onChange) {
|
||||
context.onChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
const { prefixCls: customizePrefixCls, className, children, style, ...restProps } = props;
|
||||
const prefixCls = getPrefixCls('radio', customizePrefixCls);
|
||||
const radioProps: RadioProps = { ...restProps };
|
||||
if (context) {
|
||||
radioProps.name = context.name;
|
||||
radioProps.onChange = onChange;
|
||||
radioProps.checked = props.value === context.value;
|
||||
radioProps.disabled = props.disabled || context.disabled;
|
||||
}
|
||||
const wrapperClassString = classNames(className, {
|
||||
[`${prefixCls}-wrapper`]: true,
|
||||
[`${prefixCls}-wrapper-checked`]: radioProps.checked,
|
||||
[`${prefixCls}-wrapper-disabled`]: radioProps.disabled,
|
||||
[`${prefixCls}-wrapper-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||
<label
|
||||
className={wrapperClassString}
|
||||
style={style}
|
||||
onMouseEnter={props.onMouseEnter}
|
||||
onMouseLeave={props.onMouseLeave}
|
||||
>
|
||||
<RcCheckbox {...radioProps} prefixCls={prefixCls} ref={mergedRef as any} />
|
||||
{children !== undefined ? <span>{children}</span> : null}
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
const Radio = React.forwardRef<unknown, RadioProps>(InternalRadio) as CompoundedComponent;
|
||||
Radio.displayName = 'Radio';
|
||||
Radio.Group = RadioGroup;
|
||||
Radio.Button = RadioButton;
|
||||
Radio.defaultProps = {
|
||||
type: 'radio',
|
||||
};
|
||||
|
||||
export default Radio;
|
||||
|
@ -2,27 +2,22 @@ import * as React from 'react';
|
||||
import Radio from './radio';
|
||||
import { RadioChangeEvent } from './interface';
|
||||
import { AbstractCheckboxProps } from '../checkbox/Checkbox';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import RadioGroupContext from './context';
|
||||
|
||||
export type RadioButtonProps = AbstractCheckboxProps<RadioChangeEvent>;
|
||||
|
||||
const RadioButton = (props: RadioButtonProps, ref: React.Ref<any>) => {
|
||||
const radioGroupContext = React.useContext(RadioGroupContext);
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
|
||||
return (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls }: ConfigConsumerProps) => {
|
||||
const { prefixCls: customizePrefixCls, ...radioProps }: RadioButtonProps = props;
|
||||
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
|
||||
if (radioGroupContext) {
|
||||
radioProps.checked = props.value === radioGroupContext.value;
|
||||
radioProps.disabled = props.disabled || radioGroupContext.disabled;
|
||||
}
|
||||
return <Radio prefixCls={prefixCls} {...radioProps} type="radio" ref={ref} />;
|
||||
}}
|
||||
</ConfigConsumer>
|
||||
);
|
||||
const { prefixCls: customizePrefixCls, ...radioProps } = props;
|
||||
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
|
||||
if (radioGroupContext) {
|
||||
radioProps.checked = props.value === radioGroupContext.value;
|
||||
radioProps.disabled = props.disabled || radioGroupContext.disabled;
|
||||
}
|
||||
return <Radio prefixCls={prefixCls} {...radioProps} type="radio" ref={ref} />;
|
||||
};
|
||||
|
||||
export default React.forwardRef(RadioButton);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user