refactor: 💡 format

This commit is contained in:
SIMDD 2019-05-08 12:38:57 +08:00
parent 3589913d69
commit 9e5c689d20
36 changed files with 5277 additions and 5944 deletions

View File

@ -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"
}

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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',
})
)

View File

@ -1,3 +1,3 @@
import { Collapse } from 'react-bootstrap'
import {Collapse} from 'react-bootstrap'
export default Collapse

View File

@ -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

View File

@ -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))

View File

@ -1,3 +1,3 @@
import { DropdownButton } from 'react-bootstrap'
import {DropdownButton} from 'react-bootstrap'
export default DropdownButton

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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>
}
}

View File

@ -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)

View File

@ -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()
}
}

View File

@ -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} />
}
}

View File

@ -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)

View File

@ -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',
})
)

View File

@ -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',
})
)

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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'),
}

View File

@ -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)

View File

@ -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',
})
)

View File

@ -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)

View File

@ -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>
)

View File

@ -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,
}