mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
refactor: 💡 format
This commit is contained in:
parent
3589913d69
commit
9e5c689d20
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": false,
|
||||
"trailingComma": "es5",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid"
|
||||
}
|
||||
|
@ -4,46 +4,42 @@
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import { themeable, ClassNamesFn } from '../theme'
|
||||
import {themeable, ClassNamesFn} from '../theme'
|
||||
|
||||
interface NotFoundProps {
|
||||
code?: string | number
|
||||
description?: string
|
||||
links?: React.ReactNode
|
||||
footerText?: React.ReactNode
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
code?: string | number
|
||||
description?: string
|
||||
links?: React.ReactNode
|
||||
footerText?: React.ReactNode
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class NotFound extends React.Component<NotFoundProps, any> {
|
||||
render() {
|
||||
const { links, footerText, description, children, code } = this.props
|
||||
render() {
|
||||
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}
|
||||
</div>
|
||||
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}
|
||||
</div>
|
||||
|
||||
{children}
|
||||
{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">
|
||||
<p>
|
||||
<small className="text-muted">{footerText}</small>
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{footerText ? (
|
||||
<div className="text-center">
|
||||
<p>
|
||||
<small className="text-muted">{footerText}</small>
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(NotFound)
|
||||
|
@ -4,186 +4,172 @@
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
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
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
title?: string
|
||||
confirmBtnLevel?: string
|
||||
alertBtnLevel?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
theme?: string
|
||||
container?: any
|
||||
confirmText?: string
|
||||
cancelText?: string
|
||||
title?: string
|
||||
confirmBtnLevel?: string
|
||||
alertBtnLevel?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
theme?: string
|
||||
}
|
||||
|
||||
export interface AlertState {
|
||||
show: boolean
|
||||
title?: string
|
||||
content: string
|
||||
confirm: boolean
|
||||
show: boolean
|
||||
title?: string
|
||||
content: string
|
||||
confirm: boolean
|
||||
}
|
||||
|
||||
export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
static instance: any = null
|
||||
static getInstance() {
|
||||
if (!Alert.instance) {
|
||||
console.warn('Alert 组件应该没有被渲染,所以隐性的渲染到 body 了')
|
||||
const container = document.body
|
||||
const div = document.createElement('div')
|
||||
container.appendChild(div)
|
||||
render(<ThemedAlert />, div)
|
||||
static instance: any = null
|
||||
static getInstance() {
|
||||
if (!Alert.instance) {
|
||||
console.warn('Alert 组件应该没有被渲染,所以隐性的渲染到 body 了')
|
||||
const container = document.body
|
||||
const div = document.createElement('div')
|
||||
container.appendChild(div)
|
||||
render(<ThemedAlert />, div)
|
||||
}
|
||||
|
||||
return Alert.instance
|
||||
}
|
||||
|
||||
return Alert.instance
|
||||
}
|
||||
|
||||
_resolve: (value: any) => void
|
||||
_modal: any
|
||||
_body: any
|
||||
state: AlertState = {
|
||||
show: false,
|
||||
title: '',
|
||||
content: '',
|
||||
confirm: false
|
||||
}
|
||||
constructor(props: AlertProps) {
|
||||
super(props)
|
||||
|
||||
this.close = this.close.bind(this)
|
||||
this.handleConfirm = this.handleConfirm.bind(this)
|
||||
this.handleCancel = this.handleCancel.bind(this)
|
||||
this.modalRef = this.modalRef.bind(this)
|
||||
this.bodyRef = this.bodyRef.bind(this)
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
confirmText: '确认',
|
||||
cancelText: '取消',
|
||||
title: '系统消息',
|
||||
alertBtnLevel: 'primary',
|
||||
confirmBtnLevel: 'danger'
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
Alert.instance = this
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: AlertProps, prevState: AlertState) {
|
||||
if (prevState.content !== this.state.content) {
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
_resolve: (value: any) => void
|
||||
_modal: any
|
||||
_body: any
|
||||
state: AlertState = {
|
||||
show: false,
|
||||
title: '',
|
||||
content: '',
|
||||
confirm: false,
|
||||
}
|
||||
}
|
||||
constructor(props: AlertProps) {
|
||||
super(props)
|
||||
|
||||
componentWillUnmount() {
|
||||
Alert.instance = null
|
||||
}
|
||||
this.close = this.close.bind(this)
|
||||
this.handleConfirm = this.handleConfirm.bind(this)
|
||||
this.handleCancel = this.handleCancel.bind(this)
|
||||
this.modalRef = this.modalRef.bind(this)
|
||||
this.bodyRef = this.bodyRef.bind(this)
|
||||
}
|
||||
|
||||
handleConfirm() {
|
||||
this.close(true)
|
||||
}
|
||||
static defaultProps = {
|
||||
confirmText: '确认',
|
||||
cancelText: '取消',
|
||||
title: '系统消息',
|
||||
alertBtnLevel: 'primary',
|
||||
confirmBtnLevel: 'danger',
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
this.close(false)
|
||||
}
|
||||
componentWillMount() {
|
||||
Alert.instance = this
|
||||
}
|
||||
|
||||
close(confirmed: boolean) {
|
||||
const isConfirm = this.state.confirm
|
||||
componentDidMount() {
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
}
|
||||
|
||||
this.setState(
|
||||
{
|
||||
show: false
|
||||
},
|
||||
isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
|
||||
)
|
||||
}
|
||||
componentDidUpdate(prevProps: AlertProps, prevState: AlertState) {
|
||||
if (prevState.content !== this.state.content) {
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
}
|
||||
}
|
||||
|
||||
alert(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: false
|
||||
})
|
||||
}
|
||||
componentWillUnmount() {
|
||||
Alert.instance = null
|
||||
}
|
||||
|
||||
confirm(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: true
|
||||
})
|
||||
handleConfirm() {
|
||||
this.close(true)
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this._resolve = resolve
|
||||
})
|
||||
}
|
||||
handleCancel() {
|
||||
this.close(false)
|
||||
}
|
||||
|
||||
modalRef(ref: any) {
|
||||
this._modal = ref
|
||||
}
|
||||
close(confirmed: boolean) {
|
||||
const isConfirm = this.state.confirm
|
||||
|
||||
bodyRef(ref: any) {
|
||||
this._body = ref
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
container,
|
||||
cancelText,
|
||||
confirmText,
|
||||
title,
|
||||
confirmBtnLevel,
|
||||
alertBtnLevel,
|
||||
classnames: cx,
|
||||
classPrefix
|
||||
} = this.props
|
||||
return (
|
||||
<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>
|
||||
<div className={cx('Modal-body')}>
|
||||
<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>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
alert(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: false,
|
||||
})
|
||||
}
|
||||
|
||||
confirm(content: string, title?: string) {
|
||||
this.setState({
|
||||
title,
|
||||
content,
|
||||
show: true,
|
||||
confirm: true,
|
||||
})
|
||||
|
||||
return new Promise(resolve => {
|
||||
this._resolve = resolve
|
||||
})
|
||||
}
|
||||
|
||||
modalRef(ref: any) {
|
||||
this._modal = ref
|
||||
}
|
||||
|
||||
bodyRef(ref: any) {
|
||||
this._body = ref
|
||||
this._body && (this._body.innerHTML = this.state.content)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
container,
|
||||
cancelText,
|
||||
confirmText,
|
||||
title,
|
||||
confirmBtnLevel,
|
||||
alertBtnLevel,
|
||||
classnames: cx,
|
||||
classPrefix,
|
||||
} = this.props
|
||||
return (
|
||||
<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>
|
||||
<div className={cx('Modal-body')}>
|
||||
<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>
|
||||
</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 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
|
||||
|
@ -4,79 +4,61 @@
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
|
||||
export interface AlertProps {
|
||||
level: 'danger' | 'info' | 'success' | 'warning'
|
||||
className: string
|
||||
showCloseButton: boolean
|
||||
onClose?: () => void
|
||||
classnames: ClassNamesFn
|
||||
classPrefix: string
|
||||
level: 'danger' | 'info' | 'success' | 'warning'
|
||||
className: string
|
||||
showCloseButton: boolean
|
||||
onClose?: () => void
|
||||
classnames: ClassNamesFn
|
||||
classPrefix: string
|
||||
}
|
||||
|
||||
export interface AlertState {
|
||||
show: boolean
|
||||
show: boolean
|
||||
}
|
||||
|
||||
export class Alert extends React.Component<AlertProps, AlertState> {
|
||||
static defaultProps: Pick<
|
||||
AlertProps,
|
||||
'level' | 'className' | 'showCloseButton'
|
||||
> = {
|
||||
level: 'info',
|
||||
className: '',
|
||||
showCloseButton: false
|
||||
}
|
||||
static propsList: Array<string> = [
|
||||
'level',
|
||||
'className',
|
||||
'showCloseButton',
|
||||
'onClose'
|
||||
]
|
||||
|
||||
constructor(props: AlertProps) {
|
||||
super(props)
|
||||
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.state = {
|
||||
show: true
|
||||
static defaultProps: Pick<AlertProps, 'level' | 'className' | 'showCloseButton'> = {
|
||||
level: 'info',
|
||||
className: '',
|
||||
showCloseButton: false,
|
||||
}
|
||||
}
|
||||
static propsList: Array<string> = ['level', 'className', 'showCloseButton', 'onClose']
|
||||
|
||||
handleClick() {
|
||||
this.setState(
|
||||
{
|
||||
show: false
|
||||
},
|
||||
this.props.onClose
|
||||
)
|
||||
}
|
||||
constructor(props: AlertProps) {
|
||||
super(props)
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx,
|
||||
className,
|
||||
level,
|
||||
children,
|
||||
showCloseButton
|
||||
} = this.props
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.state = {
|
||||
show: true,
|
||||
}
|
||||
}
|
||||
|
||||
return this.state.show ? (
|
||||
<div className={cx('Alert', level ? `Alert--${level}` : '', className)}>
|
||||
{showCloseButton ? (
|
||||
<button
|
||||
className={cx('Alert-close')}
|
||||
onClick={this.handleClick}
|
||||
type="button"
|
||||
>
|
||||
<span>×</span>
|
||||
</button>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
handleClick() {
|
||||
this.setState(
|
||||
{
|
||||
show: false,
|
||||
},
|
||||
this.props.onClose
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {classnames: cx, className, level, children, showCloseButton} = this.props
|
||||
|
||||
return this.state.show ? (
|
||||
<div className={cx('Alert', level ? `Alert--${level}` : '', className)}>
|
||||
{showCloseButton ? (
|
||||
<button className={cx('Alert-close')} onClick={this.handleClick} type="button">
|
||||
<span>×</span>
|
||||
</button>
|
||||
) : null}
|
||||
{children}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Alert)
|
||||
|
@ -6,251 +6,213 @@
|
||||
|
||||
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 {
|
||||
id?: number
|
||||
label: string
|
||||
hidden?: boolean
|
||||
open: boolean
|
||||
active: boolean
|
||||
className?: string
|
||||
children?: Array<LinkItem>
|
||||
id?: number
|
||||
label: string
|
||||
hidden?: boolean
|
||||
open: boolean
|
||||
active: boolean
|
||||
className?: string
|
||||
children?: Array<LinkItem>
|
||||
}
|
||||
|
||||
interface Navigation {
|
||||
label: string
|
||||
children: Array<LinkItem>
|
||||
prefix?: JSX.Element
|
||||
affix?: JSX.Element
|
||||
className?: string
|
||||
[propName: string]: any
|
||||
label: string
|
||||
children: Array<LinkItem>
|
||||
prefix?: JSX.Element
|
||||
affix?: JSX.Element
|
||||
className?: string
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
interface AsideNavProps {
|
||||
id?: string
|
||||
className?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
renderLink: Function
|
||||
isActive: Function
|
||||
isOpen: (link: LinkItemProps) => boolean
|
||||
navigations: Array<Navigation>
|
||||
renderSubLinks: (
|
||||
link: LinkItemProps,
|
||||
renderLink: Function,
|
||||
depth: number,
|
||||
props: AsideNavProps
|
||||
) => React.ReactNode
|
||||
id?: string
|
||||
className?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
renderLink: Function
|
||||
isActive: Function
|
||||
isOpen: (link: LinkItemProps) => boolean
|
||||
navigations: Array<Navigation>
|
||||
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, props: AsideNavProps) => React.ReactNode
|
||||
}
|
||||
|
||||
interface AsideNavState {
|
||||
navigations: Array<Navigation>
|
||||
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>
|
||||
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,
|
||||
isActive: (link: LinkItem) => link.open,
|
||||
isOpen: (item: LinkItemProps) => (item.children ? item.children.some(item => item.open) : false),
|
||||
}
|
||||
|
||||
constructor(props: AsideNavProps) {
|
||||
super(props)
|
||||
|
||||
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
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps),
|
||||
}
|
||||
},
|
||||
1,
|
||||
true
|
||||
),
|
||||
}
|
||||
|
||||
this.renderLink = this.renderLink.bind(this)
|
||||
this.toggleExpand = this.toggleExpand.bind(this)
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: AsideNavProps) {
|
||||
const props = this.props
|
||||
const isOpen = props.isOpen
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
active: link.active,
|
||||
open: link.open,
|
||||
toggleExpand: this.toggleExpand,
|
||||
depth,
|
||||
classnames: cx,
|
||||
...others,
|
||||
})
|
||||
|
||||
if (!dom) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
{...props}
|
||||
key={key}
|
||||
className={cx(`AsideNav-item`, link.className, {
|
||||
[`is-active`]: link.active || link.open,
|
||||
})}
|
||||
>
|
||||
{dom}
|
||||
{renderSubLinks(link, this.renderLink, depth, this.props)}
|
||||
</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
|
||||
}
|
||||
|
||||
constructor(props: AsideNavProps) {
|
||||
super(props)
|
||||
|
||||
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
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps)
|
||||
}
|
||||
},
|
||||
1,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
this.renderLink = this.renderLink.bind(this)
|
||||
this.toggleExpand = this.toggleExpand.bind(this)
|
||||
}
|
||||
render() {
|
||||
const navigations = this.state.navigations
|
||||
let links: Array<React.ReactNode> = []
|
||||
const {className, classnames: cx} = this.props
|
||||
|
||||
componentWillReceiveProps(nextProps: AsideNavProps) {
|
||||
const props = this.props
|
||||
const isOpen = props.isOpen
|
||||
|
||||
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
|
||||
|
||||
return {
|
||||
...item,
|
||||
id: id++,
|
||||
active: isActive,
|
||||
open: isActive || isOpen(item as LinkItemProps)
|
||||
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`,
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
1,
|
||||
true
|
||||
|
||||
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}`)
|
||||
link && links.push(link)
|
||||
})
|
||||
|
||||
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`,
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<nav className={cx(`AsideNav`, className)}>
|
||||
<ul className={cx(`AsideNav-list`)}>{links}</ul>
|
||||
</nav>
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
toggleExpand(link: LinkItemProps) {
|
||||
this.setState({
|
||||
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
|
||||
|
||||
const dom = (renderLink as Function)({
|
||||
link,
|
||||
active: link.active,
|
||||
open: link.open,
|
||||
toggleExpand: this.toggleExpand,
|
||||
depth,
|
||||
classnames: cx,
|
||||
...others
|
||||
})
|
||||
|
||||
if (!dom) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
{...props}
|
||||
key={key}
|
||||
className={cx(`AsideNav-item`, link.className, {
|
||||
[`is-active`]: link.active || link.open
|
||||
})}
|
||||
>
|
||||
{dom}
|
||||
{renderSubLinks(link, this.renderLink, depth, this.props)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const navigations = this.state.navigations
|
||||
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`
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
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}`)
|
||||
link && links.push(link)
|
||||
})
|
||||
|
||||
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`
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<nav className={cx(`AsideNav`, className)}>
|
||||
<ul className={cx(`AsideNav-list`)}>{links}</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(AsideNav)
|
||||
|
@ -4,124 +4,114 @@
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import TooltipWrapper, { TooltipObject, Trigger } from './TooltipWrapper'
|
||||
import { pickEventsProps } from '../utils/helper'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
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'
|
||||
level: string // 'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default';
|
||||
tooltip?: string | TooltipObject
|
||||
placement: 'top' | 'right' | 'bottom' | 'left'
|
||||
tooltipContainer?: any
|
||||
tooltipTrigger: Trigger | Array<Trigger>
|
||||
tooltipRootClose: boolean
|
||||
disabled?: boolean
|
||||
active?: boolean
|
||||
block?: boolean
|
||||
iconOnly?: boolean
|
||||
disabledTip?: string | TooltipObject
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
componentClass: React.ReactType
|
||||
extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
|
||||
id?: string
|
||||
className?: string
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg'
|
||||
type: 'button' | 'reset' | 'submit'
|
||||
level: string // 'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default';
|
||||
tooltip?: string | TooltipObject
|
||||
placement: 'top' | 'right' | 'bottom' | 'left'
|
||||
tooltipContainer?: any
|
||||
tooltipTrigger: Trigger | Array<Trigger>
|
||||
tooltipRootClose: boolean
|
||||
disabled?: boolean
|
||||
active?: boolean
|
||||
block?: boolean
|
||||
iconOnly?: boolean
|
||||
disabledTip?: string | TooltipObject
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
componentClass: React.ReactType
|
||||
}
|
||||
|
||||
export class Button extends React.Component<ButtonProps> {
|
||||
static defaultProps: Pick<
|
||||
ButtonProps,
|
||||
| 'componentClass'
|
||||
| 'level'
|
||||
| 'type'
|
||||
| 'placement'
|
||||
| 'tooltipTrigger'
|
||||
| 'tooltipRootClose'
|
||||
> = {
|
||||
componentClass: 'button',
|
||||
level: 'default',
|
||||
type: 'button',
|
||||
placement: 'top',
|
||||
tooltipTrigger: ['hover', 'focus'],
|
||||
tooltipRootClose: false
|
||||
}
|
||||
static defaultProps: Pick<
|
||||
ButtonProps,
|
||||
'componentClass' | 'level' | 'type' | 'placement' | 'tooltipTrigger' | 'tooltipRootClose'
|
||||
> = {
|
||||
componentClass: 'button',
|
||||
level: 'default',
|
||||
type: 'button',
|
||||
placement: 'top',
|
||||
tooltipTrigger: ['hover', 'focus'],
|
||||
tooltipRootClose: false,
|
||||
}
|
||||
|
||||
renderButton() {
|
||||
const {
|
||||
level,
|
||||
size,
|
||||
disabled,
|
||||
className,
|
||||
componentClass: Comp,
|
||||
classnames: cx,
|
||||
children,
|
||||
disabledTip,
|
||||
block,
|
||||
type,
|
||||
active,
|
||||
iconOnly,
|
||||
...rest
|
||||
} = this.props
|
||||
renderButton() {
|
||||
const {
|
||||
level,
|
||||
size,
|
||||
disabled,
|
||||
className,
|
||||
componentClass: Comp,
|
||||
classnames: cx,
|
||||
children,
|
||||
disabledTip,
|
||||
block,
|
||||
type,
|
||||
active,
|
||||
iconOnly,
|
||||
...rest
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<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
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{children}
|
||||
</Comp>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<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
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{children}
|
||||
</Comp>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tooltip,
|
||||
placement,
|
||||
tooltipContainer,
|
||||
tooltipTrigger,
|
||||
tooltipRootClose,
|
||||
disabled,
|
||||
disabledTip,
|
||||
classPrefix,
|
||||
classnames: cx
|
||||
} = this.props
|
||||
render() {
|
||||
const {
|
||||
tooltip,
|
||||
placement,
|
||||
tooltipContainer,
|
||||
tooltipTrigger,
|
||||
tooltipRootClose,
|
||||
disabled,
|
||||
disabledTip,
|
||||
classPrefix,
|
||||
classnames: cx,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<TooltipWrapper
|
||||
placement={placement}
|
||||
tooltip={disabled ? disabledTip : tooltip}
|
||||
container={tooltipContainer}
|
||||
trigger={tooltipTrigger}
|
||||
rootClose={tooltipRootClose}
|
||||
>
|
||||
{disabled && disabledTip ? (
|
||||
<div className={cx('Button--disabled-wrap')}>
|
||||
{this.renderButton()}
|
||||
</div>
|
||||
) : (
|
||||
this.renderButton()
|
||||
)}
|
||||
</TooltipWrapper>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<TooltipWrapper
|
||||
placement={placement}
|
||||
tooltip={disabled ? disabledTip : tooltip}
|
||||
container={tooltipContainer}
|
||||
trigger={tooltipTrigger}
|
||||
rootClose={tooltipRootClose}
|
||||
>
|
||||
{disabled && disabledTip ? (
|
||||
<div className={cx('Button--disabled-wrap')}>{this.renderButton()}</div>
|
||||
) : (
|
||||
this.renderButton()
|
||||
)}
|
||||
</TooltipWrapper>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Button)
|
||||
|
@ -5,111 +5,109 @@
|
||||
|
||||
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'
|
||||
sm: 'i-checks-sm',
|
||||
lg: 'i-checks-lg',
|
||||
small: 'i-checks-sm',
|
||||
large: 'i-checks-lg',
|
||||
}
|
||||
|
||||
interface CheckboxProps {
|
||||
id?: string
|
||||
key?: string | number
|
||||
style?: React.CSSProperties
|
||||
type?: string
|
||||
size?: 'sm' | 'lg' | 'small' | 'large'
|
||||
label?: string
|
||||
className?: string
|
||||
onChange?: (value: any) => void
|
||||
value?: any
|
||||
containerClass?: string
|
||||
inline?: boolean
|
||||
trueValue?: boolean
|
||||
falseValue?: boolean
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
checked?: boolean
|
||||
name?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
partial?: boolean
|
||||
id?: string
|
||||
key?: string | number
|
||||
style?: React.CSSProperties
|
||||
type?: string
|
||||
size?: 'sm' | 'lg' | 'small' | 'large'
|
||||
label?: string
|
||||
className?: string
|
||||
onChange?: (value: any) => void
|
||||
value?: any
|
||||
containerClass?: string
|
||||
inline?: boolean
|
||||
trueValue?: boolean
|
||||
falseValue?: boolean
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
checked?: boolean
|
||||
name?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
partial?: boolean
|
||||
}
|
||||
|
||||
export class Checkbox extends React.Component<CheckboxProps, any> {
|
||||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false,
|
||||
type: 'checkbox'
|
||||
}
|
||||
|
||||
constructor(props: CheckboxProps) {
|
||||
super(props)
|
||||
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this)
|
||||
}
|
||||
|
||||
hanldeCheck(e: React.ChangeEvent<any>) {
|
||||
const { trueValue, falseValue, onChange } = this.props
|
||||
|
||||
if (!onChange) {
|
||||
return
|
||||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false,
|
||||
type: 'checkbox',
|
||||
}
|
||||
|
||||
onChange(e.currentTarget.checked ? trueValue : falseValue)
|
||||
}
|
||||
constructor(props: CheckboxProps) {
|
||||
super(props)
|
||||
|
||||
render() {
|
||||
let {
|
||||
size,
|
||||
className,
|
||||
classPrefix: ns,
|
||||
value,
|
||||
label,
|
||||
partial,
|
||||
trueValue,
|
||||
children,
|
||||
disabled,
|
||||
readOnly,
|
||||
checked,
|
||||
type,
|
||||
name
|
||||
} = this.props
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this)
|
||||
}
|
||||
|
||||
className =
|
||||
(className ? className : '') +
|
||||
(size && sizeMap[size] ? ` ${sizeMap[size]}` : '')
|
||||
hanldeCheck(e: React.ChangeEvent<any>) {
|
||||
const {trueValue, falseValue, onChange} = this.props
|
||||
|
||||
return (
|
||||
<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
|
||||
}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
name={name}
|
||||
/>
|
||||
<i />
|
||||
<span>{children || label}</span>
|
||||
</label>
|
||||
)
|
||||
}
|
||||
if (!onChange) {
|
||||
return
|
||||
}
|
||||
|
||||
onChange(e.currentTarget.checked ? trueValue : falseValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
size,
|
||||
className,
|
||||
classPrefix: ns,
|
||||
value,
|
||||
label,
|
||||
partial,
|
||||
trueValue,
|
||||
children,
|
||||
disabled,
|
||||
readOnly,
|
||||
checked,
|
||||
type,
|
||||
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
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type={type}
|
||||
checked={
|
||||
typeof checked !== 'undefined'
|
||||
? checked
|
||||
: typeof value === 'undefined'
|
||||
? value
|
||||
: value == trueValue
|
||||
}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
name={name}
|
||||
/>
|
||||
<i />
|
||||
<span>{children || label}</span>
|
||||
</label>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Checkbox)
|
||||
|
@ -9,98 +9,82 @@ 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 {
|
||||
label?: string
|
||||
value?: any
|
||||
disabled?: boolean
|
||||
children?: Options
|
||||
[propName: string]: any
|
||||
label?: string
|
||||
value?: any
|
||||
disabled?: boolean
|
||||
children?: Options
|
||||
[propName: string]: any
|
||||
}
|
||||
export interface Options extends Array<Option> {}
|
||||
|
||||
export interface OptionProps {
|
||||
multi?: boolean
|
||||
multiple?: boolean
|
||||
valueField?: string
|
||||
options?: Options
|
||||
joinValues: boolean
|
||||
extractValue: boolean
|
||||
delimiter: string
|
||||
clearable: boolean
|
||||
placeholder?: string
|
||||
multi?: boolean
|
||||
multiple?: boolean
|
||||
valueField?: string
|
||||
options?: Options
|
||||
joinValues: boolean
|
||||
extractValue: boolean
|
||||
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> {
|
||||
if (props.multi || props.multiple) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.split(props.delimiter || ',')
|
||||
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 || ',')
|
||||
}
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
if (value === null || value === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
value = [value]
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
.filter((item: Option) => item) as Array<Option>
|
||||
}
|
||||
|
||||
if (!Array.isArray(value)) {
|
||||
if (value === null || value === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
value = [value]
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
.filter((item: Option) => item) as Array<Option>
|
||||
}
|
||||
|
||||
let expandedValue = expandValue(value as OptionValue, props)
|
||||
return expandedValue ? [expandedValue] : []
|
||||
let expandedValue = expandValue(value as OptionValue, props)
|
||||
return expandedValue ? [expandedValue] : []
|
||||
}
|
||||
|
||||
export function expandValue(
|
||||
value: OptionValue,
|
||||
props: Partial<OptionProps>
|
||||
): Option | null {
|
||||
const valueType = typeof value
|
||||
export function expandValue(value: OptionValue, props: Partial<OptionProps>): Option | null {
|
||||
const valueType = typeof value
|
||||
|
||||
if (
|
||||
valueType !== 'string' &&
|
||||
valueType !== 'number' &&
|
||||
valueType !== 'boolean' &&
|
||||
valueType !== 'object'
|
||||
) {
|
||||
return null
|
||||
}
|
||||
if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean' && valueType !== 'object') {
|
||||
return null
|
||||
}
|
||||
|
||||
let { options, valueField } = props
|
||||
let {options, valueField} = props
|
||||
|
||||
if (!options) {
|
||||
return null
|
||||
}
|
||||
if (!options) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (valueType === 'object') {
|
||||
value = (value as Option)[valueField || 'value'] || ''
|
||||
}
|
||||
if (valueType === 'object') {
|
||||
value = (value as Option)[valueField || 'value'] || ''
|
||||
}
|
||||
|
||||
return find(
|
||||
flattenTree(options),
|
||||
item => String(item[valueField || 'value']) === String(value)
|
||||
) as Option
|
||||
return find(flattenTree(options), item => String(item[valueField || 'value']) === String(value)) as Option
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,140 +99,126 @@ export function expandValue(
|
||||
* ]
|
||||
*/
|
||||
interface CheckboxesProps extends OptionProps {
|
||||
id?: string
|
||||
key?: string
|
||||
className?: string
|
||||
type: string
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
value?: string
|
||||
onChange?: Function
|
||||
inline?: boolean
|
||||
columnsCount?: number
|
||||
checked?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
id?: string
|
||||
key?: string
|
||||
className?: string
|
||||
type: string
|
||||
placeholder?: string
|
||||
disabled?: boolean
|
||||
value?: string
|
||||
onChange?: Function
|
||||
inline?: boolean
|
||||
columnsCount?: number
|
||||
checked?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class Checkboxes extends React.PureComponent<CheckboxesProps, any> {
|
||||
static defaultProps = {
|
||||
joinValues: true,
|
||||
extractValue: false,
|
||||
inline: false,
|
||||
delimiter: ',',
|
||||
columnsCount: 1 // 一行显示一个
|
||||
}
|
||||
|
||||
toggleOption(option: Option) {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
joinValues,
|
||||
extractValue,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
} = this.props
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
})
|
||||
let idx = valueArray.indexOf(option)
|
||||
|
||||
if (!~idx) {
|
||||
option =
|
||||
value2array(option[valueField || 'value'], {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
})[0] || option
|
||||
idx = valueArray.indexOf(option)
|
||||
static defaultProps = {
|
||||
joinValues: true,
|
||||
extractValue: false,
|
||||
inline: false,
|
||||
delimiter: ',',
|
||||
columnsCount: 1, // 一行显示一个
|
||||
}
|
||||
|
||||
if (~idx) {
|
||||
valueArray.splice(idx, 1)
|
||||
} else {
|
||||
valueArray.push(option)
|
||||
toggleOption(option: Option) {
|
||||
const {value, onChange, joinValues, extractValue, delimiter, valueField, options} = this.props
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
})
|
||||
let idx = valueArray.indexOf(option)
|
||||
|
||||
if (!~idx) {
|
||||
option =
|
||||
value2array(option[valueField || 'value'], {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
})[0] || option
|
||||
idx = valueArray.indexOf(option)
|
||||
}
|
||||
|
||||
if (~idx) {
|
||||
valueArray.splice(idx, 1)
|
||||
} else {
|
||||
valueArray.push(option)
|
||||
}
|
||||
|
||||
let newValue: string | Array<Option> = valueArray
|
||||
|
||||
if (joinValues) {
|
||||
newValue = newValue.map(item => item[valueField || 'value']).join(delimiter)
|
||||
} else if (extractValue) {
|
||||
newValue = newValue.map(item => item[valueField || 'value'])
|
||||
}
|
||||
|
||||
onChange && onChange(newValue)
|
||||
}
|
||||
|
||||
let newValue: string | Array<Option> = valueArray
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
className,
|
||||
placeholder,
|
||||
columnsCount,
|
||||
disabled,
|
||||
inline,
|
||||
} = this.props
|
||||
|
||||
if (joinValues) {
|
||||
newValue = newValue
|
||||
.map(item => item[valueField || 'value'])
|
||||
.join(delimiter)
|
||||
} else if (extractValue) {
|
||||
newValue = newValue.map(item => item[valueField || 'value'])
|
||||
let valueArray = value2array(value, {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
})
|
||||
let body: Array<React.ReactNode> = []
|
||||
|
||||
if (options) {
|
||||
body = options.map((option, key) => (
|
||||
<Checkbox
|
||||
key={key}
|
||||
onChange={() => this.toggleOption(option)}
|
||||
checked={!!~valueArray.indexOf(option)}
|
||||
disabled={disabled || option.disabled}
|
||||
inline={inline}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
))
|
||||
}
|
||||
|
||||
if (!inline && (columnsCount as number) > 1) {
|
||||
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>
|
||||
))
|
||||
}
|
||||
|
||||
return <div className={className}>{body && body.length ? body : placeholder}</div>
|
||||
}
|
||||
|
||||
onChange && onChange(newValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
valueField,
|
||||
delimiter,
|
||||
options,
|
||||
className,
|
||||
placeholder,
|
||||
columnsCount,
|
||||
disabled,
|
||||
inline
|
||||
} = this.props
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: true,
|
||||
valueField,
|
||||
delimiter,
|
||||
options
|
||||
})
|
||||
let body: Array<React.ReactNode> = []
|
||||
|
||||
if (options) {
|
||||
body = options.map((option, key) => (
|
||||
<Checkbox
|
||||
key={key}
|
||||
onChange={() => this.toggleOption(option)}
|
||||
checked={!!~valueArray.indexOf(option)}
|
||||
disabled={disabled || option.disabled}
|
||||
inline={inline}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
))
|
||||
}
|
||||
|
||||
if (!inline && (columnsCount as number) > 1) {
|
||||
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>
|
||||
))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{body && body.length ? body : placeholder}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange'
|
||||
})
|
||||
uncontrollable(Checkboxes, {
|
||||
value: 'onChange',
|
||||
})
|
||||
)
|
||||
|
@ -1,3 +1,3 @@
|
||||
import { Collapse } from 'react-bootstrap'
|
||||
import {Collapse} from 'react-bootstrap'
|
||||
|
||||
export default Collapse
|
||||
|
@ -6,262 +6,248 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as cx from 'classnames'
|
||||
import { findDOMNode } from 'react-dom'
|
||||
import { SketchPicker, ColorResult } from 'react-color'
|
||||
import { closeIcon } from './icons'
|
||||
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
|
||||
format: string
|
||||
// closeOnSelect:boolean;
|
||||
clearable: boolean
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
popOverContainer?: any
|
||||
placement?: string
|
||||
value: any
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onChange: (value: any) => void
|
||||
placeholder?: string
|
||||
format: string
|
||||
// closeOnSelect:boolean;
|
||||
clearable: boolean
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
popOverContainer?: any
|
||||
placement?: string
|
||||
value: any
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onChange: (value: any) => void
|
||||
}
|
||||
|
||||
export interface ColorControlState {
|
||||
isOpened: boolean
|
||||
isFocused: boolean
|
||||
inputValue: string
|
||||
isOpened: boolean
|
||||
isFocused: boolean
|
||||
inputValue: string
|
||||
}
|
||||
|
||||
export class ColorControl extends React.PureComponent<
|
||||
ColorProps,
|
||||
ColorControlState
|
||||
> {
|
||||
static defaultProps = {
|
||||
format: 'hex',
|
||||
clearable: true,
|
||||
placeholder: '请选择颜色'
|
||||
// closeOnSelect: true
|
||||
}
|
||||
state = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
inputValue: this.props.value || ''
|
||||
}
|
||||
popover: any
|
||||
closeTimer: number
|
||||
preview: React.RefObject<HTMLElement>
|
||||
input: React.RefObject<HTMLInputElement>
|
||||
constructor(props: ColorProps) {
|
||||
super(props)
|
||||
|
||||
this.open = this.open.bind(this)
|
||||
this.close = this.close.bind(this)
|
||||
this.focus = this.focus.bind(this)
|
||||
this.blur = this.blur.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleFocus = this.handleFocus.bind(this)
|
||||
this.handleBlur = this.handleBlur.bind(this)
|
||||
this.clearValue = this.clearValue.bind(this)
|
||||
this.handleInputChange = this.handleInputChange.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.preview = React.createRef()
|
||||
this.input = React.createRef()
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: ColorProps) {
|
||||
const props = this.props
|
||||
|
||||
if (props.value !== nextProps.value) {
|
||||
this.setState({
|
||||
inputValue: nextProps.value || ''
|
||||
})
|
||||
export class ColorControl extends React.PureComponent<ColorProps, ColorControlState> {
|
||||
static defaultProps = {
|
||||
format: 'hex',
|
||||
clearable: true,
|
||||
placeholder: '请选择颜色',
|
||||
// closeOnSelect: true
|
||||
}
|
||||
}
|
||||
|
||||
handleFocus() {
|
||||
this.setState({
|
||||
isFocused: true
|
||||
})
|
||||
}
|
||||
|
||||
handleBlur() {
|
||||
this.setState({
|
||||
isFocused: false,
|
||||
inputValue: this.props.value
|
||||
})
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.input.current && this.input.current.focus()
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.input.current && this.input.current.blur()
|
||||
}
|
||||
|
||||
open(fn?: () => void) {
|
||||
if (this.props.disabled) {
|
||||
return
|
||||
state = {
|
||||
isOpened: false,
|
||||
isFocused: false,
|
||||
inputValue: this.props.value || '',
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
isOpened: true
|
||||
},
|
||||
fn
|
||||
)
|
||||
}
|
||||
popover: any
|
||||
closeTimer: number
|
||||
preview: React.RefObject<HTMLElement>
|
||||
input: React.RefObject<HTMLInputElement>
|
||||
constructor(props: ColorProps) {
|
||||
super(props)
|
||||
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
})
|
||||
}
|
||||
this.open = this.open.bind(this)
|
||||
this.close = this.close.bind(this)
|
||||
this.focus = this.focus.bind(this)
|
||||
this.blur = this.blur.bind(this)
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleFocus = this.handleFocus.bind(this)
|
||||
this.handleBlur = this.handleBlur.bind(this)
|
||||
this.clearValue = this.clearValue.bind(this)
|
||||
this.handleInputChange = this.handleInputChange.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.preview = React.createRef()
|
||||
this.input = React.createRef()
|
||||
}
|
||||
|
||||
clearValue() {
|
||||
const onChange = this.props.onChange
|
||||
onChange('')
|
||||
}
|
||||
componentWillReceiveProps(nextProps: ColorProps) {
|
||||
const props = this.props
|
||||
|
||||
handleClick() {
|
||||
this.state.isOpened ? this.close() : this.open(this.focus)
|
||||
}
|
||||
|
||||
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)
|
||||
if (props.value !== nextProps.value) {
|
||||
this.setState({
|
||||
inputValue: nextProps.value || '',
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleChange(color: ColorResult) {
|
||||
const {
|
||||
onChange,
|
||||
format
|
||||
// closeOnSelect
|
||||
} = 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 {
|
||||
onChange(color.hex)
|
||||
}
|
||||
|
||||
// closeOnSelect && this.close();
|
||||
}
|
||||
handleFocus() {
|
||||
this.setState({
|
||||
isFocused: true,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
value,
|
||||
placeholder,
|
||||
disabled,
|
||||
popOverContainer,
|
||||
format,
|
||||
clearable,
|
||||
placement,
|
||||
classnames: cx
|
||||
} = this.props
|
||||
handleBlur() {
|
||||
this.setState({
|
||||
isFocused: false,
|
||||
inputValue: this.props.value,
|
||||
})
|
||||
}
|
||||
|
||||
const isOpened = this.state.isOpened
|
||||
const isFocused = this.state.isFocused
|
||||
focus() {
|
||||
this.input.current && this.input.current.focus()
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
`ColorPicker`,
|
||||
{
|
||||
'is-disabled': disabled,
|
||||
'is-focused': isFocused
|
||||
},
|
||||
className
|
||||
)}
|
||||
>
|
||||
<input
|
||||
size={10}
|
||||
ref={this.input}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
className={cx('ColorPicker-input')}
|
||||
value={this.state.inputValue || ''}
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
onChange={this.handleInputChange}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
blur() {
|
||||
this.input.current && this.input.current.blur()
|
||||
}
|
||||
|
||||
{clearable && !disabled && value ? (
|
||||
<a onClick={this.clearValue} className={cx('ColorPicker-clear')}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
) : null}
|
||||
open(fn?: () => void) {
|
||||
if (this.props.disabled) {
|
||||
return
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
isOpened: true,
|
||||
},
|
||||
fn
|
||||
)
|
||||
}
|
||||
|
||||
<span onClick={this.handleClick} className={cx('ColorPicker-preview')}>
|
||||
<i
|
||||
ref={this.preview}
|
||||
className={`${ns}ColorPicker-previewIcon`}
|
||||
style={{ background: this.state.inputValue || '#ccc' }}
|
||||
/>
|
||||
</span>
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false,
|
||||
})
|
||||
}
|
||||
|
||||
{isOpened ? (
|
||||
<Overlay
|
||||
placement={
|
||||
placement || 'left-bottom-left-top right-bottom-right-top'
|
||||
clearValue() {
|
||||
const onChange = this.props.onChange
|
||||
onChange('')
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
this.state.isOpened ? this.close() : this.open(this.focus)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
target={() => findDOMNode(this)}
|
||||
onHide={this.close}
|
||||
container={popOverContainer || (() => findDOMNode(this))}
|
||||
rootClose={false}
|
||||
show
|
||||
>
|
||||
<PopOver
|
||||
classPrefix={ns}
|
||||
className={cx('ColorPicker-popover')}
|
||||
onHide={this.close}
|
||||
overlay
|
||||
)
|
||||
}
|
||||
|
||||
handleChange(color: ColorResult) {
|
||||
const {
|
||||
onChange,
|
||||
format,
|
||||
// closeOnSelect
|
||||
} = 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 {
|
||||
onChange(color.hex)
|
||||
}
|
||||
|
||||
// closeOnSelect && this.close();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
value,
|
||||
placeholder,
|
||||
disabled,
|
||||
popOverContainer,
|
||||
format,
|
||||
clearable,
|
||||
placement,
|
||||
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
|
||||
)}
|
||||
>
|
||||
<SketchPicker
|
||||
disableAlpha={!!~['rgb', 'hex'].indexOf(format as string)}
|
||||
color={value}
|
||||
onChangeComplete={this.handleChange}
|
||||
/>
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<input
|
||||
size={10}
|
||||
ref={this.input}
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
className={cx('ColorPicker-input')}
|
||||
value={this.state.inputValue || ''}
|
||||
placeholder={placeholder}
|
||||
disabled={disabled}
|
||||
onChange={this.handleInputChange}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
|
||||
{clearable && !disabled && value ? (
|
||||
<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>
|
||||
|
||||
{isOpened ? (
|
||||
<Overlay
|
||||
placement={placement || 'left-bottom-left-top right-bottom-right-top'}
|
||||
target={() => findDOMNode(this)}
|
||||
onHide={this.close}
|
||||
container={popOverContainer || (() => findDOMNode(this))}
|
||||
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>
|
||||
</Overlay>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(ColorControl, {
|
||||
value: 'onChange'
|
||||
})
|
||||
uncontrollable(ColorControl, {
|
||||
value: 'onChange',
|
||||
})
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,180 +5,158 @@
|
||||
*/
|
||||
|
||||
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 {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 {classPrefix, classnames} from '../themes/default'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
import {noop} from '../utils/helper'
|
||||
|
||||
type DrawerPosition = 'top' | 'right' | 'bottom' | 'left'
|
||||
|
||||
export interface DrawerProps {
|
||||
className?: string
|
||||
size: any
|
||||
overlay: boolean
|
||||
onHide: () => void
|
||||
closeOnEsc?: boolean
|
||||
container: any
|
||||
show?: boolean
|
||||
position: DrawerPosition
|
||||
disabled?: boolean
|
||||
closeOnOutside?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onExited?: () => void
|
||||
onEntered?: () => void
|
||||
disableOnClickOutside: () => void
|
||||
enableOnClickOutside: () => void
|
||||
className?: string
|
||||
size: any
|
||||
overlay: boolean
|
||||
onHide: () => void
|
||||
closeOnEsc?: boolean
|
||||
container: any
|
||||
show?: boolean
|
||||
position: DrawerPosition
|
||||
disabled?: boolean
|
||||
closeOnOutside?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onExited?: () => void
|
||||
onEntered?: () => void
|
||||
disableOnClickOutside: () => void
|
||||
enableOnClickOutside: () => void
|
||||
}
|
||||
export interface DrawerState {}
|
||||
const fadeStyles: {
|
||||
[propName: string]: string
|
||||
[propName: string]: string
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in'
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in',
|
||||
}
|
||||
export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
||||
static defaultProps: Pick<
|
||||
DrawerProps,
|
||||
| 'container'
|
||||
| 'position'
|
||||
| 'size'
|
||||
| 'overlay'
|
||||
| 'disableOnClickOutside'
|
||||
| 'enableOnClickOutside'
|
||||
> = {
|
||||
container: document.body,
|
||||
position: 'left',
|
||||
size: 'md',
|
||||
overlay: true,
|
||||
disableOnClickOutside: noop,
|
||||
enableOnClickOutside: noop
|
||||
}
|
||||
|
||||
contentDom: any
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.handleEntered()
|
||||
static defaultProps: Pick<
|
||||
DrawerProps,
|
||||
'container' | 'position' | 'size' | 'overlay' | 'disableOnClickOutside' | 'enableOnClickOutside'
|
||||
> = {
|
||||
container: document.body,
|
||||
position: 'left',
|
||||
size: 'md',
|
||||
overlay: true,
|
||||
disableOnClickOutside: noop,
|
||||
enableOnClickOutside: noop,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.props.show) {
|
||||
this.handleExited()
|
||||
contentDom: any
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.handleEntered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentRef = (ref: any) => (this.contentDom = ref)
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered
|
||||
document.body.classList.add(`is-modalOpened`)
|
||||
onEntered && onEntered()
|
||||
}
|
||||
handleExited = () => {
|
||||
const onExited = this.props.onExited
|
||||
onExited && onExited()
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') ||
|
||||
document.body.classList.remove(`is-modalOpened`)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
modalRef = (ref: any) => {
|
||||
if (ref) {
|
||||
addModal(this)
|
||||
;(ref as HTMLElement).classList.add(
|
||||
`${this.props.classPrefix}Modal--${current()}th`
|
||||
)
|
||||
} else {
|
||||
removeModal()
|
||||
componentWillUnmount() {
|
||||
if (this.props.show) {
|
||||
this.handleExited()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClickOutside() {
|
||||
const { closeOnOutside, onHide } = this.props
|
||||
closeOnOutside && onHide && onHide()
|
||||
}
|
||||
contentRef = (ref: any) => (this.contentDom = ref)
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered
|
||||
document.body.classList.add(`is-modalOpened`)
|
||||
onEntered && onEntered()
|
||||
}
|
||||
handleExited = () => {
|
||||
const onExited = this.props.onExited
|
||||
onExited && onExited()
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') || document.body.classList.remove(`is-modalOpened`)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
children,
|
||||
container,
|
||||
show,
|
||||
position,
|
||||
size,
|
||||
onHide,
|
||||
disabled,
|
||||
overlay
|
||||
} = this.props
|
||||
modalRef = (ref: any) => {
|
||||
if (ref) {
|
||||
addModal(this)
|
||||
;(ref as HTMLElement).classList.add(`${this.props.classPrefix}Modal--${current()}th`)
|
||||
} else {
|
||||
removeModal()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={show}
|
||||
timeout={500}
|
||||
onExited={this.handleExited}
|
||||
onEntered={this.handleEntered}
|
||||
>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.contentDom.offsetWidth
|
||||
}
|
||||
handleClickOutside() {
|
||||
const {closeOnOutside, onHide} = this.props
|
||||
closeOnOutside && onHide && onHide()
|
||||
}
|
||||
|
||||
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.contentRef}
|
||||
className={cx(`${ns}Drawer-content`, fadeStyles[status])}
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
children,
|
||||
container,
|
||||
show,
|
||||
position,
|
||||
size,
|
||||
onHide,
|
||||
disabled,
|
||||
overlay,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={show}
|
||||
timeout={500}
|
||||
onExited={this.handleExited}
|
||||
onEntered={this.handleEntered}
|
||||
>
|
||||
<a
|
||||
onClick={disabled ? undefined : onHide}
|
||||
className={`${ns}Drawer-close`}
|
||||
>
|
||||
{closeIcon}
|
||||
</a>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.contentDom.offsetWidth
|
||||
}
|
||||
|
||||
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.contentRef} className={cx(`${ns}Drawer-content`, fadeStyles[status])}>
|
||||
<a onClick={disabled ? undefined : onHide} className={`${ns}Drawer-close`}>
|
||||
{closeIcon}
|
||||
</a>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(onClickOutside(Drawer))
|
||||
|
@ -1,3 +1,3 @@
|
||||
import { DropdownButton } from 'react-bootstrap'
|
||||
import {DropdownButton} from 'react-bootstrap'
|
||||
|
||||
export default DropdownButton
|
||||
|
@ -6,490 +6,369 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as cx from 'classnames'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
|
||||
function noJsExt(raw: string) {
|
||||
return raw.replace(/\.js$/, '')
|
||||
return raw.replace(/\.js$/, '')
|
||||
}
|
||||
|
||||
const defaultConfig = {
|
||||
url: 'vs/loader.js',
|
||||
'vs/nls': {
|
||||
availableLanguages: {
|
||||
'*': 'zh-cn'
|
||||
}
|
||||
},
|
||||
paths: {}
|
||||
url: 'vs/loader.js',
|
||||
'vs/nls': {
|
||||
availableLanguages: {
|
||||
'*': 'zh-cn',
|
||||
},
|
||||
},
|
||||
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/base/worker/workerMain': noJsExt(
|
||||
__uri('monaco-editor/min/vs/base/worker/workerMain.js')
|
||||
),
|
||||
// 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/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')
|
||||
),
|
||||
'vs/basic-languages/azcli/azcli': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/azcli/azcli')
|
||||
),
|
||||
'vs/basic-languages/clojure/clojure': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/clojure/clojure')
|
||||
),
|
||||
'vs/basic-languages/bat/bat': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/bat/bat')
|
||||
),
|
||||
'vs/basic-languages/coffee/coffee': noJsExt(
|
||||
__uri('monaco-editor/min/vs/basic-languages/coffee/coffee')
|
||||
),
|
||||
'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/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/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/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/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/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/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/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/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/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')
|
||||
),
|
||||
'vs/basic-languages/apex/apex': noJsExt(__uri('monaco-editor/min/vs/basic-languages/apex/apex')),
|
||||
'vs/basic-languages/azcli/azcli': noJsExt(__uri('monaco-editor/min/vs/basic-languages/azcli/azcli')),
|
||||
'vs/basic-languages/clojure/clojure': noJsExt(__uri('monaco-editor/min/vs/basic-languages/clojure/clojure')),
|
||||
'vs/basic-languages/bat/bat': noJsExt(__uri('monaco-editor/min/vs/basic-languages/bat/bat')),
|
||||
'vs/basic-languages/coffee/coffee': noJsExt(__uri('monaco-editor/min/vs/basic-languages/coffee/coffee')),
|
||||
'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/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/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/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/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/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/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/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/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/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')),
|
||||
|
||||
'vs/editor/editor.main': noJsExt(
|
||||
__uri('monaco-editor/min/vs/editor/editor.main.js')
|
||||
),
|
||||
'vs/editor/editor.main.css': noJsExt(
|
||||
__uri('monaco-editor/min/vs/editor/editor.main.css')
|
||||
),
|
||||
'vs/editor/editor.main.nls': noJsExt(
|
||||
__uri('monaco-editor/min/vs/editor/editor.main.nls.js')
|
||||
),
|
||||
'vs/editor/editor.main.nls.zh-cn': noJsExt(
|
||||
__uri('monaco-editor/min/vs/editor/editor.main.nls.zh-cn.js')
|
||||
),
|
||||
'vs/editor/editor.main': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')),
|
||||
'vs/editor/editor.main.css': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.css')),
|
||||
'vs/editor/editor.main.nls': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.nls.js')),
|
||||
'vs/editor/editor.main.nls.zh-cn': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.nls.zh-cn.js')),
|
||||
|
||||
// 'vs/editor/contrib/suggest/media/String_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_16x.svg')),
|
||||
// 'vs/editor/contrib/suggest/media/String_inverse_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_inverse_16x.svg')),
|
||||
// 'vs/editor/standalone/browser/quickOpen/symbol-sprite.svg': noJsExt(__uri('monaco-editor/min/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg')),
|
||||
// 'vs/editor/contrib/suggest/media/String_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_16x.svg')),
|
||||
// 'vs/editor/contrib/suggest/media/String_inverse_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_inverse_16x.svg')),
|
||||
// 'vs/editor/standalone/browser/quickOpen/symbol-sprite.svg': noJsExt(__uri('monaco-editor/min/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg')),
|
||||
|
||||
'vs/language/typescript/tsMode': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/typescript/tsMode.js')
|
||||
),
|
||||
// 'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('monaco-editor/min/vs/language/typescript/lib/typescriptServices.js')),
|
||||
'vs/language/typescript/tsWorker': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/typescript/tsWorker.js')
|
||||
),
|
||||
'vs/language/typescript/tsMode': noJsExt(__uri('monaco-editor/min/vs/language/typescript/tsMode.js')),
|
||||
// 'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('monaco-editor/min/vs/language/typescript/lib/typescriptServices.js')),
|
||||
'vs/language/typescript/tsWorker': noJsExt(__uri('monaco-editor/min/vs/language/typescript/tsWorker.js')),
|
||||
|
||||
'vs/language/json/jsonMode': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/json/jsonMode.js')
|
||||
),
|
||||
'vs/language/json/jsonWorker': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/json/jsonWorker.js')
|
||||
),
|
||||
'vs/language/json/jsonMode': noJsExt(__uri('monaco-editor/min/vs/language/json/jsonMode.js')),
|
||||
'vs/language/json/jsonWorker': noJsExt(__uri('monaco-editor/min/vs/language/json/jsonWorker.js')),
|
||||
|
||||
'vs/language/html/htmlMode': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/html/htmlMode.js')
|
||||
),
|
||||
'vs/language/html/htmlWorker': noJsExt(
|
||||
__uri('monaco-editor/min/vs/language/html/htmlWorker.js')
|
||||
),
|
||||
'vs/language/html/htmlMode': noJsExt(__uri('monaco-editor/min/vs/language/html/htmlMode.js')),
|
||||
'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/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')),
|
||||
}
|
||||
|
||||
// cdn 支持
|
||||
;/^(https?:)?\/\//.test(defaultConfig.paths.vs) &&
|
||||
((window as any).MonacoEnvironment = {
|
||||
getWorkerUrl: function() {
|
||||
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
|
||||
// cdn 支持
|
||||
;/^(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'
|
||||
)}');`)}`
|
||||
}
|
||||
})
|
||||
importScripts('${__uri('monaco-editor/min/vs/base/worker/workerMain.js')}');`)}`
|
||||
},
|
||||
})
|
||||
} catch (e) {}
|
||||
|
||||
export function monacoFactory(containerElement, monaco, options) {
|
||||
return monaco.editor.create(containerElement, {
|
||||
autoIndent: true,
|
||||
formatOnType: true,
|
||||
formatOnPaste: true,
|
||||
selectOnLineNumbers: true,
|
||||
scrollBeyondLastLine: false,
|
||||
folding: true,
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
...options
|
||||
})
|
||||
return monaco.editor.create(containerElement, {
|
||||
autoIndent: true,
|
||||
formatOnType: true,
|
||||
formatOnPaste: true,
|
||||
selectOnLineNumbers: true,
|
||||
scrollBeyondLastLine: false,
|
||||
folding: true,
|
||||
minimap: {
|
||||
enabled: false,
|
||||
},
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
export interface EditorProps {
|
||||
value?: string
|
||||
defaultValue?: string
|
||||
width?: number | string
|
||||
height?: number | string
|
||||
onChange?: (value: string, event: any) => void
|
||||
language?: string
|
||||
editorTheme?: string
|
||||
options: {
|
||||
[propName: string]: any
|
||||
}
|
||||
classPrefix: string
|
||||
className?: string
|
||||
classnames: ClassNamesFn
|
||||
context?: any
|
||||
style?: any
|
||||
onFocus?: () => void
|
||||
onBlur?: () => void
|
||||
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
|
||||
}
|
||||
value?: string
|
||||
defaultValue?: string
|
||||
width?: number | string
|
||||
height?: number | string
|
||||
onChange?: (value: string, event: any) => void
|
||||
language?: string
|
||||
editorTheme?: string
|
||||
options: {
|
||||
[propName: string]: any
|
||||
}
|
||||
classPrefix: string
|
||||
className?: string
|
||||
classnames: ClassNamesFn
|
||||
context?: any
|
||||
style?: any
|
||||
onFocus?: () => void
|
||||
onBlur?: () => void
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
export class Editor extends React.Component<EditorProps, any> {
|
||||
static defaultProps = {
|
||||
requireConfig: defaultConfig,
|
||||
language: 'javascript',
|
||||
editorTheme: 'vs',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
options: {}
|
||||
}
|
||||
|
||||
editor: any
|
||||
container: any
|
||||
currentValue: any
|
||||
preventTriggerChangeEvent: boolean
|
||||
disposes: Array<{ dispose: () => void }> = []
|
||||
constructor(props: EditorProps) {
|
||||
super(props)
|
||||
|
||||
this.wrapperRef = this.wrapperRef.bind(this)
|
||||
this.currentValue = props.value
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: EditorProps) {
|
||||
if (
|
||||
this.props.options.readOnly !== nextProps.options.readOnly &&
|
||||
this.editor
|
||||
) {
|
||||
this.editor.updateOptions && this.editor.updateOptions(nextProps.options)
|
||||
static defaultProps = {
|
||||
requireConfig: defaultConfig,
|
||||
language: 'javascript',
|
||||
editorTheme: 'vs',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
options: {},
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.props.value !== this.currentValue && this.editor) {
|
||||
let value = String(this.props.value)
|
||||
editor: any
|
||||
container: any
|
||||
currentValue: any
|
||||
preventTriggerChangeEvent: boolean
|
||||
disposes: Array<{dispose: () => void}> = []
|
||||
constructor(props: EditorProps) {
|
||||
super(props)
|
||||
|
||||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(JSON.parse(value), null, 4)
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
this.preventTriggerChangeEvent = true
|
||||
this.editor.setValue && this.editor.setValue(value)
|
||||
this.preventTriggerChangeEvent = false
|
||||
this.wrapperRef = this.wrapperRef.bind(this)
|
||||
this.currentValue = props.value
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.disposes.forEach(({ dispose }) => dispose())
|
||||
this.disposes = []
|
||||
}
|
||||
componentWillReceiveProps(nextProps: EditorProps) {
|
||||
if (this.props.options.readOnly !== nextProps.options.readOnly && this.editor) {
|
||||
this.editor.updateOptions && this.editor.updateOptions(nextProps.options)
|
||||
}
|
||||
}
|
||||
|
||||
wrapperRef(ref: any) {
|
||||
this.container = ref
|
||||
if (ref) {
|
||||
this.loadMonaco()
|
||||
} else {
|
||||
try {
|
||||
this.disposes.forEach(({ dispose }) => dispose())
|
||||
componentDidUpdate() {
|
||||
if (this.props.value !== this.currentValue && this.editor) {
|
||||
let value = String(this.props.value)
|
||||
|
||||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(JSON.parse(value), null, 4)
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
this.preventTriggerChangeEvent = true
|
||||
this.editor.setValue && this.editor.setValue(value)
|
||||
this.preventTriggerChangeEvent = false
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.disposes.forEach(({dispose}) => dispose())
|
||||
this.disposes = []
|
||||
if (this.editor) {
|
||||
this.editor.getModel().dispose()
|
||||
this.editor.dispose()
|
||||
}
|
||||
this.editor = null
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadMonaco() {
|
||||
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 onGotAmdLoader = () => {
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
// Do not use webpack
|
||||
if (requireConfig.paths && requireConfig.paths.vs) {
|
||||
context.require.config(requireConfig)
|
||||
}
|
||||
}
|
||||
|
||||
// Load monaco
|
||||
context['require'](
|
||||
['vs/editor/editor.main', 'vs/editor/editor.main.nls.zh-cn'],
|
||||
() => {
|
||||
this.initMonaco()
|
||||
}
|
||||
)
|
||||
|
||||
// Call the delayed callbacks when AMD loader has been loaded
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = false
|
||||
let loaderCallbacks = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__
|
||||
if (loaderCallbacks && loaderCallbacks.length) {
|
||||
let currentCallback = loaderCallbacks.shift()
|
||||
while (currentCallback) {
|
||||
currentCallback.fn.call(currentCallback.context)
|
||||
currentCallback = loaderCallbacks.shift()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load AMD loader if necessary
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
// We need to avoid loading multiple loader.js when there are multiple editors loading concurrently
|
||||
// delay to call callbacks except the first one
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ =
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || []
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__.push({
|
||||
context: this,
|
||||
fn: onGotAmdLoader
|
||||
})
|
||||
} else {
|
||||
if (typeof context.require === 'undefined') {
|
||||
var loaderScript = context.document.createElement('script')
|
||||
loaderScript.type = 'text/javascript'
|
||||
loaderScript.src = loaderUrl
|
||||
loaderScript.addEventListener('load', onGotAmdLoader)
|
||||
context.document.body.appendChild(loaderScript)
|
||||
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = true
|
||||
} else {
|
||||
onGotAmdLoader()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initMonaco() {
|
||||
let value =
|
||||
this.props.value !== null ? this.props.value : this.props.defaultValue
|
||||
const { language, editorTheme, options, editorFactory } = this.props
|
||||
const containerElement = this.container
|
||||
if (!containerElement) {
|
||||
return
|
||||
}
|
||||
const context = this.props.context || window
|
||||
const monaco = context.monaco || (window as any).monaco
|
||||
if (typeof monaco !== 'undefined') {
|
||||
// Before initializing monaco editor
|
||||
this.editorWillMount(monaco)
|
||||
|
||||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(
|
||||
typeof value === 'string' ? JSON.parse(value) : value,
|
||||
null,
|
||||
4
|
||||
)
|
||||
} catch (e) {
|
||||
// ignore
|
||||
wrapperRef(ref: any) {
|
||||
this.container = ref
|
||||
if (ref) {
|
||||
this.loadMonaco()
|
||||
} else {
|
||||
try {
|
||||
this.disposes.forEach(({dispose}) => dispose())
|
||||
this.disposes = []
|
||||
if (this.editor) {
|
||||
this.editor.getModel().dispose()
|
||||
this.editor.dispose()
|
||||
}
|
||||
this.editor = null
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const factory = editorFactory || monacoFactory
|
||||
this.editor = factory(containerElement, monaco, {
|
||||
...options,
|
||||
automaticLayout: true,
|
||||
value,
|
||||
language,
|
||||
editorTheme,
|
||||
theme: editorTheme
|
||||
})
|
||||
|
||||
// After initializing monaco editor
|
||||
this.editorDidMount(this.editor, monaco)
|
||||
}
|
||||
}
|
||||
|
||||
editorWillMount(monaco: any) {
|
||||
const { editorWillMount } = this.props
|
||||
editorWillMount && editorWillMount(monaco)
|
||||
}
|
||||
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
|
||||
loadMonaco() {
|
||||
const {requireConfig} = this.props
|
||||
const loaderUrl = requireConfig.url || 'vs/loader.js'
|
||||
const context =
|
||||
(window as any).monacaAmd ||
|
||||
((window as any).monacaAmd = {
|
||||
document: window.document,
|
||||
})
|
||||
|
||||
// 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))
|
||||
}
|
||||
const onGotAmdLoader = () => {
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
// Do not use webpack
|
||||
if (requireConfig.paths && requireConfig.paths.vs) {
|
||||
context.require.config(requireConfig)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, classPrefix: ns, width, height } = this.props
|
||||
let style = this.props.style || {}
|
||||
style.width = width
|
||||
style.height = height
|
||||
// Load monaco
|
||||
context['require'](['vs/editor/editor.main', 'vs/editor/editor.main.nls.zh-cn'], () => {
|
||||
this.initMonaco()
|
||||
})
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`${ns}MonacoEditor`, className)}
|
||||
style={style}
|
||||
ref={this.wrapperRef}
|
||||
/>
|
||||
)
|
||||
}
|
||||
// Call the delayed callbacks when AMD loader has been loaded
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = false
|
||||
let loaderCallbacks = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__
|
||||
if (loaderCallbacks && loaderCallbacks.length) {
|
||||
let currentCallback = loaderCallbacks.shift()
|
||||
while (currentCallback) {
|
||||
currentCallback.fn.call(currentCallback.context)
|
||||
currentCallback = loaderCallbacks.shift()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load AMD loader if necessary
|
||||
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
|
||||
// We need to avoid loading multiple loader.js when there are multiple editors loading concurrently
|
||||
// delay to call callbacks except the first one
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || []
|
||||
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__.push({
|
||||
context: this,
|
||||
fn: onGotAmdLoader,
|
||||
})
|
||||
} else {
|
||||
if (typeof context.require === 'undefined') {
|
||||
var loaderScript = context.document.createElement('script')
|
||||
loaderScript.type = 'text/javascript'
|
||||
loaderScript.src = loaderUrl
|
||||
loaderScript.addEventListener('load', onGotAmdLoader)
|
||||
context.document.body.appendChild(loaderScript)
|
||||
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = true
|
||||
} else {
|
||||
onGotAmdLoader()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initMonaco() {
|
||||
let value = this.props.value !== null ? this.props.value : this.props.defaultValue
|
||||
const {language, editorTheme, options, editorFactory} = this.props
|
||||
const containerElement = this.container
|
||||
if (!containerElement) {
|
||||
return
|
||||
}
|
||||
const context = this.props.context || window
|
||||
const monaco = context.monaco || (window as any).monaco
|
||||
if (typeof monaco !== 'undefined') {
|
||||
// Before initializing monaco editor
|
||||
this.editorWillMount(monaco)
|
||||
|
||||
if (this.props.language === 'json') {
|
||||
try {
|
||||
value = JSON.stringify(typeof value === 'string' ? JSON.parse(value) : value, null, 4)
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
const factory = editorFactory || monacoFactory
|
||||
this.editor = factory(containerElement, monaco, {
|
||||
...options,
|
||||
automaticLayout: true,
|
||||
value,
|
||||
language,
|
||||
editorTheme,
|
||||
theme: editorTheme,
|
||||
})
|
||||
|
||||
// After initializing monaco editor
|
||||
this.editorDidMount(this.editor, monaco)
|
||||
}
|
||||
}
|
||||
|
||||
editorWillMount(monaco: any) {
|
||||
const {editorWillMount} = this.props
|
||||
editorWillMount && editorWillMount(monaco)
|
||||
}
|
||||
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
|
||||
|
||||
// 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
|
||||
let style = this.props.style || {}
|
||||
style.width = width
|
||||
style.height = height
|
||||
|
||||
return <div className={cx(`${ns}MonacoEditor`, className)} style={style} ref={this.wrapperRef} />
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Editor)
|
||||
|
@ -6,63 +6,61 @@
|
||||
|
||||
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
|
||||
html?: string
|
||||
wrapperComponent?: any
|
||||
inline: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
className?: string
|
||||
html?: string
|
||||
wrapperComponent?: any
|
||||
inline: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class Html extends React.Component<HtmlProps> {
|
||||
static defaultProps = {
|
||||
inline: true
|
||||
}
|
||||
|
||||
dom: any
|
||||
|
||||
constructor(props: HtmlProps) {
|
||||
super(props)
|
||||
this.htmlRef = this.htmlRef.bind(this)
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: HtmlProps) {
|
||||
if (this.props.html !== prevProps.html) {
|
||||
this._render()
|
||||
}
|
||||
}
|
||||
|
||||
htmlRef(dom: any) {
|
||||
this.dom = dom
|
||||
|
||||
if (!dom) {
|
||||
return
|
||||
static defaultProps = {
|
||||
inline: true,
|
||||
}
|
||||
|
||||
this._render()
|
||||
}
|
||||
dom: any
|
||||
|
||||
_render() {
|
||||
const { html } = this.props
|
||||
|
||||
if (html) {
|
||||
this.dom.innerHTML = html
|
||||
constructor(props: HtmlProps) {
|
||||
super(props)
|
||||
this.htmlRef = this.htmlRef.bind(this)
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, wrapperComponent, inline, classPrefix: ns } = this.props
|
||||
componentDidUpdate(prevProps: HtmlProps) {
|
||||
if (this.props.html !== prevProps.html) {
|
||||
this._render()
|
||||
}
|
||||
}
|
||||
|
||||
const Component = wrapperComponent || (inline ? 'span' : 'div')
|
||||
htmlRef(dom: any) {
|
||||
this.dom = dom
|
||||
|
||||
return (
|
||||
<Component ref={this.htmlRef} className={cx(`${ns}Html`, className)} />
|
||||
)
|
||||
}
|
||||
if (!dom) {
|
||||
return
|
||||
}
|
||||
|
||||
this._render()
|
||||
}
|
||||
|
||||
_render() {
|
||||
const {html} = this.props
|
||||
|
||||
if (html) {
|
||||
this.dom.innerHTML = html
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className, wrapperComponent, inline, classPrefix: ns} = this.props
|
||||
|
||||
const Component = wrapperComponent || (inline ? 'span' : 'div')
|
||||
|
||||
return <Component ref={this.htmlRef} className={cx(`${ns}Html`, className)} />
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Html)
|
||||
|
@ -18,99 +18,97 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as cx from 'classnames'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
|
||||
interface LayoutProps {
|
||||
id: string
|
||||
header?: boolean | React.ReactNode
|
||||
aside?: boolean | React.ReactNode
|
||||
asideClassName: string
|
||||
folded?: boolean
|
||||
asideFixed: boolean
|
||||
headerFixed: boolean
|
||||
className?: string
|
||||
contentClassName?: string
|
||||
footer: boolean | React.ReactNode
|
||||
asideWide: boolean
|
||||
offScreen: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
size?: 'sm' | 'base' | 'md' | 'lg'
|
||||
id: string
|
||||
header?: boolean | React.ReactNode
|
||||
aside?: boolean | React.ReactNode
|
||||
asideClassName: string
|
||||
folded?: boolean
|
||||
asideFixed: boolean
|
||||
headerFixed: boolean
|
||||
className?: string
|
||||
contentClassName?: string
|
||||
footer: boolean | React.ReactNode
|
||||
asideWide: boolean
|
||||
offScreen: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
size?: 'sm' | 'base' | 'md' | 'lg'
|
||||
}
|
||||
|
||||
export class Layout extends React.Component<LayoutProps, any> {
|
||||
static defaultProps = {
|
||||
// asideWide: false,
|
||||
asideFixed: true,
|
||||
asideClassName: '',
|
||||
headerFixed: true,
|
||||
offScreen: false,
|
||||
footer: false
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
header,
|
||||
aside,
|
||||
// asideWide,
|
||||
asideClassName,
|
||||
children,
|
||||
className,
|
||||
contentClassName,
|
||||
folded,
|
||||
asideFixed,
|
||||
headerFixed,
|
||||
footer,
|
||||
offScreen,
|
||||
size,
|
||||
classPrefix,
|
||||
classnames: cx
|
||||
} = this.props
|
||||
|
||||
let body = (
|
||||
<div className={cx(`Layout-body`, contentClassName)}>{children}</div>
|
||||
)
|
||||
|
||||
if (aside) {
|
||||
body = (
|
||||
<div className={cx('Layout-content')} role="main">
|
||||
{body}
|
||||
</div>
|
||||
)
|
||||
static defaultProps = {
|
||||
// asideWide: false,
|
||||
asideFixed: true,
|
||||
asideClassName: '',
|
||||
headerFixed: true,
|
||||
offScreen: false,
|
||||
footer: false,
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`Layout`, className, {
|
||||
'Layout--withAside': !!aside,
|
||||
'Layout--headerFixed': header ? headerFixed : false,
|
||||
'Layout--asideFixed': aside ? asideFixed : false,
|
||||
// 'Layout--wide': aside ? asideWide : false,
|
||||
'Layout--folded': folded,
|
||||
'Layout--offScreen': offScreen,
|
||||
[`Layout--${size}`]: size,
|
||||
'Layout--noFooter': !footer
|
||||
})}
|
||||
>
|
||||
{header ? <div className={cx('Layout-header')}>{header}</div> : null}
|
||||
{aside ? (
|
||||
<div className={cx(`Layout-aside`, asideClassName)}>
|
||||
<div className={cx('Layout-asideWrap')}>
|
||||
<div id="asideInner" className={cx('Layout-asideInner')}>
|
||||
{aside}
|
||||
</div>
|
||||
render() {
|
||||
const {
|
||||
header,
|
||||
aside,
|
||||
// asideWide,
|
||||
asideClassName,
|
||||
children,
|
||||
className,
|
||||
contentClassName,
|
||||
folded,
|
||||
asideFixed,
|
||||
headerFixed,
|
||||
footer,
|
||||
offScreen,
|
||||
size,
|
||||
classPrefix,
|
||||
classnames: cx,
|
||||
} = this.props
|
||||
|
||||
let body = <div className={cx(`Layout-body`, contentClassName)}>{children}</div>
|
||||
|
||||
if (aside) {
|
||||
body = (
|
||||
<div className={cx('Layout-content')} role="main">
|
||||
{body}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(`Layout`, className, {
|
||||
'Layout--withAside': !!aside,
|
||||
'Layout--headerFixed': header ? headerFixed : false,
|
||||
'Layout--asideFixed': aside ? asideFixed : false,
|
||||
// 'Layout--wide': aside ? asideWide : false,
|
||||
'Layout--folded': folded,
|
||||
'Layout--offScreen': offScreen,
|
||||
[`Layout--${size}`]: size,
|
||||
'Layout--noFooter': !footer,
|
||||
})}
|
||||
>
|
||||
{header ? <div className={cx('Layout-header')}>{header}</div> : null}
|
||||
{aside ? (
|
||||
<div className={cx(`Layout-aside`, asideClassName)}>
|
||||
<div className={cx('Layout-asideWrap')}>
|
||||
<div id="asideInner" className={cx('Layout-asideInner')}>
|
||||
{aside}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{body}
|
||||
{footer ? (
|
||||
<footer className={cx('Layout-footer')} role="footer">
|
||||
{footer}
|
||||
</footer>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{body}
|
||||
{footer ? (
|
||||
<footer className={cx('Layout-footer')} role="footer">
|
||||
{footer}
|
||||
</footer>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Layout)
|
||||
|
@ -8,112 +8,96 @@ import * as React from 'react'
|
||||
import VisibilitySensor = require('react-visibility-sensor')
|
||||
|
||||
export interface LazyComponentProps {
|
||||
component?: React.ReactType
|
||||
getComponent?: () => Promise<React.ReactType>
|
||||
placeholder?: React.ReactNode
|
||||
unMountOnHidden?: boolean
|
||||
childProps?: object
|
||||
visiblilityProps?: object
|
||||
[propName: string]: any
|
||||
component?: React.ReactType
|
||||
getComponent?: () => Promise<React.ReactType>
|
||||
placeholder?: React.ReactNode
|
||||
unMountOnHidden?: boolean
|
||||
childProps?: object
|
||||
visiblilityProps?: object
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
export interface LazyComponentState {
|
||||
visible: boolean
|
||||
component?: React.ReactType
|
||||
visible: boolean
|
||||
component?: React.ReactType
|
||||
}
|
||||
|
||||
export default class LazyComponent extends React.Component<
|
||||
LazyComponentProps,
|
||||
LazyComponentState
|
||||
> {
|
||||
static defaultProps = {
|
||||
placeholder: '加载中...',
|
||||
unMountOnHidden: false,
|
||||
partialVisibility: true
|
||||
}
|
||||
|
||||
constructor(props: LazyComponentProps) {
|
||||
super(props)
|
||||
|
||||
this.handleVisibleChange = this.handleVisibleChange.bind(this)
|
||||
|
||||
this.state = {
|
||||
visible: false,
|
||||
component: props.component as React.ReactType
|
||||
}
|
||||
}
|
||||
|
||||
handleVisibleChange(visible: boolean) {
|
||||
this.setState({
|
||||
visible: visible
|
||||
})
|
||||
|
||||
if (!visible || this.state.component || !this.props.getComponent) {
|
||||
return
|
||||
export default class LazyComponent extends React.Component<LazyComponentProps, LazyComponentState> {
|
||||
static defaultProps = {
|
||||
placeholder: '加载中...',
|
||||
unMountOnHidden: false,
|
||||
partialVisibility: true,
|
||||
}
|
||||
|
||||
this.props
|
||||
.getComponent()
|
||||
.then(component =>
|
||||
constructor(props: LazyComponentProps) {
|
||||
super(props)
|
||||
|
||||
this.handleVisibleChange = this.handleVisibleChange.bind(this)
|
||||
|
||||
this.state = {
|
||||
visible: false,
|
||||
component: props.component as React.ReactType,
|
||||
}
|
||||
}
|
||||
|
||||
handleVisibleChange(visible: boolean) {
|
||||
this.setState({
|
||||
component: component
|
||||
visible: visible,
|
||||
})
|
||||
)
|
||||
.catch(reason =>
|
||||
this.setState({
|
||||
component: () => (
|
||||
<div className="alert alert-danger">{String(reason)}</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
placeholder,
|
||||
unMountOnHidden,
|
||||
childProps,
|
||||
visiblilityProps,
|
||||
partialVisibility,
|
||||
...rest
|
||||
} = this.props
|
||||
if (!visible || this.state.component || !this.props.getComponent) {
|
||||
return
|
||||
}
|
||||
|
||||
const { visible, component: Component } = this.state
|
||||
|
||||
// 需要监听从可见到不可见。
|
||||
if (unMountOnHidden) {
|
||||
return (
|
||||
<VisibilitySensor
|
||||
{...visiblilityProps}
|
||||
partialVisibility={partialVisibility}
|
||||
onChange={this.handleVisibleChange}
|
||||
>
|
||||
<div className="visibility-sensor">
|
||||
{Component && visible ? (
|
||||
<Component {...rest} {...childProps} />
|
||||
) : (
|
||||
placeholder
|
||||
)}
|
||||
</div>
|
||||
</VisibilitySensor>
|
||||
)
|
||||
this.props
|
||||
.getComponent()
|
||||
.then(component =>
|
||||
this.setState({
|
||||
component: component,
|
||||
})
|
||||
)
|
||||
.catch(reason =>
|
||||
this.setState({
|
||||
component: () => <div className="alert alert-danger">{String(reason)}</div>,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (!visible) {
|
||||
return (
|
||||
<VisibilitySensor
|
||||
{...visiblilityProps}
|
||||
partialVisibility={partialVisibility}
|
||||
onChange={this.handleVisibleChange}
|
||||
>
|
||||
<div className="visibility-sensor">{placeholder}</div>
|
||||
</VisibilitySensor>
|
||||
)
|
||||
} else if (Component) {
|
||||
// 只监听不可见到可见,一旦可见了,就销毁检查。
|
||||
return <Component {...rest} {...childProps} />
|
||||
}
|
||||
render() {
|
||||
const {placeholder, unMountOnHidden, childProps, visiblilityProps, partialVisibility, ...rest} = this.props
|
||||
|
||||
return <div>{placeholder}</div>
|
||||
}
|
||||
const {visible, component: Component} = this.state
|
||||
|
||||
// 需要监听从可见到不可见。
|
||||
if (unMountOnHidden) {
|
||||
return (
|
||||
<VisibilitySensor
|
||||
{...visiblilityProps}
|
||||
partialVisibility={partialVisibility}
|
||||
onChange={this.handleVisibleChange}
|
||||
>
|
||||
<div className="visibility-sensor">
|
||||
{Component && visible ? <Component {...rest} {...childProps} /> : placeholder}
|
||||
</div>
|
||||
</VisibilitySensor>
|
||||
)
|
||||
}
|
||||
|
||||
if (!visible) {
|
||||
return (
|
||||
<VisibilitySensor
|
||||
{...visiblilityProps}
|
||||
partialVisibility={partialVisibility}
|
||||
onChange={this.handleVisibleChange}
|
||||
>
|
||||
<div className="visibility-sensor">{placeholder}</div>
|
||||
</VisibilitySensor>
|
||||
)
|
||||
} else if (Component) {
|
||||
// 只监听不可见到可见,一旦可见了,就销毁检查。
|
||||
return <Component {...rest} {...childProps} />
|
||||
}
|
||||
|
||||
return <div>{placeholder}</div>
|
||||
}
|
||||
}
|
||||
|
@ -5,141 +5,122 @@
|
||||
*/
|
||||
|
||||
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
|
||||
size?: any
|
||||
overlay?: boolean
|
||||
onHide: () => void
|
||||
closeOnEsc?: boolean
|
||||
container?: any
|
||||
show?: boolean
|
||||
disabled?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onExited?: () => void
|
||||
onEntered?: () => void
|
||||
className?: string
|
||||
size?: any
|
||||
overlay?: boolean
|
||||
onHide: () => void
|
||||
closeOnEsc?: boolean
|
||||
container?: any
|
||||
show?: boolean
|
||||
disabled?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onExited?: () => void
|
||||
onEntered?: () => void
|
||||
}
|
||||
export interface ModalState {}
|
||||
const fadeStyles: {
|
||||
[propName: string]: string
|
||||
[propName: string]: string
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in'
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in',
|
||||
}
|
||||
export class Modal extends React.Component<ModalProps, ModalState> {
|
||||
static defaultProps = {
|
||||
container: document.body,
|
||||
size: '',
|
||||
overlay: true
|
||||
}
|
||||
|
||||
contentDom: any
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.handleEntered()
|
||||
static defaultProps = {
|
||||
container: document.body,
|
||||
size: '',
|
||||
overlay: true,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.props.show) {
|
||||
this.handleExited()
|
||||
contentDom: any
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.show) {
|
||||
this.handleEntered()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentRef = (ref: any) => (this.contentDom = ref)
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered
|
||||
document.body.classList.add(`is-modalOpened`)
|
||||
onEntered && onEntered()
|
||||
}
|
||||
handleExited = () => {
|
||||
const onExited = this.props.onExited
|
||||
onExited && onExited()
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') ||
|
||||
document.body.classList.remove(`is-modalOpened`)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
modalRef = (ref: any) => {
|
||||
const { classPrefix: ns } = this.props
|
||||
if (ref) {
|
||||
addModal(this)
|
||||
;(ref as HTMLElement).classList.add(`${ns}Modal--${current()}th`)
|
||||
} else {
|
||||
removeModal()
|
||||
componentWillUnmount() {
|
||||
if (this.props.show) {
|
||||
this.handleExited()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
container,
|
||||
show,
|
||||
size,
|
||||
overlay,
|
||||
classPrefix: ns
|
||||
} = this.props
|
||||
contentRef = (ref: any) => (this.contentDom = ref)
|
||||
handleEntered = () => {
|
||||
const onEntered = this.props.onEntered
|
||||
document.body.classList.add(`is-modalOpened`)
|
||||
onEntered && onEntered()
|
||||
}
|
||||
handleExited = () => {
|
||||
const onExited = this.props.onExited
|
||||
onExited && onExited()
|
||||
setTimeout(() => {
|
||||
document.querySelector('.amis-dialog-widget') || document.body.classList.remove(`is-modalOpened`)
|
||||
}, 200)
|
||||
}
|
||||
|
||||
return (
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={show}
|
||||
timeout={350}
|
||||
onExited={this.handleExited}
|
||||
onEntered={this.handleEntered}
|
||||
>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.contentDom.offsetWidth
|
||||
}
|
||||
modalRef = (ref: any) => {
|
||||
const {classPrefix: ns} = this.props
|
||||
if (ref) {
|
||||
addModal(this)
|
||||
;(ref as HTMLElement).classList.add(`${ns}Modal--${current()}th`)
|
||||
} else {
|
||||
removeModal()
|
||||
}
|
||||
}
|
||||
|
||||
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.contentRef}
|
||||
className={cx(`${ns}Modal-content`, fadeStyles[status])}
|
||||
render() {
|
||||
const {className, children, container, show, size, overlay, classPrefix: ns} = this.props
|
||||
|
||||
return (
|
||||
<Portal container={container}>
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={show}
|
||||
timeout={350}
|
||||
onExited={this.handleExited}
|
||||
onEntered={this.handleEntered}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.contentDom.offsetWidth
|
||||
}
|
||||
|
||||
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.contentRef} className={cx(`${ns}Modal-content`, fadeStyles[status])}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Modal)
|
||||
|
@ -7,43 +7,43 @@
|
||||
import * as keycode from 'keycode'
|
||||
|
||||
interface ModalComponent
|
||||
extends React.Component<{
|
||||
onHide: () => void
|
||||
disabled?: boolean
|
||||
closeOnEsc?: boolean
|
||||
}> {}
|
||||
extends React.Component<{
|
||||
onHide: () => void
|
||||
disabled?: boolean
|
||||
closeOnEsc?: boolean
|
||||
}> {}
|
||||
|
||||
let modals: Array<ModalComponent> = []
|
||||
|
||||
export function current() {
|
||||
return modals.length
|
||||
return modals.length
|
||||
}
|
||||
|
||||
export function currentModal(): ModalComponent | void {
|
||||
return modals[modals.length - 1]
|
||||
return modals[modals.length - 1]
|
||||
}
|
||||
|
||||
export function addModal(modal: ModalComponent) {
|
||||
modals.push(modal)
|
||||
modals.push(modal)
|
||||
}
|
||||
|
||||
export function removeModal() {
|
||||
modals.pop()
|
||||
modals.pop()
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleWindowKeyDown)
|
||||
|
||||
function handleWindowKeyDown(e: Event) {
|
||||
const code = keycode(e)
|
||||
if (code !== 'esc') {
|
||||
return
|
||||
}
|
||||
let modal = currentModal()
|
||||
if (!modal) {
|
||||
return
|
||||
}
|
||||
const { disabled, closeOnEsc } = modal.props
|
||||
if (closeOnEsc && !disabled) {
|
||||
modal.props.onHide()
|
||||
}
|
||||
const code = keycode(e)
|
||||
if (code !== 'esc') {
|
||||
return
|
||||
}
|
||||
let modal = currentModal()
|
||||
if (!modal) {
|
||||
return
|
||||
}
|
||||
const {disabled, closeOnEsc} = modal.props
|
||||
if (closeOnEsc && !disabled) {
|
||||
modal.props.onHide()
|
||||
}
|
||||
}
|
||||
|
@ -4,53 +4,45 @@
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import { Position, Overlay as BaseOverlay } from 'react-overlays'
|
||||
import { findDOMNode } from 'react-dom'
|
||||
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) {
|
||||
this._lastTarget = target
|
||||
this._lastTarget = target
|
||||
|
||||
if (!target) {
|
||||
return this.setState({
|
||||
positionLeft: 0,
|
||||
positionTop: 0,
|
||||
arrowOffsetLeft: null,
|
||||
arrowOffsetTop: null
|
||||
})
|
||||
}
|
||||
if (!target) {
|
||||
return this.setState({
|
||||
positionLeft: 0,
|
||||
positionTop: 0,
|
||||
arrowOffsetLeft: null,
|
||||
arrowOffsetTop: null,
|
||||
})
|
||||
}
|
||||
|
||||
const overlay = findDOMNode(this)
|
||||
const container = getContainer(this.props.container, ownerDocument(this).body)
|
||||
const overlay = findDOMNode(this)
|
||||
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
|
||||
rootClose?: boolean
|
||||
onHide?(props: any, ...args: any[]): any
|
||||
container?: React.ReactNode | Function
|
||||
target?: React.ReactNode | Function
|
||||
placement?: string
|
||||
show?: boolean
|
||||
rootClose?: boolean
|
||||
onHide?(props: any, ...args: any[]): any
|
||||
container?: React.ReactNode | Function
|
||||
target?: React.ReactNode | Function
|
||||
}
|
||||
export default class Overlay extends React.Component<OverlayProps> {
|
||||
constructor(props: OverlayProps) {
|
||||
super(props as any)
|
||||
}
|
||||
constructor(props: OverlayProps) {
|
||||
super(props as any)
|
||||
}
|
||||
|
||||
render() {
|
||||
return <BaseOverlay {...this.props as any} />
|
||||
}
|
||||
render() {
|
||||
return <BaseOverlay {...this.props as any} />
|
||||
}
|
||||
}
|
||||
|
@ -5,125 +5,116 @@
|
||||
*/
|
||||
|
||||
import * as React from 'react'
|
||||
import { findDOMNode } from 'react-dom'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
import {findDOMNode} from 'react-dom'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
|
||||
export interface Offset {
|
||||
x: number
|
||||
y: number
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export interface PopOverPorps {
|
||||
className?: string
|
||||
placement?: string
|
||||
positionTop?: number
|
||||
positionLeft?: number
|
||||
arrowOffsetLeft?: number
|
||||
arrowOffsetTop?: number
|
||||
offset?: ((clip: object, offset: object) => Offset) | Offset
|
||||
style?: object
|
||||
overlay?: boolean
|
||||
onHide?: () => void
|
||||
onClick?: (e: React.MouseEvent<any>) => void
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
[propName: string]: any
|
||||
className?: string
|
||||
placement?: string
|
||||
positionTop?: number
|
||||
positionLeft?: number
|
||||
arrowOffsetLeft?: number
|
||||
arrowOffsetTop?: number
|
||||
offset?: ((clip: object, offset: object) => Offset) | Offset
|
||||
style?: object
|
||||
overlay?: boolean
|
||||
onHide?: () => void
|
||||
onClick?: (e: React.MouseEvent<any>) => void
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
interface PopOverState {
|
||||
xOffset: number
|
||||
yOffset: number
|
||||
xOffset: number
|
||||
yOffset: number
|
||||
}
|
||||
|
||||
export class PopOver extends React.PureComponent<PopOverPorps, PopOverState> {
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
overlay: false,
|
||||
placement: 'bottom'
|
||||
}
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
overlay: false,
|
||||
placement: 'bottom',
|
||||
}
|
||||
|
||||
state = {
|
||||
xOffset: 0,
|
||||
yOffset: 0
|
||||
}
|
||||
state = {
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mayUpdateOffset()
|
||||
}
|
||||
componentDidMount() {
|
||||
this.mayUpdateOffset()
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.mayUpdateOffset()
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.mayUpdateOffset()
|
||||
}
|
||||
|
||||
mayUpdateOffset() {
|
||||
let offset: Offset
|
||||
let getOffset = this.props.offset
|
||||
mayUpdateOffset() {
|
||||
let offset: Offset
|
||||
let getOffset = this.props.offset
|
||||
|
||||
if (getOffset && typeof getOffset === 'function') {
|
||||
const { placement, positionTop: y, positionLeft: x } = this.props
|
||||
if (getOffset && typeof getOffset === 'function') {
|
||||
const {placement, positionTop: y, positionLeft: x} = this.props
|
||||
|
||||
offset = getOffset(
|
||||
(findDOMNode(this) as HTMLElement).getBoundingClientRect(),
|
||||
{
|
||||
x,
|
||||
y,
|
||||
placement
|
||||
offset = getOffset((findDOMNode(this) as HTMLElement).getBoundingClientRect(), {
|
||||
x,
|
||||
y,
|
||||
placement,
|
||||
})
|
||||
} else {
|
||||
offset = getOffset as Offset
|
||||
}
|
||||
)
|
||||
} else {
|
||||
offset = getOffset as Offset
|
||||
|
||||
this.setState({
|
||||
xOffset: offset ? (offset as Offset).x : 0,
|
||||
yOffset: offset ? offset.y : 0,
|
||||
})
|
||||
}
|
||||
|
||||
this.setState({
|
||||
xOffset: offset ? (offset as Offset).x : 0,
|
||||
yOffset: offset ? offset.y : 0
|
||||
})
|
||||
}
|
||||
render() {
|
||||
const {
|
||||
placement,
|
||||
positionTop,
|
||||
positionLeft,
|
||||
arrowOffsetLeft,
|
||||
arrowOffsetTop,
|
||||
style,
|
||||
children,
|
||||
offset,
|
||||
overlay,
|
||||
onHide,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
className,
|
||||
...rest
|
||||
} = this.props
|
||||
|
||||
render() {
|
||||
const {
|
||||
placement,
|
||||
positionTop,
|
||||
positionLeft,
|
||||
arrowOffsetLeft,
|
||||
arrowOffsetTop,
|
||||
style,
|
||||
children,
|
||||
offset,
|
||||
overlay,
|
||||
onHide,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
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,
|
||||
}
|
||||
|
||||
const outerStyle = {
|
||||
display: 'block',
|
||||
...style,
|
||||
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}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<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)
|
||||
|
@ -16,136 +16,121 @@
|
||||
import * as React from 'react'
|
||||
import uncontrollable = require('uncontrollable')
|
||||
import Checkbox from './Checkbox'
|
||||
import { value2array, OptionProps, Option } from './Checkboxes'
|
||||
import {value2array, OptionProps, Option} from './Checkboxes'
|
||||
import chunk = require('lodash/chunk')
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
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
|
||||
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 // 一行显示一个
|
||||
}
|
||||
|
||||
toggleOption(option: Option) {
|
||||
const {
|
||||
value,
|
||||
onChange,
|
||||
joinValues,
|
||||
extractValue,
|
||||
valueField,
|
||||
clearable,
|
||||
delimiter,
|
||||
options
|
||||
} = this.props
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
})
|
||||
const idx = valueArray.indexOf(option)
|
||||
|
||||
if (~idx) {
|
||||
clearable && valueArray.splice(idx, 1)
|
||||
} else {
|
||||
valueArray = [option]
|
||||
static defaultProps = {
|
||||
joinValues: true,
|
||||
clearable: false,
|
||||
columnsCount: 1, // 一行显示一个
|
||||
}
|
||||
|
||||
let newValue = valueArray[0]
|
||||
toggleOption(option: Option) {
|
||||
const {value, onChange, joinValues, extractValue, valueField, clearable, delimiter, options} = this.props
|
||||
|
||||
if (newValue && (joinValues || extractValue)) {
|
||||
newValue = newValue[valueField || 'value']
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options,
|
||||
})
|
||||
const idx = valueArray.indexOf(option)
|
||||
|
||||
if (~idx) {
|
||||
clearable && valueArray.splice(idx, 1)
|
||||
} else {
|
||||
valueArray = [option]
|
||||
}
|
||||
|
||||
let newValue = valueArray[0]
|
||||
|
||||
if (newValue && (joinValues || extractValue)) {
|
||||
newValue = newValue[valueField || 'value']
|
||||
}
|
||||
|
||||
// if (joinValues && newValue) {
|
||||
// newValue = newValue[valueField || 'value'];
|
||||
// }
|
||||
|
||||
onChange && onChange(newValue)
|
||||
}
|
||||
|
||||
// if (joinValues && newValue) {
|
||||
// newValue = newValue[valueField || 'value'];
|
||||
// }
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
options,
|
||||
className,
|
||||
classnames: cx,
|
||||
placeholder,
|
||||
columnsCount,
|
||||
disabled,
|
||||
inline,
|
||||
delimiter,
|
||||
valueField,
|
||||
classPrefix,
|
||||
} = this.props
|
||||
|
||||
onChange && onChange(newValue)
|
||||
}
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options,
|
||||
})
|
||||
let body: Array<React.ReactNode> = []
|
||||
|
||||
render() {
|
||||
const {
|
||||
value,
|
||||
options,
|
||||
className,
|
||||
classnames: cx,
|
||||
placeholder,
|
||||
columnsCount,
|
||||
disabled,
|
||||
inline,
|
||||
delimiter,
|
||||
valueField,
|
||||
classPrefix
|
||||
} = this.props
|
||||
if (options) {
|
||||
body = options.map((option, key) => (
|
||||
<Checkbox
|
||||
type="radio"
|
||||
classPrefix={classPrefix}
|
||||
key={key}
|
||||
onChange={() => this.toggleOption(option)}
|
||||
checked={!!~valueArray.indexOf(option)}
|
||||
className={option.className}
|
||||
disabled={disabled || option.disabled}
|
||||
inline={inline}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
))
|
||||
}
|
||||
|
||||
let valueArray = value2array(value, {
|
||||
multiple: false,
|
||||
delimiter,
|
||||
valueField,
|
||||
options
|
||||
})
|
||||
let body: Array<React.ReactNode> = []
|
||||
if (!inline && columnsCount > 1) {
|
||||
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>
|
||||
))
|
||||
}
|
||||
|
||||
if (options) {
|
||||
body = options.map((option, key) => (
|
||||
<Checkbox
|
||||
type="radio"
|
||||
classPrefix={classPrefix}
|
||||
key={key}
|
||||
onChange={() => this.toggleOption(option)}
|
||||
checked={!!~valueArray.indexOf(option)}
|
||||
className={option.className}
|
||||
disabled={disabled || option.disabled}
|
||||
inline={inline}
|
||||
>
|
||||
{option.label}
|
||||
</Checkbox>
|
||||
))
|
||||
return <div className={className}>{body && body.length ? body : placeholder}</div>
|
||||
}
|
||||
|
||||
if (!inline && columnsCount > 1) {
|
||||
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>
|
||||
))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{body && body.length ? body : placeholder}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Radios, {
|
||||
value: 'onChange'
|
||||
})
|
||||
uncontrollable(Radios, {
|
||||
value: 'onChange',
|
||||
})
|
||||
)
|
||||
|
@ -8,56 +8,56 @@ 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
|
||||
className?: string
|
||||
min: number
|
||||
max: number
|
||||
value?: number
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
id?: string
|
||||
className?: string
|
||||
min: number
|
||||
max: number
|
||||
value?: number
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class Range extends React.Component<RangeProps, any> {
|
||||
static defaultProps: Partial<RangeProps> = {
|
||||
min: 1,
|
||||
max: 100
|
||||
}
|
||||
|
||||
render() {
|
||||
const { min, max, value, className, classPrefix: ns } = this.props
|
||||
|
||||
const classNames = {
|
||||
activeTrack: `${ns}InputRange-track is-active`,
|
||||
disabledInputRange: `${ns}InputRange is-disabled`,
|
||||
inputRange: `${ns}InputRange`,
|
||||
labelContainer: `${ns}InputRange-labelContainer`,
|
||||
maxLabel: `${ns}InputRange-label ${ns}InputRange-label--max`,
|
||||
minLabel: `${ns}InputRange-label ${ns}InputRange-label--min`,
|
||||
slider: `${ns}InputRange-slider`,
|
||||
sliderContainer: `${ns}InputRange-sliderContainer`,
|
||||
track: `${ns}InputRange-track ${ns}InputRange-track--background`,
|
||||
valueLabel: `${ns}InputRange-label ${ns}InputRange-label--value`
|
||||
static defaultProps: Partial<RangeProps> = {
|
||||
min: 1,
|
||||
max: 100,
|
||||
}
|
||||
|
||||
return (
|
||||
<InputRange
|
||||
{...this.props}
|
||||
className={className}
|
||||
classNames={classNames}
|
||||
minValue={min}
|
||||
maxValue={max}
|
||||
value={typeof value === 'number' ? value : min}
|
||||
/>
|
||||
)
|
||||
}
|
||||
render() {
|
||||
const {min, max, value, className, classPrefix: ns} = this.props
|
||||
|
||||
const classNames = {
|
||||
activeTrack: `${ns}InputRange-track is-active`,
|
||||
disabledInputRange: `${ns}InputRange is-disabled`,
|
||||
inputRange: `${ns}InputRange`,
|
||||
labelContainer: `${ns}InputRange-labelContainer`,
|
||||
maxLabel: `${ns}InputRange-label ${ns}InputRange-label--max`,
|
||||
minLabel: `${ns}InputRange-label ${ns}InputRange-label--min`,
|
||||
slider: `${ns}InputRange-slider`,
|
||||
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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(Range, {
|
||||
value: 'onChange'
|
||||
})
|
||||
uncontrollable(Range, {
|
||||
value: 'onChange',
|
||||
})
|
||||
)
|
||||
|
@ -6,204 +6,202 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as cx from 'classnames'
|
||||
import { ClassNamesFn, themeable } from '../theme'
|
||||
import {ClassNamesFn, themeable} from '../theme'
|
||||
|
||||
interface RatingProps {
|
||||
id?: string
|
||||
key?: string | number
|
||||
style?: React.CSSProperties
|
||||
count: number
|
||||
half: boolean
|
||||
char: string
|
||||
size: number
|
||||
className?: string
|
||||
onChange?: (value: any) => void
|
||||
value: number
|
||||
containerClass: string
|
||||
readOnly: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
id?: string
|
||||
key?: string | number
|
||||
style?: React.CSSProperties
|
||||
count: number
|
||||
half: boolean
|
||||
char: string
|
||||
size: number
|
||||
className?: string
|
||||
onChange?: (value: any) => void
|
||||
value: number
|
||||
containerClass: string
|
||||
readOnly: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class Rating extends React.Component<RatingProps, any> {
|
||||
static defaultProps = {
|
||||
containerClass: 'rating',
|
||||
readOnly: false,
|
||||
half: true,
|
||||
value: 0,
|
||||
count: 5,
|
||||
char: '★',
|
||||
size: 24
|
||||
}
|
||||
|
||||
constructor(props: RatingProps) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
value: props.value || 0,
|
||||
stars: [],
|
||||
halfStar: {
|
||||
at: Math.floor(props.value),
|
||||
hidden: props.half && props.value % 1 < 0.5
|
||||
}
|
||||
static defaultProps = {
|
||||
containerClass: 'rating',
|
||||
readOnly: false,
|
||||
half: true,
|
||||
value: 0,
|
||||
count: 5,
|
||||
char: '★',
|
||||
size: 24,
|
||||
}
|
||||
|
||||
this.getRate = this.getRate.bind(this)
|
||||
this.getStars = this.getStars.bind(this)
|
||||
this.moreThanHalf = this.moreThanHalf.bind(this)
|
||||
this.mouseOver = this.mouseOver.bind(this)
|
||||
this.mouseLeave = this.mouseLeave.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
constructor(props: RatingProps) {
|
||||
super(props)
|
||||
|
||||
componentDidMount() {
|
||||
const { value } = this.state
|
||||
this.setState({
|
||||
stars: this.getStars(value)
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getRate() {
|
||||
let stars
|
||||
const { value } = this.state
|
||||
const { half } = this.props
|
||||
if (half) {
|
||||
stars = Math.floor(value)
|
||||
} else {
|
||||
stars = Math.round(value)
|
||||
}
|
||||
return stars
|
||||
}
|
||||
|
||||
getStars(activeCount?: number) {
|
||||
if (typeof activeCount === 'undefined') {
|
||||
activeCount = this.getRate()
|
||||
}
|
||||
let stars = []
|
||||
const { count } = this.props
|
||||
for (let i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
active: i <= activeCount - 1
|
||||
})
|
||||
}
|
||||
return stars
|
||||
}
|
||||
|
||||
mouseOver(event: React.ChangeEvent<any>) {
|
||||
let { readOnly, size, half } = this.props
|
||||
if (readOnly) return
|
||||
let index = Number(event.target.getAttribute('data-index'))
|
||||
if (half) {
|
||||
const isAtHalf = this.moreThanHalf(event, size)
|
||||
if (isAtHalf) index = index + 1
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf
|
||||
this.state = {
|
||||
value: props.value || 0,
|
||||
stars: [],
|
||||
halfStar: {
|
||||
at: Math.floor(props.value),
|
||||
hidden: props.half && props.value % 1 < 0.5,
|
||||
},
|
||||
}
|
||||
})
|
||||
} else {
|
||||
index = index + 1
|
||||
|
||||
this.getRate = this.getRate.bind(this)
|
||||
this.getStars = this.getStars.bind(this)
|
||||
this.moreThanHalf = this.moreThanHalf.bind(this)
|
||||
this.mouseOver = this.mouseOver.bind(this)
|
||||
this.mouseLeave = this.mouseLeave.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars(index)
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
componentDidMount() {
|
||||
const {value} = this.state
|
||||
this.setState({
|
||||
stars: this.getStars(value),
|
||||
})
|
||||
}
|
||||
|
||||
mouseLeave() {
|
||||
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
|
||||
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,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
getRate() {
|
||||
let stars
|
||||
const {value} = this.state
|
||||
const {half} = this.props
|
||||
if (half) {
|
||||
stars = Math.floor(value)
|
||||
} else {
|
||||
stars = Math.round(value)
|
||||
}
|
||||
})
|
||||
return stars
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars()
|
||||
})
|
||||
}
|
||||
|
||||
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 + 0.5
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf
|
||||
getStars(activeCount?: number) {
|
||||
if (typeof activeCount === 'undefined') {
|
||||
activeCount = this.getRate()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
value = index = index + 1
|
||||
let stars = []
|
||||
const {count} = this.props
|
||||
for (let i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
active: i <= activeCount - 1,
|
||||
})
|
||||
}
|
||||
return stars
|
||||
}
|
||||
this.setState({
|
||||
value: value,
|
||||
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) => {
|
||||
let className = cx('Rating', {
|
||||
'Rating-half': half && !halfStar.hidden && halfStar.at === i,
|
||||
'is-active': star.active,
|
||||
'is-disabled': readOnly
|
||||
})
|
||||
mouseOver(event: React.ChangeEvent<any>) {
|
||||
let {readOnly, size, half} = this.props
|
||||
if (readOnly) return
|
||||
let index = Number(event.target.getAttribute('data-index'))
|
||||
if (half) {
|
||||
const isAtHalf = this.moreThanHalf(event, size)
|
||||
if (isAtHalf) index = index + 1
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
index = index + 1
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars(index),
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className={className}
|
||||
key={i}
|
||||
data-index={i}
|
||||
data-forhalf={char}
|
||||
onMouseOver={this.mouseOver}
|
||||
onMouseMove={this.mouseOver}
|
||||
onMouseLeave={this.mouseLeave}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{char}
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
render() {
|
||||
let { className } = this.props
|
||||
mouseLeave() {
|
||||
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
|
||||
},
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
stars: this.getStars(),
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(className ? className : '')}>{this.renderStars()}</div>
|
||||
)
|
||||
}
|
||||
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 + 0.5
|
||||
this.setState({
|
||||
halfStar: {
|
||||
at: index,
|
||||
hidden: isAtHalf,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
value = index = index + 1
|
||||
}
|
||||
this.setState({
|
||||
value: value,
|
||||
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) => {
|
||||
let className = cx('Rating', {
|
||||
'Rating-half': half && !halfStar.hidden && halfStar.at === i,
|
||||
'is-active': star.active,
|
||||
'is-disabled': readOnly,
|
||||
})
|
||||
|
||||
return (
|
||||
<span
|
||||
className={className}
|
||||
key={i}
|
||||
data-index={i}
|
||||
data-forhalf={char}
|
||||
onMouseOver={this.mouseOver}
|
||||
onMouseMove={this.mouseOver}
|
||||
onMouseLeave={this.mouseLeave}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{char}
|
||||
</span>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let {className} = this.props
|
||||
|
||||
return <div className={cx(className ? className : '')}>{this.renderStars()}</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Rating)
|
||||
|
@ -10,26 +10,26 @@ import * as $ from 'jquery'
|
||||
// Require Editor JS files.
|
||||
// import 'froala-editor/js/froala_editor.pkgd.min.js';
|
||||
;[
|
||||
require('froala-editor/js/froala_editor.min.js'),
|
||||
require('froala-editor/js/plugins/align.min'),
|
||||
require('froala-editor/js/plugins/colors.min'),
|
||||
require('froala-editor/js/plugins/font_family.min'),
|
||||
require('froala-editor/js/plugins/font_size.min'),
|
||||
require('froala-editor/js/plugins/image.min'),
|
||||
require('froala-editor/js/plugins/image_manager.min'),
|
||||
require('froala-editor/js/plugins/inline_style.min'),
|
||||
require('froala-editor/js/plugins/line_breaker.min'),
|
||||
require('froala-editor/js/plugins/link.min'),
|
||||
require('froala-editor/js/plugins/lists.min'),
|
||||
require('froala-editor/js/plugins/paragraph_format.min'),
|
||||
require('froala-editor/js/plugins/paragraph_style.min'),
|
||||
require('froala-editor/js/plugins/quote.min'),
|
||||
require('froala-editor/js/plugins/save.min'),
|
||||
require('froala-editor/js/plugins/table.min'),
|
||||
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')
|
||||
require('froala-editor/js/froala_editor.min.js'),
|
||||
require('froala-editor/js/plugins/align.min'),
|
||||
require('froala-editor/js/plugins/colors.min'),
|
||||
require('froala-editor/js/plugins/font_family.min'),
|
||||
require('froala-editor/js/plugins/font_size.min'),
|
||||
require('froala-editor/js/plugins/image.min'),
|
||||
require('froala-editor/js/plugins/image_manager.min'),
|
||||
require('froala-editor/js/plugins/inline_style.min'),
|
||||
require('froala-editor/js/plugins/line_breaker.min'),
|
||||
require('froala-editor/js/plugins/link.min'),
|
||||
require('froala-editor/js/plugins/lists.min'),
|
||||
require('froala-editor/js/plugins/paragraph_format.min'),
|
||||
require('froala-editor/js/plugins/paragraph_style.min'),
|
||||
require('froala-editor/js/plugins/quote.min'),
|
||||
require('froala-editor/js/plugins/save.min'),
|
||||
require('froala-editor/js/plugins/table.min'),
|
||||
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 Editor CSS files.
|
||||
@ -37,403 +37,386 @@ 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 = {
|
||||
immediateReactModelUpdate: false,
|
||||
reactIgnoreAttrs: null
|
||||
}
|
||||
editorInitialized: boolean = false
|
||||
oldModel: any = null
|
||||
listeningEvents: Array<any> = []
|
||||
$element: any = null
|
||||
$editor: any = null
|
||||
config: any = {
|
||||
immediateReactModelUpdate: false,
|
||||
reactIgnoreAttrs: null,
|
||||
}
|
||||
editorInitialized: boolean = false
|
||||
oldModel: any = null
|
||||
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.textareaRef = this.textareaRef.bind(this)
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (JSON.stringify(this.oldModel) == JSON.stringify(this.props.model)) {
|
||||
return
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.textareaRef = this.textareaRef.bind(this)
|
||||
}
|
||||
|
||||
this.setContent()
|
||||
}
|
||||
componentDidUpdate() {
|
||||
if (JSON.stringify(this.oldModel) == JSON.stringify(this.props.model)) {
|
||||
return
|
||||
}
|
||||
|
||||
textareaRef(ref: any) {
|
||||
ref ? this.createEditor(ref) : this.destroyEditor()
|
||||
}
|
||||
|
||||
createEditor(ref: any) {
|
||||
if (this.editorInitialized) {
|
||||
return
|
||||
this.setContent()
|
||||
}
|
||||
|
||||
this.config = this.props.config || this.config
|
||||
this.$element = $(ref)
|
||||
this.setContent(true)
|
||||
this.registerEvents()
|
||||
this.$editor = this.$element
|
||||
.froalaEditor(this.config)
|
||||
.data('froala.editor').$el
|
||||
this.initListeners()
|
||||
this.editorInitialized = true
|
||||
}
|
||||
|
||||
setContent(firstTime: boolean = false) {
|
||||
if (!this.editorInitialized && !firstTime) {
|
||||
return
|
||||
textareaRef(ref: any) {
|
||||
ref ? this.createEditor(ref) : this.destroyEditor()
|
||||
}
|
||||
|
||||
if (this.props.model || this.props.model == '') {
|
||||
this.oldModel = this.props.model
|
||||
createEditor(ref: any) {
|
||||
if (this.editorInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
this.setNormalTagContent(firstTime)
|
||||
}
|
||||
}
|
||||
|
||||
setNormalTagContent(firstTime: boolean) {
|
||||
let self = this
|
||||
|
||||
function htmlSet() {
|
||||
self.$element.froalaEditor('html.set', self.props.model || '', true)
|
||||
//This will reset the undo stack everytime the model changes externally. Can we fix this?
|
||||
self.$element.froalaEditor('undo.reset')
|
||||
self.$element.froalaEditor('undo.saveStep')
|
||||
this.config = this.props.config || this.config
|
||||
this.$element = $(ref)
|
||||
this.setContent(true)
|
||||
this.registerEvents()
|
||||
this.$editor = this.$element.froalaEditor(this.config).data('froala.editor').$el
|
||||
this.initListeners()
|
||||
this.editorInitialized = true
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
this.registerEvent(this.$element, 'froalaEditor.initialized', htmlSet)
|
||||
} else {
|
||||
htmlSet()
|
||||
}
|
||||
}
|
||||
setContent(firstTime: boolean = false) {
|
||||
if (!this.editorInitialized && !firstTime) {
|
||||
return
|
||||
}
|
||||
|
||||
getEditor() {
|
||||
if (this.$element) {
|
||||
return this.$element.froalaEditor.bind(this.$element)
|
||||
if (this.props.model || this.props.model == '') {
|
||||
this.oldModel = this.props.model
|
||||
|
||||
this.setNormalTagContent(firstTime)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
updateModel() {
|
||||
if (!this.props.onModelChange) {
|
||||
return
|
||||
setNormalTagContent(firstTime: boolean) {
|
||||
let self = this
|
||||
|
||||
function htmlSet() {
|
||||
self.$element.froalaEditor('html.set', self.props.model || '', true)
|
||||
//This will reset the undo stack everytime the model changes externally. Can we fix this?
|
||||
self.$element.froalaEditor('undo.reset')
|
||||
self.$element.froalaEditor('undo.saveStep')
|
||||
}
|
||||
|
||||
if (firstTime) {
|
||||
this.registerEvent(this.$element, 'froalaEditor.initialized', htmlSet)
|
||||
} else {
|
||||
htmlSet()
|
||||
}
|
||||
}
|
||||
|
||||
let modelContent = ''
|
||||
getEditor() {
|
||||
if (this.$element) {
|
||||
return this.$element.froalaEditor.bind(this.$element)
|
||||
}
|
||||
|
||||
let returnedHtml = this.$element.froalaEditor('html.get')
|
||||
if (typeof returnedHtml === 'string') {
|
||||
modelContent = returnedHtml
|
||||
return null
|
||||
}
|
||||
updateModel() {
|
||||
if (!this.props.onModelChange) {
|
||||
return
|
||||
}
|
||||
|
||||
let modelContent = ''
|
||||
|
||||
let returnedHtml = this.$element.froalaEditor('html.get')
|
||||
if (typeof returnedHtml === 'string') {
|
||||
modelContent = returnedHtml
|
||||
}
|
||||
|
||||
this.oldModel = modelContent
|
||||
this.props.onModelChange(modelContent)
|
||||
}
|
||||
|
||||
this.oldModel = modelContent
|
||||
this.props.onModelChange(modelContent)
|
||||
}
|
||||
initListeners() {
|
||||
let self = this
|
||||
|
||||
initListeners() {
|
||||
let self = this
|
||||
|
||||
// bind contentChange and keyup event to froalaModel
|
||||
this.registerEvent(
|
||||
this.$element,
|
||||
'froalaEditor.contentChanged',
|
||||
function() {
|
||||
self.updateModel()
|
||||
}
|
||||
)
|
||||
if (this.config.immediateReactModelUpdate) {
|
||||
this.registerEvent(this.$editor, 'keyup', function() {
|
||||
self.updateModel()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// register event on jquery editor element
|
||||
registerEvent(element: any, eventName: any, callback: any) {
|
||||
if (!element || !eventName || !callback) {
|
||||
return
|
||||
// bind contentChange and keyup event to froalaModel
|
||||
this.registerEvent(this.$element, 'froalaEditor.contentChanged', function() {
|
||||
self.updateModel()
|
||||
})
|
||||
if (this.config.immediateReactModelUpdate) {
|
||||
this.registerEvent(this.$editor, 'keyup', function() {
|
||||
self.updateModel()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.listeningEvents.push(eventName)
|
||||
element.on(eventName, callback)
|
||||
}
|
||||
// register event on jquery editor element
|
||||
registerEvent(element: any, eventName: any, callback: any) {
|
||||
if (!element || !eventName || !callback) {
|
||||
return
|
||||
}
|
||||
|
||||
registerEvents() {
|
||||
let events = this.config.events
|
||||
if (!events) {
|
||||
return
|
||||
this.listeningEvents.push(eventName)
|
||||
element.on(eventName, callback)
|
||||
}
|
||||
|
||||
for (let event in events) {
|
||||
if (events.hasOwnProperty(event)) {
|
||||
this.registerEvent(this.$element, event, events[event])
|
||||
}
|
||||
}
|
||||
}
|
||||
registerEvents() {
|
||||
let events = this.config.events
|
||||
if (!events) {
|
||||
return
|
||||
}
|
||||
|
||||
destroyEditor() {
|
||||
if (this.$element) {
|
||||
this.listeningEvents && this.$element.off(this.listeningEvents.join(' '))
|
||||
this.$editor.off('keyup')
|
||||
this.$element.froalaEditor('destroy')
|
||||
this.listeningEvents.length = 0
|
||||
this.$element = null
|
||||
this.editorInitialized = false
|
||||
for (let event in events) {
|
||||
if (events.hasOwnProperty(event)) {
|
||||
this.registerEvent(this.$element, event, events[event])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <textarea ref={this.textareaRef} />
|
||||
}
|
||||
destroyEditor() {
|
||||
if (this.$element) {
|
||||
this.listeningEvents && this.$element.off(this.listeningEvents.join(' '))
|
||||
this.$editor.off('keyup')
|
||||
this.$element.froalaEditor('destroy')
|
||||
this.listeningEvents.length = 0
|
||||
this.$element = null
|
||||
this.editorInitialized = false
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
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',
|
||||
translation: {
|
||||
// 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'
|
||||
},
|
||||
direction: 'ltr'
|
||||
// Quick Insert
|
||||
'Quick Insert': '\u5feb\u63d2',
|
||||
},
|
||||
direction: 'ltr',
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,52 +6,45 @@
|
||||
*/
|
||||
|
||||
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
|
||||
spinnerClassName: string
|
||||
mode: string
|
||||
size: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
overlay: boolean
|
||||
spinnerClassName: string
|
||||
mode: string
|
||||
size: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
export class Spinner extends React.Component<SpinnerProps, object> {
|
||||
static defaultProps = {
|
||||
overlay: false,
|
||||
spinnerClassName: '',
|
||||
mode: '',
|
||||
size: ''
|
||||
}
|
||||
|
||||
render() {
|
||||
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
|
||||
})}
|
||||
/>
|
||||
)
|
||||
|
||||
if (overlay) {
|
||||
return <div className={cx(`Spinner-overlay`)}>{spinner}</div>
|
||||
static defaultProps = {
|
||||
overlay: false,
|
||||
spinnerClassName: '',
|
||||
mode: '',
|
||||
size: '',
|
||||
}
|
||||
|
||||
return spinner
|
||||
}
|
||||
render() {
|
||||
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,
|
||||
})}
|
||||
/>
|
||||
)
|
||||
|
||||
if (overlay) {
|
||||
return <div className={cx(`Spinner-overlay`)}>{spinner}</div>
|
||||
}
|
||||
|
||||
return spinner
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Spinner)
|
||||
|
@ -6,104 +6,104 @@
|
||||
|
||||
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'
|
||||
md: 'i-switch-md',
|
||||
lg: 'i-switch-lg',
|
||||
middle: 'i-switch-md',
|
||||
large: 'i-switch-lg',
|
||||
}
|
||||
|
||||
const levelMap = {
|
||||
info: 'bg-info',
|
||||
primary: 'bg-primary',
|
||||
danger: 'bg-danger'
|
||||
info: 'bg-info',
|
||||
primary: 'bg-primary',
|
||||
danger: 'bg-danger',
|
||||
}
|
||||
|
||||
interface SwitchProps {
|
||||
id?: string
|
||||
size?: 'md' | 'lg' | 'middle' | 'large'
|
||||
level?: 'info' | 'primary' | 'danger'
|
||||
className?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onChange?: (checked: boolean) => void
|
||||
value?: any
|
||||
inline?: boolean
|
||||
trueValue?: any
|
||||
falseValue?: any
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
checked?: boolean
|
||||
id?: string
|
||||
size?: 'md' | 'lg' | 'middle' | 'large'
|
||||
level?: 'info' | 'primary' | 'danger'
|
||||
className?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
onChange?: (checked: boolean) => void
|
||||
value?: any
|
||||
inline?: boolean
|
||||
trueValue?: any
|
||||
falseValue?: any
|
||||
disabled?: boolean
|
||||
readOnly?: boolean
|
||||
checked?: boolean
|
||||
}
|
||||
|
||||
export class Switch extends React.PureComponent<SwitchProps, any> {
|
||||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false
|
||||
}
|
||||
|
||||
constructor(props: SwitchProps) {
|
||||
super(props)
|
||||
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this)
|
||||
}
|
||||
|
||||
hanldeCheck(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const { trueValue, falseValue, onChange } = this.props
|
||||
|
||||
if (!onChange) {
|
||||
return
|
||||
static defaultProps = {
|
||||
trueValue: true,
|
||||
falseValue: false,
|
||||
}
|
||||
|
||||
onChange(e.currentTarget.checked ? trueValue : falseValue)
|
||||
}
|
||||
constructor(props: SwitchProps) {
|
||||
super(props)
|
||||
|
||||
render() {
|
||||
let {
|
||||
size,
|
||||
level,
|
||||
className,
|
||||
classPrefix,
|
||||
onChange,
|
||||
value,
|
||||
inline,
|
||||
trueValue,
|
||||
falseValue,
|
||||
disabled,
|
||||
readOnly,
|
||||
checked,
|
||||
classnames: cx,
|
||||
...rest
|
||||
} = this.props
|
||||
this.hanldeCheck = this.hanldeCheck.bind(this)
|
||||
}
|
||||
|
||||
className =
|
||||
(className ? className : '') +
|
||||
(size && sizeMap[size] ? ` ${sizeMap[size]}` : '') +
|
||||
(level && levelMap[level] ? ` ${levelMap[level]}` : '')
|
||||
hanldeCheck(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const {trueValue, falseValue, onChange} = this.props
|
||||
|
||||
return (
|
||||
<label className={cx(`Switch`, disabled ? 'is-disabled' : '', className)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={
|
||||
typeof checked !== 'undefined'
|
||||
? checked
|
||||
: typeof value === 'undefined'
|
||||
? false
|
||||
: value == trueValue
|
||||
}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
readOnly={readOnly}
|
||||
{...rest}
|
||||
/>
|
||||
<i />
|
||||
</label>
|
||||
)
|
||||
}
|
||||
if (!onChange) {
|
||||
return
|
||||
}
|
||||
|
||||
onChange(e.currentTarget.checked ? trueValue : falseValue)
|
||||
}
|
||||
|
||||
render() {
|
||||
let {
|
||||
size,
|
||||
level,
|
||||
className,
|
||||
classPrefix,
|
||||
onChange,
|
||||
value,
|
||||
inline,
|
||||
trueValue,
|
||||
falseValue,
|
||||
disabled,
|
||||
readOnly,
|
||||
checked,
|
||||
classnames: cx,
|
||||
...rest
|
||||
} = this.props
|
||||
|
||||
className =
|
||||
(className ? className : '') +
|
||||
(size && sizeMap[size] ? ` ${sizeMap[size]}` : '') +
|
||||
(level && levelMap[level] ? ` ${levelMap[level]}` : '')
|
||||
|
||||
return (
|
||||
<label className={cx(`Switch`, disabled ? 'is-disabled' : '', className)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
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)
|
||||
|
@ -9,48 +9,46 @@
|
||||
*/
|
||||
|
||||
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
|
||||
title: React.ReactNode
|
||||
titleClassName?: string
|
||||
right?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
className?: string
|
||||
title: React.ReactNode
|
||||
titleClassName?: string
|
||||
right?: boolean
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const { className, title, titleClassName, right } = this.props
|
||||
|
||||
let left = title ? <div className={titleClassName}>{title}</div> : null
|
||||
|
||||
let body = left
|
||||
|
||||
if (right) {
|
||||
body = (
|
||||
<div className="hbox hbox-auto-xs h-auto">
|
||||
<div className="col bg-light b-b wrapper">{left}</div>
|
||||
<div className="col v-middle padder-md text-right bg-light b-b wrapper-sm">
|
||||
{right}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
body = <div className="wrapper">{left}</div>
|
||||
static defaultProps = {
|
||||
className: 'bg-light lter b-b',
|
||||
title: '标题',
|
||||
titleClassName: 'm-n font-thin h3',
|
||||
right: false,
|
||||
}
|
||||
|
||||
return <div className={className}>{body}</div>
|
||||
}
|
||||
render(): JSX.Element {
|
||||
const {className, title, titleClassName, right} = this.props
|
||||
|
||||
let left = title ? <div className={titleClassName}>{title}</div> : null
|
||||
|
||||
let body = left
|
||||
|
||||
if (right) {
|
||||
body = (
|
||||
<div className="hbox hbox-auto-xs h-auto">
|
||||
<div className="col bg-light b-b wrapper">{left}</div>
|
||||
<div className="col v-middle padder-md text-right bg-light b-b wrapper-sm">{right}</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
body = <div className="wrapper">{left}</div>
|
||||
}
|
||||
|
||||
return <div className={className}>{body}</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TitleBar)
|
||||
|
@ -4,325 +4,278 @@
|
||||
* @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
|
||||
[propName: string]: string
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: '',
|
||||
[EXITING]: 'out',
|
||||
[EXITED]: 'hidden'
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: '',
|
||||
[EXITING]: 'out',
|
||||
[EXITED]: 'hidden',
|
||||
}
|
||||
|
||||
let toastRef: any = null
|
||||
let config: {
|
||||
closeButton?: boolean
|
||||
timeOut?: number
|
||||
extendedTimeOut?: number
|
||||
closeButton?: boolean
|
||||
timeOut?: number
|
||||
extendedTimeOut?: number
|
||||
} = {}
|
||||
|
||||
const show = (
|
||||
content: string,
|
||||
title: string = '',
|
||||
conf: any = {},
|
||||
method: string
|
||||
) => {
|
||||
if (!toastRef || !toastRef[method]) {
|
||||
return
|
||||
}
|
||||
toastRef[method](content, title || '', { ...config, ...conf })
|
||||
const show = (content: string, title: string = '', conf: any = {}, method: string) => {
|
||||
if (!toastRef || !toastRef[method]) {
|
||||
return
|
||||
}
|
||||
toastRef[method](content, title || '', {...config, ...conf})
|
||||
}
|
||||
|
||||
interface ToastComponentProps {
|
||||
position:
|
||||
| 'top-right'
|
||||
| 'top-center'
|
||||
| 'top-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-left'
|
||||
| 'bottom-right'
|
||||
closeButton: boolean
|
||||
timeOut: number
|
||||
extendedTimeOut: number
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
className?: string
|
||||
position: 'top-right' | 'top-center' | 'top-left' | 'bottom-center' | 'bottom-left' | 'bottom-right'
|
||||
closeButton: boolean
|
||||
timeOut: number
|
||||
extendedTimeOut: number
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
className?: string
|
||||
}
|
||||
|
||||
interface Item {
|
||||
title?: string
|
||||
body: string
|
||||
level: 'info' | 'success' | 'error' | 'warning'
|
||||
id: string
|
||||
title?: string
|
||||
body: string
|
||||
level: 'info' | 'success' | 'error' | 'warning'
|
||||
id: string
|
||||
}
|
||||
|
||||
interface ToastComponentState {
|
||||
items: Array<Item>
|
||||
items: Array<Item>
|
||||
}
|
||||
|
||||
export class ToastComponent extends React.PureComponent<
|
||||
ToastComponentProps,
|
||||
ToastComponentState
|
||||
> {
|
||||
static defaultProps = {
|
||||
position: 'top-right',
|
||||
closeButton: false,
|
||||
timeOut: 5000,
|
||||
extendedTimeOut: 3000
|
||||
}
|
||||
|
||||
// 当前ToastComponent是否真正render了
|
||||
hasRendered = false
|
||||
state: ToastComponentState = {
|
||||
items: []
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const { closeButton, timeOut, extendedTimeOut } = this.props
|
||||
config = {
|
||||
closeButton,
|
||||
timeOut,
|
||||
extendedTimeOut
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.hasRendered = true
|
||||
toastRef = this
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.hasRendered) {
|
||||
toastRef = null
|
||||
}
|
||||
}
|
||||
|
||||
notifiy(level: string, content: string, title?: string, config?: any) {
|
||||
const items = this.state.items.concat()
|
||||
items.push({
|
||||
title: title,
|
||||
body: content,
|
||||
level,
|
||||
...config,
|
||||
id: uuid()
|
||||
})
|
||||
this.setState({
|
||||
items
|
||||
})
|
||||
}
|
||||
|
||||
@autobind
|
||||
success(content: string, title?: string, config?: any) {
|
||||
this.notifiy('success', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
error(content: string, title?: string, config?: any) {
|
||||
this.notifiy('error', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
info(content: string, title?: string, config?: any) {
|
||||
this.notifiy('info', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
warning(content: string, title?: string, config?: any) {
|
||||
this.notifiy('warning', content, title, config)
|
||||
}
|
||||
|
||||
handleDismissed(index: number) {
|
||||
const items = this.state.items.concat()
|
||||
items.splice(index, 1)
|
||||
this.setState({
|
||||
items: items
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (toastRef && !this.hasRendered) {
|
||||
return null
|
||||
export class ToastComponent extends React.PureComponent<ToastComponentProps, ToastComponentState> {
|
||||
static defaultProps = {
|
||||
position: 'top-right',
|
||||
closeButton: false,
|
||||
timeOut: 5000,
|
||||
extendedTimeOut: 3000,
|
||||
}
|
||||
|
||||
const { classPrefix: ns, className, timeOut, position } = this.props
|
||||
const items = this.state.items
|
||||
// 当前ToastComponent是否真正render了
|
||||
hasRendered = false
|
||||
state: ToastComponentState = {
|
||||
items: [],
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
`${ns}Toast-wrap ${ns}Toast-wrap--${position.replace(
|
||||
/\-(\w)/g,
|
||||
(_, l) => l.toUpperCase()
|
||||
)}`,
|
||||
className
|
||||
)}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<ToastMessage
|
||||
key={item.id}
|
||||
classPrefix={ns}
|
||||
title={item.title}
|
||||
body={item.body}
|
||||
level={item.level || 'info'}
|
||||
timeOut={timeOut}
|
||||
onDismiss={this.handleDismissed.bind(this, index)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
componentWillMount() {
|
||||
const {closeButton, timeOut, extendedTimeOut} = this.props
|
||||
config = {
|
||||
closeButton,
|
||||
timeOut,
|
||||
extendedTimeOut,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.hasRendered = true
|
||||
toastRef = this
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.hasRendered) {
|
||||
toastRef = null
|
||||
}
|
||||
}
|
||||
|
||||
notifiy(level: string, content: string, title?: string, config?: any) {
|
||||
const items = this.state.items.concat()
|
||||
items.push({
|
||||
title: title,
|
||||
body: content,
|
||||
level,
|
||||
...config,
|
||||
id: uuid(),
|
||||
})
|
||||
this.setState({
|
||||
items,
|
||||
})
|
||||
}
|
||||
|
||||
@autobind
|
||||
success(content: string, title?: string, config?: any) {
|
||||
this.notifiy('success', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
error(content: string, title?: string, config?: any) {
|
||||
this.notifiy('error', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
info(content: string, title?: string, config?: any) {
|
||||
this.notifiy('info', content, title, config)
|
||||
}
|
||||
|
||||
@autobind
|
||||
warning(content: string, title?: string, config?: any) {
|
||||
this.notifiy('warning', content, title, config)
|
||||
}
|
||||
|
||||
handleDismissed(index: number) {
|
||||
const items = this.state.items.concat()
|
||||
items.splice(index, 1)
|
||||
this.setState({
|
||||
items: items,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (toastRef && !this.hasRendered) {
|
||||
return null
|
||||
}
|
||||
|
||||
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
|
||||
)}
|
||||
>
|
||||
{items.map((item, index) => (
|
||||
<ToastMessage
|
||||
key={item.id}
|
||||
classPrefix={ns}
|
||||
title={item.title}
|
||||
body={item.body}
|
||||
level={item.level || 'info'}
|
||||
timeOut={timeOut}
|
||||
onDismiss={this.handleDismissed.bind(this, index)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(ToastComponent as React.ComponentType<
|
||||
ToastComponentProps
|
||||
>)
|
||||
export default themeable(ToastComponent as React.ComponentType<ToastComponentProps>)
|
||||
|
||||
interface ToastMessageProps {
|
||||
title?: string
|
||||
body: string
|
||||
level: 'info' | 'success' | 'error' | 'warning'
|
||||
timeOut: number
|
||||
position:
|
||||
| 'top-right'
|
||||
| 'top-center'
|
||||
| 'top-left'
|
||||
| 'bottom-center'
|
||||
| 'bottom-left'
|
||||
| 'bottom-right'
|
||||
onDismiss?: () => void
|
||||
classPrefix: string
|
||||
allowHtml: boolean
|
||||
title?: string
|
||||
body: string
|
||||
level: 'info' | 'success' | 'error' | 'warning'
|
||||
timeOut: number
|
||||
position: 'top-right' | 'top-center' | 'top-left' | 'bottom-center' | 'bottom-left' | 'bottom-right'
|
||||
onDismiss?: () => void
|
||||
classPrefix: string
|
||||
allowHtml: boolean
|
||||
}
|
||||
|
||||
interface ToastMessageState {
|
||||
visible: boolean
|
||||
visible: boolean
|
||||
}
|
||||
|
||||
export class ToastMessage extends React.Component<ToastMessageProps> {
|
||||
static defaultProps = {
|
||||
timeOut: 5000,
|
||||
classPrefix: '',
|
||||
position: 'top-right',
|
||||
allowHtml: true,
|
||||
level: 'info'
|
||||
}
|
||||
static defaultProps = {
|
||||
timeOut: 5000,
|
||||
classPrefix: '',
|
||||
position: 'top-right',
|
||||
allowHtml: true,
|
||||
level: 'info',
|
||||
}
|
||||
|
||||
state = {
|
||||
visible: false
|
||||
}
|
||||
state = {
|
||||
visible: false,
|
||||
}
|
||||
|
||||
content: React.RefObject<HTMLDivElement>
|
||||
timer: NodeJS.Timeout
|
||||
constructor(props: ToastMessageProps) {
|
||||
super(props)
|
||||
content: React.RefObject<HTMLDivElement>
|
||||
timer: NodeJS.Timeout
|
||||
constructor(props: ToastMessageProps) {
|
||||
super(props)
|
||||
|
||||
this.content = React.createRef()
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this)
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this)
|
||||
this.handleEntered = this.handleEntered.bind(this)
|
||||
this.close = this.close.bind(this)
|
||||
}
|
||||
this.content = React.createRef()
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this)
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this)
|
||||
this.handleEntered = this.handleEntered.bind(this)
|
||||
this.close = this.close.bind(this)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
visible: true
|
||||
})
|
||||
}
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
visible: true,
|
||||
})
|
||||
}
|
||||
|
||||
handleMouseEnter() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
handleMouseEnter() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
|
||||
handleMouseLeave() {
|
||||
this.handleEntered()
|
||||
}
|
||||
handleMouseLeave() {
|
||||
this.handleEntered()
|
||||
}
|
||||
|
||||
handleEntered() {
|
||||
const timeOut = this.props.timeOut
|
||||
this.timer = setTimeout(this.close, timeOut)
|
||||
}
|
||||
handleEntered() {
|
||||
const timeOut = this.props.timeOut
|
||||
this.timer = setTimeout(this.close, timeOut)
|
||||
}
|
||||
|
||||
close() {
|
||||
clearTimeout(this.timer)
|
||||
this.setState({
|
||||
visible: false
|
||||
})
|
||||
}
|
||||
close() {
|
||||
clearTimeout(this.timer)
|
||||
this.setState({
|
||||
visible: false,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
onDismiss,
|
||||
classPrefix: ns,
|
||||
position,
|
||||
title,
|
||||
body,
|
||||
allowHtml,
|
||||
level
|
||||
} = this.props
|
||||
render() {
|
||||
const {onDismiss, classPrefix: ns, position, title, body, allowHtml, level} = this.props
|
||||
|
||||
return (
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={this.state.visible}
|
||||
timeout={750}
|
||||
onEntered={this.handleEntered}
|
||||
onExited={onDismiss}
|
||||
>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.content.current && this.content.current.offsetWidth
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={this.content}
|
||||
className={cx(
|
||||
`${ns}Toast ${ns}Toast--${level}`,
|
||||
fadeStyles[status]
|
||||
)}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.close}
|
||||
return (
|
||||
<Transition
|
||||
mountOnEnter
|
||||
unmountOnExit
|
||||
in={this.state.visible}
|
||||
timeout={750}
|
||||
onEntered={this.handleEntered}
|
||||
onExited={onDismiss}
|
||||
>
|
||||
{title ? <div className={`${ns}Toast-title`}>{title}</div> : null}
|
||||
<div className={`${ns}Toast-body`}>
|
||||
{allowHtml ? <Html html={body} /> : body}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.content.current && this.content.current.offsetWidth
|
||||
}
|
||||
|
||||
return (
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const toast = {
|
||||
container: toastRef,
|
||||
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')
|
||||
container: toastRef,
|
||||
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'),
|
||||
}
|
||||
|
@ -6,60 +6,56 @@
|
||||
|
||||
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
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
theme?: string
|
||||
className?: string
|
||||
style?: any
|
||||
arrowProps?: any
|
||||
placement?: string
|
||||
[propName: string]: any
|
||||
title?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
theme?: string
|
||||
className?: string
|
||||
style?: any
|
||||
arrowProps?: any
|
||||
placement?: string
|
||||
[propName: string]: any
|
||||
}
|
||||
|
||||
export class Tooltip extends React.Component<TooltipProps> {
|
||||
static defaultProps = {
|
||||
className: ''
|
||||
}
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
title,
|
||||
children,
|
||||
arrowProps,
|
||||
style,
|
||||
placement,
|
||||
arrowOffsetLeft,
|
||||
arrowOffsetTop,
|
||||
positionLeft,
|
||||
positionTop,
|
||||
classnames: cx,
|
||||
...rest
|
||||
} = this.props
|
||||
render() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
className,
|
||||
title,
|
||||
children,
|
||||
arrowProps,
|
||||
style,
|
||||
placement,
|
||||
arrowOffsetLeft,
|
||||
arrowOffsetTop,
|
||||
positionLeft,
|
||||
positionTop,
|
||||
classnames: cx,
|
||||
...rest
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(Tooltip)
|
||||
|
@ -5,222 +5,200 @@
|
||||
*/
|
||||
|
||||
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
|
||||
title?: string
|
||||
content?: string
|
||||
}
|
||||
|
||||
export type Trigger = 'hover' | 'click' | 'focus'
|
||||
|
||||
export interface TooltipWrapperProps {
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
placement: 'top' | 'right' | 'bottom' | 'left'
|
||||
tooltip?: string | TooltipObject
|
||||
container?: React.ReactNode
|
||||
trigger: Trigger | Array<Trigger>
|
||||
rootClose: boolean
|
||||
overlay?: any
|
||||
delay: number
|
||||
theme?: string
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
placement: 'top' | 'right' | 'bottom' | 'left'
|
||||
tooltip?: string | TooltipObject
|
||||
container?: React.ReactNode
|
||||
trigger: Trigger | Array<Trigger>
|
||||
rootClose: boolean
|
||||
overlay?: any
|
||||
delay: number
|
||||
theme?: string
|
||||
}
|
||||
|
||||
interface TooltipWrapperState {
|
||||
show?: boolean
|
||||
show?: boolean
|
||||
}
|
||||
|
||||
export class TooltipWrapper extends React.Component<
|
||||
TooltipWrapperProps,
|
||||
TooltipWrapperState
|
||||
> {
|
||||
static defaultProps: Pick<
|
||||
TooltipWrapperProps,
|
||||
'placement' | 'trigger' | 'rootClose' | 'delay'
|
||||
> = {
|
||||
placement: 'top',
|
||||
trigger: ['hover', 'focus'],
|
||||
rootClose: false,
|
||||
delay: 200
|
||||
}
|
||||
|
||||
target: HTMLElement
|
||||
timer: NodeJS.Timeout
|
||||
constructor(props: TooltipWrapperProps) {
|
||||
super(props)
|
||||
|
||||
this.targetRef = this.targetRef.bind(this)
|
||||
this.getTarget = this.getTarget.bind(this)
|
||||
this.show = this.show.bind(this)
|
||||
this.hide = this.hide.bind(this)
|
||||
this.handleShow = this.handleShow.bind(this)
|
||||
this.handleHide = this.handleHide.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.handleFocus = this.handleFocus.bind(this)
|
||||
this.handleBlur = this.handleBlur.bind(this)
|
||||
this.handleMouseOver = this.handleMouseOver.bind(this)
|
||||
this.handleMouseOut = this.handleMouseOut.bind(this)
|
||||
|
||||
this.state = {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
|
||||
getTarget() {
|
||||
return this.target ? findDOMNode(this.target) : null
|
||||
}
|
||||
|
||||
targetRef(ref: HTMLElement) {
|
||||
this.target = ref
|
||||
}
|
||||
|
||||
show() {
|
||||
this.setState({
|
||||
show: true
|
||||
})
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.setState({
|
||||
show: false
|
||||
})
|
||||
}
|
||||
|
||||
getChildProps() {
|
||||
const child = React.Children.only(this.props.children)
|
||||
return child && (child as any).props
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
// clearTimeout(this.timer);
|
||||
// const {
|
||||
// delay
|
||||
// } = this.props;
|
||||
|
||||
// this.timer = setTimeout(this.show, delay);
|
||||
this.show()
|
||||
}
|
||||
|
||||
handleHide() {
|
||||
clearTimeout(this.timer)
|
||||
const { delay } = this.props
|
||||
|
||||
this.timer = setTimeout(this.hide, delay)
|
||||
}
|
||||
|
||||
handleFocus(e: any) {
|
||||
const { onFocus } = this.getChildProps()
|
||||
this.handleShow()
|
||||
onFocus && onFocus(e)
|
||||
}
|
||||
|
||||
handleBlur(e: any) {
|
||||
const { onBlur } = this.getChildProps()
|
||||
this.handleHide()
|
||||
onBlur && onBlur(e)
|
||||
}
|
||||
|
||||
handleMouseOver(e: any) {
|
||||
this.handleMouseOverOut(this.handleShow, e, 'fromElement')
|
||||
}
|
||||
|
||||
handleMouseOut(e: any) {
|
||||
this.handleMouseOverOut(this.handleHide, e, 'toElement')
|
||||
}
|
||||
|
||||
handleMouseOverOut(
|
||||
handler: Function,
|
||||
e: React.MouseEvent<HTMLElement>,
|
||||
relatedNative: string
|
||||
) {
|
||||
const target = e.currentTarget
|
||||
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()
|
||||
this.state.show ? this.hide() : this.show()
|
||||
onClick && onClick(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
tooltip,
|
||||
children,
|
||||
placement,
|
||||
container,
|
||||
trigger,
|
||||
rootClose
|
||||
} = this.props
|
||||
|
||||
const child = React.Children.only(children)
|
||||
|
||||
if (!tooltip) {
|
||||
return child
|
||||
export class TooltipWrapper extends React.Component<TooltipWrapperProps, TooltipWrapperState> {
|
||||
static defaultProps: Pick<TooltipWrapperProps, 'placement' | 'trigger' | 'rootClose' | 'delay'> = {
|
||||
placement: 'top',
|
||||
trigger: ['hover', 'focus'],
|
||||
rootClose: false,
|
||||
delay: 200,
|
||||
}
|
||||
|
||||
const childProps: any = {
|
||||
ref: this.targetRef,
|
||||
key: 'target'
|
||||
target: HTMLElement
|
||||
timer: NodeJS.Timeout
|
||||
constructor(props: TooltipWrapperProps) {
|
||||
super(props)
|
||||
|
||||
this.targetRef = this.targetRef.bind(this)
|
||||
this.getTarget = this.getTarget.bind(this)
|
||||
this.show = this.show.bind(this)
|
||||
this.hide = this.hide.bind(this)
|
||||
this.handleShow = this.handleShow.bind(this)
|
||||
this.handleHide = this.handleHide.bind(this)
|
||||
this.handleClick = this.handleClick.bind(this)
|
||||
this.handleFocus = this.handleFocus.bind(this)
|
||||
this.handleBlur = this.handleBlur.bind(this)
|
||||
this.handleMouseOver = this.handleMouseOver.bind(this)
|
||||
this.handleMouseOut = this.handleMouseOut.bind(this)
|
||||
|
||||
this.state = {
|
||||
show: false,
|
||||
}
|
||||
}
|
||||
|
||||
const triggers = Array.isArray(trigger) ? trigger.concat() : [trigger]
|
||||
|
||||
if (~triggers.indexOf('click')) {
|
||||
childProps.onClick = this.handleClick
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.timer)
|
||||
}
|
||||
|
||||
if (~triggers.indexOf('focus')) {
|
||||
childProps.onFocus = this.handleShow
|
||||
childProps.onBlur = this.handleHide
|
||||
getTarget() {
|
||||
return this.target ? findDOMNode(this.target) : null
|
||||
}
|
||||
|
||||
if (~triggers.indexOf('hover')) {
|
||||
childProps.onMouseOver = this.handleMouseOver
|
||||
childProps.onMouseOut = this.handleMouseOut
|
||||
targetRef(ref: HTMLElement) {
|
||||
this.target = ref
|
||||
}
|
||||
|
||||
return [
|
||||
child ? React.cloneElement(child as any, childProps) : null,
|
||||
show() {
|
||||
this.setState({
|
||||
show: true,
|
||||
})
|
||||
}
|
||||
|
||||
<Overlay
|
||||
key="overlay"
|
||||
target={this.getTarget}
|
||||
show={this.state.show}
|
||||
onHide={this.handleHide}
|
||||
rootClose={rootClose}
|
||||
placement={placement}
|
||||
container={container}
|
||||
>
|
||||
<Tooltip
|
||||
title={typeof tooltip !== 'string' ? tooltip.title : undefined}
|
||||
>
|
||||
<Html
|
||||
html={typeof tooltip === 'string' ? tooltip : tooltip.content}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Overlay>
|
||||
]
|
||||
}
|
||||
hide() {
|
||||
this.setState({
|
||||
show: false,
|
||||
})
|
||||
}
|
||||
|
||||
getChildProps() {
|
||||
const child = React.Children.only(this.props.children)
|
||||
return child && (child as any).props
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
// clearTimeout(this.timer);
|
||||
// const {
|
||||
// delay
|
||||
// } = this.props;
|
||||
|
||||
// this.timer = setTimeout(this.show, delay);
|
||||
this.show()
|
||||
}
|
||||
|
||||
handleHide() {
|
||||
clearTimeout(this.timer)
|
||||
const {delay} = this.props
|
||||
|
||||
this.timer = setTimeout(this.hide, delay)
|
||||
}
|
||||
|
||||
handleFocus(e: any) {
|
||||
const {onFocus} = this.getChildProps()
|
||||
this.handleShow()
|
||||
onFocus && onFocus(e)
|
||||
}
|
||||
|
||||
handleBlur(e: any) {
|
||||
const {onBlur} = this.getChildProps()
|
||||
this.handleHide()
|
||||
onBlur && onBlur(e)
|
||||
}
|
||||
|
||||
handleMouseOver(e: any) {
|
||||
this.handleMouseOverOut(this.handleShow, e, 'fromElement')
|
||||
}
|
||||
|
||||
handleMouseOut(e: any) {
|
||||
this.handleMouseOverOut(this.handleHide, e, 'toElement')
|
||||
}
|
||||
|
||||
handleMouseOverOut(handler: Function, e: React.MouseEvent<HTMLElement>, relatedNative: string) {
|
||||
const target = e.currentTarget
|
||||
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()
|
||||
this.state.show ? this.hide() : this.show()
|
||||
onClick && onClick(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {tooltip, children, placement, container, trigger, rootClose} = this.props
|
||||
|
||||
const child = React.Children.only(children)
|
||||
|
||||
if (!tooltip) {
|
||||
return child
|
||||
}
|
||||
|
||||
const childProps: any = {
|
||||
ref: this.targetRef,
|
||||
key: 'target',
|
||||
}
|
||||
|
||||
const triggers = Array.isArray(trigger) ? trigger.concat() : [trigger]
|
||||
|
||||
if (~triggers.indexOf('click')) {
|
||||
childProps.onClick = this.handleClick
|
||||
}
|
||||
|
||||
if (~triggers.indexOf('focus')) {
|
||||
childProps.onFocus = this.handleShow
|
||||
childProps.onBlur = this.handleHide
|
||||
}
|
||||
|
||||
if (~triggers.indexOf('hover')) {
|
||||
childProps.onMouseOver = this.handleMouseOver
|
||||
childProps.onMouseOut = this.handleMouseOut
|
||||
}
|
||||
|
||||
return [
|
||||
child ? React.cloneElement(child as any, childProps) : null,
|
||||
|
||||
<Overlay
|
||||
key="overlay"
|
||||
target={this.getTarget}
|
||||
show={this.state.show}
|
||||
onHide={this.handleHide}
|
||||
rootClose={rootClose}
|
||||
placement={placement}
|
||||
container={container}
|
||||
>
|
||||
<Tooltip title={typeof tooltip !== 'string' ? tooltip.title : undefined}>
|
||||
<Html html={typeof tooltip === 'string' ? tooltip : tooltip.content} />
|
||||
</Tooltip>
|
||||
</Overlay>,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(
|
||||
uncontrollable(TooltipWrapper, {
|
||||
show: 'onVisibleChange'
|
||||
})
|
||||
uncontrollable(TooltipWrapper, {
|
||||
show: 'onVisibleChange',
|
||||
})
|
||||
)
|
||||
|
@ -5,488 +5,449 @@
|
||||
*/
|
||||
|
||||
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
|
||||
classnames: ClassNamesFn
|
||||
classPrefix: string
|
||||
classnames: ClassNamesFn
|
||||
|
||||
highlightTxt: string
|
||||
highlightTxt: string
|
||||
|
||||
showIcon?: boolean
|
||||
// 是否默认都展开
|
||||
initiallyOpen?: boolean
|
||||
// 默认展开的级数,从1开始,只有initiallyOpen不是true时生效
|
||||
unfoldedLevel?: number
|
||||
// 单选时,是否展示radio
|
||||
showRadio?: boolean
|
||||
multiple?: boolean
|
||||
// 是否都不可用
|
||||
disabled?: boolean
|
||||
// 多选时,选中父节点时,是否将其所有子节点也融合到取值中,默认是不融合
|
||||
withChildren?: boolean
|
||||
// 多选时,选中父节点时,是否只将起子节点加入到值中。
|
||||
onlyChildren?: boolean
|
||||
// 名称、取值等字段名映射
|
||||
nameField?: string
|
||||
valueField?: string
|
||||
iconField?: string
|
||||
unfoldedField?: string
|
||||
foldedField?: string
|
||||
disabledField?: string
|
||||
className?: string
|
||||
itemClassName?: string
|
||||
joinValues?: boolean
|
||||
extractValue?: boolean
|
||||
delimiter?: string
|
||||
data: Options
|
||||
value: any
|
||||
onChange: Function
|
||||
placeholder?: string
|
||||
hideRoot?: boolean
|
||||
rootLabel?: string
|
||||
rootValue?: any
|
||||
cascade?: boolean
|
||||
selfDisabledAffectChildren?: boolean
|
||||
showIcon?: boolean
|
||||
// 是否默认都展开
|
||||
initiallyOpen?: boolean
|
||||
// 默认展开的级数,从1开始,只有initiallyOpen不是true时生效
|
||||
unfoldedLevel?: number
|
||||
// 单选时,是否展示radio
|
||||
showRadio?: boolean
|
||||
multiple?: boolean
|
||||
// 是否都不可用
|
||||
disabled?: boolean
|
||||
// 多选时,选中父节点时,是否将其所有子节点也融合到取值中,默认是不融合
|
||||
withChildren?: boolean
|
||||
// 多选时,选中父节点时,是否只将起子节点加入到值中。
|
||||
onlyChildren?: boolean
|
||||
// 名称、取值等字段名映射
|
||||
nameField?: string
|
||||
valueField?: string
|
||||
iconField?: string
|
||||
unfoldedField?: string
|
||||
foldedField?: string
|
||||
disabledField?: string
|
||||
className?: string
|
||||
itemClassName?: string
|
||||
joinValues?: boolean
|
||||
extractValue?: boolean
|
||||
delimiter?: string
|
||||
data: Options
|
||||
value: any
|
||||
onChange: Function
|
||||
placeholder?: string
|
||||
hideRoot?: boolean
|
||||
rootLabel?: string
|
||||
rootValue?: any
|
||||
cascade?: boolean
|
||||
selfDisabledAffectChildren?: boolean
|
||||
}
|
||||
|
||||
interface TreeSelectorState {
|
||||
value: Array<any>
|
||||
unfolded: { [propName: string]: string }
|
||||
value: Array<any>
|
||||
unfolded: {[propName: string]: string}
|
||||
}
|
||||
|
||||
export class TreeSelector extends React.Component<
|
||||
TreeSelectorProps,
|
||||
TreeSelectorState
|
||||
> {
|
||||
static defaultProps = {
|
||||
showIcon: true,
|
||||
initiallyOpen: true,
|
||||
unfoldedLevel: 0,
|
||||
showRadio: false,
|
||||
multiple: false,
|
||||
disabled: false,
|
||||
withChildren: false,
|
||||
onlyChildren: false,
|
||||
nameField: 'name',
|
||||
valueField: 'value',
|
||||
iconField: 'icon',
|
||||
unfoldedField: 'unfolded',
|
||||
foldedField: 'foled',
|
||||
disabledField: 'disabled',
|
||||
joinValues: true,
|
||||
extractValue: false,
|
||||
delimiter: ',',
|
||||
hideRoot: true,
|
||||
rootLabel: '顶级',
|
||||
rootValue: 0,
|
||||
cascade: false,
|
||||
selfDisabledAffectChildren: true
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.renderList = this.renderList.bind(this)
|
||||
this.handleSelect = this.handleSelect.bind(this)
|
||||
this.clearSelect = this.clearSelect.bind(this)
|
||||
this.handleCheck = this.handleCheck.bind(this)
|
||||
this.toggleUnfolded = this.toggleUnfolded.bind(this)
|
||||
|
||||
const props = this.props
|
||||
|
||||
this.setState({
|
||||
value: value2array(props.value, {
|
||||
joinValues: props.joinValues,
|
||||
extractValue: props.extractValue,
|
||||
multiple: props.multiple,
|
||||
delimiter: props.delimiter,
|
||||
valueField: props.valueField,
|
||||
options: props.data
|
||||
}),
|
||||
unfolded: this.syncUnFolded(props)
|
||||
})
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: TreeSelectorProps) {
|
||||
const toUpdate: any = {}
|
||||
|
||||
if (
|
||||
this.props.value !== nextProps.value ||
|
||||
this.props.data !== nextProps.data
|
||||
) {
|
||||
toUpdate.value = value2array(nextProps.value, {
|
||||
joinValues: nextProps.joinValues,
|
||||
extractValue: nextProps.extractValue,
|
||||
multiple: nextProps.multiple,
|
||||
delimiter: nextProps.delimiter,
|
||||
valueField: nextProps.valueField,
|
||||
options: nextProps.data
|
||||
})
|
||||
export class TreeSelector extends React.Component<TreeSelectorProps, TreeSelectorState> {
|
||||
static defaultProps = {
|
||||
showIcon: true,
|
||||
initiallyOpen: true,
|
||||
unfoldedLevel: 0,
|
||||
showRadio: false,
|
||||
multiple: false,
|
||||
disabled: false,
|
||||
withChildren: false,
|
||||
onlyChildren: false,
|
||||
nameField: 'name',
|
||||
valueField: 'value',
|
||||
iconField: 'icon',
|
||||
unfoldedField: 'unfolded',
|
||||
foldedField: 'foled',
|
||||
disabledField: 'disabled',
|
||||
joinValues: true,
|
||||
extractValue: false,
|
||||
delimiter: ',',
|
||||
hideRoot: true,
|
||||
rootLabel: '顶级',
|
||||
rootValue: 0,
|
||||
cascade: false,
|
||||
selfDisabledAffectChildren: true,
|
||||
}
|
||||
|
||||
if (this.props.data !== nextProps.data) {
|
||||
toUpdate.unfolded = this.syncUnFolded(nextProps)
|
||||
componentWillMount() {
|
||||
this.renderList = this.renderList.bind(this)
|
||||
this.handleSelect = this.handleSelect.bind(this)
|
||||
this.clearSelect = this.clearSelect.bind(this)
|
||||
this.handleCheck = this.handleCheck.bind(this)
|
||||
this.toggleUnfolded = this.toggleUnfolded.bind(this)
|
||||
|
||||
const props = this.props
|
||||
|
||||
this.setState({
|
||||
value: value2array(props.value, {
|
||||
joinValues: props.joinValues,
|
||||
extractValue: props.extractValue,
|
||||
multiple: props.multiple,
|
||||
delimiter: props.delimiter,
|
||||
valueField: props.valueField,
|
||||
options: props.data,
|
||||
}),
|
||||
unfolded: this.syncUnFolded(props),
|
||||
})
|
||||
}
|
||||
|
||||
this.setState(toUpdate)
|
||||
}
|
||||
componentWillReceiveProps(nextProps: TreeSelectorProps) {
|
||||
const toUpdate: any = {}
|
||||
|
||||
syncUnFolded(props: TreeSelectorProps) {
|
||||
// 初始化树节点的展开状态
|
||||
let unfolded: { [propName: string]: string } = {}
|
||||
const { foldedField, unfoldedField } = this.props
|
||||
|
||||
eachTree(props.data, (node: Option, index, level) => {
|
||||
if (node.children && node.children.length) {
|
||||
let ret: any = true
|
||||
|
||||
if (unfoldedField && typeof node[unfoldedField] !== 'undefined') {
|
||||
ret = !!node[unfoldedField]
|
||||
} else if (foldedField && typeof node[foldedField] !== 'undefined') {
|
||||
ret = !node[foldedField]
|
||||
} else {
|
||||
ret = !!props.initiallyOpen
|
||||
if (!ret && level <= (props.unfoldedLevel as number)) {
|
||||
ret = true
|
||||
}
|
||||
if (this.props.value !== nextProps.value || this.props.data !== nextProps.data) {
|
||||
toUpdate.value = value2array(nextProps.value, {
|
||||
joinValues: nextProps.joinValues,
|
||||
extractValue: nextProps.extractValue,
|
||||
multiple: nextProps.multiple,
|
||||
delimiter: nextProps.delimiter,
|
||||
valueField: nextProps.valueField,
|
||||
options: nextProps.data,
|
||||
})
|
||||
}
|
||||
unfolded[node[props.valueField as string]] = ret
|
||||
}
|
||||
})
|
||||
|
||||
return unfolded
|
||||
}
|
||||
|
||||
toggleUnfolded(node: any) {
|
||||
this.setState({
|
||||
unfolded: {
|
||||
...this.state.unfolded,
|
||||
[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
|
||||
|
||||
onChange(joinValues ? rootValue : [])
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleSelect(node: any, value?: any) {
|
||||
this.setState(
|
||||
{
|
||||
value: [node]
|
||||
},
|
||||
() => {
|
||||
const { joinValues, valueField, onChange } = this.props
|
||||
|
||||
onChange(joinValues ? node[valueField as string] : node)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleCheck(item: any, checked: boolean) {
|
||||
const props = this.props
|
||||
const value = this.state.value.concat()
|
||||
const idx = value.indexOf(item)
|
||||
const onlyChildren = this.props.onlyChildren
|
||||
|
||||
if (checked) {
|
||||
~idx || value.push(item)
|
||||
if (!props.cascade) {
|
||||
const children = item.children ? item.children.concat([]) : []
|
||||
|
||||
if (onlyChildren) {
|
||||
// 父级选中的时候,子节点也都选中,但是自己不选中
|
||||
!~idx && children.length && value.shift()
|
||||
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (child.children) {
|
||||
children.push.apply(children, child.children)
|
||||
} else {
|
||||
~index || value.push(child)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 只要父节点选择了,子节点就不需要了,全部去掉勾选. withChildren时相反
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (~index) {
|
||||
value.splice(index, 1)
|
||||
}
|
||||
|
||||
if (props.withChildren) {
|
||||
value.push(child)
|
||||
}
|
||||
|
||||
if (child.children && child.children.length) {
|
||||
children.push.apply(children, child.children)
|
||||
}
|
||||
}
|
||||
if (this.props.data !== nextProps.data) {
|
||||
toUpdate.unfolded = this.syncUnFolded(nextProps)
|
||||
}
|
||||
}
|
||||
} else if (!checked) {
|
||||
~idx && value.splice(idx, 1)
|
||||
|
||||
if (!props.cascade && (props.withChildren || onlyChildren)) {
|
||||
const children = item.children ? item.children.concat([]) : []
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (~index) {
|
||||
value.splice(index, 1)
|
||||
}
|
||||
|
||||
if (child.children && child.children.length) {
|
||||
children.push.apply(children, child.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setState(toUpdate)
|
||||
}
|
||||
|
||||
this.setState(
|
||||
{
|
||||
value
|
||||
},
|
||||
() => {
|
||||
syncUnFolded(props: TreeSelectorProps) {
|
||||
// 初始化树节点的展开状态
|
||||
let unfolded: {[propName: string]: string} = {}
|
||||
const {foldedField, unfoldedField} = this.props
|
||||
|
||||
eachTree(props.data, (node: Option, index, level) => {
|
||||
if (node.children && node.children.length) {
|
||||
let ret: any = true
|
||||
|
||||
if (unfoldedField && typeof node[unfoldedField] !== 'undefined') {
|
||||
ret = !!node[unfoldedField]
|
||||
} else if (foldedField && typeof node[foldedField] !== 'undefined') {
|
||||
ret = !node[foldedField]
|
||||
} else {
|
||||
ret = !!props.initiallyOpen
|
||||
if (!ret && level <= (props.unfoldedLevel as number)) {
|
||||
ret = true
|
||||
}
|
||||
}
|
||||
unfolded[node[props.valueField as string]] = ret
|
||||
}
|
||||
})
|
||||
|
||||
return unfolded
|
||||
}
|
||||
|
||||
toggleUnfolded(node: any) {
|
||||
this.setState({
|
||||
unfolded: {
|
||||
...this.state.unfolded,
|
||||
[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
|
||||
|
||||
onChange(joinValues ? rootValue : [])
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleSelect(node: any, value?: any) {
|
||||
this.setState(
|
||||
{
|
||||
value: [node],
|
||||
},
|
||||
() => {
|
||||
const {joinValues, valueField, onChange} = this.props
|
||||
|
||||
onChange(joinValues ? node[valueField as string] : node)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleCheck(item: any, checked: boolean) {
|
||||
const props = this.props
|
||||
const value = this.state.value.concat()
|
||||
const idx = value.indexOf(item)
|
||||
const onlyChildren = this.props.onlyChildren
|
||||
|
||||
if (checked) {
|
||||
~idx || value.push(item)
|
||||
if (!props.cascade) {
|
||||
const children = item.children ? item.children.concat([]) : []
|
||||
|
||||
if (onlyChildren) {
|
||||
// 父级选中的时候,子节点也都选中,但是自己不选中
|
||||
!~idx && children.length && value.shift()
|
||||
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (child.children) {
|
||||
children.push.apply(children, child.children)
|
||||
} else {
|
||||
~index || value.push(child)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 只要父节点选择了,子节点就不需要了,全部去掉勾选. withChildren时相反
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (~index) {
|
||||
value.splice(index, 1)
|
||||
}
|
||||
|
||||
if (props.withChildren) {
|
||||
value.push(child)
|
||||
}
|
||||
|
||||
if (child.children && child.children.length) {
|
||||
children.push.apply(children, child.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!checked) {
|
||||
~idx && value.splice(idx, 1)
|
||||
|
||||
if (!props.cascade && (props.withChildren || onlyChildren)) {
|
||||
const children = item.children ? item.children.concat([]) : []
|
||||
while (children.length) {
|
||||
let child = children.shift()
|
||||
let index = value.indexOf(child)
|
||||
|
||||
if (~index) {
|
||||
value.splice(index, 1)
|
||||
}
|
||||
|
||||
if (child.children && child.children.length) {
|
||||
children.push.apply(children, child.children)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
renderList(
|
||||
list: Options,
|
||||
value: Option[],
|
||||
uncheckable: boolean
|
||||
): {dom: Array<JSX.Element | null>; childrenChecked: number} {
|
||||
const {
|
||||
joinValues,
|
||||
extractValue,
|
||||
valueField,
|
||||
delimiter,
|
||||
onChange
|
||||
itemClassName,
|
||||
showIcon,
|
||||
showRadio,
|
||||
multiple,
|
||||
disabled,
|
||||
nameField = '',
|
||||
valueField = '',
|
||||
iconField = '',
|
||||
disabledField = '',
|
||||
cascade,
|
||||
selfDisabledAffectChildren,
|
||||
onlyChildren,
|
||||
classnames: cx,
|
||||
highlightTxt,
|
||||
data,
|
||||
} = this.props
|
||||
|
||||
onChange(
|
||||
joinValues
|
||||
? value.map(item => item[valueField as string]).join(delimiter)
|
||||
: extractValue
|
||||
? value.map(item => item[valueField as string])
|
||||
: value
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
let childrenChecked = 0
|
||||
let ret = list.map((item, key) => {
|
||||
if (!isVisible(item as any, data)) {
|
||||
return null
|
||||
}
|
||||
|
||||
renderList(
|
||||
list: Options,
|
||||
value: Option[],
|
||||
uncheckable: boolean
|
||||
): { dom: Array<JSX.Element | null>; childrenChecked: number } {
|
||||
const {
|
||||
itemClassName,
|
||||
showIcon,
|
||||
showRadio,
|
||||
multiple,
|
||||
disabled,
|
||||
nameField = '',
|
||||
valueField = '',
|
||||
iconField = '',
|
||||
disabledField = '',
|
||||
cascade,
|
||||
selfDisabledAffectChildren,
|
||||
onlyChildren,
|
||||
classnames: cx,
|
||||
highlightTxt,
|
||||
data
|
||||
} = this.props
|
||||
const checked = !!~value.indexOf(item)
|
||||
const selfDisabled = item[disabledField]
|
||||
let selfChecked = !!uncheckable || checked
|
||||
|
||||
let childrenChecked = 0
|
||||
let ret = list.map((item, key) => {
|
||||
if (!isVisible(item as any, data)) {
|
||||
return null
|
||||
}
|
||||
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)
|
||||
)
|
||||
tmpChildrenChecked = !!childrenItems.childrenChecked
|
||||
if (!selfChecked && onlyChildren && item.children.length === childrenItems.childrenChecked) {
|
||||
selfChecked = true
|
||||
}
|
||||
childrenItems = childrenItems.dom
|
||||
}
|
||||
|
||||
const checked = !!~value.indexOf(item)
|
||||
const selfDisabled = item[disabledField]
|
||||
let selfChecked = !!uncheckable || checked
|
||||
if (tmpChildrenChecked || checked) {
|
||||
childrenChecked++
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
tmpChildrenChecked = !!childrenItems.childrenChecked
|
||||
if (
|
||||
!selfChecked &&
|
||||
onlyChildren &&
|
||||
item.children.length === childrenItems.childrenChecked
|
||||
) {
|
||||
selfChecked = true
|
||||
}
|
||||
childrenItems = childrenItems.dom
|
||||
}
|
||||
let nodeDisabled = !!uncheckable || !!disabled || selfDisabled
|
||||
|
||||
if (tmpChildrenChecked || checked) {
|
||||
childrenChecked++
|
||||
}
|
||||
const checkbox: JSX.Element | null = multiple ? (
|
||||
<label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled={nodeDisabled}
|
||||
checked={selfChecked}
|
||||
onChange={e => this.handleCheck(item, e.currentTarget.checked)}
|
||||
/>
|
||||
<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
|
||||
|
||||
let nodeDisabled = !!uncheckable || !!disabled || selfDisabled
|
||||
const isLeaf = !item.children || !item.children.length
|
||||
|
||||
const checkbox: JSX.Element | null = multiple ? (
|
||||
<label className={cx(`Checkbox Checkbox--checkbox Checkbox--sm`)}>
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled={nodeDisabled}
|
||||
checked={selfChecked}
|
||||
onChange={e => this.handleCheck(item, e.currentTarget.checked)}
|
||||
/>
|
||||
<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
|
||||
|
||||
const isLeaf = !item.children || !item.children.length
|
||||
|
||||
return (
|
||||
<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]]
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showIcon ? (
|
||||
<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
|
||||
})}
|
||||
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}
|
||||
</li>
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
dom: ret,
|
||||
childrenChecked
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
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')}>
|
||||
<a>
|
||||
{showIcon ? (
|
||||
<i className={cx('Tree-itemIcon Tree-rootIcon')} />
|
||||
) : null}
|
||||
|
||||
<label
|
||||
className={cx('Tree-itemLabel', {
|
||||
'is-checked': !value || !value.length
|
||||
return (
|
||||
<li
|
||||
key={key}
|
||||
className={cx(`Tree-item ${itemClassName || ''}`, {
|
||||
'Tree-item--isLeaf': isLeaf,
|
||||
})}
|
||||
>
|
||||
<span
|
||||
className={cx('Tree-itemText')}
|
||||
onClick={this.clearSelect}
|
||||
>
|
||||
{rootLabel}
|
||||
</span>
|
||||
</label>
|
||||
</a>
|
||||
<ul className={cx('Tree-sublist')}>
|
||||
{this.renderList(data, value, false).dom}
|
||||
</ul>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
) : (
|
||||
<div className={cx('Tree-placeholder')}>{placeholder}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
>
|
||||
<a>
|
||||
{!isLeaf ? (
|
||||
<i
|
||||
onClick={() => this.toggleUnfolded(item)}
|
||||
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')}`
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{checkbox}
|
||||
|
||||
<span
|
||||
className={cx('Tree-itemText', {
|
||||
'is-children-checked': multiple && !cascade && tmpChildrenChecked && !nodeDisabled,
|
||||
'is-checked': checked,
|
||||
'is-disabled': nodeDisabled,
|
||||
})}
|
||||
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}
|
||||
</li>
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
dom: ret,
|
||||
childrenChecked,
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
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')}>
|
||||
<a>
|
||||
{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}>
|
||||
{rootLabel}
|
||||
</span>
|
||||
</label>
|
||||
</a>
|
||||
<ul className={cx('Tree-sublist')}>{this.renderList(data, value, false).dom}</ul>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
) : (
|
||||
<div className={cx('Tree-placeholder')}>{placeholder}</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(TreeSelector)
|
||||
|
@ -6,78 +6,72 @@
|
||||
|
||||
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"
|
||||
/>
|
||||
</svg>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
)
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import NotFound from './404'
|
||||
import { default as Alert, alert, confirm } from './Alert'
|
||||
import {default as Alert, alert, confirm} from './Alert'
|
||||
import AsideNav from './AsideNav'
|
||||
import Button from './Button'
|
||||
import Checkbox from './Checkbox'
|
||||
@ -33,46 +33,46 @@ import Spinner from './Spinner'
|
||||
import Switch from './Switch'
|
||||
import Textarea from './Textarea'
|
||||
import TitleBar from './TitleBar'
|
||||
import { default as ToastComponent, toast } from './Toast'
|
||||
import {default as ToastComponent, toast} from './Toast'
|
||||
import Tooltip from './Tooltip'
|
||||
import TooltipWrapper from './TooltipWrapper'
|
||||
import Tree from './Tree'
|
||||
|
||||
export {
|
||||
NotFound,
|
||||
Alert as AlertComponent,
|
||||
alert,
|
||||
confirm,
|
||||
AsideNav,
|
||||
Button,
|
||||
Checkbox,
|
||||
Checkboxes,
|
||||
Collapse,
|
||||
ColorPicker,
|
||||
DatePicker,
|
||||
DateRangePicker,
|
||||
Drawer,
|
||||
DropdownButton,
|
||||
// Editor,
|
||||
Html,
|
||||
Icons,
|
||||
Layout,
|
||||
LazyComponent,
|
||||
Modal,
|
||||
Overlay,
|
||||
PopOver,
|
||||
Radios,
|
||||
Range,
|
||||
Rating,
|
||||
// RichText,
|
||||
Select,
|
||||
Spinner,
|
||||
Switch,
|
||||
Textarea,
|
||||
TitleBar,
|
||||
ToastComponent,
|
||||
toast,
|
||||
Tooltip,
|
||||
TooltipWrapper,
|
||||
Tree
|
||||
NotFound,
|
||||
Alert as AlertComponent,
|
||||
alert,
|
||||
confirm,
|
||||
AsideNav,
|
||||
Button,
|
||||
Checkbox,
|
||||
Checkboxes,
|
||||
Collapse,
|
||||
ColorPicker,
|
||||
DatePicker,
|
||||
DateRangePicker,
|
||||
Drawer,
|
||||
DropdownButton,
|
||||
// Editor,
|
||||
Html,
|
||||
Icons,
|
||||
Layout,
|
||||
LazyComponent,
|
||||
Modal,
|
||||
Overlay,
|
||||
PopOver,
|
||||
Radios,
|
||||
Range,
|
||||
Rating,
|
||||
// RichText,
|
||||
Select,
|
||||
Spinner,
|
||||
Switch,
|
||||
Textarea,
|
||||
TitleBar,
|
||||
ToastComponent,
|
||||
toast,
|
||||
Tooltip,
|
||||
TooltipWrapper,
|
||||
Tree,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user