ConfigProvider support prefixCls (#13389)

Basic support prefixCls.
This commit is contained in:
zombieJ 2018-12-05 19:12:18 +08:00 committed by GitHub
parent bdba40639c
commit 1a0a06fca9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 20348 additions and 3125 deletions

View File

@ -5,6 +5,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import shallowequal from 'shallowequal';
import omit from 'omit.js';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getScroll from '../_util/getScroll';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
@ -270,9 +271,10 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
this.placeholderNode = node;
}
render() {
renderAffix = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls } = this.props;
const className = classNames({
[this.props.prefixCls || 'ant-affix']: this.state.affixStyle,
[getPrefixCls('affix', prefixCls)]: this.state.affixStyle,
});
const props = omit(this.props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target', 'onChange']);
@ -284,5 +286,13 @@ export default class Affix extends React.Component<AffixProps, AffixState> {
</div>
</div>
);
};
render() {
return (
<ConfigConsumer>
{this.renderAffix}
</ConfigConsumer>
);
}
}

View File

@ -3,6 +3,7 @@ import * as ReactDOM from 'react-dom';
import Animate from 'rc-animate';
import Icon, { ThemeType } from '../icon';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
function noop() { }
@ -67,13 +68,15 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
(this.props.afterClose || noop)();
}
render() {
renderAlert = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
description, prefixCls = 'ant-alert', message, closeText, banner,
description, prefixCls: customizePrefixCls, message, closeText, banner,
className = '', style, icon,
} = this.props;
let { closable, type, showIcon, iconType } = this.props;
const prefixCls = getPrefixCls('alert', customizePrefixCls);
// banner模式默认有 Icon
showIcon = banner && showIcon === undefined ? true : showIcon;
// banner模式默认为警告
@ -156,4 +159,12 @@ export default class Alert extends React.Component<AlertProps, AlertState> {
</Animate>
);
}
render() {
return (
<ConfigConsumer>
{this.renderAlert}
</ConfigConsumer>
);
}
}

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import Affix from '../affix';
import AnchorLink from './AnchorLink';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getScroll from '../_util/getScroll';
import raf from 'raf';
@ -117,7 +118,6 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
static Link: typeof AnchorLink;
static defaultProps = {
prefixCls: 'ant-anchor',
affix: true,
showInkInFixed: false,
getContainer: getDefaultContainer,
@ -137,6 +137,8 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
private scrollEvent: any;
private animating: boolean;
private prefixCls?: string;
getChildContext() {
const antAnchor: AntAnchor = {
registerLink: (link: string) => {
@ -227,7 +229,7 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
if (typeof document === 'undefined') {
return;
}
const { prefixCls } = this.props;
const prefixCls = this.prefixCls;
const anchorNode = ReactDOM.findDOMNode(this) as Element;
const linkNode = anchorNode.getElementsByClassName(`${prefixCls}-link-title-active`)[0];
if (linkNode) {
@ -239,9 +241,9 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
this.inkNode = node;
}
render() {
renderAnchor = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls,
prefixCls: customizePrefixCls,
className = '',
style,
offsetTop,
@ -252,6 +254,13 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
} = this.props;
const { activeLink } = this.state;
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this.prefixCls = prefixCls;
const inkClass = classNames(`${prefixCls}-ink-ball`, {
visible: activeLink,
});
@ -287,4 +296,12 @@ export default class Anchor extends React.Component<AnchorProps, AnchorState> {
</Affix>
);
}
render() {
return(
<ConfigConsumer>
{this.renderAnchor}
</ConfigConsumer>
);
}
}

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { AntAnchor } from './Anchor';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface AnchorLinkProps {
prefixCls?: string;
@ -12,7 +13,6 @@ export interface AnchorLinkProps {
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
static defaultProps = {
prefixCls: 'ant-anchor',
href: '#',
};
@ -49,13 +49,14 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
scrollTo(href);
}
render() {
renderAnchorLink = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls,
prefixCls: customizePrefixCls,
href,
title,
children,
} = this.props;
const prefixCls = getPrefixCls('anchor', customizePrefixCls);
const active = this.context.antAnchor.activeLink === href;
const wrapperClassName = classNames(`${prefixCls}-link`, {
[`${prefixCls}-link-active`]: active,
@ -77,4 +78,12 @@ export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderAnchorLink}
</ConfigConsumer>
);
}
}

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import { Option, OptGroup } from 'rc-select';
import classNames from 'classnames';
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
import Input from '../input';
import InputElement from './InputElement';
import Input from '../input';
import Select, { AbstractSelectProps, SelectValue, OptionProps, OptGroupProps } from '../select';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface DataSourceItemObject { value: string; text: string; }
export type DataSourceItemType =
@ -47,7 +48,6 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
static OptGroup = OptGroup as React.ClassicComponentClass<OptGroupProps>;
static defaultProps = {
prefixCls: 'ant-select',
transitionName: 'slide-up',
optionLabelProp: 'children',
choiceTransitionName: 'zoom',
@ -81,10 +81,12 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
this.select = node;
}
render() {
renderAutoComplete = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
size, className = '', notFoundContent, prefixCls, optionLabelProp, dataSource, children,
prefixCls: customizePrefixCls,
size, className = '', notFoundContent, optionLabelProp, dataSource, children,
} = this.props;
const prefixCls = getPrefixCls('select', customizePrefixCls);
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
@ -134,4 +136,12 @@ export default class AutoComplete extends React.Component<AutoCompleteProps, {}>
</Select>
);
}
render() {
return (
<ConfigConsumer>
{this.renderAutoComplete}
</ConfigConsumer>
);
}
}

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Icon from '../icon';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface AvatarProps {
/** Shape of avatar, options:`circle`, `square` */
@ -34,7 +35,6 @@ export interface AvatarState {
export default class Avatar extends React.Component<AvatarProps, AvatarState> {
static defaultProps = {
prefixCls: 'ant-avatar',
shape: 'circle',
size: 'default',
};
@ -85,13 +85,16 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
}
}
render() {
renderAvatar = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls, shape, size, src, srcSet, icon, className, alt, ...others
prefixCls: customizePrefixCls,
shape, size, src, srcSet, icon, className, alt, ...others
} = this.props;
const { isImgExist, scale } = this.state;
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const sizeCls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
@ -165,4 +168,12 @@ export default class Avatar extends React.Component<AvatarProps, AvatarState> {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderAvatar}
</ConfigConsumer>
);
}
}

View File

