From 16713f4b848f3648fa93c82d70007fbec4e8a816 Mon Sep 17 00:00:00 2001 From: liujuping Date: Sun, 17 Dec 2023 16:37:17 +0800 Subject: [PATCH] feat(skeleton): Add TS defs for modules & optimize Tabs display with array contents --- .../src/components/widget-views/index.tsx | 23 ++++++++--- .../src/layouts/left-fixed-pane.tsx | 7 ++-- .../src/layouts/left-float-pane.tsx | 5 +-- packages/editor-skeleton/src/skeleton.ts | 38 +++++++++---------- packages/editor-skeleton/src/types.ts | 33 +++------------- packages/editor-skeleton/src/widget/panel.ts | 15 +++----- .../src/shell/type/widget-base-config.ts | 27 ++++++++++++- 7 files changed, 78 insertions(+), 70 deletions(-) diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx index ba49b3d1a..2b2f6931c 100644 --- a/packages/editor-skeleton/src/components/widget-views/index.tsx +++ b/packages/editor-skeleton/src/components/widget-views/index.tsx @@ -266,15 +266,28 @@ export class PanelView extends Component<{ } @observer -export class TabsPanelView extends Component<{ container: WidgetContainer }> { +export class TabsPanelView extends Component<{ + container: WidgetContainer; + // shouldHideSingleTab: 一个布尔值,用于控制当 Tabs 组件只有一个标签时是否隐藏该标签。 + shouldHideSingleTab?: boolean; +}> { render() { const { container } = this.props; const titles: ReactElement[] = []; const contents: ReactElement[] = []; - container.items.forEach((item: any) => { - titles.push(); - contents.push(); - }); + // 如果只有一个标签且 shouldHideSingleTab 为 true,则不显示 Tabs + if (this.props.shouldHideSingleTab && container.items.length === 1) { + contents.push(); + } else { + container.items.forEach((item: any) => { + titles.push(); + contents.push(); + }); + } + + if (!titles.length) { + return contents; + } return (
diff --git a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx index cda600f74..a56b44907 100644 --- a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx @@ -2,17 +2,16 @@ import { Component, Fragment } from 'react'; import classNames from 'classnames'; import { observer } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; -import { PanelConfig } from '../types'; import { Panel } from '../widget/panel'; +import { IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFixedPane extends Component<{ area: Area }> { +export default class LeftFixedPane extends Component<{ area: Area }> { componentDidUpdate() { // FIXME: dirty fix, need deep think this.props.area.skeleton.editor.get('designer')?.touchOffsetObserver(); } - render() { const { area } = this.props; const width = area.current?.config.props?.width; @@ -36,7 +35,7 @@ export default class LeftFixedPane extends Component<{ area: Area }> { +class Contents extends Component<{ area: Area }> { render() { const { area } = this.props; return {area.container.items.map((panel) => panel.content)}; diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx index 15f492619..296f08321 100644 --- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx +++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx @@ -3,11 +3,10 @@ import classNames from 'classnames'; import { observer, Focusable } from '@alilc/lowcode-editor-core'; import { Area } from '../area'; import { Panel } from '../widget/panel'; -import { PanelConfig } from '../types'; -import { IPublicApiProject } from '@alilc/lowcode-types'; +import { IPublicApiProject, IPublicTypePanelConfig } from '@alilc/lowcode-types'; @observer -export default class LeftFloatPane extends Component<{ area: Area }> { +export default class LeftFloatPane extends Component<{ area: Area }> { private dispose?: () => void; private focusing?: Focusable; diff --git a/packages/editor-skeleton/src/skeleton.ts b/packages/editor-skeleton/src/skeleton.ts index 13967e94d..7ff462391 100644 --- a/packages/editor-skeleton/src/skeleton.ts +++ b/packages/editor-skeleton/src/skeleton.ts @@ -1,7 +1,6 @@ import { action, makeObservable, obx, engineConfig, IEditor, FocusTracker } from '@alilc/lowcode-editor-core'; import { DockConfig, - PanelConfig, WidgetConfig, PanelDockConfig, DialogDockConfig, @@ -29,6 +28,7 @@ import { IPublicTypeSkeletonConfig, IPublicApiSkeleton, IPublicTypeConfigTransducer, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; const logger = new Logger({ level: 'warn', bizName: 'skeleton' }); @@ -70,15 +70,15 @@ export interface ISkeleton extends Omit; - readonly leftFixedArea: Area; + readonly leftFixedArea: Area; - readonly leftFloatArea: Area; + readonly leftFloatArea: Area; - readonly rightArea: Area; + readonly rightArea: Area; - readonly mainArea: Area; + readonly mainArea: Area; - readonly bottomArea: Area; + readonly bottomArea: Area; readonly stages: Area; @@ -104,7 +104,7 @@ export interface ISkeleton extends Omit): IWidget | Widget | Panel | Stage | Dock | PanelDock | undefined; } @@ -124,15 +124,15 @@ export class Skeleton implements ISkeleton { readonly toolbar: Area; - readonly leftFixedArea: Area; + readonly leftFixedArea: Area; - readonly leftFloatArea: Area; + readonly leftFloatArea: Area; - readonly rightArea: Area; + readonly rightArea: Area; - @obx readonly mainArea: Area; + @obx readonly mainArea: Area; - readonly bottomArea: Area; + readonly bottomArea: Area; readonly stages: Area; @@ -388,9 +388,9 @@ export class Skeleton implements ISkeleton { return this.widgets.find(widget => widget.name === name); } - createPanel(config: PanelConfig) { + createPanel(config: IPublicTypePanelConfig) { const parsedConfig = this.parseConfig(config); - const panel = new Panel(this, parsedConfig as PanelConfig); + const panel = new Panel(this, parsedConfig as IPublicTypePanelConfig); this.panels.set(panel.name, panel); logger.debug(`Panel created with name: ${panel.name} \nconfig:`, config, '\n current panels: ', this.panels); return panel; @@ -496,7 +496,7 @@ export class Skeleton implements ISkeleton { return this.leftArea.add(parsedConfig as PanelDockConfig); case 'rightArea': case 'right': - return this.rightArea.add(parsedConfig as PanelConfig); + return this.rightArea.add(parsedConfig as IPublicTypePanelConfig); case 'topArea': case 'top': return this.topArea.add(parsedConfig as PanelDockConfig); @@ -508,14 +508,14 @@ export class Skeleton implements ISkeleton { case 'main': case 'center': case 'centerArea': - return this.mainArea.add(parsedConfig as PanelConfig); + return this.mainArea.add(parsedConfig as IPublicTypePanelConfig); case 'bottomArea': case 'bottom': - return this.bottomArea.add(parsedConfig as PanelConfig); + return this.bottomArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFixedArea': - return this.leftFixedArea.add(parsedConfig as PanelConfig); + return this.leftFixedArea.add(parsedConfig as IPublicTypePanelConfig); case 'leftFloatArea': - return this.leftFloatArea.add(parsedConfig as PanelConfig); + return this.leftFloatArea.add(parsedConfig as IPublicTypePanelConfig); case 'stages': return this.stages.add(parsedConfig as StageConfig); default: diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts index b73dc4adc..8c5f1484a 100644 --- a/packages/editor-skeleton/src/types.ts +++ b/packages/editor-skeleton/src/types.ts @@ -1,11 +1,11 @@ import { ReactElement, ComponentType } from 'react'; import { IPublicTypeTitleContent, - IPublicTypeI18nData, IPublicTypeWidgetConfigArea, IPublicTypeWidgetBaseConfig, - IPublicTypePanelDockPanelProps, IPublicTypePanelDockProps, + IPublicTypePanelConfigProps, + IPublicTypePanelConfig, } from '@alilc/lowcode-types'; import { IWidget } from './widget/widget'; @@ -66,40 +66,17 @@ export function isDialogDockConfig(obj: any): obj is DialogDockConfig { return obj && obj.type === 'DialogDock'; } -// 窗格扩展 -export interface PanelConfig extends IPublicTypeWidgetBaseConfig { - type: 'Panel'; - content?: string | ReactElement | ComponentType | PanelConfig[]; // as children - props?: PanelProps; -} - -export function isPanelConfig(obj: any): obj is PanelConfig { +export function isPanelConfig(obj: any): obj is IPublicTypePanelConfig { return obj && obj.type === 'Panel'; } -export type HelpTipConfig = string | { url?: string; content?: string | ReactElement }; - -export interface PanelProps extends IPublicTypePanelDockPanelProps { - title?: IPublicTypeTitleContent; - icon?: any; // 冗余字段 - description?: string | IPublicTypeI18nData; - help?: HelpTipConfig; // 显示问号帮助 - hiddenWhenInit?: boolean; // when this is true, by default will be hidden - condition?: (widget: IWidget) => any; - onInit?: (widget: IWidget) => any; - onDestroy?: () => any; - shortcut?: string; // 只有在特定位置,可触发 toggle show - enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 - keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 -} - export interface PanelDockConfig extends IDockBaseConfig { type: 'PanelDock'; panelName?: string; - panelProps?: PanelProps & { + panelProps?: IPublicTypePanelConfigProps & { area?: IPublicTypeWidgetConfigArea; }; - content?: string | ReactElement | ComponentType | PanelConfig[]; // content for pane + content?: string | ReactElement | ComponentType | IPublicTypePanelConfig[]; // content for pane } export function isPanelDockConfig(obj: any): obj is PanelDockConfig { diff --git a/packages/editor-skeleton/src/widget/panel.ts b/packages/editor-skeleton/src/widget/panel.ts index b35af6a21..3a1ce3b00 100644 --- a/packages/editor-skeleton/src/widget/panel.ts +++ b/packages/editor-skeleton/src/widget/panel.ts @@ -1,10 +1,9 @@ import { createElement, ReactNode } from 'react'; import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core'; import { uniqueId, createContent } from '@alilc/lowcode-utils'; -import { IPublicTypeTitleContent } from '@alilc/lowcode-types'; +import { IPublicTypeHelpTipConfig, IPublicTypePanelConfig, IPublicTypeTitleContent } from '@alilc/lowcode-types'; import { WidgetContainer } from './widget-container'; import { getEvent } from '@alilc/lowcode-shell'; -import { PanelConfig, HelpTipConfig } from '../types'; import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views'; import { ISkeleton } from '../skeleton'; import { composeTitle } from './utils'; @@ -45,6 +44,7 @@ export class Panel implements IWidget { if (this.container) { return createElement(TabsPanelView, { container: this.container, + shouldHideSingleTab: true, }); } @@ -72,15 +72,15 @@ export class Panel implements IWidget { readonly title: IPublicTypeTitleContent; - readonly help?: HelpTipConfig; + readonly help?: IPublicTypeHelpTipConfig; private plain = false; - private container?: WidgetContainer; + private container?: WidgetContainer; @obx.ref public parent?: WidgetContainer; - constructor(readonly skeleton: ISkeleton, readonly config: PanelConfig) { + constructor(readonly skeleton: ISkeleton, readonly config: IPublicTypePanelConfig) { makeObservable(this); const { name, content, props = {} } = config; const { hideTitleBar, title, icon, description, help } = props; @@ -90,9 +90,6 @@ export class Panel implements IWidget { this.plain = hideTitleBar || !title; this.help = help; if (Array.isArray(content)) { - if (content.length === 1) { - // todo: not show tabs - } this.container = this.skeleton.createContainer( name, (item) => { @@ -127,7 +124,7 @@ export class Panel implements IWidget { this.parent = parent; } - add(item: Panel | PanelConfig) { + add(item: Panel | IPublicTypePanelConfig) { return this.container?.add(item); } diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts index b23ba0f13..2764ce192 100644 --- a/packages/types/src/shell/type/widget-base-config.ts +++ b/packages/types/src/shell/type/widget-base-config.ts @@ -1,4 +1,27 @@ -import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; +import { ReactElement, ComponentType } from 'react'; +import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './'; + +export type IPublicTypeHelpTipConfig = string | { url?: string; content?: string | ReactElement }; + +export interface IPublicTypePanelConfigProps extends IPublicTypePanelDockPanelProps { + title?: IPublicTypeTitleContent; + icon?: any; // 冗余字段 + description?: string | IPublicTypeI18nData; + help?: IPublicTypeHelpTipConfig; // 显示问号帮助 + hiddenWhenInit?: boolean; // when this is true, by default will be hidden + condition?: (widget: any) => any; + onInit?: (widget: any) => any; + onDestroy?: () => any; + shortcut?: string; // 只有在特定位置,可触发 toggle show + enableDrag?: boolean; // 是否开启通过 drag 调整 宽度 + keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态 +} + +export interface IPublicTypePanelConfig extends IPublicTypeWidgetBaseConfig { + type: 'Panel'; + content?: string | ReactElement | ComponentType | IPublicTypePanelConfig[]; // as children + props?: IPublicTypePanelConfigProps; +} export interface IPublicTypeWidgetBaseConfig { [extra: string]: any; @@ -13,7 +36,7 @@ export interface IPublicTypeWidgetBaseConfig { */ area?: IPublicTypeWidgetConfigArea; props?: Record; - content?: any; + content?: string | ReactElement | ComponentType | IPublicTypePanelConfig[]; contentProps?: Record; /**