mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 09:26:06 +08:00
merge master
This commit is contained in:
commit
3d8a4f3612
@ -44,6 +44,9 @@ references:
|
||||
- test_node:
|
||||
requires:
|
||||
- setup
|
||||
- check_metadata:
|
||||
requires:
|
||||
- setup
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
@ -72,6 +75,7 @@ jobs:
|
||||
- *attach_workspace
|
||||
- run: npm run dist
|
||||
- run: node ./tests/dekko/dist.test.js
|
||||
- run: npm run bundlesize
|
||||
- persist_to_workspace:
|
||||
root: ~/ant-design
|
||||
paths:
|
||||
@ -147,6 +151,13 @@ jobs:
|
||||
- *attach_workspace
|
||||
- run: npm run test-node -- -w 1
|
||||
|
||||
check_metadata:
|
||||
<<: *container_config
|
||||
steps:
|
||||
- checkout
|
||||
- *attach_workspace
|
||||
- run: node ./scripts/check-demo.js
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build_test:
|
||||
|
@ -7,3 +7,10 @@ components/*/__tests__/type.tsx
|
||||
# Docs templates
|
||||
site/theme/template/IconDisplay/*.js
|
||||
site/theme/template/IconDisplay/*.jsx
|
||||
typings
|
||||
es/**/*
|
||||
lib/**/*
|
||||
node_modules
|
||||
_site
|
||||
dist
|
||||
**/*.d.ts
|
||||
|
18
.eslintrc.js
18
.eslintrc.js
@ -16,7 +16,7 @@ const eslintrc = {
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
version: '16.8',
|
||||
version: '16.9',
|
||||
},
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
@ -24,13 +24,14 @@ const eslintrc = {
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.tsx'],
|
||||
files: ['*.ts', '*.tsx'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': [2, { args: 'none' }],
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
camelcase: 0,
|
||||
'react/jsx-one-expression-per-line': 0,
|
||||
'react/prop-types': 0,
|
||||
'react/forbid-prop-types': 0,
|
||||
@ -56,6 +57,8 @@ const eslintrc = {
|
||||
'jsx-a11y/anchor-is-valid': 0,
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'react/jsx-filename-extension': 0,
|
||||
'react/state-in-constructor': 0,
|
||||
'react/jsx-props-no-spreading': 0,
|
||||
'prefer-destructuring': 0, // TODO: remove later
|
||||
'consistent-return': 0, // TODO: remove later
|
||||
'no-return-assign': 0, // TODO: remove later
|
||||
@ -78,15 +81,20 @@ const eslintrc = {
|
||||
'react/display-name': 0,
|
||||
// ban this for Number.isNaN needs polyfill
|
||||
'no-restricted-globals': 0,
|
||||
'max-classes-per-file': 0,
|
||||
'react/static-property-placement': 0,
|
||||
},
|
||||
globals: {
|
||||
gtag: true,
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.RUN_ENV === 'DEMO') {
|
||||
eslintrc.globals = {
|
||||
eslintrc.globals = Object.assign(eslintrc.globals, {
|
||||
React: true,
|
||||
ReactDOM: true,
|
||||
mountNode: true,
|
||||
};
|
||||
});
|
||||
|
||||
Object.assign(eslintrc.rules, {
|
||||
indent: 0,
|
||||
@ -100,6 +108,8 @@ if (process.env.RUN_ENV === 'DEMO') {
|
||||
'react/no-multi-comp': 0,
|
||||
'jsx-a11y/href-no-hash': 0,
|
||||
'import/no-extraneous-dependencies': 0,
|
||||
'import/no-unresolved': 0,
|
||||
'jsx-a11y/control-has-associated-label': 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
14
.github/main.workflow
vendored
14
.github/main.workflow
vendored
@ -1,14 +0,0 @@
|
||||
workflow "Deploy website" {
|
||||
on = "release"
|
||||
resolves = ["Deploy"]
|
||||
}
|
||||
|
||||
action "Deploy" {
|
||||
uses = "docker://node:10"
|
||||
runs = [
|
||||
"sh",
|
||||
"-c",
|
||||
"git remote set-url origin https://${DEPLOY_TOKEN}@github.com/ant-design/ant-design.git && npm install && npm run deploy"
|
||||
],
|
||||
secrets = ["DEPLOY_TOKEN"]
|
||||
}
|
19
.github/workflows/deploy-site.yml
vendored
Normal file
19
.github/workflows/deploy-site.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Deploy website
|
||||
on:
|
||||
release:
|
||||
branches:
|
||||
- master
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: Deploy website
|
||||
uses: JamesIves/github-pages-deploy-action@master
|
||||
env:
|
||||
ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||
BRANCH: gh-pages
|
||||
FOLDER: _site
|
||||
BUILD_SCRIPT: npm install && npm run predeploy
|
19
.github/workflows/nodejs.yml
vendored
Normal file
19
.github/workflows/nodejs.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Node CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Use Node.js 10.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
version: 10.x
|
||||
- name: npm install, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm run test-all
|
@ -15,6 +15,63 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 3.22.2
|
||||
|
||||
`2019-08-27`
|
||||
|
||||
- 🐞 Fix Mentions has additional height in Form. [#18478](https://github.com/ant-design/ant-design/pull/18478)
|
||||
- 🐞 Fix disabled Input should not be allowed to clear. [#18482](https://github.com/ant-design/ant-design/pull/18482)
|
||||
- 🐞 Fix Input.Password crash with `Cannot read property 'input' of null` when unmount. [#18475](https://github.com/ant-design/ant-design/pull/18475)
|
||||
- 🐞 Fix Table `style` should applied to outside wrapper. [#18494](https://github.com/ant-design/ant-design/pull/18494)
|
||||
- 🐞 Fix PageHeader default english text. [#18471](https://github.com/ant-design/ant-design/pull/18471) [@hjiawei](https://github.com/hjiawei)
|
||||
|
||||
## 3.22.1
|
||||
|
||||
`2019-08-26`
|
||||
|
||||
- 🔥 The official website now supports the search icon through the picture! [#18425](https://github.com/ant-design/ant-design/pull/18425)
|
||||
- 💄 Tweak Table expand icon style. [c5344bd](https://github.com/ant-design/ant-design/commit/c5344bde529a2f2ec814f46e7ec5d249eac8d608)
|
||||
- 🐞 Fix prop `style` is getting duplicated on Table. [#18330](https://github.com/ant-design/ant-design/pull/18330) [@MrHeer](https://github.com/MrHeer)
|
||||
- 🐞 Fix Input line height style bug in IE11. [#17759](https://github.com/ant-design/ant-design/pull/17759)
|
||||
- 🐞 Fix Steps progressDot broken style. [#18356](https://github.com/ant-design/ant-design/pull/18356)
|
||||
- 🐞 Fix an issue with plain icon button style errors. [#18458](https://github.com/ant-design/ant-design/pull/18458) [@qhanw](https://github.com/qhanw)
|
||||
- 🐞 Fix TextArea with `autosize` in controlled mode that scrollbar blink when typing. [#18401](https://github.com/ant-design/ant-design/pull/18401)
|
||||
- 🐞 Fixed an issue where Input.Password `ref` could not get the input element and had no `focus` and `blur` method. [#18441](https://github.com/ant-design/ant-design/pull/18441)
|
||||
- 🐞 Fix Upload wrong line break. [#18423](https://github.com/ant-design/ant-design/pull/18423)
|
||||
- 💄 Add less variables `@select-dropdown-bg` `@select-item-selected-bg` `@select-item-active-bg` `@anchor-border-colorr` `@descriptions-bg`. [#18444](https://github.com/ant-design/ant-design/pull/18444) [#18372](https://github.com/ant-design/ant-design/pull/18440) [@MrHeer](https://github.com/MrHeer)
|
||||
|
||||
## 3.22.0
|
||||
|
||||
`2019-08-17`
|
||||
|
||||
- 🔥 New type `navigation` of Step. [#17994](https://github.com/ant-design/ant-design/pull/17994)
|
||||
- <img width="600" class="markdown-inline-image" src="https://gw.alipayobjects.com/zos/antfincdn/oc7rRuPBbR/421d7885-a822-4375-9deb-92d607e0d9de.png" />
|
||||
- 🇷🇴 Add Romanian locale. [#18163](https://github.com/ant-design/ant-design/pull/18163) [@stefy](https://github.com/stefy)
|
||||
- Anchor
|
||||
- 🌟 Add `getCurrentAnchor` property to specify current active anchor. [#17823](https://github.com/ant-design/ant-design/pull/17823) [@shaodahong](https://github.com/shaodahong)
|
||||
- 🌟 Add `targetOffset` property to customize scroll position offset. [#17827](https://github.com/ant-design/ant-design/pull/17827) [@shaodahong](https://github.com/shaodahong)
|
||||
- 🌟 Drawer supports popup in custom dom node. [#18167](https://github.com/ant-design/ant-design/pull/18167)
|
||||
- 🌟 Mentions support `getPopupContainer` property. [#18298](https://github.com/ant-design/ant-design/pull/18298) [@vijayst](https://github.com/vijayst)
|
||||
- 🌟 Modal support custom `closeIcon`. [#18309](https://github.com/ant-design/ant-design/pull/18309)
|
||||
- 🌟 Upload support to preview `jfif` format images. [#18322](https://github.com/ant-design/ant-design/pull/18322)
|
||||
- 💄 Tweak Descriptions.Item padding bottom via size. [#18270](https://github.com/ant-design/ant-design/pull/18270)
|
||||
- Cascader
|
||||
- 🌟 Allow input `autoComplete` to be overrided. [#18279](https://github.com/ant-design/ant-design/pull/18279) [@zomars](https://github.com/zomars)
|
||||
- 🐞 Fix wrong `notFoundContent` width when using `fieldNames`.[#18325](https://github.com/ant-design/ant-design/pull/18325)
|
||||
- 🐞 Fix missing `options` cause crash. [#18190](https://github.com/ant-design/ant-design/pull/18190) [@nnecec](https://github.com/nnecec)
|
||||
- 🐞 Fix Menu.SubMenu `className` applied to popup menu mistakenly. [#18290](https://github.com/ant-design/ant-design/pull/18290)
|
||||
- 🐞 Upgrade react-slick to fix Carousel lifecycle warning. [#18209](https://github.com/ant-design/ant-design/pull/18209)
|
||||
- 🐞 Fix Button `received false for a non-boolean attribute loading` warning. [#18208](https://github.com/ant-design/ant-design/pull/18208)
|
||||
- 🐞 Fix style problem when hovering Table selected row. [#18261](https://github.com/ant-design/ant-design/pull/18261)
|
||||
- 🐞 Fix Checkbox hovering border color when it is `disabled`. [#18168](https://github.com/ant-design/ant-design/pull/18168)
|
||||
- 🐞 Fix Progress missing or messed gradient color. [#18284](https://github.com/ant-design/ant-design/pull/18284)
|
||||
- 🐞 修复 TextArea scrollbar blinking problem when using `autosize` and `maxRows`. [#18289](https://github.com/ant-design/ant-design/pull/18289)
|
||||
- TypeScript
|
||||
- 🐞 Fix some components (Tooltip, Breadcrumb, Badge) importing error. [#18282](https://github.com/ant-design/ant-design/pull/18282) [@lidianhao123](https://github.com/lidianhao123)
|
||||
- 🐞 Fix MonthPicker `monthCellContentRender` property definition. [#18192](https://github.com/ant-design/ant-design/pull/18192) [@JonathanLee-LX](https://github.com/JonathanLee-LX)
|
||||
- 🐞 Fix Upload.Dragger `children` error. [#18196](https://github.com/ant-design/ant-design/pull/18196)
|
||||
- 🐞 Fix Tag.CheckableTag `style` property definition. [#18300](https://github.com/ant-design/ant-design/pull/18300)
|
||||
|
||||
## 3.21.4
|
||||
|
||||
`2019-08-09`
|
||||
@ -985,7 +1042,6 @@ timeline: true
|
||||
- 🐞 Fixed Table `Cannot read property 'children' of undefined` error when customize `column.title` as ReactNode. [#13542](https://github.com/ant-design/ant-design/issues/13542) [@geraldchen890806](https://github.com/geraldchen890806)
|
||||
- 🐞 Fixed another border problem of Button when customized less variable `@border-width-base`. [#13534](https://github.com/ant-design/ant-design/issues/13534) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 Fixed Upload don't support resolve `Blob` object when `beforeUpload` returns a Promise. [#13528](https://github.com/ant-design/ant-design/pull/13528/) [@huanz](https://github.com/huanz)
|
||||
- https://github.com/ant-design/ant-design/pull/13536
|
||||
- 🐞 Fixed two props of Dropdown TypeScript definitions. [#13536](https://github.com/ant-design/ant-design/pull/13536) [@wangxingkang](https://github.com/wangxingkang)
|
||||
|
||||
## 3.11.1
|
||||
|
@ -15,6 +15,63 @@ timeline: true
|
||||
|
||||
---
|
||||
|
||||
## 3.22.2
|
||||
|
||||
`2019-08-27`
|
||||
|
||||
- 🐞 修复 Mentions 在 Form 中高度略高的问题。[#18478](https://github.com/ant-design/ant-design/pull/18478)
|
||||
- 🐞 修复失效 Input 依然支持 allowClear 的问题。[#18482](https://github.com/ant-design/ant-design/pull/18482)
|
||||
- 🐞 修复 Input.Password unmount 时报错 `Cannot read property 'input' of null`。[#18475](https://github.com/ant-design/ant-design/pull/18475)
|
||||
- 🐞 修正 Table `style` 属性到最外层容器。[#18494](https://github.com/ant-design/ant-design/pull/18494)
|
||||
- 🐞 修正 PageHeader 默认英文文案。[#18471](https://github.com/ant-design/ant-design/pull/18471) [@hjiawei](https://github.com/hjiawei)
|
||||
|
||||
## 3.22.1
|
||||
|
||||
`2019-08-26`
|
||||
|
||||
- 🔥 官网现在支持通过图片搜索图标啦
|
||||
- 💄 调整 Table 展开按钮的样式。[c5344bd](https://github.com/ant-design/ant-design/commit/c5344bde529a2f2ec814f46e7ec5d249eac8d608)
|
||||
- 🐞 修复 Table 的 `style` 属性被应用了两次的问题。[#18330](https://github.com/ant-design/ant-design/pull/18330) [@MrHeer](https://github.com/MrHeer)
|
||||
- 🐞 修复 Input 在 IE11 下错位的问题。[#17759](https://github.com/ant-design/ant-design/pull/17759)
|
||||
- 🐞 修复 Input.Password `ref` 获取不到 input 元素且没有 `focus` 和 `blur` 方法的问题。[#18441](https://github.com/ant-design/ant-design/pull/18441)
|
||||
- 🐞 修复 Steps `progressDot` 样式错位问题。[#18356](https://github.com/ant-design/ant-design/pull/18356)
|
||||
- 🐞 修复纯图标按钮样式错误的问题。[#18458](https://github.com/ant-design/ant-design/pull/18458) [@qhanw](https://github.com/qhanw)
|
||||
- 🐞 修复 TextArea 受控模式下配置 `autosize` 时,输入会导致滚动条闪烁的问题。[#18401](https://github.com/ant-design/ant-design/pull/18401)
|
||||
- 🐞 修复 Upload 错误换行的问题。[#18423](https://github.com/ant-design/ant-design/pull/18423)
|
||||
- 💄 增加 less 变量 `@select-dropdown-bg` `@select-item-selected-bg` `@select-item-active-bg` `@anchor-border-colorr` `@descriptions-bg`。[#18444](https://github.com/ant-design/ant-design/pull/18444) [#18372](https://github.com/ant-design/ant-design/pull/18440) [@MrHeer](https://github.com/MrHeer)
|
||||
|
||||
## 3.22.0
|
||||
|
||||
`2019-08-17`
|
||||
|
||||
- 🔥 新增 Steps `type="navigation"` 导航步骤条。[#17994](https://github.com/ant-design/ant-design/pull/17994)
|
||||
- <img width="600" class="markdown-inline-image" src="https://gw.alipayobjects.com/zos/antfincdn/oc7rRuPBbR/421d7885-a822-4375-9deb-92d607e0d9de.png" />
|
||||
- 🇷🇴 新增罗马尼亚语。[#18163](https://github.com/ant-design/ant-design/pull/18163) [@stefy](https://github.com/stefy)
|
||||
- Anchor
|
||||
- 🌟 新增 `getCurrentAnchor` 属性用于指定当前高亮锚点。[#17823](https://github.com/ant-design/ant-design/pull/17823) [@shaodahong](https://github.com/shaodahong)
|
||||
- 🌟 新增 `targetOffset` 属性用于自定义滚动偏移量。[#17827](https://github.com/ant-design/ant-design/pull/17827) [@shaodahong](https://github.com/shaodahong)
|
||||
- 🌟 支持 Drawer 在局部节点弹出。[#18167](https://github.com/ant-design/ant-design/pull/18167)
|
||||
- 🌟 Mentions 新增 `getPopupContainer` 属性。[#18298](https://github.com/ant-design/ant-design/pull/18298) [@vijayst](https://github.com/vijayst)
|
||||
- 🌟 Modal 支持 `closeIcon` 属性用于自定义关闭图标。[#18309](https://github.com/ant-design/ant-design/pull/18309)
|
||||
- 🌟 Upload 支持预览 `jfif` 格式图片。[#18322](https://github.com/ant-design/ant-design/pull/18322)
|
||||
- 💄 调整不同大小下 Descriptions.Item 内边距样式。 [#18270](https://github.com/ant-design/ant-design/pull/18270)
|
||||
- Cascader
|
||||
- 🌟 允许自定义输入框的 `autoComplete` 属性可以被覆盖。[#18279](https://github.com/ant-design/ant-design/pull/18279) [@zomars](https://github.com/zomars)
|
||||
- 🐞 修复指定 `fieldNames` 时空数据弹层宽度问题。[#18325](https://github.com/ant-design/ant-design/pull/18325)
|
||||
- 🐞 修复 `options` 参数未传入数组类型导致页面崩溃。[#18190](https://github.com/ant-design/ant-design/pull/18190) [@nnecec](https://github.com/nnecec)
|
||||
- 🐞 修复 Menu.SubMenu `className` 错误应用到弹层上的问题。[#18290](https://github.com/ant-design/ant-design/pull/18290)
|
||||
- 🐞 升级 react-slick 以修复 Carousel 的生命周期警告问题。[#18209](https://github.com/ant-design/ant-design/pull/18209)
|
||||
- 🐞 修复 Button `received false for a non-boolean attribute loading` 警告信息。[#18208](https://github.com/ant-design/ant-design/pull/18208)
|
||||
- 🐞 修复 Table 选中行 hover 背景样式问题。[#18261](https://github.com/ant-design/ant-design/pull/18261)
|
||||
- 🐞 修复 Checkbox 失效时的 hover 边框颜色。[#18168](https://github.com/ant-design/ant-design/pull/18168)
|
||||
- 🐞 修复 Progress 渐变色混乱和失效的问题。[#18284](https://github.com/ant-design/ant-design/pull/18284)
|
||||
- 🐞 修复 TextArea `autosize` 内使用 `maxRows` 时滚动条闪烁的问题。[#18289](https://github.com/ant-design/ant-design/pull/18289)
|
||||
- TypeScript
|
||||
- 🐞 修复部分组件(Tooltip、Breadcrumb、Badge)无法引入的问题。[#18282](https://github.com/ant-design/ant-design/pull/18282) [@lidianhao123](https://github.com/lidianhao123)
|
||||
- 🐞 修复 MonthPicker `monthCellContentRender` 属性。[#18192](https://github.com/ant-design/ant-design/pull/18192) [@JonathanLee-LX](https://github.com/JonathanLee-LX)
|
||||
- 🐞 修复 Upload.Dragger `children` 报错的问题。[#18196](https://github.com/ant-design/ant-design/pull/18196)
|
||||
- 🐞 修复 Tag.CheckableTag 的 `style` 属性定义。[#18300](https://github.com/ant-design/ant-design/pull/18300)
|
||||
|
||||
## 3.21.4
|
||||
|
||||
`2019-08-09`
|
||||
@ -982,7 +1039,6 @@ timeline: true
|
||||
- 🐞 修复 Table 使用自定义列头时报 `Cannot read property 'children' of undefined` 的问题。[#13542](https://github.com/ant-design/ant-design/issues/13542) [@geraldchen890806](https://github.com/geraldchen890806)
|
||||
- 🐞 修复另一个 Input 在自定义了 less 变量 `@border-width-base` 时的边框问题。[#13534](https://github.com/ant-design/ant-design/pull/13534) [@morenyang](https://github.com/morenyang)
|
||||
- 🐞 修复 Upload 的 `beforeUpload` 方法返回 Promise 时不支持 resolve `Blob` 对象的问题。[#13528](https://github.com/ant-design/ant-design/pull/13528/) [@huanz](https://github.com/huanz)
|
||||
- https://github.com/ant-design/ant-design/pull/13536
|
||||
- 🐞 修复 Dropdown 两个属性的 TypeScript 定义。[#13536](https://github.com/ant-design/ant-design/pull/13536) [@wangxingkang](https://github.com/wangxingkang)
|
||||
|
||||
## 3.11.1
|
||||
|
@ -1,10 +1,12 @@
|
||||
const __NULL__ = { notExist: true };
|
||||
|
||||
export function spyElementPrototypes(Element, properties) {
|
||||
const propNames = Object.keys(properties);
|
||||
const originDescriptors = {};
|
||||
|
||||
propNames.forEach(propName => {
|
||||
const originDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, propName);
|
||||
originDescriptors[propName] = originDescriptor;
|
||||
originDescriptors[propName] = originDescriptor || __NULL__;
|
||||
|
||||
const spyProp = properties[propName];
|
||||
|
||||
@ -37,7 +39,9 @@ export function spyElementPrototypes(Element, properties) {
|
||||
mockRestore() {
|
||||
propNames.forEach(propName => {
|
||||
const originDescriptor = originDescriptors[propName];
|
||||
if (typeof originDescriptor === 'function') {
|
||||
if (originDescriptor === __NULL__) {
|
||||
delete Element.prototype[propName];
|
||||
} else if (typeof originDescriptor === 'function') {
|
||||
Element.prototype[propName] = originDescriptor;
|
||||
} else {
|
||||
Object.defineProperty(Element.prototype, propName, originDescriptor);
|
||||
|
13
components/_util/__tests__/easings.test.js
Normal file
13
components/_util/__tests__/easings.test.js
Normal file
@ -0,0 +1,13 @@
|
||||
import { easeInOutCubic } from '../easings';
|
||||
|
||||
describe('Test easings', () => {
|
||||
it('easeInOutCubic return value', () => {
|
||||
const nums = [];
|
||||
// eslint-disable-next-line no-plusplus
|
||||
for (let index = 0; index < 5; index++) {
|
||||
nums.push(easeInOutCubic(index, 1, 5, 4));
|
||||
}
|
||||
|
||||
expect(nums).toEqual([1, 1.25, 3, 4.75, 5]);
|
||||
});
|
||||
});
|
56
components/_util/__tests__/scrollTo.test.js
Normal file
56
components/_util/__tests__/scrollTo.test.js
Normal file
@ -0,0 +1,56 @@
|
||||
import scrollTo from '../scrollTo';
|
||||
|
||||
describe('Test ScrollTo function', () => {
|
||||
let dateNowMock;
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
dateNowMock = jest
|
||||
.spyOn(Date, 'now')
|
||||
.mockImplementationOnce(() => 0)
|
||||
.mockImplementationOnce(() => 1000);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
dateNowMock.mockRestore();
|
||||
});
|
||||
|
||||
it('test scrollTo', async () => {
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => {
|
||||
window.scrollY = y;
|
||||
window.pageYOffset = y;
|
||||
});
|
||||
|
||||
scrollTo(1000);
|
||||
|
||||
jest.runAllTimers();
|
||||
expect(window.pageYOffset).toBe(1000);
|
||||
|
||||
scrollToSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('test callback - option', async () => {
|
||||
const cbMock = jest.fn();
|
||||
scrollTo(1000, {
|
||||
callback: cbMock,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect(cbMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('test getContainer - option', async () => {
|
||||
const div = document.createElement('div');
|
||||
scrollTo(1000, {
|
||||
getContainer: () => div,
|
||||
});
|
||||
jest.runAllTimers();
|
||||
expect(div.scrollTop).toBe(1000);
|
||||
});
|
||||
});
|
@ -9,6 +9,8 @@ import triggerEvent from '../triggerEvent';
|
||||
import Wave from '../wave';
|
||||
import TransButton from '../transButton';
|
||||
import openAnimation from '../openAnimation';
|
||||
import ResizeObserver from '../resizeObserver';
|
||||
import { spyElementPrototype } from '../../__tests__/util/domHook';
|
||||
|
||||
describe('Test utils function', () => {
|
||||
beforeAll(() => {
|
||||
@ -143,7 +145,9 @@ describe('Test utils function', () => {
|
||||
it('bindAnimationEvent should return when node is null', () => {
|
||||
const wrapper = mount(
|
||||
<Wave>
|
||||
<button type="button" disabled />
|
||||
<button type="button" disabled>
|
||||
button
|
||||
</button>
|
||||
</Wave>,
|
||||
).instance();
|
||||
expect(wrapper.bindAnimationEvent()).toBe(undefined);
|
||||
@ -152,7 +156,9 @@ describe('Test utils function', () => {
|
||||
it('bindAnimationEvent.onClick should return when children is hidden', () => {
|
||||
const wrapper = mount(
|
||||
<Wave>
|
||||
<button type="button" style={{ display: 'none' }} />
|
||||
<button type="button" style={{ display: 'none' }}>
|
||||
button
|
||||
</button>
|
||||
</Wave>,
|
||||
).instance();
|
||||
expect(wrapper.bindAnimationEvent()).toBe(undefined);
|
||||
@ -217,4 +223,47 @@ describe('Test utils function', () => {
|
||||
expect(done).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ResizeObserver', () => {
|
||||
let domMock;
|
||||
|
||||
beforeAll(() => {
|
||||
domMock = spyElementPrototype(HTMLDivElement, 'getBoundingClientRect', () => {
|
||||
return {
|
||||
width: 1128 + Math.random(),
|
||||
height: 903 + Math.random(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
domMock.mockRestore();
|
||||
});
|
||||
|
||||
it('should not trigger `onResize` if size shaking', () => {
|
||||
const onResize = jest.fn();
|
||||
let divNode;
|
||||
|
||||
const wrapper = mount(
|
||||
<ResizeObserver onResize={onResize}>
|
||||
<div
|
||||
ref={node => {
|
||||
divNode = node;
|
||||
}}
|
||||
/>
|
||||
</ResizeObserver>,
|
||||
);
|
||||
|
||||
// First trigger
|
||||
wrapper.instance().onResize([{ target: divNode }]);
|
||||
onResize.mockReset();
|
||||
|
||||
// Repeat trigger should not trigger outer `onResize` with shaking
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
wrapper.instance().onResize([{ target: divNode }]);
|
||||
}
|
||||
|
||||
expect(onResize).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { tuple } from './type';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const PresetColorTypes = tuple(
|
||||
'pink',
|
||||
'red',
|
||||
|
9
components/_util/easings.ts
Normal file
9
components/_util/easings.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function easeInOutCubic(t: number, b: number, c: number, d: number) {
|
||||
const cc = c - b;
|
||||
t /= d / 2;
|
||||
if (t < 1) {
|
||||
return (cc / 2) * t * t * t + b;
|
||||
}
|
||||
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
|
||||
}
|
@ -28,7 +28,7 @@ export default function wrapperRaf(callback: () => void, delayFrames: number = 1
|
||||
return myId;
|
||||
}
|
||||
|
||||
wrapperRaf.cancel = function(pid?: number) {
|
||||
wrapperRaf.cancel = function cancel(pid?: number) {
|
||||
if (pid === undefined) return;
|
||||
|
||||
raf.cancel(ids[pid]);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function cloneElement(element: React.ReactNode, ...restArgs: any[]) {
|
||||
if (!React.isValidElement(element)) return element;
|
||||
|
||||
|
@ -10,9 +10,19 @@ interface ResizeObserverProps {
|
||||
onResize?: () => void;
|
||||
}
|
||||
|
||||
class ReactResizeObserver extends React.Component<ResizeObserverProps, {}> {
|
||||
interface ResizeObserverState {
|
||||
height: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
class ReactResizeObserver extends React.Component<ResizeObserverProps, ResizeObserverState> {
|
||||
resizeObserver: ResizeObserver | null = null;
|
||||
|
||||
state = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.onComponentUpdated();
|
||||
}
|
||||
@ -38,10 +48,30 @@ class ReactResizeObserver extends React.Component<ResizeObserverProps, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
onResize = () => {
|
||||
onResize: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => {
|
||||
const { onResize } = this.props;
|
||||
if (onResize) {
|
||||
onResize();
|
||||
|
||||
const { target } = entries[0];
|
||||
|
||||
const { width, height } = target.getBoundingClientRect();
|
||||
|
||||
/**
|
||||
* Resize observer trigger when content size changed.
|
||||
* In most case we just care about element size,
|
||||
* let's use `boundary` instead of `contentRect` here to avoid shaking.
|
||||
*/
|
||||
const fixedWidth = Math.floor(width);
|
||||
const fixedHeight = Math.floor(height);
|
||||
|
||||
if (this.state.width !== fixedWidth || this.state.height !== fixedHeight) {
|
||||
this.setState({
|
||||
width: fixedWidth,
|
||||
height: fixedHeight,
|
||||
});
|
||||
|
||||
if (onResize) {
|
||||
onResize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ if (typeof window !== 'undefined') {
|
||||
};
|
||||
};
|
||||
window.matchMedia = window.matchMedia || matchMediaPolyfill;
|
||||
// eslint-disable-next-line global-require
|
||||
enquire = require('enquire.js');
|
||||
}
|
||||
|
||||
@ -57,8 +58,8 @@ const responsiveObserve = {
|
||||
}
|
||||
const token = (++subUid).toString();
|
||||
subscribers.push({
|
||||
token: token,
|
||||
func: func,
|
||||
token,
|
||||
func,
|
||||
});
|
||||
func(screens);
|
||||
return token;
|
||||
|
37
components/_util/scrollTo.ts
Normal file
37
components/_util/scrollTo.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import raf from 'raf';
|
||||
import getScroll from './getScroll';
|
||||
import { easeInOutCubic } from './easings';
|
||||
|
||||
interface ScrollToOptions {
|
||||
/** Scroll container, default as window */
|
||||
getContainer?: () => HTMLElement | Window;
|
||||
/** Scroll end callback */
|
||||
callback?: () => any;
|
||||
/** Animation duration, default as 450 */
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||
const { getContainer = () => window, callback, duration = 450 } = options;
|
||||
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const startTime = Date.now();
|
||||
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
|
||||
if (container === window) {
|
||||
window.scrollTo(window.pageXOffset, nextScrollTop);
|
||||
} else {
|
||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||
}
|
||||
if (time < duration) {
|
||||
raf(frameFunc);
|
||||
} else if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
function isStyleSupport(styleName: string | Array<string>): boolean {
|
||||
const isStyleSupport = (styleName: string | Array<string>): boolean => {
|
||||
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
|
||||
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
|
||||
const { documentElement } = window.document;
|
||||
@ -6,7 +6,7 @@ function isStyleSupport(styleName: string | Array<string>): boolean {
|
||||
return styleNameList.some(name => name in documentElement.style);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);
|
||||
|
||||
|
@ -20,6 +20,7 @@ export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
|
||||
}
|
||||
|
||||
export function throttleByAnimationFrameDecorator() {
|
||||
// eslint-disable-next-line func-names
|
||||
return function(target: any, key: string, descriptor: any) {
|
||||
const fn = descriptor.value;
|
||||
let definingProperty = false;
|
||||
|
7
components/_util/warning.ts
Normal file
7
components/_util/warning.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import warning, { resetWarned } from 'rc-util/lib/warning';
|
||||
|
||||
export { resetWarned };
|
||||
|
||||
export default (valid: boolean, component: string, message: string): void => {
|
||||
warning(valid, `[antd: ${component}] ${message}`);
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
import warning from 'warning';
|
||||
|
||||
let warned: Record<string, boolean> = {};
|
||||
|
||||
export function resetWarned() {
|
||||
warned = {};
|
||||
}
|
||||
|
||||
export default (valid: boolean, component: string, message: string): void => {
|
||||
if (!valid && !warned[message]) {
|
||||
warning(false, `[antd: ${component}] ${message}`);
|
||||
warned[message] = true;
|
||||
}
|
||||
};
|
@ -3,6 +3,7 @@ import { mount } from 'enzyme';
|
||||
import Affix from '..';
|
||||
import { getObserverEntities } from '../utils';
|
||||
import Button from '../../button';
|
||||
import { spyElementPrototype } from '../../__tests__/util/domHook';
|
||||
|
||||
const events = {};
|
||||
|
||||
@ -40,6 +41,7 @@ class AffixMounter extends React.Component {
|
||||
|
||||
describe('Affix Render', () => {
|
||||
let wrapper;
|
||||
let domMock;
|
||||
|
||||
const classRect = {
|
||||
container: {
|
||||
@ -48,23 +50,21 @@ describe('Affix Render', () => {
|
||||
},
|
||||
};
|
||||
|
||||
const originGetBoundingClientRect = HTMLElement.prototype.getBoundingClientRect;
|
||||
HTMLElement.prototype.getBoundingClientRect = function getBoundingClientRect() {
|
||||
return (
|
||||
classRect[this.className] || {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
domMock = spyElementPrototype(HTMLElement, 'getBoundingClientRect', function mockBounding() {
|
||||
return (
|
||||
classRect[this.className] || {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
HTMLElement.prototype.getBoundingClientRect = originGetBoundingClientRect;
|
||||
domMock.mockRestore();
|
||||
});
|
||||
const movePlaceholder = top => {
|
||||
classRect.fixed = {
|
||||
@ -185,7 +185,7 @@ describe('Affix Render', () => {
|
||||
.find('ReactResizeObserver')
|
||||
.at(index)
|
||||
.instance()
|
||||
.onResize();
|
||||
.onResize([{ target: { getBoundingClientRect: () => ({ width: 99, height: 99 }) } }]);
|
||||
jest.runAllTimers();
|
||||
|
||||
expect(updateCalled).toHaveBeenCalled();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import Affix from './';
|
||||
import Affix from '.';
|
||||
|
||||
export type BindElement = HTMLElement | Window | null | undefined;
|
||||
export type Rect = ClientRect | DOMRect;
|
||||
|
@ -3,10 +3,10 @@ import * as ReactDOM from 'react-dom';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import raf from 'raf';
|
||||
import Affix from '../affix';
|
||||
import AnchorLink from './AnchorLink';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
import getScroll from '../_util/getScroll';
|
||||
|
||||
function getDefaultContainer() {
|
||||
@ -35,52 +35,7 @@ function getOffsetTop(element: HTMLElement, container: AnchorContainer): number
|
||||
return rect.top;
|
||||
}
|
||||
|
||||
function easeInOutCubic(t: number, b: number, c: number, d: number) {
|
||||
const cc = c - b;
|
||||
t /= d / 2;
|
||||
if (t < 1) {
|
||||
return (cc / 2) * t * t * t + b;
|
||||
}
|
||||
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
|
||||
}
|
||||
|
||||
const sharpMatcherRegx = /#([^#]+)$/;
|
||||
function scrollTo(
|
||||
href: string,
|
||||
offsetTop = 0,
|
||||
getContainer: () => AnchorContainer,
|
||||
callback = () => {},
|
||||
) {
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(href);
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
const targetElement = document.getElementById(sharpLinkMatch[1]);
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
const targetScrollTop = scrollTop + eleOffsetTop - offsetTop;
|
||||
const startTime = Date.now();
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
const nextScrollTop = easeInOutCubic(time, scrollTop, targetScrollTop, 450);
|
||||
if (container === window) {
|
||||
window.scrollTo(window.pageXOffset, nextScrollTop);
|
||||
} else {
|
||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||
}
|
||||
if (time < 450) {
|
||||
raf(frameFunc);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
}
|
||||
|
||||
type Section = {
|
||||
link: string;
|
||||
@ -99,10 +54,14 @@ export interface AnchorProps {
|
||||
affix?: boolean;
|
||||
showInkInFixed?: boolean;
|
||||
getContainer?: () => AnchorContainer;
|
||||
/** Return customize highlight anchor */
|
||||
getCurrentAnchor?: () => string;
|
||||
onClick?: (
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
link: { title: React.ReactNode; href: string },
|
||||
) => void;
|
||||
/** Scroll to target offset value, if none, it's offsetTop prop value or 0. */
|
||||
targetOffset?: number;
|
||||
}
|
||||
|
||||
export interface AnchorState {
|
||||
@ -205,6 +164,12 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
}
|
||||
|
||||
getCurrentAnchor(offsetTop = 0, bounds = 5): string {
|
||||
const { getCurrentAnchor } = this.props;
|
||||
|
||||
if (typeof getCurrentAnchor === 'function') {
|
||||
return getCurrentAnchor();
|
||||
}
|
||||
|
||||
const activeLink = '';
|
||||
if (typeof document === 'undefined') {
|
||||
return activeLink;
|
||||
@ -237,6 +202,34 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
return '';
|
||||
}
|
||||
|
||||
handleScrollTo = (link: string) => {
|
||||
const { offsetTop, getContainer, targetOffset } = this.props as AnchorDefaultProps;
|
||||
|
||||
this.setState({ activeLink: link });
|
||||
const container = getContainer();
|
||||
const scrollTop = getScroll(container, true);
|
||||
const sharpLinkMatch = sharpMatcherRegx.exec(link);
|
||||
if (!sharpLinkMatch) {
|
||||
return;
|
||||
}
|
||||
const targetElement = document.getElementById(sharpLinkMatch[1]);
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const eleOffsetTop = getOffsetTop(targetElement, container);
|
||||
let y = scrollTop + eleOffsetTop;
|
||||
y -= targetOffset !== undefined ? targetOffset : offsetTop || 0;
|
||||
this.animating = true;
|
||||
|
||||
scrollTo(y, {
|
||||
callback: () => {
|
||||
this.animating = false;
|
||||
},
|
||||
getContainer,
|
||||
});
|
||||
};
|
||||
|
||||
saveInkNode = (node: HTMLSpanElement) => {
|
||||
this.inkNode = node;
|
||||
};
|
||||
@ -246,8 +239,11 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
return;
|
||||
}
|
||||
const { activeLink } = this.state;
|
||||
const { offsetTop, bounds } = this.props;
|
||||
const currentActiveLink = this.getCurrentAnchor(offsetTop, bounds);
|
||||
const { offsetTop, bounds, targetOffset } = this.props;
|
||||
const currentActiveLink = this.getCurrentAnchor(
|
||||
targetOffset !== undefined ? targetOffset : offsetTop || 0,
|
||||
bounds,
|
||||
);
|
||||
if (activeLink !== currentActiveLink) {
|
||||
this.setState({
|
||||
activeLink: currentActiveLink,
|
||||
@ -255,15 +251,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
|
||||
}
|
||||
};
|
||||
|
||||
handleScrollTo = (link: string) => {
|
||||
const { offsetTop, getContainer } = this.props as AnchorDefaultProps;
|
||||
this.animating = true;
|
||||
this.setState({ activeLink: link });
|
||||
scrollTo(link, offsetTop, getContainer, () => {
|
||||
this.animating = false;
|
||||
});
|
||||
};
|
||||
|
||||
updateInk = () => {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
|
@ -1,12 +1,29 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Anchor from '..';
|
||||
import { spyElementPrototypes } from '../../__tests__/util/domHook';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
|
||||
|
||||
describe('Anchor Render', () => {
|
||||
const getBoundingClientRectMock = jest.fn(() => ({
|
||||
width: 100,
|
||||
height: 100,
|
||||
top: 1000,
|
||||
}));
|
||||
const getClientRectsMock = jest.fn(() => ({
|
||||
length: 1,
|
||||
}));
|
||||
const headingSpy = spyElementPrototypes(HTMLHeadingElement, {
|
||||
getBoundingClientRect: getBoundingClientRectMock,
|
||||
getClientRects: getClientRectsMock,
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
headingSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('Anchor render perfectly', () => {
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
@ -64,7 +81,7 @@ describe('Anchor Render', () => {
|
||||
wrapper.instance().handleScrollTo('##API');
|
||||
expect(wrapper.instance().state.activeLink).toBe('##API');
|
||||
expect(scrollToSpy).not.toHaveBeenCalled();
|
||||
await delay(1000);
|
||||
await sleep(1000);
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -154,7 +171,7 @@ describe('Anchor Render', () => {
|
||||
</Anchor>,
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
await delay(1000);
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -187,7 +204,7 @@ describe('Anchor Render', () => {
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await delay(1000);
|
||||
await sleep(1000);
|
||||
wrapper.setProps({ getContainer: getContainerB });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
@ -239,9 +256,67 @@ describe('Anchor Render', () => {
|
||||
);
|
||||
const removeListenerSpy = jest.spyOn(wrapper.instance().scrollEvent, 'remove');
|
||||
expect(removeListenerSpy).not.toHaveBeenCalled();
|
||||
await delay(1000);
|
||||
await sleep(1000);
|
||||
holdContainer.container = document.getElementById('API2');
|
||||
wrapper.setProps({ 'data-only-trigger-re-render': true });
|
||||
expect(removeListenerSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Anchor getCurrentAnchor prop', () => {
|
||||
const getCurrentAnchor = () => '#API2';
|
||||
const wrapper = mount(
|
||||
<Anchor getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href="#API1" title="API1" />
|
||||
<Link href="#API2" title="API2" />
|
||||
</Anchor>,
|
||||
);
|
||||
expect(wrapper.instance().state.activeLink).toBe('#API2');
|
||||
});
|
||||
|
||||
it('Anchor targetOffset prop', () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
let dateNowMock;
|
||||
|
||||
function dataNowMockFn() {
|
||||
return jest
|
||||
.spyOn(Date, 'now')
|
||||
.mockImplementationOnce(() => 0)
|
||||
.mockImplementationOnce(() => 1000);
|
||||
}
|
||||
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo');
|
||||
let root = document.getElementById('root');
|
||||
if (!root) {
|
||||
root = document.createElement('div', { id: 'root' });
|
||||
root.id = 'root';
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
mount(<h1 id="API">Hello</h1>, { attachTo: root });
|
||||
const wrapper = mount(
|
||||
<Anchor>
|
||||
<Link href="#API" title="API" />
|
||||
</Anchor>,
|
||||
);
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
jest.runAllTimers();
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 1000);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ offsetTop: 100 });
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
jest.runAllTimers();
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 900);
|
||||
dateNowMock = dataNowMockFn();
|
||||
|
||||
wrapper.setProps({ targetOffset: 200 });
|
||||
wrapper.instance().handleScrollTo('#API');
|
||||
jest.runAllTimers();
|
||||
expect(scrollToSpy).toHaveBeenLastCalledWith(0, 800);
|
||||
|
||||
dateNowMock.mockRestore();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
@ -80,6 +80,80 @@ exports[`renders ./components/anchor/demo/basic.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/customizeHighlight.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor fixed"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Basic demo"
|
||||
>
|
||||
Basic demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#API"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Anchor-Props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Link-Props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/onClick.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
@ -227,3 +301,83 @@ exports[`renders ./components/anchor/demo/static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/anchor/demo/targetOffset.md correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-wrapper"
|
||||
style="max-height:100vh"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor"
|
||||
>
|
||||
<div
|
||||
class="ant-anchor-ink"
|
||||
>
|
||||
<span
|
||||
class="ant-anchor-ink-ball"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-basic"
|
||||
title="Basic demo"
|
||||
>
|
||||
Basic demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#components-anchor-demo-static"
|
||||
title="Static demo"
|
||||
>
|
||||
Static demo
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#API"
|
||||
title="API"
|
||||
>
|
||||
API
|
||||
</a>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Anchor-Props"
|
||||
title="Anchor Props"
|
||||
>
|
||||
Anchor Props
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="ant-anchor-link"
|
||||
>
|
||||
<a
|
||||
class="ant-anchor-link-title"
|
||||
href="#Link-Props"
|
||||
title="Link Props"
|
||||
>
|
||||
Link Props
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
36
components/anchor/demo/customizeHighlight.md
Normal file
36
components/anchor/demo/customizeHighlight.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 自定义锚点高亮
|
||||
en-US: Customize the anchor highlight
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
自定义锚点高亮。
|
||||
|
||||
## en-US
|
||||
|
||||
Customize the anchor highlight.
|
||||
|
||||
```jsx
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
const getCurrentAnchor = () => {
|
||||
return '#components-anchor-demo-static';
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<Anchor affix={false} getCurrentAnchor={getCurrentAnchor}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
47
components/anchor/demo/targetOffset.md
Normal file
47
components/anchor/demo/targetOffset.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
order: 4
|
||||
title:
|
||||
zh-CN: 设置锚点滚动偏移量
|
||||
en-US: Set Anchor scroll offset
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
锚点目标滚动到屏幕正中间。
|
||||
|
||||
## en-US
|
||||
|
||||
Anchor target scroll to screen center.
|
||||
|
||||
```jsx
|
||||
import { Anchor } from 'antd';
|
||||
|
||||
const { Link } = Anchor;
|
||||
|
||||
class AnchorExample extends React.Component {
|
||||
state = {
|
||||
targetOffset: undefined,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
targetOffset: window.innerHeight / 2,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Anchor targetOffset={this.state.targetOffset}>
|
||||
<Link href="#components-anchor-demo-basic" title="Basic demo" />
|
||||
<Link href="#components-anchor-demo-static" title="Static demo" />
|
||||
<Link href="#API" title="API">
|
||||
<Link href="#Anchor-Props" title="Anchor Props" />
|
||||
<Link href="#Link-Props" title="Link Props" />
|
||||
</Link>
|
||||
</Anchor>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<AnchorExample />, mountNode);
|
||||
```
|
@ -24,6 +24,8 @@ For displaying anchor hyperlinks on page and jumping between them.
|
||||
| offsetTop | Pixels to offset from top when calculating position of scroll | number | 0 | |
|
||||
| showInkInFixed | Whether show ink-balls in Fixed mode | boolean | false | |
|
||||
| onClick | set the handler to handle `click` event | Function(e: Event, link: Object) | - | 3.9.0 |
|
||||
| getCurrentAnchor | Customize the anchor highlight | () => string | - | 3.22.0 |
|
||||
| targetOffset | Anchor scroll offset, default as `offsetTop`, [example](#components-anchor-demo-targetOffset) | number | `offsetTop` | 3.22.0 |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
@ -25,6 +25,8 @@ title: Anchor
|
||||
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | number | | |
|
||||
| showInkInFixed | 固定模式是否显示小圆点 | boolean | false | |
|
||||
| onClick | `click` 事件的 handler | Function(e: Event, link: Object) | - | 3.9.0 |
|
||||
| getCurrentAnchor | 自定义高亮的锚点 | () => string | - | 3.22.0 |
|
||||
| targetOffset | 锚点滚动偏移量,默认与 offsetTop 相同,[例子](#components-anchor-demo-targetOffset) | number | `offsetTop` | 3.22.0 |
|
||||
|
||||
### Link Props
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
width: @anchor-border-width;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
background-color: @border-color-split;
|
||||
background-color: @anchor-border-color;
|
||||
content: ' ';
|
||||
}
|
||||
&-ball {
|
||||
|
@ -1,76 +1,152 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders ./components/auto-complete/demo/basic.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
|
||||
style="width:200px"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
|
||||
style="width:200px"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
aria-autocomplete="list"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
input here
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
role="img"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<div
|
||||
class="ant-select-show-search ant-select-auto-complete ant-select ant-select-combobox ant-select-enabled"
|
||||
style="width:200px"
|
||||
>
|
||||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-controls=""
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
class="ant-select-selection
|
||||
ant-select-selection--single"
|
||||
role="combobox"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__rendered"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selection__placeholder"
|
||||
style="display:block;user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
control mode
|
||||
</div>
|
||||
<ul>
|
||||
<li
|
||||
class="ant-select-search ant-select-search--inline"
|
||||
>
|
||||
<div
|
||||
class="ant-select-search__field__wrap"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-select-search__field"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-select-search__field__mirror"
|
||||
>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<span
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-arrow-icon"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import AutoComplete from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('AutoComplete with Custom Input Element Render', () => {
|
||||
mountTest(AutoComplete);
|
||||
|
||||
it('AutoComplete with custom Input render perfectly', () => {
|
||||
const wrapper = mount(
|
||||
<AutoComplete dataSource={['12345', '23456', '34567']}>
|
||||
|
@ -11,7 +11,7 @@ title:
|
||||
|
||||
## en-US
|
||||
|
||||
Basic Usage, set datasource of autocomplete with `dataSource` property.
|
||||
Basic Usage, set data source of autocomplete with `dataSource` property.
|
||||
|
||||
```jsx
|
||||
import { AutoComplete } from 'antd';
|
||||
@ -22,25 +22,43 @@ function onSelect(value) {
|
||||
|
||||
class Complete extends React.Component {
|
||||
state = {
|
||||
value: '',
|
||||
dataSource: [],
|
||||
};
|
||||
|
||||
handleSearch = value => {
|
||||
onSearch = searchText => {
|
||||
this.setState({
|
||||
dataSource: !value ? [] : [value, value + value, value + value + value],
|
||||
dataSource: !searchText ? [] : [searchText, searchText.repeat(2), searchText.repeat(3)],
|
||||
});
|
||||
};
|
||||
|
||||
onChange = value => {
|
||||
this.setState({ value });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { dataSource } = this.state;
|
||||
const { dataSource, value } = this.state;
|
||||
return (
|
||||
<AutoComplete
|
||||
dataSource={dataSource}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.handleSearch}
|
||||
placeholder="input here"
|
||||
/>
|
||||
<div>
|
||||
<AutoComplete
|
||||
dataSource={dataSource}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.onSearch}
|
||||
placeholder="input here"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<AutoComplete
|
||||
value={value}
|
||||
dataSource={dataSource}
|
||||
style={{ width: 200 }}
|
||||
onSelect={onSelect}
|
||||
onSearch={this.onSearch}
|
||||
onChange={this.onChange}
|
||||
placeholder="control mode"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -48,3 +48,11 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
| ------- | ------------ | ------- |
|
||||
| blur() | remove focus | |
|
||||
| focus() | get focus | |
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why text composition system not works well with onSearch in controlled mode?
|
||||
|
||||
Please use `onChange` to manage control state. `onSearch` is used for searching input which is not same as `onChange`. Besides, click on the option also not trigger the `onSearch` event.
|
||||
|
||||
Related issue: [#18230](https://github.com/ant-design/ant-design/issues/18230) [#17916](https://github.com/ant-design/ant-design/issues/17916)
|
||||
|
@ -50,3 +50,11 @@ const dataSource = ['12345', '23456', '34567'];
|
||||
| ------- | -------- | ---- |
|
||||
| blur() | 移除焦点 | |
|
||||
| focus() | 获取焦点 | |
|
||||
|
||||
## FAQ
|
||||
|
||||
### 为何受控状态下使用 onSearch 无法输入中文?
|
||||
|
||||
请使用 `onChange` 进行受控管理。`onSearch` 触发于搜索输入,与 `onChange` 时机不同。此外,点选选项时也不会触发 `onSearch` 事件。
|
||||
|
||||
相关 issue:[#18230](https://github.com/ant-design/ant-design/issues/18230) [#17916](https://github.com/ant-design/ant-design/issues/17916)
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Avatar from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Avatar Render', () => {
|
||||
mountTest(Avatar);
|
||||
|
||||
let originOffsetWidth;
|
||||
beforeAll(() => {
|
||||
// Mock offsetHeight
|
||||
|
@ -1,16 +1,41 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import BackTop from '..';
|
||||
|
||||
describe('BackTop', () => {
|
||||
mountTest(BackTop);
|
||||
|
||||
it('should scroll to top after click it', async () => {
|
||||
const wrapper = mount(<BackTop visibilityHeight={-1} />);
|
||||
document.documentElement.scrollTop = 400;
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => {
|
||||
window.scrollY = y;
|
||||
window.pageYOffset = y;
|
||||
});
|
||||
window.scrollTo(0, 400);
|
||||
// trigger scroll manually
|
||||
wrapper.instance().handleScroll();
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
await sleep();
|
||||
wrapper.find('.ant-back-top').simulate('click');
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
expect(Math.abs(Math.round(document.documentElement.scrollTop))).toBe(0);
|
||||
await sleep(500);
|
||||
expect(window.pageYOffset).toBe(0);
|
||||
scrollToSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('support onClick', async () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mount(<BackTop onClick={onClick} visibilityHeight={-1} />);
|
||||
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => {
|
||||
window.scrollY = y;
|
||||
window.pageYOffset = y;
|
||||
});
|
||||
window.scrollTo(0, 400);
|
||||
// trigger scroll manually
|
||||
wrapper.instance().handleScroll();
|
||||
await sleep();
|
||||
wrapper.find('.ant-back-top').simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
scrollToSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -3,20 +3,9 @@ import Animate from 'rc-animate';
|
||||
import addEventListener from 'rc-util/lib/Dom/addEventListener';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'omit.js';
|
||||
import raf from 'raf';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import getScroll from '../_util/getScroll';
|
||||
|
||||
const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
|
||||
const cc = c - b;
|
||||
t /= d / 2;
|
||||
if (t < 1) {
|
||||
return (cc / 2) * t * t * t + b;
|
||||
}
|
||||
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
|
||||
};
|
||||
|
||||
function noop() {}
|
||||
import scrollTo from '../_util/scrollTo';
|
||||
|
||||
function getDefaultTarget() {
|
||||
return window;
|
||||
@ -58,41 +47,14 @@ export default class BackTop extends React.Component<BackTopProps, any> {
|
||||
}
|
||||
}
|
||||
|
||||
setScrollTop(value: number) {
|
||||
const getTarget = this.props.target || getDefaultTarget;
|
||||
const targetNode = getTarget();
|
||||
if (targetNode === window) {
|
||||
document.body.scrollTop = value;
|
||||
document.documentElement!.scrollTop = value;
|
||||
} else {
|
||||
(targetNode as HTMLElement).scrollTop = value;
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentScrollTop = () => {
|
||||
const getTarget = this.props.target || getDefaultTarget;
|
||||
const targetNode = getTarget();
|
||||
if (targetNode === window) {
|
||||
return window.pageYOffset || document.body.scrollTop || document.documentElement!.scrollTop;
|
||||
}
|
||||
return (targetNode as HTMLElement).scrollTop;
|
||||
};
|
||||
|
||||
scrollToTop = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const scrollTop = this.getCurrentScrollTop();
|
||||
const startTime = Date.now();
|
||||
const frameFunc = () => {
|
||||
const timestamp = Date.now();
|
||||
const time = timestamp - startTime;
|
||||
this.setScrollTop(easeInOutCubic(time, scrollTop, 0, 450));
|
||||
if (time < 450) {
|
||||
raf(frameFunc);
|
||||
} else {
|
||||
this.setScrollTop(0);
|
||||
}
|
||||
};
|
||||
raf(frameFunc);
|
||||
(this.props.onClick || noop)(e);
|
||||
const { target = getDefaultTarget, onClick } = this.props;
|
||||
scrollTo(0, {
|
||||
getContainer: target,
|
||||
});
|
||||
if (typeof onClick === 'function') {
|
||||
onClick(e);
|
||||
}
|
||||
};
|
||||
|
||||
handleScroll = () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { createElement, Component } from 'react';
|
||||
import * as React from 'react';
|
||||
import omit from 'omit.js';
|
||||
import classNames from 'classnames';
|
||||
import { polyfill } from 'react-lifecycles-compat';
|
||||
@ -47,7 +47,7 @@ export interface ScrollNumberState {
|
||||
count?: string | number | null;
|
||||
}
|
||||
|
||||
class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
|
||||
class ScrollNumber extends React.Component<ScrollNumberProps, ScrollNumberState> {
|
||||
static defaultProps = {
|
||||
count: null,
|
||||
onAnimated() {},
|
||||
@ -126,7 +126,7 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
|
||||
const position = this.getPositionByNum(num, i);
|
||||
const removeTransition =
|
||||
this.state.animateStarted || getNumberArray(this.lastCount)[i] === undefined;
|
||||
return createElement(
|
||||
return React.createElement(
|
||||
'span',
|
||||
{
|
||||
className: `${prefixCls}-only`,
|
||||
@ -200,7 +200,7 @@ class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
|
||||
),
|
||||
});
|
||||
}
|
||||
return createElement(component as any, newProps, this.renderNumberElement(prefixCls));
|
||||
return React.createElement(component as any, newProps, this.renderNumberElement(prefixCls));
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -2907,7 +2907,9 @@ exports[`Badge should support offset when count is a ReactNode 1`] = `
|
||||
<a
|
||||
class="head-example"
|
||||
href="#"
|
||||
/>
|
||||
>
|
||||
head
|
||||
</a>
|
||||
<span
|
||||
class="ant-scroll-number-custom-component custom"
|
||||
style="right:-10px;margin-top:20px;color:#f5222d"
|
||||
|
@ -2,8 +2,11 @@ import React from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import Badge from '../index';
|
||||
import Tooltip from '../../tooltip';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Badge', () => {
|
||||
mountTest(Badge);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
@ -84,7 +87,9 @@ describe('Badge', () => {
|
||||
it('should support offset when count is a ReactNode', () => {
|
||||
const wrapper = render(
|
||||
<Badge count={<span className="custom" style={{ color: '#f5222d' }} />} offset={[10, 20]}>
|
||||
<a href="#" className="head-example" />
|
||||
<a href="#" className="head-example">
|
||||
head
|
||||
</a>
|
||||
</Badge>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { cloneElement } from 'react';
|
||||
import * as React from 'react';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import BreadcrumbItem from './BreadcrumbItem';
|
||||
@ -141,9 +141,9 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
|
||||
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
|
||||
);
|
||||
|
||||
return cloneElement(element, {
|
||||
return React.cloneElement(element, {
|
||||
separator,
|
||||
key: index,
|
||||
key: index, // eslint-disable-line react/no-array-index-key
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import Breadcrumb from '../index';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Breadcrumb', () => {
|
||||
mountTest(Breadcrumb);
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -23,6 +23,9 @@
|
||||
|
||||
& > span:last-child {
|
||||
color: @breadcrumb-last-item-color;
|
||||
a {
|
||||
color: @breadcrumb-last-item-color;
|
||||
}
|
||||
}
|
||||
|
||||
& > span:last-child &-separator {
|
||||
|
@ -253,6 +253,22 @@ exports[`renders ./components/button/demo/button-group.md correctly 1`] = `
|
||||
cloud-download
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="ant-btn-group"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-sm ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
cloud
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-sm ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
cloud-download
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -427,6 +443,14 @@ exports[`renders ./components/button/demo/icon.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-circle"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary"
|
||||
type="button"
|
||||
@ -696,7 +720,7 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
|
||||
</button>
|
||||
<br />
|
||||
<button
|
||||
class="ant-btn ant-btn-circle ant-btn-loading"
|
||||
class="ant-btn ant-btn-primary ant-btn-icon-only ant-btn-loading"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
@ -721,7 +745,32 @@ exports[`renders ./components/button/demo/loading.md correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-circle ant-btn-loading"
|
||||
class="ant-btn ant-btn-primary ant-btn-circle ant-btn-icon-only ant-btn-loading"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
class="anticon anticon-loading"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="anticon-spin"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-danger ant-btn-round ant-btn-icon-only ant-btn-loading"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
@ -904,6 +953,31 @@ exports[`renders ./components/button/demo/size.md correctly 1`] = `
|
||||
</span>
|
||||
</button>
|
||||
<br />
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="download"
|
||||
class="anticon anticon-download"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="download"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-circle ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
@ -929,6 +1003,31 @@ exports[`renders ./components/button/demo/size.md correctly 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-round ant-btn-lg ant-btn-icon-only"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="download"
|
||||
class="anticon anticon-download"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="download"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="ant-btn ant-btn-primary ant-btn-round ant-btn-lg"
|
||||
type="button"
|
||||
|
@ -3,8 +3,12 @@ import { render, mount } from 'enzyme';
|
||||
import renderer from 'react-test-renderer';
|
||||
import { Search } from '@ant-design/icons';
|
||||
import Button from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Button', () => {
|
||||
mountTest(Button);
|
||||
mountTest(Button.Group);
|
||||
|
||||
it('renders correctly', () => {
|
||||
const wrapper = render(<Button>Follow</Button>);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
@ -254,11 +254,13 @@ class Button extends React.Component<ButtonProps, ButtonState> {
|
||||
break;
|
||||
}
|
||||
|
||||
const iconType = loading ? 'loading' : icon;
|
||||
|
||||
const classes = classNames(prefixCls, className, {
|
||||
[`${prefixCls}-${type}`]: type,
|
||||
[`${prefixCls}-${shape}`]: shape,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && icon,
|
||||
[`${prefixCls}-icon-only`]: !children && children !== 0 && iconType,
|
||||
[`${prefixCls}-loading`]: loading,
|
||||
[`${prefixCls}-background-ghost`]: ghost,
|
||||
[`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace,
|
||||
|
@ -56,6 +56,10 @@ ReactDOM.render(
|
||||
<Button type="primary" icon="cloud" />
|
||||
<Button type="primary" icon="cloud-download" />
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button type="primary" size="small" icon="cloud" />
|
||||
<Button type="primary" size="small" icon="cloud-download" />
|
||||
</ButtonGroup>
|
||||
</div>,
|
||||
mountNode,
|
||||
);
|
||||
|
@ -13,7 +13,7 @@ title:
|
||||
|
||||
## en-US
|
||||
|
||||
`Button` components can contain an `Icon`. This is done by setting the `icon` property or placing an `Icon` component within the `Button`
|
||||
`Button` components can contain an `Icon`. This is done by setting the `icon` property or placing an `Icon` component within the `Button`.
|
||||
|
||||
If you want specific control over the positioning and placement of the `Icon`, then that should be done by placing the `Icon` component within the `Button` rather than using the `icon` property.
|
||||
|
||||
@ -24,6 +24,9 @@ import { Search as IconSearch } from '@ant-design/icons';
|
||||
ReactDOM.render(
|
||||
<div>
|
||||
<Button type="primary" shape="circle" icon={<IconSearch />} />
|
||||
<Button type="primary" shape="circle">
|
||||
A
|
||||
</Button>
|
||||
<Button type="primary" icon={<IconSearch />}>
|
||||
Search
|
||||
</Button>
|
||||
|
@ -52,8 +52,9 @@ class App extends React.Component {
|
||||
Click me!
|
||||
</Button>
|
||||
<br />
|
||||
<Button shape="circle" loading />
|
||||
<Button type="primary" loading />
|
||||
<Button type="primary" shape="circle" loading />
|
||||
<Button type="danger" shape="round" loading />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -55,7 +55,9 @@ class ButtonSize extends React.Component {
|
||||
Link
|
||||
</Button>
|
||||
<br />
|
||||
<Button type="primary" icon={<Download />} size={size} />
|
||||
<Button type="primary" shape="circle" icon={<Download />} size={size} />
|
||||
<Button type="primary" shape="round" icon={<Download />} size={size} />
|
||||
<Button type="primary" shape="round" icon={<Download />} size={size}>
|
||||
Download
|
||||
</Button>
|
||||
|
@ -71,8 +71,15 @@
|
||||
.btn-link;
|
||||
}
|
||||
|
||||
&-icon-only {
|
||||
.btn-square(@btn-prefix-cls);
|
||||
}
|
||||
|
||||
&-round {
|
||||
.btn-round(@btn-prefix-cls);
|
||||
&.@{btn-prefix-cls}-icon-only {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&-circle,
|
||||
@ -136,11 +143,6 @@
|
||||
.btn-group(@btn-prefix-cls);
|
||||
}
|
||||
|
||||
&:not(&-circle):not(&-circle-outline)&-icon-only {
|
||||
padding-right: 8px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/21281554/3040605
|
||||
&:focus > span,
|
||||
&:active > span {
|
||||
|
@ -237,17 +237,33 @@
|
||||
);
|
||||
}
|
||||
}
|
||||
// circle button: the content only contains icon
|
||||
.btn-circle(@btnClassName: btn) {
|
||||
.square(@btn-circle-size);
|
||||
.button-size(@btn-circle-size; 0; @font-size-base + 2px; 50%);
|
||||
// square button: the content only contains icon
|
||||
.btn-square(@btnClassName: btn) {
|
||||
.square(@btn-square-size);
|
||||
.button-size(@btn-square-size; 0; @font-size-base + 2px; @btn-border-radius-base);
|
||||
&.@{btnClassName}-lg {
|
||||
.square(@btn-circle-size-lg);
|
||||
.button-size(@btn-circle-size-lg; 0; @btn-font-size-lg + 2px; 50%);
|
||||
.square(@btn-square-size-lg);
|
||||
.button-size(@btn-square-size-lg; 0; @btn-font-size-lg + 2px; @btn-border-radius-base);
|
||||
}
|
||||
&.@{btnClassName}-sm {
|
||||
.square(@btn-circle-size-sm);
|
||||
.button-size(@btn-circle-size-sm; 0; @font-size-base; 50%);
|
||||
.square(@btn-square-size-sm);
|
||||
.button-size(@btn-square-size-sm; 0; @font-size-base; @btn-border-radius-base);
|
||||
}
|
||||
}
|
||||
// circle button: the content only contains icon
|
||||
.btn-circle(@btnClassName: btn) {
|
||||
min-width: @btn-height-base;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
&.@{btnClassName}-lg {
|
||||
min-width: @btn-height-lg;
|
||||
border-radius: 50%;
|
||||
}
|
||||
&.@{btnClassName}-sm {
|
||||
min-width: @btn-height-sm;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
// Horizontal button groups style
|
||||
|
@ -49,7 +49,7 @@ export default class Header extends React.Component<HeaderProps, any> {
|
||||
private calenderHeaderNode: HTMLDivElement;
|
||||
|
||||
getYearSelectElement(prefixCls: string, year: number) {
|
||||
const { yearSelectOffset, yearSelectTotal, locale, fullscreen, validRange } = this.props;
|
||||
const { yearSelectOffset, yearSelectTotal, locale = {}, fullscreen, validRange } = this.props;
|
||||
let start = year - (yearSelectOffset as number);
|
||||
let end = start + (yearSelectTotal as number);
|
||||
if (validRange) {
|
||||
@ -171,7 +171,7 @@ export default class Header extends React.Component<HeaderProps, any> {
|
||||
};
|
||||
|
||||
getTypeSwitch = () => {
|
||||
const { locale, type, fullscreen } = this.props;
|
||||
const { locale = {}, type, fullscreen } = this.props;
|
||||
const size = fullscreen ? 'default' : 'small';
|
||||
return (
|
||||
<Group onChange={this.onInternalTypeChange} value={type} size={size}>
|
||||
|
@ -7,8 +7,12 @@ import Header from '../Header';
|
||||
import Select from '../../select';
|
||||
import Group from '../../radio/group';
|
||||
import Button from '../../radio/radioButton';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
||||
describe('Calendar', () => {
|
||||
mountTest(Calendar);
|
||||
mountTest(() => <Header value={Moment()} />);
|
||||
|
||||
it('Calendar should be selectable', () => {
|
||||
const onSelect = jest.fn();
|
||||
const wrapper = mount(<Calendar onSelect={onSelect} />);
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ar_EG from '../../date-picker/locale/ar_EG';
|
||||
|
||||
export default ar_EG;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import bg_BG from '../../date-picker/locale/bg_BG';
|
||||
|
||||
export default bg_BG;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ca_ES from '../../date-picker/locale/ca_ES';
|
||||
|
||||
export default ca_ES;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import cs_CZ from '../../date-picker/locale/cs_CZ';
|
||||
|
||||
export default cs_CZ;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import da_DK from '../../date-picker/locale/da_DK';
|
||||
|
||||
export default da_DK;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import de_DE from '../../date-picker/locale/de_DE';
|
||||
|
||||
export default de_DE;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import el_GR from '../../date-picker/locale/el_GR';
|
||||
|
||||
export default el_GR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import en_GB from '../../date-picker/locale/en_GB';
|
||||
|
||||
export default en_GB;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import en_US from '../../date-picker/locale/en_US';
|
||||
|
||||
export default en_US;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import es_ES from '../../date-picker/locale/es_ES';
|
||||
|
||||
export default es_ES;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import et_EE from '../../date-picker/locale/et_EE';
|
||||
|
||||
export default et_EE;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import fa_IR from '../../date-picker/locale/fa_IR';
|
||||
|
||||
export default fa_IR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import fi_FI from '../../date-picker/locale/fi_FI';
|
||||
|
||||
export default fi_FI;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import fr_BE from '../../date-picker/locale/fr_BE';
|
||||
|
||||
export default fr_BE;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import fr_FR from '../../date-picker/locale/fr_FR';
|
||||
|
||||
export default fr_FR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import he_IL from '../../date-picker/locale/he_IL';
|
||||
|
||||
export default he_IL;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import hi_IN from '../../date-picker/locale/hi_IN';
|
||||
|
||||
export default hi_IN;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import hr_HR from '../../date-picker/locale/hr_HR';
|
||||
|
||||
export default hr_HR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import hu_HU from '../../date-picker/locale/hu_HU';
|
||||
|
||||
export default hu_HU;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import id_ID from '../../date-picker/locale/id_ID';
|
||||
|
||||
export default id_ID;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import is_IS from '../../date-picker/locale/is_IS';
|
||||
|
||||
export default is_IS;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import it_IT from '../../date-picker/locale/it_IT';
|
||||
|
||||
export default it_IT;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ja_JP from '../../date-picker/locale/ja_JP';
|
||||
|
||||
export default ja_JP;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import kn_IN from '../../date-picker/locale/kn_IN';
|
||||
|
||||
export default kn_IN;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ko_KR from '../../date-picker/locale/ko_KR';
|
||||
|
||||
export default ko_KR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ku_IQ from '../../date-picker/locale/ku_IQ';
|
||||
|
||||
export default ku_IQ;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import lv_LV from '../../date-picker/locale/lv_LV';
|
||||
|
||||
export default lv_LV;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import mn_MN from '../../date-picker/locale/mn_MN';
|
||||
|
||||
export default mn_MN;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ms_MY from '../../date-picker/locale/ms_MY';
|
||||
|
||||
export default ms_MY;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import nb_NO from '../../date-picker/locale/nb_NO';
|
||||
|
||||
export default nb_NO;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import nl_BE from '../../date-picker/locale/nl_BE';
|
||||
|
||||
export default nl_BE;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import nl_NL from '../../date-picker/locale/nl_NL';
|
||||
|
||||
export default nl_NL;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import pl_PL from '../../date-picker/locale/pl_PL';
|
||||
|
||||
export default pl_PL;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import pt_BR from '../../date-picker/locale/pt_BR';
|
||||
|
||||
export default pt_BR;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import pt_PT from '../../date-picker/locale/pt_PT';
|
||||
|
||||
export default pt_PT;
|
||||
|
3
components/calendar/locale/ro_RO.tsx
Normal file
3
components/calendar/locale/ro_RO.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import ro_RO from '../../date-picker/locale/ro_RO';
|
||||
|
||||
export default ro_RO;
|
@ -1,2 +1,3 @@
|
||||
import ru_RU from '../../date-picker/locale/ru_RU';
|
||||
|
||||
export default ru_RU;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import sk_SK from '../../date-picker/locale/sk_SK';
|
||||
|
||||
export default sk_SK;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import sl_SI from '../../date-picker/locale/sl_SI';
|
||||
|
||||
export default sl_SI;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import sr_RS from '../../date-picker/locale/sr_RS';
|
||||
|
||||
export default sr_RS;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import sv_SE from '../../date-picker/locale/sv_SE';
|
||||
|
||||
export default sv_SE;
|
||||
|
@ -1,2 +1,3 @@
|
||||
import ta_IN from '../../date-picker/locale/ta_IN';
|
||||
|
||||
export default ta_IN;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user