2020-03-31 13:47:59 +08:00

213 lines
5.9 KiB
JavaScript

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Button from '../button';
import Icon from '../icon';
import zhCN from '../locale/zh-cn';
import { func, obj, guid } from '../util';
const { makeChain } = func;
const { pickOthers } = obj;
const noop = () => {};
export default class Inner extends Component {
static propTypes = {
prefix: PropTypes.string,
className: PropTypes.string,
title: PropTypes.node,
children: PropTypes.node,
footer: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]),
footerAlign: PropTypes.oneOf(['left', 'center', 'right']),
footerActions: PropTypes.array,
onOk: PropTypes.func,
onCancel: PropTypes.func,
okProps: PropTypes.object,
cancelProps: PropTypes.object,
closeable: PropTypes.bool,
onClose: PropTypes.func,
locale: PropTypes.object,
role: PropTypes.string,
rtl: PropTypes.bool,
// set value for a fixed height dialog. Passing a value will absolutely position the footer to the bottom.
height: PropTypes.string,
};
static defaultProps = {
prefix: 'next-',
footerAlign: 'right',
footerActions: ['ok', 'cancel'],
onOk: noop,
onCancel: noop,
okProps: {},
cancelProps: {},
closeable: true,
onClose: noop,
locale: zhCN.Dialog,
role: 'dialog',
};
getNode(name, ref) {
this[name] = ref;
}
renderHeader() {
const { prefix, title } = this.props;
if (title) {
this.titleId = guid('dialog-title-');
return (
<div
className={`${prefix}dialog-header`}
id={this.titleId}
ref={this.getNode.bind(this, 'headerNode')}
role="heading"
aria-level="1"
>
{title}
</div>
);
}
return null;
}
renderBody() {
const { prefix, children } = this.props;
if (children) {
return (
<div
className={`${prefix}dialog-body`}
ref={this.getNode.bind(this, 'bodyNode')}
>
{children}
</div>
);
}
return null;
}
renderFooter() {
const {
prefix,
footer,
footerAlign,
footerActions,
locale,
height,
} = this.props;
if (footer === false) {
return null;
}
const newClassName = cx({
[`${prefix}dialog-footer`]: true,
[`${prefix}align-${footerAlign}`]: true,
[`${prefix}dialog-footer-fixed-height`]: !!height,
});
const footerContent =
footer === true || !footer
? footerActions.map(action => {
const btnProps = this.props[`${action}Props`];
const newBtnProps = {
...btnProps,
prefix,
className: cx(
`${prefix}dialog-btn`,
btnProps.className
),
onClick: makeChain(
this.props[
`on${action[0].toUpperCase() +
action.slice(1)}`
],
btnProps.onClick
),
children: btnProps.children || locale[action],
};
if (action === 'ok') {
newBtnProps.type = 'primary';
}
return <Button key={action} {...newBtnProps} />;
})
: footer;
return (
<div
className={newClassName}
ref={this.getNode.bind(this, 'footerNode')}
>
{footerContent}
</div>
);
}
renderCloseLink() {
const { prefix, closeable, onClose, locale } = this.props;
if (closeable) {
return (
<a
role="button"
aria-label={locale.close}
className={`${prefix}dialog-close`}
onClick={onClose}
>
<Icon
className={`${prefix}dialog-close-icon`}
type="close"
/>
</a>
);
}
return null;
}
render() {
const {
prefix,
className,
closeable,
title,
role,
rtl,
height,
} = this.props;
const others = pickOthers(Object.keys(Inner.propTypes), this.props);
const newClassName = cx({
[`${prefix}dialog`]: true,
[`${prefix}closeable`]: closeable,
[className]: !!className,
});
const header = this.renderHeader();
const body = this.renderBody();
const footer = this.renderFooter();
const closeLink = this.renderCloseLink();
const ariaProps = {
role,
'aria-modal': 'true',
};
if (title) {
ariaProps['aria-labelledby'] = this.titleId;
}
others.style = Object.assign({}, others.style, { height });
return (
<div
{...ariaProps}
className={newClassName}
{...others}
dir={rtl ? 'rtl' : undefined}
>
{header}
{body}
{footer}
{closeLink}
</div>
);
}
}