Merge pull request #19 from simdd/master
format: add comment and fommat Component folder
This commit is contained in:
commit
39afde9f97
16
.prettierrc
16
.prettierrc
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"singleQuote": true,
|
||||
"semi": false,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid"
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"singleQuote": true,
|
||||
"semi": true,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { themeable, ClassNamesFn } from '../theme';
|
||||
import {themeable, ClassNamesFn} from '../theme';
|
||||
|
||||
interface NotFoundProps {
|
||||
code?: string | number;
|
||||
|
@ -17,28 +17,18 @@ interface NotFoundProps {
|
|||
|
||||
export class NotFound extends React.Component<NotFoundProps, any> {
|
||||
render() {
|
||||
const {
|
||||
links,
|
||||
footerText,
|
||||
description,
|
||||
children,
|
||||
code
|
||||
} = this.props;
|
||||
const {links, footerText, description, children, code} = this.props;
|
||||
|
||||
return (
|
||||
<div className="container w-xxl w-auto-xs">
|
||||
<div className="text-center m-b-lg">
|
||||
<h1 className="text-shadow text-white">{code || '404'}</h1>
|
||||
{description ? (<div className="text-danger">{description}</div>) : null}
|
||||
{description ? <div className="text-danger">{description}</div> : null}
|
||||
</div>
|
||||
|
||||
{children}
|
||||
|
||||
{links ? (
|
||||
<div className="list-group bg-info auto m-b-sm m-b-lg">
|
||||
{links}
|
||||
</div>
|
||||
) : null}
|
||||
{links ? <div className="list-group bg-info auto m-b-sm m-b-lg">{links}</div> : null}
|
||||
|
||||
{footerText ? (
|
||||
<div className="text-center">
|
||||
|
@ -52,4 +42,4 @@ export class NotFound extends React.Component<NotFoundProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(NotFound);
|
||||
export default themeable(NotFound);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
/**
|
||||
* @file alert
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint fecs-indent: [0, "space", 2, 2] */
|
||||
* @file Alert
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {render} from 'react-dom';
|
||||
import Modal from './Modal';
|
||||
import Button from './Button';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface AlertProps {
|
||||
container?: any;
|
||||
|
@ -20,18 +19,17 @@ export interface AlertProps {
|
|||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
theme?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface AlertState {
|
||||
show: boolean;
|
||||
title?:string;
|
||||
content:string;
|
||||
confirm:boolean;
|
||||
title?: string;
|
||||
content: string;
|
||||
confirm: boolean;
|
||||
}
|
||||
|
||||
export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
|
||||
static instance:any = null;
|
||||
static instance: any = null;
|
||||
static getInstance() {
|
||||
if (!Alert.instance) {
|
||||
console.warn('Alert 组件应该没有被渲染,所以隐性的渲染到 body 了');
|
||||
|
@ -44,16 +42,16 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
return Alert.instance;
|
||||
}
|
||||
|
||||
_resolve:(value:any) => void;
|
||||
_modal:any;
|
||||
_body:any;
|
||||
state:AlertState = {
|
||||
_resolve: (value: any) => void;
|
||||
_modal: any;
|
||||
_body: any;
|
||||
state: AlertState = {
|
||||
show: false,
|
||||
title: '',
|
||||
content: '',
|
||||
confirm: false
|
||||
confirm: false,
|
||||
};
|
||||
constructor(props:AlertProps) {
|
||||
constructor(props: AlertProps) {
|
||||
super(props);
|
||||
|
||||
this.close = this.close.bind(this);
|
||||
|
@ -68,7 +66,7 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
cancelText: '取消',
|
||||
title: '系统消息',
|
||||
alertBtnLevel: 'primary',
|
||||
confirmBtnLevel: 'danger'
|
||||
confirmBtnLevel: 'danger',
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
|
@ -79,8 +77,7 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
this._body && (this._body.innerHTML = this.state.content);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps:AlertProps, prevState:AlertState) {
|
||||
|
||||
componentDidUpdate(prevProps: AlertProps, prevState: AlertState) {
|
||||
if (prevState.content !== this.state.content) {
|
||||
this._body && (this._body.innerHTML = this.state.content);
|
||||
}
|
||||
|
@ -98,41 +95,44 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
this.close(false);
|
||||
}
|
||||
|
||||
close(confirmed:boolean) {
|
||||
close(confirmed: boolean) {
|
||||
const isConfirm = this.state.confirm;
|
||||
|
||||
this.setState({
|
||||
show: false
|
||||
}, isConfirm ? () => this._resolve(confirmed)/*this._reject()*/ : undefined);
|
||||
this.setState(
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
|
||||
);
|
||||
}
|
||||
|
||||
alert(content:string, title?:string) {
|
||||
alert(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: false
|
||||
confirm: false,
|
||||
});
|
||||
}
|
||||
|
||||
confirm(content:string, title?:string) {
|
||||
confirm(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: true
|
||||
confirm: true,
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
this._resolve = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
modalRef(ref:any) {
|
||||
modalRef(ref: any) {
|
||||
this._modal = ref;
|
||||
}
|
||||
|
||||
bodyRef(ref:any) {
|
||||
bodyRef(ref: any) {
|
||||
this._body = ref;
|
||||
this._body && (this._body.innerHTML = this.state.content);
|
||||
}
|
||||
|
@ -146,15 +146,10 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
confirmBtnLevel,
|
||||
alertBtnLevel,
|
||||
classnames: cx,
|
||||
classPrefix
|
||||
} = this.props;
|
||||
classPrefix,
|
||||
} = this.props;
|
||||
return (
|
||||
<Modal
|
||||
show={this.state.show}
|
||||
onHide={this.handleCancel}
|
||||
container={container}
|
||||
ref={this.modalRef}
|
||||
>
|
||||
<Modal show={this.state.show} onHide={this.handleCancel} container={container} ref={this.modalRef}>
|
||||
<div className={cx('Modal-header')}>
|
||||
<div className={cx('Modal-title')}>{this.state.title || title}</div>
|
||||
</div>
|
||||
|
@ -162,22 +157,19 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
<div ref={this.bodyRef} />
|
||||
</div>
|
||||
<div className={cx('Modal-footer')}>
|
||||
{this.state.confirm ? (
|
||||
<Button
|
||||
onClick={this.handleCancel}
|
||||
>{cancelText}</Button>
|
||||
) : null}
|
||||
<Button
|
||||
level={this.state.confirm ? confirmBtnLevel : alertBtnLevel}
|
||||
onClick={this.handleConfirm}
|
||||
>{confirmText}</Button>
|
||||
{this.state.confirm ? <Button onClick={this.handleCancel}>{cancelText}</Button> : null}
|
||||
<Button level={this.state.confirm ? confirmBtnLevel : alertBtnLevel} onClick={this.handleConfirm}>
|
||||
{confirmText}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const alert:(content:string, title?:string) => void = (content, title) => Alert.getInstance().alert(content, title);
|
||||
export const confirm:(content:string, title?:string)=>Promise<any> = (content, title) => Alert.getInstance().confirm(content, title);
|
||||
export const ThemedAlert = themeable(Alert)
|
||||
export const alert: (content: string, title?: string) => void = (content, title) =>
|
||||
Alert.getInstance().alert(content, title);
|
||||
export const confirm: (content: string, title?: string) => Promise<any> = (content, title) =>
|
||||
Alert.getInstance().confirm(content, title);
|
||||
export const ThemedAlert = themeable(Alert);
|
||||
export default ThemedAlert;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
/**
|
||||
* @file Alert2
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface AlertProps {
|
||||
level: 'danger' | 'info' | 'success' | 'warning';
|
||||
|
@ -12,53 +17,43 @@ export interface AlertProps {
|
|||
|
||||
export interface AlertState {
|
||||
show: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
static defaultProps:Pick<AlertProps, "level" | "className" | "showCloseButton"> = {
|
||||
static defaultProps: Pick<AlertProps, 'level' | 'className' | 'showCloseButton'> = {
|
||||
level: 'info',
|
||||
className: '',
|
||||
showCloseButton: false
|
||||
showCloseButton: false,
|
||||
};
|
||||
static propsList: Array<string> = [
|
||||
"level",
|
||||
"className",
|
||||
"showCloseButton",
|
||||
"onClose"
|
||||
];
|
||||
static propsList: Array<string> = ['level', 'className', 'showCloseButton', 'onClose'];
|
||||
|
||||
constructor(props:AlertProps) {
|
||||
constructor(props: AlertProps) {
|
||||
super(props);
|
||||
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.state = {
|
||||
show: true
|
||||
}
|
||||
show: true,
|
||||
};
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
this.setState({
|
||||
show: false
|
||||
}, this.props.onClose);
|
||||
this.setState(
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
this.props.onClose
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
className,
|
||||
level,
|
||||
children,
|
||||
showCloseButton
|
||||
} = this.props;
|
||||
const {classnames: cx, className, level, children, showCloseButton} = this.props;
|
||||
|
||||
return this.state.show ? (
|
||||
<div className={cx("Alert", level ? `Alert--${level}` : '', className)}>
|
||||
<div className={cx('Alert', level ? `Alert--${level}` : '', className)}>
|
||||
{showCloseButton ? (
|
||||
<button
|
||||
className={cx("Alert-close")}
|
||||
onClick={this.handleClick}
|
||||
type="button"
|
||||
><span>×</span></button>
|
||||
<button className={cx('Alert-close')} onClick={this.handleClick} type="button">
|
||||
<span>×</span>
|
||||
</button>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
|
@ -66,4 +61,4 @@ export class Alert extends React.Component<AlertProps, AlertState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(Alert);
|
||||
export default themeable(Alert);
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
/**
|
||||
* @file AsideNav
|
||||
* 左侧导航。
|
||||
* @description 左侧导航。
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import {
|
||||
mapTree
|
||||
} from '../utils/helper';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {mapTree} from '../utils/helper';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export type LinkItem = LinkItemProps;
|
||||
interface LinkItemProps {
|
||||
|
@ -29,8 +27,8 @@ interface Navigation {
|
|||
prefix?: JSX.Element;
|
||||
affix?: JSX.Element;
|
||||
className?: string;
|
||||
[propName:string]: any;
|
||||
};
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
interface AsideNavProps {
|
||||
id?: string;
|
||||
|
@ -39,34 +37,33 @@ interface AsideNavProps {
|
|||
classnames: ClassNamesFn;
|
||||
renderLink: Function;
|
||||
isActive: Function;
|
||||
isOpen: (link:LinkItemProps) => boolean;
|
||||
isOpen: (link: LinkItemProps) => boolean;
|
||||
navigations: Array<Navigation>;
|
||||
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, props:AsideNavProps) => React.ReactNode;
|
||||
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, props: AsideNavProps) => React.ReactNode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface AsideNavState {
|
||||
navigations: Array<Navigation>;
|
||||
}
|
||||
|
||||
export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
||||
static defaultProps = {
|
||||
renderLink: (item: LinkItemProps) => (
|
||||
<a>{item.label}</a>
|
||||
),
|
||||
renderSubLinks: (link:LinkItemProps, renderLink: Function, depth: number, {
|
||||
classnames: cx
|
||||
}: AsideNavProps) => link.children && link.children.length ? (
|
||||
<ul className={cx('AsideNav-subList')}>
|
||||
{link.label ? <li key="subHeader" className={cx('AsideNav-subHeader')}><a>{link.label}</a></li> : null}
|
||||
{link.children.map((link, key) => renderLink(link, key, {}, depth + 1))}
|
||||
</ul>
|
||||
) : link.label && depth === 1 ? (
|
||||
<div className={cx('AsideNav-tooltip')}>{link.label}</div>
|
||||
) : null,
|
||||
renderLink: (item: LinkItemProps) => <a>{item.label}</a>,
|
||||
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, {classnames: cx}: AsideNavProps) =>
|
||||
link.children && link.children.length ? (
|
||||
<ul className={cx('AsideNav-subList')}>
|
||||
{link.label ? (
|
||||
<li key="subHeader" className={cx('AsideNav-subHeader')}>
|
||||
<a>{link.label}</a>
|
||||
</li>
|
||||
) : null}
|
||||
{link.children.map((link, key) => renderLink(link, key, {}, depth + 1))}
|
||||
</ul>
|
||||
) : link.label && depth === 1 ? (
|
||||
<div className={cx('AsideNav-tooltip')}>{link.label}</div>
|
||||
) : null,
|
||||
isActive: (link: LinkItem) => link.open,
|
||||
isOpen: (item:LinkItemProps) => item.children ? item.children.some(item => item.open) : false
|
||||
isOpen: (item: LinkItemProps) => (item.children ? item.children.some(item => item.open) : false),
|
||||
};
|
||||
|
||||
constructor(props: AsideNavProps) {
|
||||
|
@ -75,16 +72,22 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
const isOpen = props.isOpen;
|
||||
let id = 1;
|
||||
this.state = {
|
||||
navigations: mapTree(props.navigations, (item: Navigation) => {
|
||||
const isActive = typeof item.active === 'undefined' ? (props.isActive as Function)(item) : item.active;
|
||||
navigations: mapTree(
|
||||
props.navigations,
|
||||
(item: Navigation) => {
|
||||
const isActive =
|
||||
typeof item.active === 'undefined' ? (props.isActive as Function)(item) : item.active;
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps)
|
||||
}
|
||||
}, 1, true)
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps),
|
||||
};
|
||||
},
|
||||
1,
|
||||
true
|
||||
),
|
||||
};
|
||||
|
||||
this.renderLink = this.renderLink.bind(this);
|
||||
|
@ -94,42 +97,46 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
componentWillReceiveProps(nextProps: AsideNavProps) {
|
||||
const props = this.props;
|
||||
const isOpen = props.isOpen;
|
||||
|
||||
if (props.navigations !== nextProps.navigations || props.isActive !== nextProps.isActive) {
|
||||
|
||||
if (props.navigations !== nextProps.navigations || props.isActive !== nextProps.isActive) {
|
||||
let id = 1;
|
||||
this.setState({
|
||||
navigations: mapTree(nextProps.navigations, (item: Navigation) => {
|
||||
const isActive = typeof item.active === 'undefined' ? (nextProps.isActive as Function)(item) : item.active;
|
||||
navigations: mapTree(
|
||||
nextProps.navigations,
|
||||
(item: Navigation) => {
|
||||
const isActive =
|
||||
typeof item.active === 'undefined' ? (nextProps.isActive as Function)(item) : item.active;
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps)
|
||||
}
|
||||
}, 1, true)
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps),
|
||||
};
|
||||
},
|
||||
1,
|
||||
true
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
toggleExpand(link: LinkItemProps) {
|
||||
this.setState({
|
||||
navigations: mapTree(this.state.navigations, (item: Navigation) => ({
|
||||
...item,
|
||||
open: link.id === item.id ? !item.open : item.open
|
||||
}), 1, true)
|
||||
navigations: mapTree(
|
||||
this.state.navigations,
|
||||
(item: Navigation) => ({
|
||||
...item,
|
||||
open: link.id === item.id ? !item.open : item.open,
|
||||
}),
|
||||
1,
|
||||
true
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
renderLink(link: LinkItemProps, key: any, props:Partial<AsideNavProps> = {}, depth = 1):React.ReactNode {
|
||||
const {
|
||||
renderLink,
|
||||
isActive,
|
||||
renderSubLinks,
|
||||
classnames: cx,
|
||||
...others
|
||||
} = this.props;
|
||||
renderLink(link: LinkItemProps, key: any, props: Partial<AsideNavProps> = {}, depth = 1): React.ReactNode {
|
||||
const {renderLink, isActive, renderSubLinks, classnames: cx, ...others} = this.props;
|
||||
|
||||
const dom = (renderLink as Function)({
|
||||
link,
|
||||
|
@ -138,7 +145,7 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
toggleExpand: this.toggleExpand,
|
||||
depth,
|
||||
classnames: cx,
|
||||
...others
|
||||
...others,
|
||||
});
|
||||
|
||||
if (!dom) {
|
||||
|
@ -150,7 +157,7 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
{...props}
|
||||
key={key}
|
||||
className={cx(`AsideNav-item`, link.className, {
|
||||
[`is-active`]: link.active || link.open
|
||||
[`is-active`]: link.active || link.open,
|
||||
})}
|
||||
>
|
||||
{dom}
|
||||
|
@ -161,29 +168,29 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
|
||||
render() {
|
||||
const navigations = this.state.navigations;
|
||||
let links:Array<React.ReactNode> = [];
|
||||
const {
|
||||
className,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
let links: Array<React.ReactNode> = [];
|
||||
const {className, classnames: cx} = this.props;
|
||||
|
||||
navigations.forEach((navigation, index) => {
|
||||
if (navigation.prefix) {
|
||||
const prefix:JSX.Element = typeof navigation.prefix === 'function' ? (navigation.prefix as any)(this.props) : navigation.prefix;
|
||||
links.push(React.cloneElement(prefix, {
|
||||
...prefix.props,
|
||||
key: `${index}-prefix`
|
||||
}))
|
||||
const prefix: JSX.Element =
|
||||
typeof navigation.prefix === 'function'
|
||||
? (navigation.prefix as any)(this.props)
|
||||
: navigation.prefix;
|
||||
links.push(
|
||||
React.cloneElement(prefix, {
|
||||
...prefix.props,
|
||||
key: `${index}-prefix`,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
navigation.label && links.push(
|
||||
<li
|
||||
key={`${index}-label`}
|
||||
className={cx(`AsideNav-label`, navigation.className)}
|
||||
>
|
||||
<span>{navigation.label}</span>
|
||||
</li>
|
||||
);
|
||||
navigation.label &&
|
||||
links.push(
|
||||
<li key={`${index}-label`} className={cx(`AsideNav-label`, navigation.className)}>
|
||||
<span>{navigation.label}</span>
|
||||
</li>
|
||||
);
|
||||
|
||||
navigation.children.forEach((item, key) => {
|
||||
const link = this.renderLink(item, `${index}-${key}`);
|
||||
|
@ -191,22 +198,23 @@ export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
|
|||
});
|
||||
|
||||
if (navigation.affix) {
|
||||
const affix:JSX.Element = typeof navigation.affix === 'function' ? (navigation.affix as any)(this.props) : navigation.affix;
|
||||
links.push(React.cloneElement(affix, {
|
||||
...affix.props,
|
||||
key: `${index}-affix`
|
||||
}))
|
||||
const affix: JSX.Element =
|
||||
typeof navigation.affix === 'function' ? (navigation.affix as any)(this.props) : navigation.affix;
|
||||
links.push(
|
||||
React.cloneElement(affix, {
|
||||
...affix.props,
|
||||
key: `${index}-affix`,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<nav className={cx(`AsideNav`, className)}>
|
||||
<ul className={cx(`AsideNav-list`)}>
|
||||
{links}
|
||||
</ul>
|
||||
<ul className={cx(`AsideNav-list`)}>{links}</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(AsideNav);
|
||||
export default themeable(AsideNav);
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
/**
|
||||
* @file 按钮
|
||||
* @file Button
|
||||
* @author fex
|
||||
* fex
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import TooltipWrapper, { TooltipObject, Trigger } from './TooltipWrapper';
|
||||
import { pickEventsProps } from '../utils/helper';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
|
||||
interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
||||
import * as React from 'react';
|
||||
import TooltipWrapper, {TooltipObject, Trigger} from './TooltipWrapper';
|
||||
import {pickEventsProps} from '../utils/helper';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface ButtonProps
|
||||
extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
||||
id?: string;
|
||||
className?: string;
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg';
|
||||
type: "button" | "reset" | "submit";
|
||||
type: 'button' | 'reset' | 'submit';
|
||||
level: string; // 'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default';
|
||||
tooltip?: string | TooltipObject;
|
||||
placement: "top" | "right" | "bottom" | "left";
|
||||
placement: 'top' | 'right' | 'bottom' | 'left';
|
||||
tooltipContainer?: any;
|
||||
tooltipTrigger: Trigger | Array<Trigger>;
|
||||
tooltipRootClose: boolean;
|
||||
|
@ -30,13 +31,16 @@ interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes
|
|||
}
|
||||
|
||||
export class Button extends React.Component<ButtonProps> {
|
||||
static defaultProps:Pick<ButtonProps, "componentClass" | "level" | "type" | "placement" | "tooltipTrigger" | "tooltipRootClose"> = {
|
||||
static defaultProps: Pick<
|
||||
ButtonProps,
|
||||
'componentClass' | 'level' | 'type' | 'placement' | 'tooltipTrigger' | 'tooltipRootClose'
|
||||
> = {
|
||||
componentClass: 'button',
|
||||
level: 'default',
|
||||
type: 'button',
|
||||
placement: 'top',
|
||||
tooltipTrigger: ['hover', 'focus'],
|
||||
tooltipRootClose: false
|
||||
tooltipRootClose: false,
|
||||
};
|
||||
|
||||
renderButton() {
|
||||
|
@ -60,14 +64,18 @@ export class Button extends React.Component<ButtonProps> {
|
|||
<Comp
|
||||
type={Comp === 'a' ? undefined : type}
|
||||
{...pickEventsProps(rest)}
|
||||
className={cx(`Button`, {
|
||||
[`Button--${level}`]: level,
|
||||
[`Button--${size}`]: size,
|
||||
[`Button--block`]: block,
|
||||
[`Button--iconOnly`]: iconOnly,
|
||||
'is-disabled': disabled,
|
||||
'is-active': active
|
||||
}, className)}
|
||||
className={cx(
|
||||
`Button`,
|
||||
{
|
||||
[`Button--${level}`]: level,
|
||||
[`Button--${size}`]: size,
|
||||
[`Button--block`]: block,
|
||||
[`Button--iconOnly`]: iconOnly,
|
||||
'is-disabled': disabled,
|
||||
'is-active': active,
|
||||
},
|
||||
className
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{children}
|
||||
|
@ -85,7 +93,7 @@ export class Button extends React.Component<ButtonProps> {
|
|||
disabled,
|
||||
disabledTip,
|
||||
classPrefix,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
@ -96,12 +104,11 @@ export class Button extends React.Component<ButtonProps> {
|
|||
trigger={tooltipTrigger}
|
||||
rootClose={tooltipRootClose}
|
||||
>
|
||||
{disabled && disabledTip ?
|
||||
<div className={cx('Button--disabled-wrap')}>
|
||||
{this.renderButton()}
|
||||
</div>
|
||||
: this.renderButton()
|
||||
}
|
||||
{disabled && disabledTip ? (
|
||||
<div className={cx('Button--disabled-wrap')}>{this.renderButton()}</div>
|
||||
) : (
|
||||
this.renderButton()
|
||||
)}
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
/**
|
||||
* @file checkbox组件
|
||||
* @file Checkbox
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
const sizeMap = {
|
||||
sm: 'i-checks-sm',
|
||||
lg: 'i-checks-lg',
|
||||
small: 'i-checks-sm',
|
||||
large: 'i-checks-lg'
|
||||
large: 'i-checks-lg',
|
||||
};
|
||||
|
||||
interface CheckboxProps {
|
||||
|
@ -22,7 +22,7 @@ interface CheckboxProps {
|
|||
size?: 'sm' | 'lg' | 'small' | 'large';
|
||||
label?: string;
|
||||
className?: string;
|
||||
onChange?: (value:any) => void;
|
||||
onChange?: (value: any) => void;
|
||||
value?: any;
|
||||
containerClass?: string;
|
||||
inline?: boolean;
|
||||
|
@ -41,21 +41,17 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
|
|||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false,
|
||||
type: 'checkbox'
|
||||
type: 'checkbox',
|
||||
};
|
||||
|
||||
constructor(props:CheckboxProps) {
|
||||
constructor(props: CheckboxProps) {
|
||||
super(props);
|
||||
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this);
|
||||
}
|
||||
|
||||
hanldeCheck(e:React.ChangeEvent<any>) {
|
||||
const {
|
||||
trueValue,
|
||||
falseValue,
|
||||
onChange
|
||||
} = this.props;
|
||||
hanldeCheck(e: React.ChangeEvent<any>) {
|
||||
const {trueValue, falseValue, onChange} = this.props;
|
||||
|
||||
if (!onChange) {
|
||||
return;
|
||||
|
@ -78,20 +74,30 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
|
|||
readOnly,
|
||||
checked,
|
||||
type,
|
||||
name
|
||||
name,
|
||||
} = this.props;
|
||||
|
||||
className = (className ? className : '') + (size && sizeMap[size] ? ` ${sizeMap[size]}` : '');
|
||||
|
||||
return (
|
||||
<label
|
||||
className={cx(`${ns}Checkbox ${ns}Checkbox--${type}`, {
|
||||
[`${ns}Checkbox--full`]: !partial
|
||||
}, className)}
|
||||
<label
|
||||
className={cx(
|
||||
`${ns}Checkbox ${ns}Checkbox--${type}`,
|
||||
{
|
||||
[`${ns}Checkbox--full`]: !partial,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type={type}
|
||||
checked={typeof checked !== 'undefined' ? checked : typeof value === 'undefined' ? value : value == trueValue}
|
||||
checked={
|
||||
typeof checked !== 'undefined'
|
||||
? checked
|
||||
: typeof value === 'undefined'
|
||||
? value
|
||||
: value == trueValue
|
||||
}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file checkboxes 多选输入框
|
||||
*
|
||||
* @file Checkboxes
|
||||
* @description 多选输入框
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
|
@ -9,9 +9,9 @@ import uncontrollable = require('uncontrollable');
|
|||
import Checkbox from './Checkbox';
|
||||
import find = require('lodash/find');
|
||||
import chunk = require('lodash/chunk');
|
||||
import { flattenTree } from '../utils/helper';
|
||||
import { Option } from './Checkboxes';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {flattenTree} from '../utils/helper';
|
||||
import {Option} from './Checkboxes';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
// import isPlainObject = require('lodash/isPlainObject');
|
||||
|
||||
export interface Option {
|
||||
|
@ -20,8 +20,8 @@ export interface Option {
|
|||
disabled?: boolean;
|
||||
children?: Options;
|
||||
[propName: string]: any;
|
||||
};
|
||||
export interface Options extends Array<Option> { };
|
||||
}
|
||||
export interface Options extends Array<Option> {}
|
||||
|
||||
export interface OptionProps {
|
||||
multi?: boolean;
|
||||
|
@ -33,7 +33,7 @@ export interface OptionProps {
|
|||
delimiter: string;
|
||||
clearable: boolean;
|
||||
placeholder?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OptionValue = string | number | null | undefined | Option;
|
||||
|
||||
|
@ -52,7 +52,14 @@ export function value2array(value: OptionValue | Array<OptionValue>, props: Part
|
|||
}
|
||||
|
||||
return (value as Array<OptionValue>)
|
||||
.map((value: OptionValue) => expandValue(!props.joinValues && value && value.hasOwnProperty(props.valueField || 'value') ? (value as any)[props.valueField || 'value'] : value, props))
|
||||
.map((value: OptionValue) =>
|
||||
expandValue(
|
||||
!props.joinValues && value && value.hasOwnProperty(props.valueField || 'value')
|
||||
? (value as any)[props.valueField || 'value']
|
||||
: value,
|
||||
props
|
||||
)
|
||||
)
|
||||
.filter((item: Option) => item) as Array<Option>;
|
||||
}
|
||||
|
||||
|
@ -67,10 +74,7 @@ export function expandValue(value: OptionValue, props: Partial<OptionProps>): Op
|
|||
return null;
|
||||
}
|
||||
|
||||
let {
|
||||
options,
|
||||
valueField
|
||||
} = props;
|
||||
let {options, valueField} = props;
|
||||
|
||||
if (!options) {
|
||||
return null;
|
||||
|
@ -116,35 +120,28 @@ export class Checkboxes extends React.PureComponent<CheckboxesProps, any> {
|
|||
extractValue: false,
|
||||
inline: false,
|
||||
delimiter: ',',
|
||||
columnsCount: 1 // 一行显示一个
|
||||
columnsCount: 1, // 一行显示一个
|
||||
};
|
||||
|
||||
toggleOption(option: Option) {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
joinValues,
|
||||
extractValue,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
} = this.props;
|
||||
const {value, onChange, joinValues, extractValue, delimiter, valueField, options} = this.props;
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
options,
|
||||
});
|
||||
let idx = valueArray.indexOf(option);
|
||||
|
||||
if (!~idx) {
|
||||
option = value2array(option[valueField || 'value'], {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
})[0] || option;
|
||||
option =
|
||||
value2array(option[valueField || 'value'], {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
})[0] || option;
|
||||
idx = valueArray.indexOf(option);
|
||||
}
|
||||
|
||||
|
@ -182,7 +179,7 @@ export class Checkboxes extends React.PureComponent<CheckboxesProps, any> {
|
|||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
options,
|
||||
});
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
|
@ -201,24 +198,27 @@ export class Checkboxes extends React.PureComponent<CheckboxesProps, any> {
|
|||
}
|
||||
|
||||
if (!inline && (columnsCount as number) > 1) {
|
||||
let cellClassName = `col-sm-${(12 / (columnsCount as number)).toFixed(1).replace(/\.0$/, '').replace(/\./, '-')}`;
|
||||
let cellClassName = `col-sm-${(12 / (columnsCount as number))
|
||||
.toFixed(1)
|
||||
.replace(/\.0$/, '')
|
||||
.replace(/\./, '-')}`;
|
||||
body = chunk(body, columnsCount).map((group, groupIndex) => (
|
||||
<div className="row" key={groupIndex}>
|
||||
{group.map((item, index) => (
|
||||
<div key={index} className={cellClassName}>{item}</div>
|
||||
<div key={index} className={cellClassName}>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{body && body.length ? body : placeholder}
|
||||
</div>
|
||||
);
|
||||
return <div className={className}>{body && body.length ? body : placeholder}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import {Collapse} from 'react-bootstrap';
|
||||
|
||||
export default Collapse;
|
||||
export default Collapse;
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
/**
|
||||
* @file ColorPicker
|
||||
* @description 颜色选择器组件
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import {
|
||||
findDOMNode
|
||||
} from 'react-dom';
|
||||
import { SketchPicker, ColorResult } from 'react-color';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {SketchPicker, ColorResult} from 'react-color';
|
||||
import {closeIcon} from './icons';
|
||||
import Overlay from './Overlay';
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import PopOver from './PopOver';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface ColorProps {
|
||||
placeholder?: string;
|
||||
|
@ -23,32 +26,32 @@ export interface ColorProps {
|
|||
value: any;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
onChange: (value:any) => void;
|
||||
};
|
||||
onChange: (value: any) => void;
|
||||
}
|
||||
|
||||
export interface ColorControlState {
|
||||
isOpened: boolean;
|
||||
isFocused: boolean;
|
||||
inputValue: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class ColorControl extends React.PureComponent<ColorProps, ColorControlState> {
|
||||
static defaultProps = {
|
||||
format: 'hex',
|
||||
clearable: true,
|
||||
placeholder: '请选择颜色'
|
||||
placeholder: '请选择颜色',
|
||||
// closeOnSelect: true
|
||||
};
|
||||
state = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
inputValue: this.props.value || ''
|
||||
inputValue: this.props.value || '',
|
||||
};
|
||||
popover:any;
|
||||
popover: any;
|
||||
closeTimer: number;
|
||||
preview: React.RefObject<HTMLElement>;
|
||||
input: React.RefObject<HTMLInputElement>;
|
||||
constructor(props:ColorProps) {
|
||||
constructor(props: ColorProps) {
|
||||
super(props);
|
||||
|
||||
this.open = this.open.bind(this);
|
||||
|
@ -65,26 +68,26 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
this.input = React.createRef();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps:ColorProps) {
|
||||
componentWillReceiveProps(nextProps: ColorProps) {
|
||||
const props = this.props;
|
||||
|
||||
if (props.value !== nextProps.value) {
|
||||
this.setState({
|
||||
inputValue: nextProps.value || ''
|
||||
inputValue: nextProps.value || '',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleFocus() {
|
||||
this.setState({
|
||||
isFocused: true
|
||||
isFocused: true,
|
||||
});
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.setState({
|
||||
isFocused: false,
|
||||
inputValue: this.props.value
|
||||
inputValue: this.props.value,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -96,18 +99,21 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
this.input.current && this.input.current.blur();
|
||||
}
|
||||
|
||||
open(fn?:() => void) {
|
||||
open(fn?: () => void) {
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
isOpened: true
|
||||
}, fn);
|
||||
this.setState(
|
||||
{
|
||||
isOpened: true,
|
||||
},
|
||||
fn
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
isOpened: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -123,31 +129,36 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const onChange = this.props.onChange;
|
||||
|
||||
this.setState({
|
||||
inputValue: e.currentTarget.value
|
||||
}, () => {
|
||||
const dom:HTMLElement = this.preview.current as HTMLElement;
|
||||
|
||||
// 通过读取dom上到值,确认当前输入值是否有效。
|
||||
if (dom && dom.style.backgroundColor === this.state.inputValue) {
|
||||
onChange(this.state.inputValue);
|
||||
this.setState(
|
||||
{
|
||||
inputValue: e.currentTarget.value,
|
||||
},
|
||||
() => {
|
||||
const dom: HTMLElement = this.preview.current as HTMLElement;
|
||||
|
||||
// 通过读取dom上到值,确认当前输入值是否有效。
|
||||
if (dom && dom.style.backgroundColor === this.state.inputValue) {
|
||||
onChange(this.state.inputValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
handleChange(color:ColorResult) {
|
||||
handleChange(color: ColorResult) {
|
||||
const {
|
||||
onChange,
|
||||
format,
|
||||
// closeOnSelect
|
||||
} = this.props;
|
||||
|
||||
} = this.props;
|
||||
|
||||
if (format === 'rgba') {
|
||||
onChange(`rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`);
|
||||
} else if (format === 'rgb') {
|
||||
onChange(`rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`);
|
||||
} else if (format === 'hsl') {
|
||||
onChange(`hsl(${Math.round(color.hsl.h)}, ${Math.round(color.hsl.s * 100)}%, ${Math.round(color.hsl.l * 100)}%)`);
|
||||
} else if (format === 'hsl') {
|
||||
onChange(
|
||||
`hsl(${Math.round(color.hsl.h)}, ${Math.round(color.hsl.s * 100)}%, ${Math.round(color.hsl.l * 100)}%)`
|
||||
);
|
||||
} else {
|
||||
onChange(color.hex);
|
||||
}
|
||||
|
@ -166,20 +177,24 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
format,
|
||||
clearable,
|
||||
placement,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
} = this.props;
|
||||
|
||||
const isOpened = this.state.isOpened;
|
||||
const isFocused = this.state.isFocused;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`ColorPicker`, {
|
||||
'is-disabled': disabled,
|
||||
'is-focused': isFocused
|
||||
}, className)}
|
||||
<div
|
||||
className={cx(
|
||||
`ColorPicker`,
|
||||
{
|
||||
'is-disabled': disabled,
|
||||
'is-focused': isFocused,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
<input
|
||||
size={10}
|
||||
ref={this.input}
|
||||
type="text"
|
||||
|
@ -195,10 +210,18 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
/>
|
||||
|
||||
{clearable && !disabled && value ? (
|
||||
<a onClick={this.clearValue} className={cx('ColorPicker-clear')}>{closeIcon}</a>
|
||||
<a onClick={this.clearValue} className={cx('ColorPicker-clear')}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
<span onClick={this.handleClick} className={cx('ColorPicker-preview')}><i ref={this.preview} className={`${ns}ColorPicker-previewIcon`} style={{background: this.state.inputValue || '#ccc'}} /></span>
|
||||
|
||||
<span onClick={this.handleClick} className={cx('ColorPicker-preview')}>
|
||||
<i
|
||||
ref={this.preview}
|
||||
className={`${ns}ColorPicker-previewIcon`}
|
||||
style={{background: this.state.inputValue || '#ccc'}}
|
||||
/>
|
||||
</span>
|
||||
|
||||
{isOpened ? (
|
||||
<Overlay
|
||||
|
@ -209,13 +232,12 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
rootClose={false}
|
||||
show
|
||||
>
|
||||
<PopOver
|
||||
classPrefix={ns}
|
||||
className={cx('ColorPicker-popover')}
|
||||
onHide={this.close}
|
||||
overlay
|
||||
>
|
||||
<SketchPicker disableAlpha={!!~['rgb', 'hex'].indexOf(format as string)} color={value} onChangeComplete={this.handleChange} />
|
||||
<PopOver classPrefix={ns} className={cx('ColorPicker-popover')} onHide={this.close} overlay>
|
||||
<SketchPicker
|
||||
disableAlpha={!!~['rgb', 'hex'].indexOf(format as string)}
|
||||
color={value}
|
||||
onChangeComplete={this.handleChange}
|
||||
/>
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
) : null}
|
||||
|
@ -224,6 +246,8 @@ export class ColorControl extends React.PureComponent<ColorProps, ColorControlSt
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(uncontrollable(ColorControl, {
|
||||
value: 'onChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(ColorControl, {
|
||||
value: 'onChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
* @file DatePicker
|
||||
* @description 时间选择器组件
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import * as moment from 'moment';
|
||||
|
@ -7,16 +13,16 @@ import 'moment/locale/zh-cn';
|
|||
import * as CalendarContainer from 'react-datetime/src/CalendarContainer';
|
||||
import * as ReactDatePicker from 'react-datetime';
|
||||
import Select from './Select';
|
||||
import { closeIcon } from './icons';
|
||||
import {closeIcon} from './icons';
|
||||
import PopOver from './PopOver';
|
||||
import Overlay from './Overlay';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
CalendarContainer.prototype.render = (function (_super) {
|
||||
return function () {
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
CalendarContainer.prototype.render = (function(_super) {
|
||||
return function() {
|
||||
if (this.props.view === 'days') {
|
||||
return (<CustomDaysView {...this.props.viewProps} />);
|
||||
return <CustomDaysView {...this.props.viewProps} />;
|
||||
}
|
||||
|
||||
return _super.apply(this, arguments);
|
||||
|
@ -32,18 +38,12 @@ class BaseDatePicker extends ReactDatePicker {
|
|||
this.__hacked = true;
|
||||
const origin = (this as any).getComponentProps;
|
||||
const setState = this.setState.bind(this);
|
||||
(this as any).getComponentProps = function () {
|
||||
(this as any).getComponentProps = function() {
|
||||
const props = origin.apply(this);
|
||||
props.setDateTimeState = setState;
|
||||
[
|
||||
'onChange',
|
||||
'onClose',
|
||||
'requiredConfirm',
|
||||
'classPrefix',
|
||||
'prevIcon',
|
||||
'nextIcon',
|
||||
'isEndDate'
|
||||
].forEach(key => props[key] = (this.props as any)[key]);
|
||||
['onChange', 'onClose', 'requiredConfirm', 'classPrefix', 'prevIcon', 'nextIcon', 'isEndDate'].forEach(
|
||||
key => (props[key] = (this.props as any)[key])
|
||||
);
|
||||
|
||||
return props;
|
||||
};
|
||||
|
@ -72,11 +72,11 @@ interface CustomDaysViewProps {
|
|||
showView: (view: string) => () => void;
|
||||
updateSelectedDate: (event: React.MouseEvent<any>, close?: boolean) => void;
|
||||
handleClickOutside: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
static defaultProps = {
|
||||
classPrefix: 'a-'
|
||||
classPrefix: 'a-',
|
||||
};
|
||||
|
||||
constructor(props: CustomDaysViewProps) {
|
||||
|
@ -95,8 +95,8 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
const dow: Array<string> = [];
|
||||
let i = 0;
|
||||
|
||||
days.forEach(function (day) {
|
||||
dow[(7 + (i++) - first) % 7] = day;
|
||||
days.forEach(function(day) {
|
||||
dow[(7 + i++ - first) % 7] = day;
|
||||
});
|
||||
|
||||
return dow;
|
||||
|
@ -117,7 +117,8 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
|
||||
if (~target.className.indexOf('rdtNew')) {
|
||||
modifier = 1;
|
||||
} if (~target.className.indexOf('rdtOld')) {
|
||||
}
|
||||
if (~target.className.indexOf('rdtOld')) {
|
||||
modifier = -1;
|
||||
}
|
||||
|
||||
|
@ -127,11 +128,11 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
.hours(currentDate.hours())
|
||||
.minutes(currentDate.minutes())
|
||||
.seconds(currentDate.seconds())
|
||||
.milliseconds(currentDate.milliseconds())
|
||||
.milliseconds(currentDate.milliseconds());
|
||||
|
||||
this.props.setDateTimeState({
|
||||
viewDate,
|
||||
selectedDate: viewDate.clone()
|
||||
selectedDate: viewDate.clone(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -151,7 +152,10 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
|
||||
const viewDate = this.props.viewDate;
|
||||
this.props.setDateTimeState({
|
||||
viewDate: viewDate.clone().month(option.value).startOf('month')
|
||||
viewDate: viewDate
|
||||
.clone()
|
||||
.month(option.value)
|
||||
.startOf('month'),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -168,7 +172,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
const viewDate = this.props.viewDate;
|
||||
const newDate = viewDate.clone().year(option.value);
|
||||
this.props.setDateTimeState({
|
||||
viewDate: newDate[newDate.isBefore(viewDate) ? 'endOf' : 'startOf']('year')
|
||||
viewDate: newDate[newDate.isBefore(viewDate) ? 'endOf' : 'startOf']('year'),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -178,7 +182,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
|
||||
this.props.setDateTimeState({
|
||||
viewDate: date.clone(),
|
||||
selectedDate: date.clone()
|
||||
selectedDate: date.clone(),
|
||||
});
|
||||
|
||||
if (!this.props.requiredConfirm) {
|
||||
|
@ -190,7 +194,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
const date = this.props.viewDate.clone();
|
||||
|
||||
this.props.setDateTimeState({
|
||||
selectedDate: date
|
||||
selectedDate: date,
|
||||
});
|
||||
this.props.onChange(date);
|
||||
this.props.onClose && this.props.onClose();
|
||||
|
@ -221,12 +225,15 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
let currentYear = date.clone().set({
|
||||
year: year,
|
||||
month: irrelevantMonth,
|
||||
date: irrelevantDate
|
||||
date: irrelevantDate,
|
||||
});
|
||||
const noOfDaysInYear = parseInt(currentYear.endOf('year').format('DDD'), 10);
|
||||
const daysInYear = Array.from({
|
||||
length: noOfDaysInYear
|
||||
}, (e, i) => i + 1);
|
||||
const daysInYear = Array.from(
|
||||
{
|
||||
length: noOfDaysInYear,
|
||||
},
|
||||
(e, i) => i + 1
|
||||
);
|
||||
const validDay = daysInYear.find(d => isValid(currentYear.clone().dayOfYear(d)));
|
||||
|
||||
if (!validDay) {
|
||||
|
@ -245,12 +252,15 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
let currentYear = date.clone().set({
|
||||
year: year,
|
||||
month: irrelevantMonth,
|
||||
date: irrelevantDate
|
||||
date: irrelevantDate,
|
||||
});
|
||||
const noOfDaysInYear = parseInt(currentYear.endOf('year').format('DDD'), 10);
|
||||
const daysInYear = Array.from({
|
||||
length: noOfDaysInYear
|
||||
}, (e, i) => i + 1);
|
||||
const daysInYear = Array.from(
|
||||
{
|
||||
length: noOfDaysInYear,
|
||||
},
|
||||
(e, i) => i + 1
|
||||
);
|
||||
const validDay = daysInYear.find(d => isValid(currentYear.clone().dayOfYear(d)));
|
||||
|
||||
if (!validDay) {
|
||||
|
@ -266,7 +276,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
value={date.year()}
|
||||
options={years.map(year => ({
|
||||
label: `${year}`,
|
||||
value: year
|
||||
value: year,
|
||||
}))}
|
||||
onChange={this.handleYearChange}
|
||||
clearable={false}
|
||||
|
@ -287,15 +297,15 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
const currentMonth = date.clone().set({
|
||||
year,
|
||||
month: i,
|
||||
date: 1
|
||||
date: 1,
|
||||
});
|
||||
|
||||
const noOfDaysInMonth = parseInt(currentMonth.endOf('month').format('D'), 10);
|
||||
const daysInMonth = Array.from({ length: noOfDaysInMonth }, function (e, i) {
|
||||
const daysInMonth = Array.from({length: noOfDaysInMonth}, function(e, i) {
|
||||
return i + 1;
|
||||
});
|
||||
|
||||
const validDay = daysInMonth.find((d) => isValid(currentMonth.clone().set('date', d)));
|
||||
const validDay = daysInMonth.find(d => isValid(currentMonth.clone().set('date', d)));
|
||||
if (validDay) {
|
||||
days.push(i);
|
||||
}
|
||||
|
@ -308,7 +318,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
value={date.month()}
|
||||
options={days.map(day => ({
|
||||
label: `${day + 1}`,
|
||||
value: day
|
||||
value: day,
|
||||
}))}
|
||||
onChange={this.handleMonthChange}
|
||||
clearable={false}
|
||||
|
@ -318,18 +328,11 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
}
|
||||
|
||||
renderDay(props: any, currentDate: moment.Moment) {
|
||||
return (
|
||||
<td {...props}>{currentDate.date()}</td>
|
||||
);
|
||||
return <td {...props}>{currentDate.date()}</td>;
|
||||
}
|
||||
|
||||
renderTimes() {
|
||||
const {
|
||||
timeFormat,
|
||||
selectedDate,
|
||||
viewDate,
|
||||
isEndDate
|
||||
} = this.props;
|
||||
const {timeFormat, selectedDate, viewDate, isEndDate} = this.props;
|
||||
|
||||
const date = selectedDate || (isEndDate ? viewDate.endOf('day') : viewDate);
|
||||
const inputs: Array<React.ReactNode> = [];
|
||||
|
@ -346,22 +349,21 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
value={date.format(format)}
|
||||
min={min}
|
||||
max={max}
|
||||
onChange={(e) => this.setTime(type, Math.max(min, Math.min(parseInt(e.currentTarget.value.replace(/\D/g, ''), 10) || 0, max)))}
|
||||
onChange={e =>
|
||||
this.setTime(
|
||||
type,
|
||||
Math.max(min, Math.min(parseInt(e.currentTarget.value.replace(/\D/g, ''), 10) || 0, max))
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
inputs.push(
|
||||
<span key={i + 'divider'}>:</span>
|
||||
);
|
||||
inputs.push(<span key={i + 'divider'}>:</span>);
|
||||
});
|
||||
|
||||
inputs.length && inputs.pop();
|
||||
|
||||
return (
|
||||
<div>
|
||||
{inputs}
|
||||
</div>
|
||||
);
|
||||
return <div>{inputs}</div>;
|
||||
}
|
||||
|
||||
renderFooter() {
|
||||
|
@ -376,8 +378,12 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
{this.props.timeFormat ? this.renderTimes() : null}
|
||||
{this.props.requiredConfirm ? (
|
||||
<div key="button" className="rdtActions">
|
||||
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>确认</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>取消</a>
|
||||
<a className="rdtBtn rdtBtnConfirm" onClick={this.confirm}>
|
||||
确认
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.cancel}>
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
</td>
|
||||
|
@ -406,36 +412,36 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
classes = 'rdtDay';
|
||||
currentDate = prevMonth.clone();
|
||||
|
||||
if ((prevMonth.year() === currentYear && prevMonth.month() < currentMonth) || (prevMonth.year() < currentYear))
|
||||
if (
|
||||
(prevMonth.year() === currentYear && prevMonth.month() < currentMonth) ||
|
||||
prevMonth.year() < currentYear
|
||||
)
|
||||
classes += ' rdtOld';
|
||||
else if ((prevMonth.year() === currentYear && prevMonth.month() > currentMonth) || (prevMonth.year() > currentYear))
|
||||
else if (
|
||||
(prevMonth.year() === currentYear && prevMonth.month() > currentMonth) ||
|
||||
prevMonth.year() > currentYear
|
||||
)
|
||||
classes += ' rdtNew';
|
||||
|
||||
if (selected && prevMonth.isSame(selected, 'day'))
|
||||
classes += ' rdtActive';
|
||||
if (selected && prevMonth.isSame(selected, 'day')) classes += ' rdtActive';
|
||||
|
||||
if (prevMonth.isSame(moment(), 'day'))
|
||||
classes += ' rdtToday';
|
||||
if (prevMonth.isSame(moment(), 'day')) classes += ' rdtToday';
|
||||
|
||||
isDisabled = !isValid(currentDate, selected);
|
||||
if (isDisabled)
|
||||
classes += ' rdtDisabled';
|
||||
if (isDisabled) classes += ' rdtDisabled';
|
||||
|
||||
dayProps = {
|
||||
key: prevMonth.format('M_D'),
|
||||
'data-value': prevMonth.date(),
|
||||
className: classes
|
||||
className: classes,
|
||||
};
|
||||
|
||||
if (!isDisabled)
|
||||
dayProps.onClick = this.handleDayChange;
|
||||
if (!isDisabled) dayProps.onClick = this.handleDayChange;
|
||||
|
||||
days.push(renderer(dayProps, currentDate, selected));
|
||||
|
||||
if (days.length === 7) {
|
||||
weeks.push(
|
||||
<tr key={prevMonth.format('M_D')}>{days}</tr>
|
||||
);
|
||||
weeks.push(<tr key={prevMonth.format('M_D')}>{days}</tr>);
|
||||
days = [];
|
||||
}
|
||||
|
||||
|
@ -455,21 +461,27 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
<tr>
|
||||
<th colSpan={7}>
|
||||
<div className="rdtHeader">
|
||||
<a className="rdtBtn" onClick={this.props.subtractTime(1, 'months')}><i className="rdtBtnPrev" /></a>
|
||||
<a className="rdtBtn" onClick={this.props.subtractTime(1, 'months')}>
|
||||
<i className="rdtBtnPrev" />
|
||||
</a>
|
||||
<div className="rdtSelect">{this.renderYearsSelect()}</div>
|
||||
<div className="rdtSelect">{this.renderMonthsSelect()}</div>
|
||||
<a className="rdtBtn" onClick={this.props.addTime(1, 'months')}><i className="rdtBtnNext" /></a>
|
||||
<a className="rdtBtn" onClick={this.props.addTime(1, 'months')}>
|
||||
<i className="rdtBtnNext" />
|
||||
</a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
{this.getDaysOfWeek(locale).map((day, index) => (
|
||||
<th key={day + index} className="dow">{day}</th>
|
||||
<th key={day + index} className="dow">
|
||||
{day}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>,
|
||||
|
||||
<tbody key="tb">{this.renderDays()}</tbody>
|
||||
<tbody key="tb">{this.renderDays()}</tbody>,
|
||||
];
|
||||
|
||||
footer && tableChildren.push(footer);
|
||||
|
@ -483,7 +495,7 @@ class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
|||
}
|
||||
|
||||
export interface DateProps {
|
||||
viewMode: "years" | "months" | "days" | "time";
|
||||
viewMode: 'years' | 'months' | 'days' | 'time';
|
||||
className?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
|
@ -499,26 +511,26 @@ export interface DateProps {
|
|||
minTime?: moment.Moment;
|
||||
maxTime?: moment.Moment;
|
||||
clearable?: boolean;
|
||||
defaultValue?: any;
|
||||
onChange: (value:any) => void;
|
||||
defaultValue?: any;
|
||||
onChange: (value: any) => void;
|
||||
value: any;
|
||||
[propName:string]: any;
|
||||
};
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export interface DatePickerState {
|
||||
isOpened: boolean;
|
||||
isFocused: boolean;
|
||||
value: moment.Moment | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
static defaultProps:Pick<DateProps, 'viewMode'> = {
|
||||
viewMode: 'days'
|
||||
static defaultProps: Pick<DateProps, 'viewMode'> = {
|
||||
viewMode: 'days',
|
||||
};
|
||||
state: DatePickerState = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
value: this.props.value ? moment(this.props.value, this.props.format) : undefined
|
||||
value: this.props.value ? moment(this.props.value, this.props.format) : undefined,
|
||||
};
|
||||
constructor(props: DateProps) {
|
||||
super(props);
|
||||
|
@ -539,14 +551,14 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
|
||||
dom: HTMLDivElement;
|
||||
|
||||
componentWillReceiveProps(nextProps:DateProps) {
|
||||
componentWillReceiveProps(nextProps: DateProps) {
|
||||
if (this.props.value !== nextProps.value) {
|
||||
this.setState({
|
||||
value: nextProps.value ? moment(nextProps.value, nextProps.format) : undefined
|
||||
value: nextProps.value ? moment(nextProps.value, nextProps.format) : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
focus() {
|
||||
if (!this.dom) {
|
||||
return;
|
||||
|
@ -557,17 +569,17 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
|
||||
handleFocus() {
|
||||
this.setState({
|
||||
isFocused: true
|
||||
isFocused: true,
|
||||
});
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.setState({
|
||||
isFocused: false
|
||||
isFocused: false,
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyPress(e:React.KeyboardEvent) {
|
||||
handleKeyPress(e: React.KeyboardEvent) {
|
||||
if (e.key === ' ') {
|
||||
this.handleClick();
|
||||
}
|
||||
|
@ -583,14 +595,18 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
}
|
||||
|
||||
open(fn?: () => void) {
|
||||
this.props.disabled || this.setState({
|
||||
isOpened: true
|
||||
}, fn);
|
||||
this.props.disabled ||
|
||||
this.setState(
|
||||
{
|
||||
isOpened: true,
|
||||
},
|
||||
fn
|
||||
);
|
||||
}
|
||||
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
isOpened: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -602,14 +618,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
}
|
||||
|
||||
handleChange(value: moment.Moment) {
|
||||
const {
|
||||
onChange,
|
||||
format,
|
||||
minTime,
|
||||
maxTime,
|
||||
dateFormat,
|
||||
timeFormat
|
||||
} = this.props;
|
||||
const {onChange, format, minTime, maxTime, dateFormat, timeFormat} = this.props;
|
||||
|
||||
if (!moment.isMoment(value)) {
|
||||
return;
|
||||
|
@ -629,10 +638,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
}
|
||||
|
||||
checkIsValidDate(currentDate: moment.Moment) {
|
||||
const {
|
||||
minDate,
|
||||
maxDate
|
||||
} = this.props;
|
||||
const {minDate, maxDate} = this.props;
|
||||
|
||||
if (minDate && currentDate.isBefore(minDate, 'day')) {
|
||||
return false;
|
||||
|
@ -651,9 +657,9 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
return this.dom;
|
||||
}
|
||||
|
||||
domRef = (ref:HTMLDivElement) => {
|
||||
domRef = (ref: HTMLDivElement) => {
|
||||
this.dom = ref;
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
|
@ -669,22 +675,26 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
viewMode,
|
||||
timeConstraints,
|
||||
popOverContainer,
|
||||
clearable
|
||||
clearable,
|
||||
} = this.props;
|
||||
|
||||
const isOpened = this.state.isOpened;
|
||||
let date: moment.Moment | undefined = this.state.value;
|
||||
|
||||
return (
|
||||
<div
|
||||
tabIndex={0}
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onFocus={this.handleFocus}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
className={cx(`${ns}DatePicker`, {
|
||||
'is-disabled': disabled,
|
||||
'is-focused': this.state.isFocused
|
||||
}, className)}
|
||||
className={cx(
|
||||
`${ns}DatePicker`,
|
||||
{
|
||||
'is-disabled': disabled,
|
||||
'is-focused': this.state.isFocused,
|
||||
},
|
||||
className
|
||||
)}
|
||||
ref={this.domRef}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
|
@ -695,10 +705,12 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
)}
|
||||
|
||||
{clearable && value ? (
|
||||
<a className={`${ns}DatePicker-clear`} onClick={this.clearValue}>{closeIcon}</a>
|
||||
<a className={`${ns}DatePicker-clear`} onClick={this.clearValue}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
<a className={`${ns}DatePicker-toggler`}></a>
|
||||
<a className={`${ns}DatePicker-toggler`} />
|
||||
|
||||
{isOpened ? (
|
||||
<Overlay
|
||||
|
@ -739,6 +751,4 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
|||
|
||||
export default themeable(DatePicker);
|
||||
|
||||
export {
|
||||
BaseDatePicker
|
||||
};
|
||||
export {BaseDatePicker};
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
import React = require("react");
|
||||
import moment = require("moment");
|
||||
import { findDOMNode } from "react-dom";
|
||||
/**
|
||||
* @file DateRangePicker
|
||||
* @description 自定义日期范围时间选择器组件
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import React = require('react');
|
||||
import moment = require('moment');
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import * as cx from 'classnames';
|
||||
import { closeIcon } from "./icons";
|
||||
import Overlay from "./Overlay";
|
||||
import { BaseDatePicker } from "./DatePicker";
|
||||
import PopOver from "./PopOver";
|
||||
import { ClassNamesFn, themeable } from "../theme";
|
||||
import {closeIcon} from './icons';
|
||||
import Overlay from './Overlay';
|
||||
import {BaseDatePicker} from './DatePicker';
|
||||
import PopOver from './PopOver';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface DateRangePickerProps {
|
||||
className?: string;
|
||||
|
@ -24,38 +30,38 @@ export interface DateRangePickerProps {
|
|||
joinValues: boolean;
|
||||
delimiter: string;
|
||||
value: any;
|
||||
onChange: (value:any) => void;
|
||||
onChange: (value: any) => void;
|
||||
data?: any;
|
||||
disabled?: boolean;
|
||||
[propName:string]: any;
|
||||
};
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export interface DateRangePickerState {
|
||||
isOpened: boolean;
|
||||
isFocused: boolean;
|
||||
startDate?: moment.Moment;
|
||||
endDate?: moment.Moment;
|
||||
};
|
||||
}
|
||||
|
||||
const availableRanges: { [propName: string]: any } = {
|
||||
'today': {
|
||||
const availableRanges: {[propName: string]: any} = {
|
||||
today: {
|
||||
label: '今天',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.startOf('day');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'yesterday': {
|
||||
yesterday: {
|
||||
label: '昨天',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.add(-1, 'days').startOf('day');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now.add(-1, 'days').endOf('day');
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'1dayago': {
|
||||
|
@ -65,7 +71,7 @@ const availableRanges: { [propName: string]: any } = {
|
|||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'7daysago': {
|
||||
|
@ -75,7 +81,7 @@ const availableRanges: { [propName: string]: any } = {
|
|||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'90daysago': {
|
||||
|
@ -85,57 +91,70 @@ const availableRanges: { [propName: string]: any } = {
|
|||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'prevweek': {
|
||||
prevweek: {
|
||||
label: '上周',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.add(-1, 'days').startOf('week').add(-1, 'weeks');
|
||||
return now
|
||||
.add(-1, 'days')
|
||||
.startOf('week')
|
||||
.add(-1, 'weeks');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now.add(-1, 'days').startOf('week').add(-1, 'day').endOf('day');
|
||||
}
|
||||
return now
|
||||
.add(-1, 'days')
|
||||
.startOf('week')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
},
|
||||
},
|
||||
|
||||
'thismonth': {
|
||||
thismonth: {
|
||||
label: '本月',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.startOf('month');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'prevmonth': {
|
||||
prevmonth: {
|
||||
label: '上个月',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.startOf('month').add(-1, 'month');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now.startOf('month').add(-1, 'day').endOf('day');
|
||||
}
|
||||
return now
|
||||
.startOf('month')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
},
|
||||
},
|
||||
|
||||
'prevquarter': {
|
||||
prevquarter: {
|
||||
label: '上个季节',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.startOf('quarter').add(-1, 'quarter');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now.startOf('quarter').add(-1, 'day').endOf('day');
|
||||
}
|
||||
return now
|
||||
.startOf('quarter')
|
||||
.add(-1, 'day')
|
||||
.endOf('day');
|
||||
},
|
||||
},
|
||||
|
||||
'thisquarter': {
|
||||
thisquarter: {
|
||||
label: '本季度',
|
||||
startDate: (now: moment.Moment) => {
|
||||
return now.startOf('quarter');
|
||||
},
|
||||
endDate: (now: moment.Moment) => {
|
||||
return now;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -149,14 +168,14 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
delimiter: ',',
|
||||
ranges: 'yesterday,7daysago,prevweek,thismonth,prevmonth,prevquarter',
|
||||
iconClassName: 'fa fa-calendar',
|
||||
resetValue: ''
|
||||
}
|
||||
resetValue: '',
|
||||
};
|
||||
|
||||
innerDom: any;
|
||||
popover: any;
|
||||
input?: HTMLInputElement;
|
||||
|
||||
static formatValue(newValue: any, format:string, joinValues: boolean, delimiter: string) {
|
||||
static formatValue(newValue: any, format: string, joinValues: boolean, delimiter: string) {
|
||||
newValue = [newValue.startDate.format(format), newValue.endDate.format(format)];
|
||||
|
||||
if (joinValues) {
|
||||
|
@ -166,12 +185,11 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
return newValue;
|
||||
}
|
||||
|
||||
static unFormatValue(value: any, format:string, joinValues: boolean, delimiter: string) {
|
||||
|
||||
static unFormatValue(value: any, format: string, joinValues: boolean, delimiter: string) {
|
||||
if (!value) {
|
||||
return {
|
||||
startDate: undefined,
|
||||
endDate: undefined
|
||||
endDate: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -181,9 +199,8 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
|
||||
return {
|
||||
startDate: value[0] ? moment(value[0], format) : undefined,
|
||||
endDate: value[1] ? moment(value[1], format) : undefined
|
||||
}
|
||||
|
||||
endDate: value[1] ? moment(value[1], format) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
dom: React.RefObject<HTMLDivElement>;
|
||||
|
@ -206,32 +223,22 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
this.handlePopOverClick = this.handlePopOverClick.bind(this);
|
||||
|
||||
const {
|
||||
format,
|
||||
joinValues,
|
||||
delimiter,
|
||||
value
|
||||
} = this.props;
|
||||
const {format, joinValues, delimiter, value} = this.props;
|
||||
|
||||
this.state = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
|
||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter),
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps:DateRangePickerProps) {
|
||||
componentWillReceiveProps(nextProps: DateRangePickerProps) {
|
||||
const props = this.props;
|
||||
const {
|
||||
value,
|
||||
format,
|
||||
joinValues,
|
||||
delimiter
|
||||
} = nextProps;
|
||||
const {value, format, joinValues, delimiter} = nextProps;
|
||||
|
||||
if (props.value !== value) {
|
||||
this.setState({
|
||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
|
||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -254,14 +261,14 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
|
||||
handleFocus() {
|
||||
this.setState({
|
||||
isFocused: true
|
||||
})
|
||||
isFocused: true,
|
||||
});
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.setState({
|
||||
isFocused: false
|
||||
})
|
||||
isFocused: false,
|
||||
});
|
||||
}
|
||||
|
||||
open() {
|
||||
|
@ -270,14 +277,17 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
}
|
||||
|
||||
this.setState({
|
||||
isOpened: true
|
||||
isOpened: true,
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
}, this.blur);
|
||||
this.setState(
|
||||
{
|
||||
isOpened: false,
|
||||
},
|
||||
this.blur
|
||||
);
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
|
@ -289,7 +299,7 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
e.preventDefault();
|
||||
}
|
||||
|
||||
handleKeyPress(e:React.KeyboardEvent) {
|
||||
handleKeyPress(e: React.KeyboardEvent) {
|
||||
if (e.key === ' ') {
|
||||
this.handleClick();
|
||||
}
|
||||
|
@ -302,56 +312,58 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
return;
|
||||
}
|
||||
|
||||
this.props.onChange(DateRangePicker.formatValue({
|
||||
startDate: this.state.startDate,
|
||||
endDate: this.state.endDate
|
||||
}, this.props.format, this.props.joinValues, this.props.delimiter));
|
||||
this.props.onChange(
|
||||
DateRangePicker.formatValue(
|
||||
{
|
||||
startDate: this.state.startDate,
|
||||
endDate: this.state.endDate,
|
||||
},
|
||||
this.props.format,
|
||||
this.props.joinValues,
|
||||
this.props.delimiter
|
||||
)
|
||||
);
|
||||
this.close();
|
||||
}
|
||||
|
||||
handleStartChange(newValue: any) {
|
||||
this.setState({
|
||||
startDate: newValue.clone()
|
||||
})
|
||||
startDate: newValue.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
handleEndChange(newValue: any) {
|
||||
newValue = !this.state.endDate && !this.props.timeFormat ? newValue.endOf('day') : newValue;
|
||||
this.setState({
|
||||
endDate: newValue.clone()
|
||||
endDate: newValue.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
selectRannge(range: { startDate: (now: moment.Moment) => moment.Moment, endDate: (now: moment.Moment) => moment.Moment }) {
|
||||
selectRannge(range: {
|
||||
startDate: (now: moment.Moment) => moment.Moment;
|
||||
endDate: (now: moment.Moment) => moment.Moment;
|
||||
}) {
|
||||
const now = moment();
|
||||
this.setState({
|
||||
startDate: range.startDate(now.clone()),
|
||||
endDate: range.endDate(now.clone())
|
||||
endDate: range.endDate(now.clone()),
|
||||
});
|
||||
}
|
||||
|
||||
clearValue(e: React.MouseEvent<any>) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const {
|
||||
resetValue,
|
||||
onChange
|
||||
} = this.props;
|
||||
|
||||
const {resetValue, onChange} = this.props;
|
||||
|
||||
onChange(resetValue);
|
||||
}
|
||||
|
||||
checkStartIsValidDate(currentDate: moment.Moment) {
|
||||
let {
|
||||
endDate
|
||||
} = this.state;
|
||||
let {endDate} = this.state;
|
||||
|
||||
let {
|
||||
minDate,
|
||||
maxDate,
|
||||
} = this.props;
|
||||
let {minDate, maxDate} = this.props;
|
||||
|
||||
maxDate = maxDate && endDate ? (maxDate.isBefore(endDate) ? maxDate : endDate) : (maxDate || endDate);
|
||||
maxDate = maxDate && endDate ? (maxDate.isBefore(endDate) ? maxDate : endDate) : maxDate || endDate;
|
||||
|
||||
if (minDate && currentDate.isBefore(minDate, 'day')) {
|
||||
return false;
|
||||
|
@ -363,16 +375,11 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
}
|
||||
|
||||
checkEndIsValidDate(currentDate: moment.Moment) {
|
||||
let {
|
||||
startDate
|
||||
} = this.state;
|
||||
let {startDate} = this.state;
|
||||
|
||||
let {
|
||||
minDate,
|
||||
maxDate,
|
||||
} = this.props;
|
||||
let {minDate, maxDate} = this.props;
|
||||
|
||||
minDate = minDate && startDate ? (minDate.isAfter(startDate) ? minDate : startDate) : (minDate || startDate);
|
||||
minDate = minDate && startDate ? (minDate.isAfter(startDate) ? minDate : startDate) : minDate || startDate;
|
||||
|
||||
if (minDate && currentDate.isBefore(minDate, 'day')) {
|
||||
return false;
|
||||
|
@ -398,15 +405,10 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
timeFormat,
|
||||
ranges,
|
||||
disabled,
|
||||
iconClassName
|
||||
iconClassName,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isOpened,
|
||||
isFocused,
|
||||
startDate,
|
||||
endDate
|
||||
} = this.state;
|
||||
const {isOpened, isFocused, startDate, endDate} = this.state;
|
||||
|
||||
const selectedDate = DateRangePicker.unFormatValue(value, format, joinValues, delimiter);
|
||||
const startViewValue = selectedDate.startDate ? selectedDate.startDate.format(inputFormat) : '';
|
||||
|
@ -415,31 +417,38 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
startViewValue && arr.push(startViewValue);
|
||||
endViewValue && arr.push(endViewValue);
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
tabIndex={0}
|
||||
<div
|
||||
tabIndex={0}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onFocus={this.handleFocus}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
className={cx(`${ns}DateRangePicker`, {
|
||||
'is-disabled': disabled,
|
||||
'is-focused': isFocused
|
||||
}, className)}
|
||||
className={cx(
|
||||
`${ns}DateRangePicker`,
|
||||
{
|
||||
'is-disabled': disabled,
|
||||
'is-focused': isFocused,
|
||||
},
|
||||
className
|
||||
)}
|
||||
ref={this.dom}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{arr.length ? (
|
||||
<span className={`${ns}DateRangePicker-value`} >{arr.join(' 至 ')}</span>
|
||||
<span className={`${ns}DateRangePicker-value`}>{arr.join(' 至 ')}</span>
|
||||
) : (
|
||||
<span className={`${ns}DateRangePicker-placeholder`}>{placeholder}</span>
|
||||
)}
|
||||
|
||||
{clearable && value ? (
|
||||
<a className={`${ns}DateRangePicker-clear`} onClick={this.clearValue}>{closeIcon}</a>
|
||||
<a className={`${ns}DateRangePicker-clear`} onClick={this.clearValue}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
<a className={`${ns}DateRangePicker-toggler`}><i className={iconClassName} /></a>
|
||||
<a className={`${ns}DateRangePicker-toggler`}>
|
||||
<i className={iconClassName} />
|
||||
</a>
|
||||
|
||||
{isOpened ? (
|
||||
<Overlay
|
||||
|
@ -460,13 +469,22 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
<div className={`${ns}DateRangePicker-wrap`}>
|
||||
{ranges ? (
|
||||
<ul className={`${ns}DateRangePicker-rangers`}>
|
||||
{
|
||||
(typeof ranges === 'string' ? ranges.split(',') : Array.isArray(ranges) ? ranges : [])
|
||||
.filter(key => !!availableRanges[key])
|
||||
.map(key => (
|
||||
<li className={`${ns}DateRangePicker-ranger`} onClick={() => this.selectRannge(availableRanges[key])} key={key}><a>{availableRanges[key].label}</a></li>
|
||||
))
|
||||
}
|
||||
{(typeof ranges === 'string'
|
||||
? ranges.split(',')
|
||||
: Array.isArray(ranges)
|
||||
? ranges
|
||||
: []
|
||||
)
|
||||
.filter(key => !!availableRanges[key])
|
||||
.map(key => (
|
||||
<li
|
||||
className={`${ns}DateRangePicker-ranger`}
|
||||
onClick={() => this.selectRannge(availableRanges[key])}
|
||||
key={key}
|
||||
>
|
||||
<a>{availableRanges[key].label}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
|
||||
|
@ -502,10 +520,17 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
/>
|
||||
|
||||
<div key="button" className={`${ns}DateRangePicker-actions`}>
|
||||
<a className={cx("rdtBtn rdtBtnConfirm", {
|
||||
"is-disabled": !this.state.startDate || !this.state.endDate
|
||||
})} onClick={this.confirm}>确认</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.close}>取消</a>
|
||||
<a
|
||||
className={cx('rdtBtn rdtBtnConfirm', {
|
||||
'is-disabled': !this.state.startDate || !this.state.endDate,
|
||||
})}
|
||||
onClick={this.confirm}
|
||||
>
|
||||
确认
|
||||
</a>
|
||||
<a className="rdtBtn rdtBtnCancel" onClick={this.close}>
|
||||
取消
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</PopOver>
|
||||
|
@ -516,4 +541,4 @@ export class DateRangePicker extends React.Component<DateRangePickerProps, DateR
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(DateRangePicker);
|
||||
export default themeable(DateRangePicker);
|
||||
|
|
|
@ -1,25 +1,19 @@
|
|||
/**
|
||||
* @file Drawer
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import Transition, {
|
||||
ENTERED,
|
||||
ENTERING,
|
||||
EXITING
|
||||
} from 'react-transition-group/Transition';
|
||||
import {
|
||||
Portal
|
||||
} from 'react-overlays';
|
||||
import {
|
||||
closeIcon
|
||||
} from './icons';
|
||||
import Transition, {ENTERED, ENTERING, EXITING} from 'react-transition-group/Transition';
|
||||
import {Portal} from 'react-overlays';
|
||||
import {closeIcon} from './icons';
|
||||
import * as cx from 'classnames';
|
||||
import {
|
||||
current,
|
||||
addModal,
|
||||
removeModal
|
||||
} from './ModalManager';
|
||||
import onClickOutside from "react-onclickoutside";
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import { noop } from '../utils/helper';
|
||||
import {current, addModal, removeModal} from './ModalManager';
|
||||
import onClickOutside from 'react-onclickoutside';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {noop} from '../utils/helper';
|
||||
|
||||
type DrawerPosition = 'top' | 'right' | 'bottom' | 'left';
|
||||
|
||||
|
@ -40,24 +34,25 @@ export interface DrawerProps {
|
|||
onEntered?: () => void;
|
||||
disableOnClickOutside: () => void;
|
||||
enableOnClickOutside: () => void;
|
||||
};
|
||||
export interface DrawerState {
|
||||
}
|
||||
export interface DrawerState {}
|
||||
const fadeStyles: {
|
||||
[propName: string]: string;
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in'
|
||||
[ENTERED]: 'in',
|
||||
};
|
||||
export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
||||
|
||||
static defaultProps:Pick<DrawerProps, "container" | "position" | "size" | "overlay" | "disableOnClickOutside" | "enableOnClickOutside"> = {
|
||||
static defaultProps: Pick<
|
||||
DrawerProps,
|
||||
'container' | 'position' | 'size' | 'overlay' | 'disableOnClickOutside' | 'enableOnClickOutside'
|
||||
> = {
|
||||
container: document.body,
|
||||
position: 'left',
|
||||
size: 'md',
|
||||
overlay: true,
|
||||
disableOnClickOutside: noop,
|
||||
enableOnClickOutside: noop
|
||||
enableOnClickOutside: noop,
|
||||
};
|
||||
|
||||
contentDom: any;
|
||||
|
@ -74,7 +69,7 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
}
|
||||
}
|
||||
|
||||
contentRef = (ref: any) => this.contentDom = ref;
|
||||
contentRef = (ref: any) => (this.contentDom = ref);
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered;
|
||||
document.body.classList.add(`is-modalOpened`);
|
||||
|
@ -84,7 +79,7 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
const onExited = this.props.onExited;
|
||||
onExited && onExited();
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') || (document.body.classList.remove(`is-modalOpened`));
|
||||
document.querySelector('.amis-dialog-widget') || document.body.classList.remove(`is-modalOpened`);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
|
@ -95,13 +90,10 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
} else {
|
||||
removeModal();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleClickOutside() {
|
||||
const {
|
||||
closeOnOutside,
|
||||
onHide
|
||||
} = this.props;
|
||||
const {closeOnOutside, onHide} = this.props;
|
||||
closeOnOutside && onHide && onHide();
|
||||
}
|
||||
|
||||
|
@ -116,13 +108,11 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
size,
|
||||
onHide,
|
||||
disabled,
|
||||
overlay
|
||||
overlay,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Portal
|
||||
container={container}
|
||||
>
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
|
@ -140,12 +130,20 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
}
|
||||
|
||||
return (
|
||||
<div ref={this.modalRef} role="dialog" className={cx(`amis-dialog-widget ${ns}Drawer`, {
|
||||
[`${ns}Drawer--${position}`]: position,
|
||||
[`${ns}Drawer--${size}`]: size,
|
||||
[`${ns}Drawer--noOverlay`]: !overlay,
|
||||
}, className)}>
|
||||
{overlay ? (<div className={cx(`${ns}Drawer-overlay`, fadeStyles[status])} />) : null}
|
||||
<div
|
||||
ref={this.modalRef}
|
||||
role="dialog"
|
||||
className={cx(
|
||||
`amis-dialog-widget ${ns}Drawer`,
|
||||
{
|
||||
[`${ns}Drawer--${position}`]: position,
|
||||
[`${ns}Drawer--${size}`]: size,
|
||||
[`${ns}Drawer--noOverlay`]: !overlay,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{overlay ? <div className={cx(`${ns}Drawer-overlay`, fadeStyles[status])} /> : null}
|
||||
<div ref={this.contentRef} className={cx(`${ns}Drawer-content`, fadeStyles[status])}>
|
||||
<a onClick={disabled ? undefined : onHide} className={`${ns}Drawer-close`}>
|
||||
{closeIcon}
|
||||
|
@ -153,7 +151,7 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
|
@ -161,4 +159,4 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(onClickOutside(Drawer));
|
||||
export default themeable(onClickOutside(Drawer));
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import {DropdownButton} from 'react-bootstrap';
|
||||
|
||||
export default DropdownButton;
|
||||
export default DropdownButton;
|
||||
|
|
|
@ -1,26 +1,32 @@
|
|||
/**
|
||||
* @file Editor
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
function noJsExt(raw:string) {
|
||||
function noJsExt(raw: string) {
|
||||
return raw.replace(/\.js$/, '');
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
url: 'vs/loader.js',
|
||||
'vs/nls' : {
|
||||
'vs/nls': {
|
||||
availableLanguages: {
|
||||
'*': 'zh-cn'
|
||||
}
|
||||
'*': 'zh-cn',
|
||||
},
|
||||
},
|
||||
paths: {}
|
||||
paths: {},
|
||||
};
|
||||
|
||||
try {
|
||||
// fis 编译的话,能正确赋值上,如果不是,那请通过外部参数传递。
|
||||
defaultConfig.url = __uri('monaco-editor/min/vs/loader.js');
|
||||
defaultConfig.paths = {
|
||||
'vs': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')).replace(/\/vs\/.*$/, ''),
|
||||
vs: noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')).replace(/\/vs\/.*$/, ''),
|
||||
'vs/base/worker/workerMain': noJsExt(__uri('monaco-editor/min/vs/base/worker/workerMain.js')),
|
||||
|
||||
'vs/basic-languages/apex/apex': noJsExt(__uri('monaco-editor/min/vs/basic-languages/apex/apex')),
|
||||
|
@ -31,39 +37,59 @@ try {
|
|||
'vs/basic-languages/cpp/cpp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/cpp/cpp')),
|
||||
'vs/basic-languages/csharp/csharp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/csharp/csharp')),
|
||||
'vs/basic-languages/css/css': noJsExt(__uri('monaco-editor/min/vs/basic-languages/css/css')),
|
||||
'vs/basic-languages/dockerfile/dockerfile': noJsExt(__uri('monaco-editor/min/vs/basic-languages/dockerfile/dockerfile')),
|
||||
'vs/basic-languages/dockerfile/dockerfile': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/dockerfile/dockerfile')
|
||||
),
|
||||
'vs/basic-languages/fsharp/fsharp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/fsharp/fsharp')),
|
||||
'vs/basic-languages/go/go': noJsExt(__uri('monaco-editor/min/vs/basic-languages/go/go')),
|
||||
'vs/basic-languages/handlebars/handlebars': noJsExt(__uri('monaco-editor/min/vs/basic-languages/handlebars/handlebars')),
|
||||
'vs/basic-languages/handlebars/handlebars': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/handlebars/handlebars')
|
||||
),
|
||||
'vs/basic-languages/html/html': noJsExt(__uri('monaco-editor/min/vs/basic-languages/html/html')),
|
||||
'vs/basic-languages/ini/ini': noJsExt(__uri('monaco-editor/min/vs/basic-languages/ini/ini')),
|
||||
'vs/basic-languages/java/java': noJsExt(__uri('monaco-editor/min/vs/basic-languages/java/java')),
|
||||
'vs/basic-languages/javascript/javascript': noJsExt(__uri('monaco-editor/min/vs/basic-languages/javascript/javascript')),
|
||||
'vs/basic-languages/javascript/javascript': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/javascript/javascript')
|
||||
),
|
||||
'vs/basic-languages/less/less': noJsExt(__uri('monaco-editor/min/vs/basic-languages/less/less')),
|
||||
'vs/basic-languages/lua/lua': noJsExt(__uri('monaco-editor/min/vs/basic-languages/lua/lua')),
|
||||
'vs/basic-languages/markdown/markdown': noJsExt(__uri('monaco-editor/min/vs/basic-languages/markdown/markdown')),
|
||||
'vs/basic-languages/markdown/markdown': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/markdown/markdown')
|
||||
),
|
||||
'vs/basic-languages/msdax/msdax': noJsExt(__uri('monaco-editor/min/vs/basic-languages/msdax/msdax')),
|
||||
'vs/basic-languages/objective-c/objective-c': noJsExt(__uri('monaco-editor/min/vs/basic-languages/objective-c/objective-c')),
|
||||
'vs/basic-languages/objective-c/objective-c': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/objective-c/objective-c')
|
||||
),
|
||||
'vs/basic-languages/php/php': noJsExt(__uri('monaco-editor/min/vs/basic-languages/php/php')),
|
||||
'vs/basic-languages/postiats/postiats': noJsExt(__uri('monaco-editor/min/vs/basic-languages/postiats/postiats')),
|
||||
'vs/basic-languages/powershell/powershell': noJsExt(__uri('monaco-editor/min/vs/basic-languages/powershell/powershell')),
|
||||
'vs/basic-languages/postiats/postiats': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/postiats/postiats')
|
||||
),
|
||||
'vs/basic-languages/powershell/powershell': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/powershell/powershell')
|
||||
),
|
||||
'vs/basic-languages/pug/pug': noJsExt(__uri('monaco-editor/min/vs/basic-languages/pug/pug')),
|
||||
'vs/basic-languages/python/python': noJsExt(__uri('monaco-editor/min/vs/basic-languages/python/python')),
|
||||
'vs/basic-languages/r/r': noJsExt(__uri('monaco-editor/min/vs/basic-languages/r/r')),
|
||||
'vs/basic-languages/razor/razor': noJsExt(__uri('monaco-editor/min/vs/basic-languages/razor/razor')),
|
||||
'vs/basic-languages/redis/redis': noJsExt(__uri('monaco-editor/min/vs/basic-languages/redis/redis')),
|
||||
'vs/basic-languages/redshift/redshift': noJsExt(__uri('monaco-editor/min/vs/basic-languages/redshift/redshift')),
|
||||
'vs/basic-languages/redshift/redshift': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/redshift/redshift')
|
||||
),
|
||||
'vs/basic-languages/ruby/ruby': noJsExt(__uri('monaco-editor/min/vs/basic-languages/ruby/ruby')),
|
||||
'vs/basic-languages/rust/rust': noJsExt(__uri('monaco-editor/min/vs/basic-languages/rust/rust')),
|
||||
'vs/basic-languages/sb/sb': noJsExt(__uri('monaco-editor/min/vs/basic-languages/sb/sb')),
|
||||
'vs/basic-languages/scheme/scheme': noJsExt(__uri('monaco-editor/min/vs/basic-languages/scheme/scheme')),
|
||||
'vs/basic-languages/scss/scss': noJsExt(__uri('monaco-editor/min/vs/basic-languages/scss/scss')),
|
||||
'vs/basic-languages/shell/shell': noJsExt(__uri('monaco-editor/min/vs/basic-languages/shell/shell')),
|
||||
'vs/basic-languages/solidity/solidity': noJsExt(__uri('monaco-editor/min/vs/basic-languages/solidity/solidity')),
|
||||
'vs/basic-languages/solidity/solidity': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/solidity/solidity')
|
||||
),
|
||||
'vs/basic-languages/sql/sql': noJsExt(__uri('monaco-editor/min/vs/basic-languages/sql/sql')),
|
||||
'vs/basic-languages/st/st': noJsExt(__uri('monaco-editor/min/vs/basic-languages/st/st')),
|
||||
'vs/basic-languages/swift/swift': noJsExt(__uri('monaco-editor/min/vs/basic-languages/swift/swift')),
|
||||
'vs/basic-languages/typescript/typescript': noJsExt(__uri('monaco-editor/min/vs/basic-languages/typescript/typescript')),
|
||||
'vs/basic-languages/typescript/typescript': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/typescript/typescript')
|
||||
),
|
||||
'vs/basic-languages/vb/vb': noJsExt(__uri('monaco-editor/min/vs/basic-languages/vb/vb')),
|
||||
'vs/basic-languages/xml/xml': noJsExt(__uri('monaco-editor/min/vs/basic-languages/xml/xml')),
|
||||
'vs/basic-languages/yaml/yaml': noJsExt(__uri('monaco-editor/min/vs/basic-languages/yaml/yaml')),
|
||||
|
@ -88,22 +114,22 @@ try {
|
|||
'vs/language/html/htmlWorker': noJsExt(__uri('monaco-editor/min/vs/language/html/htmlWorker.js')),
|
||||
|
||||
'vs/language/css/cssMode': noJsExt(__uri('monaco-editor/min/vs/language/css/cssMode.js')),
|
||||
'vs/language/css/cssWorker': noJsExt(__uri('monaco-editor/min/vs/language/css/cssWorker.js'))
|
||||
'vs/language/css/cssWorker': noJsExt(__uri('monaco-editor/min/vs/language/css/cssWorker.js')),
|
||||
};
|
||||
|
||||
// cdn 支持
|
||||
/^(https?:)?\/\//.test(defaultConfig.paths.vs) && ((window as any).MonacoEnvironment = {
|
||||
getWorkerUrl: function() {
|
||||
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
|
||||
/^(https?:)?\/\//.test(defaultConfig.paths.vs) &&
|
||||
((window as any).MonacoEnvironment = {
|
||||
getWorkerUrl: function() {
|
||||
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
|
||||
self.MonacoEnvironment = {
|
||||
baseUrl: '${defaultConfig.paths.vs}',
|
||||
paths: ${JSON.stringify(defaultConfig.paths)}
|
||||
};
|
||||
importScripts('${__uri('monaco-editor/min/vs/base/worker/workerMain.js')}');`
|
||||
)}`;
|
||||
}
|
||||
});
|
||||
} catch (e) {};
|
||||
importScripts('${__uri('monaco-editor/min/vs/base/worker/workerMain.js')}');`)}`;
|
||||
},
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
export function monacoFactory(containerElement, monaco, options) {
|
||||
return monaco.editor.create(containerElement, {
|
||||
|
@ -114,22 +140,22 @@ export function monacoFactory(containerElement, monaco, options) {
|
|||
scrollBeyondLastLine: false,
|
||||
folding: true,
|
||||
minimap: {
|
||||
enabled: false
|
||||
enabled: false,
|
||||
},
|
||||
...options
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export interface EditorProps {
|
||||
value?:string;
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
onChange?: (value:string, event:any) => void;
|
||||
onChange?: (value: string, event: any) => void;
|
||||
language?: string;
|
||||
editorTheme?: string;
|
||||
options: {
|
||||
[propName:string]: any;
|
||||
[propName: string]: any;
|
||||
};
|
||||
classPrefix: string;
|
||||
className?: string;
|
||||
|
@ -138,13 +164,13 @@ export interface EditorProps {
|
|||
style?: any;
|
||||
onFocus?: () => void;
|
||||
onBlur?: () => void;
|
||||
editorDidMount?: (editor:any, monaco:any) => void;
|
||||
editorWillMount?: (monaco:any) => void;
|
||||
editorFactory?: (conatainer:HTMLElement, monaco:any, options:any) => any;
|
||||
editorDidMount?: (editor: any, monaco: any) => void;
|
||||
editorWillMount?: (monaco: any) => void;
|
||||
editorFactory?: (conatainer: HTMLElement, monaco: any, options: any) => any;
|
||||
requireConfig: {
|
||||
url: string;
|
||||
paths?: any;
|
||||
[propName:string]: any;
|
||||
[propName: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -155,22 +181,22 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
editorTheme: 'vs',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
options: {}
|
||||
options: {},
|
||||
};
|
||||
|
||||
editor:any;
|
||||
container:any;
|
||||
currentValue:any;
|
||||
editor: any;
|
||||
container: any;
|
||||
currentValue: any;
|
||||
preventTriggerChangeEvent: boolean;
|
||||
disposes:Array<{dispose:() => void}> = [];
|
||||
constructor(props:EditorProps) {
|
||||
disposes: Array<{dispose: () => void}> = [];
|
||||
constructor(props: EditorProps) {
|
||||
super(props);
|
||||
|
||||
this.wrapperRef = this.wrapperRef.bind(this);
|
||||
this.currentValue = props.value;
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps:EditorProps) {
|
||||
componentWillReceiveProps(nextProps: EditorProps) {
|
||||
if (this.props.options.readOnly !== nextProps.options.readOnly && this.editor) {
|
||||
this.editor.updateOptions && this.editor.updateOptions(nextProps.options);
|
||||
}
|
||||
|
@ -183,9 +209,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(JSON.parse(value), null, 4);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
this.preventTriggerChangeEvent = true;
|
||||
|
@ -199,7 +223,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
this.disposes = [];
|
||||
}
|
||||
|
||||
wrapperRef(ref:any) {
|
||||
wrapperRef(ref: any) {
|
||||
this.container = ref;
|
||||
if (ref) {
|
||||
this.loadMonaco();
|
||||
|
@ -218,15 +242,15 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
loadMonaco() {
|
||||
const { requireConfig } = this.props;
|
||||
const {requireConfig} = this.props;
|
||||
const loaderUrl = requireConfig.url || 'vs/loader.js';
|
||||
const context = (window as any).monacaAmd || ((window as any).monacaAmd = {
|
||||
document: window.document
|
||||
});
|
||||
|
||||
const context =
|
||||
(window as any).monacaAmd ||
|
||||
((window as any).monacaAmd = {
|
||||
document: window.document,
|
||||
});
|
||||
|
||||
const onGotAmdLoader = () => {
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
// Do not use webpack
|
||||
|
@ -261,7 +285,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || [];
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__.push({
|
||||
context: this,
|
||||
fn: onGotAmdLoader
|
||||
fn: onGotAmdLoader,
|
||||
});
|
||||
} else {
|
||||
if (typeof context.require === 'undefined') {
|
||||
|
@ -279,7 +303,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
|
||||
initMonaco() {
|
||||
let value = this.props.value !== null ? this.props.value : this.props.defaultValue;
|
||||
const { language, editorTheme, options, editorFactory } = this.props;
|
||||
const {language, editorTheme, options, editorFactory} = this.props;
|
||||
const containerElement = this.container;
|
||||
if (!containerElement) {
|
||||
return;
|
||||
|
@ -292,7 +316,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
|
||||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(typeof value === "string" ? JSON.parse(value) : value, null, 4);
|
||||
value = JSON.stringify(typeof value === 'string' ? JSON.parse(value) : value, null, 4);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
@ -305,7 +329,7 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
value,
|
||||
language,
|
||||
editorTheme,
|
||||
theme: editorTheme
|
||||
theme: editorTheme,
|
||||
});
|
||||
|
||||
// After initializing monaco editor
|
||||
|
@ -313,46 +337,38 @@ export class Editor extends React.Component<EditorProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
editorWillMount(monaco:any) {
|
||||
const { editorWillMount } = this.props;
|
||||
editorWillMount(monaco: any) {
|
||||
const {editorWillMount} = this.props;
|
||||
editorWillMount && editorWillMount(monaco);
|
||||
}
|
||||
editorDidMount(editor:any, monaco:any) {
|
||||
const { editorDidMount, onChange, onFocus, onBlur } = this.props;
|
||||
editorDidMount(editor: any, monaco: any) {
|
||||
const {editorDidMount, onChange, onFocus, onBlur} = this.props;
|
||||
editorDidMount && editorDidMount(editor, monaco);
|
||||
editor.onDidChangeModelContent && this.disposes.push(editor.onDidChangeModelContent((event:any) => {
|
||||
const value = editor.getValue();
|
||||
// Always refer to the latest value
|
||||
this.currentValue = value;
|
||||
editor.onDidChangeModelContent &&
|
||||
this.disposes.push(
|
||||
editor.onDidChangeModelContent((event: any) => {
|
||||
const value = editor.getValue();
|
||||
// Always refer to the latest value
|
||||
this.currentValue = value;
|
||||
|
||||
// Only invoking when user input changed
|
||||
if (!this.preventTriggerChangeEvent && onChange) {
|
||||
onChange(value, event);
|
||||
}
|
||||
}));
|
||||
// Only invoking when user input changed
|
||||
if (!this.preventTriggerChangeEvent && onChange) {
|
||||
onChange(value, event);
|
||||
}
|
||||
})
|
||||
);
|
||||
onFocus && editor.onDidFocusEditorWidget && this.disposes.push(editor.onDidFocusEditorWidget(onFocus));
|
||||
onBlur && editor.onDidBlurEditorWidget && this.disposes.push(editor.onDidBlurEditorWidget(onBlur));
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
classPrefix: ns,
|
||||
width,
|
||||
height
|
||||
} = this.props;
|
||||
const {className, classPrefix: ns, width, height} = this.props;
|
||||
let style = this.props.style || {};
|
||||
style.width = width;
|
||||
style.height = height;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`${ns}MonacoEditor`, className)}
|
||||
style={style}
|
||||
ref={this.wrapperRef}
|
||||
/>
|
||||
);
|
||||
return <div className={cx(`${ns}MonacoEditor`, className)} style={style} ref={this.wrapperRef} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Editor);
|
||||
export default themeable(Editor);
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
/**
|
||||
* @file Html
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface HtmlProps {
|
||||
className?: string;
|
||||
|
@ -14,24 +20,23 @@ export interface HtmlProps {
|
|||
|
||||
export class Html extends React.Component<HtmlProps> {
|
||||
static defaultProps = {
|
||||
inline: true
|
||||
inline: true,
|
||||
};
|
||||
|
||||
dom:any;
|
||||
dom: any;
|
||||
|
||||
constructor(props:HtmlProps) {
|
||||
constructor(props: HtmlProps) {
|
||||
super(props);
|
||||
this.htmlRef = this.htmlRef.bind(this);
|
||||
}
|
||||
|
||||
|
||||
componentDidUpdate(prevProps:HtmlProps) {
|
||||
componentDidUpdate(prevProps: HtmlProps) {
|
||||
if (this.props.html !== prevProps.html) {
|
||||
this._render();
|
||||
}
|
||||
}
|
||||
|
||||
htmlRef(dom:any) {
|
||||
htmlRef(dom: any) {
|
||||
this.dom = dom;
|
||||
|
||||
if (!dom) {
|
||||
|
@ -42,9 +47,7 @@ export class Html extends React.Component<HtmlProps> {
|
|||
}
|
||||
|
||||
_render() {
|
||||
const {
|
||||
html,
|
||||
} = this.props;
|
||||
const {html} = this.props;
|
||||
|
||||
if (html) {
|
||||
this.dom.innerHTML = html;
|
||||
|
@ -52,19 +55,12 @@ export class Html extends React.Component<HtmlProps> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
wrapperComponent,
|
||||
inline,
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
const {className, wrapperComponent, inline, classPrefix: ns} = this.props;
|
||||
|
||||
const Component = wrapperComponent || (inline ? 'span' : 'div');
|
||||
|
||||
return (
|
||||
<Component ref={this.htmlRef} className={cx(`${ns}Html`, className)} />
|
||||
);
|
||||
return <Component ref={this.htmlRef} className={cx(`${ns}Html`, className)} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Html);
|
||||
export default themeable(Html);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* @file 页面布局,支持左边栏、顶部、内容区域布局。
|
||||
*
|
||||
* 参数说明:
|
||||
* @file Layout
|
||||
* @description 页面布局,支持左边栏、顶部、内容区域布局。
|
||||
* @author fex
|
||||
*
|
||||
* @param 参数说明:
|
||||
* * children 会渲染在内容区。
|
||||
* * header 头部区域
|
||||
* * aside 边栏
|
||||
|
@ -13,12 +14,11 @@
|
|||
* * asideFixed 边栏是否为固定模式,如果是会用 position:fixed 来定位.
|
||||
* * className 附件的样式名
|
||||
* * contentClassName 内容区域附加样式名称
|
||||
*
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface LayoutProps {
|
||||
id: string;
|
||||
|
@ -39,14 +39,13 @@ interface LayoutProps {
|
|||
}
|
||||
|
||||
export class Layout extends React.Component<LayoutProps, any> {
|
||||
|
||||
static defaultProps = {
|
||||
// asideWide: false,
|
||||
asideFixed: true,
|
||||
asideClassName: '',
|
||||
headerFixed: true,
|
||||
offScreen: false,
|
||||
footer: false
|
||||
footer: false,
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -65,16 +64,10 @@ export class Layout extends React.Component<LayoutProps, any> {
|
|||
offScreen,
|
||||
size,
|
||||
classPrefix,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
} = this.props;
|
||||
|
||||
let body = (
|
||||
<div
|
||||
className={cx(`Layout-body`, contentClassName)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
let body = <div className={cx(`Layout-body`, contentClassName)}>{children}</div>;
|
||||
|
||||
if (aside) {
|
||||
body = (
|
||||
|
@ -94,12 +87,10 @@ export class Layout extends React.Component<LayoutProps, any> {
|
|||
'Layout--folded': folded,
|
||||
'Layout--offScreen': offScreen,
|
||||
[`Layout--${size}`]: size,
|
||||
'Layout--noFooter': !footer
|
||||
'Layout--noFooter': !footer,
|
||||
})}
|
||||
>
|
||||
{header ? (
|
||||
<div className={cx('Layout-header')}>{header}</div>
|
||||
) : null}
|
||||
{header ? <div className={cx('Layout-header')}>{header}</div> : null}
|
||||
{aside ? (
|
||||
<div className={cx(`Layout-aside`, asideClassName)}>
|
||||
<div className={cx('Layout-asideWrap')}>
|
||||
|
@ -111,10 +102,7 @@ export class Layout extends React.Component<LayoutProps, any> {
|
|||
) : null}
|
||||
{body}
|
||||
{footer ? (
|
||||
<footer
|
||||
className={cx('Layout-footer')}
|
||||
role="footer"
|
||||
>
|
||||
<footer className={cx('Layout-footer')} role="footer">
|
||||
{footer}
|
||||
</footer>
|
||||
) : null}
|
||||
|
@ -123,4 +111,4 @@ export class Layout extends React.Component<LayoutProps, any> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(Layout);
|
||||
export default themeable(Layout);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
* @file LazyComponent
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import VisibilitySensor = require('react-visibility-sensor');
|
||||
|
||||
|
@ -8,7 +14,7 @@ export interface LazyComponentProps {
|
|||
unMountOnHidden?: boolean;
|
||||
childProps?: object;
|
||||
visiblilityProps?: object;
|
||||
[propName:string]: any;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export interface LazyComponentState {
|
||||
|
@ -20,57 +26,47 @@ export default class LazyComponent extends React.Component<LazyComponentProps, L
|
|||
static defaultProps = {
|
||||
placeholder: '加载中...',
|
||||
unMountOnHidden: false,
|
||||
partialVisibility: true
|
||||
partialVisibility: true,
|
||||
};
|
||||
|
||||
constructor(props:LazyComponentProps) {
|
||||
constructor(props: LazyComponentProps) {
|
||||
super(props);
|
||||
|
||||
this.handleVisibleChange = this.handleVisibleChange.bind(this);
|
||||
|
||||
this.state = {
|
||||
visible: false,
|
||||
component: props.component as React.ReactType
|
||||
component: props.component as React.ReactType,
|
||||
};
|
||||
}
|
||||
|
||||
handleVisibleChange(visible:boolean) {
|
||||
handleVisibleChange(visible: boolean) {
|
||||
this.setState({
|
||||
visible: visible
|
||||
visible: visible,
|
||||
});
|
||||
|
||||
if (!visible || this.state.component || !this.props.getComponent) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.getComponent()
|
||||
.then(component => this.setState({
|
||||
component: component
|
||||
}))
|
||||
.catch(reason => this.setState({
|
||||
component: () => (
|
||||
<div className="alert alert-danger">
|
||||
{String(reason)}
|
||||
</div>
|
||||
)
|
||||
}))
|
||||
|
||||
this.props
|
||||
.getComponent()
|
||||
.then(component =>
|
||||
this.setState({
|
||||
component: component,
|
||||
})
|
||||
)
|
||||
.catch(reason =>
|
||||
this.setState({
|
||||
component: () => <div className="alert alert-danger">{String(reason)}</div>,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
placeholder,
|
||||
unMountOnHidden,
|
||||
childProps,
|
||||
visiblilityProps,
|
||||
partialVisibility,
|
||||
...rest
|
||||
} = this.props;
|
||||
const {placeholder, unMountOnHidden, childProps, visiblilityProps, partialVisibility, ...rest} = this.props;
|
||||
|
||||
const {
|
||||
visible,
|
||||
component: Component
|
||||
} = this.state;
|
||||
const {visible, component: Component} = this.state;
|
||||
|
||||
// 需要监听从可见到不可见。
|
||||
if (unMountOnHidden) {
|
||||
|
@ -81,12 +77,7 @@ export default class LazyComponent extends React.Component<LazyComponentProps, L
|
|||
onChange={this.handleVisibleChange}
|
||||
>
|
||||
<div className="visibility-sensor">
|
||||
{Component && visible ? (
|
||||
<Component
|
||||
{...rest}
|
||||
{...childProps}
|
||||
/>
|
||||
) : placeholder}
|
||||
{Component && visible ? <Component {...rest} {...childProps} /> : placeholder}
|
||||
</div>
|
||||
</VisibilitySensor>
|
||||
);
|
||||
|
@ -94,7 +85,7 @@ export default class LazyComponent extends React.Component<LazyComponentProps, L
|
|||
|
||||
if (!visible) {
|
||||
return (
|
||||
<VisibilitySensor
|
||||
<VisibilitySensor
|
||||
{...visiblilityProps}
|
||||
partialVisibility={partialVisibility}
|
||||
onChange={this.handleVisibleChange}
|
||||
|
@ -102,15 +93,11 @@ export default class LazyComponent extends React.Component<LazyComponentProps, L
|
|||
<div className="visibility-sensor">{placeholder}</div>
|
||||
</VisibilitySensor>
|
||||
);
|
||||
} else if (Component) {
|
||||
} else if (Component) {
|
||||
// 只监听不可见到可见,一旦可见了,就销毁检查。
|
||||
return (
|
||||
<Component {...rest} {...childProps} />
|
||||
);
|
||||
return <Component {...rest} {...childProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>{placeholder}</div>
|
||||
);
|
||||
return <div>{placeholder}</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
/**
|
||||
* @file Modal
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import Transition, {
|
||||
ENTERED,
|
||||
ENTERING
|
||||
} from 'react-transition-group/Transition';
|
||||
import {
|
||||
Portal
|
||||
} from 'react-overlays';
|
||||
import Transition, {ENTERED, ENTERING} from 'react-transition-group/Transition';
|
||||
import {Portal} from 'react-overlays';
|
||||
import * as cx from 'classnames';
|
||||
import {
|
||||
current,
|
||||
addModal,
|
||||
removeModal
|
||||
} from './ModalManager';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {current, addModal, removeModal} from './ModalManager';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface ModalProps {
|
||||
className?: string;
|
||||
|
@ -27,21 +24,19 @@ export interface ModalProps {
|
|||
classnames: ClassNamesFn;
|
||||
onExited?: () => void;
|
||||
onEntered?: () => void;
|
||||
};
|
||||
export interface ModalState {
|
||||
}
|
||||
export interface ModalState {}
|
||||
const fadeStyles: {
|
||||
[propName: string]: string;
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in'
|
||||
[ENTERED]: 'in',
|
||||
};
|
||||
export class Modal extends React.Component<ModalProps, ModalState> {
|
||||
|
||||
static defaultProps = {
|
||||
container: document.body,
|
||||
size: '',
|
||||
overlay: true
|
||||
overlay: true,
|
||||
};
|
||||
|
||||
contentDom: any;
|
||||
|
@ -58,7 +53,7 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
}
|
||||
}
|
||||
|
||||
contentRef = (ref: any) => this.contentDom = ref;
|
||||
contentRef = (ref: any) => (this.contentDom = ref);
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered;
|
||||
document.body.classList.add(`is-modalOpened`);
|
||||
|
@ -68,37 +63,25 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
const onExited = this.props.onExited;
|
||||
onExited && onExited();
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') || (document.body.classList.remove(`is-modalOpened`));
|
||||
document.querySelector('.amis-dialog-widget') || document.body.classList.remove(`is-modalOpened`);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
modalRef = (ref: any) => {
|
||||
const {
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
const {classPrefix: ns} = this.props;
|
||||
if (ref) {
|
||||
addModal(this);
|
||||
(ref as HTMLElement).classList.add(`${ns}Modal--${current()}th`);
|
||||
} else {
|
||||
removeModal();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
container,
|
||||
show,
|
||||
size,
|
||||
overlay,
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
const {className, children, container, show, size, overlay, classPrefix: ns} = this.props;
|
||||
|
||||
return (
|
||||
<Portal
|
||||
container={container}
|
||||
>
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
|
@ -116,15 +99,23 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
}
|
||||
|
||||
return (
|
||||
<div ref={this.modalRef} role="dialog" className={cx(`amis-dialog-widget ${ns}Modal`, {
|
||||
[`${ns}Modal--${size}`]: size
|
||||
}, className)}>
|
||||
{overlay ? (<div className={cx(`${ns}Modal-overlay`, fadeStyles[status])} />) : null}
|
||||
<div
|
||||
ref={this.modalRef}
|
||||
role="dialog"
|
||||
className={cx(
|
||||
`amis-dialog-widget ${ns}Modal`,
|
||||
{
|
||||
[`${ns}Modal--${size}`]: size,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
{overlay ? <div className={cx(`${ns}Modal-overlay`, fadeStyles[status])} /> : null}
|
||||
<div ref={this.contentRef} className={cx(`${ns}Modal-content`, fadeStyles[status])}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
|
@ -132,4 +123,4 @@ export class Modal extends React.Component<ModalProps, ModalState> {
|
|||
}
|
||||
}
|
||||
|
||||
export default themeable(Modal);
|
||||
export default themeable(Modal);
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import * as keycode from "keycode";
|
||||
/**
|
||||
* @file ModalManager
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
interface ModalComponent extends React.Component<{
|
||||
onHide: () => void;
|
||||
disabled?: boolean;
|
||||
closeOnEsc?: boolean;
|
||||
}> {}
|
||||
import * as keycode from 'keycode';
|
||||
|
||||
interface ModalComponent
|
||||
extends React.Component<{
|
||||
onHide: () => void;
|
||||
disabled?: boolean;
|
||||
closeOnEsc?: boolean;
|
||||
}> {}
|
||||
|
||||
let modals: Array<ModalComponent> = [];
|
||||
|
||||
|
@ -12,11 +19,11 @@ export function current() {
|
|||
return modals.length;
|
||||
}
|
||||
|
||||
export function currentModal():ModalComponent | void {
|
||||
export function currentModal(): ModalComponent | void {
|
||||
return modals[modals.length - 1];
|
||||
}
|
||||
|
||||
export function addModal(modal:ModalComponent) {
|
||||
export function addModal(modal: ModalComponent) {
|
||||
modals.push(modal);
|
||||
}
|
||||
|
||||
|
@ -26,7 +33,7 @@ export function removeModal() {
|
|||
|
||||
window.addEventListener('keydown', handleWindowKeyDown);
|
||||
|
||||
function handleWindowKeyDown(e:Event) {
|
||||
function handleWindowKeyDown(e: Event) {
|
||||
const code = keycode(e);
|
||||
if (code !== 'esc') {
|
||||
return;
|
||||
|
@ -39,4 +46,4 @@ function handleWindowKeyDown(e:Event) {
|
|||
if (closeOnEsc && !disabled) {
|
||||
modal.props.onHide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import {
|
||||
Position,
|
||||
Overlay as BaseOverlay
|
||||
} from 'react-overlays';
|
||||
/**
|
||||
* @file Overlay
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import {Position, Overlay as BaseOverlay} from 'react-overlays';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
calculatePosition,
|
||||
getContainer,
|
||||
ownerDocument
|
||||
} from '../utils/dom';
|
||||
import {calculatePosition, getContainer, ownerDocument} from '../utils/dom';
|
||||
|
||||
Position.propTypes.placement = BaseOverlay.propTypes.placement = () => null;
|
||||
|
||||
Position.prototype.updatePosition = function(target:any) {
|
||||
Position.prototype.updatePosition = function(target: any) {
|
||||
this._lastTarget = target;
|
||||
|
||||
if (!target) {
|
||||
|
@ -20,25 +19,16 @@ Position.prototype.updatePosition = function(target:any) {
|
|||
positionLeft: 0,
|
||||
positionTop: 0,
|
||||
arrowOffsetLeft: null,
|
||||
arrowOffsetTop: null
|
||||
arrowOffsetTop: null,
|
||||
});
|
||||
}
|
||||
|
||||
const overlay = findDOMNode(this);
|
||||
const container = getContainer(
|
||||
this.props.container, ownerDocument(this).body
|
||||
);
|
||||
const container = getContainer(this.props.container, ownerDocument(this).body);
|
||||
|
||||
this.setState(calculatePosition(
|
||||
this.props.placement,
|
||||
overlay,
|
||||
target,
|
||||
container,
|
||||
this.props.containerPadding
|
||||
));
|
||||
this.setState(calculatePosition(this.props.placement, overlay, target, container, this.props.containerPadding));
|
||||
};
|
||||
|
||||
|
||||
interface OverlayProps {
|
||||
placement?: string;
|
||||
show?: boolean;
|
||||
|
@ -48,14 +38,11 @@ interface OverlayProps {
|
|||
target?: React.ReactNode | Function;
|
||||
}
|
||||
export default class Overlay extends React.Component<OverlayProps> {
|
||||
constructor(props:OverlayProps) {
|
||||
constructor(props: OverlayProps) {
|
||||
super(props as any);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<BaseOverlay {...this.props as any} />
|
||||
)
|
||||
return <BaseOverlay {...this.props as any} />;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
/**
|
||||
* @file simple-popover
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint fecs-indent: [0, "space", 2, 2] */
|
||||
* @file PopOver
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface Offset {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PopOverPorps {
|
||||
className?: string;
|
||||
|
@ -20,14 +20,14 @@ export interface PopOverPorps {
|
|||
positionLeft?: number;
|
||||
arrowOffsetLeft?: number;
|
||||
arrowOffsetTop?: number;
|
||||
offset?: ((clip:object, offset:object) => Offset) | Offset;
|
||||
offset?: ((clip: object, offset: object) => Offset) | Offset;
|
||||
style?: object;
|
||||
overlay?: boolean;
|
||||
onHide?: () => void;
|
||||
onClick?: (e:React.MouseEvent<any>) => void;
|
||||
onClick?: (e: React.MouseEvent<any>) => void;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
[propName:string]: any;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
interface PopOverState {
|
||||
|
@ -40,49 +40,47 @@ export class PopOver extends React.PureComponent<PopOverPorps, PopOverState> {
|
|||
className: '',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
y: 0,
|
||||
},
|
||||
overlay: false,
|
||||
placement: 'bottom',
|
||||
};
|
||||
|
||||
|
||||
state = {
|
||||
xOffset: 0,
|
||||
yOffset: 0
|
||||
yOffset: 0,
|
||||
};
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
this.mayUpdateOffset();
|
||||
}
|
||||
|
||||
|
||||
componentDidUpdate() {
|
||||
this.mayUpdateOffset();
|
||||
}
|
||||
|
||||
|
||||
mayUpdateOffset() {
|
||||
let offset:Offset;
|
||||
let offset: Offset;
|
||||
let getOffset = this.props.offset;
|
||||
|
||||
|
||||
if (getOffset && typeof getOffset === 'function') {
|
||||
const {
|
||||
placement,
|
||||
positionTop: y,
|
||||
positionLeft: x
|
||||
} = this.props;
|
||||
const {placement, positionTop: y, positionLeft: x} = this.props;
|
||||
|
||||
offset = getOffset((findDOMNode(this) as HTMLElement).getBoundingClientRect(), {
|
||||
x, y, placement
|
||||
x,
|
||||
y,
|
||||
placement,
|
||||
});
|
||||
} else {
|
||||
offset = getOffset as Offset;
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
xOffset: offset ? (offset as Offset).x : 0,
|
||||
yOffset: offset ? offset.y : 0
|
||||
yOffset: offset ? offset.y : 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
const {
|
||||
placement,
|
||||
|
@ -100,32 +98,23 @@ export class PopOver extends React.PureComponent<PopOverPorps, PopOverState> {
|
|||
className,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
|
||||
const {
|
||||
xOffset,
|
||||
yOffset
|
||||
} = this.state;
|
||||
|
||||
|
||||
const {xOffset, yOffset} = this.state;
|
||||
|
||||
const outerStyle = {
|
||||
display: 'block',
|
||||
...style,
|
||||
top: positionTop as number + yOffset,
|
||||
left: positionLeft as number + xOffset
|
||||
top: (positionTop as number) + yOffset,
|
||||
left: (positionLeft as number) + xOffset,
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`${ns}PopOver`, className, `${ns}PopOver--${placement}`)}
|
||||
style={outerStyle}
|
||||
{...rest}
|
||||
>
|
||||
{overlay ? (<div className={`${ns}PopOver-overlay`} onClick={onHide} />) : null}
|
||||
<div className={cx(`${ns}PopOver`, className, `${ns}PopOver--${placement}`)} style={outerStyle} {...rest}>
|
||||
{overlay ? <div className={`${ns}PopOver-overlay`} onClick={onHide} /> : null}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default themeable(PopOver);
|
||||
export default themeable(PopOver);
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
/**
|
||||
* @file checkboxes 多选输入框
|
||||
*
|
||||
* @file Radios
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import Checkbox from './Checkbox';
|
||||
import {value2array, OptionProps, Option} from './Checkboxes';
|
||||
import chunk = require('lodash/chunk');
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
|
||||
/**
|
||||
* 参数说明:
|
||||
*
|
||||
* @param 参数说明:
|
||||
* options: [
|
||||
* {
|
||||
* label: '显示的名字',
|
||||
|
@ -23,45 +13,42 @@ import { ClassNamesFn, themeable } from '../theme';
|
|||
* ]
|
||||
*/
|
||||
|
||||
interface RadioProps extends OptionProps {
|
||||
id?: string;
|
||||
type: string;
|
||||
value?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
inline?: boolean;
|
||||
disabled?: boolean;
|
||||
onChange?: Function;
|
||||
columnsCount: number;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
}
|
||||
import * as React from 'react';
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import Checkbox from './Checkbox';
|
||||
import {value2array, OptionProps, Option} from './Checkboxes';
|
||||
import chunk = require('lodash/chunk');
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface RadioProps extends OptionProps {
|
||||
id?: string;
|
||||
type: string;
|
||||
value?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
inline?: boolean;
|
||||
disabled?: boolean;
|
||||
onChange?: Function;
|
||||
columnsCount: number;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
}
|
||||
|
||||
export class Radios extends React.Component<RadioProps, any> {
|
||||
|
||||
static defaultProps = {
|
||||
joinValues: true,
|
||||
clearable: false,
|
||||
columnsCount: 1 // 一行显示一个
|
||||
columnsCount: 1, // 一行显示一个
|
||||
};
|
||||
|
||||
toggleOption(option: Option) {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
joinValues,
|
||||
extractValue,
|
||||
valueField,
|
||||
clearable,
|
||||
delimiter,
|
||||
options
|
||||
} = this.props;
|
||||
const {value, onChange, joinValues, extractValue, valueField, clearable, delimiter, options} = this.props;
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
options,
|
||||
});
|
||||
const idx = valueArray.indexOf(option);
|
||||
|
||||
|
@ -96,14 +83,14 @@ export class Radios extends React.Component<RadioProps, any> {
|
|||
inline,
|
||||
delimiter,
|
||||
valueField,
|
||||
classPrefix
|
||||
classPrefix,
|
||||
} = this.props;
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
options,
|
||||
});
|
||||
let body: Array<React.ReactNode> = [];
|
||||
|
||||
|
@ -125,25 +112,25 @@ export class Radios extends React.Component<RadioProps, any> {
|
|||
}
|
||||
|
||||
if (!inline && columnsCount > 1) {
|
||||
let weight = 12/(columnsCount as number);
|
||||
let weight = 12 / (columnsCount as number);
|
||||
let cellClassName = `Grid-col--sm${weight === Math.round(weight) ? weight : ''}`;
|
||||
body = chunk(body, columnsCount).map((group, groupIndex) => (
|
||||
<div className={cx('Grid')} key={groupIndex}>
|
||||
{group.map((item, index) => (
|
||||
<div key={index} className={cx(cellClassName)}>{item}</div>
|
||||
<div key={index} className={cx(cellClassName)}>
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{body && body.length ? body : placeholder}
|
||||
</div>
|
||||
);
|
||||
return <div className={className}>{body && body.length ? body : placeholder}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(uncontrollable(Radios, {
|
||||
value: 'onChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(Radios, {
|
||||
value: 'onChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/**
|
||||
* @file Input Range
|
||||
* @file Range
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as InputRange from 'react-input-range';
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import * as cx from 'classnames';
|
||||
import { RendererProps } from '../factory';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {RendererProps} from '../factory';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface RangeProps extends RendererProps {
|
||||
id?: string;
|
||||
|
@ -22,17 +24,11 @@ interface RangeProps extends RendererProps {
|
|||
export class Range extends React.Component<RangeProps, any> {
|
||||
static defaultProps: Partial<RangeProps> = {
|
||||
min: 1,
|
||||
max: 100
|
||||
max: 100,
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
min,
|
||||
max,
|
||||
value,
|
||||
className,
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
const {min, max, value, className, classPrefix: ns} = this.props;
|
||||
|
||||
const classNames = {
|
||||
activeTrack: `${ns}InputRange-track is-active`,
|
||||
|
@ -45,14 +41,23 @@ export class Range extends React.Component<RangeProps, any> {
|
|||
sliderContainer: `${ns}InputRange-sliderContainer`,
|
||||
track: `${ns}InputRange-track ${ns}InputRange-track--background`,
|
||||
valueLabel: `${ns}InputRange-label ${ns}InputRange-label--value`,
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<InputRange {...this.props} className={className} classNames={classNames} minValue={min} maxValue={max} value={typeof value === 'number' ? value : min} />
|
||||
)
|
||||
<InputRange
|
||||
{...this.props}
|
||||
className={className}
|
||||
classNames={classNames}
|
||||
minValue={min}
|
||||
maxValue={max}
|
||||
value={typeof value === 'number' ? value : min}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(uncontrollable(Range, {
|
||||
value: 'onChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(Range, {
|
||||
value: 'onChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/**
|
||||
* @file rating组件
|
||||
* @file Rating
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface RatingProps {
|
||||
id?: string;
|
||||
|
@ -16,7 +17,7 @@ interface RatingProps {
|
|||
char: string;
|
||||
size: number;
|
||||
className?: string;
|
||||
onChange?: (value:any) => void;
|
||||
onChange?: (value: any) => void;
|
||||
value: number;
|
||||
containerClass: string;
|
||||
readOnly: boolean;
|
||||
|
@ -32,10 +33,10 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
value: 0,
|
||||
count: 5,
|
||||
char: '★',
|
||||
size: 24
|
||||
size: 24,
|
||||
};
|
||||
|
||||
constructor(props:RatingProps) {
|
||||
constructor(props: RatingProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
@ -43,9 +44,9 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
stars: [],
|
||||
halfStar: {
|
||||
at: Math.floor(props.value),
|
||||
hidden: props.half && props.value % 1 < 0.5
|
||||
}
|
||||
}
|
||||
hidden: props.half && props.value % 1 < 0.5,
|
||||
},
|
||||
};
|
||||
|
||||
this.getRate = this.getRate.bind(this);
|
||||
this.getStars = this.getStars.bind(this);
|
||||
|
@ -56,27 +57,27 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { value } = this.state;
|
||||
const {value} = this.state;
|
||||
this.setState({
|
||||
stars: this.getStars(value)
|
||||
})
|
||||
stars: this.getStars(value),
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props:RatingProps) {
|
||||
componentWillReceiveProps(props: RatingProps) {
|
||||
this.setState({
|
||||
stars: this.getStars(props.value),
|
||||
value: props.value,
|
||||
halfStar: {
|
||||
at: Math.floor(props.value),
|
||||
hidden: props.half && props.value % 1 < 0.5
|
||||
}
|
||||
})
|
||||
hidden: props.half && props.value % 1 < 0.5,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getRate() {
|
||||
let stars;
|
||||
const { value } = this.state;
|
||||
const { half } = this.props;
|
||||
const {value} = this.state;
|
||||
const {half} = this.props;
|
||||
if (half) {
|
||||
stars = Math.floor(value);
|
||||
} else {
|
||||
|
@ -85,22 +86,22 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
return stars;
|
||||
}
|
||||
|
||||
getStars(activeCount?:number) {
|
||||
getStars(activeCount?: number) {
|
||||
if (typeof activeCount === 'undefined') {
|
||||
activeCount = this.getRate();
|
||||
}
|
||||
let stars = [];
|
||||
const { count } = this.props;
|
||||
const {count} = this.props;
|
||||
for (let i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
active: i <= activeCount - 1
|
||||
})
|
||||
active: i <= activeCount - 1,
|
||||
});
|
||||
}
|
||||
return stars;
|
||||
}
|
||||
|
||||
mouseOver(event:React.ChangeEvent<any>) {
|
||||
let { readOnly, size, half } = this.props;
|
||||
mouseOver(event: React.ChangeEvent<any>) {
|
||||
let {readOnly, size, half} = this.props;
|
||||
if (readOnly) return;
|
||||
let index = Number(event.target.getAttribute('data-index'));
|
||||
if (half) {
|
||||
|
@ -109,75 +110,75 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf
|
||||
}
|
||||
})
|
||||
hidden: isAtHalf,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
index = index + 1;
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars(index)
|
||||
})
|
||||
stars: this.getStars(index),
|
||||
});
|
||||
}
|
||||
|
||||
moreThanHalf(event:any, size:number) {
|
||||
let { target } = event;
|
||||
moreThanHalf(event: any, size: number) {
|
||||
let {target} = event;
|
||||
let mouseAt = event.clientX - target.getBoundingClientRect().left;
|
||||
mouseAt = Math.round(Math.abs(mouseAt));
|
||||
return mouseAt > size / 2;
|
||||
}
|
||||
|
||||
mouseLeave() {
|
||||
let { value } = this.state;
|
||||
const { half, readOnly } = this.props;
|
||||
let {value} = this.state;
|
||||
const {half, readOnly} = this.props;
|
||||
if (readOnly) return;
|
||||
if (half) {
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: Math.floor(value),
|
||||
hidden: value % 1 === 0 // check value is decimal or not
|
||||
}
|
||||
})
|
||||
hidden: value % 1 === 0, // check value is decimal or not
|
||||
},
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars()
|
||||
})
|
||||
stars: this.getStars(),
|
||||
});
|
||||
}
|
||||
|
||||
handleClick(event:React.ChangeEvent<any>) {
|
||||
const { half, readOnly, onChange, size } = this.props;
|
||||
handleClick(event: React.ChangeEvent<any>) {
|
||||
const {half, readOnly, onChange, size} = this.props;
|
||||
if (readOnly) return;
|
||||
let index = Number(event.target.getAttribute('data-index'));
|
||||
let value;
|
||||
if (half) {
|
||||
const isAtHalf = this.moreThanHalf(event, size);
|
||||
if (isAtHalf) index = index + 1;
|
||||
value = isAtHalf ? index : index + .5;
|
||||
value = isAtHalf ? index : index + 0.5;
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf
|
||||
}
|
||||
})
|
||||
hidden: isAtHalf,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
value = index = index + 1;
|
||||
}
|
||||
this.setState({
|
||||
value: value,
|
||||
stars: this.getStars(index)
|
||||
})
|
||||
stars: this.getStars(index),
|
||||
});
|
||||
onChange && onChange(value);
|
||||
}
|
||||
|
||||
renderStars() {
|
||||
const { halfStar, stars } = this.state;
|
||||
const { char, half, readOnly, classnames: cx } = this.props;
|
||||
return stars.map((star:any, i:number) => {
|
||||
const {halfStar, stars} = this.state;
|
||||
const {char, half, readOnly, classnames: cx} = this.props;
|
||||
return stars.map((star: any, i: number) => {
|
||||
let className = cx('Rating', {
|
||||
'Rating-half': half && !halfStar.hidden && halfStar.at === i,
|
||||
'is-active': star.active,
|
||||
'is-disabled': readOnly
|
||||
})
|
||||
'is-disabled': readOnly,
|
||||
});
|
||||
|
||||
return (
|
||||
<span
|
||||
|
@ -188,22 +189,19 @@ export class Rating extends React.Component<RatingProps, any> {
|
|||
onMouseOver={this.mouseOver}
|
||||
onMouseMove={this.mouseOver}
|
||||
onMouseLeave={this.mouseLeave}
|
||||
onClick={this.handleClick}>
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{char}
|
||||
</span>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let { className } = this.props;
|
||||
let {className} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx(className ? className : '')}>
|
||||
{this.renderStars()}
|
||||
</div>
|
||||
)
|
||||
return <div className={cx(className ? className : '')}>{this.renderStars()}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Rating);
|
||||
export default themeable(Rating);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
* @file RichText
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as $ from 'jquery';
|
||||
|
||||
|
@ -23,26 +29,25 @@ import * as $ from 'jquery';
|
|||
require('froala-editor/js/plugins/code_view.min'),
|
||||
// require('froala-editor/js/plugins/emotion'),
|
||||
require('froala-editor/js/plugins/fullscreen.min'),
|
||||
require('froala-editor/js/plugins/video.min')
|
||||
].forEach(init => init());
|
||||
|
||||
require('froala-editor/js/plugins/video.min'),
|
||||
].forEach(init => init());
|
||||
|
||||
// Require Editor CSS files.
|
||||
import 'froala-editor/css/froala_style.min.css';
|
||||
import 'froala-editor/css/froala_editor.pkgd.min.css';
|
||||
|
||||
export default class FroalaEditor extends React.Component<any, any> {
|
||||
listeningEvents:Array<any> = [];
|
||||
$element:any = null;
|
||||
$editor:any = null;
|
||||
config:any = {
|
||||
listeningEvents: Array<any> = [];
|
||||
$element: any = null;
|
||||
$editor: any = null;
|
||||
config: any = {
|
||||
immediateReactModelUpdate: false,
|
||||
reactIgnoreAttrs: null
|
||||
reactIgnoreAttrs: null,
|
||||
};
|
||||
editorInitialized:boolean = false;
|
||||
oldModel:any = null;
|
||||
editorInitialized: boolean = false;
|
||||
oldModel: any = null;
|
||||
|
||||
constructor(props:any) {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.textareaRef = this.textareaRef.bind(this);
|
||||
}
|
||||
|
@ -55,11 +60,11 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
this.setContent();
|
||||
}
|
||||
|
||||
textareaRef(ref:any) {
|
||||
textareaRef(ref: any) {
|
||||
ref ? this.createEditor(ref) : this.destroyEditor();
|
||||
}
|
||||
|
||||
createEditor(ref:any) {
|
||||
createEditor(ref: any) {
|
||||
if (this.editorInitialized) {
|
||||
return;
|
||||
}
|
||||
|
@ -73,8 +78,7 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
this.editorInitialized = true;
|
||||
}
|
||||
|
||||
setContent (firstTime:boolean = false) {
|
||||
|
||||
setContent(firstTime: boolean = false) {
|
||||
if (!this.editorInitialized && !firstTime) {
|
||||
return;
|
||||
}
|
||||
|
@ -86,7 +90,7 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
}
|
||||
}
|
||||
|
||||
setNormalTagContent (firstTime:boolean) {
|
||||
setNormalTagContent(firstTime: boolean) {
|
||||
let self = this;
|
||||
|
||||
function htmlSet() {
|
||||
|
@ -101,17 +105,16 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
} else {
|
||||
htmlSet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getEditor () {
|
||||
getEditor() {
|
||||
if (this.$element) {
|
||||
return this.$element.froalaEditor.bind(this.$element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
updateModel () {
|
||||
updateModel() {
|
||||
if (!this.props.onModelChange) {
|
||||
return;
|
||||
}
|
||||
|
@ -127,23 +130,22 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
this.props.onModelChange(modelContent);
|
||||
}
|
||||
|
||||
initListeners () {
|
||||
initListeners() {
|
||||
let self = this;
|
||||
|
||||
// bind contentChange and keyup event to froalaModel
|
||||
this.registerEvent(this.$element, 'froalaEditor.contentChanged',function () {
|
||||
this.registerEvent(this.$element, 'froalaEditor.contentChanged', function() {
|
||||
self.updateModel();
|
||||
});
|
||||
if (this.config.immediateReactModelUpdate) {
|
||||
this.registerEvent(this.$editor, 'keyup', function () {
|
||||
this.registerEvent(this.$editor, 'keyup', function() {
|
||||
self.updateModel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// register event on jquery editor element
|
||||
registerEvent (element:any, eventName:any, callback:any) {
|
||||
|
||||
registerEvent(element: any, eventName: any, callback: any) {
|
||||
if (!element || !eventName || !callback) {
|
||||
return;
|
||||
}
|
||||
|
@ -152,7 +154,7 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
element.on(eventName, callback);
|
||||
}
|
||||
|
||||
registerEvents () {
|
||||
registerEvents() {
|
||||
let events = this.config.events;
|
||||
if (!events) {
|
||||
return;
|
||||
|
@ -165,9 +167,9 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
}
|
||||
}
|
||||
|
||||
destroyEditor () {
|
||||
destroyEditor() {
|
||||
if (this.$element) {
|
||||
this.listeningEvents && this.$element.off(this.listeningEvents.join(" "));
|
||||
this.listeningEvents && this.$element.off(this.listeningEvents.join(' '));
|
||||
this.$editor.off('keyup');
|
||||
this.$element.froalaEditor('destroy');
|
||||
this.listeningEvents.length = 0;
|
||||
|
@ -177,241 +179,244 @@ export default class FroalaEditor extends React.Component<any, any> {
|
|||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<textarea ref={this.textareaRef}></textarea>
|
||||
);
|
||||
return <textarea ref={this.textareaRef} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
($ as any).FE.VIDEO_PROVIDERS = [
|
||||
{
|
||||
test_regex: /^.+(bcebos.com)\/[^_&]+/,
|
||||
url_regex: '',
|
||||
url_text: '',
|
||||
html: '<span class="fr-video fr-dvb fr-draggable" contenteditable="false" draggable="true"><video class="fr-draggable" controls="" data-msg="ok" data-status="0" src="{url}" style="width: 600px;"></video></span>'
|
||||
test_regex: /^.+(bcebos.com)\/[^_&]+/,
|
||||
url_regex: '',
|
||||
url_text: '',
|
||||
html:
|
||||
'<span class="fr-video fr-dvb fr-draggable" contenteditable="false" draggable="true"><video class="fr-draggable" controls="" data-msg="ok" data-status="0" src="{url}" style="width: 600px;"></video></span>',
|
||||
},
|
||||
];
|
||||
($ as any).FE.LANGUAGE['zh_cn'] = {
|
||||
translation: {
|
||||
// Place holder
|
||||
"Type something": "\u8f93\u5165\u4e00\u4e9b\u5185\u5bb9",
|
||||
// Place holder
|
||||
'Type something': '\u8f93\u5165\u4e00\u4e9b\u5185\u5bb9',
|
||||
|
||||
// Basic formatting
|
||||
"Bold": "\u7c97\u4f53",
|
||||
"Italic": "\u659c\u4f53",
|
||||
"Underline": "\u4e0b\u5212\u7ebf",
|
||||
"Strikethrough": "\u5220\u9664\u7ebf",
|
||||
// Basic formatting
|
||||
Bold: '\u7c97\u4f53',
|
||||
Italic: '\u659c\u4f53',
|
||||
Underline: '\u4e0b\u5212\u7ebf',
|
||||
Strikethrough: '\u5220\u9664\u7ebf',
|
||||
|
||||
// Main buttons
|
||||
"Insert": "\u63d2\u5165",
|
||||
"Delete": "\u5220\u9664",
|
||||
"Cancel": "\u53d6\u6d88",
|
||||
"OK": "\u786e\u5b9a",
|
||||
"Back": "\u80cc\u90e8",
|
||||
"Remove": "\u53bb\u6389",
|
||||
"More": "\u66f4\u591a",
|
||||
"Update": "\u66f4\u65b0",
|
||||
"Style": "\u98ce\u683c",
|
||||
// Main buttons
|
||||
Insert: '\u63d2\u5165',
|
||||
Delete: '\u5220\u9664',
|
||||
Cancel: '\u53d6\u6d88',
|
||||
OK: '\u786e\u5b9a',
|
||||
Back: '\u80cc\u90e8',
|
||||
Remove: '\u53bb\u6389',
|
||||
More: '\u66f4\u591a',
|
||||
Update: '\u66f4\u65b0',
|
||||
Style: '\u98ce\u683c',
|
||||
|
||||
// Font
|
||||
"Font Family": "\u5b57\u4f53",
|
||||
"Font Size": "\u5b57\u53f7",
|
||||
// Font
|
||||
'Font Family': '\u5b57\u4f53',
|
||||
'Font Size': '\u5b57\u53f7',
|
||||
|
||||
// Colors
|
||||
"Colors": "\u989c\u8272",
|
||||
"Background": "\u80cc\u666f",
|
||||
"Text": "\u6587\u5b57",
|
||||
// Colors
|
||||
Colors: '\u989c\u8272',
|
||||
Background: '\u80cc\u666f',
|
||||
Text: '\u6587\u5b57',
|
||||
|
||||
// Paragraphs
|
||||
"Paragraph Format": "\u683c\u5f0f",
|
||||
"Normal": "\u6b63\u5e38",
|
||||
"Code": "\u4ee3\u7801",
|
||||
"Heading 1": "\u6807\u98981",
|
||||
"Heading 2": "\u6807\u98982",
|
||||
"Heading 3": "\u6807\u98983",
|
||||
"Heading 4": "\u6807\u98984",
|
||||
// Paragraphs
|
||||
'Paragraph Format': '\u683c\u5f0f',
|
||||
Normal: '\u6b63\u5e38',
|
||||
Code: '\u4ee3\u7801',
|
||||
'Heading 1': '\u6807\u98981',
|
||||
'Heading 2': '\u6807\u98982',
|
||||
'Heading 3': '\u6807\u98983',
|
||||
'Heading 4': '\u6807\u98984',
|
||||
|
||||
// Style
|
||||
"Paragraph Style": "\u6bb5\u843d\u6837\u5f0f",
|
||||
"Inline Style": "\u5185\u8054\u6837\u5f0f",
|
||||
// Style
|
||||
'Paragraph Style': '\u6bb5\u843d\u6837\u5f0f',
|
||||
'Inline Style': '\u5185\u8054\u6837\u5f0f',
|
||||
|
||||
// Alignment
|
||||
"Align": "\u5bf9\u9f50\u65b9\u5f0f",
|
||||
"Align Left": "\u5de6\u5bf9\u9f50",
|
||||
"Align Center": "\u5c45\u4e2d",
|
||||
"Align Right": "\u53f3\u5bf9\u9f50",
|
||||
"Align Justify": "\u4e24\u7aef\u5bf9\u9f50",
|
||||
"None": "\u65e0",
|
||||
// Alignment
|
||||
Align: '\u5bf9\u9f50\u65b9\u5f0f',
|
||||
'Align Left': '\u5de6\u5bf9\u9f50',
|
||||
'Align Center': '\u5c45\u4e2d',
|
||||
'Align Right': '\u53f3\u5bf9\u9f50',
|
||||
'Align Justify': '\u4e24\u7aef\u5bf9\u9f50',
|
||||
None: '\u65e0',
|
||||
|
||||
// Lists
|
||||
"Ordered List": "\u7f16\u53f7\u5217\u8868",
|
||||
"Unordered List": "\u9879\u76ee\u7b26\u53f7",
|
||||
// Lists
|
||||
'Ordered List': '\u7f16\u53f7\u5217\u8868',
|
||||
'Unordered List': '\u9879\u76ee\u7b26\u53f7',
|
||||
|
||||
// Indent
|
||||
"Decrease Indent": "\u51cf\u5c11\u7f29\u8fdb",
|
||||
"Increase Indent": "\u589e\u52a0\u7f29\u8fdb",
|
||||
// Indent
|
||||
'Decrease Indent': '\u51cf\u5c11\u7f29\u8fdb',
|
||||
'Increase Indent': '\u589e\u52a0\u7f29\u8fdb',
|
||||
|
||||
// Links
|
||||
"Insert Link": "\u63d2\u5165\u94fe\u63a5",
|
||||
"Open in new tab": "\u5f00\u542f\u5728\u65b0\u6807\u7b7e\u9875",
|
||||
"Open Link": "\u6253\u5f00\u94fe\u63a5",
|
||||
"Edit Link": "\u7f16\u8f91\u94fe\u63a5",
|
||||
"Unlink": "\u5220\u9664\u94fe\u63a5",
|
||||
"Choose Link": "\u9009\u62e9\u94fe\u63a5",
|
||||
// Links
|
||||
'Insert Link': '\u63d2\u5165\u94fe\u63a5',
|
||||
'Open in new tab': '\u5f00\u542f\u5728\u65b0\u6807\u7b7e\u9875',
|
||||
'Open Link': '\u6253\u5f00\u94fe\u63a5',
|
||||
'Edit Link': '\u7f16\u8f91\u94fe\u63a5',
|
||||
Unlink: '\u5220\u9664\u94fe\u63a5',
|
||||
'Choose Link': '\u9009\u62e9\u94fe\u63a5',
|
||||
|
||||
// Images
|
||||
"Insert Image": "\u63d2\u5165\u56fe\u7247",
|
||||
"Upload Image": "\u4e0a\u4f20\u56fe\u7247",
|
||||
"By URL": "\u901a\u8fc7\u7f51\u5740",
|
||||
"Browse": "\u6d4f\u89c8",
|
||||
"Drop image": "\u56fe\u50cf\u62d6\u653e",
|
||||
"or click": "\u6216\u70b9\u51fb",
|
||||
"Manage Images": "\u7ba1\u7406\u56fe\u50cf",
|
||||
"Loading": "\u8f7d\u5165\u4e2d",
|
||||
"Deleting": "\u5220\u9664",
|
||||
"Tags": "\u6807\u7b7e",
|
||||
"Are you sure? Image will be deleted.": "\u4f60\u786e\u5b9a\u5417\uff1f\u56fe\u50cf\u5c06\u88ab\u5220\u9664\u3002",
|
||||
"Replace": "\u66f4\u6362",
|
||||
"Uploading": "\u4e0a\u4f20",
|
||||
"Loading image": "\u5bfc\u5165\u56fe\u50cf",
|
||||
"Display": "\u663e\u793a",
|
||||
"Inline": "\u6392\u961f",
|
||||
"Break Text": "\u65ad\u5f00\u6587\u672c",
|
||||
"Alternate Text": "\u5907\u7528\u6587\u672c",
|
||||
"Change Size": "\u5c3a\u5bf8\u53d8\u5316",
|
||||
"Width": "\u5bbd\u5ea6",
|
||||
"Height": "\u9ad8\u5ea6",
|
||||
"Something went wrong. Please try again.": "\u51fa\u4e86\u4e9b\u95ee\u9898\u3002 \u8bf7\u518d\u8bd5\u4e00\u6b21\u3002",
|
||||
// Images
|
||||
'Insert Image': '\u63d2\u5165\u56fe\u7247',
|
||||
'Upload Image': '\u4e0a\u4f20\u56fe\u7247',
|
||||
'By URL': '\u901a\u8fc7\u7f51\u5740',
|
||||
Browse: '\u6d4f\u89c8',
|
||||
'Drop image': '\u56fe\u50cf\u62d6\u653e',
|
||||
'or click': '\u6216\u70b9\u51fb',
|
||||
'Manage Images': '\u7ba1\u7406\u56fe\u50cf',
|
||||
Loading: '\u8f7d\u5165\u4e2d',
|
||||
Deleting: '\u5220\u9664',
|
||||
Tags: '\u6807\u7b7e',
|
||||
'Are you sure? Image will be deleted.':
|
||||
'\u4f60\u786e\u5b9a\u5417\uff1f\u56fe\u50cf\u5c06\u88ab\u5220\u9664\u3002',
|
||||
Replace: '\u66f4\u6362',
|
||||
Uploading: '\u4e0a\u4f20',
|
||||
'Loading image': '\u5bfc\u5165\u56fe\u50cf',
|
||||
Display: '\u663e\u793a',
|
||||
Inline: '\u6392\u961f',
|
||||
'Break Text': '\u65ad\u5f00\u6587\u672c',
|
||||
'Alternate Text': '\u5907\u7528\u6587\u672c',
|
||||
'Change Size': '\u5c3a\u5bf8\u53d8\u5316',
|
||||
Width: '\u5bbd\u5ea6',
|
||||
Height: '\u9ad8\u5ea6',
|
||||
'Something went wrong. Please try again.':
|
||||
'\u51fa\u4e86\u4e9b\u95ee\u9898\u3002 \u8bf7\u518d\u8bd5\u4e00\u6b21\u3002',
|
||||
|
||||
// Video
|
||||
"Insert Video": "\u63d2\u5165\u89c6\u9891",
|
||||
"Embedded Code": "\u5d4c\u5165\u5f0f\u4ee3\u7801",
|
||||
// Video
|
||||
'Insert Video': '\u63d2\u5165\u89c6\u9891',
|
||||
'Embedded Code': '\u5d4c\u5165\u5f0f\u4ee3\u7801',
|
||||
|
||||
// Tables
|
||||
"Insert Table": "\u63d2\u5165\u8868\u683c",
|
||||
"Table Header": "\u8868\u5934",
|
||||
"Remove Table": "\u5220\u9664\u8868",
|
||||
"Table Style": "\u8868\u683c\u6837\u5f0f",
|
||||
"Horizontal Align": "\u6c34\u5e73\u5bf9\u9f50\u65b9\u5f0f",
|
||||
"Row": "\u884c",
|
||||
"Insert row above": "\u5728\u4e0a\u65b9\u63d2\u5165",
|
||||
"Insert row below": "\u5728\u4e0b\u65b9\u63d2\u5165",
|
||||
"Delete row": "\u5220\u9664\u884c",
|
||||
"Column": "\u5217",
|
||||
"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
|
||||
"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
|
||||
"Delete column": "\u5220\u9664\u5217",
|
||||
"Cell": "\u5355\u5143\u683c",
|
||||
"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
|
||||
"Horizontal split": "\u6c34\u5e73\u5206\u5272",
|
||||
"Vertical split": "\u5782\u76f4\u5206\u5272",
|
||||
"Cell Background": "\u5355\u5143\u683c\u80cc\u666f",
|
||||
"Vertical Align": "\u5782\u76f4\u5bf9\u9f50\u65b9\u5f0f",
|
||||
"Top": "\u6700\u4f73",
|
||||
"Middle": "\u4e2d\u95f4",
|
||||
"Bottom": "\u5e95\u90e8",
|
||||
"Align Top": "\u9876\u90e8\u5bf9\u9f50",
|
||||
"Align Middle": "\u4e2d\u95f4\u5bf9\u9f50",
|
||||
"Align Bottom": "\u5e95\u90e8\u5bf9\u9f50",
|
||||
"Cell Style": "\u5355\u5143\u683c\u6837\u5f0f",
|
||||
// Tables
|
||||
'Insert Table': '\u63d2\u5165\u8868\u683c',
|
||||
'Table Header': '\u8868\u5934',
|
||||
'Remove Table': '\u5220\u9664\u8868',
|
||||
'Table Style': '\u8868\u683c\u6837\u5f0f',
|
||||
'Horizontal Align': '\u6c34\u5e73\u5bf9\u9f50\u65b9\u5f0f',
|
||||
Row: '\u884c',
|
||||
'Insert row above': '\u5728\u4e0a\u65b9\u63d2\u5165',
|
||||
'Insert row below': '\u5728\u4e0b\u65b9\u63d2\u5165',
|
||||
'Delete row': '\u5220\u9664\u884c',
|
||||
Column: '\u5217',
|
||||
'Insert column before': '\u5728\u5de6\u4fa7\u63d2\u5165',
|
||||
'Insert column after': '\u5728\u53f3\u4fa7\u63d2\u5165',
|
||||
'Delete column': '\u5220\u9664\u5217',
|
||||
Cell: '\u5355\u5143\u683c',
|
||||
'Merge cells': '\u5408\u5e76\u5355\u5143\u683c',
|
||||
'Horizontal split': '\u6c34\u5e73\u5206\u5272',
|
||||
'Vertical split': '\u5782\u76f4\u5206\u5272',
|
||||
'Cell Background': '\u5355\u5143\u683c\u80cc\u666f',
|
||||
'Vertical Align': '\u5782\u76f4\u5bf9\u9f50\u65b9\u5f0f',
|
||||
Top: '\u6700\u4f73',
|
||||
Middle: '\u4e2d\u95f4',
|
||||
Bottom: '\u5e95\u90e8',
|
||||
'Align Top': '\u9876\u90e8\u5bf9\u9f50',
|
||||
'Align Middle': '\u4e2d\u95f4\u5bf9\u9f50',
|
||||
'Align Bottom': '\u5e95\u90e8\u5bf9\u9f50',
|
||||
'Cell Style': '\u5355\u5143\u683c\u6837\u5f0f',
|
||||
|
||||
// Files
|
||||
"Upload File": "\u4e0a\u4f20\u6587\u4ef6",
|
||||
"Drop file": "\u6587\u4ef6\u62d6\u653e",
|
||||
// Files
|
||||
'Upload File': '\u4e0a\u4f20\u6587\u4ef6',
|
||||
'Drop file': '\u6587\u4ef6\u62d6\u653e',
|
||||
|
||||
// Emoticons
|
||||
"Emoticons": "\u8868\u60c5",
|
||||
"Grinning face": "\u8138\u4e0a\u7b11\u563b\u563b",
|
||||
"Grinning face with smiling eyes": "",
|
||||
"Face with tears of joy": "\u7b11\u563b\u563b\u7684\u8138\uff0c\u542b\u7b11\u7684\u773c\u775b",
|
||||
"Smiling face with open mouth": "\u7b11\u8138\u5f20\u5f00\u5634",
|
||||
"Smiling face with open mouth and smiling eyes": "\u7b11\u8138\u5f20\u5f00\u5634\u5fae\u7b11\u7684\u773c\u775b",
|
||||
"Smiling face with open mouth and cold sweat": "\u7b11\u8138\u5f20\u5f00\u5634\uff0c\u4e00\u8eab\u51b7\u6c57",
|
||||
"Smiling face with open mouth and tightly-closed eyes": "\u7b11\u8138\u5f20\u5f00\u5634\uff0c\u7d27\u7d27\u95ed\u7740\u773c\u775b",
|
||||
"Smiling face with halo": "\u7b11\u8138\u6655",
|
||||
"Smiling face with horns": "\u5fae\u7b11\u7684\u8138\u89d2",
|
||||
"Winking face": "\u7728\u773c\u8868\u60c5",
|
||||
"Smiling face with smiling eyes": "\u9762\u5e26\u5fae\u7b11\u7684\u773c\u775b",
|
||||
"Face savoring delicious food": "\u9762\u5bf9\u54c1\u5c1d\u7f8e\u5473\u7684\u98df\u7269",
|
||||
"Relieved face": "\u9762\u5bf9\u5982\u91ca\u91cd\u8d1f",
|
||||
"Smiling face with heart-shaped eyes": "\u5fae\u7b11\u7684\u8138\uff0c\u5fc3\u810f\u5f62\u7684\u773c\u775b",
|
||||
"Smiling face with sunglasses": "\u7b11\u8138\u592a\u9633\u955c",
|
||||
"Smirking face": "\u9762\u5bf9\u9762\u5e26\u7b11\u5bb9",
|
||||
"Neutral face": "\u4e2d\u6027\u9762",
|
||||
"Expressionless face": "\u9762\u65e0\u8868\u60c5",
|
||||
"Unamused face": "\u4e00\u8138\u4e0d\u5feb\u7684\u8138",
|
||||
"Face with cold sweat": "\u9762\u5bf9\u51b7\u6c57",
|
||||
"Pensive face": "\u6c89\u601d\u7684\u8138",
|
||||
"Confused face": "\u9762\u5bf9\u56f0\u60d1",
|
||||
"Confounded face": "\u8be5\u6b7b\u7684\u8138",
|
||||
"Kissing face": "\u9762\u5bf9\u63a5\u543b",
|
||||
"Face throwing a kiss": "\u9762\u5bf9\u6295\u63b7\u4e00\u4e2a\u543b",
|
||||
"Kissing face with smiling eyes": "\u63a5\u543b\u8138\uff0c\u542b\u7b11\u7684\u773c\u775b",
|
||||
"Kissing face with closed eyes": "\u63a5\u543b\u7684\u8138\u95ed\u7740\u773c\u775b",
|
||||
"Face with stuck out tongue": "\u9762\u5bf9\u4f38\u51fa\u820c\u5934",
|
||||
"Face with stuck out tongue and winking eye": "\u9762\u5bf9\u4f38\u51fa\u820c\u5934\u548c\u7728\u52a8\u7684\u773c\u775b",
|
||||
"Face with stuck out tongue and tightly-closed eyes": "\u9762\u5bf9\u4f38\u51fa\u820c\u5934\u548c\u7d27\u95ed\u7684\u773c\u775b",
|
||||
"Disappointed face": "\u9762\u5bf9\u5931\u671b",
|
||||
"Worried face": "\u9762\u5bf9\u62c5\u5fc3",
|
||||
"Angry face": "\u6124\u6012\u7684\u8138",
|
||||
"Pouting face": "\u9762\u5bf9\u5658\u5634",
|
||||
"Crying face": "\u54ed\u6ce3\u7684\u8138",
|
||||
"Persevering face": "\u600e\u5948\u8138",
|
||||
"Face with look of triumph": "\u9762\u5e26\u770b\u7684\u80dc\u5229",
|
||||
"Disappointed but relieved face": "\u5931\u671b\uff0c\u4f46\u8138\u4e0a\u91ca\u7136",
|
||||
"Frowning face with open mouth": "\u9762\u5bf9\u76b1\u7740\u7709\u5934\u5f20\u53e3",
|
||||
"Anguished face": "\u9762\u5bf9\u75db\u82e6",
|
||||
"Fearful face": "\u53ef\u6015\u7684\u8138",
|
||||
"Weary face": "\u9762\u5bf9\u538c\u5026",
|
||||
"Sleepy face": "\u9762\u5bf9\u56f0",
|
||||
"Tired face": "\u75b2\u60eb\u7684\u8138",
|
||||
"Grimacing face": "\u72f0\u72de\u7684\u8138",
|
||||
"Loudly crying face": "\u5927\u58f0\u54ed\u8138",
|
||||
"Face with open mouth": "\u9762\u5bf9\u5f20\u5f00\u5634",
|
||||
"Hushed face": "\u5b89\u9759\u7684\u8138",
|
||||
"Face with open mouth and cold sweat": "",
|
||||
"Face screaming in fear": "\u9762\u5bf9\u5f20\u5f00\u5634\uff0c\u4e00\u8eab\u51b7\u6c57",
|
||||
"Astonished face": "\u9762\u5bf9\u60ca\u8bb6",
|
||||
"Flushed face": "\u7ea2\u6251\u6251\u7684\u8138\u86cb",
|
||||
"Sleeping face": "\u719f\u7761\u7684\u8138",
|
||||
"Dizzy face": "\u9762\u5bf9\u7729",
|
||||
"Face without mouth": "\u8138\u4e0a\u6ca1\u6709\u5634",
|
||||
"Face with medical mask": "\u9762\u5bf9\u533b\u7597\u53e3\u7f69",
|
||||
// Emoticons
|
||||
Emoticons: '\u8868\u60c5',
|
||||
'Grinning face': '\u8138\u4e0a\u7b11\u563b\u563b',
|
||||
'Grinning face with smiling eyes': '',
|
||||
'Face with tears of joy': '\u7b11\u563b\u563b\u7684\u8138\uff0c\u542b\u7b11\u7684\u773c\u775b',
|
||||
'Smiling face with open mouth': '\u7b11\u8138\u5f20\u5f00\u5634',
|
||||
'Smiling face with open mouth and smiling eyes': '\u7b11\u8138\u5f20\u5f00\u5634\u5fae\u7b11\u7684\u773c\u775b',
|
||||
'Smiling face with open mouth and cold sweat': '\u7b11\u8138\u5f20\u5f00\u5634\uff0c\u4e00\u8eab\u51b7\u6c57',
|
||||
'Smiling face with open mouth and tightly-closed eyes':
|
||||
'\u7b11\u8138\u5f20\u5f00\u5634\uff0c\u7d27\u7d27\u95ed\u7740\u773c\u775b',
|
||||
'Smiling face with halo': '\u7b11\u8138\u6655',
|
||||
'Smiling face with horns': '\u5fae\u7b11\u7684\u8138\u89d2',
|
||||
'Winking face': '\u7728\u773c\u8868\u60c5',
|
||||
'Smiling face with smiling eyes': '\u9762\u5e26\u5fae\u7b11\u7684\u773c\u775b',
|
||||
'Face savoring delicious food': '\u9762\u5bf9\u54c1\u5c1d\u7f8e\u5473\u7684\u98df\u7269',
|
||||
'Relieved face': '\u9762\u5bf9\u5982\u91ca\u91cd\u8d1f',
|
||||
'Smiling face with heart-shaped eyes': '\u5fae\u7b11\u7684\u8138\uff0c\u5fc3\u810f\u5f62\u7684\u773c\u775b',
|
||||
'Smiling face with sunglasses': '\u7b11\u8138\u592a\u9633\u955c',
|
||||
'Smirking face': '\u9762\u5bf9\u9762\u5e26\u7b11\u5bb9',
|
||||
'Neutral face': '\u4e2d\u6027\u9762',
|
||||
'Expressionless face': '\u9762\u65e0\u8868\u60c5',
|
||||
'Unamused face': '\u4e00\u8138\u4e0d\u5feb\u7684\u8138',
|
||||
'Face with cold sweat': '\u9762\u5bf9\u51b7\u6c57',
|
||||
'Pensive face': '\u6c89\u601d\u7684\u8138',
|
||||
'Confused face': '\u9762\u5bf9\u56f0\u60d1',
|
||||
'Confounded face': '\u8be5\u6b7b\u7684\u8138',
|
||||
'Kissing face': '\u9762\u5bf9\u63a5\u543b',
|
||||
'Face throwing a kiss': '\u9762\u5bf9\u6295\u63b7\u4e00\u4e2a\u543b',
|
||||
'Kissing face with smiling eyes': '\u63a5\u543b\u8138\uff0c\u542b\u7b11\u7684\u773c\u775b',
|
||||
'Kissing face with closed eyes': '\u63a5\u543b\u7684\u8138\u95ed\u7740\u773c\u775b',
|
||||
'Face with stuck out tongue': '\u9762\u5bf9\u4f38\u51fa\u820c\u5934',
|
||||
'Face with stuck out tongue and winking eye':
|
||||
'\u9762\u5bf9\u4f38\u51fa\u820c\u5934\u548c\u7728\u52a8\u7684\u773c\u775b',
|
||||
'Face with stuck out tongue and tightly-closed eyes':
|
||||
'\u9762\u5bf9\u4f38\u51fa\u820c\u5934\u548c\u7d27\u95ed\u7684\u773c\u775b',
|
||||
'Disappointed face': '\u9762\u5bf9\u5931\u671b',
|
||||
'Worried face': '\u9762\u5bf9\u62c5\u5fc3',
|
||||
'Angry face': '\u6124\u6012\u7684\u8138',
|
||||
'Pouting face': '\u9762\u5bf9\u5658\u5634',
|
||||
'Crying face': '\u54ed\u6ce3\u7684\u8138',
|
||||
'Persevering face': '\u600e\u5948\u8138',
|
||||
'Face with look of triumph': '\u9762\u5e26\u770b\u7684\u80dc\u5229',
|
||||
'Disappointed but relieved face': '\u5931\u671b\uff0c\u4f46\u8138\u4e0a\u91ca\u7136',
|
||||
'Frowning face with open mouth': '\u9762\u5bf9\u76b1\u7740\u7709\u5934\u5f20\u53e3',
|
||||
'Anguished face': '\u9762\u5bf9\u75db\u82e6',
|
||||
'Fearful face': '\u53ef\u6015\u7684\u8138',
|
||||
'Weary face': '\u9762\u5bf9\u538c\u5026',
|
||||
'Sleepy face': '\u9762\u5bf9\u56f0',
|
||||
'Tired face': '\u75b2\u60eb\u7684\u8138',
|
||||
'Grimacing face': '\u72f0\u72de\u7684\u8138',
|
||||
'Loudly crying face': '\u5927\u58f0\u54ed\u8138',
|
||||
'Face with open mouth': '\u9762\u5bf9\u5f20\u5f00\u5634',
|
||||
'Hushed face': '\u5b89\u9759\u7684\u8138',
|
||||
'Face with open mouth and cold sweat': '',
|
||||
'Face screaming in fear': '\u9762\u5bf9\u5f20\u5f00\u5634\uff0c\u4e00\u8eab\u51b7\u6c57',
|
||||
'Astonished face': '\u9762\u5bf9\u60ca\u8bb6',
|
||||
'Flushed face': '\u7ea2\u6251\u6251\u7684\u8138\u86cb',
|
||||
'Sleeping face': '\u719f\u7761\u7684\u8138',
|
||||
'Dizzy face': '\u9762\u5bf9\u7729',
|
||||
'Face without mouth': '\u8138\u4e0a\u6ca1\u6709\u5634',
|
||||
'Face with medical mask': '\u9762\u5bf9\u533b\u7597\u53e3\u7f69',
|
||||
|
||||
// Line breaker
|
||||
"Break": "\u7834",
|
||||
// Line breaker
|
||||
Break: '\u7834',
|
||||
|
||||
// Math
|
||||
"Subscript": "\u4e0b\u6807",
|
||||
"Superscript": "\u4e0a\u6807",
|
||||
// Math
|
||||
Subscript: '\u4e0b\u6807',
|
||||
Superscript: '\u4e0a\u6807',
|
||||
|
||||
// Full screen
|
||||
"Fullscreen": "\u5168\u5c4f",
|
||||
// Full screen
|
||||
Fullscreen: '\u5168\u5c4f',
|
||||
|
||||
// Horizontal line
|
||||
"Insert Horizontal Line": "\u63d2\u5165\u6c34\u5e73\u7ebf",
|
||||
// Horizontal line
|
||||
'Insert Horizontal Line': '\u63d2\u5165\u6c34\u5e73\u7ebf',
|
||||
|
||||
// Clear formatting
|
||||
"Clear Formatting": "\u683c\u5f0f\u5316\u5220\u9664",
|
||||
// Clear formatting
|
||||
'Clear Formatting': '\u683c\u5f0f\u5316\u5220\u9664',
|
||||
|
||||
// Undo, redo
|
||||
"Undo": "\u64a4\u6d88",
|
||||
"Redo": "\u91cd\u590d",
|
||||
// Undo, redo
|
||||
Undo: '\u64a4\u6d88',
|
||||
Redo: '\u91cd\u590d',
|
||||
|
||||
// Select all
|
||||
"Select All": "\u5168\u9009",
|
||||
// Select all
|
||||
'Select All': '\u5168\u9009',
|
||||
|
||||
// Code view
|
||||
"Code View": "\u4ee3\u7801\u89c6\u56fe",
|
||||
// Code view
|
||||
'Code View': '\u4ee3\u7801\u89c6\u56fe',
|
||||
|
||||
// Quote
|
||||
"Quote": "\u5f15\u7528",
|
||||
"Increase": "\u589e\u52a0\u5f15\u7528",
|
||||
"Decrease": "\u5220\u9664\u5f15\u7528",
|
||||
// Quote
|
||||
Quote: '\u5f15\u7528',
|
||||
Increase: '\u589e\u52a0\u5f15\u7528',
|
||||
Decrease: '\u5220\u9664\u5f15\u7528',
|
||||
|
||||
// Quick Insert
|
||||
"Quick Insert": "\u5feb\u63d2"
|
||||
// Quick Insert
|
||||
'Quick Insert': '\u5feb\u63d2',
|
||||
},
|
||||
direction: "ltr"
|
||||
};
|
||||
direction: 'ltr',
|
||||
};
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
/**
|
||||
* @file Select Component
|
||||
* @author FEX
|
||||
* @file Select
|
||||
* @description
|
||||
* @author fex
|
||||
* @date 2017-11-07
|
||||
*
|
||||
*/
|
||||
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import * as React from 'react';
|
||||
import 'react-datetime/css/react-datetime.css';
|
||||
import Overlay from './Overlay';
|
||||
import PopOver from './PopOver';
|
||||
import Downshift, { ControllerStateAndHelpers } from 'downshift';
|
||||
import Downshift, {ControllerStateAndHelpers} from 'downshift';
|
||||
import * as cx from 'classnames';
|
||||
import { closeIcon } from './icons';
|
||||
import {closeIcon} from './icons';
|
||||
import * as matchSorter from 'match-sorter';
|
||||
import { noop, anyChanged } from '../utils/helper';
|
||||
import {noop, anyChanged} from '../utils/helper';
|
||||
import find = require('lodash/find');
|
||||
import isPlainObject = require('lodash/isPlainObject');
|
||||
import { highlight } from '../renderers/Form/Options';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface Option {
|
||||
label?: string;
|
||||
|
@ -28,9 +28,9 @@ export interface Option {
|
|||
children?: Options;
|
||||
visible?: boolean;
|
||||
hidden?: boolean;
|
||||
[propName:string]: any;
|
||||
};
|
||||
export interface Options extends Array<Option> {};
|
||||
[propName: string]: any;
|
||||
}
|
||||
export interface Options extends Array<Option> {}
|
||||
|
||||
export interface OptionProps {
|
||||
multi?: boolean;
|
||||
|
@ -42,11 +42,11 @@ export interface OptionProps {
|
|||
delimiter?: string;
|
||||
clearable?: boolean;
|
||||
placeholder?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type OptionValue = string | number | null | undefined | Option;
|
||||
|
||||
export function value2array(value:OptionValue | Array<OptionValue>, props:Partial<OptionProps>):Array<Option> {
|
||||
export function value2array(value: OptionValue | Array<OptionValue>, props: Partial<OptionProps>): Array<Option> {
|
||||
if (props.multi || props.multiple) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.split(props.delimiter || ',');
|
||||
|
@ -60,9 +60,7 @@ export function value2array(value:OptionValue | Array<OptionValue>, props:Partia
|
|||
value = [value];
|
||||
}
|
||||
|
||||
return value
|
||||
.map((value:any) => expandValue(value, props))
|
||||
.filter((item:any) => item) as Array<Option>;
|
||||
return value.map((value: any) => expandValue(value, props)).filter((item: any) => item) as Array<Option>;
|
||||
} else if (Array.isArray(value)) {
|
||||
value = value[0];
|
||||
}
|
||||
|
@ -71,16 +69,14 @@ export function value2array(value:OptionValue | Array<OptionValue>, props:Partia
|
|||
return expandedValue ? [expandedValue] : [];
|
||||
}
|
||||
|
||||
export function expandValue(value:OptionValue, props: Partial<OptionProps>):Option | null {
|
||||
export function expandValue(value: OptionValue, props: Partial<OptionProps>): Option | null {
|
||||
const valueType = typeof value;
|
||||
|
||||
if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') {
|
||||
return value as Option;
|
||||
}
|
||||
|
||||
let {
|
||||
options
|
||||
} = props;
|
||||
let {options} = props;
|
||||
|
||||
if (!options) {
|
||||
return null;
|
||||
|
@ -89,22 +85,22 @@ export function expandValue(value:OptionValue, props: Partial<OptionProps>):Opti
|
|||
return find(options, item => String(item[props.valueField || 'value']) === String(value)) as Option;
|
||||
}
|
||||
|
||||
export function normalizeOptions(options:string|{[propName:string]: string} | Array<string> | Options):Options {
|
||||
export function normalizeOptions(options: string | {[propName: string]: string} | Array<string> | Options): Options {
|
||||
if (typeof options === 'string') {
|
||||
return options.split(',').map(item => ({
|
||||
label: item,
|
||||
value: item
|
||||
value: item,
|
||||
}));
|
||||
} else if (Array.isArray(options as Array<string>) && typeof (options as Array<string>)[0] === 'string') {
|
||||
return (options as Array<string>).map(item => ({
|
||||
label: item,
|
||||
value: item
|
||||
}))
|
||||
value: item,
|
||||
}));
|
||||
} else if (Array.isArray(options as Options)) {
|
||||
return (options as Options).map(item => {
|
||||
let option = {
|
||||
...item,
|
||||
value: item && item.value
|
||||
value: item && item.value,
|
||||
};
|
||||
|
||||
if (typeof option.children !== 'undefined') {
|
||||
|
@ -115,8 +111,8 @@ export function normalizeOptions(options:string|{[propName:string]: string} | Ar
|
|||
});
|
||||
} else if (isPlainObject(options)) {
|
||||
return Object.keys(options).map(key => ({
|
||||
label: (options as {[propName:string]: string})[key] as string,
|
||||
value: key
|
||||
label: (options as {[propName: string]: string})[key] as string,
|
||||
value: key,
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -147,9 +143,9 @@ interface SelectProps {
|
|||
inline: boolean;
|
||||
disabled: boolean;
|
||||
popOverContainer?: any;
|
||||
promptTextCreator: (label:string) => string;
|
||||
promptTextCreator: (label: string) => string;
|
||||
onChange: (value: void | string | Option | Array<Option>) => void;
|
||||
onNewOptionClick: (value:Option) => void;
|
||||
onNewOptionClick: (value: Option) => void;
|
||||
onFocus?: Function;
|
||||
onBlur?: Function;
|
||||
}
|
||||
|
@ -176,14 +172,14 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
valueField: 'value',
|
||||
labelField: 'label',
|
||||
spinnerClassName: 'fa fa-spinner fa-spin fa-1x fa-fw',
|
||||
promptTextCreator: (label:string) => `新增:${label}`,
|
||||
promptTextCreator: (label: string) => `新增:${label}`,
|
||||
onNewOptionClick: noop,
|
||||
inline: false
|
||||
}
|
||||
inline: false,
|
||||
};
|
||||
|
||||
input:HTMLInputElement;
|
||||
input: HTMLInputElement;
|
||||
target: HTMLElement;
|
||||
constructor(props:SelectProps) {
|
||||
constructor(props: SelectProps) {
|
||||
super(props);
|
||||
|
||||
this.open = this.open.bind(this);
|
||||
|
@ -205,58 +201,62 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
isFocused: false,
|
||||
inputValue: '',
|
||||
highlightedIndex: -1,
|
||||
selection: value2array(props.value, props)
|
||||
selection: value2array(props.value, props),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
loadOptions
|
||||
} = this.props;
|
||||
const {loadOptions} = this.props;
|
||||
|
||||
loadOptions && loadOptions('');
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps:SelectProps) {
|
||||
componentWillReceiveProps(nextProps: SelectProps) {
|
||||
const props = this.props;
|
||||
|
||||
if (props.value !== nextProps.value || JSON.stringify(props.options) !== JSON.stringify(nextProps.options)) {
|
||||
this.setState({
|
||||
selection: value2array(nextProps.value, nextProps)
|
||||
selection: value2array(nextProps.value, nextProps),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
open() {
|
||||
this.props.disabled || this.setState({
|
||||
isOpen: true
|
||||
});
|
||||
this.props.disabled ||
|
||||
this.setState({
|
||||
isOpen: true,
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
this.setState({
|
||||
isOpen: false
|
||||
isOpen: false,
|
||||
});
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.props.disabled || this.setState({
|
||||
isOpen: !this.state.isOpen
|
||||
});
|
||||
this.props.disabled ||
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen,
|
||||
});
|
||||
}
|
||||
|
||||
onFocus(e:any) {
|
||||
this.props.disabled || this.setState({
|
||||
isFocused: true,
|
||||
}, this.focus);
|
||||
onFocus(e: any) {
|
||||
this.props.disabled ||
|
||||
this.setState(
|
||||
{
|
||||
isFocused: true,
|
||||
},
|
||||
this.focus
|
||||
);
|
||||
|
||||
this.props.onFocus && this.props.onFocus(e);
|
||||
}
|
||||
|
||||
onBlur(e:any) {
|
||||
onBlur(e: any) {
|
||||
this.setState({
|
||||
isFocused: false,
|
||||
inputValue: ''
|
||||
inputValue: '',
|
||||
});
|
||||
|
||||
this.props.onBlur && this.props.onBlur(e);
|
||||
|
@ -277,11 +277,11 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
return this.target as HTMLElement;
|
||||
}
|
||||
|
||||
inputRef(ref:HTMLInputElement) {
|
||||
inputRef(ref: HTMLInputElement) {
|
||||
this.input = ref;
|
||||
}
|
||||
|
||||
removeItem(index:number, e?: React.MouseEvent<HTMLElement>) {
|
||||
removeItem(index: number, e?: React.MouseEvent<HTMLElement>) {
|
||||
let value = this.props.value;
|
||||
const onChange = this.props.onChange;
|
||||
|
||||
|
@ -291,22 +291,19 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
onChange(value);
|
||||
}
|
||||
|
||||
handleInputChange(evt:React.ChangeEvent<HTMLInputElement>) {
|
||||
const {
|
||||
loadOptions
|
||||
} = this.props;
|
||||
handleInputChange(evt: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {loadOptions} = this.props;
|
||||
|
||||
this.setState({
|
||||
inputValue: evt.currentTarget.value
|
||||
}, () => loadOptions && loadOptions(this.state.inputValue));
|
||||
this.setState(
|
||||
{
|
||||
inputValue: evt.currentTarget.value,
|
||||
},
|
||||
() => loadOptions && loadOptions(this.state.inputValue)
|
||||
);
|
||||
}
|
||||
|
||||
handleChange(selectItem:any) {
|
||||
const {
|
||||
onChange,
|
||||
multiple,
|
||||
onNewOptionClick,
|
||||
} = this.props;
|
||||
handleChange(selectItem: any) {
|
||||
const {onChange, multiple, onNewOptionClick} = this.props;
|
||||
|
||||
let selection = this.state.selection;
|
||||
|
||||
|
@ -330,7 +327,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
}
|
||||
|
||||
handleStateChange(changes: any) {
|
||||
let update:any = {};
|
||||
let update: any = {};
|
||||
const loadOptions = this.props.loadOptions;
|
||||
let doLoad = false;
|
||||
|
||||
|
@ -349,46 +346,35 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
...update,
|
||||
inputValue: '',
|
||||
isOpen: false,
|
||||
isFocused: false
|
||||
}
|
||||
isFocused: false,
|
||||
};
|
||||
doLoad = true;
|
||||
break;
|
||||
case Downshift.stateChangeTypes.changeInput:
|
||||
update.highlightedIndex = 0
|
||||
update.highlightedIndex = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (Object.keys(update).length) {
|
||||
this.setState(update, doLoad && loadOptions ? () => loadOptions('') : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyPress(e:React.KeyboardEvent) {
|
||||
handleKeyPress(e: React.KeyboardEvent) {
|
||||
if (e.key === ' ') {
|
||||
this.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
clearValue(e:React.MouseEvent<any>) {
|
||||
clearValue(e: React.MouseEvent<any>) {
|
||||
const onChange = this.props.onChange;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onChange('');
|
||||
}
|
||||
|
||||
renderValue({
|
||||
inputValue,
|
||||
isOpen
|
||||
}:ControllerStateAndHelpers<any>) {
|
||||
const {
|
||||
multiple,
|
||||
placeholder,
|
||||
classPrefix: ns,
|
||||
labelField,
|
||||
searchable,
|
||||
creatable
|
||||
} = this.props;
|
||||
renderValue({inputValue, isOpen}: ControllerStateAndHelpers<any>) {
|
||||
const {multiple, placeholder, classPrefix: ns, labelField, searchable, creatable} = this.props;
|
||||
|
||||
const selection = this.state.selection;
|
||||
|
||||
|
@ -397,30 +383,30 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
}
|
||||
|
||||
if (!selection.length) {
|
||||
return creatable && inputValue ? null : (
|
||||
<div key="placeholder" className={`${ns}Select-placeholder`}>{placeholder}</div>
|
||||
return creatable && inputValue ? null : (
|
||||
<div key="placeholder" className={`${ns}Select-placeholder`}>
|
||||
{placeholder}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return selection.map((item, index) => multiple ? (
|
||||
<div className={`${ns}Select-value`} key={index}>
|
||||
<span className={`${ns}Select-valueIcon`} onClick={this.removeItem.bind(this, index)}>×</span>
|
||||
<span className={`${ns}Select-valueLabel`}>{item[labelField||'label']}</span>
|
||||
</div>
|
||||
) : inputValue && isOpen ? null : (
|
||||
<div className={`${ns}Select-value`} key={index}>
|
||||
{item.label}
|
||||
</div>
|
||||
));
|
||||
return selection.map((item, index) =>
|
||||
multiple ? (
|
||||
<div className={`${ns}Select-value`} key={index}>
|
||||
<span className={`${ns}Select-valueIcon`} onClick={this.removeItem.bind(this, index)}>
|
||||
×
|
||||
</span>
|
||||
<span className={`${ns}Select-valueLabel`}>{item[labelField || 'label']}</span>
|
||||
</div>
|
||||
) : inputValue && isOpen ? null : (
|
||||
<div className={`${ns}Select-value`} key={index}>
|
||||
{item.label}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
renderOuter({
|
||||
selectedItem,
|
||||
getItemProps,
|
||||
highlightedIndex,
|
||||
inputValue,
|
||||
isOpen
|
||||
}:ControllerStateAndHelpers<any>) {
|
||||
renderOuter({selectedItem, getItemProps, highlightedIndex, inputValue, isOpen}: ControllerStateAndHelpers<any>) {
|
||||
const {
|
||||
popOverContainer,
|
||||
options,
|
||||
|
@ -431,52 +417,64 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
creatable,
|
||||
promptTextCreator,
|
||||
multiple,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
} = this.props;
|
||||
|
||||
let filtedOptions:Array<Option> = inputValue && isOpen && !loadOptions ? matchSorter(options, inputValue, {keys: [labelField || 'label', valueField || 'value']}) : options.concat();
|
||||
|
||||
let filtedOptions: Array<Option> =
|
||||
inputValue && isOpen && !loadOptions
|
||||
? matchSorter(options, inputValue, {
|
||||
keys: [labelField || 'label', valueField || 'value'],
|
||||
})
|
||||
: options.concat();
|
||||
|
||||
if (multiple) {
|
||||
filtedOptions = filtedOptions.filter((option:any) => !~selectedItem.indexOf(option));
|
||||
filtedOptions = filtedOptions.filter((option: any) => !~selectedItem.indexOf(option));
|
||||
}
|
||||
|
||||
if (inputValue && creatable
|
||||
&& (
|
||||
!filtedOptions.length
|
||||
|| isOpen && loadOptions
|
||||
&& !matchSorter(options, inputValue, {
|
||||
keys: [labelField || 'label',
|
||||
valueField || 'value']
|
||||
}).length
|
||||
)) {
|
||||
if (
|
||||
inputValue &&
|
||||
creatable &&
|
||||
(!filtedOptions.length ||
|
||||
(isOpen &&
|
||||
loadOptions &&
|
||||
!matchSorter(options, inputValue, {
|
||||
keys: [labelField || 'label', valueField || 'value'],
|
||||
}).length))
|
||||
) {
|
||||
filtedOptions.push({
|
||||
[labelField]: inputValue,
|
||||
[valueField]: inputValue,
|
||||
isNew: true
|
||||
isNew: true,
|
||||
});
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<div className={cx('Select-menu')}>
|
||||
{filtedOptions.length ? filtedOptions.map((item, index) => (
|
||||
<div
|
||||
{...getItemProps({
|
||||
key: index,
|
||||
index,
|
||||
item,
|
||||
disabled: item.disabled
|
||||
})}
|
||||
className={cx(`Select-option`, {
|
||||
'is-disabled': item.disabled,
|
||||
'is-highlight': highlightedIndex === index,
|
||||
'is-active': selectedItem === item || Array.isArray(selectedItem) && ~selectedItem.indexOf(item)
|
||||
})}
|
||||
>
|
||||
{item.isNew ? (
|
||||
promptTextCreator(item.label as string)
|
||||
) : item.disabled ? item[labelField] : highlight(item[labelField], inputValue as string, cx('Select-option-hl'))}
|
||||
</div>
|
||||
)) : (
|
||||
{filtedOptions.length ? (
|
||||
filtedOptions.map((item, index) => (
|
||||
<div
|
||||
{...getItemProps({
|
||||
key: index,
|
||||
index,
|
||||
item,
|
||||
disabled: item.disabled,
|
||||
})}
|
||||
className={cx(`Select-option`, {
|
||||
'is-disabled': item.disabled,
|
||||
'is-highlight': highlightedIndex === index,
|
||||
'is-active':
|
||||
selectedItem === item ||
|
||||
(Array.isArray(selectedItem) && ~selectedItem.indexOf(item)),
|
||||
})}
|
||||
>
|
||||
{item.isNew
|
||||
? promptTextCreator(item.label as string)
|
||||
: item.disabled
|
||||
? item[labelField]
|
||||
: highlight(item[labelField], inputValue as string, cx('Select-option-hl'))}
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className={cx('Select-option Select-option--placeholder')}>{noResultsText}</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -484,13 +482,8 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
|
||||
if (popOverContainer) {
|
||||
return (
|
||||
<Overlay
|
||||
container={popOverContainer}
|
||||
placement="left-bottom-left-top"
|
||||
target={this.getTarget}
|
||||
show
|
||||
>
|
||||
<PopOver
|
||||
<Overlay container={popOverContainer} placement="left-bottom-left-top" target={this.getTarget} show>
|
||||
<PopOver
|
||||
className={cx('Select-popover')}
|
||||
style={{width: this.target ? this.target.offsetWidth : 'auto'}}
|
||||
>
|
||||
|
@ -499,13 +492,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
</Overlay>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div
|
||||
className={cx('Select-menuOuter')}
|
||||
>
|
||||
{menu}
|
||||
</div>
|
||||
);
|
||||
return <div className={cx('Select-menuOuter')}>{menu}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,64 +523,72 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
|||
onChange={this.handleChange}
|
||||
onStateChange={this.handleStateChange}
|
||||
onOuterClick={this.close}
|
||||
itemToString={(item) => item ? item[labelField] : ''}
|
||||
>{(options:ControllerStateAndHelpers<any>) => {
|
||||
const {
|
||||
isOpen,
|
||||
getInputProps
|
||||
} = options;
|
||||
return (
|
||||
<div
|
||||
tabIndex={searchable || disabled ? -1 : 0}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onClick={this.toggle}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
className={cx(`Select`, {
|
||||
[`Select--multi`]: multiple,
|
||||
[`Select--inline`]: inline,
|
||||
[`Select--searchable`]: searchable,
|
||||
'is-opened': isOpen,
|
||||
'is-focused': this.state.isFocused,
|
||||
'is-disabled': disabled
|
||||
}, className)}
|
||||
>
|
||||
<div className={cx(`Select-valueWrap`)}>
|
||||
{this.renderValue(options)}
|
||||
{searchable ? (
|
||||
<input
|
||||
{...getInputProps({
|
||||
className: cx(`Select-input`),
|
||||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
onKeyDown: (event) => {
|
||||
if (event.key === 'Backspace' && !inputValue) {
|
||||
this.removeItem(value.length - 1);
|
||||
}
|
||||
},
|
||||
onChange: this.handleInputChange,
|
||||
ref: this.inputRef
|
||||
})}
|
||||
/>
|
||||
itemToString={item => (item ? item[labelField] : '')}
|
||||
>
|
||||
{(options: ControllerStateAndHelpers<any>) => {
|
||||
const {isOpen, getInputProps} = options;
|
||||
return (
|
||||
<div
|
||||
tabIndex={searchable || disabled ? -1 : 0}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
onClick={this.toggle}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
className={cx(
|
||||
`Select`,
|
||||
{
|
||||
[`Select--multi`]: multiple,
|
||||
[`Select--inline`]: inline,
|
||||
[`Select--searchable`]: searchable,
|
||||
'is-opened': isOpen,
|
||||
'is-focused': this.state.isFocused,
|
||||
'is-disabled': disabled,
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className={cx(`Select-valueWrap`)}>
|
||||
{this.renderValue(options)}
|
||||
{searchable ? (
|
||||
<input
|
||||
{...getInputProps({
|
||||
className: cx(`Select-input`),
|
||||
onFocus: this.onFocus,
|
||||
onBlur: this.onBlur,
|
||||
onKeyDown: event => {
|
||||
if (event.key === 'Backspace' && !inputValue) {
|
||||
this.removeItem(value.length - 1);
|
||||
}
|
||||
},
|
||||
onChange: this.handleInputChange,
|
||||
ref: this.inputRef,
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{clearable && !disabled && value && value.length ? (
|
||||
<a onClick={this.clearValue} className={cx('Select-clear')}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
) : null}
|
||||
{loading ? (
|
||||
<span className={cx('Select-spinner')}>
|
||||
<i className={spinnerClassName} />
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
<span className={cx('Select-arrow')} />
|
||||
{isOpen ? this.renderOuter(options) : null}
|
||||
</div>
|
||||
{clearable && !disabled && value && value.length ? (<a onClick={this.clearValue} className={cx('Select-clear')}>{closeIcon}</a>) : null}
|
||||
{loading ? (
|
||||
<span className={cx('Select-spinner')}>
|
||||
<i className={spinnerClassName} />
|
||||
</span>
|
||||
) : null}
|
||||
|
||||
<span className={cx('Select-arrow')}></span>
|
||||
{isOpen ? this.renderOuter(options) : null}
|
||||
</div>
|
||||
);
|
||||
}}</Downshift>
|
||||
);
|
||||
}}
|
||||
</Downshift>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default themeable(uncontrollable(Select, {
|
||||
value: 'onChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(Select, {
|
||||
value: 'onChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
/**
|
||||
* @file Spinner
|
||||
* @description
|
||||
* @author fex
|
||||
* @date 2017-11-07
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Renderer,
|
||||
RendererProps
|
||||
} from '../factory';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
|
||||
interface SpinnerProps extends RendererProps {
|
||||
overlay: boolean;
|
||||
|
@ -13,44 +17,34 @@ interface SpinnerProps extends RendererProps {
|
|||
size: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
};
|
||||
}
|
||||
|
||||
export class Spinner extends React.Component<SpinnerProps, object> {
|
||||
static defaultProps= {
|
||||
static defaultProps = {
|
||||
overlay: false,
|
||||
spinnerClassName: '',
|
||||
mode: '',
|
||||
size: ''
|
||||
size: '',
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
mode,
|
||||
overlay,
|
||||
spinnerClassName,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
size
|
||||
} = this.props;
|
||||
const {mode, overlay, spinnerClassName, classPrefix: ns, classnames: cx, size} = this.props;
|
||||
|
||||
const spinner = (
|
||||
<div className={cx(`${ns}Spinner`, spinnerClassName, {
|
||||
[`Spinner--${mode}`]: !!mode,
|
||||
[`Spinner--${size}`]: !!size
|
||||
})}>
|
||||
</div>
|
||||
<div
|
||||
className={cx(`${ns}Spinner`, spinnerClassName, {
|
||||
[`Spinner--${mode}`]: !!mode,
|
||||
[`Spinner--${size}`]: !!size,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
|
||||
if (overlay) {
|
||||
return (
|
||||
<div className={cx(`Spinner-overlay`)}>
|
||||
{spinner}
|
||||
</div>
|
||||
);
|
||||
return <div className={cx(`Spinner-overlay`)}>{spinner}</div>;
|
||||
}
|
||||
|
||||
return spinner;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Spinner);
|
||||
export default themeable(Spinner);
|
||||
|
|
|
@ -1,36 +1,37 @@
|
|||
/**
|
||||
* @file switch组件
|
||||
* @file Switch
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
|
||||
const sizeMap = {
|
||||
md: 'i-switch-md',
|
||||
lg: 'i-switch-lg',
|
||||
middle: 'i-switch-md',
|
||||
large: 'i-switch-lg'
|
||||
large: 'i-switch-lg',
|
||||
};
|
||||
|
||||
const levelMap = {
|
||||
info: 'bg-info',
|
||||
primary: 'bg-primary',
|
||||
danger: 'bg-danger'
|
||||
danger: 'bg-danger',
|
||||
};
|
||||
|
||||
interface SwitchProps {
|
||||
id?: string;
|
||||
size?: 'md' | 'lg' | 'middle' | 'large',
|
||||
level?: 'info' | 'primary' | 'danger',
|
||||
className?: string,
|
||||
size?: 'md' | 'lg' | 'middle' | 'large';
|
||||
level?: 'info' | 'primary' | 'danger';
|
||||
className?: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
onChange?: (checked:boolean) => void,
|
||||
value?: any,
|
||||
inline?: boolean,
|
||||
onChange?: (checked: boolean) => void;
|
||||
value?: any;
|
||||
inline?: boolean;
|
||||
trueValue?: any;
|
||||
falseValue?: any;
|
||||
disabled?: boolean;
|
||||
|
@ -41,21 +42,17 @@ interface SwitchProps {
|
|||
export class Switch extends React.PureComponent<SwitchProps, any> {
|
||||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false
|
||||
falseValue: false,
|
||||
};
|
||||
|
||||
constructor(props:SwitchProps) {
|
||||
constructor(props: SwitchProps) {
|
||||
super(props);
|
||||
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this);
|
||||
}
|
||||
|
||||
hanldeCheck(e:React.ChangeEvent<HTMLInputElement>) {
|
||||
const {
|
||||
trueValue,
|
||||
falseValue,
|
||||
onChange
|
||||
} = this.props;
|
||||
hanldeCheck(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {trueValue, falseValue, onChange} = this.props;
|
||||
|
||||
if (!onChange) {
|
||||
return;
|
||||
|
@ -82,26 +79,31 @@ export class Switch extends React.PureComponent<SwitchProps, any> {
|
|||
...rest
|
||||
} = this.props;
|
||||
|
||||
className = (className ? className : '')
|
||||
+ (size && sizeMap[size] ? ` ${sizeMap[size]}` : '')
|
||||
+ (level && levelMap[level] ? ` ${levelMap[level]}` : '');
|
||||
className =
|
||||
(className ? className : '') +
|
||||
(size && sizeMap[size] ? ` ${sizeMap[size]}` : '') +
|
||||
(level && levelMap[level] ? ` ${levelMap[level]}` : '');
|
||||
|
||||
return (
|
||||
<label
|
||||
className={cx(`Switch`, disabled ? 'is-disabled' : '', className)}
|
||||
>
|
||||
<label className={cx(`Switch`, disabled ? 'is-disabled' : '', className)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={typeof checked !== 'undefined' ? checked : typeof value === 'undefined' ? false : value == trueValue}
|
||||
checked={
|
||||
typeof checked !== 'undefined'
|
||||
? checked
|
||||
: typeof value === 'undefined'
|
||||
? false
|
||||
: value == trueValue
|
||||
}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
{...rest}
|
||||
/>
|
||||
/>
|
||||
<i />
|
||||
</label>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Switch);
|
||||
export default themeable(Switch);
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
import * as Textarea from 'react-textarea-autosize';
|
||||
export default Textarea;
|
||||
export default Textarea;
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
/**
|
||||
* @file 页面标题组件。
|
||||
*
|
||||
* 参数说明:
|
||||
* @file TitleBar。
|
||||
* @description
|
||||
* @author fex
|
||||
* @param 参数说明:
|
||||
* title 标题内容
|
||||
* titleClassName 标题类名,默认为 bg-light lter b-b
|
||||
* right 可以传入右侧节点, 当有右侧时自动采用 hbox 来左右布局。
|
||||
*
|
||||
*
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface TitleBarProps {
|
||||
className?: string;
|
||||
|
@ -23,27 +22,17 @@ interface TitleBarProps {
|
|||
}
|
||||
|
||||
export class TitleBar extends React.PureComponent<TitleBarProps, any> {
|
||||
|
||||
static defaultProps = {
|
||||
className: 'bg-light lter b-b',
|
||||
title: '标题',
|
||||
titleClassName: 'm-n font-thin h3',
|
||||
right: false
|
||||
right: false,
|
||||
};
|
||||
|
||||
render() : JSX.Element {
|
||||
const {
|
||||
className,
|
||||
title,
|
||||
titleClassName,
|
||||
right
|
||||
} = this.props;
|
||||
render(): JSX.Element {
|
||||
const {className, title, titleClassName, right} = this.props;
|
||||
|
||||
let left = title ? (
|
||||
<div className={titleClassName}>
|
||||
{title}
|
||||
</div>
|
||||
) : null;
|
||||
let left = title ? <div className={titleClassName}>{title}</div> : null;
|
||||
|
||||
let body = left;
|
||||
|
||||
|
@ -55,17 +44,11 @@ export class TitleBar extends React.PureComponent<TitleBarProps, any> {
|
|||
</div>
|
||||
);
|
||||
} else {
|
||||
body = (
|
||||
<div className="wrapper">{left}</div>
|
||||
);
|
||||
body = <div className="wrapper">{left}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{body}
|
||||
</div>
|
||||
);
|
||||
return <div className={className}>{body}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TitleBar);
|
||||
export default themeable(TitleBar);
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
/**
|
||||
* @file toast提示组件, 单例模式,App级别只需要一个ToastComponent,引入了多个会兼容,也只有第一个生效
|
||||
* @file Toast
|
||||
* @description toast提示组件, 单例模式,App级别只需要一个ToastComponent,引入了多个会兼容,也只有第一个生效
|
||||
* @author fex
|
||||
*/
|
||||
import Transition, {
|
||||
ENTERED,
|
||||
ENTERING,
|
||||
EXITING,
|
||||
EXITED
|
||||
} from 'react-transition-group/Transition';
|
||||
|
||||
import Transition, {ENTERED, ENTERING, EXITING, EXITED} from 'react-transition-group/Transition';
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import Html from './Html';
|
||||
import { uuid, autobind } from '../utils/helper';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {uuid, autobind} from '../utils/helper';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
const fadeStyles: {
|
||||
[propName: string]: string;
|
||||
|
@ -20,11 +17,15 @@ const fadeStyles: {
|
|||
[ENTERING]: 'in',
|
||||
[ENTERED]: '',
|
||||
[EXITING]: 'out',
|
||||
[EXITED]: 'hidden'
|
||||
[EXITED]: 'hidden',
|
||||
};
|
||||
|
||||
let toastRef: any = null;
|
||||
let config: {closeButton?: boolean; timeOut?: number; extendedTimeOut?: number;} = {};
|
||||
let config: {
|
||||
closeButton?: boolean;
|
||||
timeOut?: number;
|
||||
extendedTimeOut?: number;
|
||||
} = {};
|
||||
|
||||
const show = (content: string, title: string = '', conf: any = {}, method: string) => {
|
||||
if (!toastRef || !toastRef[method]) {
|
||||
|
@ -48,36 +49,32 @@ interface Item {
|
|||
body: string;
|
||||
level: 'info' | 'success' | 'error' | 'warning';
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ToastComponentState {
|
||||
items: Array<Item>;
|
||||
}
|
||||
|
||||
export class ToastComponent extends React.PureComponent<ToastComponentProps, ToastComponentState> {
|
||||
export class ToastComponent extends React.PureComponent<ToastComponentProps, ToastComponentState> {
|
||||
static defaultProps = {
|
||||
position: 'top-right',
|
||||
closeButton: false,
|
||||
timeOut: 5000,
|
||||
extendedTimeOut: 3000
|
||||
extendedTimeOut: 3000,
|
||||
};
|
||||
|
||||
// 当前ToastComponent是否真正render了
|
||||
hasRendered = false;
|
||||
state:ToastComponentState = {
|
||||
items: []
|
||||
state: ToastComponentState = {
|
||||
items: [],
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
const {
|
||||
closeButton,
|
||||
timeOut,
|
||||
extendedTimeOut
|
||||
} = this.props;
|
||||
const {closeButton, timeOut, extendedTimeOut} = this.props;
|
||||
config = {
|
||||
closeButton,
|
||||
timeOut,
|
||||
extendedTimeOut
|
||||
extendedTimeOut,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -89,7 +86,7 @@ export class ToastComponent extends React.PureComponent<ToastComponentProps, Toa
|
|||
componentWillUnmount() {
|
||||
if (this.hasRendered) {
|
||||
toastRef = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifiy(level: string, content: string, title?: string, config?: any) {
|
||||
|
@ -99,10 +96,10 @@ export class ToastComponent extends React.PureComponent<ToastComponentProps, Toa
|
|||
body: content,
|
||||
level,
|
||||
...config,
|
||||
id: uuid()
|
||||
id: uuid(),
|
||||
});
|
||||
this.setState({
|
||||
items
|
||||
items,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -126,11 +123,11 @@ export class ToastComponent extends React.PureComponent<ToastComponentProps, Toa
|
|||
this.notifiy('warning', content, title, config);
|
||||
}
|
||||
|
||||
handleDismissed(index:number) {
|
||||
handleDismissed(index: number) {
|
||||
const items = this.state.items.concat();
|
||||
items.splice(index, 1);
|
||||
this.setState({
|
||||
items: items
|
||||
items: items,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -139,18 +136,18 @@ export class ToastComponent extends React.PureComponent<ToastComponentProps, Toa
|
|||
return null;
|
||||
}
|
||||
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
timeOut,
|
||||
position
|
||||
} = this.props;
|
||||
const {classPrefix: ns, className, timeOut, position} = this.props;
|
||||
const items = this.state.items;
|
||||
|
||||
return (
|
||||
<div className={cx(`${ns}Toast-wrap ${ns}Toast-wrap--${position.replace(/\-(\w)/g, (_, l) => l.toUpperCase())}`, className)}>
|
||||
<div
|
||||
className={cx(
|
||||
`${ns}Toast-wrap ${ns}Toast-wrap--${position.replace(/\-(\w)/g, (_, l) => l.toUpperCase())}`,
|
||||
className
|
||||
)}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<ToastMessage
|
||||
<ToastMessage
|
||||
key={item.id}
|
||||
classPrefix={ns}
|
||||
title={item.title}
|
||||
|
@ -180,7 +177,7 @@ interface ToastMessageProps {
|
|||
|
||||
interface ToastMessageState {
|
||||
visible: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export class ToastMessage extends React.Component<ToastMessageProps> {
|
||||
static defaultProps = {
|
||||
|
@ -188,14 +185,14 @@ export class ToastMessage extends React.Component<ToastMessageProps> {
|
|||
classPrefix: '',
|
||||
position: 'top-right',
|
||||
allowHtml: true,
|
||||
level: 'info'
|
||||
level: 'info',
|
||||
};
|
||||
|
||||
state = {
|
||||
visible: false
|
||||
visible: false,
|
||||
};
|
||||
|
||||
content:React.RefObject<HTMLDivElement>;
|
||||
content: React.RefObject<HTMLDivElement>;
|
||||
timer: NodeJS.Timeout;
|
||||
constructor(props: ToastMessageProps) {
|
||||
super(props);
|
||||
|
@ -213,7 +210,7 @@ export class ToastMessage extends React.Component<ToastMessageProps> {
|
|||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
visible: true
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -224,7 +221,7 @@ export class ToastMessage extends React.Component<ToastMessageProps> {
|
|||
handleMouseLeave() {
|
||||
this.handleEntered();
|
||||
}
|
||||
|
||||
|
||||
handleEntered() {
|
||||
const timeOut = this.props.timeOut;
|
||||
this.timer = setTimeout(this.close, timeOut);
|
||||
|
@ -233,20 +230,12 @@ export class ToastMessage extends React.Component<ToastMessageProps> {
|
|||
close() {
|
||||
clearTimeout(this.timer);
|
||||
this.setState({
|
||||
visible: false
|
||||
visible: false,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
onDismiss,
|
||||
classPrefix: ns,
|
||||
position,
|
||||
title,
|
||||
body,
|
||||
allowHtml,
|
||||
level
|
||||
} = this.props;
|
||||
const {onDismiss, classPrefix: ns, position, title, body, allowHtml, level} = this.props;
|
||||
|
||||
return (
|
||||
<Transition
|
||||
|
@ -266,22 +255,20 @@ export class ToastMessage extends React.Component<ToastMessageProps> {
|
|||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
ref={this.content}
|
||||
className={cx(`${ns}Toast ${ns}Toast--${level}`, fadeStyles[status])}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.close}
|
||||
>
|
||||
{title ? (<div className={`${ns}Toast-title`}>{title}</div>) : null}
|
||||
<div className={`${ns}Toast-body`}>
|
||||
{allowHtml ? (<Html html={body} />) : body}
|
||||
</div>
|
||||
{title ? <div className={`${ns}Toast-title`}>{title}</div> : null}
|
||||
<div className={`${ns}Toast-body`}>{allowHtml ? <Html html={body} /> : body}</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,6 +277,5 @@ export const toast = {
|
|||
success: (content: string, title?: string, conf?: any) => show(content, title, conf, 'success'),
|
||||
error: (content: string, title?: string, conf?: any) => show(content, title, conf, 'error'),
|
||||
info: (content: string, title?: string, conf?: any) => show(content, title, conf, 'info'),
|
||||
warning: (content: string, title?: string, conf?: any) => show(content, title, conf, 'warning')
|
||||
warning: (content: string, title?: string, conf?: any) => show(content, title, conf, 'warning'),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
/**
|
||||
* @file Tooltip
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as cx from 'classnames';
|
||||
import { classPrefix, classnames } from '../themes/default';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
interface TooltipProps extends React.HTMLProps<HTMLDivElement> {
|
||||
title?: string;
|
||||
|
@ -12,13 +18,12 @@ interface TooltipProps extends React.HTMLProps<HTMLDivElement> {
|
|||
style?: any;
|
||||
arrowProps?: any;
|
||||
placement?: string;
|
||||
[propName:string]: any;
|
||||
};
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
export class Tooltip extends React.Component<TooltipProps> {
|
||||
|
||||
static defaultProps = {
|
||||
className: ''
|
||||
className: '',
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -39,22 +44,18 @@ export class Tooltip extends React.Component<TooltipProps> {
|
|||
} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
{...rest}
|
||||
className={cx(`Tooltip`, placement ? `Tooltip--${placement}` : '', className)}
|
||||
style={style}
|
||||
role="tooltip"
|
||||
>
|
||||
<div className={cx(`Tooltip-arrow`)} {...arrowProps} />
|
||||
{title ? (
|
||||
<div className={cx('Tooltip-title')}>{title}</div>
|
||||
) : null}
|
||||
<div className={cx('Tooltip-body')}>
|
||||
{children}
|
||||
</div>
|
||||
{title ? <div className={cx('Tooltip-title')}>{title}</div> : null}
|
||||
<div className={cx('Tooltip-body')}>{children}</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Tooltip);
|
||||
export default themeable(Tooltip);
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
/**
|
||||
* @file tooltip
|
||||
* @file TooltipWrapper
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint fecs-indent: [0, "space", 2, 2] */
|
||||
|
||||
import React = require('react');
|
||||
import {
|
||||
Overlay
|
||||
} from 'react-overlays';
|
||||
import {Overlay} from 'react-overlays';
|
||||
import Html from './Html';
|
||||
import uncontrollable = require('uncontrollable');
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import Tooltip from './Tooltip';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
|
||||
export interface TooltipObject {
|
||||
title?: string;
|
||||
content?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type Trigger = 'hover' | 'click' | 'focus';
|
||||
|
||||
export interface TooltipWrapperProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
placement: "top" | "right" | "bottom" | "left";
|
||||
placement: 'top' | 'right' | 'bottom' | 'left';
|
||||
tooltip?: string | TooltipObject;
|
||||
container?: React.ReactNode;
|
||||
trigger: Trigger | Array<Trigger>;
|
||||
|
@ -39,11 +37,11 @@ interface TooltipWrapperState {
|
|||
}
|
||||
|
||||
export class TooltipWrapper extends React.Component<TooltipWrapperProps, TooltipWrapperState> {
|
||||
static defaultProps:Pick<TooltipWrapperProps, 'placement' | 'trigger' | 'rootClose' | 'delay'> = {
|
||||
static defaultProps: Pick<TooltipWrapperProps, 'placement' | 'trigger' | 'rootClose' | 'delay'> = {
|
||||
placement: 'top',
|
||||
trigger: ['hover', 'focus'],
|
||||
rootClose: false,
|
||||
delay: 200
|
||||
delay: 200,
|
||||
};
|
||||
|
||||
target: HTMLElement;
|
||||
|
@ -64,7 +62,7 @@ export class TooltipWrapper extends React.Component<TooltipWrapperProps, Tooltip
|
|||
this.handleMouseOut = this.handleMouseOut.bind(this);
|
||||
|
||||
this.state = {
|
||||
show: false
|
||||
show: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -76,19 +74,19 @@ export class TooltipWrapper extends React.Component<TooltipWrapperProps, Tooltip
|
|||
return this.target ? findDOMNode(this.target) : null;
|
||||
}
|
||||
|
||||
targetRef(ref:HTMLElement) {
|
||||
targetRef(ref: HTMLElement) {
|
||||
this.target = ref;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.setState({
|
||||
show: true
|
||||
show: true,
|
||||
});
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.setState({
|
||||
show: false
|
||||
show: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -109,58 +107,48 @@ export class TooltipWrapper extends React.Component<TooltipWrapperProps, Tooltip
|
|||
|
||||
handleHide() {
|
||||
clearTimeout(this.timer);
|
||||
const {
|
||||
delay
|
||||
} = this.props;
|
||||
const {delay} = this.props;
|
||||
|
||||
this.timer = setTimeout(this.hide, delay);
|
||||
}
|
||||
|
||||
|
||||
handleFocus(e:any) {
|
||||
const { onFocus } = this.getChildProps();
|
||||
handleFocus(e: any) {
|
||||
const {onFocus} = this.getChildProps();
|
||||
this.handleShow();
|
||||
onFocus && onFocus(e);
|
||||
}
|
||||
|
||||
handleBlur(e:any) {
|
||||
const { onBlur } = this.getChildProps();
|
||||
handleBlur(e: any) {
|
||||
const {onBlur} = this.getChildProps();
|
||||
this.handleHide();
|
||||
onBlur && onBlur(e);
|
||||
}
|
||||
|
||||
handleMouseOver(e:any) {
|
||||
handleMouseOver(e: any) {
|
||||
this.handleMouseOverOut(this.handleShow, e, 'fromElement');
|
||||
}
|
||||
|
||||
handleMouseOut(e:any) {
|
||||
handleMouseOut(e: any) {
|
||||
this.handleMouseOverOut(this.handleHide, e, 'toElement');
|
||||
}
|
||||
|
||||
handleMouseOverOut(handler:Function, e:React.MouseEvent<HTMLElement>, relatedNative:string) {
|
||||
handleMouseOverOut(handler: Function, e: React.MouseEvent<HTMLElement>, relatedNative: string) {
|
||||
const target = e.currentTarget;
|
||||
const related:any = e.relatedTarget || (e as any).nativeEvent[relatedNative];
|
||||
|
||||
const related: any = e.relatedTarget || (e as any).nativeEvent[relatedNative];
|
||||
|
||||
if ((!related || related !== target) && !target.contains(related)) {
|
||||
handler(e);
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e:any) {
|
||||
const { onClick } = this.getChildProps();
|
||||
handleClick(e: any) {
|
||||
const {onClick} = this.getChildProps();
|
||||
this.state.show ? this.hide() : this.show();
|
||||
onClick && onClick(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tooltip,
|
||||
children,
|
||||
placement,
|
||||
container,
|
||||
trigger,
|
||||
rootClose,
|
||||
} = this.props;
|
||||
const {tooltip, children, placement, container, trigger, rootClose} = this.props;
|
||||
|
||||
const child = React.Children.only(children);
|
||||
|
||||
|
@ -168,9 +156,9 @@ export class TooltipWrapper extends React.Component<TooltipWrapperProps, Tooltip
|
|||
return child;
|
||||
}
|
||||
|
||||
const childProps:any = {
|
||||
const childProps: any = {
|
||||
ref: this.targetRef,
|
||||
key: 'target'
|
||||
key: 'target',
|
||||
};
|
||||
|
||||
const triggers = Array.isArray(trigger) ? trigger.concat() : [trigger];
|
||||
|
@ -201,18 +189,16 @@ export class TooltipWrapper extends React.Component<TooltipWrapperProps, Tooltip
|
|||
placement={placement}
|
||||
container={container}
|
||||
>
|
||||
<Tooltip
|
||||
title={typeof tooltip !== 'string' ? tooltip.title : undefined}
|
||||
>
|
||||
<Html
|
||||
html={typeof tooltip === 'string' ? tooltip : tooltip.content}
|
||||
/>
|
||||
<Tooltip title={typeof tooltip !== 'string' ? tooltip.title : undefined}>
|
||||
<Html html={typeof tooltip === 'string' ? tooltip : tooltip.content} />
|
||||
</Tooltip>
|
||||
</Overlay>
|
||||
</Overlay>,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(uncontrollable(TooltipWrapper, {
|
||||
show: 'onVisibleChange'
|
||||
}));
|
||||
export default themeable(
|
||||
uncontrollable(TooltipWrapper, {
|
||||
show: 'onVisibleChange',
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
/**
|
||||
* @file 树形组件
|
||||
* @file Tree
|
||||
* @description 树形组件
|
||||
* @author fex
|
||||
*/
|
||||
/* eslint fecs-indent: [2, "space", 2, 0] */
|
||||
|
||||
import * as React from 'react';
|
||||
import { eachTree, isVisible } from '../utils/helper';
|
||||
import {
|
||||
Option,
|
||||
Options,
|
||||
value2array,
|
||||
} from './Checkboxes';
|
||||
import { ClassNamesFn, themeable } from '../theme';
|
||||
import { highlight } from '../renderers/Form/Options';
|
||||
import {eachTree, isVisible} from '../utils/helper';
|
||||
import {Option, Options, value2array} from './Checkboxes';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {highlight} from '../renderers/Form/Options';
|
||||
|
||||
interface TreeSelectorProps {
|
||||
classPrefix: string;
|
||||
|
@ -59,7 +55,7 @@ interface TreeSelectorProps {
|
|||
|
||||
interface TreeSelectorState {
|
||||
value: Array<any>;
|
||||
unfolded: { [propName: string]: string };
|
||||
unfolded: {[propName: string]: string};
|
||||
}
|
||||
|
||||
export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelectorState> {
|
||||
|
@ -85,7 +81,7 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
rootLabel: '顶级',
|
||||
rootValue: 0,
|
||||
cascade: false,
|
||||
selfDisabledAffectChildren: true
|
||||
selfDisabledAffectChildren: true,
|
||||
};
|
||||
|
||||
componentWillMount() {
|
||||
|
@ -97,7 +93,6 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
|
||||
const props = this.props;
|
||||
|
||||
|
||||
this.setState({
|
||||
value: value2array(props.value, {
|
||||
joinValues: props.joinValues,
|
||||
|
@ -105,9 +100,9 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
multiple: props.multiple,
|
||||
delimiter: props.delimiter,
|
||||
valueField: props.valueField,
|
||||
options: props.data
|
||||
options: props.data,
|
||||
}),
|
||||
unfolded: this.syncUnFolded(props)
|
||||
unfolded: this.syncUnFolded(props),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -121,12 +116,12 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
multiple: nextProps.multiple,
|
||||
delimiter: nextProps.delimiter,
|
||||
valueField: nextProps.valueField,
|
||||
options: nextProps.data
|
||||
options: nextProps.data,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.props.data !== nextProps.data) {
|
||||
toUpdate.unfolded = this.syncUnFolded(nextProps)
|
||||
toUpdate.unfolded = this.syncUnFolded(nextProps);
|
||||
}
|
||||
|
||||
this.setState(toUpdate);
|
||||
|
@ -134,11 +129,8 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
|
||||
syncUnFolded(props: TreeSelectorProps) {
|
||||
// 初始化树节点的展开状态
|
||||
let unfolded: { [propName: string]: string } = {};
|
||||
const {
|
||||
foldedField,
|
||||
unfoldedField
|
||||
} = this.props;
|
||||
let unfolded: {[propName: string]: string} = {};
|
||||
const {foldedField, unfoldedField} = this.props;
|
||||
|
||||
eachTree(props.data, (node: Option, index, level) => {
|
||||
if (node.children && node.children.length) {
|
||||
|
@ -165,37 +157,35 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
this.setState({
|
||||
unfolded: {
|
||||
...this.state.unfolded,
|
||||
[node[this.props.valueField as string]]: !this.state.unfolded[node[this.props.valueField as string]]
|
||||
}
|
||||
[node[this.props.valueField as string]]: !this.state.unfolded[node[this.props.valueField as string]],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
clearSelect() {
|
||||
this.setState({
|
||||
value: []
|
||||
}, () => {
|
||||
const {
|
||||
joinValues,
|
||||
rootValue,
|
||||
onChange
|
||||
} = this.props;
|
||||
this.setState(
|
||||
{
|
||||
value: [],
|
||||
},
|
||||
() => {
|
||||
const {joinValues, rootValue, onChange} = this.props;
|
||||
|
||||
onChange(joinValues ? rootValue : []);
|
||||
});
|
||||
onChange(joinValues ? rootValue : []);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleSelect(node: any, value?: any) {
|
||||
this.setState({
|
||||
value: [node]
|
||||
}, () => {
|
||||
const {
|
||||
joinValues,
|
||||
valueField,
|
||||
onChange
|
||||
} = this.props;
|
||||
this.setState(
|
||||
{
|
||||
value: [node],
|
||||
},
|
||||
() => {
|
||||
const {joinValues, valueField, onChange} = this.props;
|
||||
|
||||
onChange(joinValues ? node[valueField as string] : node);
|
||||
});
|
||||
onChange(joinValues ? node[valueField as string] : node);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleCheck(item: any, checked: boolean) {
|
||||
|
@ -263,22 +253,29 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
value
|
||||
}, () => {
|
||||
const {
|
||||
joinValues,
|
||||
extractValue,
|
||||
valueField,
|
||||
delimiter,
|
||||
onChange
|
||||
} = this.props;
|
||||
this.setState(
|
||||
{
|
||||
value,
|
||||
},
|
||||
() => {
|
||||
const {joinValues, extractValue, valueField, delimiter, onChange} = this.props;
|
||||
|
||||
onChange(joinValues ? value.map(item => item[valueField as string]).join(delimiter) : extractValue ? value.map(item => item[valueField as string]) : value);
|
||||
});
|
||||
onChange(
|
||||
joinValues
|
||||
? value.map(item => item[valueField as string]).join(delimiter)
|
||||
: extractValue
|
||||
? value.map(item => item[valueField as string])
|
||||
: value
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
renderList(list: Options, value: Option[], uncheckable: boolean): { dom: Array<JSX.Element | null>; childrenChecked: number } {
|
||||
renderList(
|
||||
list: Options,
|
||||
value: Option[],
|
||||
uncheckable: boolean
|
||||
): {dom: Array<JSX.Element | null>; childrenChecked: number} {
|
||||
const {
|
||||
itemClassName,
|
||||
showIcon,
|
||||
|
@ -310,7 +307,13 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
let childrenItems = null;
|
||||
let tmpChildrenChecked = false;
|
||||
if (item.children && item.children.length) {
|
||||
childrenItems = this.renderList(item.children, value, cascade ? false : uncheckable || (selfDisabledAffectChildren ? selfDisabled : false) || multiple && checked);
|
||||
childrenItems = this.renderList(
|
||||
item.children,
|
||||
value,
|
||||
cascade
|
||||
? false
|
||||
: uncheckable || (selfDisabledAffectChildren ? selfDisabled : false) || (multiple && checked)
|
||||
);
|
||||
tmpChildrenChecked = !!childrenItems.childrenChecked;
|
||||
if (!selfChecked && onlyChildren && item.children.length === childrenItems.childrenChecked) {
|
||||
selfChecked = true;
|
||||
|
@ -324,7 +327,7 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
|
||||
let nodeDisabled = !!uncheckable || !!disabled || selfDisabled;
|
||||
|
||||
const checkbox: JSX.Element|null = (multiple ? (
|
||||
const checkbox: JSX.Element | null = multiple ? (
|
||||
<label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
|
@ -334,119 +337,117 @@ export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelecto
|
|||
/>
|
||||
<i />
|
||||
</label>
|
||||
) : (
|
||||
showRadio ? (
|
||||
<label className={cx(`Checkbox Checkbox--radio Checkbox--sm`)}>
|
||||
<input
|
||||
type="radio"
|
||||
disabled={nodeDisabled}
|
||||
checked={checked}
|
||||
onChange={() => this.handleSelect(item)}
|
||||
/>
|
||||
<i />
|
||||
</label>
|
||||
) : null
|
||||
)
|
||||
);
|
||||
) : showRadio ? (
|
||||
<label className={cx(`Checkbox Checkbox--radio Checkbox--sm`)}>
|
||||
<input
|
||||
type="radio"
|
||||
disabled={nodeDisabled}
|
||||
checked={checked}
|
||||
onChange={() => this.handleSelect(item)}
|
||||
/>
|
||||
<i />
|
||||
</label>
|
||||
) : null;
|
||||
|
||||
const isLeaf = !item.children || !item.children.length;
|
||||
|
||||
return (
|
||||
<li key={key} className={cx(`Tree-item ${itemClassName || ''}`, {'Tree-item--isLeaf': isLeaf})}>
|
||||
<li
|
||||
key={key}
|
||||
className={cx(`Tree-item ${itemClassName || ''}`, {
|
||||
'Tree-item--isLeaf': isLeaf,
|
||||
})}
|
||||
>
|
||||
<a>
|
||||
{!isLeaf ? (
|
||||
<i
|
||||
onClick={() => this.toggleUnfolded(item)}
|
||||
className={cx("Tree-itemArrow", {
|
||||
'is-folded': !this.state.unfolded[item[valueField]]
|
||||
className={cx('Tree-itemArrow', {
|
||||
'is-folded': !this.state.unfolded[item[valueField]],
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showIcon ? (
|
||||
<i className={cx(`Tree-itemIcon ${item[iconField] || (childrenItems ? 'Tree-folderIcon' : 'Tree-leafIcon')}`)} />
|
||||
<i
|
||||
className={cx(
|
||||
`Tree-itemIcon ${item[iconField] ||
|
||||
(childrenItems ? 'Tree-folderIcon' : 'Tree-leafIcon')}`
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{checkbox}
|
||||
|
||||
|
||||
<span
|
||||
className={cx('Tree-itemText', {
|
||||
'is-children-checked': multiple && !cascade && tmpChildrenChecked && !nodeDisabled,
|
||||
'is-checked': checked,
|
||||
'is-disabled': nodeDisabled
|
||||
'is-disabled': nodeDisabled,
|
||||
})}
|
||||
onClick={() => !nodeDisabled && (multiple ? this.handleCheck(item, !selfChecked) : this.handleSelect(item))}
|
||||
onClick={() =>
|
||||
!nodeDisabled &&
|
||||
(multiple ? this.handleCheck(item, !selfChecked) : this.handleSelect(item))
|
||||
}
|
||||
>
|
||||
{highlightTxt ? highlight(item[nameField], highlightTxt) : item[nameField]}
|
||||
</span>
|
||||
</a>
|
||||
{
|
||||
childrenItems ? (
|
||||
<ul
|
||||
className={cx('Tree-sublist', {
|
||||
'is-folded': !this.state.unfolded[item[valueField]]
|
||||
})}
|
||||
>
|
||||
{childrenItems}
|
||||
</ul>
|
||||
) : null
|
||||
}
|
||||
{childrenItems ? (
|
||||
<ul
|
||||
className={cx('Tree-sublist', {
|
||||
'is-folded': !this.state.unfolded[item[valueField]],
|
||||
})}
|
||||
>
|
||||
{childrenItems}
|
||||
</ul>
|
||||
) : null}
|
||||
</li>
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
dom: ret,
|
||||
childrenChecked
|
||||
childrenChecked,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
placeholder,
|
||||
hideRoot,
|
||||
rootLabel,
|
||||
showIcon,
|
||||
classnames: cx,
|
||||
} = this.props;
|
||||
const {className, placeholder, hideRoot, rootLabel, showIcon, classnames: cx} = this.props;
|
||||
let data = this.props.data;
|
||||
|
||||
const value = this.state.value;
|
||||
return (
|
||||
<div className={cx(`Tree ${className || ''}`)}>
|
||||
{data && data.length ? (
|
||||
<ul className={cx("Tree-list")}>
|
||||
{hideRoot ? this.renderList(data, value, false).dom : (
|
||||
<li className={cx("Tree-item Tree-rootItem")}>
|
||||
<ul className={cx('Tree-list')}>
|
||||
{hideRoot ? (
|
||||
this.renderList(data, value, false).dom
|
||||
) : (
|
||||
<li className={cx('Tree-item Tree-rootItem')}>
|
||||
<a>
|
||||
{showIcon ? (
|
||||
<i className={cx('Tree-itemIcon Tree-rootIcon')} />
|
||||
) : null}
|
||||
{showIcon ? <i className={cx('Tree-itemIcon Tree-rootIcon')} /> : null}
|
||||
|
||||
<label
|
||||
className={cx('Tree-itemLabel', {
|
||||
'is-checked': !value || !value.length,
|
||||
})}
|
||||
>
|
||||
<span
|
||||
className={cx("Tree-itemText")}
|
||||
onClick={this.clearSelect}
|
||||
>
|
||||
<span className={cx('Tree-itemText')} onClick={this.clearSelect}>
|
||||
{rootLabel}
|
||||
</span>
|
||||
</label>
|
||||
</a>
|
||||
<ul className={cx("Tree-sublist")}>{this.renderList(data, value, false).dom}</ul>
|
||||
<ul className={cx('Tree-sublist')}>{this.renderList(data, value, false).dom}</ul>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
) : (
|
||||
<div className={cx("Tree-placeholder")}>{placeholder}</div>
|
||||
)}
|
||||
<div className={cx('Tree-placeholder')}>{placeholder}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TreeSelector);
|
||||
export default themeable(TreeSelector);
|
||||
|
|
|
@ -1,9 +1,77 @@
|
|||
/**
|
||||
* @file Icon
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
export const closeIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1463"><path d="M967.81435 106.836237 917.16274 56.18565 512 461.34839 106.836237 56.18565 56.184627 106.836237 461.34839 512 56.184627 917.163763 106.836237 967.815373 512 562.65161 917.16274 967.815373 967.81435 917.163763 562.650587 512Z" p-id="1464" data-spm-anchor-id="a313x.7781069.0.i0"></path></svg>);
|
||||
export const unDoIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M661.333333 341.333333H167.04l183.253333-183.253333L320 128 85.333333 362.666667l234.666667 234.666666 30.08-30.08L167.04 384H661.333333a234.666667 234.666667 0 0 1 0 469.333333H448v42.666667h213.333333a277.333333 277.333333 0 0 0 0-554.666667z"></path></svg>);
|
||||
export const reDoIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M704 128l-30.08 30.08L856.96 341.333333H362.666667a277.333333 277.333333 0 0 0 0 554.666667h213.333333v-42.666667H362.666667a234.666667 234.666667 0 0 1 0-469.333333h494.293333l-183.253333 183.253333L704 597.333333l234.666667-234.666666z"></path></svg>)
|
||||
export const enterIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M864 192c-19.2 0-32 12.8-32 32v224c0 89.6-70.4 160-160 160H236.8l105.6-105.6c12.8-12.8 12.8-32 0-44.8s-32-12.8-44.8 0l-160 160c-3.2 3.2-6.4 6.4-6.4 9.6-3.2 6.4-3.2 16 0 25.6 3.2 3.2 3.2 6.4 6.4 9.6l160 160c6.4 6.4 12.8 9.6 22.4 9.6s16-3.2 22.4-9.6c12.8-12.8 12.8-32 0-44.8L236.8 672H672c124.8 0 224-99.2 224-224V224c0-19.2-12.8-32-32-32z"></path></svg>)
|
||||
export const volumeIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M536.319574 5.11991a63.99888 63.99888 0 0 0-69.758779 13.439765L229.764939 255.99552H64.00784a63.99888 63.99888 0 0 0-63.99888 63.99888v383.99328a63.99888 63.99888 0 0 0 63.99888 63.99888h165.757099l236.795856 237.435845A63.99888 63.99888 0 0 0 512 1023.98208a53.759059 53.759059 0 0 0 24.319574-5.11991A63.99888 63.99888 0 0 0 575.99888 959.9832V63.99888a63.99888 63.99888 0 0 0-39.679306-58.87897zM192.0056 639.9888H128.00672V383.99328h63.99888z m255.99552 165.757099l-127.99776-127.99776V346.233941l127.99776-127.99776zM879.353571 148.477402a63.99888 63.99888 0 0 0-94.718342 87.038476 402.552955 402.552955 0 0 1 0 552.950324A63.99888 63.99888 0 0 0 831.9944 895.98432a63.99888 63.99888 0 0 0 46.719183-20.479641 531.830693 531.830693 0 0 0 0-727.027277z" fill="#606670" p-id="3605"></path><path d="M751.9958 277.11515a63.99888 63.99888 0 0 0-95.99832 85.7585A218.236181 218.236181 0 0 1 703.99664 511.99104a221.436125 221.436125 0 0 1-47.359171 149.117391 63.99888 63.99888 0 0 0 4.479921 90.23842A63.99888 63.99888 0 0 0 703.99664 767.98656a63.99888 63.99888 0 0 0 47.359171-21.11963A349.433885 349.433885 0 0 0 831.9944 511.99104a353.273818 353.273818 0 0 0-79.9986-234.87589z" fill="#606670" p-id="3606"></path></svg>)
|
||||
export const muteIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M536.310615 5.11991a63.99888 63.99888 0 0 0-69.75878 13.439765L229.755979 255.99552H63.99888a63.99888 63.99888 0 0 0-63.99888 63.99888v383.99328a63.99888 63.99888 0 0 0 63.99888 63.99888h165.757099l236.795856 237.435845A63.99888 63.99888 0 0 0 511.99104 1023.98208a53.759059 53.759059 0 0 0 24.319575-5.11991A63.99888 63.99888 0 0 0 575.98992 959.9832V63.99888a63.99888 63.99888 0 0 0-39.679305-58.87897zM191.99664 639.9888H127.99776V383.99328h63.99888z m255.99552 165.757099l-127.99776-127.99776V346.233941l127.99776-127.99776zM914.543995 511.99104l90.87841-90.238421a63.99888 63.99888 0 1 0-90.87841-90.878409l-90.23842 90.878409-90.238421-90.878409a63.99888 63.99888 0 0 0-90.87841 90.878409L734.067154 511.99104l-90.87841 90.238421a63.99888 63.99888 0 0 0 90.87841 90.87841l90.238421-90.87841 90.23842 90.87841a63.99888 63.99888 0 1 0 90.87841-90.87841z" fill="#606670" p-id="2312"></path></svg>)
|
||||
export const playIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M852.727563 392.447107C956.997809 458.473635 956.941389 565.559517 852.727563 631.55032L281.888889 993.019655C177.618644 1059.046186 93.090909 1016.054114 93.090909 897.137364L93.090909 126.860063C93.090909 7.879206 177.675064-35.013033 281.888889 30.977769L852.727563 392.447107 852.727563 392.447107Z" p-id="4494" fill="#606670"></path></svg>)
|
||||
export const pauseIcon = (<svg className="icon" viewBox="0 0 1024 1024" version="1.1"><path d="M757.52 73.107h-62.493c-34.526 0-62.498 27.984-62.498 62.511v749.948c0 34.526 27.974 62.493 62.498 62.493h62.493c34.516 0 62.502-27.968 62.502-62.493v-749.953c-0.001-34.524-27.984-62.509-62.502-62.509z" p-id="7567" fill="#606670"></path><path d="M320.054 73.107h-62.502c-34.526 0-62.498 27.984-62.498 62.511v749.948c0 34.526 27.974 62.493 62.498 62.493h62.502c34.505 0 62.493-27.968 62.493-62.493v-749.953c-0.001-34.524-27.984-62.509-62.493-62.509z" p-id="7568" fill="#606670"></path></svg>)
|
||||
export const closeIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1463">
|
||||
<path
|
||||
d="M967.81435 106.836237 917.16274 56.18565 512 461.34839 106.836237 56.18565 56.184627 106.836237 461.34839 512 56.184627 917.163763 106.836237 967.815373 512 562.65161 917.16274 967.815373 967.81435 917.163763 562.650587 512Z"
|
||||
p-id="1464"
|
||||
data-spm-anchor-id="a313x.7781069.0.i0"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const unDoIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path d="M661.333333 341.333333H167.04l183.253333-183.253333L320 128 85.333333 362.666667l234.666667 234.666666 30.08-30.08L167.04 384H661.333333a234.666667 234.666667 0 0 1 0 469.333333H448v42.666667h213.333333a277.333333 277.333333 0 0 0 0-554.666667z" />
|
||||
</svg>
|
||||
);
|
||||
export const reDoIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path d="M704 128l-30.08 30.08L856.96 341.333333H362.666667a277.333333 277.333333 0 0 0 0 554.666667h213.333333v-42.666667H362.666667a234.666667 234.666667 0 0 1 0-469.333333h494.293333l-183.253333 183.253333L704 597.333333l234.666667-234.666666z" />
|
||||
</svg>
|
||||
);
|
||||
export const enterIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path d="M864 192c-19.2 0-32 12.8-32 32v224c0 89.6-70.4 160-160 160H236.8l105.6-105.6c12.8-12.8 12.8-32 0-44.8s-32-12.8-44.8 0l-160 160c-3.2 3.2-6.4 6.4-6.4 9.6-3.2 6.4-3.2 16 0 25.6 3.2 3.2 3.2 6.4 6.4 9.6l160 160c6.4 6.4 12.8 9.6 22.4 9.6s16-3.2 22.4-9.6c12.8-12.8 12.8-32 0-44.8L236.8 672H672c124.8 0 224-99.2 224-224V224c0-19.2-12.8-32-32-32z" />
|
||||
</svg>
|
||||
);
|
||||
export const volumeIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path
|
||||
d="M536.319574 5.11991a63.99888 63.99888 0 0 0-69.758779 13.439765L229.764939 255.99552H64.00784a63.99888 63.99888 0 0 0-63.99888 63.99888v383.99328a63.99888 63.99888 0 0 0 63.99888 63.99888h165.757099l236.795856 237.435845A63.99888 63.99888 0 0 0 512 1023.98208a53.759059 53.759059 0 0 0 24.319574-5.11991A63.99888 63.99888 0 0 0 575.99888 959.9832V63.99888a63.99888 63.99888 0 0 0-39.679306-58.87897zM192.0056 639.9888H128.00672V383.99328h63.99888z m255.99552 165.757099l-127.99776-127.99776V346.233941l127.99776-127.99776zM879.353571 148.477402a63.99888 63.99888 0 0 0-94.718342 87.038476 402.552955 402.552955 0 0 1 0 552.950324A63.99888 63.99888 0 0 0 831.9944 895.98432a63.99888 63.99888 0 0 0 46.719183-20.479641 531.830693 531.830693 0 0 0 0-727.027277z"
|
||||
fill="#606670"
|
||||
p-id="3605"
|
||||
/>
|
||||
<path
|
||||
d="M751.9958 277.11515a63.99888 63.99888 0 0 0-95.99832 85.7585A218.236181 218.236181 0 0 1 703.99664 511.99104a221.436125 221.436125 0 0 1-47.359171 149.117391 63.99888 63.99888 0 0 0 4.479921 90.23842A63.99888 63.99888 0 0 0 703.99664 767.98656a63.99888 63.99888 0 0 0 47.359171-21.11963A349.433885 349.433885 0 0 0 831.9944 511.99104a353.273818 353.273818 0 0 0-79.9986-234.87589z"
|
||||
fill="#606670"
|
||||
p-id="3606"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const muteIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path
|
||||
d="M536.310615 5.11991a63.99888 63.99888 0 0 0-69.75878 13.439765L229.755979 255.99552H63.99888a63.99888 63.99888 0 0 0-63.99888 63.99888v383.99328a63.99888 63.99888 0 0 0 63.99888 63.99888h165.757099l236.795856 237.435845A63.99888 63.99888 0 0 0 511.99104 1023.98208a53.759059 53.759059 0 0 0 24.319575-5.11991A63.99888 63.99888 0 0 0 575.98992 959.9832V63.99888a63.99888 63.99888 0 0 0-39.679305-58.87897zM191.99664 639.9888H127.99776V383.99328h63.99888z m255.99552 165.757099l-127.99776-127.99776V346.233941l127.99776-127.99776zM914.543995 511.99104l90.87841-90.238421a63.99888 63.99888 0 1 0-90.87841-90.878409l-90.23842 90.878409-90.238421-90.878409a63.99888 63.99888 0 0 0-90.87841 90.878409L734.067154 511.99104l-90.87841 90.238421a63.99888 63.99888 0 0 0 90.87841 90.87841l90.238421-90.87841 90.23842 90.87841a63.99888 63.99888 0 1 0 90.87841-90.87841z"
|
||||
fill="#606670"
|
||||
p-id="2312"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const playIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path
|
||||
d="M852.727563 392.447107C956.997809 458.473635 956.941389 565.559517 852.727563 631.55032L281.888889 993.019655C177.618644 1059.046186 93.090909 1016.054114 93.090909 897.137364L93.090909 126.860063C93.090909 7.879206 177.675064-35.013033 281.888889 30.977769L852.727563 392.447107 852.727563 392.447107Z"
|
||||
p-id="4494"
|
||||
fill="#606670"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const pauseIcon = (
|
||||
<svg className="icon" viewBox="0 0 1024 1024" version="1.1">
|
||||
<path
|
||||
d="M757.52 73.107h-62.493c-34.526 0-62.498 27.984-62.498 62.511v749.948c0 34.526 27.974 62.493 62.498 62.493h62.493c34.516 0 62.502-27.968 62.502-62.493v-749.953c-0.001-34.524-27.984-62.509-62.502-62.509z"
|
||||
p-id="7567"
|
||||
fill="#606670"
|
||||
/>
|
||||
<path
|
||||
d="M320.054 73.107h-62.502c-34.526 0-62.498 27.984-62.498 62.511v749.948c0 34.526 27.974 62.493 62.498 62.493h62.502c34.505 0 62.493-27.968 62.493-62.493v-749.953c-0.001-34.524-27.984-62.509-62.493-62.509z"
|
||||
p-id="7568"
|
||||
fill="#606670"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
/**
|
||||
* @file Index
|
||||
* @description
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import NotFound from './404';
|
||||
import {default as Alert, alert, confirm} from './Alert';
|
||||
import AsideNav from './AsideNav';
|
||||
|
@ -32,8 +38,6 @@ import Tooltip from './Tooltip';
|
|||
import TooltipWrapper from './TooltipWrapper';
|
||||
import Tree from './Tree';
|
||||
|
||||
|
||||
|
||||
export {
|
||||
NotFound,
|
||||
Alert as AlertComponent,
|
||||
|
@ -70,5 +74,5 @@ export {
|
|||
toast,
|
||||
Tooltip,
|
||||
TooltipWrapper,
|
||||
Tree
|
||||
};
|
||||
Tree,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue