From 0c81d96bf1c685f98ab7613b307ac911b0ad03fb Mon Sep 17 00:00:00 2001 From: kangwei Date: Sat, 16 May 2020 20:27:13 +0800 Subject: [PATCH] fix reducers --- .../bem-tools/drag-resize-engine.ts | 30 ++++++++++---- .../designer/src/builtin-simulator/host.ts | 3 ++ .../live-editing/live-editing.ts | 8 +++- packages/designer/src/component-meta.ts | 6 +-- .../designer/src/designer/builtin-hotkey.ts | 2 +- packages/designer/src/designer/dragon.ts | 5 --- .../designer/src/document/document-model.ts | 2 +- packages/designer/src/document/node/node.ts | 8 ++-- .../designer/src/document/node/props/prop.ts | 27 ++++++++++++- .../src/document/node/transform-stage.ts | 3 +- .../settings/settings-primary-pane.tsx | 40 ++++++++++++++----- .../plugin-outline-pane/src/views/tree.tsx | 5 ++- .../src/renderer.less | 9 +++++ .../src/bundle/upgrade-metadata.ts | 4 +- packages/vision-preset/src/editor.ts | 35 +++++++++++----- packages/vision-preset/src/i18n-reducer.ts | 9 ++++- packages/vision-preset/src/index.ts | 5 +-- packages/vision-preset/src/project.ts | 2 +- packages/vision-preset/src/vc-live-editing.ts | 11 ++++- 19 files changed, 158 insertions(+), 56 deletions(-) diff --git a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts index 11308316e..895084878 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts +++ b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts @@ -1,6 +1,6 @@ -import * as EventEmitter from 'events'; -import { ISimulatorHost, isSimulatorHost } from '../../../../designer/src/simulator'; -import { Designer } from '../../../../designer/src/designer/designer'; +import { EventEmitter } from 'events'; +import { ISimulatorHost, isSimulatorHost } from '../../simulator'; +import { Designer, Point } from '../../designer'; import { setNativeSelection, cursor } from '@ali/lowcode-utils'; // import Cursor from './cursor'; // import Pages from './pages'; @@ -66,21 +66,37 @@ export default class DragResizeEngine { */ from(shell: Element, direction: string, boost: (e: MouseEvent) => any) { let node: any; - let startEvent: MouseEvent; + let startEvent: Point; if (!shell) { return () => {}; } const move = (e: MouseEvent) => { - const moveX = e.clientX - startEvent.clientX; - const moveY = e.clientY - startEvent.clientY; + const x = createResizeEvent(e); + const moveX = x.clientX - startEvent.clientX; + const moveY = x.clientY - startEvent.clientY; this.emitter.emit('resize', e, direction, node, moveX, moveY); }; const masterSensors = this.getMasterSensors(); + const createResizeEvent = (e: MouseEvent | DragEvent): Point => { + const evt: any = {}; + + const sourceDocument = e.view?.document; + + if (!sourceDocument || sourceDocument === document) { + return e; + } + const srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument); + if (srcSim) { + return srcSim.viewport.toGlobalPoint(e); + } + return e; + }; + const over = (e: MouseEvent) => { const handleEvents = makeEventsHandler(e, masterSensors); handleEvents((doc) => { @@ -96,7 +112,7 @@ export default class DragResizeEngine { const mousedown = (e: MouseEvent) => { node = boost(e); - startEvent = e; + startEvent = createResizeEvent(e); const handleEvents = makeEventsHandler(e, masterSensors); handleEvents((doc) => { doc.addEventListener('mousemove', move, true); diff --git a/packages/designer/src/builtin-simulator/host.ts b/packages/designer/src/builtin-simulator/host.ts index 04aad80ad..e216a16e2 100644 --- a/packages/designer/src/builtin-simulator/host.ts +++ b/packages/designer/src/builtin-simulator/host.ts @@ -247,6 +247,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost item.condition(prop))?.onSaveContent || defaultSaveContent; setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only'); - setterPropElement.removeAttribute('for'); setterPropElement.classList.add('engine-live-editing'); // be sure setterPropElement.focus(); @@ -110,6 +109,13 @@ export class LiveEditing { const keydown = (e: KeyboardEvent) => { console.info(e.code); + switch (e.code) { + case 'Enter': + // TODO: check is richtext? + case 'Escape': + case 'Tab': + setterPropElement?.blur(); + } // esc // enter // tab diff --git a/packages/designer/src/component-meta.ts b/packages/designer/src/component-meta.ts index 411a23ae3..71c418c9c 100644 --- a/packages/designer/src/component-meta.ts +++ b/packages/designer/src/component-meta.ts @@ -13,7 +13,7 @@ import { FieldConfig, } from '@ali/lowcode-types'; import { computed } from '@ali/lowcode-editor-core'; -import { Node, ParentalNode } from './document'; +import { Node, ParentalNode, TransformStage } from './document'; import { Designer } from './designer'; import { intlNode } from './locale'; import { IconContainer } from './icons/container'; @@ -379,8 +379,8 @@ const builtinComponentActions: ComponentAction[] = [ title: intlNode('copy'), action(node: Node) { // node.remove(); - const { document: doc, parent, schema, index } = node; - parent && doc.insertNode(parent, schema, index); + const { document: doc, parent, index } = node; + parent && doc.insertNode(parent, node, index, true); }, }, important: true, diff --git a/packages/designer/src/designer/builtin-hotkey.ts b/packages/designer/src/designer/builtin-hotkey.ts index 3f1fbc2c4..a30ee0ad4 100644 --- a/packages/designer/src/designer/builtin-hotkey.ts +++ b/packages/designer/src/designer/builtin-hotkey.ts @@ -106,7 +106,7 @@ hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => { if (!selected || selected.length < 1) return; const componentsMap = {}; - const componentsTree = selected.map((item) => item.export(TransformStage.Save)); + const componentsTree = selected.map((item) => item.export(TransformStage.Clone)); // FIXME: clear node.id diff --git a/packages/designer/src/designer/dragon.ts b/packages/designer/src/designer/dragon.ts index feadee53e..8cb020ca4 100644 --- a/packages/designer/src/designer/dragon.ts +++ b/packages/designer/src/designer/dragon.ts @@ -159,20 +159,15 @@ function makeEventsHandler( const topDoc = window.top.document; const sourceDoc = boostEvent.view?.document || topDoc; // TODO: optimize this logic, reduce listener - // const boostPrevented = boostEvent.defaultPrevented; const docs = new Set(); - // if (boostPrevented || isDragEvent(boostEvent)) { docs.add(topDoc); - // } docs.add(sourceDoc); - // if (sourceDoc !== topDoc || isDragEvent(boostEvent)) { sensors.forEach((sim) => { const sdoc = sim.contentDocument; if (sdoc) { docs.add(sdoc); } }); - // } return (handle: (sdoc: Document) => void) => { docs.forEach((doc) => handle(doc)); diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index b1c72b44d..352cb681a 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -88,7 +88,7 @@ export class DocumentModel { ); this.history = new History( - () => this.schema, + () => this.export(TransformStage.Serilize), (schema) => this.import(schema as RootSchema, true), ); this.setupListenActiveNodes(); diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index d743b0bd1..eeded1e39 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -481,15 +481,13 @@ export class Node { * 导出 schema */ export(stage: TransformStage = TransformStage.Save): Schema { - // run transducers - // run const baseSchema: any = { componentName: this.componentName, }; - // if (stage !== TransformStage.Save) { + if (stage !== TransformStage.Clone) { baseSchema.id = this.id; - // } + } if (this.isLeaf()) { baseSchema.children = this.props.get('children')?.export(stage); @@ -827,7 +825,7 @@ export function comparePosition(node1: Node, node2: Node): PositionNO { export function insertChild(container: ParentalNode, thing: Node | NodeData, at?: number | null, copy?: boolean): Node { let node: Node; if (isNode(thing) && (copy || thing.isSlot())) { - thing = thing.export(TransformStage.Save); + thing = thing.export(TransformStage.Clone); } if (isNode(thing)) { node = thing; diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index 518f62d26..1777a6b89 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -20,6 +20,27 @@ export type ValueTypes = 'unset' | 'literal' | 'map' | 'list' | 'expression' | ' export class Prop implements IPropParent { readonly isProp = true; + /** + * @see SettingTarget + */ + getPropValue(propName: string | number): any { + return this.get(propName)!.getValue(); + } + + /** + * @see SettingTarget + */ + setPropValue(propName: string | number, value: any): void { + this.set(propName, value); + } + + /** + * @see SettingTarget + */ + clearPropValue(propName: string | number): void { + this.get(propName, false)?.unset(); + } + readonly id = uniqueId('prop$'); @obx.ref private _type: ValueTypes = 'unset'; @@ -341,7 +362,7 @@ export class Prop implements IPropParent { * 获取某个属性 * @param stash 如果不存在,临时获取一个待写入 */ - get(path: string | number, stash = true): Prop | null { + get(path: string | number, stash: boolean = true): Prop | null { const type = this._type; if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) { return null; @@ -588,6 +609,10 @@ export class Prop implements IPropParent { return isMap ? fn(item, item.key) : fn(item, index); }); } + + getProps() { + return this.parent; + } } export function isProp(obj: any): obj is Prop { diff --git a/packages/designer/src/document/node/transform-stage.ts b/packages/designer/src/document/node/transform-stage.ts index 5baec4675..e415d44ae 100644 --- a/packages/designer/src/document/node/transform-stage.ts +++ b/packages/designer/src/document/node/transform-stage.ts @@ -2,5 +2,6 @@ export enum TransformStage { Render = 1, Serilize = 2, Save = 3, - Init = 4, + Clone = 4, + Init = 5, } diff --git a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx index 182a521b7..c146ffb5d 100644 --- a/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx +++ b/packages/editor-skeleton/src/components/settings/settings-primary-pane.tsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { Tab, Breadcrumb } from '@alifd/next'; -import { Title, observer, Editor } from '@ali/lowcode-editor-core'; +import { Title, observer, Editor, obx } from '@ali/lowcode-editor-core'; import { Node, isSettingField, SettingField } from '@ali/lowcode-designer'; import { SettingsMain } from './main'; import { SettingsPane } from './settings-pane'; @@ -10,6 +10,8 @@ import { createIcon } from '@ali/lowcode-utils'; export class SettingsPrimaryPane extends Component<{ editor: Editor }> { private main = new SettingsMain(this.props.editor); + @obx.ref private _activeKey?: any; + shouldComponentUpdate() { return false; } @@ -26,7 +28,7 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> { if (settings.isMultiple) { return (
- {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon'})} + {createIcon(settings.componentMeta?.icon, { className: 'lc-settings-navigator-icon' })} <span>x {settings.nodes.length}</span> </div> @@ -45,13 +47,17 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> { onMouseOut: hoverNode.bind(null, node, false), onClick: selectNode.bind(null, node), }; - items.unshift(<Breadcrumb.Item {...props} key={node.id}><Title title={node.title} /></Breadcrumb.Item>); + items.unshift( + <Breadcrumb.Item {...props} key={node.id}> + <Title title={node.title} /> + </Breadcrumb.Item>, + ); node = node.parent; } return ( <div className="lc-settings-navigator"> - {createIcon(this.main.componentMeta?.icon, { className: 'lc-settings-navigator-icon'})} + {createIcon(this.main.componentMeta?.icon, { className: 'lc-settings-navigator-icon' })} <Breadcrumb className="lc-settings-node-breadcrumb">{items}</Breadcrumb> </div> ); @@ -82,7 +88,7 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> { } const { items } = settings; - if (items.length > 5 || items.some(item => !isSettingField(item) || !item.isGroup)) { + if (items.length > 5 || items.some((item) => !isSettingField(item) || !item.isGroup)) { return ( <div className="lc-settings-main"> {this.renderBreadcrumb()} @@ -93,21 +99,33 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> { ); } + let matched = false; + const tabs = (items as SettingField[]).map((field) => { + if (this._activeKey === field.name) { + matched = true; + } + return ( + <Tab.Item className="lc-settings-tab-item" title={<Title title={field.title} />} key={field.name}> + <SettingsPane target={field} key={field.id} /> + </Tab.Item> + ); + }); + const activeKey = matched ? this._activeKey : (items[0] as SettingField).name; + return ( <div className="lc-settings-main"> <Tab - key={settings.id} + activeKey={activeKey} + onChange={(tabKey) => { + this._activeKey = tabKey; + }} navClassName="lc-settings-tabs" animation={false} excessMode="dropdown" contentClassName="lc-settings-tabs-content" extra={this.renderBreadcrumb()} > - {(items as SettingField[]).map(field => ( - <Tab.Item className="lc-settings-tab-item" title={<Title title={field.title} />} key={field.name}> - <SettingsPane target={field} key={field.id} /> - </Tab.Item> - ))} + {tabs} </Tab> </div> ); diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx index b629d6c44..8512825d6 100644 --- a/packages/plugin-outline-pane/src/views/tree.tsx +++ b/packages/plugin-outline-pane/src/views/tree.tsx @@ -52,7 +52,7 @@ export default class TreeView extends Component<{ tree: Tree }> { const doc = node.document; const selection = doc.selection; const id = node.id; - const isMulti = e.metaKey || e.ctrlKey; + const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; designer.activeTracker.track(node); if (isMulti && !isRootNode(node) && selection.has(id)) { if (!isFormEvent(e.nativeEvent)) { @@ -96,7 +96,8 @@ export default class TreeView extends Component<{ tree: Tree }> { const doc = node.document; const selection = doc.selection; - const isMulti = e.metaKey || e.ctrlKey; + // TODO: shift selection + const isMulti = e.metaKey || e.ctrlKey || e.shiftKey; const isLeftButton = e.button === 0; if (isLeftButton && !isRootNode(node)) { diff --git a/packages/react-simulator-renderer/src/renderer.less b/packages/react-simulator-renderer/src/renderer.less index c4f1d352b..5a4caa1d8 100644 --- a/packages/react-simulator-renderer/src/renderer.less +++ b/packages/react-simulator-renderer/src/renderer.less @@ -83,6 +83,15 @@ body.engine-document { &:after { clear: both; } + + .next-input-group, + .next-checkbox-group,.next-date-picker,.next-input,.next-month-picker, + .next-number-picker,.next-radio-group,.next-range,.next-range-picker, + .next-rating,.next-select,.next-switch,.next-time-picker,.next-upload, + .next-year-picker, + .next-breadcrumb-item,.next-calendar-header,.next-calendar-table { + pointer-events: none !important; + } } .engine-live-editing { diff --git a/packages/vision-preset/src/bundle/upgrade-metadata.ts b/packages/vision-preset/src/bundle/upgrade-metadata.ts index cad503a57..79adb6db3 100644 --- a/packages/vision-preset/src/bundle/upgrade-metadata.ts +++ b/packages/vision-preset/src/bundle/upgrade-metadata.ts @@ -302,6 +302,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec const setterInitial = getInitialFromSetter(setter); collector.addInitial({ + // FIXME! name should be "xxx.xxx" name: slotName || name, initial: (field: Field, currentValue: any) => { // FIXME! read from prototype.defaultProps @@ -323,6 +324,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec if (ignore != null || disabled != null) { collector.addFilter({ + // FIXME! name should be "xxx.xxx" name: slotName || name, filter: (field: Field, currentValue: any) => { let disabledValue: boolean; @@ -396,7 +398,7 @@ export function upgradePropConfig(config: OldPropConfig, collector: ConfigCollec const initials: InitialItem[] = []; const filters: FilterItem[] = []; const objItems = items - ? upgradeConfigure(items, + ? upgradeConfigure(items, { addInitial: (item) => { initials.push(item); diff --git a/packages/vision-preset/src/editor.ts b/packages/vision-preset/src/editor.ts index 5735a946b..e9b6f3d1e 100644 --- a/packages/vision-preset/src/editor.ts +++ b/packages/vision-preset/src/editor.ts @@ -1,9 +1,10 @@ -import { isJSBlock, isJSExpression, isJSSlot } from '@ali/lowcode-types'; -import { isPlainObject } from '@ali/lowcode-utils'; +import { isJSBlock, isJSExpression, isJSSlot, isI18nData } from '@ali/lowcode-types'; +import { isPlainObject, hasOwnProperty } from '@ali/lowcode-utils'; import { globalContext, Editor } from '@ali/lowcode-editor-core'; import { Designer, LiveEditing, TransformStage, addBuiltinComponentAction, Node } from '@ali/lowcode-designer'; import Outline, { OutlineBackupPane, getTreeMaster } from '@ali/lowcode-plugin-outline-pane'; import { toCss } from '@ali/vu-css-style'; +import logger from '@ali/vu-logger'; import DesignerPlugin from '@ali/lowcode-plugin-designer'; import { Skeleton, SettingsPrimaryPane } from '@ali/lowcode-editor-skeleton'; @@ -31,9 +32,16 @@ designer.addPropsReducer((props, node) => { const newProps: any = {}; initials.forEach((item) => { // FIXME! this implements SettingTarget - const v = item.initial(node as any, props[item.name]); - if (v !== undefined) { - newProps[item.name] = v; + try { + // FIXME! item.name could be 'xxx.xxx' + const v = item.initial(node as any, props[item.name]); + if (v !== undefined) { + newProps[item.name] = v; + } + } catch (e) { + if (hasOwnProperty(props, item.name)) { + newProps[item.name] = props[item.name]; + } } }); return newProps; @@ -49,9 +57,17 @@ function filterReducer(props: any, node: Node): any { if (filters && filters.length) { const newProps = { ...props }; filters.forEach((item) => { - const v = item.filter(node as any, props[item.name]); - if (!v) { - delete newProps[item.name]; + // FIXME! item.name could be 'xxx.xxx' + if (!hasOwnProperty(newProps, item.name)) { + return; + } + try { + if (item.filter(node.getProp(item.name) as any, props[item.name]) === false) { + delete newProps[item.name]; + } + } catch (e) { + console.warn(e); + logger.trace(e); } }); return newProps; @@ -138,6 +154,7 @@ designer.addPropsReducer(stylePropsReducer, TransformStage.Render); // FIXME: 表达式使用 mock 值,未来live 模式直接使用原始值 function expressionReducer(obj?: any): any { + // TODO: merge with i18nReducer for optimize if (!obj) { return obj; } @@ -148,7 +165,7 @@ function expressionReducer(obj?: any): any { if (isJSExpression(obj)) { return obj.mock; } - if (isJSSlot(obj)) { + if (isJSSlot(obj) || isI18nData(obj)) { return obj; } const out: any = {}; diff --git a/packages/vision-preset/src/i18n-reducer.ts b/packages/vision-preset/src/i18n-reducer.ts index a1a153932..fb792d810 100644 --- a/packages/vision-preset/src/i18n-reducer.ts +++ b/packages/vision-preset/src/i18n-reducer.ts @@ -1,4 +1,6 @@ import Env from './env'; +import { isJSSlot, isI18nData, isJSExpression } from '@ali/lowcode-types'; +import { isPlainObject } from '@ali/lowcode-utils'; const I18nUtil = require('@ali/ve-i18n-util'); interface I18nObject { @@ -15,8 +17,8 @@ export function i18nReducer(obj?: any): any { if (Array.isArray(obj)) { return obj.map((item) => i18nReducer(item)); } - if (typeof obj === 'object') { - if (obj.type === 'i18n') { + if (isPlainObject(obj)) { + if (isI18nData(obj)) { // FIXME! use editor.get let locale = Env.getLocale(); if (obj.key) { @@ -28,6 +30,9 @@ export function i18nReducer(obj?: any): any { } return obj[obj.use || locale] || obj.zh_CN; } + if (isJSSlot(obj) || isJSExpression(obj)) { + return obj; + } const out: I18nObject = {}; Object.keys(obj).forEach((key) => { out[key] = i18nReducer(obj[key]); diff --git a/packages/vision-preset/src/index.ts b/packages/vision-preset/src/index.ts index ed632b3ef..6ad999d25 100644 --- a/packages/vision-preset/src/index.ts +++ b/packages/vision-preset/src/index.ts @@ -161,11 +161,10 @@ export { Symbols, }; +const version = '6.0.0(LowcodeEngine 0.9.0-beta)'; -/* console.log( - `%cLowcodeEngine %cv${VERSION}`, + `%cVisionEngine %cv${version}`, "color:#000;font-weight:bold;", "color:green;font-weight:bold;" ); -*/ diff --git a/packages/vision-preset/src/project.ts b/packages/vision-preset/src/project.ts index ba5d2309b..9239a9497 100644 --- a/packages/vision-preset/src/project.ts +++ b/packages/vision-preset/src/project.ts @@ -1,4 +1,4 @@ -class Project { +export class Project { private schema: any; constructor() { diff --git a/packages/vision-preset/src/vc-live-editing.ts b/packages/vision-preset/src/vc-live-editing.ts index 9f1ec6410..810069a1e 100644 --- a/packages/vision-preset/src/vc-live-editing.ts +++ b/packages/vision-preset/src/vc-live-editing.ts @@ -53,8 +53,7 @@ export function liveEditingRule(target: EditingTarget) { const innerText = targetElement.innerText; const propTarget = ['title', 'label', 'text', 'content'].find(prop => { - // TODO: enhance compare text logic - return getText(node, prop) === innerText; + return equalText(getText(node, prop), innerText); }); if (propTarget) { @@ -66,6 +65,14 @@ export function liveEditingRule(target: EditingTarget) { return null; } +function equalText(v: any, innerText: string) { + // TODO: enhance compare text logic + if (typeof v !== 'string') { + return false; + } + return v.trim() === innerText +} + // TODO: export function liveEditingSaveHander() {