@ -3,8 +3,9 @@ import Animate from 'rc-animate';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import omit from 'omit.js';
import getScroll from '../_util/getScroll';
import raf from 'raf';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import getScroll from '../_util/getScroll';
const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
const cc = c - b;
@ -29,6 +30,7 @@ export interface BackTopProps {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
visible?: boolean; // Only for test. Don't use it.
}
export default class BackTop extends React.Component<BackTopProps, any> {
@ -102,8 +104,9 @@ export default class BackTop extends React.Component<BackTopProps, any> {
}
}
render() {
const { prefixCls = 'ant-back-top', className = '', children } = this.props;
renderBackTop = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', children } = this.props;
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
const classString = classNames(prefixCls, className);
const defaultElement = (
@ -119,9 +122,12 @@ export default class BackTop extends React.Component<BackTopProps, any> {
'children',
'visibilityHeight',
'target',
'visible',
]);
const backTopBtn = this.state.visible ? (
const visible = 'visible' in this.props ? this.props.visible : this.state.visible;
const backTopBtn = visible ? (
<div {...divProps} className={classString} onClick={this.scrollToTop}>
{children || defaultElement}
</div>
@ -133,4 +139,12 @@ export default class BackTop extends React.Component<BackTopProps, any> {
</Animate>
);
}
render() {
return (
<ConfigConsumer>
{this.renderBackTop}
</ConfigConsumer>
);
}
}

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import { createElement, Component } from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function getNumberArray(num: string | number | undefined | null) {
return num ?
@ -29,7 +30,6 @@ export interface ScrollNumberState {
export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNumberState> {
static defaultProps = {
prefixCls: 'ant-scroll-number',
count: null,
onAnimated() {
},
@ -100,12 +100,12 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
return childrenToReturn;
}
renderCurrentNumber(num: number, i: number) {
renderCurrentNumber(prefixCls: string, num: number, i: number) {
const position = this.getPositionByNum(num, i);
const removeTransition = this.state.animateStarted ||
(getNumberArray(this.lastCount)[i] === undefined);
return createElement('span', {
className: `${this.props.prefixCls}-only`,
className: `${prefixCls}-only`,
style: {
transition: removeTransition ? 'none' : undefined,
msTransform: `translateY(${-position * 100}%)`,
@ -116,17 +116,20 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
}, this.renderNumberList(position));
}
renderNumberElement() {
renderNumberElement(prefixCls: string) {
const { count } = this.state;
if (!count || isNaN(count as number)) {
return count;
}
return getNumberArray(count)
.map((num, i) => this.renderCurrentNumber(num, i)).reverse();
.map((num, i) => this.renderCurrentNumber(prefixCls, num, i)).reverse();
}
render() {
const { prefixCls, className, style, title, component = 'sup', displayComponent } = this.props;
renderScrollNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className, style, title, component = 'sup', displayComponent,
} = this.props;
// fix https://fb.me/react-unknown-prop
const restProps = omit(this.props, [
'count',
@ -135,11 +138,13 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
'prefixCls',
'displayComponent',
]);
const prefixCls = getPrefixCls('scroll-number', customizePrefixCls);
const newProps = {
...restProps,
className: classNames(prefixCls, className),
title: title as string,
};
// allow specify the border
// mock border-color by box-shadow for compatible with old usage:
// <Badge count={4} style={{ backgroundColor: '#fff', color: '#999', borderColor: '#d9d9d9' }} />
@ -154,7 +159,15 @@ export default class ScrollNumber extends Component<ScrollNumberProps, ScrollNum
return createElement(
component as any,
newProps,
this.renderNumberElement(),
this.renderNumberElement(prefixCls),
);
}
render() {
return (
<ConfigConsumer>
{this.renderScrollNumber}
</ConfigConsumer>
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import Animate from 'rc-animate';
import ScrollNumber from './ScrollNumber';
import classNames from 'classnames';
import ScrollNumber from './ScrollNumber';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export { ScrollNumberProps } from './ScrollNumber';
@ -26,8 +27,6 @@ export interface BadgeProps {
export default class Badge extends React.Component<BadgeProps, any> {
static defaultProps = {
prefixCls: 'ant-badge',
scrollNumberPrefixCls: 'ant-scroll-number',
count: null,
showZero: false,
dot: false,
@ -41,9 +40,8 @@ export default class Badge extends React.Component<BadgeProps, any> {
overflowCount: PropTypes.number,
};
getBadgeClassName() {
getBadgeClassName(prefixCls: string) {
const {
prefixCls,
className,
status,
children,
@ -106,8 +104,8 @@ export default class Badge extends React.Component<BadgeProps, any> {
} : style;
}
renderStatusText() {
const { prefixCls, text } = this.props;
renderStatusText(prefixCls: string) {
const { text } = this.props;
const hidden = this.isHidden();
return (hidden || !text) ? null : (
<span className={`${prefixCls}-status-text`}>{text}</span>
@ -119,11 +117,9 @@ export default class Badge extends React.Component<BadgeProps, any> {
return (count && typeof count === 'object') ? (count as React.ReactElement<any>) : undefined;
}
renderBadgeNumber() {
renderBadgeNumber(prefixCls: string, scrollNumberPrefixCls: string) {
const {
count,
prefixCls,
scrollNumberPrefixCls,
status,
} = this.props;
@ -154,12 +150,12 @@ export default class Badge extends React.Component<BadgeProps, any> {
);
}
render() {
renderBadge = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
count,
showZero,
prefixCls,
scrollNumberPrefixCls,
prefixCls: customizePrefixCls,
scrollNumberPrefixCls: customizeScrollNumberPrefixCls,
overflowCount,
className,
style,
@ -172,8 +168,11 @@ export default class Badge extends React.Component<BadgeProps, any> {
...restProps
} = this.props;
const scrollNumber = this.renderBadgeNumber();
const statusText = this.renderStatusText();
const prefixCls = getPrefixCls('badge', customizePrefixCls);
const scrollNumberPrefixCls = getPrefixCls('scroll-number', customizeScrollNumberPrefixCls);
const scrollNumber = this.renderBadgeNumber(prefixCls, scrollNumberPrefixCls);
const statusText = this.renderStatusText(prefixCls);
const statusCls = classNames({
[`${prefixCls}-status-dot`]: !!status,
@ -185,7 +184,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
// <Badge status="success" />
if (!children && status) {
return (
<span {...restProps} className={this.getBadgeClassName()} style={styleWithOffset}>
<span {...restProps} className={this.getBadgeClassName(prefixCls)} style={styleWithOffset}>
<span className={statusCls} />
<span className={`${prefixCls}-status-text`}>{text}</span>
</span>
@ -193,7 +192,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
return (
<span {...restProps} className={this.getBadgeClassName()}>
<span {...restProps} className={this.getBadgeClassName(prefixCls)}>
{children}
<Animate
component=""
@ -207,4 +206,12 @@ export default class Badge extends React.Component<BadgeProps, any> {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderBadge}
</ConfigConsumer>
);
}
}

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { cloneElement } from 'react';
import warning from '../_util/warning';
import BreadcrumbItem from './BreadcrumbItem';
import classNames from 'classnames';
import BreadcrumbItem from './BreadcrumbItem';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
export interface Route {
path: string;
@ -44,7 +45,6 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
static Item: typeof BreadcrumbItem;
static defaultProps = {
prefixCls: 'ant-breadcrumb',
separator: '/',
};
@ -66,12 +66,14 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
);
}
render() {
renderBreadcrumb = ({ getPrefixCls }: ConfigConsumerProps) => {
let crumbs;
const {
separator, prefixCls, style, className, routes, params = {},
prefixCls: customizePrefixCls,
separator, 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) => {
@ -110,4 +112,12 @@ export default class Breadcrumb extends React.Component<BreadcrumbProps, any> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderBreadcrumb}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface BreadcrumbItemProps {
prefixCls?: string;
@ -11,7 +12,6 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
static __ANT_BREADCRUMB_ITEM = true;
static defaultProps = {
prefixCls: 'ant-breadcrumb',
separator: '/',
};
@ -24,8 +24,12 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
href: PropTypes.string,
};
render() {
const { prefixCls, separator, children, ...restProps } = this.props;
renderBreadcrumbItem = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
separator, children, ...restProps
} = this.props;
const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls);
let link;
if ('href' in this.props) {
link = <a className={`${prefixCls}-link`} {...restProps}>{children}</a>;
@ -42,4 +46,12 @@ export default class BreadcrumbItem extends React.Component<BreadcrumbItemProps,
}
return null;
}
render() {
return (
<ConfigConsumer>
{this.renderBreadcrumbItem}
</ConfigConsumer>
);
}
}

View File

@ -7,7 +7,6 @@ exports[`react router react router 3 1`] = `
"id": 1,
}
}
prefixCls="ant-breadcrumb"
routes={
Array [
Object {
@ -76,95 +75,101 @@ exports[`react router react router 3 1`] = `
}
separator="/"
>
<div
className="ant-breadcrumb"
>
<BreadcrumbItem
key="Home"
prefixCls="ant-breadcrumb"
separator="/"
<Consumer>
<div
className="ant-breadcrumb"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/"
>
Home
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Application List"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps"
>
Application List
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Application:id"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps/1"
>
Application1
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
<BreadcrumbItem
key="Detail"
prefixCls="ant-breadcrumb"
separator="/"
>
<span>
<span
className="ant-breadcrumb-link"
>
<BreadcrumbItem
key="Home"
separator="/"
>
<Consumer>
<span>
Detail
<span
className="ant-breadcrumb-link"
>
<a
href="#/"
>
Home
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</BreadcrumbItem>
</div>
</Consumer>
</BreadcrumbItem>
<BreadcrumbItem
key="Application List"
separator="/"
>
<Consumer>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps"
>
Application List
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</Consumer>
</BreadcrumbItem>
<BreadcrumbItem
key="Application:id"
separator="/"
>
<Consumer>
<span>
<span
className="ant-breadcrumb-link"
>
<a
href="#/apps/1"
>
Application1
</a>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</Consumer>
</BreadcrumbItem>
<BreadcrumbItem
key="Detail"
separator="/"
>
<Consumer>
<span>
<span
className="ant-breadcrumb-link"
>
<span>
Detail
</span>
</span>
<span
className="ant-breadcrumb-separator"
>
/
</span>
</span>
</Consumer>
</BreadcrumbItem>
</div>
</Consumer>
</Breadcrumb>
`;

View File

@ -1,6 +1,7 @@
import * as React from 'react';
import classNames from 'classnames';
import { ButtonSize } from './button';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface ButtonGroupProps {
size?: ButtonSize;
@ -9,27 +10,32 @@ export interface ButtonGroupProps {
prefixCls?: string;
}
const ButtonGroup: React.SFC<ButtonGroupProps> = (props) => {
const { prefixCls = 'ant-btn-group', size, className, ...others } = props;
const ButtonGroup: React.SFC<ButtonGroupProps> = props => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, size, className, ...others } = props;
const prefixCls = getPrefixCls('btn-group', customizePrefixCls);
// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
default:
break;
}
// large => lg
// small => sm
let sizeCls = '';
switch (size) {
case 'large':
sizeCls = 'lg';
break;
case 'small':
sizeCls = 'sm';
default:
break;
}
const classes = classNames(prefixCls, {
[`${prefixCls}-${sizeCls}`]: sizeCls,
}, className);
const classes = classNames(prefixCls, {
[`${prefixCls}-${sizeCls}`]: sizeCls,
}, className);
return <div {...others} className={classes} />;
};
return <div {...others} className={classes} />;
}}
</ConfigConsumer>
);
export default ButtonGroup;

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import Wave from '../_util/wave';
import Icon from '../icon';
import Group from './button-group';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Wave from '../_util/wave';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
@ -69,7 +70,6 @@ export default class Button extends React.Component<ButtonProps, any> {
static __ANT_BUTTON = true;
static defaultProps = {
prefixCls: 'ant-btn',
loading: false,
ghost: false,
block: false,
@ -166,13 +166,16 @@ export default class Button extends React.Component<ButtonProps, any> {
return React.Children.count(children) === 1 && !icon;
}
render() {
renderButton = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
type, shape, size, className, children, icon, prefixCls, ghost, loading: _loadingProp, block, ...rest
prefixCls: customizePrefixCls,
type, shape, size, className, children, icon, ghost, loading: _loadingProp, block,
...rest
} = this.props;
const { loading, hasTwoCNChar } = this.state;
const prefixCls = getPrefixCls('btn', customizePrefixCls);
// large => lg
// small => sm
let sizeCls = '';
@ -239,4 +242,12 @@ export default class Button extends React.Component<ButtonProps, any> {
);
}
}
render() {
return (
<ConfigConsumer>
{this.renderButton}
</ConfigConsumer>
);
}
}

View File

@ -1 +0,0 @@
export const PREFIX_CLS = 'ant-fullcalendar';

View File

@ -1,8 +1,8 @@
import * as React from 'react';
import * as moment from 'moment';
import { PREFIX_CLS } from './Constants';
import Select from '../select';
import { Group, Button, RadioChangeEvent } from '../radio';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const Option = Select.Option;
export interface HeaderProps {
@ -20,19 +20,17 @@ export interface HeaderProps {
export default class Header extends React.Component<HeaderProps, any> {
static defaultProps = {
prefixCls: `${PREFIX_CLS}-header`,
yearSelectOffset: 10,
yearSelectTotal: 20,
};
private calenderHeaderNode: HTMLDivElement;
getYearSelectElement(year: number) {
getYearSelectElement(prefixCls: string, year: number) {
const {
yearSelectOffset,
yearSelectTotal,
locale,
prefixCls,
fullscreen,
validRange,
} = this.props;
@ -72,9 +70,8 @@ export default class Header extends React.Component<HeaderProps, any> {
return months;
}
getMonthSelectElement(month: number, months: number[]) {
const props = this.props;
const { prefixCls, fullscreen, validRange, value } = props;
getMonthSelectElement(prefixCls: string,month: number, months: number[]) {
const { fullscreen, validRange, value } = this.props;
const options: React.ReactElement<any>[] = [];
let start = 0;
let end = 12;
@ -147,11 +144,15 @@ export default class Header extends React.Component<HeaderProps, any> {
this.calenderHeaderNode = node;
}
render() {
const { type, value, prefixCls, locale, fullscreen } = this.props;
const yearSelect = this.getYearSelectElement(value.year());
renderHeader = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
type, value, locale, fullscreen,
} = this.props;
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
const yearSelect = this.getYearSelectElement(prefixCls, value.year());
const monthSelect = type === 'date' ?
this.getMonthSelectElement(value.month(), this.getMonthsLocale(value)) : null;
this.getMonthSelectElement(prefixCls, value.month(), this.getMonthsLocale(value)) : null;
const size = (fullscreen ? 'default' : 'small') as any;
const typeSwitch = (
<Group onChange={this.onTypeChange} value={type} size={size}>
@ -168,4 +169,12 @@ export default class Header extends React.Component<HeaderProps, any> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderHeader}
</ConfigConsumer>
);
}
}

View File

@ -2,11 +2,11 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import * as moment from 'moment';
import FullCalendar from 'rc-calendar/lib/FullCalendar';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { PREFIX_CLS } from './Constants';
import Header from './Header';
import interopDefault from '../_util/interopDefault';
import enUS from './locale/en_US';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import interopDefault from '../_util/interopDefault';
export { HeaderProps } from './Header';
@ -50,7 +50,6 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
static defaultProps = {
locale: {},
fullscreen: true,
prefixCls: PREFIX_CLS,
mode: 'month',
onSelect: noop,
onPanelChange: noop,
@ -73,6 +72,8 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
onChange: PropTypes.func,
};
prefixCls?: string;
constructor(props: CalendarProps) {
super(props);
@ -103,7 +104,8 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
}
monthCellRender = (value: moment.Moment) => {
const { prefixCls, monthCellRender = noop as Function } = this.props;
const { monthCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-month`}>
<div className={`${prefixCls}-value`}>
@ -117,7 +119,8 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
}
dateCellRender = (value: moment.Moment) => {
const { prefixCls, dateCellRender = noop as Function } = this.props;
const { dateCellRender = noop as Function } = this.props;
const { prefixCls } = this;
return (
<div className={`${prefixCls}-date`}>
<div className={`${prefixCls}-value`}>
@ -188,20 +191,30 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
return inRange;
}
getDefaultLocale = () => {
const result = {
...enUS,
...this.props.locale,
};
result.lang = {
...result.lang,
...(this.props.locale || {}).lang,
};
return result;
}
renderCalendar = (locale: any, localeCode: string) => {
const { state, props } = this;
const { value, mode } = state;
if (value && localeCode) {
value.locale(localeCode);
}
const { prefixCls, style, className, fullscreen, dateFullCellRender, monthFullCellRender } = props;
const {
prefixCls: customizePrefixCls,
style, className, fullscreen, dateFullCellRender, monthFullCellRender,
} = props;
const type = (mode === 'year') ? 'month' : 'date';
let cls = className || '';
if (fullscreen) {
cls += (` ${prefixCls}-fullscreen`);
}
const monthCellRender = monthFullCellRender || this.monthCellRender;
const dateCellRender = dateFullCellRender || this.dateCellRender;
@ -212,44 +225,50 @@ export default class Calendar extends React.Component<CalendarProps, CalendarSta
}
return (
<div className={cls} style={style}>
<Header
fullscreen={fullscreen}
type={type}
value={value}
locale={locale.lang}
prefixCls={prefixCls}
onTypeChange={this.onHeaderTypeChange}
onValueChange={this.onHeaderValueChange}
validRange={props.validRange}
/>
<FullCalendar
{...props}
disabledDate={disabledDate}
Select={noop}
locale={locale.lang}
type={type}
prefixCls={prefixCls}
showHeader={false}
value={value}
monthCellRender={monthCellRender}
dateCellRender={dateCellRender}
onSelect={this.onSelect}
/>
</div>
);
}
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
getDefaultLocale = () => {
const result = {
...enUS,
...this.props.locale,
};
result.lang = {
...result.lang,
...(this.props.locale || {}).lang,
};
return result;
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this.prefixCls = prefixCls;
let cls = className || '';
if (fullscreen) {
cls += (` ${prefixCls}-fullscreen`);
}
return (
<div className={cls} style={style}>
<Header
fullscreen={fullscreen}
type={type}
value={value}
locale={locale.lang}
prefixCls={prefixCls}
onTypeChange={this.onHeaderTypeChange}
onValueChange={this.onHeaderValueChange}
validRange={props.validRange}
/>
<FullCalendar
{...props}
disabledDate={disabledDate}
Select={noop}
locale={locale.lang}
type={type}
prefixCls={prefixCls}
showHeader={false}
value={value}
monthCellRender={monthCellRender}
dateCellRender={dateCellRender}
onSelect={this.onSelect}
/>
</div>
);
}}
</ConfigConsumer>
);
}
render() {

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface CardGridProps {
prefixCls?: string;
@ -7,8 +8,13 @@ export interface CardGridProps {
className?: string;
}
export default (props: CardGridProps) => {
const { prefixCls = 'ant-card', className, ...others } = props;
const classString = classNames(`${prefixCls}-grid`, className);
return <div {...others} className={classString} />;
};
export default (props: CardGridProps) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, ...others } = props;
const prefixCls = getPrefixCls('card', customizePrefixCls);
const classString = classNames(`${prefixCls}-grid`, className);
return <div {...others} className={classString} />;
}}
</ConfigConsumer>
);

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface CardMetaProps {
prefixCls?: string;
@ -10,22 +11,27 @@ export interface CardMetaProps {
description?: React.ReactNode;
}
export default (props: CardMetaProps) => {
const { prefixCls = 'ant-card', className, avatar, title, description, ...others } = props;
const classString = classNames(`${prefixCls}-meta`, className);
const avatarDom = avatar ? <div className={`${prefixCls}-meta-avatar`}>{avatar}</div> : null;
const titleDom = title ? <div className={`${prefixCls}-meta-title`}>{title}</div> : null;
const descriptionDom = description ?
<div className={`${prefixCls}-meta-description`}>{description}</div> : null;
const MetaDetail = titleDom || descriptionDom ?
<div className={`${prefixCls}-meta-detail`}>
{titleDom}
{descriptionDom}
</div> : null;
return (
<div {...others} className={classString}>
{avatarDom}
{MetaDetail}
</div>
);
};
export default (props: CardMetaProps) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, avatar, title, description, ...others } = props;
const prefixCls = getPrefixCls('card', customizePrefixCls);
const classString = classNames(`${prefixCls}-meta`, className);
const avatarDom = avatar ? <div className={`${prefixCls}-meta-avatar`}>{avatar}</div> : null;
const titleDom = title ? <div className={`${prefixCls}-meta-title`}>{title}</div> : null;
const descriptionDom = description ?
<div className={`${prefixCls}-meta-description`}>{description}</div> : null;
const MetaDetail = titleDom || descriptionDom ?
<div className={`${prefixCls}-meta-detail`}>
{titleDom}
{descriptionDom}
</div> : null;
return (
<div {...others} className={classString}>
{avatarDom}
{MetaDetail}
</div>
);
}}
</ConfigConsumer>
);

View File

@ -7,6 +7,7 @@ import Meta from './Meta';
import Tabs from '../tabs';
import Row from '../row';
import Col from '../col';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
import warning from '../_util/warning';
import { Omit } from '../_util/type';
@ -142,12 +143,14 @@ export default class Card extends React.Component<CardProps, CardState> {
return !!hoverable;
}
render() {
renderCard = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls = 'ant-card', className, extra, headStyle = {}, bodyStyle = {}, noHovering, hoverable, title, loading,
prefixCls: customizePrefixCls,
className, extra, headStyle = {}, bodyStyle = {}, noHovering, hoverable, title, loading,
bordered = true, type, cover, actions, tabList, children, activeTabKey, defaultActiveTabKey, ...others
} = this.props;
const prefixCls = getPrefixCls('card', customizePrefixCls);
const classString = classNames(prefixCls, className, {
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-bordered`]: bordered,
@ -270,4 +273,12 @@ export default class Card extends React.Component<CardProps, CardState> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCard}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import debounce from 'lodash/debounce';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
@ -70,7 +71,6 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
static defaultProps = {
dots: true,
arrows: false,
prefixCls: 'ant-carousel',
draggable: false,
};
@ -126,7 +126,7 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
this.slick.slickGoTo(slide, dontAnimate);
}
render() {
renderCarousel = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = {
...this.props,
};
@ -135,7 +135,7 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
props.fade = true;
}
let className = props.prefixCls;
let className = getPrefixCls('carousel', props.prefixCls);
if (props.vertical) {
className = `${className} ${className}-vertical`;
}
@ -146,4 +146,12 @@ export default class Carousel extends React.Component<CarouselProps, {}> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCarousel}
</ConfigConsumer>
);
}
}

View File

@ -707,7 +707,6 @@ exports[`Cascader should highlight keyword and filter when search in Cascader 1`
"value": "value",
}
}
inputPrefixCls="ant-input"
loadingIcon={
<span
className="ant-cascader-menu-item-loading-icon"
@ -1107,7 +1106,6 @@ exports[`Cascader should render not found content 1`] = `
"value": "value",
}
}
inputPrefixCls="ant-input"
loadingIcon={
<span
className="ant-cascader-menu-item-loading-icon"

View File

@ -6,7 +6,7 @@ import omit from 'omit.js';
import KeyCode from 'rc-util/lib/KeyCode';
import Input from '../input';
import Icon from '../icon';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
export interface CascaderOptionType {
@ -161,8 +161,6 @@ const defaultDisplayRender = (label: string[]) => label.join(' / ');
export default class Cascader extends React.Component<CascaderProps, CascaderState> {
static defaultProps = {
prefixCls: 'ant-cascader',
inputPrefixCls: 'ant-input',
placeholder: 'Please select',
transitionName: 'slide-up',
popupPlacement: 'bottomLeft',
@ -378,14 +376,18 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
this.input = node;
}
renderCascader = ({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
renderCascader = ({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const { props, state } = this;
const {
prefixCls, inputPrefixCls, children, placeholder, size, disabled,
prefixCls: customizePrefixCls, inputPrefixCls: customizeInputPrefixCls,
children, placeholder, size, disabled,
className, style, allowClear, showSearch = false, suffixIcon, ...otherProps
} = props;
const { value, inputFocused } = state;
const prefixCls = getPrefixCls('cascader', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const sizeCls = classNames({
[`${inputPrefixCls}-lg`]: size === 'large',
[`${inputPrefixCls}-sm`]: size === 'small',
@ -514,6 +516,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
return (
<RcCascader
{...rest}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer}
options={options}
value={value}

View File

@ -4,6 +4,7 @@ import classNames from 'classnames';
import RcCheckbox from 'rc-checkbox';
import shallowEqual from 'shallowequal';
import CheckboxGroup, { CheckboxGroupContext } from './Group';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface AbstractCheckboxProps<T> {
prefixCls?: string;
@ -41,7 +42,6 @@ export interface CheckboxChangeEvent {
export default class Checkbox extends React.Component<CheckboxProps, {}, {}> {
static Group: typeof CheckboxGroup;
static defaultProps = {
prefixCls: 'ant-checkbox',
indeterminate: false,
};
@ -71,10 +71,10 @@ export default class Checkbox extends React.Component<CheckboxProps, {}, {}> {
this.rcCheckbox = node;
}
render() {
renderCheckbox = ({ getPrefixCls }: ConfigConsumerProps) => {
const { props, context } = this;
const {
prefixCls,
prefixCls: customizePrefixCls,
className,
children,
indeterminate,
@ -84,6 +84,7 @@ export default class Checkbox extends React.Component<CheckboxProps, {}, {}> {
...restProps
} = props;
const { checkboxGroup } = context;
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
const checkboxProps: CheckboxProps = { ...restProps };
if (checkboxGroup) {
checkboxProps.onChange = (...args) => {
@ -120,4 +121,12 @@ export default class Checkbox extends React.Component<CheckboxProps, {}, {}> {
</label>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCheckbox}
</ConfigConsumer>
);
}
}

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import shallowEqual from 'shallowequal';
import omit from 'omit.js';
import Checkbox, { CheckboxChangeEvent } from './Checkbox';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type CheckboxValueType = string | number | boolean;
@ -44,7 +45,6 @@ export interface CheckboxGroupContext {
class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupState> {
static defaultProps = {
options: [],
prefixCls: 'ant-checkbox',
};
static propTypes = {
@ -120,9 +120,13 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
}
}
render() {
renderGroup = ({ getPrefixCls }: ConfigConsumerProps) => {
const { props, state } = this;
const { prefixCls, className, style, options, ...restProps } = props;
const {
prefixCls: customizePrefixCls,
className, style, options, ...restProps
} = props;
const prefixCls = getPrefixCls('checkbox', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const domProps = omit(restProps, ['children', 'defaultValue', 'value', 'onChange', 'disabled']);
@ -151,6 +155,14 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderGroup}
</ConfigConsumer>
);
}
}
polyfill(CheckboxGroup);

View File

@ -1,5 +1,5 @@
import React from 'react';
import { shallow } from 'enzyme';
import { mount } from 'enzyme';
import Checkbox from '..';
import focusTest from '../../../tests/shared/focusTest';
@ -10,17 +10,17 @@ describe('Checkbox', () => {
const onMouseEnter = jest.fn();
const onMouseLeave = jest.fn();
const wrapper = shallow(
const wrapper = mount(
<Checkbox
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
/>
);
wrapper.simulate('mouseenter');
wrapper.find('label').simulate('mouseenter');
expect(onMouseEnter).toHaveBeenCalled();
wrapper.simulate('mouseleave');
wrapper.find('label').simulate('mouseleave');
expect(onMouseLeave).toHaveBeenCalled();
});
});

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import RcCollapse from 'rc-collapse';
import classNames from 'classnames';
import animation from '../_util/openAnimation';
import CollapsePanel from './CollapsePanel';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import animation from '../_util/openAnimation';
export interface CollapseProps {
activeKey?: Array<string> | string;
@ -22,7 +23,6 @@ export default class Collapse extends React.Component<CollapseProps, any> {
static Panel = CollapsePanel;
static defaultProps = {
prefixCls: 'ant-collapse',
bordered: true,
openAnimation: { ...animation, appear() { } },
};
@ -33,17 +33,27 @@ export default class Collapse extends React.Component<CollapseProps, any> {
);
}
render() {
const { prefixCls, className = '', bordered } = this.props;
renderCollapse = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', bordered } = this.props;
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const collapseClassName = classNames({
[`${prefixCls}-borderless`]: !bordered,
}, className);
return (
<RcCollapse
{...this.props}
prefixCls={prefixCls}
className={collapseClassName}
expandIcon={this.renderExpandIcon}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCollapse}
</ConfigConsumer>
);
}
}

View File

@ -1,6 +1,7 @@
import * as React from 'react';
import RcCollapse from 'rc-collapse';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface CollapsePanelProps {
key: string;
@ -15,11 +16,26 @@ export interface CollapsePanelProps {
}
export default class CollapsePanel extends React.Component<CollapsePanelProps, {}> {
render() {
const { prefixCls, className = '', showArrow = true } = this.props;
renderCollapsePanel = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', showArrow = true } = this.props;
const prefixCls = getPrefixCls('collapse', customizePrefixCls);
const collapsePanelClassName = classNames({
[`${prefixCls}-no-arrow`]: !showArrow,
}, className);
return <RcCollapse.Panel {...this.props} className={collapsePanelClassName} />;
return (
<RcCollapse.Panel
{...this.props}
prefixCls={prefixCls}
className={collapsePanelClassName}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCollapsePanel}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface CommentProps {
/** List of action items rendered below the comment content */
@ -23,10 +24,6 @@ export interface CommentProps {
}
export default class Comment extends React.Component<CommentProps, {}> {
static defaultProps = {
prefixCls: 'ant-comment',
}
getAction(actions: React.ReactNode[]) {
if (!actions || !actions.length) {
return null;
@ -40,9 +37,7 @@ export default class Comment extends React.Component<CommentProps, {}> {
return actionList;
}
renderNested = (children: any) => {
const { prefixCls } = this.props;
renderNested = (prefixCls: string, children: any) => {
return (
<div className={classNames(`${prefixCls}-nested`)}>
{children}
@ -50,7 +45,7 @@ export default class Comment extends React.Component<CommentProps, {}> {
);
}
render() {
renderComment = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
actions,
author,
@ -58,12 +53,14 @@ export default class Comment extends React.Component<CommentProps, {}> {
children,
className,
content,
prefixCls,
prefixCls: customizePrefixCls,
style,
datetime,
...otherProps
} = this.props;
const prefixCls = getPrefixCls('comment', customizePrefixCls);
const avatarDom = (
<div className={`${prefixCls}-avatar`}>
{typeof avatar === 'string' ? <img src={avatar} /> : avatar}
@ -109,8 +106,16 @@ export default class Comment extends React.Component<CommentProps, {}> {
return (
<div {...otherProps} className={classNames(prefixCls, className)} style={style}>
{comment}
{children ? this.renderNested(children) : null}
{children ? this.renderNested(prefixCls, children) : null}
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderComment}
</ConfigConsumer>
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
import React from 'react';
import { render } from 'enzyme';
import moment from 'moment';
import ConfigProvider from '..';
import Alert from '../../alert';
import Anchor from '../../anchor';
import AutoComplete from '../../auto-complete';
import Avatar from '../../avatar';
import BackTop from '../../back-top';
import Badge from '../../badge';
import Breadcrumb from '../../breadcrumb';
import Button from '../../button';
import Calendar from '../../calendar';
import Card from '../../card';
import Carousel from '../../carousel';
import Cascader from '../../cascader';
import Checkbox from '../../checkbox';
import Collapse from '../../collapse';
import Comment from '../../comment';
import DatePicker from '../../date-picker';
import Divider from '../../divider';
import Drawer from '../../drawer';
import Dropdown from '../../dropdown';
import Form from '../../form';
import { Row, Col } from '../../grid';
import Input from '../../input';
import InputNumber from '../../input-number';
import Layout from '../../layout';
import List from '../../list';
import Mention from '../../mention';
import Menu from '../../menu';
import Modal from '../../modal';
import Pagination from '../../pagination';
import Popconfirm from '../../popconfirm';
import Popover from '../../popover';
import Progress from '../../progress';
import Radio from '../../radio';
import Rate from '../../rate';
import Select from '../../select';
import Skeleton from '../../skeleton';
import Slider from '../../slider';
import Spin from '../../spin';
import Steps from '../../steps';
import Switch from '../../switch';
import Table from '../../table';
import Tabs from '../../tabs';
import Tag from '../../tag';
import TimePicker from '../../time-picker';
import Timeline from '../../timeline';
import Tooltip from '../../tooltip';
import Transfer from '../../transfer';
import Tree from '../../tree';
import TreeSelect from '../../tree-select';
import Upload from '../../upload';
jest.mock('draft-js/lib/generateRandomKey', () => () => '123');
jest.mock('rc-util/lib/Portal');
describe('ConfigProvider', () => {
describe('components', () => {
function testPair(name, renderComponent) {
describe(name, () => {
// normal
it('normal', () => {
expect(render(renderComponent({}))).toMatchSnapshot();
});
// prefixCls
it('prefixCls', () => {
expect(render(renderComponent({ prefixCls: `prefix-${name}` }))).toMatchSnapshot();
});
// configProvider
it('configProvider', () => {
expect(render(
<ConfigProvider prefixCls="config">
{renderComponent({})}
</ConfigProvider>
)).toMatchSnapshot();
});
});
}
// Alert
testPair('Alert', props => (
<Alert {...props} message="Bamboo is Little Light" type="success" />
));
// Anchor
testPair('Anchor', props => (
<Anchor {...props}>
<Anchor.Link {...props} href="#bamboo" title="Little Light" />
</Anchor>
));
// AutoComplete
testPair('AutoComplete', props => (
<AutoComplete {...props} />
));
// Avatar
testPair('Avatar', props => (
<Avatar {...props} />
));
// BackTop
testPair('BackTop', props => (
<BackTop visible {...props} />
));
// Badge
testPair('Badge', (props) => {
const newProps = {
...props,
};
// Hook for additional `scrollNumberPrefixCls` prop
if (props.prefixCls) {
newProps.scrollNumberPrefixCls = 'prefix-scroll-number';
}
return (
<div>
<Badge {...newProps} count={5}>
<span />
</Badge>
<Badge {...newProps} dot>
<span />
</Badge>
</div>
);
});
// Breadcrumb
testPair('Breadcrumb', props => (
<Breadcrumb {...props}>
<Breadcrumb.Item {...props}>Bamboo</Breadcrumb.Item>
<Breadcrumb.Item {...props}>Light</Breadcrumb.Item>
</Breadcrumb>
));
// Button
testPair('Button', props => (
<div>
<Button {...props}>Bamboo</Button>
<Button.Group {...props}>
<Button {...props}>Little</Button>
<Button {...props}>Light</Button>
</Button.Group>
</div>
));
// Calendar
testPair('Calendar', props => (
<div>
<Calendar {...props} value={moment('2000-09-03')} mode="month" />
<Calendar {...props} value={moment('2000-09-03')} mode="year" />
</div>
));
// Card
testPair('Card', props => (
<Card {...props}>
<Card.Grid {...props}>
<Card.Meta {...props} />
</Card.Grid>
</Card>
));
// Carousel
testPair('Carousel', props => (
<Carousel {...props}>
<div><h3>Bamboo</h3></div>
<div><h3>Light</h3></div>
</Carousel>
));
// Cascader
testPair('Cascader', props => (
<Cascader {...props} options={[]} showSearch />
));
// Checkbox
testPair('Checkbox', props => (
<Checkbox.Group {...props}>
<Checkbox {...props}>Bamboo</Checkbox>
</Checkbox.Group>
));
// Collapse
testPair('Collapse', props => (
<Collapse {...props}>
<Collapse.Panel header="Bamboo">
<p>Light</p>
</Collapse.Panel>
</Collapse>
));
// Comment
testPair('Comment', props => (
<Comment {...props} content="Bamboo">
<Comment {...props} content="Light" />
</Comment>
));
// DatePicker
describe('DatePicker', () => {
testPair('DatePicker', props => (
<div>
<DatePicker {...props} />
</div>
));
// RangePicker
testPair('RangePicker', props => (
<div>
<DatePicker.RangePicker {...props} />
</div>
));
// MonthPicker
testPair('MonthPicker', props => (
<div>
<DatePicker.MonthPicker {...props} />
</div>
));
// WeekPicker
testPair('WeekPicker', props => (
<div>
<DatePicker.WeekPicker {...props} />
</div>
));
});
// Divider
testPair('Divider', props => (
<Divider {...props} />
));
// Drawer
testPair('Drawer', props => (
<Drawer {...props} visible getContainer={false} />
));
// Dropdown
testPair('Dropdown', (props) => {
const menu = (
<Menu {...props}>
<Menu.Item {...props}>Bamboo</Menu.Item>
</Menu>
);
return (
<Dropdown.Button {...props} overlay={menu}>
Light
</Dropdown.Button>
);
});
// Form
testPair('Form', props => (
<Form {...props}>
<Form.Item
{...props}
validateStatus="error"
help="Bamboo is Light"
>
<Input {...props} />
</Form.Item>
</Form>
));
// Grid
testPair('Grid', (props) => {
const rowProps = {};
const colProps = {};
if (props.prefixCls) {
rowProps.prefixCls = 'prefix-row';
colProps.prefixCls = 'prefix-col';
}
return (
<Row {...rowProps}>
<Col {...colProps} span={1} />
</Row>
);
});
// Input
testPair('Input', props => (
<div>
<Input.Group {...props}>
<Input {...props} />
<Input.Search {...props} />
</Input.Group>
<Input.TextArea {...props} />
</div>
));
// InputNumber
testPair('InputNumber', props => (
<InputNumber {...props} />
));
// Layout
testPair('Layout', (props) => {
const siderProps = {};
const headerProps = {};
const contentProps = {};
const footerProps = {};
if (props.prefixCls) {
siderProps.prefixCls = 'prefix-sider';
headerProps.prefixCls = 'prefix-header';
contentProps.prefixCls = 'prefix-content';
footerProps.prefixCls = 'prefix-footer';
}
return (
<Layout {...props}>
<Layout.Sider {...siderProps} />
<Layout {...props}>
<Layout.Header {...headerProps} />
<Layout.Content {...contentProps} />
<Layout.Footer {...footerProps} />
</Layout>
</Layout>
);
});
// List
testPair('List', props => (
<List
{...props}
itemLayout="horizontal"
dataSource={['']}
renderItem={() => (
<List.Item {...props}>
<List.Item.Meta
{...props}
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title="Ant Design"
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
));
// Mention
testPair('Mention', props => (
<Mention {...props} />
));
// Menu
testPair('Menu', props => (
<Menu
{...props}
defaultOpenKeys={['bamboo']}
mode="inline"
>
<Menu.SubMenu {...props} key="bamboo" title="bamboo">
<Menu.ItemGroup {...props} key="g1" title="Item 1">
<Menu.Item {...props} key="1">Light</Menu.Item>
</Menu.ItemGroup>
</Menu.SubMenu>
</Menu>
));
// Modal
testPair('Modal', props => (
<div>
<Modal
{...props}
visible
>
Bamboo is Little Light
</Modal>
</div>
));
// Pagination
testPair('Pagination', props => (
<div>
<Pagination showSizeChanger showQuickJumper {...props} />
<Pagination size="small" showSizeChanger showQuickJumper {...props} />
</div>
));
// Popconfirm
testPair('Popconfirm', props => (
<div>
<Popconfirm
{...props}
visible
>
<span>Bamboo</span>
</Popconfirm>
</div>
));
// Popover
testPair('Popover', props => (
<div>
<Popover
{...props}
visible
>
<span>Light</span>
</Popover>
</div>
));
// Progress
testPair('Progress', props => (
<Progress {...props} />
));
// Radio
testPair('Radio', props => (
<div>
<Radio.Group {...props}>
<Radio {...props}>Bamboo</Radio>
</Radio.Group>
<Radio.Group {...props}>
<Radio.Button {...props}>Light</Radio.Button>
</Radio.Group>
</div>
));
// Rate
testPair('Rate', props => (
<Rate {...props} />
));
// Select
testPair('Select', props => (
<Select
{...props}
open
>
<Select.OptGroup key="grp">
<Select.Option key="Bamboo">Light</Select.Option>
</Select.OptGroup>
</Select>
));
// Skeleton
testPair('Skeleton', props => (
<Skeleton title avatar paragraph {...props} />
));
// Slider
testPair('Slider', (props) => {
const myProps = { ...props };
if (myProps.prefixCls) {
myProps.tooltipPrefixCls = `${myProps.prefixCls}-tooltip`;
}
return (
<Slider tooltipVisible {...myProps} />
);
});
// Spin
testPair('Spin', props => (
<Spin {...props} />
));
// Steps
testPair('Steps', (props) => {
const myProps = { ...props };
if (props.prefixCls) {
myProps.iconPrefix = 'prefixIcon';
}
return (
<Steps {...props}>
<Steps.Step title="Bamboo" description="Little Light" />
</Steps>
);
});
// Switch
testPair('Switch', props => (
<Switch {...props} />
));
// Table
testPair('Table', (props) => {
const columns = [{
title: 'Name',
dataIndex: 'name',
filters: [{
text: 'Joe',
value: 'Joe',
}, {
text: 'Submenu',
value: 'Submenu',
children: [{
text: 'Green',
value: 'Green',
}],
}],
filterDropdownVisible: true,
onFilter: (value, record) => record.name.indexOf(value) === 0,
sorter: (a, b) => a.name.length - b.name.length,
}];
const myProps = { ...props };
if (props.prefixCls) {
myProps.dropdownPrefixCls = 'prefix-dropdown';
}
return (
<Table columns={columns} {...props} />
);
});
// Tabs
testPair('Tabs', props => (
<Tabs {...props}>
<Tabs.TabPane tab="Bamboo" key="Light" />
</Tabs>
));
// Tags
testPair('Tags', props => (
<div>
<Tag {...props}>Bamboo</Tag>
<Tag.CheckableTag {...props}>Light</Tag.CheckableTag>
</div>
));
// TimePicker
testPair('TimePicker', props => (
<TimePicker {...props} open defaultOpenValue={moment('00:00:00', 'HH:mm:ss')} />
));
// Timeline
testPair('Timeline', props => (
<Timeline {...props}>
<Timeline.Item {...props}>Bamboo</Timeline.Item>
</Timeline>
));
// Tooltip
testPair('Tooltip', props => (
<Tooltip {...props} title="Bamboo" visible>
<span>Light</span>
</Tooltip>
));
// Transfer
testPair('Transfer', props => (
<Transfer
{...props}
dataSource={[]}
/>
));
// Tree
testPair('Tree', props => (
<div>
<Tree {...props}>
<Tree.TreeNode title="bamboo" />
</Tree>
<Tree.DirectoryTree {...props}>
<Tree.TreeNode title="bamboo" />
</Tree.DirectoryTree>
</div>
));
// TreeSelect
testPair('TreeSelect', props => (
<TreeSelect {...props} open>
<TreeSelect.TreeNode title="bamboo" value="light" />
</TreeSelect>
));
// Upload
testPair('Upload', props => (
<Upload
{...props}
defaultFileList={[{
uid: '1',
name: 'xxx.png',
status: 'done',
}]}
>
<span />
</Upload>
));
});
});

View File

@ -28,3 +28,4 @@ return (
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| getPopupContainer | to set the container of the popup element. The default is to create a `div` element in `body`. | Function(triggerNode) | `() => document.body` |
| prefixCls | set prefix class | string | ant |

View File

@ -1,25 +1,60 @@
import * as React from 'react';
import createReactContext, { Context } from 'create-react-context';
export interface ConfigProviderProps {
export interface ConfigConsumerProps {
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
rootPrefixCls?: string;
getPrefixCls: (suffixCls: string, customizePrefixCls?: string) => string;
}
const ConfigContext: Context<ConfigProviderProps | null> = createReactContext({});
interface ConfigProviderProps {
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
prefixCls?: string;
children?: React.ReactNode;
}
const ConfigProvider: React.SFC<ConfigProviderProps> = (props) => {
const { getPopupContainer, children } = props;
const config = {
getPopupContainer,
const ConfigContext: Context<ConfigConsumerProps | null> = createReactContext({
getPrefixCls: (suffixCls: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return `ant-${suffixCls}`;
},
});
export const ConfigConsumer = ConfigContext.Consumer;
class ConfigProvider extends React.Component<ConfigProviderProps> {
getPrefixCls = (suffixCls: string, customizePrefixCls?: string) => {
const { prefixCls = 'ant' } = this.props;
if (customizePrefixCls) return customizePrefixCls;
return suffixCls ? `${prefixCls}-${suffixCls}` : prefixCls;
};
return (
<ConfigContext.Provider value={config}>
{children}
</ConfigContext.Provider>
);
}
renderProvider = (context: ConfigConsumerProps) => {
const { getPopupContainer, children } = this.props;
export const ConfigConsumer = ConfigContext.Consumer;
const config: ConfigConsumerProps = {
...context,
getPopupContainer,
getPrefixCls: this.getPrefixCls,
};
return (
<ConfigContext.Provider value={config}>
{children}
</ConfigContext.Provider>
);
}
render() {
return (
<ConfigConsumer>
{this.renderProvider}
</ConfigConsumer>
);
}
}
export default ConfigProvider;

View File

@ -29,3 +29,4 @@ return (
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | Function(triggerNode) | () => document.body |
| prefixCls | 设置统一样式前缀 | string | ant |

View File

@ -8,6 +8,7 @@ import classNames from 'classnames';
import shallowequal from 'shallowequal';
import Icon from '../icon';
import Tag from '../tag';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import interopDefault from '../_util/interopDefault';
import { RangePickerValue, RangePickerPresetRange } from './interface';
@ -67,8 +68,6 @@ function fixLocale(value: RangePickerValue | undefined, localeCode: string) {
class RangePicker extends React.Component<any, RangePickerState> {
static defaultProps = {
prefixCls: 'ant-calendar',
tagPrefixCls: 'ant-tag',
allowClear: true,
showToday: false,
};
@ -97,6 +96,8 @@ class RangePicker extends React.Component<any, RangePickerState> {
}
private picker: HTMLSpanElement;
private prefixCls?: string;
private tagPrefixCls?: string;
constructor(props: any) {
super(props);
@ -215,7 +216,8 @@ class RangePicker extends React.Component<any, RangePickerState> {
}
renderFooter = (...args: any[]) => {
const { prefixCls, ranges, renderExtraFooter, tagPrefixCls } = this.props;
const { ranges, renderExtraFooter } = this.props;
const { prefixCls, tagPrefixCls } = this;
if (!ranges && !renderExtraFooter) {
return null;
}
@ -247,17 +249,27 @@ class RangePicker extends React.Component<any, RangePickerState> {
return [rangeNode, customFooter];
}
render() {
renderRangePicker = ({ getPrefixCls }: ConfigConsumerProps) => {
const { state, props } = this;
const { value, showDate, hoverValue, open } = state;
const {
prefixCls, popupStyle, style,
prefixCls: customizePrefixCls,
tagPrefixCls: customizeTagPrefixCls,
popupStyle, style,
disabledDate, disabledTime,
showTime, showToday,
ranges, onOk, locale, localeCode, format,
dateRender, onCalendarChange, suffixIcon,
} = props;
const prefixCls = getPrefixCls('calendar', customizePrefixCls);
const tagPrefixCls = getPrefixCls('tag', customizeTagPrefixCls);
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this.prefixCls = prefixCls;
this.tagPrefixCls = tagPrefixCls;
fixLocale(value, localeCode);
fixLocale(showDate, localeCode);
@ -398,6 +410,14 @@ class RangePicker extends React.Component<any, RangePickerState> {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderRangePicker}
</ConfigConsumer>
);
}
}
polyfill(RangePicker);

View File

@ -5,6 +5,7 @@ import Calendar from 'rc-calendar';
import RcDatePicker from 'rc-calendar/lib/Picker';
import classNames from 'classnames';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import interopDefault from '../_util/interopDefault';
function formatValue(value: moment.Moment | null, format: string): string {
@ -25,6 +26,7 @@ class WeekPicker extends React.Component<any, any> {
}
private input: any;
private prefixCls?: string;
constructor(props: any) {
super(props);
@ -41,7 +43,7 @@ class WeekPicker extends React.Component<any, any> {
}
weekDateRender = (current: any) => {
const selectedValue = this.state.value;
const { prefixCls } = this.props;
const { prefixCls } = this;
if (selectedValue &&
current.year() === selectedValue.year() &&
current.week() === selectedValue.week()) {
@ -84,13 +86,20 @@ class WeekPicker extends React.Component<any, any> {
this.input = node;
}
render() {
renderWeekPicker = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls, className, disabled, pickerClass, popupStyle,
prefixCls: customizePrefixCls,
className, disabled, pickerClass, popupStyle,
pickerInputClass, format, allowClear, locale, localeCode, disabledDate,
style, onFocus, onBlur, id, suffixIcon,
} = this.props;
const prefixCls = getPrefixCls('calendar', customizePrefixCls);
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this.prefixCls = prefixCls;
const pickerValue = this.state.value;
if (pickerValue && localeCode) {
pickerValue.locale(localeCode);
@ -171,6 +180,14 @@ class WeekPicker extends React.Component<any, any> {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderWeekPicker}
</ConfigConsumer>
);
}
}
polyfill(WeekPicker);

View File

@ -6,6 +6,8 @@ import RcDatePicker from 'rc-calendar/lib/Picker';
import classNames from 'classnames';
import omit from 'omit.js';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import interopDefault from '../_util/interopDefault';
import getDataOrAriaProps from '../_util/getDataOrAriaProps';
@ -25,7 +27,6 @@ export interface PickerState {
export default function createPicker(TheCalendar: React.ComponentClass): any {
class CalenderWrapper extends React.Component<any, PickerState> {
static defaultProps = {
prefixCls: 'ant-calendar',
allowClear: true,
showToday: true,
};
@ -51,6 +52,7 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
}
private input: any;
private prefixCls?: string;
constructor(props: any) {
super(props);
@ -69,7 +71,8 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
}
renderFooter = (...args: any[]) => {
const { prefixCls, renderExtraFooter } = this.props;
const { renderExtraFooter } = this.props;
const { prefixCls } = this;
return renderExtraFooter ? (
<div className={`${prefixCls}-footer-extra`}>
{renderExtraFooter(...args)}
@ -122,10 +125,16 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
this.input = node;
}
render() {
renderPicker = ({ getPrefixCls }: ConfigConsumerProps) => {
const { value, showDate, open } = this.state;
const props = omit(this.props, ['onChange']);
const { prefixCls, locale, localeCode, suffixIcon } = props;
const { prefixCls: customizePrefixCls, locale, localeCode, suffixIcon } = props;
const prefixCls = getPrefixCls('calendar', customizePrefixCls);
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this.prefixCls = prefixCls;
const placeholder = ('placeholder' in props)
? props.placeholder : locale.lang.placeholder;
@ -249,6 +258,14 @@ export default function createPicker(TheCalendar: React.ComponentClass): any {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderPicker}
</ConfigConsumer>
);
}
}
polyfill(CalenderWrapper);
return CalenderWrapper;

View File

@ -1,9 +1,10 @@
import * as React from 'react';
import TimePickerPanel from 'rc-time-picker/lib/Panel';
import classNames from 'classnames';
import enUS from './locale/en_US';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { generateShowHourMinuteSecond } from '../time-picker';
import enUS from './locale/en_US';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function getColumns({ showHour, showMinute, showSecond, use12Hours }: any) {
let column = 0;
@ -35,8 +36,6 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, defaultFor
onOpenChange() {
},
locale: {},
prefixCls: 'ant-calendar',
inputPrefixCls: 'ant-input',
};
private picker: any;
@ -106,51 +105,61 @@ export default function wrapPicker(Picker: React.ComponentClass<any>, defaultFor
}
renderPicker = (locale: any, localeCode: string) => {
const props = this.props;
const { prefixCls, inputPrefixCls } = props;
const pickerClass = classNames(`${prefixCls}-picker`, {
[`${prefixCls}-picker-${props.size}`]: !!props.size,
});
const pickerInputClass = classNames(`${prefixCls}-picker-input`, inputPrefixCls, {
[`${inputPrefixCls}-lg`]: props.size === 'large',
[`${inputPrefixCls}-sm`]: props.size === 'small',
[`${inputPrefixCls}-disabled`]: props.disabled,
});
const timeFormat = (props.showTime && props.showTime.format) || 'HH:mm:ss';
const rcTimePickerProps = {
...generateShowHourMinuteSecond(timeFormat),
format: timeFormat,
use12Hours: (props.showTime && props.showTime.use12Hours),
};
const columns = getColumns(rcTimePickerProps);
const timePickerCls = `${prefixCls}-time-picker-column-${columns}`;
const timePicker = props.showTime ? (
<TimePickerPanel
{...rcTimePickerProps}
{...props.showTime}
prefixCls={`${prefixCls}-time-picker`}
className={timePickerCls}
placeholder={locale.timePickerLocale.placeholder}
transitionName="slide-up"
/>
) : null;
return (
<Picker
{...props}
ref={this.savePicker}
pickerClass={pickerClass}
pickerInputClass={pickerInputClass}
locale={locale}
localeCode={localeCode}
timePicker={timePicker}
onOpenChange={this.handleOpenChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
/>
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls, inputPrefixCls: customizeInputPrefixCls,
size, disabled, showTime,
} = this.props;
const prefixCls = getPrefixCls('calendar', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const pickerClass = classNames(`${prefixCls}-picker`, {
[`${prefixCls}-picker-${size}`]: !!size,
});
const pickerInputClass = classNames(`${prefixCls}-picker-input`, inputPrefixCls, {
[`${inputPrefixCls}-lg`]: size === 'large',
[`${inputPrefixCls}-sm`]: size === 'small',
[`${inputPrefixCls}-disabled`]: disabled,
});
const timeFormat = (showTime && showTime.format) || 'HH:mm:ss';
const rcTimePickerProps = {
...generateShowHourMinuteSecond(timeFormat),
format: timeFormat,
use12Hours: (showTime && showTime.use12Hours),
};
const columns = getColumns(rcTimePickerProps);
const timePickerCls = `${prefixCls}-time-picker-column-${columns}`;
const timePicker = showTime ? (
<TimePickerPanel
{...rcTimePickerProps}
{...showTime}
prefixCls={`${prefixCls}-time-picker`}
className={timePickerCls}
placeholder={locale.timePickerLocale.placeholder}
transitionName="slide-up"
/>
) : null;
return (
<Picker
{...this.props}
ref={this.savePicker}
pickerClass={pickerClass}
pickerInputClass={pickerInputClass}
locale={locale}
localeCode={localeCode}
timePicker={timePicker}
onOpenChange={this.handleOpenChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
/>
);
}}
</ConfigConsumer>
);
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface DividerProps {
prefixCls?: string;
@ -11,24 +12,32 @@ export interface DividerProps {
style?: React.CSSProperties;
}
export default function Divider({
prefixCls = 'ant',
type = 'horizontal',
orientation = '',
className,
children,
dashed,
...restProps
}: DividerProps) {
const orientationPrefix = (orientation.length > 0) ? '-' + orientation : orientation;
const classString = classNames(
className, `${prefixCls}-divider`, `${prefixCls}-divider-${type}`, {
[`${prefixCls}-divider-with-text${orientationPrefix}`]: children,
[`${prefixCls}-divider-dashed`]: !!dashed,
});
return (
<div className={classString} {...restProps}>
{children && <span className={`${prefixCls}-divider-inner-text`}>{children}</span>}
</div>
);
}
const Divider: React.SFC<DividerProps> = props => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
type = 'horizontal',
orientation = '',
className,
children,
dashed,
...restProps
} = props;
const prefixCls = getPrefixCls('divider', customizePrefixCls);
const orientationPrefix = (orientation.length > 0) ? '-' + orientation : orientation;
const classString = classNames(
className, prefixCls, `${prefixCls}-${type}`, {
[`${prefixCls}-with-text${orientationPrefix}`]: children,
[`${prefixCls}-dashed`]: !!dashed,
});
return (
<div className={classString} {...restProps}>
{children && <span className={`${prefixCls}-inner-text`}>{children}</span>}
</div>
);
}}
</ConfigConsumer>
);
export default Divider;

View File

@ -5,6 +5,7 @@ import createReactContext, { Context } from 'create-react-context';
import warning from 'warning';
import classNames from 'classnames';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const DrawerContext: Context<Drawer | null> = createReactContext(null);
@ -66,7 +67,6 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
};
static defaultProps = {
prefixCls: 'ant-drawer',
width: 256,
height: 256,
closable: true,
@ -144,8 +144,22 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
}
}
getRcDrawerStyle = () => {
const { zIndex, placement, maskStyle } = this.props;
return this.state.push
? {
...maskStyle,
zIndex,
transform: this.getPushTransform(placement),
}
: {
...maskStyle,
zIndex,
};
}
// render drawer body dom
renderBody = () => {
renderBody = (prefixCls: string) => {
if (this.destoryClose && !this.props.visible) {
return null;
}
@ -165,7 +179,7 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
containerStyle.opacity = 0;
containerStyle.transition = 'opacity .3s';
}
const { prefixCls, title, closable } = this.props;
const { title, closable } = this.props;
// is have header dom
let header;
@ -207,23 +221,13 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
);
}
getRcDrawerStyle = () => {
const { zIndex, placement, maskStyle } = this.props;
return this.state.push
? {
...maskStyle,
zIndex,
transform: this.getPushTransform(placement),
}
: {
...maskStyle,
zIndex,
};
}
// render Provider for Multi-level drawe
// render Provider for Multi-level drawer
renderProvider = (value: Drawer) => {
const { zIndex, style, placement, className, wrapClassName, width, height, ...rest } = this.props;
const {
prefixCls: customizePrefixCls,
zIndex, style, placement, className, wrapClassName, width, height,
...rest
} = this.props;
warning(wrapClassName === undefined, 'wrapClassName is deprecated, please use className instead.');
const haveMask = rest.mask ? "" : "no-mask";
this.parentDrawer = value;
@ -235,19 +239,28 @@ export default class Drawer extends React.Component<DrawerProps, IDrawerState> {
}
return (
<DrawerContext.Provider value={this}>
<RcDrawer
handler={false}
{...rest}
{...offsetStyle}
open={this.props.visible}
onMaskClick={this.onMaskClick}
showMask={this.props.mask}
placement={placement}
style={this.getRcDrawerStyle()}
className={classNames(wrapClassName, className, haveMask)}
>
{this.renderBody()}
</RcDrawer>
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const prefixCls = getPrefixCls('drawer', customizePrefixCls);
return (
<RcDrawer
handler={false}
{...rest}
{...offsetStyle}
prefixCls={prefixCls}
open={this.props.visible}
onMaskClick={this.onMaskClick}
showMask={this.props.mask}
placement={placement}
style={this.getRcDrawerStyle()}
className={classNames(wrapClassName, className, haveMask)}
>
{this.renderBody(prefixCls)}
</RcDrawer>
);
}}
</ConfigConsumer>
</DrawerContext.Provider>
);
}

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import Button from '../button';
import { ButtonHTMLType } from '../button/button';
import { ButtonGroupProps } from '../button/button-group';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Dropdown, { DropDownProps } from './dropdown';
import classNames from 'classnames';
const ButtonGroup = Button.Group;
@ -19,17 +19,18 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
static defaultProps = {
placement: 'bottomRight',
type: 'default',
prefixCls: 'ant-dropdown-button',
};
renderButton = ({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
renderButton = ({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
type, disabled, onClick, htmlType, children,
prefixCls, className, overlay, trigger, align,
className, overlay, trigger, align,
visible, onVisibleChange, placement, getPopupContainer,
...restProps
} = this.props;
const prefixCls = getPrefixCls('dropdown-button', customizePrefixCls);
const dropdownProps = {
align,
overlay,

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import RcDropdown from 'rc-dropdown';
import classNames from 'classnames';
import DropdownButton from './dropdown-button';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import Icon from '../icon';
@ -24,7 +24,6 @@ export interface DropDownProps {
export default class Dropdown extends React.Component<DropDownProps, any> {
static Button: typeof DropdownButton;
static defaultProps = {
prefixCls: 'ant-dropdown',
mouseEnterDelay: 0.15,
mouseLeaveDelay: 0.1,
placement: 'bottomLeft',
@ -52,9 +51,13 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
}
}
renderDropDown = ({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
const { children, prefixCls, overlay: overlayElements, trigger, disabled, getPopupContainer } = this.props;
renderDropDown = ({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
children, overlay: overlayElements, trigger, disabled, getPopupContainer,
} = this.props;
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
const child = React.Children.only(children);
const overlay = React.Children.only(overlayElements);
@ -90,6 +93,7 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
<RcDropdown
alignPoint={alignPoint}
{...this.props}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer || getContextPopupContainer}
transitionName={this.getTransitionName()}
trigger={triggerActions}

View File

@ -4,10 +4,11 @@ import classNames from 'classnames';
import createDOMForm from 'rc-form/lib/createDOMForm';
import createFormField from 'rc-form/lib/createFormField';
import omit from 'omit.js';
import warning from '../_util/warning';
import FormItem from './FormItem';
import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { Omit } from '../_util/type';
import warning from '../_util/warning';
type FormCreateOptionMessagesCallback = (...args: any[]) => string;
@ -145,7 +146,6 @@ export interface ComponentDecorator {
export default class Form extends React.Component<FormProps, any> {
static defaultProps = {
prefixCls: 'ant-form',
layout: 'horizontal' as FormLayout,
hideRequiredMark: false,
onSubmit(e: React.FormEvent<HTMLFormElement>) {
@ -191,10 +191,12 @@ export default class Form extends React.Component<FormProps, any> {
};
}
render() {
renderForm = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls, hideRequiredMark, className = '', layout,
prefixCls: customizePrefixCls,
hideRequiredMark, className = '', layout,
} = this.props;
const prefixCls = getPrefixCls('form', customizePrefixCls);
const formClassName = classNames(prefixCls, {
[`${prefixCls}-horizontal`]: layout === 'horizontal',
[`${prefixCls}-vertical`]: layout === 'vertical',
@ -212,4 +214,12 @@ export default class Form extends React.Component<FormProps, any> {
return <form {...formProps} className={formClassName} />;
}
render() {
return (
<ConfigConsumer>
{this.renderForm}
</ConfigConsumer>
);
}
}

View File

@ -4,11 +4,12 @@ import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import intersperse from 'intersperse';
import Animate from 'rc-animate';
import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants';
import Row from '../grid/row';
import Col, { ColProps } from '../grid/col';
import warning from '../_util/warning';
import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
export interface FormItemProps {
prefixCls?: string;
@ -33,7 +34,6 @@ export interface FormItemContext {
export default class FormItem extends React.Component<FormItemProps, any> {
static defaultProps = {
hasFeedback: false,
prefixCls: 'ant-form',
colon: true,
};
@ -137,8 +137,7 @@ export default class FormItem extends React.Component<FormItemProps, any> {
}
}
renderHelp() {
const prefixCls = this.props.prefixCls;
renderHelp(prefixCls: string) {
const help = this.getHelpMessage();
const children = help ? (
<div className={`${prefixCls}-explain`} key="help">
@ -161,8 +160,8 @@ export default class FormItem extends React.Component<FormItemProps, any> {
);
}
renderExtra() {
const { prefixCls, extra } = this.props;
renderExtra(prefixCls: string) {
const { extra } = this.props;
return extra ? (
<div className={`${prefixCls}-extra`}>{extra}</div>
) : null;
@ -187,16 +186,16 @@ export default class FormItem extends React.Component<FormItemProps, any> {
return '';
}
renderValidateWrapper(c1: React.ReactNode, c2: React.ReactNode, c3: React.ReactNode) {
renderValidateWrapper(prefixCls: string, c1: React.ReactNode, c2: React.ReactNode, c3: React.ReactNode) {
const props = this.props;
const onlyControl = this.getOnlyControl;
const validateStatus = (props.validateStatus === undefined && onlyControl) ?
this.getValidateStatus() :
props.validateStatus;
let classes = `${this.props.prefixCls}-item-control`;
let classes = `${prefixCls}-item-control`;
if (validateStatus) {
classes = classNames(`${this.props.prefixCls}-item-control`, {
classes = classNames(`${prefixCls}-item-control`, {
'has-feedback': props.hasFeedback || validateStatus === 'validating',
'has-success': validateStatus === 'success',
'has-warning': validateStatus === 'warning',
@ -225,13 +224,13 @@ export default class FormItem extends React.Component<FormItemProps, any> {
}
const icon = (props.hasFeedback && iconType) ?
<span className={`${this.props.prefixCls}-item-children-icon`}>
<span className={`${prefixCls}-item-children-icon`}>
<Icon type={iconType} theme={iconType === 'loading' ? 'outlined' : 'filled'} />
</span> : null;
return (
<div className={classes}>
<span className={`${this.props.prefixCls}-item-children`}>
<span className={`${prefixCls}-item-children`}>
{c1}{icon}
</span>
{c2}{c3}
@ -239,8 +238,8 @@ export default class FormItem extends React.Component<FormItemProps, any> {
);
}
renderWrapper(children: React.ReactNode) {
const { prefixCls, wrapperCol } = this.props;
renderWrapper(prefixCls: string, children: React.ReactNode) {
const { wrapperCol } = this.props;
const className = classNames(
`${prefixCls}-item-control-wrapper`,
wrapperCol && wrapperCol.className,
@ -291,8 +290,8 @@ export default class FormItem extends React.Component<FormItemProps, any> {
}
}
renderLabel() {
const { prefixCls, label, labelCol, colon, id } = this.props;
renderLabel(prefixCls: string) {
const { label, labelCol, colon, id } = this.props;
const context = this.context;
const required = this.isRequired();
@ -326,29 +325,34 @@ export default class FormItem extends React.Component<FormItemProps, any> {
) : null;
}
renderChildren() {
renderChildren(prefixCls: string) {
const { children } = this.props;
return [
this.renderLabel(),
this.renderLabel(prefixCls),
this.renderWrapper(
prefixCls,
this.renderValidateWrapper(
prefixCls,
children,
this.renderHelp(),
this.renderExtra(),
this.renderHelp(prefixCls),
this.renderExtra(prefixCls),
),
),
];
}
renderFormItem(children: React.ReactNode) {
const props = this.props;
const prefixCls = props.prefixCls;
const style = props.style;
renderFormItem = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
style, colon, className,
} = this.props;
const prefixCls = getPrefixCls('form', customizePrefixCls);
const children = this.renderChildren(prefixCls);
const itemClassName = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-with-help`]: this.helpShow,
[`${prefixCls}-item-no-colon`]: !props.colon,
[`${props.className}`]: !!props.className,
[`${prefixCls}-item-no-colon`]: !colon,
[`${className}`]: !!className,
};
return (
<Row className={classNames(itemClassName)} style={style}>
@ -358,7 +362,10 @@ export default class FormItem extends React.Component<FormItemProps, any> {
}
render() {
const children = this.renderChildren();
return this.renderFormItem(children);
return (
<ConfigConsumer>
{this.renderFormItem}
</ConfigConsumer>
);
}
}

View File

@ -1,13 +1,13 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import { mount } from 'enzyme';
import Form from '..';
describe('Form', () => {
it('hideRequiredMark', () => {
const wrapper = shallow(
const wrapper = mount(
<Form hideRequiredMark />
);
expect(wrapper.hasClass('ant-form-hide-required-mark')).toBe(true);
expect(wrapper.find('form').hasClass('ant-form-hide-required-mark')).toBe(true);
});
describe('wrappedComponentRef', () => {

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import RowContext from './RowContext';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const stringOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
const objectOrNumber = PropTypes.oneOfType([PropTypes.object, PropTypes.number]);
@ -46,9 +47,14 @@ export default class Col extends React.Component<ColProps, {}> {
xxl: objectOrNumber,
};
render() {
renderCol = ({ getPrefixCls }: ConfigConsumerProps) => {
const props: any = this.props;
const { span, order, offset, push, pull, className, children, prefixCls = 'ant-col', ...others } = props;
const {
prefixCls: customizePrefixCls,
span, order, offset, push, pull, className, children,
...others
} = props;
const prefixCls = getPrefixCls('col', customizePrefixCls);
let sizeClassObj = {};
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
let sizeProps: ColSize = {};
@ -93,4 +99,12 @@ export default class Col extends React.Component<ColProps, {}> {
</RowContext.Consumer>
)
}
render() {
return (
<ConfigConsumer>
{this.renderCol}
</ConfigConsumer>
);
}
}

View File

@ -1,3 +1,5 @@
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
let enquire: any;
@ -112,11 +114,13 @@ export default class Row extends React.Component<RowProps, RowState> {
}
return gutter as number;
}
render() {
renderRow = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
type, justify, align, className, style, children,
prefixCls = 'ant-row', ...others
...others
} = this.props;
const prefixCls = getPrefixCls('row', customizePrefixCls);
const gutter = this.getGutter();
const classes = classNames({
[prefixCls]: !type,
@ -139,4 +143,12 @@ export default class Row extends React.Component<RowProps, RowState> {
</RowContext.Provider>
);
}
render() {
return (
<ConfigConsumer>
{this.renderRow}
</ConfigConsumer>
);
}
}

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import classNames from 'classnames';
import RcInputNumber from 'rc-input-number';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { Omit } from '../_util/type';
// omitting this attrs because they conflicts with the ones defined in InputNumberProps
@ -31,32 +32,11 @@ export interface InputNumberProps extends Omit<React.InputHTMLAttributes<HTMLInp
export default class InputNumber extends React.Component<InputNumberProps, any> {
static defaultProps = {
prefixCls: 'ant-input-number',
step: 1,
};
private inputNumberRef: any;
render() {
const { className, size, ...others } = this.props;
const inputNumberClass = classNames({
[`${this.props.prefixCls}-lg`]: size === 'large',
[`${this.props.prefixCls}-sm`]: size === 'small',
}, className);
const upIcon = <Icon type="up" className={`${this.props.prefixCls}-handler-up-inner`}/>;
const downIcon = <Icon type="down" className={`${this.props.prefixCls}-handler-down-inner`}/>;
return (
<RcInputNumber
ref={(c: any) => this.inputNumberRef = c}
className={inputNumberClass}
upHandler={upIcon}
downHandler={downIcon}
{...others}
/>
);
}
focus() {
this.inputNumberRef.focus();
}
@ -64,4 +44,34 @@ export default class InputNumber extends React.Component<InputNumberProps, any>
blur() {
this.inputNumberRef.blur();
}
renderInputNumber = ({ getPrefixCls }: ConfigConsumerProps) => {
const { className, size, prefixCls: customizePrefixCls, ...others } = this.props;
const prefixCls = getPrefixCls('input-number', customizePrefixCls);
const inputNumberClass = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
}, className);
const upIcon = <Icon type="up" className={`${prefixCls}-handler-up-inner`}/>;
const downIcon = <Icon type="down" className={`${prefixCls}-handler-down-inner`}/>;
return (
<RcInputNumber
ref={(c: any) => this.inputNumberRef = c}
className={inputNumberClass}
upHandler={upIcon}
downHandler={downIcon}
prefixCls={prefixCls}
{...others}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderInputNumber}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface GroupProps {
className?: string;
@ -14,25 +15,30 @@ export interface GroupProps {
compact?: boolean;
}
const Group: React.StatelessComponent<GroupProps> = (props) => {
const { prefixCls = 'ant-input-group', className = '' } = props;
const cls = classNames(prefixCls, {
[`${prefixCls}-lg`]: props.size === 'large',
[`${prefixCls}-sm`]: props.size === 'small',
[`${prefixCls}-compact`]: props.compact,
}, className);
return (
<span
className={cls}
style={props.style}
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
onFocus={props.onFocus}
onBlur={props.onBlur}
>
{props.children}
</span>
);
};
const Group: React.StatelessComponent<GroupProps> = props => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '' } = props;
const prefixCls = getPrefixCls('input-group', customizePrefixCls);
const cls = classNames(prefixCls, {
[`${prefixCls}-lg`]: props.size === 'large',
[`${prefixCls}-sm`]: props.size === 'small',
[`${prefixCls}-compact`]: props.compact,
}, className);
return (
<span
className={cls}
style={props.style}
onMouseEnter={props.onMouseEnter}
onMouseLeave={props.onMouseLeave}
onFocus={props.onFocus}
onBlur={props.onBlur}
>
{props.children}
</span>
);
}}
</ConfigConsumer>
);
export default Group;

View File

@ -5,6 +5,7 @@ import omit from 'omit.js';
import Group from './Group';
import Search from './Search';
import TextArea from './TextArea';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { Omit } from '../_util/type';
function fixControlledValue<T>(value: T) {
@ -30,7 +31,6 @@ export default class Input extends React.Component<InputProps, any> {
static TextArea: typeof TextArea;
static defaultProps = {
prefixCls: 'ant-input',
type: 'text',
disabled: false,
};
@ -86,8 +86,8 @@ export default class Input extends React.Component<InputProps, any> {
this.input.select();
}
getInputClassName() {
const { prefixCls, size, disabled } = this.props;
getInputClassName(prefixCls: string) {
const { size, disabled } = this.props;
return classNames(prefixCls, {
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-lg`]: size === 'large',
@ -99,14 +99,14 @@ export default class Input extends React.Component<InputProps, any> {
this.input = node;
}
renderLabeledInput(children: React.ReactElement<any>) {
renderLabeledInput(prefixCls: string, children: React.ReactElement<any>) {
const props = this.props;
// Not wrap when there is not addons
if ((!props.addonBefore && !props.addonAfter)) {
return children;
}
const wrapperClassName = `${props.prefixCls}-group`;
const wrapperClassName = `${prefixCls}-group`;
const addonClassName = `${wrapperClassName}-addon`;
const addonBefore = props.addonBefore ? (
<span className={addonClassName}>
@ -120,13 +120,13 @@ export default class Input extends React.Component<InputProps, any> {
</span>
) : null;
const className = classNames(`${props.prefixCls}-wrapper`, {
const className = classNames(`${prefixCls}-wrapper`, {
[wrapperClassName]: (addonBefore || addonAfter),
});
const groupClassName = classNames(`${props.prefixCls}-group-wrapper`, {
[`${props.prefixCls}-group-wrapper-sm`]: props.size === 'small',
[`${props.prefixCls}-group-wrapper-lg`]: props.size === 'large',
const groupClassName = classNames(`${prefixCls}-group-wrapper`, {
[`${prefixCls}-group-wrapper-sm`]: props.size === 'small',
[`${prefixCls}-group-wrapper-lg`]: props.size === 'large',
});
// Need another wrapper for changing display:table to display:inline-block
@ -145,27 +145,27 @@ export default class Input extends React.Component<InputProps, any> {
);
}
renderLabeledIcon(children: React.ReactElement<any>) {
renderLabeledIcon(prefixCls: string, children: React.ReactElement<any>) {
const { props } = this;
if (!('prefix' in props || 'suffix' in props)) {
return children;
}
const prefix = props.prefix ? (
<span className={`${props.prefixCls}-prefix`}>
<span className={`${prefixCls}-prefix`}>
{props.prefix}
</span>
) : null;
const suffix = props.suffix ? (
<span className={`${props.prefixCls}-suffix`}>
<span className={`${prefixCls}-suffix`}>
{props.suffix}
</span>
) : null;
const affixWrapperCls = classNames(props.className, `${props.prefixCls}-affix-wrapper`, {
[`${props.prefixCls}-affix-wrapper-sm`]: props.size === 'small',
[`${props.prefixCls}-affix-wrapper-lg`]: props.size === 'large',
const affixWrapperCls = classNames(props.className, `${prefixCls}-affix-wrapper`, {
[`${prefixCls}-affix-wrapper-sm`]: props.size === 'small',
[`${prefixCls}-affix-wrapper-lg`]: props.size === 'large',
});
return (
<span
@ -173,13 +173,13 @@ export default class Input extends React.Component<InputProps, any> {
style={props.style}
>
{prefix}
{React.cloneElement(children, { style: null, className: this.getInputClassName() })}
{React.cloneElement(children, { style: null, className: this.getInputClassName(prefixCls) })}
{suffix}
</span>
);
}
renderInput() {
renderInput(prefixCls: string) {
const { value, className } = this.props;
// Fix https://fb.me/react-unknown-prop
const otherProps = omit(this.props, [
@ -198,16 +198,27 @@ export default class Input extends React.Component<InputProps, any> {
delete otherProps.defaultValue;
}
return this.renderLabeledIcon(
prefixCls,
<input
{...otherProps}
className={classNames(this.getInputClassName(), className)}
className={classNames(this.getInputClassName(prefixCls), className)}
onKeyDown={this.handleKeyDown}
ref={this.saveInput}
/>,
);
}
renderComponent = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls } = this.props;
const prefixCls = getPrefixCls('input', customizePrefixCls);
return this.renderLabeledInput(prefixCls, this.renderInput(prefixCls));
};
render() {
return this.renderLabeledInput(this.renderInput());
return (
<ConfigConsumer>
{this.renderComponent}
</ConfigConsumer>
);
}
}

View File

@ -3,6 +3,7 @@ import classNames from 'classnames';
import Input, { InputProps } from './Input';
import Icon from '../icon';
import Button from '../button';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface SearchProps extends InputProps {
inputPrefixCls?: string;
@ -12,8 +13,6 @@ export interface SearchProps extends InputProps {
export default class Search extends React.Component<SearchProps, any> {
static defaultProps = {
inputPrefixCls: 'ant-input',
prefixCls: 'ant-input-search',
enterButton: false,
};
@ -39,8 +38,8 @@ export default class Search extends React.Component<SearchProps, any> {
this.input = node;
}
getButtonOrIcon() {
const { enterButton, prefixCls, size, disabled } = this.props;
getButtonOrIcon(prefixCls: string) {
const { enterButton, size, disabled } = this.props;
const enterButtonAsElement = enterButton as React.ReactElement<any>;
let node;
if (!enterButton) {
@ -68,10 +67,16 @@ export default class Search extends React.Component<SearchProps, any> {
});
}
render() {
const { className, prefixCls, inputPrefixCls, size, suffix, enterButton, ...others } = this.props;
renderSearch = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls, inputPrefixCls: customizeInputPrefixCls,
className, size, suffix, enterButton,
...others
} = this.props;
delete (others as any).onSearch;
const buttonOrIcon = this.getButtonOrIcon();
const prefixCls = getPrefixCls('input-search', customizePrefixCls);
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
const buttonOrIcon = this.getButtonOrIcon(prefixCls);
let searchSuffix = suffix ? [suffix, buttonOrIcon] : buttonOrIcon;
if (Array.isArray(searchSuffix)) {
searchSuffix = (searchSuffix as React.ReactElement<any>[]).map((item, index) => {
@ -97,4 +102,12 @@ export default class Search extends React.Component<SearchProps, any> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderSearch}
</ConfigConsumer>
);
}
}

View File

@ -4,6 +4,7 @@ import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';
import ResizeObserver from 'resize-observer-polyfill';
import calculateNodeHeight from './calculateNodeHeight';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function onNextFrame(cb: () => void) {
if (window.requestAnimationFrame) {
@ -38,10 +39,6 @@ export interface TextAreaState {
}
class TextArea extends React.Component<TextAreaProps, TextAreaState> {
static defaultProps = {
prefixCls: 'ant-input',
};
nextFrameActionId: number;
resizeObserver: ResizeObserver | null;
@ -109,13 +106,6 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
this.setState({ textareaStyles });
}
getTextAreaClassName() {
const { prefixCls, className, disabled } = this.props;
return classNames(prefixCls, className, {
[`${prefixCls}-disabled`]: disabled,
});
}
handleTextareaChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
if (!('value' in this.props)) {
this.resizeTextarea();
@ -140,13 +130,19 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
this.textAreaRef = textArea;
}
render() {
const props = this.props;
renderTextArea = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, disabled } = this.props;
const { ...props } = this.props;
const otherProps = omit(props, [
'prefixCls',
'onPressEnter',
'autosize',
]);
const prefixCls = getPrefixCls('input', customizePrefixCls);
const cls = classNames(prefixCls, className, {
[`${prefixCls}-disabled`]: disabled,
});
const style = {
...props.style,
...this.state.textareaStyles,
@ -159,7 +155,7 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
return (
<textarea
{...otherProps}
className={this.getTextAreaClassName()}
className={cls}
style={style}
onKeyDown={this.handleKeyDown}
onChange={this.handleTextareaChange}
@ -167,6 +163,14 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderTextArea}
</ConfigConsumer>
);
}
}
polyfill(TextArea);

View File

@ -4,121 +4,126 @@ exports[`Input should support maxLength 1`] = `
<Input
disabled={false}
maxLength="3"
prefixCls="ant-input"
type="text"
>
<input
className="ant-input"
disabled={false}
maxLength="3"
onKeyDown={[Function]}
type="text"
/>
<Consumer>
<input
className="ant-input"
disabled={false}
maxLength="3"
onKeyDown={[Function]}
type="text"
/>
</Consumer>
</Input>
`;
exports[`Input.Search should support suffix 1`] = `
<Search
enterButton={false}
inputPrefixCls="ant-input"
prefixCls="ant-input-search"
suffix="suffix"
>
<Input
className="ant-input-search"
disabled={false}
onPressEnter={[Function]}
prefixCls="ant-input"
suffix={
Array [
"suffix",
<Icon
className="ant-input-search-icon"
onClick={[Function]}
type="search"
/>,
]
}
type="text"
>
<span
className="ant-input-search ant-input-affix-wrapper"
>
<input
className="ant-input"
disabled={false}
onKeyDown={[Function]}
style={null}
type="text"
/>
<span
className="ant-input-suffix"
>
suffix
<Icon
className="ant-input-search-icon"
key="searchIcon"
onClick={[Function]}
type="search"
>
<i
className="anticon anticon-search ant-input-search-icon"
<Consumer>
<Input
className="ant-input-search"
disabled={false}
onPressEnter={[Function]}
prefixCls="ant-input"
suffix={
Array [
"suffix",
<Icon
className="ant-input-search-icon"
onClick={[Function]}
type="search"
/>,
]
}
type="text"
>
<Consumer>
<span
className="ant-input-search ant-input-affix-wrapper"
>
<input
className="ant-input"
disabled={false}
onKeyDown={[Function]}
style={null}
type="text"
/>
<span
className="ant-input-suffix"
>
<IconReact
className=""
type="search-o"
suffix
<Icon
className="ant-input-search-icon"
key="searchIcon"
onClick={[Function]}
type="search"
>
<svg
aria-hidden="true"
className=""
data-icon="search"
fill="currentColor"
height="1em"
key="svg-search"
viewBox="64 64 896 896"
width="1em"
<i
className="anticon anticon-search ant-input-search-icon"
onClick={[Function]}
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
key="svg-search-svg-0"
/>
</svg>
</IconReact>
</i>
</Icon>
</span>
</span>
</Input>
<IconReact
className=""
type="search-o"
>
<svg
aria-hidden="true"
className=""
data-icon="search"
fill="currentColor"
height="1em"
key="svg-search"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0 0 11.6 0l43.6-43.5a8.2 8.2 0 0 0 0-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
key="svg-search-svg-0"
/>
</svg>
</IconReact>
</i>
</Icon>
</span>
</span>
</Consumer>
</Input>
</Consumer>
</Search>
`;
exports[`TextArea should support disabled 1`] = `
<TextArea
disabled={true}
prefixCls="ant-input"
>
<textarea
className="ant-input ant-input-disabled"
disabled={true}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
<Consumer>
<textarea
className="ant-input ant-input-disabled"
disabled={true}
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
</Consumer>
</TextArea>
`;
exports[`TextArea should support maxLength 1`] = `
<TextArea
maxLength="10"
prefixCls="ant-input"
>
<textarea
className="ant-input"
maxLength="10"
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
<Consumer>
<textarea
className="ant-input"
maxLength="10"
onChange={[Function]}
onKeyDown={[Function]}
style={Object {}}
/>
</Consumer>
</TextArea>
`;

View File

@ -1,3 +1,5 @@
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
// matchMedia polyfill for
// https://github.com/WickyNilliams/enquire.js/issues/82
if (typeof window !== 'undefined') {
@ -72,7 +74,6 @@ class Sider extends React.Component<SiderProps, SiderState> {
static __ANT_LAYOUT_SIDER: any = true;
static defaultProps = {
prefixCls: 'ant-layout-sider',
collapsible: false,
defaultCollapsed: false,
reverseArrow: false,
@ -187,11 +188,14 @@ class Sider extends React.Component<SiderProps, SiderState> {
this.setState({ belowShow: !this.state.belowShow });
}
render() {
const { prefixCls, className, theme,
renderSider = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className, theme,
collapsible, reverseArrow, trigger, style, width, collapsedWidth,
...others
} = this.props;
const prefixCls = getPrefixCls('layout-sider', customizePrefixCls);
const divProps = omit(others, ['collapsed',
'defaultCollapsed', 'onCollapse', 'breakpoint', 'onBreakpoint']);
const rawWidth = this.state.collapsed ? collapsedWidth : width;
@ -237,6 +241,14 @@ class Sider extends React.Component<SiderProps, SiderState> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderSider}
</ConfigConsumer>
);
}
}
polyfill(Sider);

View File

@ -2,23 +2,38 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { SiderProps } from './Sider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface GeneratorProps {
suffixCls: string;
}
export interface BasicProps extends React.HTMLAttributes<HTMLDivElement> {
prefixCls?: string;
hasSider?: boolean;
}
function generator(props: BasicProps) {
function generator({ suffixCls }: GeneratorProps) {
return (BasicComponent: React.ComponentClass<BasicProps>): any => {
return class Adapter extends React.Component<BasicProps, any> {
static Header: any;
static Footer: any;
static Content: any;
static Sider: any;
render() {
const { prefixCls } = props;
renderComponent = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls } = this.props;
const prefixCls = getPrefixCls(suffixCls, customizePrefixCls);
return <BasicComponent prefixCls={prefixCls} {...this.props} />;
}
render() {
return (
<ConfigConsumer>
{this.renderComponent}
</ConfigConsumer>
);
}
};
};
}
@ -73,19 +88,19 @@ const Layout: React.ComponentClass<BasicProps> & {
Content: React.ComponentClass<BasicProps>;
Sider: React.ComponentClass<SiderProps>;
} = generator({
prefixCls: 'ant-layout',
suffixCls: 'layout',
})(BasicLayout);
const Header = generator({
prefixCls: 'ant-layout-header',
suffixCls: 'layout-header',
})(Basic);
const Footer = generator({
prefixCls: 'ant-layout-footer',
suffixCls: 'layout-footer',
})(Basic);
const Content = generator({
prefixCls: 'ant-layout-content',
suffixCls: 'layout-content',
})(Basic);
Layout.Header = Header;

View File

@ -1,8 +1,9 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { Col } from '../grid';
import { ListGridType, ColumnType } from './index';
import { Col } from '../grid';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface ListItemProps {
className?: string;
@ -24,32 +25,37 @@ export interface ListItemMetaProps {
title?: React.ReactNode;
}
export const Meta = (props: ListItemMetaProps) => {
const {
prefixCls = 'ant-list',
className,
avatar,
title,
description,
...others
} = props;
export const Meta = (props: ListItemMetaProps) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className,
avatar,
title,
description,
...others
} = props;
const classString = classNames(`${prefixCls}-item-meta`, className);
const prefixCls = getPrefixCls('list', customizePrefixCls);
const classString = classNames(`${prefixCls}-item-meta`, className);
const content = (
<div className={`${prefixCls}-item-meta-content`}>
{title && <h4 className={`${prefixCls}-item-meta-title`}>{title}</h4>}
{description && <div className={`${prefixCls}-item-meta-description`}>{description}</div>}
</div>
);
const content = (
<div className={`${prefixCls}-item-meta-content`}>
{title && <h4 className={`${prefixCls}-item-meta-title`}>{title}</h4>}
{description && <div className={`${prefixCls}-item-meta-description`}>{description}</div>}
</div>
);
return (
<div {...others} className={classString}>
{avatar && <div className={`${prefixCls}-item-meta-avatar`}>{avatar}</div>}
{(title || description) && content}
</div>
);
};
return (
<div {...others} className={classString}>
{avatar && <div className={`${prefixCls}-item-meta-avatar`}>{avatar}</div>}
{(title || description) && content}
</div>
);
}}
</ConfigConsumer>
);
function getGrid(grid: ListGridType, t: ColumnType) {
return grid[t] && Math.floor(24 / grid[t]!);
@ -76,9 +82,10 @@ export default class Item extends React.Component<ListItemProps, any> {
context: any;
render() {
renderItem = ({ getPrefixCls }: ConfigConsumerProps) => {
const { grid } = this.context;
const { prefixCls = 'ant-list', children, actions, extra, className, ...others } = this.props;
const { prefixCls: customizePrefixCls, children, actions, extra, className, ...others } = this.props;
const prefixCls = getPrefixCls('list', customizePrefixCls);
const classString = classNames(`${prefixCls}-item`, className);
const metaContent: React.ReactElement<any>[] = [];
@ -154,4 +161,12 @@ export default class Item extends React.Component<ListItemProps, any> {
return mainContent;
}
render() {
return (
<ConfigConsumer>
{this.renderItem}
</ConfigConsumer>
);
}
}

View File

@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { SpinProps } from '../spin';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import defaultLocale from '../locale-provider/default';
import Spin from '../spin';
@ -73,7 +74,6 @@ export default class List extends React.Component<ListProps> {
static defaultProps = {
dataSource: [],
prefixCls: 'ant-list',
bordered: false,
split: true,
loading: false,
@ -133,18 +133,19 @@ export default class List extends React.Component<ListProps> {
return !!(loadMore || pagination || footer);
}
renderEmpty = (contextLocale: ListLocale) => {
renderEmpty = (prefixCls: string, contextLocale: ListLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
return (
<div className={`${this.props.prefixCls}-empty-text`}>
<div className={`${prefixCls}-empty-text`}>
{locale.emptyText}
</div>
);
}
render() {
renderList = ({ getPrefixCls }: ConfigConsumerProps) => {
const { paginationCurrent } = this.state;
const {
prefixCls: customizePrefixCls,
bordered,
split,
className,
@ -152,7 +153,6 @@ export default class List extends React.Component<ListProps> {
itemLayout,
loadMore,
pagination,
prefixCls,
grid,
dataSource,
size,
@ -165,6 +165,7 @@ export default class List extends React.Component<ListProps> {
...rest
} = this.props;
const prefixCls = getPrefixCls('list', customizePrefixCls);
let loadingProp = loading;
if (typeof loadingProp === 'boolean') {
loadingProp = {
@ -256,7 +257,9 @@ export default class List extends React.Component<ListProps> {
componentName="Table"
defaultLocale={defaultLocale.Table}
>
{this.renderEmpty}
{(contextLocale: ListLocale) => (
this.renderEmpty(prefixCls, contextLocale)
)}
</LocaleReceiver>
);
}
@ -276,4 +279,12 @@ export default class List extends React.Component<ListProps> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderList}
</ConfigConsumer>
);
}
}

View File

@ -4,6 +4,8 @@ import { polyfill } from 'react-lifecycles-compat';
import classNames from 'classnames';
import shallowequal from 'shallowequal';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type MentionPlacement = 'top' | 'bottom';
export interface MentionProps {
@ -38,7 +40,6 @@ export interface MentionState {
class Mention extends React.Component<MentionProps, MentionState> {
static getMentions = getMentions;
static defaultProps = {
prefixCls: 'ant-mention',
notFoundContent: '无匹配结果,轻敲空格完成输入',
loading: false,
multiLines: false,
@ -119,9 +120,10 @@ class Mention extends React.Component<MentionProps, MentionState> {
mentionRef = (ele: any) => {
this.mentionEle = ele;
}
render() {
const { className = '', prefixCls, loading, placement } = this.props;
renderMention = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className = '', loading, placement } = this.props;
const { suggestions, focus } = this.state;
const prefixCls = getPrefixCls('mention', customizePrefixCls);
const cls = classNames(className, {
[`${prefixCls}-active`]: focus,
[`${prefixCls}-placement-top`]: placement === 'top',
@ -134,6 +136,7 @@ class Mention extends React.Component<MentionProps, MentionState> {
return (
<RcMention
{...this.props}
prefixCls={prefixCls}
className={cls}
ref={this.mentionRef}
onSearchChange={this.onSearchChange}
@ -145,6 +148,14 @@ class Mention extends React.Component<MentionProps, MentionState> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderMention}
</ConfigConsumer>
);
}
}
polyfill(Mention);

View File

@ -2,11 +2,11 @@ import * as React from 'react';
import RcMenu, { Divider, ItemGroup } from 'rc-menu';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import animation from '../_util/openAnimation';
import warning from '../_util/warning';
import SubMenu from './SubMenu';
import Item from './MenuItem';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import animation from '../_util/openAnimation';
import warning from '../_util/warning';
import { SiderContext } from '../layout/Sider';
export interface SelectParam {
@ -28,7 +28,7 @@ export type MenuMode = 'vertical' | 'vertical-left' | 'vertical-right' | 'horizo
export type MenuTheme = 'light' | 'dark';
export interface MenuProps extends ConfigProviderProps {
export interface MenuProps {
id?: string;
theme?: MenuTheme;
mode?: MenuMode;
@ -53,6 +53,7 @@ export interface MenuProps extends ConfigProviderProps {
subMenuOpenDelay?: number;
focusable?: boolean;
onMouseEnter?: (e: MouseEvent) => void;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
}
export interface MenuState {
@ -65,7 +66,6 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
static SubMenu = SubMenu;
static ItemGroup = ItemGroup;
static defaultProps: Partial<MenuProps> = {
prefixCls: 'ant-menu',
className: '',
theme: 'light', // or dark
focusable: false,
@ -225,11 +225,12 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
return menuOpenAnimation;
}
renderMenu = ({ getPopupContainer }: ConfigProviderProps) => {
const { prefixCls, className, theme } = this.props;
renderMenu = ({ getPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, theme } = this.props;
const menuMode = this.getRealMenuMode();
const menuOpenAnimation = this.getMenuOpenAnimation(menuMode!);
const prefixCls = getPrefixCls('menu', customizePrefixCls);
const menuClassName = classNames(className, `${prefixCls}-${theme}`, {
[`${prefixCls}-inline-collapsed`]: this.getInlineCollapsed(),
});
@ -263,6 +264,7 @@ export default class Menu extends React.Component<MenuProps, MenuState> {
getPopupContainer={getPopupContainer}
{...this.props}
{...menuProps}
prefixCls={prefixCls}
onTransitionEnd={this.handleTransitionEnd}
onMouseEnter={this.handleMouseEnter}
/>

View File

@ -3,11 +3,12 @@ import Dialog from 'rc-dialog';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import { getConfirmLocale } from './locale';
import Icon from '../icon';
import Button from '../button';
import { ButtonType, NativeButtonProps } from '../button/button';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { getConfirmLocale } from './locale';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
let mousePosition: { x: number, y: number } | null;
let mousePositionEventBinded: boolean;
@ -106,7 +107,6 @@ export default class Modal extends React.Component<ModalProps, {}> {
static confirm: ModalFunc;
static defaultProps = {
prefixCls: 'ant-modal',
width: 520,
transitionName: 'zoom',
maskTransitionName: 'fade',
@ -187,9 +187,14 @@ export default class Modal extends React.Component<ModalProps, {}> {
);
}
render() {
const { footer, visible, wrapClassName, centered, prefixCls, ...restProps } = this.props;
renderModal = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
footer, visible, wrapClassName, centered,
...restProps
} = this.props;
const prefixCls = getPrefixCls('modal', customizePrefixCls);
const defaultFooter = (
<LocaleReceiver
componentName="Modal"
@ -218,4 +223,12 @@ export default class Modal extends React.Component<ModalProps, {}> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderModal}
</ConfigConsumer>
);
}
}

View File

@ -2,10 +2,11 @@ import * as React from 'react';
import RcPagination from 'rc-pagination';
import enUS from 'rc-pagination/lib/locale/en_US';
import classNames from 'classnames';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import Select from '../select';
import MiniSelect from './MiniSelect';
import Icon from '../icon';
import Select from '../select';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface PaginationProps {
total?: number;
@ -38,13 +39,7 @@ export interface PaginationConfig extends PaginationProps {
export type PaginationLocale = any;
export default class Pagination extends React.Component<PaginationProps, {}> {
static defaultProps = {
prefixCls: 'ant-pagination',
selectPrefixCls: 'ant-select',
};
getIconsProps = () => {
const { prefixCls } = this.props;
getIconsProps = (prefixCls: string) => {
const prevIcon = (
<a className={`${prefixCls}-item-link`}>
<Icon type="left" />
@ -88,17 +83,32 @@ export default class Pagination extends React.Component<PaginationProps, {}> {
}
renderPagination = (contextLocale: PaginationLocale) => {
const { className, size, locale: customLocale, ...restProps } = this.props;
const {
prefixCls: customizePrefixCls, selectPrefixCls: customizeSelectPrefixCls,
className, size, locale: customLocale,
...restProps
} = this.props;
const locale = { ...contextLocale, ...customLocale };
const isSmall = size === 'small';
return (
<RcPagination
{...restProps}
{...this.getIconsProps()}
className={classNames(className, { mini: isSmall })}
selectComponentClass={isSmall ? MiniSelect : Select}
locale={locale}
/>
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const prefixCls = getPrefixCls('pagination', customizePrefixCls);
const selectPrefixCls = getPrefixCls('select', customizeSelectPrefixCls);
return (
<RcPagination
{...restProps}
prefixCls={prefixCls}
selectPrefixCls={selectPrefixCls}
{...this.getIconsProps(prefixCls)}
className={classNames(className, { mini: isSmall })}
selectComponentClass={isSmall ? MiniSelect : Select}
locale={locale}
/>
);
}}
</ConfigConsumer>
);
}

View File

@ -6,6 +6,7 @@ import Button from '../button';
import { ButtonType, NativeButtonProps } from '../button/button';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface PopconfirmProps extends AbstractTooltipProps {
title: React.ReactNode;
@ -31,7 +32,6 @@ export interface PopconfirmLocale {
class Popconfirm extends React.Component<PopconfirmProps, PopconfirmState> {
static defaultProps = {
prefixCls: 'ant-popover',
transitionName: 'zoom-big',
placement: 'top',
trigger: 'click',
@ -100,8 +100,8 @@ class Popconfirm extends React.Component<PopconfirmProps, PopconfirmState> {
this.tooltip = node;
}
renderOverlay = (popconfirmLocale: PopconfirmLocale) => {
const { prefixCls, okButtonProps, cancelButtonProps, title, cancelText, okText, okType, icon } = this.props;
renderOverlay = (prefixCls: string, popconfirmLocale: PopconfirmLocale) => {
const { okButtonProps, cancelButtonProps, title, cancelText, okText, okType, icon } = this.props;
return (
<div>
<div className={`${prefixCls}-inner-content`}>
@ -122,15 +122,18 @@ class Popconfirm extends React.Component<PopconfirmProps, PopconfirmState> {
);
}
render() {
const { prefixCls, placement, ...restProps } = this.props;
renderConfirm = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, placement, ...restProps } = this.props;
const prefixCls = getPrefixCls('popover', customizePrefixCls);
const overlay = (
<LocaleReceiver
componentName="Popconfirm"
defaultLocale={defaultLocale.Popconfirm}
>
{this.renderOverlay}
{(popconfirmLocale: PopconfirmLocale) => (
this.renderOverlay(prefixCls, popconfirmLocale)
)}
</LocaleReceiver>
);
@ -146,6 +149,14 @@ class Popconfirm extends React.Component<PopconfirmProps, PopconfirmState> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderConfirm}
</ConfigConsumer>
);
}
}
polyfill(Popconfirm);

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import Tooltip, { AbstractTooltipProps, TooltipPlacement, TooltipTrigger } from '../tooltip';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
export interface PopoverProps extends AbstractTooltipProps {
@ -9,7 +10,6 @@ export interface PopoverProps extends AbstractTooltipProps {
export default class Popover extends React.Component<PopoverProps, {}> {
static defaultProps = {
prefixCls: 'ant-popover',
placement: 'top' as TooltipPlacement,
transitionName: 'zoom-big',
trigger: 'hover' as TooltipTrigger,
@ -24,8 +24,8 @@ export default class Popover extends React.Component<PopoverProps, {}> {
return this.tooltip.getPopupDomNode();
}
getOverlay() {
const { title, prefixCls, content } = this.props;
getOverlay(prefixCls: string) {
const { title, content } = this.props;
warning(
!('overlay' in this.props),
'Popover[overlay] is removed, please use Popover[content] instead, ' +
@ -45,15 +45,25 @@ export default class Popover extends React.Component<PopoverProps, {}> {
this.tooltip = node;
}
render() {
const props = { ...this.props };
renderPopover = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, ...props } = this.props;
delete props.title;
const prefixCls = getPrefixCls('popover', customizePrefixCls);
return (
<Tooltip
{...props}
prefixCls={prefixCls}
ref={this.saveTooltip}
overlay={this.getOverlay()}
overlay={this.getOverlay(prefixCls)}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderPopover}
</ConfigConsumer>
);
}
}

View File

@ -3,6 +3,7 @@ import * as React from 'react';
import Icon from '../icon';
import { Circle } from 'rc-progress';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const statusColorMap: Record<string, string> = {
normal: '#108ee9',
@ -48,7 +49,6 @@ export default class Progress extends React.Component<ProgressProps, {}> {
percent: 0,
showInfo: true,
trailColor: '#f3f3f3',
prefixCls: 'ant-progress',
size: 'default',
};
@ -67,13 +67,15 @@ export default class Progress extends React.Component<ProgressProps, {}> {
default: PropTypes.oneOf(['default', 'small']),
};
render() {
renderProgress = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = this.props;
const {
prefixCls, className, percent = 0, status, format, trailColor, size, successPercent,
prefixCls: customizePrefixCls,
className, percent = 0, status, format, trailColor, size, successPercent,
type, strokeWidth, width, showInfo, gapDegree = 0, gapPosition, strokeColor, strokeLinecap = 'round',
...restProps
} = props;
const prefixCls = getPrefixCls('progress', customizePrefixCls);
const progressStatus = parseInt((successPercent ? successPercent.toString() : percent.toString()), 10) >= 100 &&
!('status' in props) ? 'success' : (status || 'normal');
let progressInfo;
@ -167,4 +169,12 @@ export default class Progress extends React.Component<ProgressProps, {}> {
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderProgress}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,5 @@
import React from 'react';
import { shallow, mount, render } from 'enzyme';
import { mount, render } from 'enzyme';
import Radio from '../radio';
import RadioGroup from '../group';
@ -35,7 +35,7 @@ describe('Radio', () => {
const onMouseEnter = jest.fn();
const onMouseLeave = jest.fn();
const wrapper = shallow(
const wrapper = mount(
<RadioGroup
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
@ -44,10 +44,10 @@ describe('Radio', () => {
</RadioGroup>
);
wrapper.simulate('mouseenter');
wrapper.find('div').at(0).simulate('mouseenter');
expect(onMouseEnter).toHaveBeenCalled();
wrapper.simulate('mouseleave');
wrapper.find('div').at(0).simulate('mouseleave');
expect(onMouseLeave).toHaveBeenCalled();
});

View File

@ -1,5 +1,5 @@
import React from 'react';
import { shallow, render } from 'enzyme';
import { mount, render } from 'enzyme';
import Radio from '../radio';
import focusTest from '../../../tests/shared/focusTest';
@ -15,17 +15,17 @@ describe('Radio', () => {
const onMouseEnter = jest.fn();
const onMouseLeave = jest.fn();
const wrapper = shallow(
const wrapper = mount(
<Radio
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
/>
);
wrapper.simulate('mouseenter');
wrapper.find('label').simulate('mouseenter');
expect(onMouseEnter).toHaveBeenCalled();
wrapper.simulate('mouseleave');
wrapper.find('label').simulate('mouseleave');
expect(onMouseLeave).toHaveBeenCalled();
});
});

View File

@ -4,6 +4,7 @@ import classNames from 'classnames';
import shallowEqual from 'shallowequal';
import Radio from './radio';
import { RadioGroupProps, RadioGroupState, RadioChangeEvent, RadioGroupButtonStyle } from './interface';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
function getCheckedValue(children: React.ReactNode) {
let value = null;
@ -20,7 +21,6 @@ function getCheckedValue(children: React.ReactNode) {
export default class RadioGroup extends React.Component<RadioGroupProps, RadioGroupState> {
static defaultProps = {
disabled: false,
prefixCls: 'ant-radio',
buttonStyle: 'outline' as RadioGroupButtonStyle,
};
@ -89,9 +89,10 @@ export default class RadioGroup extends React.Component<RadioGroupProps, RadioGr
onChange(ev);
}
}
render() {
renderGroup = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = this.props;
const { prefixCls, className = '', options, buttonStyle } = props;
const { prefixCls: customizePrefixCls, className = '', options, buttonStyle } = props;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
[`${groupPrefixCls}-${props.size}`]: props.size,
@ -144,4 +145,12 @@ export default class RadioGroup extends React.Component<RadioGroupProps, RadioGr
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderGroup}
</ConfigConsumer>
);
}
}

View File

@ -6,13 +6,13 @@ import shallowEqual from 'shallowequal';
import RadioGroup from './group';
import RadioButton from './radioButton';
import { RadioProps, RadioGroupContext } from './interface';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export default class Radio extends React.Component<RadioProps, {}> {
static Group: typeof RadioGroup;
static Button: typeof RadioButton;
static defaultProps = {
prefixCls: 'ant-radio',
type: 'radio',
};
@ -42,16 +42,17 @@ export default class Radio extends React.Component<RadioProps, {}> {
this.rcCheckbox = node;
}
render() {
renderRadio = ({ getPrefixCls }: ConfigConsumerProps) => {
const { props, context } = this;
const {
prefixCls,
prefixCls: customizePrefixCls,
className,
children,
style,
...restProps
} = props;
const { radioGroup } = context;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const radioProps: RadioProps = { ...restProps };
if (radioGroup) {
radioProps.name = radioGroup.name;
@ -81,4 +82,12 @@ export default class Radio extends React.Component<RadioProps, {}> {
</label>
);
}
render() {
return (
<ConfigConsumer>
{this.renderRadio}
</ConfigConsumer>
);
}
}

View File

@ -1,30 +1,36 @@
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { AbstractCheckboxProps } from '../checkbox/Checkbox';
import Radio from './radio';
import { RadioChangeEvent } from './interface';
import { AbstractCheckboxProps } from '../checkbox/Checkbox';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type RadioButtonProps = AbstractCheckboxProps<RadioChangeEvent>;
export default class RadioButton extends React.Component<RadioButtonProps, any> {
static defaultProps = {
prefixCls: 'ant-radio-button',
};
static contextTypes = {
radioGroup: PropTypes.any,
};
context: any;
render() {
const radioProps: RadioButtonProps = { ...this.props };
renderRadioButton = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, ...radioProps }: RadioButtonProps = this.props;
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
if (this.context.radioGroup) {
radioProps.onChange = this.context.radioGroup.onChange;
radioProps.checked = this.props.value === this.context.radioGroup.value;
radioProps.disabled = this.props.disabled || this.context.radioGroup.disabled;
}
return <Radio {...radioProps} />;
return <Radio prefixCls={prefixCls} {...radioProps} />;
}
render() {
return (
<ConfigConsumer>
{this.renderRadioButton}
</ConfigConsumer>
);
}
}

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import RcRate from 'rc-rate';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface RateProps {
prefixCls?: string;
@ -25,7 +26,6 @@ export default class Rate extends React.Component<RateProps, any> {
};
static defaultProps = {
prefixCls: 'ant-rate',
character: <Icon type="star" theme="filled" />,
};
@ -43,7 +43,19 @@ export default class Rate extends React.Component<RateProps, any> {
this.rcRate = node;
}
renderRate = ({ getPrefixCls }: ConfigConsumerProps) => (
<RcRate
ref={this.saveRate}
{...this.props}
prefixCls={getPrefixCls('rate', this.props.prefixCls)}
/>
);
render() {
return <RcRate ref={this.saveRate} {...this.props} />;
return (
<ConfigConsumer>
{this.renderRate}
</ConfigConsumer>
);
}
}

View File

@ -4,7 +4,7 @@ import RcSelect, { Option, OptGroup } from 'rc-select';
import classNames from 'classnames';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import omit from 'omit.js';
import warning from 'warning';
import Icon from '../icon';
@ -116,7 +116,6 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
static SECRET_COMBOBOX_MODE_DO_NOT_USE = 'SECRET_COMBOBOX_MODE_DO_NOT_USE';
static defaultProps = {
prefixCls: 'ant-select',
showSearch: false,
transitionName: 'slide-up',
choiceTransitionName: 'zoom',
@ -163,9 +162,8 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
return mode === 'combobox' || mode === Select.SECRET_COMBOBOX_MODE_DO_NOT_USE;
}
renderSuffixIcon() {
renderSuffixIcon(prefixCls: string) {
const {
prefixCls,
loading,
suffixIcon,
} = this.props;
@ -181,102 +179,101 @@ export default class Select<T = SelectValue> extends React.Component<SelectProps
return <Icon type="down" className={`${prefixCls}-arrow-icon`} />;
}
renderSelect = (locale: SelectLocale) => {
const {
prefixCls,
className = '',
size,
mode,
getPopupContainer,
removeIcon,
clearIcon,
menuItemSelectedIcon,
...restProps
} = this.props;
const rest = omit(restProps, ['inputIcon']);
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
}, className);
let { optionLabelProp } = this.props;
if (this.isCombobox()) {
// children 带 dom 结构时,无法填入输入框
optionLabelProp = optionLabelProp || 'value';
}
const modeConfig = {
multiple: mode === 'multiple',
tags: mode === 'tags',
combobox: this.isCombobox(),
};
const finalRemoveIcon = removeIcon && (
React.isValidElement<{ className?: string }>(removeIcon) ?
React.cloneElement(
renderSelect = (locale: SelectLocale) => (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className = '',
size,
mode,
getPopupContainer,
removeIcon,
{
className: classNames(
removeIcon.props.className,
`${prefixCls}-remove-icon`,
),
},
) : removeIcon) || (
<Icon type="close" className={`${prefixCls}-remove-icon`} />
);
const finalClearIcon = clearIcon && (
React.isValidElement<{ className?: string }>(clearIcon) ?
React.cloneElement(
clearIcon,
{
className: classNames(
clearIcon.props.className,
`${prefixCls}-clear-icon`,
),
},
) : clearIcon) || (
<Icon type="close-circle" theme="filled" className={`${prefixCls}-clear-icon`} />
);
const finalMenuItemSelectedIcon = menuItemSelectedIcon && (
React.isValidElement<{ className?: string }>(menuItemSelectedIcon) ?
React.cloneElement(
menuItemSelectedIcon,
{
className: classNames(
menuItemSelectedIcon.props.className,
`${prefixCls}-selected-icon`,
),
},
) : menuItemSelectedIcon) || (
<Icon type="check" className={`${prefixCls}-selected-icon`} />
);
...restProps
} = this.props;
const rest = omit(restProps, ['inputIcon']);
return (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
return (
<RcSelect
inputIcon={this.renderSuffixIcon()}
removeIcon={finalRemoveIcon}
clearIcon={finalClearIcon}
menuItemSelectedIcon={finalMenuItemSelectedIcon}
{...rest}
{...modeConfig}
prefixCls={prefixCls}
className={cls}
optionLabelProp={optionLabelProp || 'children'}
notFoundContent={this.getNotFoundContent(locale)}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveSelect}
/>
);
}}
</ConfigConsumer>
);
}
const prefixCls = getPrefixCls('select', customizePrefixCls);
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
}, className);
let { optionLabelProp } = this.props;
if (this.isCombobox()) {
// children 带 dom 结构时,无法填入输入框
optionLabelProp = optionLabelProp || 'value';
}
const modeConfig = {
multiple: mode === 'multiple',
tags: mode === 'tags',
combobox: this.isCombobox(),
};
const finalRemoveIcon = removeIcon && (
React.isValidElement<{ className?: string }>(removeIcon) ?
React.cloneElement(
removeIcon,
{
className: classNames(
removeIcon.props.className,
`${prefixCls}-remove-icon`,
),
},
) : removeIcon) || (
<Icon type="close" className={`${prefixCls}-remove-icon`} />
);
const finalClearIcon = clearIcon && (
React.isValidElement<{ className?: string }>(clearIcon) ?
React.cloneElement(
clearIcon,
{
className: classNames(
clearIcon.props.className,
`${prefixCls}-clear-icon`,
),
},
) : clearIcon) || (
<Icon type="close-circle" theme="filled" className={`${prefixCls}-clear-icon`} />
);
const finalMenuItemSelectedIcon = menuItemSelectedIcon && (
React.isValidElement<{ className?: string }>(menuItemSelectedIcon) ?
React.cloneElement(
menuItemSelectedIcon,
{
className: classNames(
menuItemSelectedIcon.props.className,
`${prefixCls}-selected-icon`,
),
},
) : menuItemSelectedIcon) || (
<Icon type="check" className={`${prefixCls}-selected-icon`} />
);
return (
<RcSelect
inputIcon={this.renderSuffixIcon(prefixCls)}
removeIcon={finalRemoveIcon}
clearIcon={finalClearIcon}
menuItemSelectedIcon={finalMenuItemSelectedIcon}
{...rest}
{...modeConfig}
prefixCls={prefixCls}
className={cls}
optionLabelProp={optionLabelProp || 'children'}
notFoundContent={this.getNotFoundContent(locale)}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveSelect}
/>
);
}}
</ConfigConsumer>
);
render() {
return (

View File

@ -11,7 +11,6 @@ export interface SkeletonAvatarProps {
class Title extends React.Component<SkeletonAvatarProps, any> {
static defaultProps: Partial<SkeletonAvatarProps> = {
prefixCls: 'ant-skeleton-avatar',
size: 'large',
};

View File

@ -12,10 +12,6 @@ export interface SkeletonParagraphProps {
}
class Paragraph extends React.Component<SkeletonParagraphProps, {}> {
static defaultProps: Partial<SkeletonParagraphProps> = {
prefixCls: 'ant-skeleton-paragraph',
};
getWidth(index: number) {
const { width, rows = 2 } = this.props;
if (Array.isArray(width)) {

View File

@ -9,10 +9,6 @@ export interface SkeletonTitleProps {
}
class Title extends React.Component<SkeletonTitleProps, any> {
static defaultProps: Partial<SkeletonTitleProps> = {
prefixCls: 'ant-skeleton-title',
};
render() {
const { prefixCls, className, width, style } = this.props;

View File

@ -3,6 +3,7 @@ import classNames from 'classnames';
import Avatar, { SkeletonAvatarProps } from './Avatar';
import Title, { SkeletonTitleProps } from './Title';
import Paragraph, { SkeletonParagraphProps } from './Paragraph';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface SkeletonProps {
active?: boolean;
@ -62,18 +63,20 @@ function getParagraphBasicProps(hasAvatar: boolean, hasTitle: boolean): Skeleton
class Skeleton extends React.Component<SkeletonProps, any> {
static defaultProps: Partial<SkeletonProps> = {
prefixCls: 'ant-skeleton',
avatar: false,
title: true,
paragraph: true,
};
render() {
renderSkeleton = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
loading, prefixCls, className, children,
prefixCls: customizePrefixCls,
loading, className, children,
avatar, title, paragraph, active,
} = this.props;
const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
if (loading || !('loading' in this.props)) {
const hasAvatar = !!avatar;
const hasTitle = !!title;
@ -83,6 +86,7 @@ class Skeleton extends React.Component<SkeletonProps, any> {
let avatarNode;
if (hasAvatar) {
const avatarProps: SkeletonAvatarProps = {
prefixCls: `${prefixCls}-avatar`,
...getAvatarBasicProps(hasTitle, hasParagraph),
...getComponentProps(avatar),
};
@ -100,6 +104,7 @@ class Skeleton extends React.Component<SkeletonProps, any> {
let $title;
if (hasTitle) {
const titleProps: SkeletonTitleProps = {
prefixCls: `${prefixCls}-title`,
...getTitleBasicProps(hasAvatar, hasParagraph),
...getComponentProps(title),
};
@ -113,6 +118,7 @@ class Skeleton extends React.Component<SkeletonProps, any> {
let paragraphNode;
if (hasParagraph) {
const paragraphProps: SkeletonParagraphProps = {
prefixCls: `${prefixCls}-paragraph`,
...getParagraphBasicProps(hasAvatar, hasTitle),
...getComponentProps(paragraph),
};
@ -148,6 +154,14 @@ class Skeleton extends React.Component<SkeletonProps, any> {
return children;
}
render() {
return (
<ConfigConsumer>
{this.renderSkeleton}
</ConfigConsumer>
);
}
}
export default Skeleton;

View File

@ -3,6 +3,7 @@ import RcSlider from 'rc-slider/lib/Slider';
import RcRange from 'rc-slider/lib/Range';
import RcHandle from 'rc-slider/lib/Handle';
import Tooltip from '../tooltip';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface SliderMarks {
[key: number]: React.ReactNode | {
@ -13,12 +14,13 @@ export interface SliderMarks {
export type SliderValue = number | [number, number];
export type HandleGeneratorFn = (info: {
value: number,
dragging: boolean,
index: number,
rest: any[],
}) => React.ReactElement<any>;
interface HandleGeneratorInfo {
value: number;
dragging: boolean;
index: number;
rest: any[];
};
export type HandleGeneratorFn = (tooltipPrefixCls: string, info: HandleGeneratorInfo) => React.ReactElement<any>;
export interface SliderProps {
prefixCls?: string;
@ -49,8 +51,6 @@ export interface SliderState {
export default class Slider extends React.Component<SliderProps, SliderState> {
static defaultProps = {
prefixCls: 'ant-slider',
tooltipPrefixCls: 'ant-tooltip',
tipFormatter(value: number) {
return value.toString();
},
@ -73,8 +73,8 @@ export default class Slider extends React.Component<SliderProps, SliderState> {
},
}));
}
handleWithTooltip: HandleGeneratorFn = ({ value, dragging, index, ...restProps }) => {
const { tooltipPrefixCls, tipFormatter, tooltipVisible } = this.props;
handleWithTooltip: HandleGeneratorFn = (tooltipPrefixCls: string, { value, dragging, index, ...restProps }) => {
const { tipFormatter, tooltipVisible } = this.props;
const { visibles } = this.state;
const isTipFormatter = tipFormatter ? (visibles[index] || dragging) : false;
let visible;
@ -114,11 +114,44 @@ export default class Slider extends React.Component<SliderProps, SliderState> {
this.rcSlider = node;
}
render() {
const { range, ...restProps } = this.props;
renderSlider = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls, tooltipPrefixCls: customizeTooltipPrefixCls,
range, ...restProps
} = this.props;
const prefixCls = getPrefixCls('slider', customizePrefixCls);
const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
if (range) {
return <RcRange {...restProps} ref={this.saveSlider} handle={this.handleWithTooltip} />;
return (
<RcRange
{...restProps}
ref={this.saveSlider}
handle={(info: HandleGeneratorInfo) => (
this.handleWithTooltip(tooltipPrefixCls, info)
)}
prefixCls={prefixCls}
tooltipPrefixCls={tooltipPrefixCls}
/>
);
}
return <RcSlider {...restProps} ref={this.saveSlider} handle={this.handleWithTooltip} />;
return (
<RcSlider
{...restProps}
ref={this.saveSlider}
handle={(info: HandleGeneratorInfo) => (
this.handleWithTooltip(tooltipPrefixCls, info)
)}
prefixCls={prefixCls}
tooltipPrefixCls={tooltipPrefixCls}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderSlider}
</ConfigConsumer>
);
}
}

View File

@ -1,10 +1,10 @@
import React from 'react';
import { shallow, render, mount } from 'enzyme';
import { render, mount } from 'enzyme';
import Spin from '..';
describe('Spin', () => {
it('should only affect the spin element when set style to a nested <Spin>xx</Spin>', () => {
const wrapper = shallow(
const wrapper = mount(
<Spin style={{ background: 'red' }}>
<div>content</div>
</Spin>
@ -22,7 +22,7 @@ describe('Spin', () => {
});
it('should render with delay when it\'s mounted with spinning=true and delay', () => {
const wrapper = shallow(
const wrapper = mount(
<Spin spinning delay={500} />
);
expect(wrapper.find('.ant-spin').at(0).hasClass('ant-spin-spinning')).toEqual(false);

View File

@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import Animate from 'rc-animate';
import omit from 'omit.js';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export type SpinSize = 'small' | 'default' | 'large';
export type SpinIndicator = React.ReactElement<any>;
@ -27,8 +28,8 @@ export interface SpinState {
// Render indicator
let defaultIndicator: React.ReactNode = null;
function renderIndicator(props: SpinProps): React.ReactNode {
const { prefixCls, indicator } = props;
function renderIndicator(prefixCls: string, props: SpinProps): React.ReactNode {
const { indicator } = props;
const dotClassName = `${prefixCls}-dot`;
if (React.isValidElement(indicator)) {
return React.cloneElement((indicator as SpinIndicator), {
@ -58,7 +59,6 @@ function shouldDelay(spinning?: boolean, delay?: number): boolean {
class Spin extends React.Component<SpinProps, SpinState> {
static defaultProps = {
prefixCls: 'ant-spin',
spinning: true,
size: 'default' as SpinSize,
wrapperClassName: '',
@ -144,10 +144,15 @@ class Spin extends React.Component<SpinProps, SpinState> {
}
};
render() {
const { className, size, prefixCls, tip, wrapperClassName, ...restProps } = this.props;
renderSpin = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className, size, tip, wrapperClassName,
...restProps
} = this.props;
const { spinning } = this.state;
const prefixCls = getPrefixCls('spin', customizePrefixCls);
const spinClassName = classNames(prefixCls, {
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-lg`]: size === 'large',
@ -164,7 +169,7 @@ class Spin extends React.Component<SpinProps, SpinState> {
const spinElement = (
<div {...divProps} className={spinClassName} >
{renderIndicator(this.props)}
{renderIndicator(prefixCls, this.props)}
{tip ? <div className={`${prefixCls}-text`}>{tip}</div> : null}
</div>
);
@ -194,6 +199,14 @@ class Spin extends React.Component<SpinProps, SpinState> {
}
return spinElement;
}
render() {
return (
<ConfigConsumer>
{this.renderSpin}
</ConfigConsumer>
);
}
}
export default Spin;

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import RcSteps from 'rc-steps';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface StepsProps {
prefixCls?: string;
@ -20,8 +21,6 @@ export default class Steps extends React.Component<StepsProps, any> {
static Step = RcSteps.Step;
static defaultProps = {
prefixCls: 'ant-steps',
iconPrefix: 'ant',
current: 0,
};
@ -31,14 +30,28 @@ export default class Steps extends React.Component<StepsProps, any> {
current: PropTypes.number,
};
render() {
const { prefixCls } = this.props;
renderSteps = ({ getPrefixCls }: ConfigConsumerProps) => {
const prefixCls = getPrefixCls('steps', this.props.prefixCls);
const iconPrefix = getPrefixCls('', this.props.iconPrefix);
const icons = {
finish: <Icon type="check" className={`${prefixCls}-finish-icon`} />,
error: <Icon type="close" className={`${prefixCls}-error-icon`} />,
};
return (
<RcSteps icons={icons} {...this.props} />
<RcSteps
icons={icons}
{...this.props}
prefixCls={prefixCls}
iconPrefix={iconPrefix}
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderSteps}
</ConfigConsumer>
);
}
}

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import omit from 'omit.js';
import Wave from '../_util/wave';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface SwitchProps {
prefixCls?: string;
@ -22,10 +23,6 @@ export interface SwitchProps {
}
export default class Switch extends React.Component<SwitchProps, {}> {
static defaultProps = {
prefixCls: 'ant-switch',
};
static propTypes = {
prefixCls: PropTypes.string,
// HACK: https://github.com/ant-design/ant-design/issues/5368
@ -48,8 +45,12 @@ export default class Switch extends React.Component<SwitchProps, {}> {
this.rcSwitch = node;
}
render() {
const { prefixCls, size, loading, className = '', disabled } = this.props;
renderSwitch = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
size, loading, className = '', disabled,
} = this.props;
const prefixCls = getPrefixCls('switch', customizePrefixCls);
const classes = classNames(className, {
[`${prefixCls}-small`]: size === 'small',
[`${prefixCls}-loading`]: loading,
@ -64,6 +65,7 @@ export default class Switch extends React.Component<SwitchProps, {}> {
<Wave insertExtraNode>
<RcSwitch
{...omit(this.props, ['loading'])}
prefixCls={prefixCls}
className={classes}
disabled={disabled || loading}
ref={this.saveSwitch}
@ -72,4 +74,12 @@ export default class Switch extends React.Component<SwitchProps, {}> {
</Wave>
);
}
render() {
return (
<ConfigConsumer>
{this.renderSwitch}
</ConfigConsumer>
);
}
}

View File

@ -1,15 +1,15 @@
// FilterDropdown
// createBodyRow
// SelectionCheckboxAll
// SelectionBox
// FilterDropdown
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import RcTable from 'rc-table';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import shallowEqual from 'shallowequal';
import Pagination from '../pagination';
import Icon from '../icon';
import Spin from '../spin';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import warning from '../_util/warning';
import FilterDropdown from './filterDropdown';
import createStore, { Store } from './createStore';
import SelectionBox from './SelectionBox';
@ -18,7 +18,6 @@ import Column from './Column';
import ColumnGroup from './ColumnGroup';
import createBodyRow from './createBodyRow';
import { flatArray, treeMap, flatFilter, normalizeColumns } from './util';
import { SpinProps } from '../spin';
import {
TableProps,
TableSize,
@ -36,8 +35,15 @@ import {
PaginationConfig,
PrepareParamsArgumentsReturn,
} from './interface';
import Pagination from '../pagination';
import Icon from '../icon';
import Spin, { SpinProps } from '../spin';
import { RadioChangeEvent } from '../radio';
import { CheckboxChangeEvent } from '../checkbox';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
function noop() {
}
@ -88,7 +94,6 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
static defaultProps = {
dataSource: [],
prefixCls: 'ant-table',
useFixedHeader: false,
className: '',
size: 'default' as TableSize,
@ -224,8 +229,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
this.createComponents(nextProps.components, this.props.components);
}
onRow = (record: T, index: number) => {
const { onRow, prefixCls } = this.props;
onRow = (prefixCls: string, record: T, index: number) => {
const { onRow } = this.props;
const custom = onRow ? onRow(record, index) : {};
return {
...custom,
@ -705,8 +710,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
return ReactDOM.findDOMNode(this) as HTMLElement;
}
renderRowSelection(locale: TableLocale) {
const { prefixCls, rowSelection } = this.props;
renderRowSelection(prefixCls: string, locale: TableLocale) {
const { rowSelection } = this.props;
const columns = this.columns.concat();
if (rowSelection) {
const data = this.getFlatCurrentPageData().filter((item, index) => {
@ -778,8 +783,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
return this.getColumnKey(sortColumn) === this.getColumnKey(column);
}
renderColumnsDropdown(columns: ColumnProps<T>[], locale: TableLocale) {
const { prefixCls, dropdownPrefixCls } = this.props;
renderColumnsDropdown(prefixCls: string, dropdownPrefixCls: string, columns: ColumnProps<T>[], locale: TableLocale) {
const { sortOrder, filters } = this.state;
return treeMap(columns, (column, i) => {
const key = this.getColumnKey(column, i) as string;
@ -874,7 +878,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
}
}
renderPagination(paginationPosition: string) {
renderPagination(prefixCls: string, paginationPosition: string) {
// 强制不需要分页
if (!this.hasPagination()) {
return null;
@ -892,7 +896,7 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
<Pagination
key={`pagination-${paginationPosition}`}
{...pagination}
className={classNames(pagination.className, `${this.props.prefixCls}-pagination`)}
className={classNames(pagination.className, `${prefixCls}-pagination`)}
onChange={this.handlePageChange}
total={total}
size={size}
@ -1021,9 +1025,9 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
};
}
renderTable = (contextLocale: TableLocale, loading: SpinProps) => {
renderTable = (prefixCls: string, dropdownPrefixCls: string, contextLocale: TableLocale, loading: SpinProps) => {
const locale = { ...contextLocale, ...this.props.locale };
const { style, className, prefixCls, showHeader, ...restProps } = this.props;
const { style, className, showHeader, ...restProps } = this.props;
const data = this.getCurrentPageData();
const expandIconAsCell = this.props.expandedRowRender && this.props.expandIconAsCell !== false;
@ -1034,8 +1038,8 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
[`${prefixCls}-without-column-header`]: !showHeader,
});
let columns = this.renderRowSelection(locale);
columns = this.renderColumnsDropdown(columns, locale);
let columns = this.renderRowSelection(prefixCls, locale);
columns = this.renderColumnsDropdown(prefixCls, dropdownPrefixCls, columns, locale);
columns = columns.map((column, i) => {
const newColumn = { ...column };
newColumn.key = this.getColumnKey(newColumn, i);
@ -1050,7 +1054,9 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
<RcTable
key="table"
{...restProps}
onRow={this.onRow}
onRow={(record: T, index: number) => (
this.onRow(prefixCls, record, index)
)}
components={this.components}
prefixCls={prefixCls}
data={data}
@ -1064,8 +1070,11 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
);
}
render() {
const { style, className, prefixCls } = this.props;
renderComponent = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls, dropdownPrefixCls: customizeDropdownPrefixCls,
style, className,
} = this.props;
const data = this.getCurrentPageData();
let loading = this.props.loading as SpinProps;
@ -1075,12 +1084,14 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
};
}
const prefixCls = getPrefixCls('table', customizePrefixCls);
const dropdownPrefixCls = getPrefixCls('dropdown', customizeDropdownPrefixCls);
const table = (
<LocaleReceiver
componentName="Table"
defaultLocale={defaultLocale.Table}
>
{(locale) => this.renderTable(locale, loading)}
{(locale) => this.renderTable(prefixCls, dropdownPrefixCls, locale, loading)}
</LocaleReceiver>
);
@ -1098,11 +1109,19 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
{...loading}
className={loading.spinning ? `${paginationPatchClass} ${prefixCls}-spin-holder` : ''}
>
{this.renderPagination('top')}
{this.renderPagination(prefixCls, 'top')}
{table}
{this.renderPagination('bottom')}
{this.renderPagination(prefixCls, 'bottom')}
</Spin>
</div>
);
}
render() {
return (
<ConfigConsumer>
{this.renderComponent}
</ConfigConsumer>
);
}
}

View File

@ -5,6 +5,7 @@ import TabContent from 'rc-tabs/lib/TabContent';
import TabBar from './TabBar';
import classNames from 'classnames';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import isFlexSupported from '../_util/isFlexSupported';
@ -49,7 +50,6 @@ export default class Tabs extends React.Component<TabsProps, any> {
static TabPane = TabPane as React.ClassicComponentClass<TabPaneProps>;
static defaultProps = {
prefixCls: 'ant-tabs',
hideAdd: false,
tabPosition: 'top',
};
@ -88,9 +88,9 @@ export default class Tabs extends React.Component<TabsProps, any> {
}
}
render() {
renderTabs = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls,
prefixCls: customizePrefixCls,
className = '',
size,
type = 'line',
@ -112,6 +112,7 @@ export default class Tabs extends React.Component<TabsProps, any> {
!(type.indexOf('card') >= 0 && (size === 'small' || size === 'large')),
'Tabs[type=card|editable-card] doesn\'t have small or large size, it\'s by design.',
);
const prefixCls = getPrefixCls('tabs', customizePrefixCls);
const cls = classNames(className, {
[`${prefixCls}-vertical`]: tabPosition === 'left' || tabPosition === 'right',
[`${prefixCls}-${size}`]: !!size,
@ -169,6 +170,7 @@ export default class Tabs extends React.Component<TabsProps, any> {
return (
<RcTabs
{...this.props}
prefixCls={prefixCls}
className={cls}
tabBarPosition={tabPosition}
renderTabBar={() => <TabBar {...tabBarProps} tabBarExtraContent={tabBarExtraContent}/>}
@ -179,4 +181,12 @@ export default class Tabs extends React.Component<TabsProps, any> {
</RcTabs>
);
}
render() {
return (
<ConfigConsumer>
{this.renderTabs}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface CheckableTagProps {
prefixCls?: string;
@ -15,8 +16,9 @@ export default class CheckableTag extends React.Component<CheckableTagProps> {
onChange(!checked);
}
}
render() {
const { prefixCls = 'ant-tag', className, checked, ...restProps } = this.props;
renderCheckableTag = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, checked, ...restProps } = this.props;
const prefixCls = getPrefixCls('tag', customizePrefixCls);
const cls = classNames(prefixCls, {
[`${prefixCls}-checkable`]: true,
[`${prefixCls}-checkable-checked`]: checked,
@ -31,4 +33,12 @@ export default class CheckableTag extends React.Component<CheckableTagProps> {
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderCheckableTag}
</ConfigConsumer>
);
}
}

View File

@ -6,6 +6,7 @@ import omit from 'omit.js';
import { polyfill } from 'react-lifecycles-compat';
import Icon from '../icon';
import CheckableTag from './CheckableTag';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Wave from '../_util/wave';
export { CheckableTagProps } from './CheckableTag';
@ -34,7 +35,6 @@ export interface TagState {
class Tag extends React.Component<TagProps, TagState> {
static CheckableTag = CheckableTag;
static defaultProps = {
prefixCls: 'ant-tag',
closable: false,
};
@ -127,10 +127,15 @@ class Tag extends React.Component<TagProps, TagState> {
);
}
render() {
const { prefixCls, closable, color, className, children, style, ...otherProps } = this.props;
renderTag = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
closable, color, className, children, style,
...otherProps
} = this.props;
const closeIcon = closable ? <Icon type="close" onClick={this.handleIconClick} /> : '';
const isPresetColor = this.isPresetColor(color);
const prefixCls = getPrefixCls('tag', customizePrefixCls);
const classString = classNames(prefixCls, {
[`${prefixCls}-${color}`]: isPresetColor,
[`${prefixCls}-has-color`]: (color && !isPresetColor),
@ -172,6 +177,14 @@ class Tag extends React.Component<TagProps, TagState> {
</Wave>
);
}
render() {
return (
<ConfigConsumer>
{this.renderTag}
</ConfigConsumer>
);
}
}
polyfill(Tag);

View File

@ -4,7 +4,7 @@ import { polyfill } from 'react-lifecycles-compat';
import RcTimePicker from 'rc-time-picker/lib/TimePicker';
import classNames from 'classnames';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import defaultLocale from './locale/en_US';
import interopDefault from '../_util/interopDefault';
import Icon from '../icon';
@ -60,7 +60,6 @@ export interface TimePickerLocale {
class TimePicker extends React.Component<TimePickerProps, any> {
static defaultProps = {
prefixCls: 'ant-time-picker',
align: {
offset: [0, -2],
},
@ -136,81 +135,81 @@ class TimePicker extends React.Component<TimePickerProps, any> {
return 'HH:mm:ss';
}
renderTimePicker = (locale: TimePickerLocale) => {
const { getPopupContainer, ...props } = this.props;
delete props.defaultValue;
renderTimePicker = (locale: TimePickerLocale) => (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const { getPopupContainer, prefixCls: customizePrefixCls, ...props } = this.props;
delete props.defaultValue;
const format = this.getDefaultFormat();
const className = classNames(props.className, {
[`${props.prefixCls}-${props.size}`]: !!props.size,
});
const format = this.getDefaultFormat();
const prefixCls = getPrefixCls('time-picker', customizePrefixCls);
const className = classNames(props.className, {
[`${prefixCls}-${props.size}`]: !!props.size,
});
const addon = (panel: React.ReactElement<any>) => (
props.addon ? (
<div className={`${props.prefixCls}-panel-addon`}>
{props.addon(panel)}
</div>
) : null
);
const addon = (panel: React.ReactElement<any>) => (
props.addon ? (
<div className={`${prefixCls}-panel-addon`}>
{props.addon(panel)}
</div>
) : null
);
const { suffixIcon, prefixCls } = props;
const clockIcon = suffixIcon && (
React.isValidElement<{ className?: string }>(suffixIcon)
? React.cloneElement(
suffixIcon,
{
className: classNames({
[suffixIcon.props.className!]: suffixIcon.props.className,
[`${prefixCls}-clock-icon`]: true,
}),
},
) : <span className={`${prefixCls}-clock-icon`}>{suffixIcon}</span>) || (
<Icon
type="clock-circle"
className={`${prefixCls}-clock-icon`}
theme="outlined"
/>
);
const inputIcon = (
<span className={`${prefixCls}-icon`}>
{clockIcon}
</span>
);
const clearIcon = (
<Icon
type="close-circle"
className={`${prefixCls}-panel-clear-btn-icon`}
theme="filled"
/>
);
return (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
return (
<RcTimePicker
{...generateShowHourMinuteSecond(format)}
{...props}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveTimePicker}
format={format}
className={className}
value={this.state.value}
placeholder={props.placeholder === undefined ? locale.placeholder : props.placeholder}
onChange={this.handleChange}
onOpen={this.handleOpenClose}
onClose={this.handleOpenClose}
addon={addon}
inputIcon={inputIcon}
clearIcon={clearIcon}
const { suffixIcon } = props;
const clockIcon = suffixIcon && (
React.isValidElement<{ className?: string }>(suffixIcon)
? React.cloneElement(
suffixIcon,
{
className: classNames({
[suffixIcon.props.className!]: suffixIcon.props.className,
[`${prefixCls}-clock-icon`]: true,
}),
},
) : <span className={`${prefixCls}-clock-icon`}>{suffixIcon}</span>) || (
<Icon
type="clock-circle"
className={`${prefixCls}-clock-icon`}
theme="outlined"
/>
);
}}
</ConfigConsumer>
);
}
const inputIcon = (
<span className={`${prefixCls}-icon`}>
{clockIcon}
</span>
);
const clearIcon = (
<Icon
type="close-circle"
className={`${prefixCls}-panel-clear-btn-icon`}
theme="filled"
/>
);
return (
<RcTimePicker
{...generateShowHourMinuteSecond(format)}
{...props}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={this.saveTimePicker}
format={format}
className={className}
value={this.state.value}
placeholder={props.placeholder === undefined ? locale.placeholder : props.placeholder}
onChange={this.handleChange}
onOpen={this.handleOpenClose}
onClose={this.handleOpenClose}
addon={addon}
inputIcon={inputIcon}
clearIcon={clearIcon}
/>
);
}}
</ConfigConsumer>
);
render() {
return (

View File

@ -2,6 +2,7 @@ import * as React from 'react';
import classNames from 'classnames';
import TimelineItem, { TimeLineItemProps } from './TimelineItem';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface TimelineProps {
prefixCls?: string;
@ -15,21 +16,21 @@ export interface TimelineProps {
}
export default class Timeline extends React.Component<TimelineProps, any> {
static Item = TimelineItem as React.ClassicComponentClass<TimeLineItemProps>;
static Item: React.SFC<TimeLineItemProps> = TimelineItem;
static defaultProps = {
prefixCls: 'ant-timeline',
reverse: false,
mode: '',
};
render() {
renderTimeline = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls,
prefixCls: customizePrefixCls,
pending = null, pendingDot,
children, className, reverse,
mode,
...restProps
} = this.props;
const prefixCls = getPrefixCls('timeline', customizePrefixCls);
const pendingNode = typeof pending === 'boolean' ? null : pending;
const classString = classNames(prefixCls, {
[`${prefixCls}-pending`]: !!pending,
@ -74,4 +75,12 @@ export default class Timeline extends React.Component<TimelineProps, any> {
</ul>
);
}
render() {
return (
<ConfigConsumer>
{this.renderTimeline}
</ConfigConsumer>
);
}
}

View File

@ -1,5 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export interface TimeLineItemProps {
prefixCls?: string;
@ -10,40 +11,48 @@ export interface TimeLineItemProps {
style?: React.CSSProperties;
}
export default class TimelineItem extends React.Component<TimeLineItemProps, any> {
static defaultProps = {
prefixCls: 'ant-timeline',
color: 'blue',
pending: false,
};
const TimelineItem: React.SFC<TimeLineItemProps> = (props) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className, color = '', children, pending, dot,
...restProps
} = props;
render() {
const { prefixCls, className, color = '', children, pending, dot, ...restProps } = this.props;
const prefixCls = getPrefixCls('timeline', customizePrefixCls);
const itemClassName = classNames({
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-pending`]: pending,
}, className);
const itemClassName = classNames({
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-pending`]: pending,
}, className);
const dotClassName = classNames({
[`${prefixCls}-item-head`]: true,
[`${prefixCls}-item-head-custom`]: dot,
[`${prefixCls}-item-head-${color}`]: true,
});
const dotClassName = classNames({
[`${prefixCls}-item-head`]: true,
[`${prefixCls}-item-head-custom`]: dot,
[`${prefixCls}-item-head-${color}`]: true,
});
return (
<li {...restProps} className={itemClassName}>
<div className={`${prefixCls}-item-tail`} />
<div
className={dotClassName}
style={{ borderColor: /blue|red|green/.test(color) ? undefined : color }}
>
{dot}
</div>
<div className={`${prefixCls}-item-content`}>
{children}
</div>
</li>
);
}}
</ConfigConsumer>
);
return (
<li {...restProps} className={itemClassName}>
<div className={`${prefixCls}-item-tail`} />
<div
className={dotClassName}
style={{ borderColor: /blue|red|green/.test(color) ? undefined : color }}
>
{dot}
</div>
<div className={`${prefixCls}-item-content`}>
{children}
</div>
</li>
);
}
}
TimelineItem.defaultProps = {
color: 'blue',
pending: false,
};
export default TimelineItem;

View File

@ -3,9 +3,9 @@ import { cloneElement } from 'react';
import { polyfill } from 'react-lifecycles-compat';
import RcTooltip from 'rc-tooltip';
import classNames from 'classnames';
import Button from '../button/index';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import getPlacements, { AdjustOverflow, PlacementsConfig } from './placements';
import Button from '../button/index';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export { AdjustOverflow, PlacementsConfig };
@ -28,7 +28,7 @@ export interface TooltipAlignConfig {
useCssTransform?: boolean
}
export interface AbstractTooltipProps extends ConfigProviderProps {
export interface AbstractTooltipProps {
prefixCls?: string;
overlayClassName?: string;
style?: React.CSSProperties;
@ -47,6 +47,7 @@ export interface AbstractTooltipProps extends ConfigProviderProps {
autoAdjustOverflow?: boolean | AdjustOverflow;
// getTooltipContainer had been rename to getPopupContainer
getTooltipContainer?: (triggerNode: Element) => HTMLElement;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
children?: React.ReactNode;
// align is a more higher api
align?: TooltipAlignConfig;
@ -73,7 +74,6 @@ const splitObject = (obj: any, keys: string[]) => {
class Tooltip extends React.Component<TooltipProps, any> {
static defaultProps = {
prefixCls: 'ant-tooltip',
placement: 'top' as TooltipPlacement,
transitionName: 'zoom-big-fast',
mouseEnterDelay: 0.1,
@ -198,10 +198,14 @@ class Tooltip extends React.Component<TooltipProps, any> {
this.tooltip = node;
}
renderTooltip = ({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
renderTooltip = ({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const { props, state } = this;
const { prefixCls, title, overlay, openClassName, getPopupContainer, getTooltipContainer } = props;
const {
prefixCls: customizePrefixCls,
title, overlay, openClassName, getPopupContainer, getTooltipContainer,
} = props;
const children = props.children as React.ReactElement<any>;
const prefixCls = getPrefixCls('tooltip', customizePrefixCls);
let visible = state.visible;
// Hide tooltip when there is no title
if (!('visible' in props) && this.isNoTitle()) {
@ -220,6 +224,7 @@ class Tooltip extends React.Component<TooltipProps, any> {
return (
<RcTooltip
{...this.props}
prefixCls={prefixCls}
getTooltipContainer={getPopupContainer || getTooltipContainer || getContextPopupContainer}
ref={this.saveTooltip}
builtinPlacements={this.getPlacements()}

View File

@ -10,19 +10,20 @@ exports[`Search should show cross icon when input value exists 1`] = `
disabled={false}
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
type="text"
value=""
>
<input
className="ant-input"
disabled={false}
onChange={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value=""
/>
<Consumer>
<input
className="ant-input"
disabled={false}
onChange={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value=""
/>
</Consumer>
</Input>
<span
className="undefined-action"
@ -70,19 +71,20 @@ exports[`Search should show cross icon when input value exists 2`] = `
disabled={false}
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
type="text"
value="a"
>
<input
className="ant-input"
disabled={false}
onChange={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value="a"
/>
<Consumer>
<input
className="ant-input"
disabled={false}
onChange={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value="a"
/>
</Consumer>
</Input>
<a
className="undefined-action"

View File

@ -7,6 +7,7 @@ import Search from './search';
import warning from '../_util/warning';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export { TransferListProps } from './list';
export { TransferOperationProps } from './operation';
@ -360,90 +361,95 @@ export default class Transfer extends React.Component<TransferProps, any> {
return ({ ...transferLocale, ...oldLocale, ...this.props.locale });
}
renderTransfer = (transferLocale: TransferLocale) => {
const {
prefixCls = 'ant-transfer',
className,
disabled,
operations = [],
showSearch,
body,
footer,
style,
listStyle,
operationStyle,
filterOption,
render,
lazy,
} = this.props;
const locale = this.getLocale(transferLocale);
const { leftFilter, rightFilter, sourceSelectedKeys, targetSelectedKeys } = this.state;
renderTransfer = (transferLocale: TransferLocale) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className,
disabled,
operations = [],
showSearch,
body,
footer,
style,
listStyle,
operationStyle,
filterOption,
render,
lazy,
} = this.props;
const prefixCls = getPrefixCls('transfer', customizePrefixCls);
const locale = this.getLocale(transferLocale);
const { leftFilter, rightFilter, sourceSelectedKeys, targetSelectedKeys } = this.state;
const { leftDataSource, rightDataSource } = this.separateDataSource(this.props);
const leftActive = targetSelectedKeys.length > 0;
const rightActive = sourceSelectedKeys.length > 0;
const { leftDataSource, rightDataSource } = this.separateDataSource(this.props);
const leftActive = targetSelectedKeys.length > 0;
const rightActive = sourceSelectedKeys.length > 0;
const cls = classNames(className, prefixCls, disabled && `${prefixCls}-disabled`);
const cls = classNames(className, prefixCls, disabled && `${prefixCls}-disabled`);
const titles = this.getTitles(locale);
return (
<div className={cls} style={style}>
<List
prefixCls={`${prefixCls}-list`}
titleText={titles[0]}
dataSource={leftDataSource}
filter={leftFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={sourceSelectedKeys}
handleFilter={this.handleLeftFilter}
handleClear={this.handleLeftClear}
handleSelect={this.handleLeftSelect}
handleSelectAll={this.handleLeftSelectAll}
render={render}
showSearch={showSearch}
body={body}
footer={footer}
lazy={lazy}
onScroll={this.handleLeftScroll}
disabled={disabled}
{...locale}
/>
<Operation
className={`${prefixCls}-operation`}
rightActive={rightActive}
rightArrowText={operations[0]}
moveToRight={this.moveToRight}
leftActive={leftActive}
leftArrowText={operations[1]}
moveToLeft={this.moveToLeft}
style={operationStyle}
disabled={disabled}
/>
<List
prefixCls={`${prefixCls}-list`}
titleText={titles[1]}
dataSource={rightDataSource}
filter={rightFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={targetSelectedKeys}
handleFilter={this.handleRightFilter}
handleClear={this.handleRightClear}
handleSelect={this.handleRightSelect}
handleSelectAll={this.handleRightSelectAll}
render={render}
showSearch={showSearch}
body={body}
footer={footer}
lazy={lazy}
onScroll={this.handleRightScroll}
disabled={disabled}
{...locale}
/>
</div>
);
}
const titles = this.getTitles(locale);
return (
<div className={cls} style={style}>
<List
prefixCls={`${prefixCls}-list`}
titleText={titles[0]}
dataSource={leftDataSource}
filter={leftFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={sourceSelectedKeys}
handleFilter={this.handleLeftFilter}
handleClear={this.handleLeftClear}
handleSelect={this.handleLeftSelect}
handleSelectAll={this.handleLeftSelectAll}
render={render}
showSearch={showSearch}
body={body}
footer={footer}
lazy={lazy}
onScroll={this.handleLeftScroll}
disabled={disabled}
{...locale}
/>
<Operation
className={`${prefixCls}-operation`}
rightActive={rightActive}
rightArrowText={operations[0]}
moveToRight={this.moveToRight}
leftActive={leftActive}
leftArrowText={operations[1]}
moveToLeft={this.moveToLeft}
style={operationStyle}
disabled={disabled}
/>
<List
prefixCls={`${prefixCls}-list`}
titleText={titles[1]}
dataSource={rightDataSource}
filter={rightFilter}
filterOption={filterOption}
style={listStyle}
checkedKeys={targetSelectedKeys}
handleFilter={this.handleRightFilter}
handleClear={this.handleRightClear}
handleSelect={this.handleRightSelect}
handleSelectAll={this.handleRightSelectAll}
render={render}
showSearch={showSearch}
body={body}
footer={footer}
lazy={lazy}
onScroll={this.handleRightScroll}
disabled={disabled}
{...locale}
/>
</div>
);
}}
</ConfigConsumer>
);
render() {
return (

View File

@ -4,7 +4,7 @@ import classNames from 'classnames';
import { TreeSelectProps } from './interface';
import { SelectLocale } from '../select';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { ConfigConsumer, ConfigProviderProps } from '../config-provider';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import warning from '../_util/warning';
import Icon from '../icon';
import { AntTreeNodeProps } from '../tree';
@ -19,7 +19,6 @@ export default class TreeSelect extends React.Component<TreeSelectProps, any> {
static SHOW_CHILD = SHOW_CHILD;
static defaultProps = {
prefixCls: 'ant-select',
transitionName: 'slide-up',
choiceTransitionName: 'zoom',
showSearch: false,
@ -48,10 +47,7 @@ export default class TreeSelect extends React.Component<TreeSelectProps, any> {
this.rcTreeSelect = node;
}
renderSwitcherIcon = ({ isLeaf, loading }: AntTreeNodeProps) => {
const {
prefixCls,
} = this.props;
renderSwitcherIcon = (prefixCls: string, { isLeaf, loading }: AntTreeNodeProps) => {
if (loading) {
return (
<Icon
@ -68,68 +64,69 @@ export default class TreeSelect extends React.Component<TreeSelectProps, any> {
);
}
renderTreeSelect = (locale: SelectLocale) => {
const {
prefixCls,
className,
size,
notFoundContent,
dropdownStyle,
dropdownClassName,
suffixIcon,
getPopupContainer,
...restProps
} = this.props;
const rest = omit(restProps, ['inputIcon', 'removeIcon', 'clearIcon', 'switcherIcon']);
renderTreeSelect = (locale: SelectLocale) => (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer, getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
className,
size,
notFoundContent,
dropdownStyle,
dropdownClassName,
suffixIcon,
getPopupContainer,
...restProps
} = this.props;
const rest = omit(restProps, ['inputIcon', 'removeIcon', 'clearIcon', 'switcherIcon']);
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
}, className);
const prefixCls = getPrefixCls('select', customizePrefixCls);
const cls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
}, className);
let checkable = rest.treeCheckable;
if (checkable) {
checkable = <span className={`${prefixCls}-tree-checkbox-inner`} />;
}
let checkable = rest.treeCheckable;
if (checkable) {
checkable = <span className={`${prefixCls}-tree-checkbox-inner`} />;
}
const inputIcon = suffixIcon && (
React.isValidElement<{ className?: string }>(suffixIcon)
? React.cloneElement(suffixIcon) : suffixIcon) || (
<Icon type="down" className={`${prefixCls}-arrow-icon`} />
);
const removeIcon = (
<Icon type="close" className={`${prefixCls}-remove-icon`} />
);
const clearIcon = (
<Icon type="close-circle" className={`${prefixCls}-clear-icon`} theme="filled" />
);
return (
<ConfigConsumer>
{({ getPopupContainer: getContextPopupContainer }: ConfigProviderProps) => {
return (
<RcTreeSelect
switcherIcon={this.renderSwitcherIcon}
inputIcon={inputIcon}
removeIcon={removeIcon}
clearIcon={clearIcon}
{...rest}
getPopupContainer={getPopupContainer || getContextPopupContainer}
dropdownClassName={classNames(dropdownClassName, `${prefixCls}-tree-dropdown`)}
prefixCls={prefixCls}
className={cls}
dropdownStyle={{ maxHeight: '100vh', overflow: 'auto', ...dropdownStyle }}
treeCheckable={checkable}
notFoundContent={notFoundContent || locale.notFoundContent}
ref={this.saveTreeSelect}
/>
const inputIcon = suffixIcon && (
React.isValidElement<{ className?: string }>(suffixIcon)
? React.cloneElement(suffixIcon) : suffixIcon) || (
<Icon type="down" className={`${prefixCls}-arrow-icon`} />
);
}}
</ConfigConsumer>
);
}
const removeIcon = (
<Icon type="close" className={`${prefixCls}-remove-icon`} />
);
const clearIcon = (
<Icon type="close-circle" className={`${prefixCls}-clear-icon`} theme="filled" />
);
return (
<RcTreeSelect
switcherIcon={(nodeProps: AntTreeNodeProps) => (
this.renderSwitcherIcon(prefixCls, nodeProps)
)}
inputIcon={inputIcon}
removeIcon={removeIcon}
clearIcon={clearIcon}
{...rest}
getPopupContainer={getPopupContainer || getContextPopupContainer}
dropdownClassName={classNames(dropdownClassName, `${prefixCls}-tree-dropdown`)}
prefixCls={prefixCls}
className={cls}
dropdownStyle={{ maxHeight: '100vh', overflow: 'auto', ...dropdownStyle }}
treeCheckable={checkable}
notFoundContent={notFoundContent || locale.notFoundContent}
ref={this.saveTreeSelect}
/>
);
}}
</ConfigConsumer>
);
render() {
return (

View File

@ -3,6 +3,7 @@ import classNames from 'classnames';
import omit from 'omit.js';
import debounce from 'lodash/debounce';
import { conductExpandParent, convertTreeToEntities } from 'rc-tree/lib/util';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import Tree, {
TreeProps, AntdTreeNodeAttribute,
@ -32,7 +33,6 @@ function getIcon(props: AntdTreeNodeAttribute): React.ReactNode {
export default class DirectoryTree extends React.Component<DirectoryTreeProps, DirectoryTreeState> {
static defaultProps = {
prefixCls: 'ant-tree',
showIcon: true,
expandAction: 'click',
};
@ -184,10 +184,11 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
}
}
render() {
const { prefixCls, className, ...props } = this.props;
renderDirectoryTree = ({ getPrefixCls }: ConfigConsumerProps) => {
const { prefixCls: customizePrefixCls, className, ...props } = this.props;
const { expandedKeys, selectedKeys } = this.state;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
const connectClassName = classNames(`${prefixCls}-directory`, className);
return (
@ -207,4 +208,12 @@ export default class DirectoryTree extends React.Component<DirectoryTreeProps, D
/>
);
}
render() {
return (
<ConfigConsumer>
{this.renderDirectoryTree}
</ConfigConsumer>
);
}
}

View File

@ -2,8 +2,9 @@ import * as React from 'react';
import RcTree, { TreeNode } from 'rc-tree';
import DirectoryTree from './DirectoryTree';
import classNames from 'classnames';
import animation from '../_util/openAnimation';
import Icon from '../icon';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import animation from '../_util/openAnimation';
export interface AntdTreeNodeAttribute {
eventKey: string;
@ -152,7 +153,6 @@ export default class Tree extends React.Component<TreeProps, any> {
static DirectoryTree = DirectoryTree;
static defaultProps = {
prefixCls: 'ant-tree',
checkable: false,
showIcon: false,
openAnimation: {
@ -163,9 +163,8 @@ export default class Tree extends React.Component<TreeProps, any> {
tree: any;
renderSwitcherIcon = ({ isLeaf, expanded, loading }: AntTreeNodeProps) => {
renderSwitcherIcon = (prefixCls: string, { isLeaf, expanded, loading }: AntTreeNodeProps) => {
const {
prefixCls,
showLine,
} = this.props;
if (loading) {
@ -206,20 +205,32 @@ export default class Tree extends React.Component<TreeProps, any> {
this.tree = node;
};
render() {
renderTree = ({ getPrefixCls }: ConfigConsumerProps) => {
const props = this.props;
const { prefixCls, className, showIcon } = props;
const { prefixCls: customizePrefixCls, className, showIcon } = props;
const checkable = props.checkable;
const prefixCls = getPrefixCls('tree', customizePrefixCls);
return (
<RcTree
ref={this.setTreeRef}
{...props}
prefixCls={prefixCls}
className={classNames(!showIcon && `${prefixCls}-icon-hide`, className)}
checkable={checkable ? <span className={`${prefixCls}-checkbox-inner`} /> : checkable}
switcherIcon={this.renderSwitcherIcon}
switcherIcon={(nodeProps: AntTreeNodeProps) => (
this.renderSwitcherIcon(prefixCls, nodeProps)
)}
>
{this.props.children}
</RcTree>
);
}
render() {
return (
<ConfigConsumer>
{this.renderTree}
</ConfigConsumer>
);
}
}

View File

@ -3,8 +3,6 @@ import { polyfill } from 'react-lifecycles-compat';
import RcUpload from 'rc-upload';
import classNames from 'classnames';
import uniqBy from 'lodash/uniqBy';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import Dragger from './Dragger';
import UploadList from './UploadList';
import {
@ -18,6 +16,9 @@ import {
UploadListType,
} from './interface';
import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from './utils';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export { UploadProps };
@ -25,7 +26,6 @@ class Upload extends React.Component<UploadProps, UploadState> {
static Dragger: typeof Dragger;
static defaultProps = {
prefixCls: 'ant-upload',
type: 'select' as UploadType,
multiple: false,
action: '',
@ -241,9 +241,9 @@ class Upload extends React.Component<UploadProps, UploadState> {
);
}
render() {
renderUpload = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls = '',
prefixCls: customizePrefixCls,
className,
showUploadList,
listType,
@ -252,12 +252,15 @@ class Upload extends React.Component<UploadProps, UploadState> {
children,
} = this.props;
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const rcUploadProps = {
onStart: this.onStart,
onError: this.onError,
onProgress: this.onProgress,
onSuccess: this.onSuccess,
...this.props,
prefixCls,
beforeUpload: this.beforeUpload,
};
@ -325,6 +328,14 @@ class Upload extends React.Component<UploadProps, UploadState> {
</span>
);
}
render() {
return (
<ConfigConsumer>
{this.renderUpload}
</ConfigConsumer>
);
}
}
polyfill(Upload);

View File

@ -1,10 +1,11 @@
import * as React from 'react';
import Animate from 'rc-animate';
import classNames from 'classnames';
import { UploadListProps, UploadFile, UploadListType } from './interface';
import Icon from '../icon';
import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from 'classnames';
import { UploadListProps, UploadFile, UploadListType } from './interface';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
const imageTypes: string[] = ['image', 'webp', 'png', 'svg', 'gif', 'jpg', 'jpeg', 'bmp'];
// https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
@ -49,7 +50,6 @@ export default class UploadList extends React.Component<UploadListProps, any> {
strokeWidth: 2,
showInfo: false,
},
prefixCls: 'ant-upload',
showRemoveIcon: true,
showPreviewIcon: true,
};
@ -94,8 +94,12 @@ export default class UploadList extends React.Component<UploadListProps, any> {
});
}
render() {
const { prefixCls, items = [], listType, showPreviewIcon, showRemoveIcon, locale } = this.props;
renderUploadList = ({ getPrefixCls }: ConfigConsumerProps) => {
const {
prefixCls: customizePrefixCls,
items = [], listType, showPreviewIcon, showRemoveIcon, locale,
} = this.props;
const prefixCls = getPrefixCls('upload', customizePrefixCls);
const list = items.map(file => {
let progress;
let icon = <Icon type={file.status === 'uploading' ? 'loading' : 'paper-clip'} />;
@ -225,4 +229,12 @@ export default class UploadList extends React.Component<UploadListProps, any> {
</Animate>
);
}
render() {
return (
<ConfigConsumer>
{this.renderUploadList}
</ConfigConsumer>
);
}
}