import Icons from '@ali/ve-icons';
import classNames from 'classnames';
import { Component } from 'react';
import { testType } from '@ali/ve-utils';
import VEField, { IVEFieldProps } from './field';
import { SettingField } from './settingField';
import VariableSwitcher from './variableSwitcher';
import popups from '@ali/ve-popups';
import './fields.less';
interface IHelpTip {
url?: string;
content?: string | JSX.Element;
}
function renderTip(tip: IHelpTip, prop?: { propName?: string }) {
const propName = prop && prop.propName;
if (!tip) {
return (
);
}
if (testType(tip) === 'object') {
return (
属性:{propName}
说明:{tip.content}
);
}
return (
);
}
export class PlainField extends VEField {
public static defaultProps = {
headDIY: true,
};
public static displayName = 'PlainField';
public renderHead(): null {
return null;
}
}
export class InlineField extends VEField {
public static displayName = 'InlineField';
constructor(props: any) {
super(props);
this.classNames = ['engine-setting-field', 'engine-inline-field'];
}
public renderFoot() {
return (
);
}
}
export class BlockField extends VEField {
public static displayName = 'BlockField';
constructor(props: IVEFieldProps) {
super(props);
this.classNames = ['engine-setting-field', 'engine-block-field', props.isGroup ? 'engine-group-field' : ''];
}
public renderHead() {
const { title, tip, propName } = this.props;
return [
{title}
,
renderTip(tip, { propName }),
,
];
}
}
export class AccordionField extends VEField {
public readonly props: IVEFieldProps;
private willDetach?: () => any;
constructor(props: IVEFieldProps) {
super(props);
this._generateClassNames(props);
if (this.props.onExpandChange) {
this.willDetach = this.props.onExpandChange(() => this.forceUpdate());
}
}
public componentWillReceiveProps(nextProps: IVEFieldProps) {
this.classNames = this._generateClassNames(nextProps);
}
public componentWillUnmount() {
if (this.willDetach) {
this.willDetach();
}
}
public renderHead() {
const { title, tip, toggleExpand, propName } = this.props;
return (
toggleExpand && toggleExpand()}>
{title}
{renderTip(tip, { propName })}
{}
);
}
private _generateClassNames(props: IVEFieldProps) {
this.classNames = [
'engine-setting-field',
'engine-accordion-field',
props.isGroup ? 'engine-group-field' : '',
!props.isExpand ? 'engine-collapsed' : '',
];
return this.classNames;
}
}
export class EntryField extends VEField {
constructor(props: any) {
super(props);
this.classNames = ['engine-setting-field', 'engine-entry-field'];
}
public render() {
const { propName, stageName, tip, title } = this.props;
const classNameList = classNames(...this.classNames, this.props.className);
const fieldProps: any = {};
if (stageName) {
// 为 stage 切换奠定基础
fieldProps['data-stage-target'] = this.props.stageName;
}
const innerElements = [
{title}
,
renderTip(tip, { propName }),
,
];
return (
{innerElements}
);
}
}
export class PopupField extends VEField {
constructor(props: any) {
super(props);
this.classNames = ['engine-setting-field', 'engine-popup-field'];
}
public renderBody() {
return '';
}
public render() {
const { propName, stageName, tip, title } = this.props;
const classNameList = classNames(...this.classNames, this.props.className);
const fieldProps: any = {};
if (stageName) {
// 为 stage 切换奠定基础
fieldProps['data-stage-target'] = this.props.stageName;
}
return (
popups.popup({
cancelOnBlur: true,
content: this.props.children,
position: 'left bottom',
showClose: true,
sizeFixed: true,
target: e.currentTarget,
})
}
>
{title}
{renderTip(tip, { propName })}
);
}
}
export class CaptionField extends VEField {
constructor(props: IVEFieldProps) {
super(props);
this.classNames = ['engine-setting-field', 'engine-caption-field'];
}
public renderHead() {
const { title, tip, propName } = this.props;
return (
{title}
{renderTip(tip, { propName })}
);
}
}
export class Stage extends Component {
public readonly props: {
key: any;
stage: any;
current?: boolean;
direction?: any;
};
public stage: any;
public additionClassName: string;
public shell: Element | null = null;
private willDetach: () => any;
public componentWillMount() {
this.stage = this.props.stage;
if (this.stage.onCurrentTabChange) {
this.willDetach = this.stage.onCurrentTabChange(() => this.forceUpdate());
}
}
public componentDidMount() {
this.doSkate();
}
public componentWillReceiveProps(props: any) {
if (props.stage !== this.stage) {
this.stage = props.stage;
if (this.willDetach) {
this.willDetach();
}
if (this.stage.onCurrentTabChange) {
this.willDetach = this.stage.onCurrentTabChange(() => this.forceUpdate());
}
}
}
public componentDidUpdate() {
this.doSkate();
}
public componentWillUnmount() {
if (this.willDetach) {
this.willDetach();
}
}
public doSkate() {
if (this.additionClassName) {
setTimeout(() => {
const elem = this.shell;
if (elem && elem.classList) {
if (this.props.current) {
elem.classList.remove(this.additionClassName);
} else {
elem.classList.add(this.additionClassName);
}
this.additionClassName = '';
}
}, 10);
}
}
public render() {
const { stage } = this;
let content = null;
let tabs = null;
let className = 'engine-settings-stage';
if (stage.getTabs) {
const selected = stage.getNode();
// stat for cache
stage.stat();
const currentTab = stage.getCurrentTab();
if (stage.hasTabs()) {
className += ' engine-has-tabs';
tabs = (
{stage.getTabs().map((tab: any) => (
stage.setCurrentTab(tab)}
>
{tab.getTitle()}
{renderTip(tab.getTip())}
))}
);
}
if (currentTab) {
if (currentTab.getVisibleItems) {
content = currentTab
.getVisibleItems()
.map((item: any) => );
} else if (currentTab.getSetter) {
content = (
);
}
}
} else {
content = stage.getContent();
}
if (this.props.current) {
if (this.props.direction) {
this.additionClassName = `engine-stagein-${this.props.direction}`;
className += ` ${this.additionClassName}`;
}
} else if (this.props.direction) {
this.additionClassName = `engine-stageout-${this.props.direction}`;
}
let stageBacker = null;
if (stage.hasBack()) {
className += ' engine-has-backer';
stageBacker = (
{stage.getTitle()}
{renderTip(stage.getTip())}
);
}
return (
{
this.shell = ref;
}}
className={className}
>
{stageBacker}
{tabs}
{content}
);
}
}