diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index ae73cc6fd0..a2813160f0 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -1,10 +1,10 @@ name: Deploy website on: release: - actions: - - published + types: [published] branches: - master + jobs: build-and-deploy: runs-on: ubuntu-latest diff --git a/.github/workflows/publish-to-github-package.yml b/.github/workflows/publish-to-github-package.yml new file mode 100644 index 0000000000..a54bdb9fed --- /dev/null +++ b/.github/workflows/publish-to-github-package.yml @@ -0,0 +1,28 @@ +name: Publish to github-package +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@master + + - uses: actions/setup-node@v1 + with: + node-version: '12.x' + registry-url: 'https://npm.pkg.github.com' + + - name: install + run: npm install + + - name: compile + run: npm run compile + + - name: publish + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 1b25d53f0d..5187bdf3ed 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -66,7 +66,7 @@ timeline: true - Descriptions - 🐞 修复 Descriptions.Item 最后一个宽度计算不正确的问题。[#18568](https://github.com/ant-design/ant-design/pull/18568) - 🐞 Description.Item 在渲染时会复用用户提供的 `key`。[#18578](https://github.com/ant-design/ant-design/pull/18578) -- 🐞 修复 Tab 内容宽度在 Safari 下不正确的问题。[#18574](https://github.com/ant-design/ant-design/pull/18574) +- 🐞 修复 Tabs 内容宽度在 Safari 下不正确的问题。[#18574](https://github.com/ant-design/ant-design/pull/18574) - 🐞 修复 Mentions 的 `prefix` 为空字符串时,弹窗位置不正确的问题。[#18576](https://github.com/ant-design/ant-design/pull/18576) - 🐞 修复 Upload.Dragger 在 `multiple` 为 false 时,仍然可以上传多份文件的问题。[#18580](https://github.com/ant-design/ant-design/pull/18580) - 🐞 修复 `Button[href]` 在 Card `actions` 中样式变形的问题。[#18588](https://github.com/ant-design/ant-design/pull/18588) diff --git a/README-zh_CN.md b/README-zh_CN.md index d361388c00..0565c1c042 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -8,7 +8,7 @@
-一套企业级的 UI 设计语言和 React 实现。 +一套企业级 UI 设计语言和 React 组件库。 [![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd) diff --git a/README.md b/README.md index ac49dbdd98..72f52e04c4 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@
-An enterprise-class UI design language and React implementation. +An enterprise-class UI design language and React UI library. [![CircleCI branch](https://img.shields.io/circleci/project/github/ant-design/ant-design/master.svg?style=flat-square)](https://circleci.com/gh/ant-design/ant-design) [![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master) [![](https://flat.badgen.net/npm/v/antd?icon=npm)](https://www.npmjs.com/package/antd) [![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://npmjs.com/antd) diff --git a/components/alert/__tests__/__snapshots__/demo.test.js.snap b/components/alert/__tests__/__snapshots__/demo.test.js.snap index f0d5138702..a7a82672eb 100644 --- a/components/alert/__tests__/__snapshots__/demo.test.js.snap +++ b/components/alert/__tests__/__snapshots__/demo.test.js.snap @@ -68,10 +68,10 @@ exports[`renders ./components/alert/demo/banner.md correctly 1`] = ` - - +

- - +
Error Description Error Description Error Description Error Description Error Description Error Description - - +
`; @@ -260,17 +260,17 @@ exports[`renders ./components/alert/demo/close-text.md correctly 1`] = ` - Close Now - + `; @@ -932,10 +932,10 @@ exports[`renders ./components/alert/demo/smooth-closed.md correctly 1`] = ` - - +

placeholder text here diff --git a/components/alert/index.tsx b/components/alert/index.tsx index adfe50de6d..b123248ac3 100755 --- a/components/alert/index.tsx +++ b/components/alert/index.tsx @@ -33,7 +33,7 @@ export interface AlertProps { /** Additional content of Alert */ description?: React.ReactNode; /** Callback when close Alert */ - onClose?: React.MouseEventHandler; + onClose?: React.MouseEventHandler; /** Trigger when animation ending of Alert */ afterClose?: () => void; /** Whether to show icon */ @@ -70,7 +70,7 @@ export default class Alert extends React.Component { closed: false, }; - handleClose = (e: React.MouseEvent) => { + handleClose = (e: React.MouseEvent) => { e.preventDefault(); const dom = ReactDOM.findDOMNode(this) as HTMLElement; dom.style.height = `${dom.offsetHeight}px`; @@ -134,14 +134,14 @@ export default class Alert extends React.Component { ); const closeIcon = closable ? ( - {closeText ? {closeText} : } - + ) : null; const dataOrAriaProps = getDataOrAriaProps(this.props); diff --git a/components/alert/style/index.less b/components/alert/style/index.less index a945b3b1ed..abf540db96 100644 --- a/components/alert/style/index.less +++ b/components/alert/style/index.less @@ -74,6 +74,8 @@ overflow: hidden; font-size: @font-size-sm; line-height: 22px; + border: none; + background-color: transparent; cursor: pointer; .@{iconfont-css-prefix}-close { diff --git a/components/avatar/style/index.less b/components/avatar/style/index.less index f2c22c0376..e305105458 100644 --- a/components/avatar/style/index.less +++ b/components/avatar/style/index.less @@ -37,6 +37,7 @@ display: block; width: 100%; height: 100%; + object-fit: cover; } } diff --git a/components/button/__tests__/__snapshots__/index.test.js.snap b/components/button/__tests__/__snapshots__/index.test.js.snap index fa70f1f7ca..4259fdf439 100644 --- a/components/button/__tests__/__snapshots__/index.test.js.snap +++ b/components/button/__tests__/__snapshots__/index.test.js.snap @@ -155,6 +155,17 @@ exports[`Button renders Chinese characters correctly 6`] = ` `; +exports[`Button renders Chinese characters correctly 7`] = ` + +`; + exports[`Button renders correctly 1`] = ` +`; + exports[`Button should not render as link button when href is undefined 1`] = ` +`; + exports[`Button should support link button 1`] = ` { mountTest(Button); + mountTest(() => ); @@ -45,6 +50,14 @@ describe('Button', () => { // should insert space while loading const wrapper5 = render(); expect(wrapper5).toMatchSnapshot(); + + // should insert space while only one nested element + const wrapper6 = render( + , + ); + expect(wrapper6).toMatchSnapshot(); }); it('renders Chinese characters correctly in HOC', () => { @@ -67,6 +80,22 @@ describe('Button', () => { expect(wrapper.find('.ant-btn').hasClass('ant-btn-two-chinese-chars')).toBe(true); }); + // https://github.com/ant-design/ant-design/issues/18118 + it('should not insert space to link button', () => { + const wrapper = render(); + expect(wrapper).toMatchSnapshot(); + }); + + it('should render empty button without errors', () => { + const wrapper = mount( + , + ); + expect(wrapper).toMatchSnapshot(); + }); + it('have static property for type detecting', () => { const wrapper = mount(); // eslint-disable-next-line @@ -122,6 +151,17 @@ describe('Button', () => { expect(wrapper.hasClass('ant-btn-loading')).toBe(false); }); + it('should not clickable when button is loading', () => { + const onClick = jest.fn(); + const wrapper = mount( + , + ); + wrapper.simulate('click'); + expect(onClick).not.toHaveBeenCalledWith(); + }); + it('should support link button', () => { const wrapper = mount( ); + wrapper.setProps({ loading: true }); + wrapper.update(); + expect(wrapper.find('.ant-btn-loading').length).toBe(1); + wrapper.setProps({ loading: false }); + wrapper.update(); + expect(wrapper.find('.ant-btn-loading').length).toBe(0); + wrapper.setProps({ loading: { delay: 50 } }); + wrapper.update(); + expect(wrapper.find('.ant-btn-loading').length).toBe(0); + await sleep(50); + wrapper.update(); + expect(wrapper.find('.ant-btn-loading').length).toBe(1); + wrapper.setProps({ loading: false }); + await sleep(50); + wrapper.update(); + expect(wrapper.find('.ant-btn-loading').length).toBe(0); + expect(() => { + wrapper.unmount(); + }).not.toThrow(); + }); }); diff --git a/components/button/button.tsx b/components/button/button.tsx index 12101a2ebf..4b60085143 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -135,16 +135,6 @@ class Button extends React.Component { title: PropTypes.string, }; - static getDerivedStateFromProps(nextProps: ButtonProps, prevState: ButtonState) { - if (nextProps.loading instanceof Boolean) { - return { - ...prevState, - loading: nextProps.loading, - }; - } - return null; - } - private delayTimeout: number; private buttonNode: HTMLElement | null; @@ -170,8 +160,10 @@ class Button extends React.Component { const { loading } = this.props; if (loading && typeof loading !== 'boolean' && loading.delay) { - this.delayTimeout = window.setTimeout(() => this.setState({ loading }), loading.delay); - } else if (prevProps.loading !== this.props.loading) { + this.delayTimeout = window.setTimeout(() => { + this.setState({ loading }); + }, loading.delay); + } else if (prevProps.loading !== loading) { // eslint-disable-next-line react/no-did-update-set-state this.setState({ loading }); } @@ -218,8 +210,8 @@ class Button extends React.Component { } isNeedInserted() { - const { icon, children } = this.props; - return React.Children.count(children) === 1 && !icon; + const { icon, children, type } = this.props; + return React.Children.count(children) === 1 && !icon && type !== 'link'; } renderButton = ({ getPrefixCls, autoInsertSpaceInButton }: ConfigConsumerProps) => { @@ -261,7 +253,7 @@ class Button extends React.Component { [`${prefixCls}-${shape}`]: shape, [`${prefixCls}-${sizeCls}`]: sizeCls, [`${prefixCls}-icon-only`]: !children && children !== 0 && iconType, - [`${prefixCls}-loading`]: loading, + [`${prefixCls}-loading`]: !!loading, [`${prefixCls}-background-ghost`]: ghost, [`${prefixCls}-two-chinese-chars`]: hasTwoCNChar && autoInsertSpace, [`${prefixCls}-block`]: block, diff --git a/components/config-provider/__tests__/locale.test.js b/components/config-provider/__tests__/locale.test.js index e234af716d..880eb4ef15 100644 --- a/components/config-provider/__tests__/locale.test.js +++ b/components/config-provider/__tests__/locale.test.js @@ -2,10 +2,16 @@ import React from 'react'; import { mount } from 'enzyme'; import ConfigProvider from '..'; import LocaleProvider from '../../locale-provider'; -import locale from '../../locale/zh_CN'; +import zhCN from '../../locale/zh_CN'; +import enUS from '../../locale/en_US'; import TimePicker from '../../time-picker'; +import Modal from '../../modal'; describe('ConfigProvider.Locale', () => { + function $$(className) { + return document.body.querySelectorAll(className); + } + it('not throw', () => { if (process.env.REACT === '15') { return; @@ -19,14 +25,54 @@ describe('ConfigProvider.Locale', () => { ); }); + // https://github.com/ant-design/ant-design/issues/18731 + it('should not reset locale for Modal', () => { + class App extends React.Component { + state = { + showButton: false, + }; + + componentDidMount() { + this.setState({ + showButton: true, + }); + } + + openConfirm = () => { + Modal.confirm({ + title: 'title', + content: 'Some descriptions', + }); + }; + + render() { + return ( + + {this.state.showButton ? ( + + + + ) : null} + + ); + } + } + + const wrapper = mount(); + wrapper.find('button').simulate('click'); + expect($$('.ant-btn-primary')[0].textContent).toBe('OK'); + }); + describe('support legacy LocaleProvider', () => { function testLocale(wrapper) { - expect(wrapper.find('input').props().placeholder).toBe(locale.TimePicker.placeholder); + expect(wrapper.find('input').props().placeholder).toBe(zhCN.TimePicker.placeholder); } it('LocaleProvider', () => { const wrapper = mount( - + , ); @@ -36,7 +82,7 @@ describe('ConfigProvider.Locale', () => { it('LocaleProvider > ConfigProvider', () => { const wrapper = mount( - + @@ -48,7 +94,7 @@ describe('ConfigProvider.Locale', () => { it('ConfigProvider > ConfigProvider', () => { const wrapper = mount( - + diff --git a/components/descriptions/index.zh-CN.md b/components/descriptions/index.zh-CN.md index ff03bc2174..c1bb53bafc 100644 --- a/components/descriptions/index.zh-CN.md +++ b/components/descriptions/index.zh-CN.md @@ -32,4 +32,4 @@ cols: 1 | label | 内容的描述 | ReactNode | - | 3.19.0 | | span | 包含列的数量 | number | 1 | 3.19.0 | -> span Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。 +> span 是 Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。 diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index 9e2ad22d58..6a35c195b1 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -4030,20 +4030,16 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `

-
- -
-
- -
+
+
+
diff --git a/components/form/demo/validate-other.md b/components/form/demo/validate-other.md index 0dae3b3f9f..36fcd1f023 100644 --- a/components/form/demo/validate-other.md +++ b/components/form/demo/validate-other.md @@ -171,17 +171,15 @@ const Demo = () => { -
- - -

- -

-

Click or drag file to this area to upload

-

Support for a single or bulk upload.

-
-
-
+ + +

+ +

+

Click or drag file to this area to upload

+

Support for a single or bulk upload.

+
+
@@ -195,10 +193,3 @@ const Demo = () => { ReactDOM.render(, mountNode); ``` - -```css -#components-form-demo-validate-other .dropbox { - height: 180px; - line-height: 1.5; -} -``` diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index e1527d3798..4aabecea50 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -19,7 +19,7 @@ High performance Form component with data scope management. Including data colle | Property | Description | Type | Default | | --- | --- | --- | --- | | component | Set the Form rendering element. Do not create a DOM node for `false` | ComponentType \| false | form | -| colon | Configure the default value of `colon` for Form.Item. Indicates whether the colon after the label is displayed | boolean | true | +| colon | Configure the default value of `colon` for Form.Item. Indicates whether the colon after the label is displayed (only effective when prop layout is horizontal) | boolean | true | | fields | Control of form fields through state management (such as redux). Not recommended for non-strong demand. View [example](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - | | form | Form control instance created by `Form.useForm()`. Automatically created when not provided | [FormInstance](#FormInstance) | - | | hideRequiredMark | Hide required mark for all form items | boolean | false | diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index 8a5c88c095..e9ceb2d902 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -20,7 +20,7 @@ title: Form | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | component | 设置 Form 渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType \| false | form | -| colon | 配置 Form.Item 的 `colon` 的默认值。表示是否显示 label 后面的冒号 | boolean | true | +| colon | 配置 Form.Item 的 `colon` 的默认值。表示是否显示 label 后面的冒号 (只有在属性 layout 为 horizontal 时有效) | boolean | true | | fields | 通过状态管理(如 redux)控制表单字段,如非强需求不推荐使用。查看[示例](#components-form-demo-global-state) | [FieldData](#FieldData)\[] | - | | form | 经 `Form.useForm()` 创建的 form 控制实例,不提供时会自动创建 | [FormInstance](#FormInstance) | - | | hideRequiredMark | 隐藏所有表单项的必选标记 | boolean | false | diff --git a/components/input-number/style/index.less b/components/input-number/style/index.less index 1c91a88c35..8b625c2763 100644 --- a/components/input-number/style/index.less +++ b/components/input-number/style/index.less @@ -141,6 +141,7 @@ &-handler-up { cursor: pointer; + border-top-right-radius: @border-radius-base; &-inner { top: 50%; margin-top: -5px; @@ -154,6 +155,7 @@ &-handler-down { top: 0; border-top: @border-width-base @border-style-base @border-color-base; + border-bottom-right-radius: @border-radius-base; cursor: pointer; &-inner { top: 50%; diff --git a/components/input/Search.tsx b/components/input/Search.tsx index fd4f69fcb4..805b36526e 100644 --- a/components/input/Search.tsx +++ b/components/input/Search.tsx @@ -10,7 +10,10 @@ export interface SearchProps extends InputProps { inputPrefixCls?: string; onSearch?: ( value: string, - event?: React.MouseEvent | React.KeyboardEvent, + event?: + | React.ChangeEvent + | React.MouseEvent + | React.KeyboardEvent, ) => void; enterButton?: boolean | React.ReactNode; } @@ -26,6 +29,16 @@ export default class Search extends React.Component { this.input = node; }; + onChange = (e: React.ChangeEvent) => { + const { onChange, onSearch } = this.props; + if (e && e.target && e.type === 'click' && onSearch) { + onSearch((e as React.ChangeEvent).target.value, e); + } + if (onChange) { + onChange(e); + } + }; + onSearch = (e: React.MouseEvent | React.KeyboardEvent) => { const { onSearch } = this.props; if (onSearch) { @@ -137,6 +150,7 @@ export default class Search extends React.Component { prefixCls={inputPrefixCls} addonAfter={this.renderAddonAfter(prefixCls)} suffix={this.renderSuffix(prefixCls)} + onChange={this.onChange} ref={this.saveInput} className={inputClassName} /> diff --git a/components/input/__tests__/Search.test.js b/components/input/__tests__/Search.test.js index 26c14fbe8a..3197da8299 100644 --- a/components/input/__tests__/Search.test.js +++ b/components/input/__tests__/Search.test.js @@ -137,4 +137,19 @@ describe('Input.Search', () => { expect(wrapper.render()).toMatchSnapshot(); expect(wrapperWithEnterButton.render()).toMatchSnapshot(); }); + + // https://github.com/ant-design/ant-design/issues/18729 + it('should trigger onSearch when click clear icon', () => { + const onSearch = jest.fn(); + const onChange = jest.fn(); + const wrapper = mount( + , + ); + wrapper + .find('.ant-input-clear-icon') + .at(0) + .simulate('click'); + expect(onSearch).toHaveBeenLastCalledWith('', expect.anything()); + expect(onChange).toHaveBeenCalled(); + }); }); diff --git a/components/input/__tests__/__snapshots__/index.test.js.snap b/components/input/__tests__/__snapshots__/index.test.js.snap index 3cf8aae1b4..cdf3b92a65 100644 --- a/components/input/__tests__/__snapshots__/index.test.js.snap +++ b/components/input/__tests__/__snapshots__/index.test.js.snap @@ -294,6 +294,7 @@ exports[`Input.Search should support suffix 1`] = ` > void` | `()=>history.back()` | 3.14.0 | - -> breadcrumbs will automatically disappear when configuring back icon. diff --git a/components/page-header/index.zh-CN.md b/components/page-header/index.zh-CN.md index e2aa846da0..8f127794df 100644 --- a/components/page-header/index.zh-CN.md +++ b/components/page-header/index.zh-CN.md @@ -25,5 +25,3 @@ subtitle: 页头 | breadcrumb | 面包屑的配置 | [breadcrumb](https://ant.design/components/breadcrumb-cn/) | - | 3.14.0 | | footer | PageHeader 的页脚,一般用于渲染 TabBar | ReactNode | - | 3.14.0 | | onBack | 返回按钮的点击事件 | `()=>void` | `()=>history.back()` | 3.14.0 | - -> 配置返回按钮时,breadcrumb 会自动隐藏。 diff --git a/components/select/index.en-US.md b/components/select/index.en-US.md index 590cff53a1..9150382372 100644 --- a/components/select/index.en-US.md +++ b/components/select/index.en-US.md @@ -33,6 +33,7 @@ Select component to select value from options. | dropdownMatchSelectWidth | Whether dropdown's width is same with select. | boolean | true | | | dropdownRender | Customize dropdown content | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 | | dropdownStyle | style of dropdown menu | object | - | | +| dropdownMenuStyle | additional style applied to dropdown menu | object | - | | | filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true | | | firstActiveValue | Value of action option by default | string\|string\[] | - | | | getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. [Example](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | | diff --git a/components/select/index.zh-CN.md b/components/select/index.zh-CN.md index 2dddaa004d..16b8532517 100644 --- a/components/select/index.zh-CN.md +++ b/components/select/index.zh-CN.md @@ -34,6 +34,7 @@ title: Select | dropdownMatchSelectWidth | 下拉菜单和选择器同宽 | boolean | true | | | dropdownRender | 自定义下拉框内容 | (menuNode: ReactNode, props) => ReactNode | - | 3.11.0 | | dropdownStyle | 下拉菜单的 style 属性 | object | - | | +| dropdownMenuStyle | dropdown 菜单自定义样式 | object | - | | | filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | | | firstActiveValue | 默认高亮的选项 | string\|string\[] | - | | | getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | Function(triggerNode) | () => document.body | | diff --git a/components/table/index.zh-CN.md b/components/table/index.zh-CN.md index ae5bdc1cc0..3bc1c888a4 100644 --- a/components/table/index.zh-CN.md +++ b/components/table/index.zh-CN.md @@ -141,7 +141,7 @@ const columns = [ | sorter | 排序函数,本地排序使用一个函数(参考 [Array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) 的 compareFunction),需要服务端排序可设为 true | Function\|boolean | - | | | sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 `'ascend'` `'descend'` `false` | boolean\|string | - | | | sortDirections | 支持的排序方式,取值为 `'ascend'` `'descend'` | Array | `['ascend', 'descend']` | 3.15.2 | -| title | 列头显示文字 | ReactNode\|({ sortOrder, filters }) => ReactNode | - | | +| title | 列头显示文字(函数用法 `3.10.0` 后支持) | ReactNode\|({ sortOrder, filters }) => ReactNode | - | | | width | 列宽度([指定了也不生效?](https://github.com/ant-design/ant-design/issues/13825#issuecomment-449889241)) | string\|number | - | | | onCell | 设置单元格属性 | Function(record, rowIndex) | - | | | onFilter | 本地模式下,确定筛选的运行函数 | Function | - | | diff --git a/components/transfer/index.en-US.md b/components/transfer/index.en-US.md index 734ca5202d..7e77b1ae04 100644 --- a/components/transfer/index.en-US.md +++ b/components/transfer/index.en-US.md @@ -24,19 +24,19 @@ One or more elements can be selected from either column, one click on the proper | dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in `targetKeys` prop. | [TransferItem](https://git.io/vMM64)\[] | \[] | | | disabled | Whether disabled transfer | boolean | false | 3.10.0 | | filterOption | A function to determine whether an item should show in search result list | (inputValue, option): boolean | | | -| footer | A function used for rendering the footer. | (props): ReactNode | | | +| footer | A function used for rendering the footer. | (props) => ReactNode | | | | lazy | property of [react-lazy-load](https://github.com/loktar00/react-lazy-load) for lazy rendering items. Turn off it by set to `false`. | object\|boolean | `{ height: 32, offset: 32 }` | | | listStyle | A custom CSS style used for rendering the transfer columns. | object | | | | locale | i18n text including filter, empty text, item unit, etc | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: 'item', itemsUnit: 'items', notFoundContent: 'The list is empty', searchPlaceholder: 'Search here' }` | 3.9.0 | | operations | A set of operations that are sorted from top to bottom. | string\[] | \['>', '<'] | | | operationStyle | A custom CSS style used for rendering the operations column. | object | | 3.6.0 | -| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a React element and `value` is for title | Function(record) | | | +| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. Also, it can return a plain object with `value` and `label`, `label` is a React element and `value` is for title | (record) => ReactNode | | | | selectedKeys | A set of keys of selected items. | string\[] | \[] | | | showSearch | If included, a search box is shown on each column. | boolean | false | | | showSelectAll | Show select all checkbox on the header | boolean | true | 3.18.0 | | style | A custom CSS style used for rendering wrapper element. | object | | 3.6.0 | | targetKeys | A set of keys of elements that are listed on the right column. | string\[] | \[] | | -| titles | A set of titles that are sorted from left to right. | string\[] | - | | +| titles | A set of titles that are sorted from left to right. | ReactNode\[] | - | | | onChange | A callback function that is executed when the transfer between columns is complete. | (targetKeys, direction, moveKeys): void | | | | onScroll | A callback function which is executed when scroll options list | (direction, event): void | | | | onSearch | A callback function which is executed when search field are changed | (direction: 'left'\|'right', value: string): void | - | 3.11.0 | diff --git a/components/transfer/index.zh-CN.md b/components/transfer/index.zh-CN.md index 5c090e469e..a387b96a29 100644 --- a/components/transfer/index.zh-CN.md +++ b/components/transfer/index.zh-CN.md @@ -27,18 +27,18 @@ title: Transfer | dataSource | 数据源,其中的数据将会被渲染到左边一栏中,`targetKeys` 中指定的除外。 | [TransferItem](https://git.io/vMM64)\[] | \[] | | | disabled | 是否禁用 | boolean | false | 3.10.0 | | filterOption | 接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | | (inputValue, option): boolean | | | -| footer | 底部渲染函数 | (props): ReactNode | | | +| footer | 底部渲染函数 | (props) => ReactNode | | | | lazy | Transfer 使用了 [react-lazy-load](https://github.com/loktar00/react-lazy-load) 优化性能,这里可以设置相关参数。设为 `false` 可以关闭懒加载。 | object\|boolean | `{ height: 32, offset: 32 }` | | | listStyle | 两个穿梭框的自定义样式 | object | | | | locale | 各种语言 | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode; } | `{ itemUnit: '项', itemsUnit: '项', searchPlaceholder: '请输入搜索内容' }` | 3.9.0 | | operations | 操作文案集合,顺序从上至下 | string\[] | \['>', '<'] | | -| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | Function(record) | | | +| render | 每行数据渲染函数,该函数的入参为 `dataSource` 中的项,返回值为 ReactElement。或者返回一个普通对象,其中 `label` 字段为 ReactElement,`value` 字段为 title | (record) => ReactNode | | | | selectedKeys | 设置哪些项应该被选中 | string\[] | \[] | | | showSearch | 是否显示搜索框 | boolean | false | | | showSelectAll | 是否展示全选勾选框 | boolean | true | 3.18.0 | | style | 容器的自定义样式 | object | | 3.6.0 | | targetKeys | 显示在右侧框数据的 key 集合 | string\[] | \[] | | -| titles | 标题集合,顺序从左至右 | string\[] | \['', ''] | | +| titles | 标题集合,顺序从左至右 | ReactNode\[] | \['', ''] | | | onChange | 选项在两栏之间转移时的回调函数 | (targetKeys, direction, moveKeys): void | | | | onScroll | 选项列表滚动时的回调函数 | (direction, event): void | | | | onSearch | 搜索框内容时改变时的回调函数 | (direction: 'left'\|'right', value: string): void | - | 3.11.0 | diff --git a/components/tree/Tree.tsx b/components/tree/Tree.tsx index d66ff8cff9..b2a15c3c08 100644 --- a/components/tree/Tree.tsx +++ b/components/tree/Tree.tsx @@ -156,6 +156,8 @@ export interface TreeProps { onDragOver?: (options: AntTreeNodeMouseEvent) => void; onDragLeave?: (options: AntTreeNodeMouseEvent) => void; onDragEnd?: (options: AntTreeNodeMouseEvent) => void; + onMouseEnter?: (options: AntTreeNodeMouseEvent) => void; + onMouseLeave?: (options: AntTreeNodeMouseEvent) => void; onDrop?: (options: AntTreeNodeDropEvent) => void; style?: React.CSSProperties; showIcon?: boolean; diff --git a/components/tree/index.en-US.md b/components/tree/index.en-US.md index a3da89c2ac..97ea642909 100644 --- a/components/tree/index.en-US.md +++ b/components/tree/index.en-US.md @@ -33,6 +33,7 @@ Almost anything can be represented in a tree structure. Examples include directo | loadData | Load data asynchronously | function(node) | - | | | loadedKeys | (Controlled) Set loaded tree nodes. Need work with `loadData` | string\[] | \[] | 3.7.0 | | multiple | Allows selecting multiple treeNodes | boolean | false | | +| selectable | whether can be selected | boolean | true | | | selectedKeys | (Controlled) Specifies the keys of the selected treeNodes | string\[] | - | | | showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false | | | switcherIcon | customize collapse/expand icon of tree node | React.ReactElement | - | 3.12.0 | diff --git a/components/tree/index.zh-CN.md b/components/tree/index.zh-CN.md index adb38bee5a..bcac7e03f7 100644 --- a/components/tree/index.zh-CN.md +++ b/components/tree/index.zh-CN.md @@ -34,6 +34,7 @@ subtitle: 树形控件 | loadData | 异步加载数据 | function(node) | - | | | loadedKeys | (受控)已经加载的节点,需要配合 `loadData` 使用 | string\[] | \[] | 3.7.0 | | multiple | 支持点选多个节点(节点本身) | boolean | false | | +| selectable | 是否可选中 | boolean | true | | | selectedKeys | (受控)设置选中的树节点 | string\[] | - | | | showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false | | | switcherIcon | 自定义树节点的展开/折叠图标 | React.ReactElement | - | 3.12.0 | diff --git a/docs/spec/overview.en-US.md b/docs/spec/overview.en-US.md index dc261e076f..7a27aaf9f9 100644 --- a/docs/spec/overview.en-US.md +++ b/docs/spec/overview.en-US.md @@ -26,5 +26,5 @@ The complete design pattern will include examples of templates, components (ETC) We work with engineers to transform design patterns into reusable code that maximizes your productivity and communication efficiency. - [Ant Design Pro](https://pro.ant.design): Out-of-the-box solution with 20+ templates and 10+ business components -- [Ant Design Components](https://ant.design/docs/react/introduce): Ant Design's React implementation is a global component library with 50+ base components +- [Ant Design Components](https://ant.design/docs/react/introduce): Ant Design's React UI library is a global component library with 50+ base components - [Ant Design Library](http://library.ant.design/): Axure resource packs are included with the code to make your prototype look like a visual draft, including templates, components, and more. diff --git a/package.json b/package.json index 3203bc8906..0d1c582986 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,91 @@ { "name": "antd", "version": "4.0.0-alpha.3", - "title": "Ant Design", "description": "An enterprise-class UI design language and React components implementation", - "homepage": "http://ant.design/", "keywords": [ "ant", - "design", - "react", - "react-component", "component", "components", - "ui", + "design", "framework", - "frontend" - ], - "contributors": [ - "ant" + "frontend", + "react", + "react-component", + "ui" ], - "publishConfig": { - "registry": "https://registry.npmjs.org/" + "homepage": "http://ant.design/", + "bugs": { + "url": "https://github.com/ant-design/ant-design/issues" }, "repository": { "type": "git", "url": "https://github.com/ant-design/ant-design" }, - "bugs": { - "url": "https://github.com/ant-design/ant-design/issues" - }, - "main": "lib/index.js", - "module": "es/index.js", + "license": "MIT", + "contributors": [ + "ant" + ], "files": [ "dist", "lib", "es" ], + "sideEffects": [ + "dist/*", + "es/**/style/*", + "lib/**/style/*", + "*.less" + ], + "main": "lib/index.js", + "module": "es/index.js", "typings": "lib/index.d.ts", - "license": "MIT", - "peerDependencies": { - "react": ">=16.0.0", - "react-dom": ">=16.0.0" + "scripts": { + "api-collection": "antd-tools run api-collection", + "authors": "git log --format='%aN <%aE>' | sort -u | grep -v 'users.noreply.github.com' | grep -v 'gitter.im' | grep -v '.local>' | grep -v 'alibaba-inc.com' | grep -v 'alipay.com' | grep -v 'taobao.com' > AUTHORS.txt", + "bundlesize": "bundlesize", + "check-commit": "node ./scripts/check-commit.js", + "compile": "antd-tools run compile", + "predeploy": "antd-tools run clean && npm run site && cp netlify.toml CNAME _site && cp .circleci/config.yml _site", + "deploy": "bisheng gh-pages --push-only", + "deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages", + "dist": "antd-tools run dist", + "lint": "npm run lint:tsc && npm run lint:script && npm run lint:demo && npm run lint:style && npm run lint:deps", + "lint-fix": "npm run lint-fix:script && npm run lint-fix:demo && npm run lint-fix:style", + "lint-fix:demo": "eslint-tinker ./components/*/demo/*.md", + "lint-fix:script": "npm run lint:script -- --fix", + "lint-fix:style": "npm run lint:style -- --fix", + "lint:demo": "cross-env RUN_ENV=DEMO eslint components/*/demo/*.md --ext '.md'", + "lint:deps": "antd-tools run deps-lint", + "lint:md": "remark components/", + "lint:script": "eslint . --ext '.js,.jsx,.ts,.tsx'", + "lint:style": "stylelint '{site,components}/**/*.less' --syntax less", + "lint:tsc": "npm run tsc", + "pre-publish": "npm run check-commit && npm run test-all", + "prettier": "prettier -c --write '**/*'", + "pretty-quick": "pretty-quick", + "pub": "antd-tools run pub", + "prepublish": "antd-tools run guard", + "site": "cross-env NODE_ICU_DATA=node_modules/full-icu bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js", + "sort": "npx sort-package-json", + "sort-api": "antd-tools run sort-api-table", + "start": "rimraf _site && mkdir _site && node ./scripts/generateColorLess.js && cross-env NODE_ENV=development bisheng start -c ./site/bisheng.config.js", + "start:preact": "node ./scripts/generateColorLess.js && cross-env NODE_ENV=development REACT_ENV=preact bisheng start -c ./site/bisheng.config.js", + "test": "jest --config .jest.js --no-cache", + "test-all": "./scripts/test-all.sh", + "test-node": "jest --config .jest.node.js --no-cache", + "tsc": "tsc" }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "browserslist": [ + "last 2 version", + "Firefox ESR", + "> 1%", + "ie >= 9" + ], "dependencies": { "@ant-design/create-react-context": "^0.2.4", "@ant-design/icons": "^4.0.0-alpha.7", @@ -115,7 +160,7 @@ "antd-theme-generator": "^1.1.6", "babel-eslint": "^10.0.1", "babel-plugin-add-react-displayname": "^0.0.5", - "bisheng": "^1.3.0", + "bisheng": "^1.3.1-alpha.0", "bisheng-plugin-antd": "^1.2.1", "bisheng-plugin-description": "^0.1.4", "bisheng-plugin-react": "^1.1.0", @@ -141,7 +186,6 @@ "eslint-plugin-react": "^7.14.2", "eslint-tinker": "^0.5.0", "fetch-jsonp": "^1.1.3", - "fs-extra": "^8.1.0", "full-icu": "^1.3.0", "glob": "^7.1.4", "husky": "^3.0.2", @@ -168,7 +212,6 @@ "react-copy-to-clipboard": "^5.0.1", "react-dnd": "^9.0.0", "react-dnd-html5-backend": "^9.0.0", - "react-document-title": "^2.0.3", "react-dom": "^16.9.0", "react-github-button": "^0.1.11", "react-helmet": "^6.0.0-beta", @@ -196,58 +239,13 @@ "xhr2": "^0.2.0", "yaml-front-matter": "^4.0.0" }, - "scripts": { - "test": "jest --config .jest.js --no-cache", - "test-node": "jest --config .jest.node.js --no-cache", - "test-all": "./scripts/test-all.sh", - "check-commit": "node ./scripts/check-commit.js", - "lint": "npm run lint:tsc && npm run lint:script && npm run lint:demo && npm run lint:style && npm run lint:deps", - "lint:deps": "antd-tools run deps-lint", - "lint:tsc": "npm run tsc", - "lint:script": "eslint . --ext '.js,.jsx,.ts,.tsx'", - "lint:md": "remark components/", - "lint:demo": "cross-env RUN_ENV=DEMO eslint components/*/demo/*.md --ext '.md'", - "lint:style": "stylelint '{site,components}/**/*.less' --syntax less", - "lint-fix": "npm run lint-fix:script && npm run lint-fix:demo && npm run lint-fix:style", - "lint-fix:script": "npm run lint:script -- --fix", - "lint-fix:demo": "eslint-tinker ./components/*/demo/*.md", - "lint-fix:style": "npm run lint:style -- --fix", - "sort-api": "antd-tools run sort-api-table", - "api-collection": "antd-tools run api-collection", - "dist": "antd-tools run dist", - "bundlesize": "bundlesize", - "compile": "antd-tools run compile", - "tsc": "tsc", - "start": "rimraf _site && mkdir _site && node ./scripts/generateColorLess.js && cross-env NODE_ENV=development bisheng start -c ./site/bisheng.config.js", - "start:preact": "node ./scripts/generateColorLess.js && cross-env NODE_ENV=development REACT_ENV=preact bisheng start -c ./site/bisheng.config.js", - "site": "cross-env NODE_ICU_DATA=node_modules/full-icu bisheng build --ssr -c ./site/bisheng.config.js && node ./scripts/generateColorLess.js", - "predeploy": "antd-tools run clean && npm run site && cp netlify.toml CNAME _site && cp .circleci/config.yml _site", - "deploy": "bisheng gh-pages --push-only", - "deploy:china-mirror": "git checkout gh-pages && git pull origin gh-pages && git push git@gitee.com:ant-design/ant-design.git gh-pages", - "pub": "antd-tools run pub", - "prepublish": "antd-tools run guard", - "pre-publish": "npm run check-commit && npm run test-all", - "authors": "git log --format='%aN <%aE>' | sort -u | grep -v 'users.noreply.github.com' | grep -v 'gitter.im' | grep -v '.local>' | grep -v 'alibaba-inc.com' | grep -v 'alipay.com' | grep -v 'taobao.com' > AUTHORS.txt", - "prettier": "prettier -c --write '**/*'", - "pretty-quick": "pretty-quick" + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" }, - "husky": { - "hooks": { - "pre-commit": "pretty-quick --staged" - } + "publishConfig": { + "registry": "https://registry.npmjs.org/" }, - "sideEffects": [ - "dist/*", - "es/**/style/*", - "lib/**/style/*", - "*.less" - ], - "browserslist": [ - "last 2 version", - "Firefox ESR", - "> 1%", - "ie >= 9" - ], "bundlesize": [ { "path": "./dist/antd.min.js", @@ -257,5 +255,6 @@ "path": "./dist/antd.min.css", "maxSize": "60 kB" } - ] + ], + "title": "Ant Design" } diff --git a/scripts/check-demo.js b/scripts/check-demo.js index 9443d23487..d903f7cdfc 100644 --- a/scripts/check-demo.js +++ b/scripts/check-demo.js @@ -1,7 +1,7 @@ const path = require('path'); const yfm = require('yaml-front-matter'); const glob = require('glob'); -const fs = require('fs-extra'); +const fs = require('fs'); const demoFiles = glob.sync(path.join(process.cwd(), 'components/**/demo/*.md')); // eslint-disable-next-line no-restricted-syntax diff --git a/site/theme/en-US.js b/site/theme/en-US.js index de298c9f90..ba9ca7fb6a 100644 --- a/site/theme/en-US.js +++ b/site/theme/en-US.js @@ -31,7 +31,7 @@ module.exports = { 'app.home.design-language': 'Design Language', 'app.home.solution': 'Solution', 'app.home.components-explain': - 'Based on the Ant Design language, we have provided a suite of out-of-the-box with high quality for developing and serving enterprise background applications, including the official React implementation and Angular, Vue implementations', + 'Based on the Ant Design language, we have provided a suite of out-of-the-box with high quality for developing and serving enterprise background applications, including the official React UI library and Angular, Vue implementations', 'app.home.product-pro-slogan': 'Out-of-the-box front-end / Design solution', 'app.home.product-mobile-slogan': "antd-mobile is the implementation of Ant Design's mobile specification", diff --git a/site/theme/static/template.html b/site/theme/static/template.html index b650c28e9d..bde0cbc79f 100644 --- a/site/theme/static/template.html +++ b/site/theme/static/template.html @@ -1,14 +1,11 @@ - + - - {% if title %}{{ title }}{% else %}Ant Design - A UI Design Language{% endif %} + {% if title %}{{ title }}{% else %}{% endif %} + {% if meta %}{{ meta | safe }}{% endif %} - {/* eslint-disable-next-line */} -
- {isNotTranslated && ( - - This article has not been translated yet. Wanna help us out?  - - See this issue on GitHub. - - - } - /> - )} -

- {title[locale] || title} - {!subtitle || locale === 'en-US' ? null : {subtitle}} - } - filename={filename} - /> -

- {!description - ? null - : utils.toReactComponent( - ['section', { className: 'markdown' }].concat(getChildren(description)), - )} - {!content.toc || content.toc.length <= 1 || meta.toc === false ? null : ( - - {utils.toReactComponent( - ['ul', { className: 'toc' }].concat(getChildren(content.toc)), - )} - - )} - {this.getArticle( - utils.toReactComponent( - ['section', { className: 'markdown' }].concat(getChildren(content.content)), - ), - )} - {utils.toReactComponent( - [ - 'section', - { - className: 'markdown api-container', - }, - ].concat(getChildren(content.api || ['placeholder'])), - )} -
- + /* eslint-disable-next-line */ +
+ + {helmetTitle && {helmetTitle}} + {helmetTitle && } + {metaDesc && } + + {isNotTranslated && ( + + This article has not been translated yet. Wanna help us out?  + + See this issue on GitHub. + + + } + /> + )} +

+ {title[locale] || title} + {!subtitle || locale === 'en-US' ? null : {subtitle}} + } filename={filename} /> +

+ {!description + ? null + : utils.toReactComponent( + ['section', { className: 'markdown' }].concat(getChildren(description)), + )} + {!content.toc || content.toc.length <= 1 || meta.toc === false ? null : ( + + {utils.toReactComponent(['ul', { className: 'toc' }].concat(getChildren(content.toc)))} + + )} + {this.getArticle( + utils.toReactComponent( + ['section', { className: 'markdown' }].concat(getChildren(content.content)), + ), + )} + {utils.toReactComponent( + [ + 'section', + { + className: 'markdown api-container', + }, + ].concat(getChildren(content.api || ['placeholder'])), + )} +
); } } diff --git a/site/theme/template/Content/ComponentDoc.jsx b/site/theme/template/Content/ComponentDoc.jsx index a0e4a888b3..b2e1a76f50 100644 --- a/site/theme/template/Content/ComponentDoc.jsx +++ b/site/theme/template/Content/ComponentDoc.jsx @@ -1,13 +1,13 @@ import React from 'react'; -import DocumentTitle from 'react-document-title'; +import { Helmet } from 'react-helmet'; import { FormattedMessage, injectIntl } from 'react-intl'; import classNames from 'classnames'; import { Row, Col, Affix, Tooltip } from 'antd'; import { getChildren } from 'jsonml.js/lib/utils'; +import { AppstoreFilled, Appstore } from '@ant-design/icons'; import Demo from './Demo'; import EditButton from './EditButton'; -import Icon from '../Icon'; -import { ping } from '../utils'; +import { ping, getMetaDescription } from '../utils'; class ComponentDoc extends React.Component { state = { @@ -107,66 +107,70 @@ class ComponentDoc extends React.Component { const articleClassName = classNames({ 'show-riddle-button': showRiddleButton, }); + const helmetTitle = `${subtitle || ''} ${title[locale] || title} - Ant Design`; + const contentChild = getMetaDescription(getChildren(content)); + return ( - -
- -
    - {jumper} -
-
-
-

- {title[locale] || title} - {!subtitle ? null : {subtitle}} - } - filename={filename} - /> -

- {utils.toReactComponent( - ['section', { className: 'markdown' }].concat(getChildren(content)), - )} -

- - - } - > - + + {helmetTitle && {helmetTitle}} + {helmetTitle && } + {contentChild && } + + +
    + {jumper} +
+
+
+

+ {title[locale] || title} + {!subtitle ? null : {subtitle}} + } + filename={filename} + /> +

+ {utils.toReactComponent( + ['section', { className: 'markdown' }].concat(getChildren(content)), + )} +

+ + - -

-
- - - {leftChildren} + + {expandAll ? : } + +
+

+
+ + + {leftChildren} + + {isSingleCol ? null : ( + + {rightChildren} - {isSingleCol ? null : ( - - {rightChildren} - - )} - - {utils.toReactComponent( - [ - 'section', - { - className: 'markdown api-container', - }, - ].concat(getChildren(doc.api || ['placeholder'])), )} -
-
+ + {utils.toReactComponent( + [ + 'section', + { + className: 'markdown api-container', + }, + ].concat(getChildren(doc.api || ['placeholder'])), + )} + ); } } diff --git a/site/theme/template/Home/index.jsx b/site/theme/template/Home/index.jsx index 7b5124638e..114f5c126f 100644 --- a/site/theme/template/Home/index.jsx +++ b/site/theme/template/Home/index.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { injectIntl } from 'react-intl'; -import DocumentTitle from 'react-document-title'; +import { Helmet } from 'react-helmet'; import PropTypes from 'prop-types'; import Banner from './Banner'; import Page1 from './Page1'; @@ -69,16 +69,17 @@ class Home extends React.Component { const { isMobile } = this.context; const childProps = { ...this.props, isMobile, locale: intl.locale }; return ( - - <> -