未验证 提交 785c1322 编写于 作者: 陈帅 提交者: GitHub

meger feature to master (#16421)

* use ul in list

* update snapshot

* update comment

* feat: TreeSelect support `showSearch` in multiple mode (#15933)

* update rc-tree-select

* typo

* update desc & snapshot

* update desc & snapshot

* check default showSearch

* feat: table customizing variable (#15971)

* feat: added table selected row color variable

* fix: @table-selected-row-color default is inherit

* feat: Upload support customize previewFile (#15984)

* support preview file

* use promise

* dealy load

* use canvas of render

* use domHook of test

* update demo

* add snapshot

* update types

* update testcase

* feat: form customizing variables (#15954)

* fix: added styling form input background-color

* feat: added '@form-warning-input-bg' variable

* feat: added '@form-error-input-bg' variable

* use li wrap with comment

* feat: Support append theme less file with less-variable (#16118)

* add override

* add override support

* update doc

* feat: dropdown support set right icon

* docs: update doc of dropdown component

* style: format dropdown-button.md

* test: update updateSnapshot

* style: format dropdown-button.md

* test: update updateSnapshot

* test: update updateSnapshot

* style: change style of dropdown-button demo

* fix: fix document table order

* feat: Support SkeletonAvatarProps.size accept number (#16078) (#16128)

* chore:update style of demo

* feat: Notification functions accept top, bottom and getContainer as arguments

* drawer: add afterVisibleChange

* rm onVisibleChange

* update

* feat: 🇭🇷 hr_HR locale (#16258)

* Added Croatian locale

* fixed lint error

*  Add test cases for hr_HR

* 📝 update i18n documentation

* feat:  add `htmlFor` in Form.Item (#16278)

* add htmlFor in Form.Item

* update doc

* feat: Button support `link` type (#16289)

close #15892

* feat: Add Timeline.Item.position (#16148) (#16193)

* fix: Timeline.pendingDot interface documentation there is a small problem (#16177)

* feat: Add Timeline.Item.position (#16148)

* doc: add version infomation for Timeline.Item.position

* refactor: Update Tree & TreeSelect deps (#16330)

* use CSSMotion

* update snapshot

* feat: Collapse support `expandIconPosition` (#16365)

* update doc

* support expandIconPosition

* update snapshot

* feat: Breadcrumb  support DropDown (#16315)

* breadcrumbs support drop down menu

* update doc

* add require less

* fix test

* fix md doc

* less code

* fix  style warning

* update snap

* add children render test

* feat: TreeNode support checkable

* feat: add optional to support top and left slick dots (#16186) (#16225)

* add optional to support top and left slick dots

* update carousel snapshot

* Update doc, add placement demo

* update carousel placement demo snapshots

* rename dots placement to position

* update vertical as deprecated

* rename dotsPosition to dotPosition

* refine code

* add warning testcase for vertical

* remove unused warning

* update expression

* Additional test case for dotPosition

* refactor: Upgrade `rc-tree-select` to support pure React motion (#16402)

* upgrade `rc-tree-select`

* update snapshot

* 3.17.0 changelog

* fix warning

* fix review warning
上级 20ddb402
此差异已折叠。
此差异已折叠。
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;
const spyProp = properties[propName];
if (typeof spyProp === 'function') {
// If is a function
Element.prototype[propName] = function spyFunc(...args) {
return spyProp.call(this, originDescriptor, ...args);
};
} else {
// Otherwise tread as a property
Object.defineProperty(Element.prototype, propName, {
...spyProp,
set(value) {
if (spyProp.set) {
return spyProp.set.call(this, originDescriptor, value);
}
return originDescriptor.set(value);
},
get() {
if (spyProp.get) {
return spyProp.get.call(this, originDescriptor);
}
return originDescriptor.get();
},
});
}
});
return {
mockRestore() {
propNames.forEach(propName => {
const originDescriptor = originDescriptors[propName];
if (typeof originDescriptor === 'function') {
Element.prototype[propName] = originDescriptor;
} else {
Object.defineProperty(Element.prototype, propName, originDescriptor);
}
});
},
};
}
export function spyElementPrototype(Element, propName, property) {
return spyElementPrototypes(Element, {
[propName]: property,
});
}
import * as React from 'react';
type MotionFunc = (element: HTMLElement) => React.CSSProperties;
interface Motion {
visible?: boolean;
motionName?: string; // It also support object, but we only use string here.
motionAppear?: boolean;
motionEnter?: boolean;
motionLeave?: boolean;
motionLeaveImmediately?: boolean; // Trigger leave motion immediately
removeOnLeave?: boolean;
leavedClassName?: string;
onAppearStart?: MotionFunc;
onAppearActive?: MotionFunc;
onAppearEnd?: MotionFunc;
onEnterStart?: MotionFunc;
onEnterActive?: MotionFunc;
onEnterEnd?: MotionFunc;
onLeaveStart?: MotionFunc;
onLeaveActive?: MotionFunc;
onLeaveEnd?: MotionFunc;
}
// ================== Collapse Motion ==================
const getCollapsedHeight: MotionFunc = () => ({ height: 0, opacity: 0 });
const getRealHeight: MotionFunc = node => ({ height: node.scrollHeight, opacity: 1 });
const getCurrentHeight: MotionFunc = node => ({ height: node.offsetHeight });
export const collapseMotion: Motion = {
motionName: 'ant-motion-collapse',
onAppearStart: getCollapsedHeight,
onEnterStart: getCollapsedHeight,
onAppearActive: getRealHeight,
onEnterActive: getRealHeight,
onLeaveStart: getCurrentHeight,
onLeaveActive: getCollapsedHeight,
};
/**
* Deprecated. We should replace the animation with pure react motion instead of modify style directly.
* If you are creating new component with animation, please use `./motion`.
*/
import cssAnimation from 'css-animation';
import raf from 'raf';
function animate(node: HTMLElement, show: boolean, done: () => void) {
let height: number;
let requestAnimationFrameId: number;
return cssAnimation(node, 'ant-motion-collapse', {
return cssAnimation(node, 'ant-motion-collapse-legacy', {
start() {
if (!show) {
node.style.height = `${node.offsetHeight}px`;
......
@import '../../style/themes/default';
@import '../../style/themes/index';
.@{ant-prefix}-affix {
position: fixed;
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@alert-prefix-cls: ~'@{ant-prefix}-alert';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@anchor-border-width: 2px;
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@avatar-prefix-cls: ~'@{ant-prefix}-avatar';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@backtop-prefix-cls: ~'@{ant-prefix}-back-top';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@badge-prefix-cls: ~'@{ant-prefix}-badge';
......
......@@ -3,12 +3,15 @@ import * as PropTypes from 'prop-types';
import { cloneElement } from 'react';
import classNames from 'classnames';
import BreadcrumbItem from './BreadcrumbItem';
import Menu from '../menu';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import { Omit } from '../_util/type';
export interface Route {
path: string;
breadcrumbName: string;
children: Omit<Route, 'children'>[];
}
export interface BreadcrumbProps {
......@@ -69,7 +72,44 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
'see: https://u.ant.design/item-render.',
);
}
genForRoutes = ({
routes = [],
params = {},
separator,
itemRender = defaultItemRender,
}: BreadcrumbProps) => {
const paths: string[] = [];
return routes.map(route => {
route.path = route.path || '';
let path = route.path.replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key]);
});
if (path) {
paths.push(path);
}
// generated overlay by route.children
let overlay = null;
if (route.children && route.children.length) {
overlay = (
<Menu>
{route.children.map(child => (
<Menu.Item key={child.breadcrumbName || child.path}>
{itemRender(child, params, routes, paths)}
</Menu.Item>
))}
</Menu>
);
}
return (
<BreadcrumbItem overlay={overlay} separator={separator} key={route.breadcrumbName || path}>
{itemRender(route, params, routes, paths)}
</BreadcrumbItem>
);
});
};
renderBreadcrumb = ({ getPrefixCls }: ConfigConsumerProps) => {
let crumbs;
const {
......@@ -78,28 +118,12 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
style,
className,
routes,
params = {},
children,
itemRender = defaultItemRender,
} = this.props;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
if (routes && routes.length > 0) {
const paths: string[] = [];
crumbs = routes.map(route => {
route.path = route.path || '';
let path: string = route.path.replace(/^\//, '');
Object.keys(params).forEach(key => {
path = path.replace(`:${key}`, params[key]);
});
if (path) {
paths.push(path);
}
return (
<BreadcrumbItem separator={separator} key={route.breadcrumbName || path}>
{itemRender(route, params, routes, paths)}
</BreadcrumbItem>
);
});
// generated by route
crumbs = this.genForRoutes(this.props);
} else if (children) {
crumbs = React.Children.map(children, (element: any, index) => {
if (!element) {
......
import * as React from 'react';
import * as PropTypes from 'prop-types';
import DropDown, { DropDownProps } from '../dropdown/dropdown';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface BreadcrumbItemProps {
prefixCls?: string;
separator?: React.ReactNode;
href?: string;
overlay?: DropDownProps['overlay'];
onClick?: React.MouseEventHandler<HTMLAnchorElement | HTMLSpanElement>;
}
......@@ -23,7 +26,13 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
};
renderBreadcrumbItem = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, separator, children, ...restProps } = this.props;
const {
prefixCls: customizePrefixCls,
separator,
children,
overlay,
...restProps
} = this.props;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
let link;
if ('href' in this.props) {
......@@ -39,6 +48,9 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
</span>
);
}
// wrap to dropDown
link = this.renderBreadcrumbNode(link, prefixCls);
if (children) {
return (
<span>
......@@ -50,6 +62,24 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
return null;
};
/**
* if overlay is have
* Wrap a DropDown
*/
renderBreadcrumbNode = (breadcrumbItem: React.ReactNode, prefixCls: string) => {
const { overlay } = this.props;
if (overlay) {
return (
<DropDown overlay={overlay} placement="bottomCenter">
<a className={`${prefixCls}-overlay-link`}>
{breadcrumbItem}
<Icon type="down" />
</a>
</DropDown>
);
}
return breadcrumbItem;
};
render() {
return <ConfigConsumer>{this.renderBreadcrumbItem}</ConfigConsumer>;
}
......
......@@ -51,4 +51,37 @@ describe('Breadcrumb', () => {
);
expect(wrapper).toMatchSnapshot();
});
it('should render a menu', () => {
const routes = [
{
path: 'index',
breadcrumbName: 'home',
},
{
path: 'first',
breadcrumbName: 'first',
children: [
{
path: '/general',
breadcrumbName: 'General',
},
{
path: '/layout',
breadcrumbName: 'Layout',
},
{
path: '/navigation',
breadcrumbName: 'Navigation',
},
],
},
{
path: 'second',
breadcrumbName: 'second',
},
];
const wrapper = render(<Breadcrumb routes={routes} />);
expect(wrapper).toMatchSnapshot();
});
});
......@@ -49,3 +49,78 @@ exports[`Breadcrumb should not display Breadcrumb Item when its children is fals
</span>
</div>
`;
exports[`Breadcrumb should render a menu 1`] = `
<div
class="ant-breadcrumb"
>
<span>
<span
class="ant-breadcrumb-link"
>
<a
href="#/index"
>
home
</a>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
<span>
<a
class="ant-breadcrumb-overlay-link ant-dropdown-trigger"
>
<span
class="ant-breadcrumb-link"
/>
</a>
<a
href="#/index/first"
>
first
</a>
</span>
<i
aria-label="icon: down"
class="anticon anticon-down"
>
<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>
</i>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<span
class="ant-breadcrumb-link"
>
<span>
second
</span>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
</div>
`;
......@@ -63,6 +63,93 @@ exports[`renders ./components/breadcrumb/demo/basic.md correctly 1`] = `
</div>
`;
exports[`renders ./components/breadcrumb/demo/overlay.md correctly 1`] = `
<div>
<div
class="ant-breadcrumb"
>
<span>
<span
class="ant-breadcrumb-link"
>
Ant Design
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
<span>
<span
class="ant-breadcrumb-link"
>
<a
href=""
>
Component
</a>
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
<span>
<a
class="ant-breadcrumb-overlay-link ant-dropdown-trigger"
>
<span
class="ant-breadcrumb-link"
/>
</a>
<a
href=""
>
General
</a>
</span>
<i
aria-label="icon: down"
class="anticon anticon-down"
>
<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>
</i>
<span
class="ant-breadcrumb-separator"
>
/
</span>
<span>
<span
class="ant-breadcrumb-link"
>
Button
</span>
<span
class="ant-breadcrumb-separator"
>
/
</span>
</span>
</div>
</div>
`;
exports[`renders ./components/breadcrumb/demo/router.md correctly 1`] = `
<div
class="demo"
......
......@@ -80,6 +80,7 @@ exports[`react router react router 3 1`] = `
>
<BreadcrumbItem
key="Home"
overlay={null}
separator="/"
>
<span>
......@@ -101,6 +102,7 @@ exports[`react router react router 3 1`] = `
</BreadcrumbItem>
<BreadcrumbItem
key="Application List"
overlay={null}
separator="/"
>
<span>
......@@ -122,6 +124,7 @@ exports[`react router react router 3 1`] = `
</BreadcrumbItem>
<BreadcrumbItem
key="Application:id"
overlay={null}
separator="/"
>
<span>
......@@ -143,6 +146,7 @@ exports[`react router react router 3 1`] = `
</BreadcrumbItem>
<BreadcrumbItem
key="Detail"
overlay={null}
separator="/"
>
<span>
......
......@@ -13,16 +13,20 @@ title:
The simplest use
````jsx
```jsx
import { Breadcrumb } from 'antd';
ReactDOM.render(
<Breadcrumb>
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item><a href="">Application Center</a></Breadcrumb.Item>
<Breadcrumb.Item><a href="">Application List</a></Breadcrumb.Item>
<Breadcrumb.Item>
<a href="">Application Center</a>
</Breadcrumb.Item>
<Breadcrumb.Item>
<a href="">Application List</a>
</Breadcrumb.Item>
<Breadcrumb.Item>An Application</Breadcrumb.Item>
</Breadcrumb>,
mountNode
mountNode,
);
````
```
---
order: 5
title:
zh-CN: 带下拉菜单的面包屑
en-US: Bread crumbs with drop down menu
---
## zh-CN
面包屑支持下拉菜单。
## en-US
Breadcrumbs support drop down menu.
```jsx
import { Breadcrumb, Menu } from 'antd';
const menu = (
<Menu>
<Menu.Item>
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">
General
</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">
Layout
</a>
</Menu.Item>
<Menu.Item>
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">
Navigation
</a>
</Menu.Item>
</Menu>
);
ReactDOM.render(
<div>
<Breadcrumb>
<Breadcrumb.Item>Ant Design</Breadcrumb.Item>
<Breadcrumb.Item>
<a href="">Component</a>
</Breadcrumb.Item>
<Breadcrumb.Item overlay={menu}>
<a href="">General</a>
</Breadcrumb.Item>
<Breadcrumb.Item>Button</Breadcrumb.Item>
</Breadcrumb>
</div>,
mountNode,
);
```
......@@ -15,10 +15,8 @@ title:
Used together with `react-router@2` `react-router@3`.
````jsx
import {
Router, Route, Link, hashHistory,
} from 'react-router';
```jsx
import { Router, Route, Link, hashHistory } from 'react-router';
import { Breadcrumb, Alert } from 'antd';
const Apps = () => (
......@@ -54,11 +52,11 @@ ReactDOM.render(
</Route>
</Route>
</Router>,
mountNode
mountNode,
);
````
```
````css
```css
.demo {
margin: 16px;
}
......@@ -75,4 +73,4 @@ ReactDOM.render(
.app-list {
margin-top: 16px;
}
````
```
......@@ -16,10 +16,10 @@ A breadcrumb displays the current location within a hierarchy. It allows going b
## API
| Property | Description | Type | Optional | Default |
| -------- | ----------- | ---- | -------- | ------- |
| --- | --- | --- | --- | --- |
| itemRender | Custom item renderer | (route, params, routes, paths) => ReactNode | | - |
| params | Routing parameters | object | | - |
| routes | The routing stack information of router | object\[] | | - |
| routes | The routing stack information of router | [routes\[\]](#routes) | | - |
| separator | Custom separator | string\|ReactNode | | `/` |
### Use with browserHistory
......@@ -29,19 +29,41 @@ The link of Breadcrumb item targets `#` by default, you can use `itemRender` to
```jsx
import { Link } from 'react-router';
const routes = [{
path: 'index',
 breadcrumbName: 'home'
}, {
path: 'first',
breadcrumbName: 'first'
}, {
path: 'second',
breadcrumbName: 'second'
}];
const routes = [
{
path: 'index',
breadcrumbName: 'home',
},
{
path: 'first',
breadcrumbName: 'first',
children: [
{
path: '/general',
breadcrumbName: 'General',
},
{
path: '/layout',
breadcrumbName: 'Layout',
},
{
path: '/navigation',
breadcrumbName: 'Navigation',
},
],
},
{
path: 'second',
breadcrumbName: 'second',
},
];
function itemRender(route, params, routes, paths) {
const last = routes.indexOf(route) === routes.length - 1;
return last ? <span>{route.breadcrumbName}</span> : <Link to={paths.join('/')}>{route.breadcrumbName}</Link>;
return last ? (
<span>{route.breadcrumbName}</span>
) : (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
);
}
return <Breadcrumb itemRender={itemRender} routes={routes} />;
......
......@@ -15,12 +15,36 @@ title: Breadcrumb
## API
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| --- | --- | --- | --- | --- |
| itemRender | 自定义链接函数,和 react-router 配置使用 | (route, params, routes, paths) => ReactNode | | - |
| params | 路由的参数 | object | | - |
| routes | router 的路由栈信息 | object\[] | | - |
| separator | 分隔符自定义 | string\|ReactNode | | '/' |
### Breadcrumb
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| itemRender | 自定义链接函数,和 react-router 配置使用 | (route, params, routes, paths) => ReactNode | - |
| params | 路由的参数 | object | - |
| routes | router 的路由栈信息 | [routes\[\]](#routes) | - |
| separator | 分隔符自定义 | string\|ReactNode | '/' |
### Breadcrumb.Item
| 参数 | 参数 | 类型 | 默认值 |
| --------- | -------------- | -------------------------------------- | ------ |
| href | 链接的目的地 | string | - |
| separator | 自定义的分隔符 | string\|ReactNode | '/' |
| overlay | 下来菜单的内容 | [Menu](/components/menu) \| () => Menu | - |
| onClick | 单击事件 | (e:MouseEventHandler)=>void | - |
### routes
```ts
interface Route {
path: string;
breadcrumbName: string;
children: Array<{
path: string;
breadcrumbName: string;
}>;
}
```
### 和 browserHistory 配合
......@@ -29,20 +53,43 @@ title: Breadcrumb
```jsx
import { Link } from 'react-router';
const routes = [{
path: 'index',
breadcrumbName: '首页'
}, {
path: 'first',
breadcrumbName: '一级面包屑'
}, {
path: 'second',
breadcrumbName: '当前页面'
}];
const routes = [
{
path: 'index',
breadcrumbName: 'home',
},
{
path: 'first',
breadcrumbName: 'first',
children: [
{
path: '/general',
breadcrumbName: 'General',
},
{
path: '/layout',
breadcrumbName: 'Layout',
},
{
path: '/navigation',
breadcrumbName: 'Navigation',
},
],
},
{
path: 'second',
breadcrumbName: 'second',
},
];
function itemRender(route, params, routes, paths) {
const last = routes.indexOf(route) === routes.length - 1;
return last ? <span>{route.breadcrumbName}</span> : <Link to={paths.join('/')}>{route.breadcrumbName}</Link>;
return last ? (
<span>{route.breadcrumbName}</span>
) : (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
);
}
return <Breadcrumb itemRender={itemRender} routes={routes}/>;
return <Breadcrumb itemRender={itemRender} routes={routes} />;
```
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@breadcrumb-prefix-cls: ~'@{ant-prefix}-breadcrumb';
......@@ -39,4 +39,10 @@
margin-left: 4px;
}
}
&-overlay-link {
> .@{iconfont-css-prefix} {
margin-left: 4px;
}
}
}
import '../../style/index.less';
import './index.less';
import '../../menu/style';
import '../../dropdown/style';
......@@ -34,6 +34,14 @@ exports[`renders ./components/button/demo/basic.md correctly 1`] = `
Danger
</span>
</button>
<button
class="ant-btn ant-btn-link"
type="button"
>
<span>
Link
</span>
</button>
</div>
`;
......@@ -68,7 +76,15 @@ exports[`renders ./components/button/demo/block.md correctly 1`] = `
type="button"
>
<span>
danger
Danger
</span>
</button>
<button
class="ant-btn ant-btn-link ant-btn-block"
type="button"
>
<span>
Link
</span>
</button>
</div>
......@@ -332,6 +348,24 @@ exports[`renders ./components/button/demo/disabled.md correctly 1`] = `
Dashed(disabled)
</span>
</button>
<br />
<button
class="ant-btn ant-btn-link"
type="button"
>
<span>
Link
</span>
</button>
<button
class="ant-btn ant-btn-link"
disabled=""
type="button"
>
<span>
Link(disabled)
</span>
</button>
<div
style="padding:8px 8px 0 8px;background:rgb(190, 200, 200)"
>
......@@ -392,6 +426,14 @@ exports[`renders ./components/button/demo/ghost.md correctly 1`] = `
danger
</span>
</button>
<button
class="ant-btn ant-btn-link ant-btn-background-ghost"
type="button"
>
<span>
link
</span>
</button>
</div>
`;
......@@ -895,6 +937,14 @@ exports[`renders ./components/button/demo/size.md correctly 1`] = `
Danger
</span>
</button>
<button
class="ant-btn ant-btn-link ant-btn-lg"
type="button"
>
<span>
Link
</span>
</button>
<br />
<button
class="ant-btn ant-btn-primary ant-btn-circle ant-btn-lg ant-btn-icon-only"
......
......@@ -40,7 +40,7 @@ function insertSpace(child: React.ReactChild, needInserted: boolean) {
return child;
}
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'danger');
const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'danger', 'link');
export type ButtonType = (typeof ButtonTypes)[number];
const ButtonShapes = tuple('circle', 'circle-outline', 'round');
export type ButtonShape = (typeof ButtonShapes)[number];
......@@ -266,20 +266,24 @@ class Button extends React.Component<ButtonProps, ButtonState> {
// React does not recognize the `htmlType` prop on a DOM element. Here we pick it out of `rest`.
const { htmlType, ...otherProps } = rest as NativeButtonProps;
return (
<Wave>
<button
{...otherProps as NativeButtonProps}
type={htmlType}
className={classes}
onClick={this.handleClick}
ref={this.saveButtonRef}
>
{iconNode}
{kids}
</button>
</Wave>
const buttonNode = (
<button
{...otherProps as NativeButtonProps}
type={htmlType}
className={classes}
onClick={this.handleClick}
ref={this.saveButtonRef}
>
{iconNode}
{kids}
</button>
);
if (type === 'link') {
return buttonNode;
}
return <Wave>{buttonNode}</Wave>;
};
render() {
......
......@@ -22,6 +22,7 @@ ReactDOM.render(
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="danger">Danger</Button>
<Button type="link">Link</Button>
</div>,
mountNode
);
......
......@@ -21,7 +21,8 @@ ReactDOM.render(
<Button type="primary" block>Primary</Button>
<Button block>Default</Button>
<Button type="dashed" block>Dashed</Button>
<Button type="danger" block>danger</Button>
<Button type="danger" block>Danger</Button>
<Button type="link" block>Link</Button>
</div>,
mountNode
);
......
......@@ -26,6 +26,9 @@ ReactDOM.render(
<br />
<Button type="dashed">Dashed</Button>
<Button type="dashed" disabled>Dashed(disabled)</Button>
<br />
<Button type="link">Link</Button>
<Button type="link" disabled>Link(disabled)</Button>
<div style={{ padding: '8px 8px 0 8px', background: 'rgb(190, 200, 200)' }}>
<Button ghost>Ghost</Button>
<Button ghost disabled>Ghost(disabled)</Button>
......
......@@ -22,6 +22,7 @@ ReactDOM.render(
<Button ghost>Default</Button>
<Button type="dashed" ghost>Dashed</Button>
<Button type="danger" ghost>danger</Button>
<Button type="link" ghost>link</Button>
</div>,
mountNode
);
......
......@@ -43,6 +43,7 @@ class ButtonSize extends React.Component {
<Button size={size}>Normal</Button>
<Button type="dashed" size={size}>Dashed</Button>
<Button type="danger" size={size}>Danger</Button>
<Button type="link" size={size}>Link</Button>
<br />
<Button type="primary" shape="circle" icon="download" size={size} />
<Button type="primary" shape="round" icon="download" size={size}>Download</Button>
......
......@@ -25,7 +25,7 @@ To get a customized button, just set `type`/`shape`/`size`/`loading`/`disabled`.
| shape | can be set to `circle`, `round` or omitted | string | - |
| size | can be set to `small` `large` or omitted | string | `default` |
| target | same as target attribute of a, works when href is specified | string | - |
| type | can be set to `primary` `ghost` `dashed` `danger`(added in 2.7) or omitted (meaning `default`) | string | `default` |
| type | can be set to `primary` `ghost` `dashed` `danger` `link`(added in 3.17) or omitted (meaning `default`) | string | `default` |
| onClick | set the handler to handle `click` event | (event) => void | - |
| block | option to fit button width to its parent width | boolean | `false` |
......
......@@ -18,7 +18,7 @@ subtitle: 按钮
按钮的属性说明如下:
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| --- | --- | --- | --- | --- |
| disabled | 按钮失效状态 | boolean | `false` |
| ghost | 幽灵属性,使按钮背景透明,版本 2.7 中增加 | boolean | false |
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - |
......@@ -28,7 +28,7 @@ subtitle: 按钮
| shape | 设置按钮形状,可选值为 `circle``round` 或者不设 | string | - |
| size | 设置按钮大小,可选值为 `small` `large` 或者不设 | string | `default` |
| target | 相当于 a 链接的 target 属性,href 存在时生效 | string | - |
| type | 设置按钮类型,可选值为 `primary` `dashed` `danger`(版本 2.7 中增加) 或者不设 | string | - |
| type | 设置按钮类型,可选值为 `primary` `dashed` `danger` `link`(3.17 中增加) 或者不设 | string | - |
| onClick | 点击按钮时的回调 | (event) => void | - |
| block | 将按钮宽度调整为其父宽度的选项 | boolean | `false` |
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
......@@ -69,6 +69,10 @@
.btn-danger;
}
&-link {
.btn-link;
}
&-round {
.btn-round(@btn-prefix-cls);
}
......@@ -165,6 +169,12 @@
.button-variant-ghost(@btn-danger-color);
}
&-background-ghost&-link {
.button-variant-ghost(@link-color; transparent);
color: @component-background;
}
&-two-chinese-chars::first-letter {
letter-spacing: 0.34em;
}
......
......@@ -7,7 +7,7 @@
border-radius: @border-radius;
}
.button-disabled() {
.button-disabled(@color: @btn-disable-color; @background: @btn-disable-bg; @border: @btn-disable-border) {
&-disabled,
&.disabled,
&[disabled] {
......@@ -16,7 +16,7 @@
&:focus,
&:active,
&.active {
.button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);
.button-color(@color; @background; @border);
text-shadow: none;
box-shadow: none;
......@@ -86,17 +86,27 @@
}
.button-disabled();
}
.button-variant-ghost(@color) {
.button-color(@color; transparent; @color);
.button-variant-ghost(@color; @border: @color) {
.button-color(@color; transparent; @border);
text-shadow: none;
&:hover,
&:focus {
.button-color(~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `);
& when (@border = transparent) {
.button-color(~`colorPalette('@{color}', 5) `; transparent; transparent);
}
& when not(@border = transparent) {
.button-color(~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `);
}
}
&:active,
&.active {
.button-color(~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `);
& when (@border = transparent) {
.button-color(~`colorPalette('@{color}', 7) `; transparent; transparent);
}
& when not(@border = transparent) {
.button-color(~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `);
}
}
.button-disabled();
}
......@@ -226,6 +236,18 @@
.btn-danger() {
.button-variant-danger(@btn-danger-color, @btn-danger-bg, @btn-danger-border);
}
// link button style
.btn-link() {
.button-variant-other(@link-color, transparent, transparent);
box-shadow: none;
&:hover,
&:focus,
&:active {
border-color: transparent;
}
.button-disabled(@disabled-color; transparent; transparent);
}
// round button
.btn-round(@btnClassName: btn) {
.button-size(@btn-circle-size; 0 @btn-circle-size / 2; @font-size-base + 2px; @btn-circle-size);
......
import hr_HR from '../../date-picker/locale/hr_HR';
export default hr_HR;
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@full-calendar-prefix-cls: ~'@{ant-prefix}-fullcalendar';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@card-prefix-cls: ~'@{ant-prefix}-card';
......
......@@ -180,7 +180,7 @@ exports[`renders ./components/carousel/demo/autoplay.md correctly 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -396,7 +396,7 @@ exports[`renders ./components/carousel/demo/basic.md correctly 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -522,7 +522,7 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -558,218 +558,302 @@ exports[`renders ./components/carousel/demo/fade.md correctly 1`] = `
</div>
`;
exports[`renders ./components/carousel/demo/vertical.md correctly 1`] = `
<div
class="ant-carousel ant-carousel-vertical"
>
exports[`renders ./components/carousel/demo/position.md correctly 1`] = `
<div>
<div
class="slick-slider slick-vertical slick-initialized"
dir="ltr"
class="ant-radio-group ant-radio-group-outline"
style="margin-bottom:8px"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"
>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="top"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Top
</span>
</label>
<label
class="ant-radio-button-wrapper"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="bottom"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Bottom
</span>
</label>
<label
class="ant-radio-button-wrapper"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="left"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Left
</span>
</label>
<label
class="ant-radio-button-wrapper"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="right"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Right
</span>
</label>
</div>
<div
class="ant-carousel"
>
<div
class="slick-list"
class="slick-slider slick-initialized"
dir="ltr"
>
<div
class="slick-track"
style="width:900%;left:-100%"
class="slick-list"
>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="-1"
style="width:11.11111111111111%"
tabindex="-1"
class="slick-track"
style="width:900%;left:-100%"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="-1"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
1
</h3>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
1
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide"
data-index="1"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
2
</h3>
<div
aria-hidden="true"
class="slick-slide"
data-index="1"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
2
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide"
data-index="2"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
3
</h3>
<div
aria-hidden="true"
class="slick-slide"
data-index="2"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
3
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide"
data-index="3"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
<div
aria-hidden="true"
class="slick-slide"
data-index="3"
style="outline:none;width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="4"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
1
</h3>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="4"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
1
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="5"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
2
</h3>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="5"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
2
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="6"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
3
</h3>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="6"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
3
</h3>
</div>
</div>
</div>
</div>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="7"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
<div
aria-hidden="true"
class="slick-slide slick-cloned"
data-index="7"
style="width:11.11111111111111%"
tabindex="-1"
>
<div>
<div
style="width:100%;display:inline-block"
tabindex="-1"
>
<h3>
4
</h3>
</div>
</div>
</div>
</div>
</div>
</div>
<ul
class="slick-dots"
style="display:block"
>
<li
class="slick-active"
>
<button>
1
</button>
</li>
<li
class=""
<ul
class="slick-dots slick-dots-top"
style="display:block"
>
<button>
2
</button>
</li>
<li
class=""
>
<button>
3
</button>
</li>
<li
class=""
>
<button>
4
</button>
</li>
</ul>
<li
class="slick-active"
>
<button>
1
</button>
</li>
<li
class=""
>
<button>
2
</button>
</li>
<li
class=""
>
<button>
3
</button>
</li>
<li
class=""
>
<button>
4
</button>
</li>
</ul>
</div>
</div>
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Carousel should works for dotPosition bottom 1`] = `
<div
class="ant-carousel"
>
<div
class="slick-slider slick-initialized"
>
<div
class="slick-list"
>
<div
class="slick-track"
style="opacity: 1; transform: translate3d(0px, 0px, 0px);"
>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline: none; width: 0px;"
tabindex="-1"
>
<div>
<div
style="width: 100%; display: inline-block;"
tabindex="-1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Carousel should works for dotPosition left 1`] = `
<div
class="ant-carousel ant-carousel-vertical"
>
<div
class="slick-slider slick-vertical slick-initialized"
>
<div
class="slick-list"
>
<div
class="slick-track"
style="opacity: 1; transform: translate3d(0px, 0px, 0px);"
>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline: none; width: 0px;"
tabindex="-1"
>
<div>
<div
style="width: 100%; display: inline-block;"
tabindex="-1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Carousel should works for dotPosition right 1`] = `
<div
class="ant-carousel ant-carousel-vertical"
>
<div
class="slick-slider slick-vertical slick-initialized"
>
<div
class="slick-list"
>
<div
class="slick-track"
style="opacity: 1; transform: translate3d(0px, 0px, 0px);"
>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline: none; width: 0px;"
tabindex="-1"
>
<div>
<div
style="width: 100%; display: inline-block;"
tabindex="-1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Carousel should works for dotPosition top 1`] = `
<div
class="ant-carousel"
>
<div
class="slick-slider slick-initialized"
>
<div
class="slick-list"
>
<div
class="slick-track"
style="opacity: 1; transform: translate3d(0px, 0px, 0px);"
>
<div
aria-hidden="false"
class="slick-slide slick-active slick-current"
data-index="0"
style="outline: none; width: 0px;"
tabindex="-1"
>
<div>
<div
style="width: 100%; display: inline-block;"
tabindex="-1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
......@@ -78,4 +78,31 @@ describe('Carousel', () => {
expect(spy).toHaveBeenCalled();
expect(spy2).toHaveBeenCalledWith('resize', onWindowResized);
});
describe('should works for dotPosition', () => {
['left', 'right', 'top', 'bottom'].forEach(dotPosition => {
it(dotPosition, () => {
const wrapper = mount(
<Carousel dotPosition={dotPosition}>
<div />
</Carousel>,
);
jest.runAllTimers();
expect(wrapper.render()).toMatchSnapshot();
});
});
});
it('warning', () => {
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(
<Carousel vertical>
<div />
</Carousel>,
);
expect(warnSpy).toHaveBeenCalledWith(
'Warning: [antd: Carousel] `vertical` is deprecated, please use `dotPosition` instead.',
);
warnSpy.mockRestore();
});
});
---
order: 2
order: 3
title:
zh-CN: 渐显
en-US: Fade in
......
---
order: 2
title:
zh-CN: 位置
en-US: Position
---
## zh-CN
位置有 4 个方向。
## en-US
There are 4 position options available.
````jsx
import { Carousel, Radio } from 'antd';
class PositionCarouselDemo extends React.Component {
state = {
dotPosition: 'top',
};
handlePositionChange = ({ target: { value: dotPosition } }) => this.setState({ dotPosition });
render() {
const { dotPosition } = this.state;
return (
<div>
<Radio.Group onChange={this.handlePositionChange} value={dotPosition} style={{ marginBottom: 8 }}>
<Radio.Button value="top">Top</Radio.Button>
<Radio.Button value="bottom">Bottom</Radio.Button>
<Radio.Button value="left">Left</Radio.Button>
<Radio.Button value="right">Right</Radio.Button>
</Radio.Group>
<Carousel dotPosition={dotPosition}>
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</Carousel>
</div>
);
}
}
ReactDOM.render(<PositionCarouselDemo />, mountNode);
````
````css
/* For demo */
.ant-carousel .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel .slick-slide h3 {
color: #fff;
}
````
---
order: 1
title:
zh-CN: 垂直
en-US: Vertical
---
## zh-CN
垂直显示。
## en-US
Vertical pagination.
````jsx
import { Carousel } from 'antd';
ReactDOM.render(
<Carousel vertical>
<div><h3>1</h3></div>
<div><h3>2</h3></div>
<div><h3>3</h3></div>
<div><h3>4</h3></div>
</Carousel>,
mountNode
);
````
````css
/* For demo */
.ant-carousel .slick-slide {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel .slick-slide h3 {
color: #fff;
}
````
......@@ -14,15 +14,15 @@ A carousel component. Scales with its container.
## API
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| afterChange | Callback function called after the current index changes | function(current) | - |
| autoplay | Whether to scroll automatically | boolean | `false` |
| beforeChange | Callback function called before the current index changes | function(from, to) | - |
| dots | Whether to show the dots at the bottom of the gallery | boolean | `true` |
| easing | Transition interpolation function name | string | `linear` |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` |
| vertical | Whether to use a vertical display | boolean | `false` |
| Property | Description | Type | Default | Version |
| -------- | ----------- | ---- | ------- | ------- |
| afterChange | Callback function called after the current index changes | function(current) | - | |
| autoplay | Whether to scroll automatically | boolean | `false` | |
| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | bottom | 3.17.0 |
| dots | Whether to show the dots at the bottom of the gallery | boolean | `true` | |
| easing | Transition interpolation function name | string | `linear` | |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` | |
## Methods
......
......@@ -2,6 +2,7 @@ import * as React from 'react';
import debounce from 'lodash/debounce';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { Settings } from 'react-slick';
import warning from '../_util/warning';
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
......@@ -23,12 +24,15 @@ if (typeof window !== 'undefined') {
const SlickCarousel = require('react-slick').default;
export type CarouselEffect = 'scrollx' | 'fade';
export type DotPosition = 'top' | 'bottom' | 'left' | 'right';
// Carousel
export interface CarouselProps extends Settings {
effect?: CarouselEffect;
style?: React.CSSProperties;
prefixCls?: string;
slickGoTo?: number;
dotPosition?: DotPosition;
}
export default class Carousel extends React.Component<CarouselProps, {}> {
......@@ -47,6 +51,14 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
this.onWindowResized = debounce(this.onWindowResized, 500, {
leading: false,
});
if ('vertical' in this.props) {
warning(
!this.props.vertical,
'Carousel',
'`vertical` is deprecated, please use `dotPosition` instead.',
);
}
}
componentDidMount() {
......@@ -90,6 +102,15 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
this.slick.slickGoTo(slide, dontAnimate);
}
getDotPosition(): DotPosition {
if (this.props.dotPosition) {
return this.props.dotPosition;
} else if ('vertical' in this.props) {
return this.props.vertical ? 'right' : 'bottom';
}
return 'bottom';
}
renderCarousel = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = {
...this.props,
......@@ -100,6 +121,10 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
}
let className = getPrefixCls('carousel', props.prefixCls);
const dotsClass = 'slick-dots';
const dotPosition = this.getDotPosition();
props.vertical = dotPosition === 'left' || dotPosition === 'right';
props.dotsClass = `${dotsClass} ${dotsClass}-${dotPosition || 'bottom'}`;
if (props.vertical) {
className = `${className} ${className}-vertical`;
}
......
......@@ -15,15 +15,15 @@ subtitle: 走马灯
## API
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| afterChange | 切换面板的回调 | function(current) | 无 |
| autoplay | 是否自动切换 | boolean | false |
| beforeChange | 切换面板的回调 | function(from, to) | 无 |
| dots | 是否显示面板指示点 | boolean | true |
| easing | 动画效果 | string | linear |
| effect | 动画效果函数,可取 scrollx, fade | string | scrollx |
| vertical | 垂直显示 | boolean | false |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| afterChange | 切换面板的回调 | function(current) | 无 | |
| autoplay | 是否自动切换 | boolean | false | |
| beforeChange | 切换面板的回调 | function(from, to) | 无 | |
| dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | bottom | 3.17.0 |
| dots | 是否显示面板指示点 | boolean | true | |
| easing | 动画效果 | string | linear | |
| effect | 动画效果函数,可取 scrollx, fade | string | scrollx | |
## 方法
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
.@{ant-prefix}-carousel {
......@@ -146,7 +146,6 @@
// Dots
.slick-dots {
position: absolute;
bottom: 12px;
display: block;
width: 100%;
height: @carousel-dot-height;
......@@ -154,6 +153,12 @@
padding: 0;
text-align: center;
list-style: none;
&-bottom {
bottom: 12px;
}
&-top {
top: 12px;
}
li {
position: relative;
display: inline-block;
......@@ -196,11 +201,16 @@
.@{ant-prefix}-carousel-vertical {
.slick-dots {
top: 50%;
right: 12px;
bottom: auto;
width: @carousel-dot-height;
height: auto;
transform: translateY(-50%);
&-left {
left: 12px;
}
&-right {
right: 12px;
}
li {
margin: 0 2px;
vertical-align: baseline;
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import './mixin';
.antCheckboxFn();
......@@ -6,6 +6,8 @@ import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import animation from '../_util/openAnimation';
export type ExpandIconPosition = 'left' | 'right';
export interface CollapseProps {
activeKey?: Array<string> | string;
defaultActiveKey?: Array<string>;
......@@ -18,6 +20,7 @@ export interface CollapseProps {
bordered?: boolean;
prefixCls?: string;
expandIcon?: (panelProps: any) => React.ReactNode;
expandIconPosition?: ExpandIconPosition;
}
interface PanelProps {
......@@ -37,6 +40,7 @@ export default class Collapse extends React.Component<CollapseProps, any> {
static defaultProps = {
bordered: true,
openAnimation: { ...animation, appear() {} },
expandIconPosition: 'left',
};
renderExpandIcon = (panelProps: PanelProps = {}, prefixCls: string) => {
......@@ -54,11 +58,17 @@ export default class Collapse extends React.Component<CollapseProps, any> {
};
renderCollapse = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', bordered } = this.props;
const {
prefixCls: customizePrefixCls,
className = '',
bordered,
expandIconPosition,
} = this.props;
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const collapseClassName = classNames(
{
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-icon-position-${expandIconPosition}`]: true,
},
className,
);
......
......@@ -2,7 +2,7 @@
exports[`Collapse should render extra node of panel 1`] = `
<div
class="ant-collapse"
class="ant-collapse ant-collapse-icon-position-left"
>
<div
class="ant-collapse-item"
......@@ -89,7 +89,7 @@ exports[`Collapse should render extra node of panel 1`] = `
exports[`Collapse should support remove expandIcon 1`] = `
<div
class="ant-collapse"
class="ant-collapse ant-collapse-icon-position-left"
>
<div
class="ant-collapse-item"
......
......@@ -14,9 +14,10 @@ title:
More than one panel can be expanded at a time, the first panel is initialized to be active in this case.
````jsx
import { Collapse, Icon } from 'antd';
import { Collapse, Icon, Select } from 'antd';
const Panel = Collapse.Panel;
const { Panel } = Collapse;
const { Option } = Select;
function callback(key) {
console.log(key);
......@@ -38,18 +39,42 @@ const genExtra = () => (
/>
);
ReactDOM.render(
<Collapse defaultActiveKey={['1']} onChange={callback}>
<Panel header="This is panel header 1" key="1" extra={genExtra()}>
<div>{text}</div>
</Panel>
<Panel header="This is panel header 2" key="2" extra={genExtra()}>
<div>{text}</div>
</Panel>
<Panel header="This is panel header 3" key="3" extra={genExtra()}>
<div>{text}</div>
</Panel>
</Collapse>,
mountNode
);
class Demo extends React.Component {
state = {
expandIconPosition: 'left',
};
onPositionChange = (expandIconPosition) => {
this.setState({ expandIconPosition });
};
render() {
const { expandIconPosition } = this.state;
return (
<div>
<Collapse defaultActiveKey={['1']} onChange={callback} expandIconPosition={expandIconPosition}>
<Panel header="This is panel header 1" key="1" extra={genExtra()}>
<div>{text}</div>
</Panel>
<Panel header="This is panel header 2" key="2" extra={genExtra()}>
<div>{text}</div>
</Panel>
<Panel header="This is panel header 3" key="3" extra={genExtra()}>
<div>{text}</div>
</Panel>
</Collapse>
<br />
Expand Icon Position:
{' '}
<Select value={expandIconPosition} onChange={this.onPositionChange}>
<Option value="left">left</Option>
<Option value="right">right</Option>
</Select>
</div>
);
}
}
ReactDOM.render(<Demo />, mountNode);
````
......@@ -16,15 +16,16 @@ A content area which can be collapsed and expanded.
### Collapse
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| activeKey | Key of the active panel | string\[]\|string | No default value. In `accordion` mode, it's the key of the first panel. |
| defaultActiveKey | Key of the initial active panel | string | - |
| bordered | Toggles rendering of the border around the collapse block | boolean | `true` |
| accordion | If `true`, `Collapse` renders as `Accordion` | boolean | `false` |
| onChange | Callback function executed when active panel is changed | Function | - |
| expandIcon | allow to customize collapse icon | (panelProps) => ReactNode | - |
| destroyInactivePanel | Destroy Inactive Panel | boolean | `false` |
| Property | Description | Type | Default | Version |
| -------- | ----------- | ---- | ------- | ------- |
| activeKey | Key of the active panel | string\[]\|string | No default value. In `accordion` mode, it's the key of the first panel. | |
| defaultActiveKey | Key of the initial active panel | string | - | |
| bordered | Toggles rendering of the border around the collapse block | boolean | `true` | |
| accordion | If `true`, `Collapse` renders as `Accordion` | boolean | `false` | |
| onChange | Callback function executed when active panel is changed | Function | - | |
| expandIcon | allow to customize collapse icon | (panelProps) => ReactNode | - | |
| expandIconPosition | Set expand icon position: `left`, `right` | `left` | - | 3.17.0 |
| destroyInactivePanel | Destroy Inactive Panel | boolean | `false` | |
### Collapse.Panel
......@@ -36,9 +37,3 @@ A content area which can be collapsed and expanded.
| key | Unique key identifying the panel from among its siblings | string | - |
| showArrow | If `false`, panel will not show arrow icon | boolean | `true` |
| extra | extra element in the corner | ReactNode | - |
## FAQ
### How to let the arrow to be on the right?
You can adjust style of the arrow: <https://codesandbox.io/s/v046rx89n0>
......@@ -17,15 +17,16 @@ cols: 1
### Collapse
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| activeKey | 当前激活 tab 面板的 key | string\[]\|string | 默认无,accordion模式下默认第一个元素 |
| defaultActiveKey | 初始化选中面板的 key | string | 无 |
| bordered | 带边框风格的折叠面板 | boolean | `true` |
| accordion | 手风琴模式 | boolean | `false` |
| onChange | 切换面板的回调 | Function | 无 |
| expandIcon | 自定义切换图标 | (panelProps) => ReactNode | - |
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | `false` |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| activeKey | 当前激活 tab 面板的 key | string\[]\|string | 默认无,accordion模式下默认第一个元素 | |
| defaultActiveKey | 初始化选中面板的 key | string | 无 | |
| bordered | 带边框风格的折叠面板 | boolean | `true` | |
| accordion | 手风琴模式 | boolean | `false` | |
| onChange | 切换面板的回调 | Function | 无 | |
| expandIcon | 自定义切换图标 | (panelProps) => ReactNode | - | |
| expandIconPosition | 设置图标位置: `left`, `right` | `left` | - | 3.17.0 |
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | `false` | |
### Collapse.Panel
......@@ -37,9 +38,3 @@ cols: 1
| key | 对应 activeKey | string | 无 |
| showArrow | 是否展示当前面板上的箭头 | boolean | `true` |
| extra | 自定义渲染每个面板右上角的内容 | ReactNode | - |
## FAQ
### 我希望箭头在右边,怎么做?
通过样式调整,将箭头放到右边就行啦:<https://codesandbox.io/s/v046rx89n0>
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@collapse-prefix-cls: ~'@{ant-prefix}-collapse';
......@@ -24,6 +24,7 @@
> .@{collapse-prefix-cls}-header {
position: relative;
padding: @collapse-header-padding;
padding-left: @collapse-header-padding-extra;
color: @heading-color;
line-height: 22px;
cursor: pointer;
......@@ -62,6 +63,21 @@
}
}
// Expand Icon right
&-icon-position-right {
& > .@{collapse-prefix-cls}-item {
> .@{collapse-prefix-cls}-header {
padding: @collapse-header-padding;
padding-right: @collapse-header-padding-extra;
.@{collapse-prefix-cls}-arrow {
right: @padding-md;
left: initial;
}
}
}
}
&-anim-active {
transition: height 0.2s @ease-out;
}
......
......@@ -216,108 +216,116 @@ exports[`renders ./components/comment/demo/list.md correctly 1`] = `
<div
class="ant-spin-container"
>
<div
class="ant-comment"
<ul
class="ant-list-items"
>
<div
class="ant-comment-inner"
>
<div
class="ant-comment-avatar"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>
<li>
<div
class="ant-comment-content"
class="ant-comment"
>
<div
class="ant-comment-content-author"
class="ant-comment-inner"
>
<span
class="ant-comment-content-author-name"
<div
class="ant-comment-avatar"
>
Han Solo
</span>
<span
class="ant-comment-content-author-time"
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>
<div
class="ant-comment-content"
>
<span>
a day ago
</span>
</span>
</div>
<div
class="ant-comment-content-detail"
>
<p>
We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.
</p>
<div
class="ant-comment-content-author"
>
<span
class="ant-comment-content-author-name"
>
Han Solo
</span>
<span
class="ant-comment-content-author-time"
>
<span>
a day ago
</span>
</span>
</div>
<div
class="ant-comment-content-detail"
>
<p>
We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.
</p>
</div>
<ul
class="ant-comment-actions"
>
<li>
<span>
Reply to
</span>
</li>
</ul>
</div>
</div>
<ul
class="ant-comment-actions"
>
<li>
<span>
Reply to
</span>
</li>
</ul>
</div>
</div>
</div>
<div
class="ant-comment"
>
<div
class="ant-comment-inner"
>
<div
class="ant-comment-avatar"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>
</li>
<li>
<div
class="ant-comment-content"
class="ant-comment"
>
<div
class="ant-comment-content-author"
class="ant-comment-inner"
>
<span
class="ant-comment-content-author-name"
<div
class="ant-comment-avatar"
>
Han Solo
</span>
<span
class="ant-comment-content-author-time"
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</div>
<div
class="ant-comment-content"
>
<span>
2 days ago
</span>
</span>
</div>
<div
class="ant-comment-content-detail"
>
<p>
We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.
</p>
<div
class="ant-comment-content-author"
>
<span
class="ant-comment-content-author-name"
>
Han Solo
</span>
<span
class="ant-comment-content-author-time"
>
<span>
2 days ago
</span>
</span>
</div>
<div
class="ant-comment-content-detail"
>
<p>
We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.
</p>
</div>
<ul
class="ant-comment-actions"
>
<li>
<span>
Reply to
</span>
</li>
</ul>
</div>
</div>
<ul
class="ant-comment-actions"
>
<li>
<span>
Reply to
</span>
</li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
......
......@@ -53,13 +53,15 @@ ReactDOM.render(
itemLayout="horizontal"
dataSource={data}
renderItem={item => (
<Comment
actions={item.actions}
author={item.author}
avatar={item.avatar}
content={item.content}
datetime={item.datetime}
/>
<li>
<Comment
actions={item.actions}
author={item.author}
avatar={item.avatar}
content={item.content}
datetime={item.datetime}
/>
</li>
)}
/>,
mountNode,
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@comment-prefix-cls: ~'@{ant-prefix}-comment';
......
......@@ -5517,7 +5517,7 @@ exports[`ConfigProvider components Carousel configProvider 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -5647,7 +5647,7 @@ exports[`ConfigProvider components Carousel normal 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -5777,7 +5777,7 @@ exports[`ConfigProvider components Carousel prefixCls 1`] = `
</div>
</div>
<ul
class="slick-dots"
class="slick-dots slick-dots-bottom"
style="display:block"
>
<li
......@@ -5990,7 +5990,7 @@ exports[`ConfigProvider components Checkbox prefixCls 1`] = `
exports[`ConfigProvider components Collapse configProvider 1`] = `
<div
class="config-collapse"
class="config-collapse config-collapse-icon-position-left"
>
<div
class="config-collapse-item"
......@@ -6028,7 +6028,7 @@ exports[`ConfigProvider components Collapse configProvider 1`] = `
exports[`ConfigProvider components Collapse normal 1`] = `
<div
class="ant-collapse"
class="ant-collapse ant-collapse-icon-position-left"
>
<div
class="ant-collapse-item"
......@@ -6066,7 +6066,7 @@ exports[`ConfigProvider components Collapse normal 1`] = `
exports[`ConfigProvider components Collapse prefixCls 1`] = `
<div
class="prefix-Collapse"
class="prefix-Collapse prefix-Collapse-icon-position-left"
>
<div
class="prefix-Collapse-item"
......@@ -6955,7 +6955,7 @@ exports[`ConfigProvider components Dropdown configProvider 1`] = `
</span>
</button>
<button
class="config-btn config-dropdown-trigger config-btn-default config-btn-icon-only"
class="config-btn config-dropdown-trigger config-btn-default"
type="button"
>
<i
......@@ -6994,7 +6994,7 @@ exports[`ConfigProvider components Dropdown normal 1`] = `
</span>
</button>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default ant-btn-icon-only"
class="ant-btn ant-dropdown-trigger ant-btn-default"
type="button"
>
<i
......@@ -7033,7 +7033,7 @@ exports[`ConfigProvider components Dropdown prefixCls 1`] = `
</span>
</button>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default ant-btn-icon-only"
class="ant-btn ant-dropdown-trigger ant-btn-default"
type="button"
>
<i
......@@ -7666,39 +7666,43 @@ exports[`ConfigProvider components List configProvider 1`] = `
<div
class="config-spin-container"
>
<div
class="config-list-item"
<ul
class="config-list-items"
>
<div
class="config-list-item-meta"
<li
class="config-list-item"
>
<div
class="config-list-item-meta-avatar"
>
<span
class="config-avatar config-avatar-circle config-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="config-list-item-meta-content"
class="config-list-item-meta"
>
<h4
class="config-list-item-meta-title"
<div
class="config-list-item-meta-avatar"
>
Ant Design
</h4>
<span
class="config-avatar config-avatar-circle config-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="config-list-item-meta-description"
class="config-list-item-meta-content"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
<h4
class="config-list-item-meta-title"
>
Ant Design
</h4>
<div
class="config-list-item-meta-description"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
......@@ -7714,39 +7718,43 @@ exports[`ConfigProvider components List normal 1`] = `
<div
class="ant-spin-container"
>
<div
class="ant-list-item"
<ul
class="ant-list-items"
>
<div
class="ant-list-item-meta"
<li
class="ant-list-item"
>
<div
class="ant-list-item-meta-avatar"
class="ant-list-item-meta"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="ant-list-item-meta-content"
>
<h4
class="ant-list-item-meta-title"
<div
class="ant-list-item-meta-avatar"
>
Ant Design
</h4>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="ant-list-item-meta-description"
class="ant-list-item-meta-content"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
<h4
class="ant-list-item-meta-title"
>
Ant Design
</h4>
<div
class="ant-list-item-meta-description"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
......@@ -7762,39 +7770,43 @@ exports[`ConfigProvider components List prefixCls 1`] = `
<div
class="ant-spin-container"
>
<div
class="prefix-List-item"
<ul
class="prefix-List-items"
>
<div
class="prefix-List-item-meta"
<li
class="prefix-List-item"
>
<div
class="prefix-List-item-meta-avatar"
class="prefix-List-item-meta"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="prefix-List-item-meta-content"
>
<h4
class="prefix-List-item-meta-title"
<div
class="prefix-List-item-meta-avatar"
>
Ant Design
</h4>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
</div>
<div
class="prefix-List-item-meta-description"
class="prefix-List-item-meta-content"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
<h4
class="prefix-List-item-meta-title"
>
Ant Design
</h4>
<div
class="prefix-List-item-meta-description"
>
Ant Design, a design language for background applications, is refined by Ant UED Team
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
......
// placeholder
@import '../../style/themes/default';
@import '../../style/themes/index';
import CalendarLocale from 'rc-calendar/lib/locale/hr_HR';
import TimePickerLocale from '../../time-picker/locale/hr_HR';
// Merge into a locale object
const locale = {
lang: {
placeholder: 'Odaberite datum',
rangePlaceholder: ['Početni datum', 'Završni datum'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@import '../../button/style/mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@divider-prefix-cls: ~'@{ant-prefix}-divider';
......
......@@ -167,98 +167,102 @@ exports[`renders ./components/drawer/demo/user-profile.md correctly 1`] = `
<div
class="ant-spin-container"
>
<div
class="ant-list-item"
<ul
class="ant-list-items"
>
<div
class="ant-list-item-meta"
<li
class="ant-list-item"
>
<div
class="ant-list-item-meta-avatar"
class="ant-list-item-meta"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
/>
</span>
</div>
<div
class="ant-list-item-meta-content"
>
<h4
class="ant-list-item-meta-title"
<div
class="ant-list-item-meta-avatar"
>
<a
href="https://ant.design/index-cn"
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
Lily
</a>
</h4>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
/>
</span>
</div>
<div
class="ant-list-item-meta-description"
class="ant-list-item-meta-content"
>
Progresser AFX
<h4
class="ant-list-item-meta-title"
>
<a
href="https://ant.design/index-cn"
>
Lily
</a>
</h4>
<div
class="ant-list-item-meta-description"
>
Progresser AFX
</div>
</div>
</div>
</div>
<ul
class="ant-list-item-action"
>
<li>
<a>
View Profile
</a>
</li>
</ul>
</div>
<div
class="ant-list-item"
>
<div
class="ant-list-item-meta"
>
<div
class="ant-list-item-meta-avatar"
<ul
class="ant-list-item-action"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
/>
</span>
</div>
<li>
<a>
View Profile
</a>
</li>
</ul>
</li>
<li
class="ant-list-item"
>
<div
class="ant-list-item-meta-content"
class="ant-list-item-meta"
>
<h4
class="ant-list-item-meta-title"
<div
class="ant-list-item-meta-avatar"
>
<a
href="https://ant.design/index-cn"
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
Lily
</a>
</h4>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png"
/>
</span>
</div>
<div
class="ant-list-item-meta-description"
class="ant-list-item-meta-content"
>
Progresser AFX
<h4
class="ant-list-item-meta-title"
>
<a
href="https://ant.design/index-cn"
>
Lily
</a>
</h4>
<div
class="ant-list-item-meta-description"
>
Progresser AFX
</div>
</div>
</div>
</div>
<ul
class="ant-list-item-action"
>
<li>
<a>
View Profile
</a>
</li>
</ul>
</div>
<ul
class="ant-list-item-action"
>
<li>
<a>
View Profile
</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
......
......@@ -35,6 +35,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
| zIndex | The `z-index` of the Drawer. | Number | 1000 |
| placement | The placement of the Drawer. | 'top' \| 'right' \| 'bottom' \| 'left' | 'right' |
| onClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button. | function(e) | - |
| afterVisibleChange | Callback after the animation ends when switching drawers. | function(visible) | - |
<style>
#_hj_feedback_container {
......
......@@ -36,6 +36,7 @@ export interface DrawerProps {
push?: boolean;
placement?: placementType;
onClose?: (e: EventType) => void;
afterVisibleChange?: (visible: boolean) => void;
className?: string;
handler?: React.ReactNode;
}
......@@ -65,6 +66,7 @@ class Drawer extends React.Component<DrawerProps & ConfigConsumerProps, IDrawerS
prefixCls: PropTypes.string,
placement: PropTypes.oneOf(PlacementTypes),
onClose: PropTypes.func,
afterVisibleChange: PropTypes.func,
className: PropTypes.string,
};
......
......@@ -34,6 +34,7 @@ title: Drawer
| zIndex | 设置 Drawer 的 `z-index` | Number | 1000 |
| placement | 抽屉的方向 | 'top' \| 'right' \| 'bottom' \| 'left' | 'right'
| onClose | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | 无 |
| afterVisibleChange | 切换抽屉时动画结束后的回调 | function(visible) | 无 |
<style>
#_hj_feedback_container {
......
@import '../../style/themes/default';
@import '../../style/themes/index';
// Preserve the typo for compatibility
// https://github.com/ant-design/ant-design/issues/14628
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './drawer';
......@@ -38,7 +38,9 @@ exports[`renders ./components/dropdown/demo/context-menu.md correctly 1`] = `
`;
exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
<div>
<div
id="components-dropdown-demo-dropdown-button"
>
<div
class="ant-btn-group ant-dropdown-button"
>
......@@ -51,7 +53,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
</span>
</button>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default ant-btn-icon-only"
class="ant-btn ant-dropdown-trigger ant-btn-default"
type="button"
>
<i
......@@ -77,7 +79,42 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
</div>
<div
class="ant-btn-group ant-dropdown-button"
style="margin-left:8px"
>
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Dropdown
</span>
</button>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default"
type="button"
>
<i
aria-label="icon: user"
class="anticon anticon-user"
>
<svg
aria-hidden="true"
class=""
data-icon="user"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M858.5 763.6a374 374 0 0 0-80.6-119.5 375.63 375.63 0 0 0-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 0 0-80.6 119.5A371.7 371.7 0 0 0 136 901.8a8 8 0 0 0 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 0 0 8-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
/>
</svg>
</i>
</button>
</div>
<div
class="ant-btn-group ant-dropdown-button"
>
<button
class="ant-btn ant-btn-default"
......@@ -89,7 +126,7 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
</span>
</button>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default ant-btn-icon-only"
class="ant-btn ant-dropdown-trigger ant-btn-default"
disabled=""
type="button"
>
......@@ -116,7 +153,6 @@ exports[`renders ./components/dropdown/demo/dropdown-button.md correctly 1`] = `
</div>
<button
class="ant-btn ant-dropdown-trigger"
style="margin-left:8px"
type="button"
>
<span>
......
......@@ -9,7 +9,7 @@ exports[`DropdownButton should support href like Button 1`] = `
href="https://ant.design"
/>
<button
class="ant-btn ant-dropdown-trigger ant-btn-default ant-btn-icon-only"
class="ant-btn ant-dropdown-trigger ant-btn-default"
type="button"
>
<i
......
......@@ -8,10 +8,12 @@ title:
## zh-CN
左边是按钮,右边是额外的相关功能菜单。
可设置 `icon` 属性来修改右边的图标。
## en-US
A button is on the left, and a related functional menu is on the right.
You can set the icon property to modify the icon of right.
````jsx
import {
......@@ -37,24 +39,35 @@ const menu = (
);
ReactDOM.render(
<div>
<div id="components-dropdown-demo-dropdown-button">
<Dropdown.Button onClick={handleButtonClick} overlay={menu}>
Dropdown
</Dropdown.Button>
<Dropdown.Button
overlay={menu}
icon={<Icon type="user" />}
>
Dropdown
</Dropdown.Button>
<Dropdown.Button
onClick={handleButtonClick}
overlay={menu}
disabled
style={{ marginLeft: 8 }}
>
Dropdown
</Dropdown.Button>
<Dropdown overlay={menu}>
<Button style={{ marginLeft: 8 }}>
<Button>
Button <Icon type="down" />
</Button>
</Dropdown>
</div>,
mountNode
mountNode,
);
````
````css
#components-dropdown-demo-dropdown-button .ant-dropdown-button{
margin: 0 8px 8px 0;
}
````
\ No newline at end of file
......@@ -16,7 +16,7 @@ The menu has multiple levels.
````jsx
import { Menu, Dropdown, Icon } from 'antd';
const SubMenu = Menu.SubMenu;
const { SubMenu } = Menu;
const menu = (
<Menu>
......
import * as React from 'react';
import classNames from 'classnames';
import Button from '../button';
import { ButtonHTMLType } from '../button/button';
import { ButtonGroupProps } from '../button/button-group';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Dropdown, { DropDownProps } from './dropdown';
import classNames from 'classnames';
import Icon from '../icon';
const ButtonGroup = Button.Group;
type DropdownButtonType = 'primary' | 'ghost' | 'dashed';
......@@ -14,6 +16,10 @@ export interface DropdownButtonProps extends ButtonGroupProps, DropDownProps {
htmlType?: ButtonHTMLType;
disabled?: boolean;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
/**
* @since 3.17.0
*/
icon?: React.ReactNode;
href?: string;
children?: any;
}
......@@ -44,6 +50,7 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
placement,
getPopupContainer,
href,
icon = <Icon type="ellipsis" />,
...restProps
} = this.props;
......@@ -67,7 +74,7 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
{children}
</Button>
<Dropdown {...dropdownProps}>
<Button type={type} icon="ellipsis" />
<Button type={type}>{icon}</Button>
</Dropdown>
</ButtonGroup>
);
......
......@@ -34,14 +34,16 @@ You should use [Menu](/components/menu/) as `overlay`. The menu items and divide
### Dropdown.Button
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| disabled | whether the dropdown menu is disabled | boolean | - |
| overlay | the dropdown menu | [Menu](/components/menu) | - |
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| size | size of the button, the same as [Button](/components/button) | string | `default` |
| trigger | the trigger mode which executes the drop-down action | Array&lt;`click`\|`hover`\|`contextMenu`> | `['hover']` |
| type | type of the button, the same as [Button](/components/button) | string | `default` |
| visible | whether the dropdown menu is visible | boolean | - |
| onClick | a callback function, the same as [Button](/components/button), which will be executed when you click the button on the left | Function | - |
| onVisibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | Function | - |
| Property | Description | Type | Default | Version |
| -------- | ----------- | ---- | ------- |------- |
| disabled | whether the dropdown menu is disabled | boolean | - ||
| icon | icon of right | ReactNode | - | 3.17.0 |
| overlay | the dropdown menu | [Menu](/components/menu) | - ||
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` ||
| size | size of the button, the same as [Button](/components/button) | string | `default` ||
| trigger | the trigger mode which executes the drop-down action | Array&lt;`click`\|`hover`\|`contextMenu`> | `['hover']` ||
| type | type of the button, the same as [Button](/components/button) | string | `default` ||
| visible | whether the dropdown menu is visible | boolean | - ||
| onClick | a callback function, the same as [Button](/components/button), which will be executed when you click the button on the left | Function | - ||
| onVisibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | Function | - ||
......@@ -35,14 +35,15 @@ title: Dropdown
### Dropdown.Button
| 参数 | 说明 | 类型 | 默认值 |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- |
| disabled | 菜单是否禁用 | boolean | - |
| overlay | 菜单 | [Menu](/components/menu/) | - |
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| size | 按钮大小,和 [Button](/components/button/) 一致 | string | 'default' |
| trigger | 触发下拉的行为 | Array&lt;`click`\|`hover`\|`contextMenu`> | `['hover']` |
| type | 按钮类型,和 [Button](/components/button/) 一致 | string | 'default' |
| visible | 菜单是否显示 | boolean | - |
| onClick | 点击左侧按钮的回调,和 [Button](/components/button/) 一致 | Function | - |
| onVisibleChange | 菜单显示状态改变时调用,参数为 visible | Function | - |
| disabled | 菜单是否禁用 | boolean | - |||
| icon | 右侧的 icon | ReactNode | - | 3.17.0 |
| overlay | 菜单 | [Menu](/components/menu/) | - ||
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` ||
| size | 按钮大小,和 [Button](/components/button/) 一致 | string | 'default' ||
| trigger | 触发下拉的行为 | Array&lt;`click`\|`hover`\|`contextMenu`> | `['hover']` ||
| type | 按钮类型,和 [Button](/components/button/) 一致 | string | 'default' ||
| visible | 菜单是否显示 | boolean | - ||
| onClick | 点击左侧按钮的回调,和 [Button](/components/button/) 一致 | Function | - ||
| onVisibleChange | 菜单显示状态改变时调用,参数为 visible | Function | - ||
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@dropdown-prefix-cls: ~'@{ant-prefix}-dropdown';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@empty-prefix-cls: ~'@{ant-prefix}-empty';
......
......@@ -20,6 +20,7 @@ export interface FormItemProps {
prefixCls?: string;
className?: string;
id?: string;
htmlFor?: string;
label?: React.ReactNode;
labelAlign?: FormLabelAlign;
labelCol?: ColProps;
......@@ -60,7 +61,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
helpShow = false;
componentDidMount() {
const { children, help, validateStatus } = this.props;
const { children, help, validateStatus, id } = this.props;
warning(
this.getControls(children, true).length <= 1 ||
(help !== undefined || validateStatus !== undefined),
......@@ -68,6 +69,12 @@ export default class FormItem extends React.Component<FormItemProps, any> {
'Cannot generate `validateStatus` and `help` automatically, ' +
'while there are more than one `getFieldDecorator` in it.',
);
warning(
!id,
'Form.Item',
'`id` is deprecated for its label `htmlFor`. Please use `htmlFor` directly.',
);
}
getHelpMessage() {
......@@ -328,7 +335,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
labelCol: contextLabelCol,
colon: contextColon,
}: FormContextProps) => {
const { label, labelCol, labelAlign, colon, id } = this.props;
const { label, labelCol, labelAlign, colon, id, htmlFor } = this.props;
const required = this.isRequired();
const mergedLabelCol: ColProps =
......@@ -361,7 +368,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
return label ? (
<Col {...mergedLabelCol} className={labelColClassName}>
<label
htmlFor={id || this.getId()}
htmlFor={htmlFor || id || this.getId()}
className={labelClassName}
title={typeof label === 'string' ? label : ''}
onClick={this.onLabelClick}
......
......@@ -236,4 +236,30 @@ describe('Form', () => {
),
).toMatchSnapshot();
});
describe('should `htmlFor` work', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
afterEach(() => {
errorSpy.mockReset();
});
afterAll(() => {
errorSpy.mockRestore();
});
it('should warning when use `id`', () => {
mount(<Form.Item id="bamboo" label="bamboo" />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Form.Item] `id` is deprecated for its label `htmlFor`. Please use `htmlFor` directly.',
);
});
it('use `htmlFor`', () => {
const wrapper = mount(<Form.Item htmlFor="bamboo" label="bamboo" />);
expect(wrapper.find('label').props().htmlFor).toBe('bamboo');
});
});
});
......@@ -193,17 +193,18 @@ More option at [rc-form option](https://github.com/react-component/form#option-o
Note: if Form.Item has multiple children that had been decorated by `getFieldDecorator`, `help` and `required` and `validateStatus` can't be generated automatically.
| Property | Description | Type | Default Value |
| -------- | ----------- | ---- | ------------- |
| colon | Used with `label`, whether to display `:` after label text. | boolean | true |
| extra | The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. | string\|ReactNode | |
| hasFeedback | Used with `validateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input`. | boolean | false |
| help | The prompt message. If not provided, the prompt message will be generated by the validation rule. | string\|ReactNode | |
| label | Label text | string\|ReactNode | |
| labelCol | The layout of label. You can set `span` `offset` to something like `{span: 3, offset: 12}` or `sm: {span: 3, offset: 12}` same as with `<Col>`. You can set on Form one time after 3.14.0. Will take FormItem's prop when both set with Form. | [object](https://ant.design/components/grid/#Col) | |
| required | Whether provided or not, it will be generated by the validation rule. | boolean | false |
| validateStatus | The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' | string | |
| wrapperCol | The layout for input controls, same as `labelCol`. You can set on Form one time after 3.14.0. Will take FormItem's prop when both set with Form. | [object](https://ant.design/components/grid/#Col) | |
| Property | Description | Type | Default Value | Version |
| -------- | ----------- | ---- | ------------- | ------- |
| colon | Used with `label`, whether to display `:` after label text. | boolean | true | |
| extra | The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. | string\|ReactNode | | |
| hasFeedback | Used with `validateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input`. | boolean | false | |
| help | The prompt message. If not provided, the prompt message will be generated by the validation rule. | string\|ReactNode | | |
| htmlFor | Set sub label `htmlFor`. | string | | 3.17.0 |
| label | Label text | string\|ReactNode | | |
| labelCol | The layout of label. You can set `span` `offset` to something like `{span: 3, offset: 12}` or `sm: {span: 3, offset: 12}` same as with `<Col>`. You can set on Form one time after 3.14.0. Will take FormItem's prop when both set with Form. | [object](https://ant.design/components/grid/#Col) | | |
| required | Whether provided or not, it will be generated by the validation rule. | boolean | false | |
| validateStatus | The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' | string | | |
| wrapperCol | The layout for input controls, same as `labelCol`. You can set on Form one time after 3.14.0. Will take FormItem's prop when both set with Form. | [object](https://ant.design/components/grid/#Col) | | |
### Validation Rules
......
......@@ -195,17 +195,18 @@ validateFields(['field1', 'field2'], options, (errors, values) => {
注意:一个 Form.Item 建议只放一个被 getFieldDecorator 装饰过的 child,当有多个被装饰过的 child 时,`help` `required` `validateStatus` 无法自动生成。
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| colon | 配合 label 属性使用,表示是否显示 label 后面的冒号 | boolean | true |
| extra | 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 | string\|ReactNode | |
| hasFeedback | 配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用 | boolean | false |
| help | 提示信息,如不设置,则会根据校验规则自动生成 | string\|ReactNode | |
| label | label 标签的文本 | string\|ReactNode | |
| labelCol | label 标签布局,同 `<Col>` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}``sm: {span: 3, offset: 12}`。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | |
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false |
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | |
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| colon | 配合 label 属性使用,表示是否显示 label 后面的冒号 | boolean | true | |
| extra | 额外的提示信息,和 help 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 | string\|ReactNode | | |
| hasFeedback | 配合 validateStatus 属性使用,展示校验状态图标,建议只配合 Input 组件使用 | boolean | false | |
| help | 提示信息,如不设置,则会根据校验规则自动生成 | string\|ReactNode | | |
| htmlFor | 设置子元素 label `htmlFor` 属性 | string | | 3.17.0 |
| label | label 标签的文本 | string\|ReactNode | | |
| labelCol | label 标签布局,同 `<Col>` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}``sm: {span: 3, offset: 12}`。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | | |
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false | |
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | | |
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol。在 3.14.0 之后,你可以通过 Form 的 labelCol 进行统一设置。当和 Form 同时设置时,以 FormItem 为准。 | [object](https://ant.design/components/grid/#Col) | | |
### 校验规则
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
@import '../../button/style/mixin';
......@@ -457,7 +457,7 @@ form {
}
.has-warning {
.form-control-validation(@warning-color; @warning-color;);
.form-control-validation(@warning-color; @warning-color; @form-warning-input-bg;);
&.has-feedback .@{form-prefix-cls}-item-children-icon {
color: @warning-color;
......@@ -506,7 +506,7 @@ form {
}
.has-error {
.form-control-validation(@error-color; @error-color;);
.form-control-validation(@error-color; @error-color; @form-error-input-bg;);
&.has-feedback .@{form-prefix-cls}-item-children-icon {
color: @error-color;
......
......@@ -30,6 +30,7 @@
.@{ant-prefix}-input {
&,
&:hover {
background-color: @background-color;
border-color: @border-color;
}
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@icon-prefix-cls: ~'@{ant-prefix}-icon';
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../input/style/mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import './mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@input-affix-width: 19px;
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@import '../../button/style/mixin';
@import './mixin';
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@layout-prefix-cls: ~'@{ant-prefix}-layout';
......
......@@ -113,9 +113,10 @@ export default class Item extends React.Component<ListItemProps, any> {
))}
</ul>
);
const Tag = grid ? 'div' : 'li';
const itemChildren = (
<div
{...others}
<Tag
{...others as any} // `li` element `onCopy` prop args is not same as `div`
className={classNames(`${prefixCls}-item`, className, {
[`${prefixCls}-item-no-flex`]: !this.isFlexMode(),
})}
......@@ -131,7 +132,7 @@ export default class Item extends React.Component<ListItemProps, any> {
</div>,
]
: [children, actionsContent, cloneElement(extra, { key: 'extra' })]}
</div>
</Tag>
);
return grid ? (
......
......@@ -10,44 +10,48 @@ exports[`List Item Layout horizontal itemLayout List should accept extra node 1`
<div
class="ant-spin-container"
>
<div
class="ant-list-item"
<ul
class="ant-list-items"
>
<div
class="ant-list-item-meta"
<li
class="ant-list-item"
>
<div
class="ant-list-item-meta-content"
class="ant-list-item-meta"
>
<h4
class="ant-list-item-meta-title"
>
<a
href="http://ant.design"
>
ant design
</a>
</h4>
<div
class="ant-list-item-meta-description"
class="ant-list-item-meta-content"
>
Ant Design, a design language for background applications, is refined by Ant UED Team.
<h4
class="ant-list-item-meta-title"
>
<a
href="http://ant.design"
>
ant design
</a>
</h4>
<div
class="ant-list-item-meta-description"
>
Ant Design, a design language for background applications, is refined by Ant UED Team.
</div>
</div>
</div>
</div>
<ul
class="ant-list-item-action"
>
<li>
<a>
Action
</a>
</li>
</ul>
<span>
extra
</span>
</div>
<ul
class="ant-list-item-action"
>
<li>
<a>
Action
</a>
</li>
</ul>
<span>
extra
</span>
</li>
</ul>
</div>
</div>
</div>
......
......@@ -10,16 +10,20 @@ exports[`List.pagination renders pagination correctly 1`] = `
<div
class="ant-spin-container"
>
<div
class="ant-list-item ant-list-item-no-flex"
>
Jack
</div>
<div
class="ant-list-item ant-list-item-no-flex"
<ul
class="ant-list-items"
>
Lucy
</div>
<li
class="ant-list-item ant-list-item-no-flex"
>
Jack
</li>
<li
class="ant-list-item ant-list-item-no-flex"
>
Lucy
</li>
</ul>
</div>
</div>
<div
......
......@@ -258,7 +258,11 @@ export default class List<T> extends React.Component<ListProps<T>, ListState> {
);
});
childrenContent = grid ? <Row gutter={grid.gutter}>{childrenList}</Row> : childrenList;
childrenContent = grid ? (
<Row gutter={grid.gutter}>{childrenList}</Row>
) : (
<ul className={`${prefixCls}-items`}>{childrenList}</ul>
);
} else if (!children && !isLoading) {
childrenContent = this.renderEmpty(prefixCls, renderEmpty);
}
......
@import '../../style/themes/default';
@import '../../style/themes/index';
@import '../../style/mixins/index';
@list-prefix-cls: ~'@{ant-prefix}-list';
......@@ -38,6 +38,12 @@
text-align: center;
}
&-items {
margin: 0;
padding: 0;
list-style: none;
}
&-item {
display: flex;
align-items: center;
......@@ -144,7 +150,7 @@
min-height: 32px;
}
&-something-after-last-item .@{ant-prefix}-spin-container > &-item:last-child {
&-something-after-last-item .@{ant-prefix}-spin-container > &-items > &-item:last-child {
border-bottom: 1px solid @border-color-split;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册