diff --git a/packages/globals/src/types/field-config.ts b/packages/globals/src/types/field-config.ts index be65dd64b..21ace1a20 100644 --- a/packages/globals/src/types/field-config.ts +++ b/packages/globals/src/types/field-config.ts @@ -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 { diff --git a/packages/plugin-settings-pane/src/field/fields.tsx b/packages/plugin-settings-pane/src/field/fields.tsx index 5bbc0116c..28258335e 100644 --- a/packages/plugin-settings-pane/src/field/fields.tsx +++ b/packages/plugin-settings-pane/src/field/fields.tsx @@ -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 { - private shell: HTMLDivElement | null = null; +export class Field extends Component { + 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 ( -
(this.shell = shell)} className={classNames('lc-field lc-inline-field', className)}> - {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> + ); + } +} diff --git a/packages/plugin-settings-pane/src/field/index.less b/packages/plugin-settings-pane/src/field/index.less index b6235aa0e..fefda56e6 100644 --- a/packages/plugin-settings-pane/src/field/index.less +++ b/packages/plugin-settings-pane/src/field/index.less @@ -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; diff --git a/packages/plugin-settings-pane/src/field/index.ts b/packages/plugin-settings-pane/src/field/index.ts new file mode 100644 index 000000000..2f50d53ff --- /dev/null +++ b/packages/plugin-settings-pane/src/field/index.ts @@ -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 }; diff --git a/packages/plugin-settings-pane/src/field/index.tsx b/packages/plugin-settings-pane/src/field/index.tsx deleted file mode 100644 index 0ca843e51..000000000 --- a/packages/plugin-settings-pane/src/field/index.tsx +++ /dev/null @@ -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> - ); - } -} diff --git a/packages/plugin-settings-pane/src/setters/array-setter/bugs.md b/packages/plugin-settings-pane/src/setters/array-setter/bugs.md new file mode 100644 index 000000000..8fe96cc16 --- /dev/null +++ b/packages/plugin-settings-pane/src/setters/array-setter/bugs.md @@ -0,0 +1,5 @@ +* 拖拽排序有问题 +* forceInline 有问题 +* 部分改变不响应 +* 样式还原 +* autofocus diff --git a/packages/plugin-settings-pane/src/setters/array-setter/index.tsx b/packages/plugin-settings-pane/src/setters/array-setter/index.tsx index 8a47655b5..19323d050 100644 --- a/packages/plugin-settings-pane/src/setters/array-setter/index.tsx +++ b/packages/plugin-settings-pane/src/setters/array-setter/index.tsx @@ -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; diff --git a/packages/plugin-settings-pane/src/setters/array-setter/style.less b/packages/plugin-settings-pane/src/setters/array-setter/style.less index 407ed8041..8e0da024b 100644 --- a/packages/plugin-settings-pane/src/setters/array-setter/style.less +++ b/packages/plugin-settings-pane/src/setters/array-setter/style.less @@ -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%; diff --git a/packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx b/packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx index 0f0e90d48..6eb0dabc5 100644 --- a/packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx +++ b/packages/plugin-settings-pane/src/setters/mixed-setter/index.tsx @@ -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; diff --git a/packages/plugin-settings-pane/src/settings/setting-entry.ts b/packages/plugin-settings-pane/src/settings/setting-entry.ts index cf4cc1831..cd70724db 100644 --- a/packages/plugin-settings-pane/src/settings/setting-entry.ts +++ b/packages/plugin-settings-pane/src/settings/setting-entry.ts @@ -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; + } } diff --git a/packages/plugin-settings-pane/src/settings/setting-field.ts b/packages/plugin-settings-pane/src/settings/setting-field.ts index 5194576d6..2e6dfde28 100644 --- a/packages/plugin-settings-pane/src/settings/setting-field.ts +++ b/packages/plugin-settings-pane/src/settings/setting-field.ts @@ -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) { diff --git a/packages/plugin-settings-pane/src/settings/settings-pane.tsx b/packages/plugin-settings-pane/src/settings/settings-pane.tsx index 949dbd699..4040468bd 100644 --- a/packages/plugin-settings-pane/src/settings/settings-pane.tsx +++ b/packages/plugin-settings-pane/src/settings/settings-pane.tsx @@ -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> ); } } diff --git a/packages/plugin-settings-pane/src/style.less b/packages/plugin-settings-pane/src/style.less index ccc6c34fb..9b2c2b403 100644 --- a/packages/plugin-settings-pane/src/style.less +++ b/packages/plugin-settings-pane/src/style.less @@ -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; diff --git a/packages/plugin-settings-pane/src/transducers/addon-combine.ts b/packages/plugin-settings-pane/src/transducers/addon-combine.ts index 8650bcafc..4f6b3e42d 100644 --- a/packages/plugin-settings-pane/src/transducers/addon-combine.ts +++ b/packages/plugin-settings-pane/src/transducers/addon-combine.ts @@ -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', diff --git a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts index bf742c542..ce50f37ed 100644 --- a/packages/vision-polyfill/src/bundle/upgrade-metadata.ts +++ b/packages/vision-polyfill/src/bundle/upgrade-metadata.ts @@ -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; } diff --git a/packages/vision-polyfill/src/demo/index.ts b/packages/vision-polyfill/src/demo/index.ts index 45a56728f..fca8c9a03 100644 --- a/packages/vision-polyfill/src/demo/index.ts +++ b/packages/vision-polyfill/src/demo/index.ts @@ -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) => { diff --git a/packages/vision-polyfill/src/vision.less b/packages/vision-polyfill/src/vision.less index 495668ce8..bc70869fa 100644 --- a/packages/vision-polyfill/src/vision.less +++ b/packages/vision-polyfill/src/vision.less @@ -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;