commit
392c19caec
|
@ -369,7 +369,7 @@ $Spinner-height: px2rem(26px) !default;
|
|||
$Spinner--lg-width: px2rem(50px) !default;
|
||||
$Spinner--lg-height: px2rem(50px) !default;
|
||||
|
||||
$Spinner-bg: url('./spinner-default.svg') !default;
|
||||
$Spinner-bg: url('./spinner-default.svg?__inline') !default;
|
||||
|
||||
// Tabs
|
||||
$Tabs-linkFontSize: $fontSizeBase !default;
|
||||
|
|
|
@ -16,18 +16,12 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
background: $Spinner-overlay-bg;
|
||||
transition: ease-out opacity 0.3s;
|
||||
|
||||
.#{$ns}Spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
opacity: 0;
|
||||
|
||||
.#{$ns}Spinner--lg {
|
||||
width: $Spinner--lg-width;
|
||||
height: $Spinner--lg-height;
|
||||
line-height: $Spinner--lg-height;
|
||||
&.in {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,14 +37,30 @@
|
|||
width: $Spinner--lg-width;
|
||||
height: $Spinner--lg-height;
|
||||
}
|
||||
|
||||
transition: ease-out all 0.3s;
|
||||
}
|
||||
|
||||
// 当启用 overlay 的时候,应该是居中模式。
|
||||
.#{$ns}Spinner--overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
}
|
||||
|
||||
.#{$ns}Spinner--overlay.#{$ns}Spinner--lg {
|
||||
width: $Spinner--lg-width;
|
||||
height: $Spinner--lg-height;
|
||||
line-height: $Spinner--lg-height;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.#{$ns}Layout .#{$ns}Page-body > .#{$ns}Spinner-overlay {
|
||||
.#{$ns}Layout .#{$ns}Page-body>.#{$ns}Spinner-overlay {
|
||||
left: $Layout-aside-width;
|
||||
}
|
||||
|
||||
.#{$ns}Layout--folded .#{$ns}Page-body > .#{$ns}Spinner-overlay {
|
||||
.#{$ns}Layout--folded .#{$ns}Page-body>.#{$ns}Spinner-overlay {
|
||||
left: $Layout-aside--folded-width;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,17 +6,24 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {ClassNamesFn, themeable} from '../theme';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import Transition, {ENTERED, ENTERING} from 'react-transition-group/Transition';
|
||||
|
||||
interface SpinnerProps extends RendererProps {
|
||||
const fadeStyles: {
|
||||
[propName: string]: string;
|
||||
} = {
|
||||
[ENTERING]: 'in',
|
||||
[ENTERED]: 'in'
|
||||
};
|
||||
|
||||
interface SpinnerProps {
|
||||
overlay: boolean;
|
||||
spinnerClassName: string;
|
||||
mode: string;
|
||||
size: string;
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export class Spinner extends React.Component<SpinnerProps, object> {
|
||||
|
@ -24,26 +31,45 @@ export class Spinner extends React.Component<SpinnerProps, object> {
|
|||
overlay: false,
|
||||
spinnerClassName: '',
|
||||
mode: '',
|
||||
size: ''
|
||||
size: '',
|
||||
show: true
|
||||
};
|
||||
|
||||
div: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
overlay: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
|
||||
render() {
|
||||
const {mode, overlay, spinnerClassName, classPrefix: ns, classnames: cx, size} = this.props;
|
||||
const {show, classnames: cx, spinnerClassName, mode, size, overlay} = this.props;
|
||||
return (
|
||||
<Transition mountOnEnter unmountOnExit in={show} timeout={350}>
|
||||
{(status: string) => {
|
||||
if (status === ENTERING) {
|
||||
// force reflow
|
||||
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短,上次的样式还没应用进去,所以这里强制reflow一把。
|
||||
// 否则看不到动画。
|
||||
this.div.current!.offsetWidth;
|
||||
this.overlay.current && this.overlay.current.offsetWidth;
|
||||
}
|
||||
|
||||
const spinner = (
|
||||
<div
|
||||
className={cx(`${ns}Spinner`, spinnerClassName, {
|
||||
[`Spinner--${mode}`]: !!mode,
|
||||
[`Spinner--${size}`]: !!size
|
||||
})}
|
||||
/>
|
||||
return (
|
||||
<>
|
||||
{overlay ? (
|
||||
<div ref={this.overlay} className={cx(`Spinner-overlay`, fadeStyles[status])} />
|
||||
) : null}
|
||||
|
||||
<div
|
||||
ref={this.div}
|
||||
className={cx(`Spinner`, spinnerClassName, fadeStyles[status], {
|
||||
[`Spinner--${mode}`]: mode,
|
||||
[`Spinner--overlay`]: overlay,
|
||||
[`Spinner--${size}`]: size
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Transition>
|
||||
);
|
||||
|
||||
if (overlay) {
|
||||
return <div className={cx(`Spinner-overlay`)}>{spinner}</div>;
|
||||
}
|
||||
|
||||
return spinner;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import {isValidApi, buildApi, isEffectiveApi} from '../utils/api';
|
|||
import omit = require('lodash/omit');
|
||||
import find = require('lodash/find');
|
||||
import Html from '../components/Html';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
interface CRUDProps extends RendererProps {
|
||||
api?: Api;
|
||||
|
@ -1367,23 +1368,11 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
|||
onPopOverClose: this.handleChildPopOverClose,
|
||||
headerToolbarRender: this.renderHeaderToolbar,
|
||||
footerToolbarRender: this.renderFooterToolbar,
|
||||
data: store.mergedData,
|
||||
data: store.mergedData
|
||||
}
|
||||
)}
|
||||
|
||||
{store.loading
|
||||
? render(
|
||||
'info',
|
||||
{
|
||||
type: 'spinner',
|
||||
overlay: true
|
||||
},
|
||||
{
|
||||
size: 'lg',
|
||||
key: 'info'
|
||||
}
|
||||
)
|
||||
: null}
|
||||
<Spinner overlay size="lg" key="info" show={store.loading} />
|
||||
|
||||
{render(
|
||||
'dialog',
|
||||
|
|
|
@ -13,6 +13,7 @@ import {reaction} from 'mobx';
|
|||
import {Icon} from '../components/icons';
|
||||
import {ModalStore, IModalStore} from '../store/modal';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
export interface DialogProps extends RendererProps {
|
||||
title?: string; // 标题
|
||||
|
@ -324,18 +325,7 @@ export default class Dialog extends React.Component<DialogProps, DialogState> {
|
|||
<div className={cx('Modal-footer')}>
|
||||
{store.loading || store.error ? (
|
||||
<div className={cx('Dialog-info')} key="info">
|
||||
{store.loading
|
||||
? render(
|
||||
'info',
|
||||
{
|
||||
type: 'spinner'
|
||||
},
|
||||
{
|
||||
key: 'info',
|
||||
size: 'sm'
|
||||
}
|
||||
)
|
||||
: null}
|
||||
<Spinner size="sm" key="info" show={store.loading} />
|
||||
{store.error ? <span className={cx('Dialog-error')}>{store.msg}</span> : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
@ -13,6 +13,7 @@ import {reaction} from 'mobx';
|
|||
import {findDOMNode} from 'react-dom';
|
||||
import {IModalStore, ModalStore} from '../store/modal';
|
||||
import {filter} from '../utils/tpl';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
export interface DrawerProps extends RendererProps {
|
||||
title?: string; // 标题
|
||||
|
@ -284,17 +285,7 @@ export default class Drawer extends React.Component<DrawerProps, object> {
|
|||
<div className={cx('Drawer-footer')}>
|
||||
{store.loading || store.error ? (
|
||||
<div className={cx('Drawer-info')}>
|
||||
{store.loading
|
||||
? render(
|
||||
'info',
|
||||
{
|
||||
type: 'spinner'
|
||||
},
|
||||
{
|
||||
key: 'info'
|
||||
}
|
||||
)
|
||||
: null}
|
||||
<Spinner size="sm" key="info" show={store.loading} />
|
||||
{store.error ? <span className={cx('Drawer-error')}>{store.msg}</span> : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
@ -7,7 +7,7 @@ import React from 'react';
|
|||
import cx from 'classnames';
|
||||
import {FormControlProps, FormItem} from './Item';
|
||||
import {buildApi, isValidApi, isEffectiveApi} from '../../utils/api';
|
||||
import {Checkbox} from '../../components';
|
||||
import {Checkbox, Spinner} from '../../components';
|
||||
|
||||
export interface Column {
|
||||
label: string;
|
||||
|
@ -241,13 +241,7 @@ export default class MatrixCheckbox extends React.Component<MatrixProps, MatrixS
|
|||
this.renderInput()
|
||||
)}
|
||||
|
||||
{loading
|
||||
? render('loading', {
|
||||
type: 'spinner',
|
||||
overlay: true,
|
||||
size: 'lg'
|
||||
})
|
||||
: null}
|
||||
<Spinner size="lg" overlay key="info" show={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import {OptionsControl, OptionsControlProps, Option} from './Options';
|
|||
import {xorBy, find} from 'lodash';
|
||||
import Checkbox from '../../components/Checkbox';
|
||||
import {closeIcon, Icon} from '../../components/icons';
|
||||
import {Spinner} from '../../components';
|
||||
|
||||
export interface TransferSelectProps extends OptionsControlProps {
|
||||
viewMode?: 'table' | 'normal';
|
||||
|
@ -377,19 +378,7 @@ export class TransferSelect extends React.Component<TransferSelectProps, Transfe
|
|||
|
||||
{viewMode === 'table' ? this.renderTableSelectedOptions() : this.renderNormalSelectedOptions()}
|
||||
|
||||
{loading
|
||||
? render(
|
||||
'loading',
|
||||
{
|
||||
type: 'spinner',
|
||||
overlay: true
|
||||
},
|
||||
{
|
||||
size: 'lg',
|
||||
key: 'info'
|
||||
}
|
||||
)
|
||||
: null}
|
||||
<Spinner size="lg" overlay key="info" show={loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Action, Schema, PlainObject, Api, Payload} from '../../types';
|
|||
import {isEffectiveApi} from '../../utils/api';
|
||||
import {filter} from '../../utils/tpl';
|
||||
import {Option} from '../../components/Checkboxes';
|
||||
import {Spinner} from '../../components';
|
||||
|
||||
export interface TreeProps extends OptionsControlProps {
|
||||
placeholder?: any;
|
||||
|
@ -28,11 +29,11 @@ export interface TreeProps extends OptionsControlProps {
|
|||
}
|
||||
|
||||
export interface TreeState {
|
||||
isAddModalOpened: boolean,
|
||||
isEditModalOpened: boolean,
|
||||
parent: Option | null,
|
||||
prev: Option | null,
|
||||
data: any
|
||||
isAddModalOpened: boolean;
|
||||
isEditModalOpened: boolean;
|
||||
parent: Option | null;
|
||||
prev: Option | null;
|
||||
data: any;
|
||||
}
|
||||
|
||||
export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
||||
|
@ -51,7 +52,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
parent: null,
|
||||
prev: null,
|
||||
data: null
|
||||
}
|
||||
};
|
||||
|
||||
reload() {
|
||||
const reload = this.props.reloadOptions;
|
||||
|
@ -65,10 +66,13 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
|
||||
@autobind
|
||||
handleAddModalConfirm(values: Array<any>, action: Action, ctx: any, components: Array<any>) {
|
||||
this.saveRemote({
|
||||
...values,
|
||||
parent: this.state.parent
|
||||
}, 'add');
|
||||
this.saveRemote(
|
||||
{
|
||||
...values,
|
||||
parent: this.state.parent
|
||||
},
|
||||
'add'
|
||||
);
|
||||
this.closeAddDialog();
|
||||
}
|
||||
|
||||
|
@ -79,21 +83,19 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
|
||||
@autobind
|
||||
handleEditModalConfirm(values: Array<any>, action: Action, ctx: any, components: Array<any>) {
|
||||
this.saveRemote({
|
||||
...values,
|
||||
prev: this.state.prev
|
||||
}, 'edit');
|
||||
this.saveRemote(
|
||||
{
|
||||
...values,
|
||||
prev: this.state.prev
|
||||
},
|
||||
'edit'
|
||||
);
|
||||
this.closeEditDialog();
|
||||
}
|
||||
|
||||
@autobind
|
||||
async saveRemote(item: any, type: 'add' | 'edit') {
|
||||
const {
|
||||
addApi,
|
||||
editApi,
|
||||
data,
|
||||
env
|
||||
} = this.props;
|
||||
const {addApi, editApi, data, env} = this.props;
|
||||
|
||||
let remote: Payload | null = null;
|
||||
if (type == 'add' && isEffectiveApi(addApi, createObject(data, item))) {
|
||||
|
@ -106,7 +108,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
env.notify('error', remote.msg || '保存失败');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.reload();
|
||||
}
|
||||
|
||||
|
@ -207,11 +209,8 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
|
||||
return (
|
||||
<div className={cx(`${ns}TreeControl`, className)}>
|
||||
{loading ? (
|
||||
render('loading', {
|
||||
type: 'spinner'
|
||||
})
|
||||
) : (
|
||||
<Spinner size="sm" key="info" show={loading} />
|
||||
{loading ? null : (
|
||||
<TreeSelector
|
||||
classPrefix={ns}
|
||||
valueField={valueField}
|
||||
|
@ -250,35 +249,37 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
|||
/>
|
||||
)}
|
||||
|
||||
{addMode && render(
|
||||
'modal',
|
||||
{
|
||||
type: 'dialog',
|
||||
...addDialog
|
||||
},
|
||||
{
|
||||
key: 'addModal',
|
||||
data: data,
|
||||
onConfirm: this.handleAddModalConfirm,
|
||||
onClose: this.closeAddDialog,
|
||||
show: this.state.isAddModalOpened
|
||||
}
|
||||
)}
|
||||
{addMode &&
|
||||
render(
|
||||
'modal',
|
||||
{
|
||||
type: 'dialog',
|
||||
...addDialog
|
||||
},
|
||||
{
|
||||
key: 'addModal',
|
||||
data: data,
|
||||
onConfirm: this.handleAddModalConfirm,
|
||||
onClose: this.closeAddDialog,
|
||||
show: this.state.isAddModalOpened
|
||||
}
|
||||
)}
|
||||
|
||||
{editMode && render(
|
||||
'modal',
|
||||
{
|
||||
type: 'dialog',
|
||||
...editDialog
|
||||
},
|
||||
{
|
||||
key: 'editModal',
|
||||
data: data,
|
||||
onConfirm: this.handleEditModalConfirm,
|
||||
onClose: this.closeEditDialog,
|
||||
show: this.state.isEditModalOpened
|
||||
}
|
||||
)}
|
||||
{editMode &&
|
||||
render(
|
||||
'modal',
|
||||
{
|
||||
type: 'dialog',
|
||||
...editDialog
|
||||
},
|
||||
{
|
||||
key: 'editModal',
|
||||
data: data,
|
||||
onConfirm: this.handleEditModalConfirm,
|
||||
onClose: this.closeEditDialog,
|
||||
show: this.state.isEditModalOpened
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import {isVisible, autobind, bulkBindFunctions} from '../utils/helper';
|
|||
import {ScopedContext, IScopedContext} from '../Scoped';
|
||||
import Alert from '../components/Alert2';
|
||||
import {isApiOutdated, isEffectiveApi} from '../utils/api';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
export interface PageProps extends RendererProps {
|
||||
title?: string; // 标题
|
||||
|
@ -403,13 +404,7 @@ export default class Page extends React.Component<PageProps> {
|
|||
<div className={cx('Page-main')}>
|
||||
{this.renderHeader()}
|
||||
<div className={cx(`Page-body`, bodyClassName)}>
|
||||
{store.loading
|
||||
? render('spinner', {
|
||||
type: 'spinner',
|
||||
overlay: true,
|
||||
size: 'lg'
|
||||
})
|
||||
: null}
|
||||
<Spinner size="lg" overlay key="info" show={store.loading} />
|
||||
|
||||
{store.error ? (
|
||||
<Alert level="danger" showCloseButton onClose={store.clearMessage}>
|
||||
|
|
|
@ -8,6 +8,7 @@ import cx from 'classnames';
|
|||
import Scoped, {ScopedContext, IScopedContext} from '../Scoped';
|
||||
import {observer} from 'mobx-react';
|
||||
import {isApiOutdated, isEffectiveApi} from '../utils/api';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
export interface ServiceProps extends RendererProps {
|
||||
api?: Api;
|
||||
|
@ -199,19 +200,7 @@ export default class Service extends React.Component<ServiceProps> {
|
|||
|
||||
{this.renderBody()}
|
||||
|
||||
{store.loading
|
||||
? render(
|
||||
'info',
|
||||
{
|
||||
type: 'spinner',
|
||||
overlay: true
|
||||
},
|
||||
{
|
||||
key: 'info',
|
||||
size: 'lg'
|
||||
}
|
||||
)
|
||||
: null}
|
||||
<Spinner size="lg" overlay key="info" show={store.loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import Spinner from '../components/Spinner';
|
||||
import {Renderer} from '../factory';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import React from 'react';
|
||||
|
||||
interface SpinnerProps extends RendererProps {}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)spinner$/,
|
||||
name: 'spinner'
|
||||
})
|
||||
export class SpinnerRenderer extends Spinner {}
|
||||
export class SpinnerRenderer extends React.Component<SpinnerProps> {
|
||||
render() {
|
||||
return <Spinner {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import {observer} from 'mobx-react';
|
|||
import {createObject, until, isVisible} from '../utils/helper';
|
||||
import {isApiOutdated, isEffectiveApi} from '../utils/api';
|
||||
import {IFormStore} from '../store/form';
|
||||
import {Spinner} from '../components';
|
||||
|
||||
export interface WizardProps extends RendererProps {
|
||||
store: IServiceStore;
|
||||
|
@ -583,13 +584,7 @@ export default class Wizard extends React.Component<WizardProps, WizardState> {
|
|||
)}
|
||||
{this.renderActions()}
|
||||
|
||||
{store.loading
|
||||
? render('spinner', {
|
||||
type: 'spinner',
|
||||
overlay: true,
|
||||
size: 'lg'
|
||||
})
|
||||
: null}
|
||||
<Spinner size="lg" overlay key="info" show={store.loading} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -232,7 +232,16 @@ export const filters: {
|
|||
arg1 = expOrDirective;
|
||||
}
|
||||
arg1 = arg1 ? (/^('|")(.*)\1$/.test(arg1) ? RegExp.$2 : resolveVariable(arg1, this as any)) : '';
|
||||
fn = value => !!~String(value).toLowerCase().indexOf(arg1);
|
||||
|
||||
// 比对的值是空时直接返回。
|
||||
if (!arg1) {
|
||||
return input;
|
||||
}
|
||||
|
||||
fn = value =>
|
||||
!!~String(value)
|
||||
.toLowerCase()
|
||||
.indexOf(arg1);
|
||||
}
|
||||
|
||||
keys = keys.split(/\s*,\s*/);
|
||||
|
|
Loading…
Reference in New Issue