From f04204162ee4ca962d19ce1e1309c1f59ee0e606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E7=9F=97?= Date: Tue, 5 May 2020 14:32:27 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E6=97=A7=E7=9A=84?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=97=A0=E6=B3=95=E7=BB=A7=E7=BB=AD=E6=B2=BF?= =?UTF-8?q?=E7=94=A8,=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 有一个icon还没处理晚点加上 --- .../vision-preset/src/components/index.less | 82 ++++++++++++++++ .../vision-preset/src/components/index.tsx | 95 +++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 packages/vision-preset/src/components/index.less create mode 100644 packages/vision-preset/src/components/index.tsx diff --git a/packages/vision-preset/src/components/index.less b/packages/vision-preset/src/components/index.less new file mode 100644 index 000000000..c630e0914 --- /dev/null +++ b/packages/vision-preset/src/components/index.less @@ -0,0 +1,82 @@ +@import '~@ali/ve-less-variables/index.less'; + +// 样式直接沿用之前的样式,优化了下命名 +.instance-node-selector { + position: relative; + margin-right: 2px; + color: var(--color-icon-white, @title-bgcolor); + border-radius: @global-border-radius; + margin-right: 2px; + pointer-events: auto; + flex-grow: 0; + flex-shrink: 0; + + svg { + width: 16px; + height: 16px; + margin-right: 5px; + flex-grow: 0; + flex-shrink: 0; + max-width: inherit; + path { + fill: var(--color-icon-white, @title-bgcolor); + } + } + &-current { + background: var(--color-brand, @brand-color-1); + padding: 0 6px; + display: flex; + align-items: center; + height: 20px; + cursor: pointer; + color: var(--color-icon-white, @title-bgcolor); + border-radius: 3px; + + &-title { + padding-right: 6px; + color: var(--color-icon-white, @title-bgcolor); + } + } + &-list { + position: absolute; + left: 0; + right: 0; + opacity: 0; + visibility: hidden; + } + &-node { + margin: 2px 0; + &-content { + padding-left: 6px; + background: #78869a; + display: inline-flex; + border-radius: 3px; + align-items: center; + height: 20px; + color: var(--color-icon-white, @title-bgcolor); + cursor: pointer; + overflow: visible; + } + &-title { + padding-right: 6px; + // margin-left: 5px; + color: var(--color-icon-white, @title-bgcolor); + cursor: pointer; + overflow: visible; + } + &:hover { + opacity: 0.8; + } + } +} + +&:hover { + .instance-node-selector-current { + color: ar(--color-text-reverse, @white-alpha-2); + } + .instance-node-selector-popup { + visibility: visible; + opacity: 1; + transition: 0.2s all ease-in; + } +} diff --git a/packages/vision-preset/src/components/index.tsx b/packages/vision-preset/src/components/index.tsx new file mode 100644 index 000000000..2518705aa --- /dev/null +++ b/packages/vision-preset/src/components/index.tsx @@ -0,0 +1,95 @@ +import { Overlay } from '@alifd/next'; +import React from 'react'; +import './index.less'; +import { Title } from '@ali/lowcode-editor-core'; + +import { Node, ParentalNode } from '@ali/lowcode-designer'; + +const { Popup } = Overlay; + +export interface IProps { + node: Node; +} + +export interface IState { + parentNodes: Node[]; +} + +type UnionNode = Node | ParentalNode | null; + +export class InstanceNodeSelector extends React.Component { + state: IState = { + parentNodes: [], + }; + + componentDidMount() { + const parentNodes = this.getParentNodes(this.props.node); + this.setState({ + parentNodes, + }); + } + + // 获取节点的父级节点(最多获取5层) + getParentNodes = (node: Node) => { + const parentNodes = []; + let currentNode: UnionNode = node; + + while (currentNode && parentNodes.length < 5) { + currentNode = currentNode.getParent(); + if (currentNode) { + parentNodes.push(currentNode); + } + } + return parentNodes; + }; + + onSelect = (node: Node) => () => { + if (node && typeof node.select === 'function') { + node.select(); + } + }; + + renderNodes = (node: Node) => { + const nodes = this.state.parentNodes || []; + const children = nodes.map((node, key) => { + return ( +
+
+ + </div> + </div> + ); + }); + return children; + }; + + render() { + const { node } = this.props; + return ( + <div className="instance-node-selector"> + <Popup + trigger={ + <div className="instance-node-selector-current"> + <Title + className="instance-node-selector-node-title" + title={{ + label: node.title, + icon: node.icon, + }} + /> + </div> + } + triggerType="hover" + > + <div className="instance-node-selector">{this.renderNodes(node)}</div> + </Popup> + </div> + ); + } +} From f1a082369d1f5b1e44eb7dc90aa397b8e1cb176e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E7=9F=97?= <fengchu.yangfengch@alibaba-inc.com> Date: Tue, 5 May 2020 14:33:07 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=A2=9E=E5=8A=A0ic?= =?UTF-8?q?on=E8=8E=B7=E5=8F=96api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/designer/src/document/node/node.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9f19ce0eb..074718dee 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -7,6 +7,7 @@ import { PropsList, NodeData, TitleContent, + I18nData, SlotSchema, PageSchema, ComponentSchema, @@ -19,6 +20,7 @@ import { Prop } from './props/prop'; import { ComponentMeta } from '../../component-meta'; import { ExclusiveGroup, isExclusiveGroup } from './exclusive-group'; import { TransformStage } from './transform-stage'; +import { ReactElement } from 'react'; /** * 基础节点 @@ -122,7 +124,7 @@ export class Node<Schema extends NodeSchema = NodeSchema> { return 0; } - @computed get title(): TitleContent { + @computed get title(): string | I18nData | ReactElement { let t = this.getExtraProp('title'); if (!t && this.componentMeta.descriptor) { t = this.getProp(this.componentMeta.descriptor, false); @@ -136,6 +138,10 @@ export class Node<Schema extends NodeSchema = NodeSchema> { return this.componentMeta.title; } + get icon() { + return this.componentMeta.icon; + } + constructor(readonly document: DocumentModel, nodeSchema: Schema) { const { componentName, id, children, props, ...extras } = nodeSchema; this.id = id || `node$${document.nextId()}`; From e945d79364749036a1b266664b43dd3daaf14636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E7=9F=97?= <fengchu.yangfengch@alibaba-inc.com> Date: Tue, 5 May 2020 14:34:17 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vision-preset/src/editor.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/vision-preset/src/editor.ts b/packages/vision-preset/src/editor.ts index 2c965991e..a317b9fff 100644 --- a/packages/vision-preset/src/editor.ts +++ b/packages/vision-preset/src/editor.ts @@ -1,7 +1,7 @@ import { isJSBlock } from '@ali/lowcode-types'; import { isPlainObject } from '@ali/lowcode-utils'; import { globalContext, Editor } from '@ali/lowcode-editor-core'; -import { Designer, TransformStage } from '@ali/lowcode-designer'; +import { Designer, TransformStage, addBuiltinComponentAction } from '@ali/lowcode-designer'; import { registerSetters } from '@ali/lowcode-setters'; import Outline from '@ali/lowcode-plugin-outline-pane'; import DesignerPlugin from '@ali/lowcode-plugin-designer'; @@ -10,6 +10,8 @@ import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton'; import Preview from '@ali/lowcode-plugin-sample-preview'; import SourceEditor from '@ali/lowcode-plugin-source-editor'; import { i18nReducer } from './i18n-reducer'; +import { InstanceNodeSelector } from './components'; +import { Divider } from '@alifd/next'; registerSetters(); @@ -114,3 +116,10 @@ skeleton.add({ // }, // content: SourceEditor, // }); + +// 实例节点选择器,线框高亮 +addBuiltinComponentAction({ + name: 'instance-node-selector', + content: InstanceNodeSelector, + important: true, +}); From 89064f5c299923122479986e765572dcbaa8599a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E7=9F=97?= <fengchu.yangfengch@alibaba-inc.com> Date: Tue, 5 May 2020 14:35:22 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20=E5=A2=9E=E5=8A=A0ic?= =?UTF-8?q?on=E7=9B=B8=E5=85=B3=E7=9A=84=E5=88=A4=E6=96=AD=E5=87=BD?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 康师傅后期会改造这块,临时方案。 --- packages/types/src/title.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/types/src/title.ts b/packages/types/src/title.ts index 3be21d84e..658ddf73a 100644 --- a/packages/types/src/title.ts +++ b/packages/types/src/title.ts @@ -13,3 +13,6 @@ export interface TitleConfig { export type TitleContent = string | I18nData | ReactElement | TitleConfig; +export function isTitleConfig(obj: any): obj is TitleConfig { + return obj && (obj.label || obj.tip || obj.icon); +} From 2f9bb2567cd70670d53fde52b2f8aca605445cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E7=9F=97?= <fengchu.yangfengch@alibaba-inc.com> Date: Tue, 5 May 2020 14:38:19 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=F0=9F=90=9B=20title=E7=BC=BA?= =?UTF-8?q?=E5=B0=91icon=E5=AD=97=E6=AE=B5=EF=BC=8C=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E8=BD=AC=E6=8E=A5=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 需要后续相关同学增加api,已经标注 --- packages/designer/src/component-meta.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 1954f6091..0de4a9224 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -7,6 +7,8 @@ import { TitleContent, TransformedComponentMetadata, NestingFilter, + isTitleConfig, + I18nData, } from '@ali/lowcode-types'; import { computed } from '@ali/lowcode-editor-core'; import { Node, ParentalNode } from './document'; @@ -17,6 +19,7 @@ import { IconPage } from './icons/page'; import { IconComponent } from './icons/component'; import { IconRemove } from './icons/remove'; import { IconClone } from './icons/clone'; +import { ReactElement } from 'react'; function ensureAList(list?: string | string[]): string[] | null { if (!list) { @@ -91,12 +94,20 @@ export class ComponentMeta { private childWhitelist?: NestingFilter | null; private _title?: TitleContent; - get title() { + get title(): string | I18nData | ReactElement { + // TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。 + // string | i18nData | ReactElement + // TitleConfig title.label + if (isTitleConfig(this._title)) { + return (this._title.label as any) || this.componentName; + } return this._title || this.componentName; } @computed get icon() { + // TODO: 标记下。这块需要康师傅加一下API,页面正常渲染。 // give Slot default icon + // if _title is TitleConfig get _title.icon return ( this._transformedMetadata?.icon || (this.componentName === 'Page' ? IconPage : this.isContainer ? IconContainer : IconComponent) @@ -131,10 +142,10 @@ export class ComponentMeta { this._title = typeof title === 'string' ? { - type: 'i18n', - 'en-US': this.componentName, - 'zh-CN': title, - } + type: 'i18n', + 'en-US': this.componentName, + 'zh-CN': title, + } : title; } From 7e70a2b3580e0387fb643dba4c92b579189df55c Mon Sep 17 00:00:00 2001 From: "mario.gk" <mario.gk@alibaba-inc.com> Date: Tue, 5 May 2020 14:54:09 +0800 Subject: [PATCH 6/6] =?UTF-8?q?pages=20componentsTree=20=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/vision-preset/src/pages.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vision-preset/src/pages.ts b/packages/vision-preset/src/pages.ts index 81430a4f1..ff17f214c 100644 --- a/packages/vision-preset/src/pages.ts +++ b/packages/vision-preset/src/pages.ts @@ -15,8 +15,8 @@ const pages = Object.assign(project, { project.load({ version: '1.0.0', componentsMap: [], - componentsTree: pages.map(page => page.layout), - }); + componentsTree: pages[0].componentsTree, + }, true); }, addPage(data: OldPageData) { return project.open(data.layout);