mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-02-28 04:40:32 +00:00
fix: settings pane
This commit is contained in:
parent
92ea6505c1
commit
27db010b8a
@ -38,6 +38,10 @@ export interface FieldExtraProps {
|
||||
* internal use
|
||||
*/
|
||||
forceInline?: number;
|
||||
/**
|
||||
* compatiable vision display
|
||||
*/
|
||||
display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';
|
||||
}
|
||||
|
||||
export interface FieldConfig extends FieldExtraProps {
|
||||
|
||||
@ -7,44 +7,89 @@ import './index.less';
|
||||
|
||||
export interface FieldProps {
|
||||
className?: string;
|
||||
// span
|
||||
title?: TitleContent | null;
|
||||
defaultDisplay?: 'accordion' | 'inline' | 'block';
|
||||
collapsed?: boolean;
|
||||
onExpandChange?: (expandState: boolean) => void;
|
||||
}
|
||||
|
||||
export class CommonField extends Component<FieldProps> {
|
||||
private shell: HTMLDivElement | null = null;
|
||||
export class Field extends Component<FieldProps> {
|
||||
state = {
|
||||
collapsed: this.props.collapsed,
|
||||
display: this.props.defaultDisplay || 'inline',
|
||||
};
|
||||
|
||||
private checkIsBlockField() {
|
||||
if (this.shell) {
|
||||
const setter = this.shell.lastElementChild!.firstElementChild;
|
||||
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||
this.shell.classList.add('lc-block-field');
|
||||
this.shell.classList.remove('lc-inline-field');
|
||||
} else {
|
||||
this.shell.classList.remove('lc-block-field');
|
||||
this.shell.classList.add('lc-inline-field');
|
||||
}
|
||||
private toggleExpand = () => {
|
||||
const { onExpandChange } = this.props;
|
||||
const collapsed = !this.state.collapsed;
|
||||
this.setState({
|
||||
collapsed,
|
||||
});
|
||||
onExpandChange && onExpandChange(!collapsed);
|
||||
};
|
||||
private body: HTMLDivElement | null = null;
|
||||
private dispose?: () => void;
|
||||
private deployBlockTesting() {
|
||||
if (this.dispose) {
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.checkIsBlockField();
|
||||
const body = this.body;
|
||||
if (!body) {
|
||||
return;
|
||||
}
|
||||
const check = () => {
|
||||
const setter = body.firstElementChild;
|
||||
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||
this.setState({
|
||||
display: 'block',
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
display: 'inline',
|
||||
});
|
||||
}
|
||||
};
|
||||
const observer = new MutationObserver(check);
|
||||
check();
|
||||
observer.observe(body, {
|
||||
childList: true,
|
||||
subtree: false,
|
||||
attributes: true,
|
||||
attributeFilter: ['class'],
|
||||
});
|
||||
this.dispose = () => observer.disconnect();
|
||||
}
|
||||
componentDidMount() {
|
||||
this.checkIsBlockField();
|
||||
const { defaultDisplay } = this.props;
|
||||
if (!defaultDisplay || defaultDisplay === 'inline') {
|
||||
this.deployBlockTesting();
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
if (this.dispose) {
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, children, title } = this.props;
|
||||
const { display, collapsed } = this.state;
|
||||
const isAccordion = display === 'accordion';
|
||||
return (
|
||||
<div ref={(shell) => (this.shell = shell)} className={classNames('lc-field lc-inline-field', className)}>
|
||||
{title && (
|
||||
<div className="lc-field-head">
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
<div
|
||||
className={classNames(`lc-field lc-${display}-field`, className, {
|
||||
'lc-field-is-collapsed': isAccordion && collapsed,
|
||||
})}
|
||||
>
|
||||
<div className="lc-field-head" onClick={isAccordion ? this.toggleExpand : undefined}>
|
||||
<div className="lc-field-title">
|
||||
<Title title={title || ''} />
|
||||
</div>
|
||||
)}
|
||||
<div className="lc-field-body">{children}</div>
|
||||
{isAccordion && <Icon className="lc-field-icon" type="arrow-up" size="xs" />}
|
||||
</div>
|
||||
<div key="body" ref={(shell) => (this.body = shell)} className="lc-field-body">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -96,15 +141,13 @@ export class PopupField extends Component<PopupFieldProps> {
|
||||
}
|
||||
}
|
||||
|
||||
export type EntryFieldProps = FieldProps;
|
||||
export interface EntryFieldProps extends FieldProps {
|
||||
stageName?: string;
|
||||
}
|
||||
|
||||
export class EntryField extends Component<EntryFieldProps> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { propName, stageName, tip, title, className } = this.props;
|
||||
const { stageName, title, className } = this.props;
|
||||
const classNameList = classNames('engine-setting-field', 'engine-entry-field', className);
|
||||
const fieldProps: any = {};
|
||||
|
||||
@ -117,8 +160,8 @@ export class EntryField extends Component<EntryFieldProps> {
|
||||
<span className="engine-field-title" key="field-title">
|
||||
{title}
|
||||
</span>,
|
||||
renderTip(tip, { propName }),
|
||||
<Icons name="arrow" className="engine-field-arrow" size="12px" key="engine-field-arrow-icon" />,
|
||||
// renderTip(tip, { propName }),
|
||||
// <Icons name="arrow" className="engine-field-arrow" size="12px" key="engine-field-arrow-icon" />,
|
||||
];
|
||||
|
||||
return (
|
||||
@ -128,3 +171,14 @@ export class EntryField extends Component<EntryFieldProps> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class PlainField extends Component<FieldProps> {
|
||||
render() {
|
||||
const { className, children } = this.props;
|
||||
return (
|
||||
<div className={classNames(`lc-field lc-plain-field`, className)}>
|
||||
<div className="lc-field-body">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.lc-plain-field {
|
||||
// for top-level style
|
||||
padding: 8px 10px;
|
||||
> .lc-field-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.lc-inline-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
28
packages/plugin-settings-pane/src/field/index.ts
Normal file
28
packages/plugin-settings-pane/src/field/index.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { ReactNode, createElement } from 'react';
|
||||
import { TitleContent } from '@ali/lowcode-globals';
|
||||
import './index.less';
|
||||
import { Field, PopupField, EntryField, PlainField } from './fields';
|
||||
|
||||
export interface FieldProps {
|
||||
className?: string;
|
||||
title?: TitleContent | null;
|
||||
display?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry';
|
||||
collapsed?: boolean;
|
||||
onExpandChange?: (collapsed: boolean) => void;
|
||||
[extra: string]: any;
|
||||
}
|
||||
|
||||
export function createField(props: FieldProps, children: ReactNode, type?: 'accordion' | 'inline' | 'block' | 'plain' | 'popup' | 'entry') {
|
||||
if (type === 'popup') {
|
||||
return createElement(PopupField, props, children);
|
||||
}
|
||||
if (type === 'entry') {
|
||||
return createElement(EntryField, props, children);
|
||||
}
|
||||
if (type === 'plain' || !props.title) {
|
||||
return createElement(PlainField, props, children);
|
||||
}
|
||||
return createElement(Field, { ...props, defaultDisplay: type }, children);
|
||||
}
|
||||
|
||||
export { Field, PopupField, EntryField, PlainField };
|
||||
@ -1,65 +0,0 @@
|
||||
import { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Icon } from '@alifd/next';
|
||||
import { Title, TitleContent } from '@ali/lowcode-globals';
|
||||
import './index.less';
|
||||
import { CommonField, PopupField } from './fields';
|
||||
|
||||
export interface FieldProps {
|
||||
className?: string;
|
||||
// span
|
||||
title?: TitleContent | null;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class Field extends Component<FieldProps> {
|
||||
render() {
|
||||
const { type, ...rest } = this.props;
|
||||
if (type === 'popup') {
|
||||
return <PopupField {...rest} />;
|
||||
}
|
||||
return <CommonField {...rest} />;
|
||||
}
|
||||
}
|
||||
|
||||
export interface FieldGroupProps extends FieldProps {
|
||||
defaultCollapsed?: boolean;
|
||||
onExpandChange?: (collapsed: boolean) => void;
|
||||
}
|
||||
|
||||
export class FieldGroup extends Component<FieldGroupProps> {
|
||||
state = {
|
||||
collapsed: this.props.defaultCollapsed,
|
||||
};
|
||||
|
||||
toggleExpand() {
|
||||
const { onExpandChange } = this.props;
|
||||
const collapsed = !this.state.collapsed;
|
||||
this.setState({
|
||||
collapsed,
|
||||
});
|
||||
onExpandChange && onExpandChange(collapsed);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, children, title } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('lc-field lc-accordion-field', className, {
|
||||
'lc-field-is-collapsed': this.state.collapsed,
|
||||
})}
|
||||
>
|
||||
{title && (
|
||||
<div className="lc-field-head" onClick={this.toggleExpand.bind(this)}>
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
<Icon className="lc-field-icon" type="arrow-up" size="xs" />
|
||||
</div>
|
||||
)}
|
||||
<div className="lc-field-body">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
* 拖拽排序有问题
|
||||
* forceInline 有问题
|
||||
* 部分改变不响应
|
||||
* 样式还原
|
||||
* autofocus
|
||||
@ -133,7 +133,7 @@ export class ListSetter extends Component<ArraySetterProps, ArraySetterState> {
|
||||
render() {
|
||||
let columns: any = null;
|
||||
if (this.props.columns) {
|
||||
columns = this.props.columns.map((column) => <Title title={column.title || (column.name as string)} />);
|
||||
columns = this.props.columns.map((column) => <Title key={column.name} title={column.title || (column.name as string)} />);
|
||||
}
|
||||
|
||||
const { items } = this.state;
|
||||
|
||||
@ -75,6 +75,11 @@
|
||||
text-overflow: ellipsis;
|
||||
.lc-field {
|
||||
padding: 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
>.lc-field-body {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
> * {
|
||||
width: 100%;
|
||||
|
||||
@ -103,22 +103,6 @@ export default class MixedSetter extends Component<{
|
||||
});
|
||||
}
|
||||
|
||||
private checkIsBlockField() {
|
||||
if (this.shell) {
|
||||
const setter = this.shell.lastElementChild!.firstElementChild;
|
||||
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||
this.shell.classList.add('lc-block-setter');
|
||||
} else {
|
||||
this.shell.classList.remove('lc-block-field');
|
||||
}
|
||||
}
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
componentDidMount() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
|
||||
private useSetter: (id: string) => {
|
||||
const { field, onChange } = this.props;
|
||||
|
||||
@ -391,4 +391,47 @@ export class SettingPropEntry implements SettingTarget {
|
||||
onValueChange() {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.path.join('.');
|
||||
}
|
||||
|
||||
getKey() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/*
|
||||
getDefaultValue() {
|
||||
return this.extraProps.defaultValue;
|
||||
}
|
||||
|
||||
getConfig<K extends keyof IPropConfig>(configName?: K): IPropConfig[K] | IPropConfig {
|
||||
if (configName) {
|
||||
return this.config[configName];
|
||||
}
|
||||
|
||||
return this.config;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
isHidden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
isDisabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getSetter() {
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
isIgnore() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { TitleContent, computed, isDynamicSetter, SetterType, DynamicSetter, FieldExtraProps, FieldConfig, CustomView, isCustomView } from '@ali/lowcode-globals';
|
||||
import { TitleContent, computed, isDynamicSetter, SetterType, DynamicSetter, FieldExtraProps, FieldConfig, CustomView, isCustomView, obx } from '@ali/lowcode-globals';
|
||||
import { Transducer } from '../utils';
|
||||
import { SettingPropEntry } from './setting-entry';
|
||||
import { SettingTarget } from './setting-target';
|
||||
@ -26,9 +26,20 @@ export class SettingField extends SettingPropEntry implements SettingTarget {
|
||||
return this._setter;
|
||||
}
|
||||
|
||||
@obx.ref private _expanded = true;
|
||||
get expanded(): boolean {
|
||||
return this._expanded;
|
||||
}
|
||||
|
||||
setExpanded(value: boolean) {
|
||||
this._expanded = value;
|
||||
}
|
||||
|
||||
constructor(readonly parent: SettingTarget, config: FieldConfig) {
|
||||
super(parent, config.name, config.type);
|
||||
|
||||
console.info(config);
|
||||
|
||||
const { title, items, setter, extraProps, ...rest } = config;
|
||||
this._title = title;
|
||||
this._setter = setter;
|
||||
@ -37,6 +48,7 @@ export class SettingField extends SettingPropEntry implements SettingTarget {
|
||||
...extraProps,
|
||||
};
|
||||
this.isRequired = config.isRequired || (setter as any)?.isRequired;
|
||||
this._expanded = extraProps?.defaultCollapsed ? false : true;
|
||||
|
||||
// initial items
|
||||
if (this.type === 'group' && items) {
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
createSetterContent,
|
||||
observer,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { Field, FieldGroup } from '../field';
|
||||
import { Field, createField } from '../field';
|
||||
import PopupService from '../popup';
|
||||
import { SettingField, isSettingField } from './setting-field';
|
||||
import { SettingTarget } from './setting-target';
|
||||
@ -20,7 +20,7 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
const { field } = this.props;
|
||||
const { extraProps } = field;
|
||||
const { condition, defaultValue } = extraProps;
|
||||
const visible = field.isOneNode && typeof condition === 'function' ? !condition(field) : true;
|
||||
const visible = field.isOneNode && typeof condition === 'function' ? condition(field) !== false : true;
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
@ -62,28 +62,29 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: error handling
|
||||
|
||||
return (
|
||||
<Field title={extraProps.forceInline ? null : field.title}>
|
||||
{createSetterContent(setterType, {
|
||||
...shallowIntl(setterProps),
|
||||
forceInline: extraProps.forceInline,
|
||||
key: field.id,
|
||||
// === injection
|
||||
prop: field, // for compatible vision
|
||||
field,
|
||||
// === IO
|
||||
value, // reaction point
|
||||
onChange: (value: any) => {
|
||||
this.setState({
|
||||
value,
|
||||
});
|
||||
field.setValue(value);
|
||||
},
|
||||
})}
|
||||
</Field>
|
||||
);
|
||||
return createField({
|
||||
title: field.title,
|
||||
collapsed: !field.expanded,
|
||||
onExpandChange: (expandState) => field.setExpanded(expandState),
|
||||
}, createSetterContent(setterType, {
|
||||
...shallowIntl(setterProps),
|
||||
forceInline: extraProps.forceInline,
|
||||
key: field.id,
|
||||
// === injection
|
||||
prop: field, // for compatible vision
|
||||
field,
|
||||
// === IO
|
||||
value, // reaction point
|
||||
onChange: (value: any) => {
|
||||
this.setState({
|
||||
value,
|
||||
});
|
||||
field.setValue(value);
|
||||
},
|
||||
}), extraProps.forceInline ? 'plain' : extraProps.display);
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,17 +97,20 @@ class SettingGroupView extends Component<{ field: SettingField }> {
|
||||
render() {
|
||||
const { field } = this.props;
|
||||
const { extraProps } = field;
|
||||
const { condition, defaultCollapsed } = extraProps;
|
||||
const visible = field.isOneNode && typeof condition === 'function' ? !condition(field) : true;
|
||||
const { condition } = extraProps;
|
||||
const visible = field.isOneNode && typeof condition === 'function' ? condition(field) !== false : true;
|
||||
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// todo: split collapsed state | field.items for optimize
|
||||
return (
|
||||
<FieldGroup title={field.title} defaultCollapsed={defaultCollapsed}>
|
||||
<Field defaultDisplay="accordion" title={field.title} collapsed={!field.expanded} onExpandChange={(expandState) => {
|
||||
field.setExpanded(expandState);
|
||||
}}>
|
||||
{field.items.map((item, index) => createSettingFieldView(item, field, index))}
|
||||
</FieldGroup>
|
||||
</Field>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,10 +54,6 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.lc-settings-pane {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
// ====== reset fusion-tabs =====
|
||||
.lc-settings-tabs {
|
||||
position: relative;
|
||||
@ -114,6 +110,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.lc-settings-pane {
|
||||
padding-bottom: 50px;
|
||||
.next-btn {
|
||||
line-height: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
html.lc-cursor-dragging:not(.lowcode-has-fixed-tree) {
|
||||
.lc-settings-main .lc-outline-pane {
|
||||
display: block;
|
||||
|
||||
@ -102,11 +102,12 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
|
||||
title: 'Ref',
|
||||
setter: 'StringSetter',
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: '!more',
|
||||
title: '更多',
|
||||
setter: 'PropertiesSetter',
|
||||
},
|
||||
},*/
|
||||
],
|
||||
});
|
||||
const combined: FieldConfig[] = [
|
||||
@ -168,11 +169,13 @@ export default function(metadata: TransformedComponentMetadata): TransformedComp
|
||||
}
|
||||
|
||||
if (isRoot) {
|
||||
/*
|
||||
combined.push({
|
||||
name: '#advanced',
|
||||
title: { type: 'i18n', 'zh-CN': '高级', 'en-US': 'Advance' },
|
||||
items: [],
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
combined.push({
|
||||
name: '#advanced',
|
||||
|
||||
@ -216,7 +216,7 @@ export function upgradePropConfig(config: OldPropConfig) {
|
||||
if (tip) {
|
||||
if (typeof title !== 'object' || isI18nData(title) || isValidElement(title)) {
|
||||
newConfig.title = {
|
||||
title,
|
||||
label: title,
|
||||
tip: tip.content,
|
||||
docUrl: tip.url
|
||||
};
|
||||
@ -615,7 +615,9 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
|
||||
experimental.callbacks = callbacks;
|
||||
|
||||
const props = upgradeConfigure(configure || []);
|
||||
meta.configure = { props, component };
|
||||
const events = {};
|
||||
const styles = {};
|
||||
meta.configure = { props, component, events, styles };
|
||||
meta.experimental = experimental;
|
||||
return meta;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ async function load() {
|
||||
|
||||
const externals = ['react', 'react-dom', 'prop-types', 'react-router', 'react-router-dom', '@ali/recore'];
|
||||
async function loadAssets() {
|
||||
const assets = await editor.utils.get('./assets.json');
|
||||
const assets = await editor.utils.get('./legao-assets.json');
|
||||
|
||||
if (assets.packages) {
|
||||
assets.packages.forEach((item: any) => {
|
||||
|
||||
@ -11,7 +11,7 @@ html.engine-cursor-ew-resize, html.engine-cursor-ew-resize * {
|
||||
}
|
||||
|
||||
body, #engine {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user