From 2cf8573b7808bdbdf14eb234595189287f7f5967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8B=E7=BE=8A?= Date: Fri, 17 Apr 2020 10:39:29 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:=E5=88=A0=E9=99=A4=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=A4=9A=E4=BD=99=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/demo/src/editor/config/skeleton.js | 4 +- packages/editor-core/src/areaManager.ts | 2 +- packages/editor-core/src/editor.ts | 2 +- packages/editor-core/src/index.ts | 1 - packages/editor-skeleton/src/index.ts | 4 +- packages/react-renderer/src/adapter/rax.jsx | 33 - .../react-renderer/src/comp/addon/index.jsx | 87 --- .../react-renderer/src/comp/canvas/index.jsx | 729 ------------------ .../react-renderer/src/comp/canvas/index.scss | 361 --------- .../react-renderer/src/hoc/addonFactory.js | 55 -- .../react-renderer/src/hoc/compFactory.js | 75 -- .../react-renderer/src/hoc/localeConfig.js | 29 - .../react-renderer/src/hoc/suspenseWrapper.js | 15 - .../react-renderer/src/utils/appHelper.js | 49 -- .../react-renderer/src/utils/dndHelper.js | 574 -------------- .../react-renderer/src/utils/postMessager.js | 59 -- .../react-renderer/src/utils/schemaHelper.js | 482 ------------ .../react-renderer/src/utils/storageHelper.js | 81 -- .../src/utils/undoRedoHelper.js | 88 --- packages/react-renderer/src/utils/wsHelper.js | 87 --- 20 files changed, 8 insertions(+), 2809 deletions(-) delete mode 100644 packages/react-renderer/src/adapter/rax.jsx delete mode 100644 packages/react-renderer/src/comp/addon/index.jsx delete mode 100644 packages/react-renderer/src/comp/canvas/index.jsx delete mode 100644 packages/react-renderer/src/comp/canvas/index.scss delete mode 100644 packages/react-renderer/src/hoc/addonFactory.js delete mode 100644 packages/react-renderer/src/hoc/compFactory.js delete mode 100644 packages/react-renderer/src/hoc/localeConfig.js delete mode 100644 packages/react-renderer/src/hoc/suspenseWrapper.js delete mode 100644 packages/react-renderer/src/utils/appHelper.js delete mode 100644 packages/react-renderer/src/utils/dndHelper.js delete mode 100644 packages/react-renderer/src/utils/postMessager.js delete mode 100644 packages/react-renderer/src/utils/schemaHelper.js delete mode 100644 packages/react-renderer/src/utils/storageHelper.js delete mode 100644 packages/react-renderer/src/utils/undoRedoHelper.js delete mode 100644 packages/react-renderer/src/utils/wsHelper.js diff --git a/packages/demo/src/editor/config/skeleton.js b/packages/demo/src/editor/config/skeleton.js index a772f94ee..4a8e417cc 100644 --- a/packages/demo/src/editor/config/skeleton.js +++ b/packages/demo/src/editor/config/skeleton.js @@ -68,7 +68,9 @@ export default { "align": "top", "icon": "zujianku", "title": "组件库", - "floatable": true + "panelProps": { + "floatable": true + } }, "config": { "package": "@ali/lowcode-plugin-components-pane", diff --git a/packages/editor-core/src/areaManager.ts b/packages/editor-core/src/areaManager.ts index f6ce5e782..666f4d6d2 100644 --- a/packages/editor-core/src/areaManager.ts +++ b/packages/editor-core/src/areaManager.ts @@ -18,7 +18,7 @@ export default class AreaManager { this.pluginStatus = clone(editor.pluginStatus); } - public isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean { + isPluginStatusUpdate(pluginType?: string, notUpdateStatus?: boolean): boolean { const { pluginStatus } = this.editor; const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config; diff --git a/packages/editor-core/src/editor.ts b/packages/editor-core/src/editor.ts index 6f9a1a01f..06bd5f133 100644 --- a/packages/editor-core/src/editor.ts +++ b/packages/editor-core/src/editor.ts @@ -77,7 +77,7 @@ export default class Editor extends EventEmitter { return instance; }; - public config: EditorConfig; + config: EditorConfig; public components: PluginClassSet; diff --git a/packages/editor-core/src/index.ts b/packages/editor-core/src/index.ts index 92e36fa4b..89ecdbfda 100644 --- a/packages/editor-core/src/index.ts +++ b/packages/editor-core/src/index.ts @@ -1,7 +1,6 @@ import Editor from './editor'; import * as utils from './utils'; -export * from './definitions'; export { default as PluginFactory } from './pluginFactory'; export { default as EditorContext } from './context'; diff --git a/packages/editor-skeleton/src/index.ts b/packages/editor-skeleton/src/index.ts index c519f0552..061621d42 100644 --- a/packages/editor-skeleton/src/index.ts +++ b/packages/editor-skeleton/src/index.ts @@ -1,7 +1,9 @@ import Skeleton from './skeleton'; import Panel from './components/Panel'; import TopIcon from './components/TopIcon'; +import TopPlugin from './components/TopPlugin'; +import LeftPlugin from './components/LeftPlugin'; export default Skeleton; -export { Panel, TopIcon }; +export { Panel, TopIcon, TopPlugin, LeftPlugin }; diff --git a/packages/react-renderer/src/adapter/rax.jsx b/packages/react-renderer/src/adapter/rax.jsx deleted file mode 100644 index 85176ff68..000000000 --- a/packages/react-renderer/src/adapter/rax.jsx +++ /dev/null @@ -1,33 +0,0 @@ -import { createElement, render, useState } from 'rax'; -import React, { PureComponent } from 'react'; -import DriverUniversal from 'driver-universal'; -import { Engine } from '@ali/iceluna-rax'; -import findDOMNode from 'rax-find-dom-node'; - -let updateRax = () => {}; - -export default class Rax extends PureComponent { - constructor(props) { - super(props); - } - - componentDidMount() { - const RaxEngine = () => { - const [config, setConfig] = useState(this.props); - updateRax = setConfig; - return createElement(Engine, { - ...config, - }); - }; - render(createElement(RaxEngine), document.getElementById('luna-rax-container'), { driver: DriverUniversal }); - } - componentDidUpdate() { - updateRax(this.props); - } - - render() { - return
; - } -} - -Rax.findDOMNode = findDOMNode; diff --git a/packages/react-renderer/src/comp/addon/index.jsx b/packages/react-renderer/src/comp/addon/index.jsx deleted file mode 100644 index 1222a8c8b..000000000 --- a/packages/react-renderer/src/comp/addon/index.jsx +++ /dev/null @@ -1,87 +0,0 @@ -import { PureComponent } from 'react'; -import PropTypes from 'prop-types'; - -import AppContext from '../../context/appContext'; -import { isEmpty, generateI18n, goldlog } from '../../utils'; - -export default class Addon extends PureComponent { - static displayName = 'lunaAddon'; - static propTypes = { - config: PropTypes.object, - locale: PropTypes.string, - messages: PropTypes.object, - }; - static defaultProps = { - config: {}, - }; - static contextType = AppContext; - constructor(props, context) { - super(props, context); - if (isEmpty(props.config) || !props.config.addonKey) { - console.warn('luna addon has wrong config'); - return; - } - // 插件上下文中的appHelper使用IDE的appHelper - context.appHelper = (window.__ctx && window.__ctx.appHelper) || context.appHelper; - context.locale = props.locale; - context.messages = props.messages; - // 注册插件 - this.appHelper = context.appHelper; - let { locale, messages } = props; - this.i18n = generateI18n(locale, messages); - this.addonKey = props.config.addonKey; - this.appHelper.addons = this.appHelper.addons || {}; - this.appHelper.addons[this.addonKey] = this; - } - - async componentWillUnmount() { - // 销毁插件 - const config = this.props.config || {}; - if (config && this.appHelper.addons) { - delete this.appHelper.addons[config.addonKey]; - } - } - - open = () => { - return true; - }; - - close = () => { - return true; - }; - - goldlog = (goKey, params) => { - const { addonKey, addonConfig = {} } = this.props.config || {}; - goldlog( - goKey, - { - addonKey, - package: addonConfig.package, - version: addonConfig.version, - ...this.appHelper.logParams, - ...params, - }, - 'addon', - ); - }; - - get utils() { - return this.appHelper.utils; - } - - get constants() { - return this.appHelper.constants; - } - - get history() { - return this.appHelper.history; - } - - get location() { - return this.appHelper.location; - } - - render() { - return null; - } -} diff --git a/packages/react-renderer/src/comp/canvas/index.jsx b/packages/react-renderer/src/comp/canvas/index.jsx deleted file mode 100644 index 355eba566..000000000 --- a/packages/react-renderer/src/comp/canvas/index.jsx +++ /dev/null @@ -1,729 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { on, off } from '@ali/b3-one/lib/event'; -import AppHelper from '../../utils/appHelper'; -import SchemaHelper from '../../utils/schemaHelper'; -import DndHelper from '../../utils/dndHelper'; -import Engine from '../../engine'; - -import CompFactory from '../../hoc/compFactory'; -import { - isSchema, - isFileSchema, - isEmpty, - isJSSlot, - jsonuri, - registShortCuts, - unRegistShortCuts, - generateUtils, - parseObj, - shallowEqual, - addCssTag, - transformSchemaToPure, - goldlog, -} from '../../utils'; -import './index.scss'; - -const DESIGN_MODE = { - EXTEND: 'extend', - BORDER: 'border', - PREVIEW: 'preview', -}; - -const DEFAULT_PLACEHOLDER = { - emptyImage: '//img.alicdn.com/tfs/TB1zpkUoUT1gK0jSZFhXXaAtVXa-620-430.png', - emptyText: '当前页面为空~\n请拖拽组件放入页面容器内吧!', - nullImage: '//img.alicdn.com/tfs/TB1m_oSoND1gK0jSZFsXXbldVXa-620-430.png', - nullText: '编辑内容不存在~!', -}; - -export default class Canvas extends PureComponent { - static displayName = 'Canvas'; - static propTypes = { - appHelper: PropTypes.object, - components: PropTypes.object, - engine: PropTypes.element, - onCreate: PropTypes.func, - initSchema: PropTypes.object, - shortCuts: PropTypes.array, - utils: PropTypes.object, - }; - static defaultProps = { - components: {}, - engine: Engine, - onCreate: () => {}, - initSchema: {}, - shortCuts: [], - utils: {}, - }; - constructor(props) { - super(props); - this.appHelper = props.appHelper || new AppHelper(); - if (!this.appHelper.schemaHelper) { - this.appHelper.set('schemaHelper', new SchemaHelper(props.initSchema || {}, this.appHelper)); - } - this.appHelper.set('basicSchemaHelper', this.appHelper.schemaHelper); - if (!this.appHelper.dndHelper) { - this.appHelper.set('dndHelper', new DndHelper(this.appHelper)); - } - this.appHelper.dndHelper.setCanvasWin(window); - if (this.appHelper.designMode === undefined) { - this.appHelper.designMode = 'extend'; - } - - this.canvasAppHelper = new AppHelper({ - history: this.appHelper.history, - location: this.appHelper.location, - match: this.appHelper.match, - }); - - this.updateCanvasAppHelper(props); - this.appHelper.once('ide.ready', () => { - this.updateCanvasAppHelper(props); - }); - - window.__ctx = { - appHelper: this.appHelper, - canvasAppHelper: this.canvasAppHelper, - components: this.props.components, - }; - - window.goldlog = window.goldlog || window.parent.goldlog; - - this.state = { - canvasStack: [ - { - lunaKey: 'root', - lunaPath: '', - name: 'root', - schemaHelper: this.appHelper.schemaHelper, - schema: this.appHelper.schemaHelper.get('schema'), - }, - ], - }; - this.appHelper.set('canvasStack', this.state.canvasStack); - } - - componentDidMount() { - const appHelper = this.appHelper; - appHelper.batchOn(['behavior.undo', 'behavior.redo'], this.handleUndoRedo); - appHelper.on('schema.reset', this.handleSchemaReset); - appHelper.on('material.move', this.handleMaterialMove); - appHelper.on('material.add', this.handleMaterialAdd); - appHelper.on('material.remove', this.handleMaterialRemove); - appHelper.on('material.up', this.handleMaterialMoveUp); - appHelper.on('material.down', this.handleMaterialMoveDown); - appHelper.on('material.copy', this.handleMaterialCopy); - appHelper.on('material.update', this.handleMaterialUpdate); - appHelper.on('material.select', this.handleMaterialSelect); - appHelper.on('schemaHelper.schema.afterUpdate', this.handleReset); - appHelper.on('designMode.change', this.handleDesignModeChange); - appHelper.on('preview.change', this.handlePreviewChange); - appHelper.on('canvas.stack.push', this.handleCanvasPush); - appHelper.on('canvas.stack.pop', this.handleCanvasPop); - appHelper.on('canvas.stack.jump', this.handleCanvasJump); - appHelper.on('style.update', this.updateStyle); - appHelper.batchOn(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate); - appHelper.on('viewPort.update', this.handleForceUpdate); - - registShortCuts(this.props.shortCuts, this.appHelper); - this.appHelper.set('canvas', this); - this.props.onCreate(this.appHelper); - appHelper.emit('canvas.ready', this); - goldlog( - 'EXP', - { - action: 'appear', - }, - 'canvas', - ); - } - - componentWillUnmount() { - const appHelper = this.appHelper; - appHelper.batchOff(['behavior.undo', 'behavior.redo'], this.handleUndoRedo); - appHelper.on('schema.reset', this.handleSchemaReset); - appHelper.off('material.move', this.handleMaterialMove); - appHelper.off('material.add', this.handleMaterialAdd); - appHelper.off('material.remove', this.handleMaterialRemove); - appHelper.off('material.up', this.handleMaterialMoveUp); - appHelper.off('material.down', this.handleMaterialMoveDown); - appHelper.off('material.copy', this.handleMaterialCopy); - appHelper.off('material.update', this.handleMaterialUpdate); - appHelper.off('material.select', this.handleMaterialSelect); - appHelper.off('schemaHelper.schema.afterUpdate', this.handleReset); - appHelper.off('designMode.change', this.handleDesignModeChange); - appHelper.off('preview.change', this.handlePreviewChange); - appHelper.off('canvas.stack.push', this.handleCanvasPush); - appHelper.off('canvas.stack.pop', this.handleCanvasPop); - appHelper.off('canvas.stack.jump', this.handleCanvasJump); - appHelper.off('style.update', this.updateStyle); - appHelper.batchOff(['utils.update', 'constants.update', 'componentsMap.update'], this.handleCanvasAppHelperUpdate); - appHelper.off('viewPort.update', this.handleForceUpdate); - unRegistShortCuts(this.props.shortCuts); - } - - // 消息处理 - - handleMaterialMove = ({ lunaKey, targetKey, direction }) => { - const appHelper = this.appHelper; - appHelper.schemaHelper.move(lunaKey, targetKey, direction); - appHelper.emit('behavior.record'); - }; - - handleMaterialAdd = ({ schema, targetKey, direction }) => { - if (!isSchema(schema)) { - throw new Error('物料schema结构异常,无法添加!'); - } - const appHelper = this.appHelper; - const addSchema = Array.isArray(schema) ? schema[0] : schema; - // 对于没有设置文件名的容器组件,交给画布外层处理 - if (isFileSchema(addSchema) && !addSchema.fileName) { - return appHelper.emit('onFileNameMaterial.add', { schema: addSchema, targetKey, direction }); - } - - const addKey = appHelper.schemaHelper.add(schema, targetKey, direction); - appHelper.emit('behavior.record'); - this.autoSelectComponent(addKey); - }; - - handleMaterialRemove = (lunaKey) => { - const appHelper = this.appHelper; - const schemaHelper = appHelper.schemaHelper; - const currCompSchema = schemaHelper.schemaMap[lunaKey]; - // 获取当前删除物料的相邻物料 - const nextCompSchema = jsonuri.get( - schemaHelper.schema, - currCompSchema.__ctx.lunaPath.replace(/\/(\d+)$/, (res, idx) => `/${parseInt(idx) + 1}`), - ); - const activeKey = (nextCompSchema && nextCompSchema.__ctx.lunaKey) || currCompSchema.__ctx.parentKey; - appHelper.schemaHelper.remove(lunaKey); - appHelper.emit('behavior.record'); - this.autoSelectComponent(activeKey); - }; - - handleMaterialMoveUp = (lunaKey) => { - const appHelper = this.appHelper; - appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'up'); - appHelper.emit('behavior.record'); - }; - - handleMaterialMoveDown = (lunaKey) => { - const appHelper = this.appHelper; - appHelper.schemaHelper && appHelper.schemaHelper.slide(lunaKey, 'down'); - appHelper.emit('behavior.record'); - }; - - handleMaterialCopy = (lunaKey) => { - const appHelper = this.appHelper; - const addKey = appHelper.schemaHelper.copy(lunaKey); - - appHelper.emit('behavior.record'); - this.autoSelectComponent(addKey); - }; - - handleMaterialUpdate = ({ lunaKey, props, propsKey }) => { - const appHelper = this.appHelper; - appHelper.schemaHelper.update(lunaKey, props); - appHelper.emit('behavior.record', { lunaKey, propsKey }); - }; - - handleMaterialSelect = (lunaKey, options) => { - const appHelper = this.appHelper; - if (appHelper.activeKey === lunaKey) return; - appHelper.set('activeKey', lunaKey); - appHelper.emit('material.select.change', lunaKey, options); - const preNode = document.querySelectorAll('[data-active=true]'); - if (preNode[0] && preNode[0].dataset.lunaKey === lunaKey) return; - (preNode || []).forEach((item) => { - item.removeAttribute('data-active'); - item.removeAttribute('data-nochild'); - }); - //判断是否容器组件且没有子元素 - if (!lunaKey) { - window.parent.t = window.t = null; - return; - } - let schema = appHelper.schemaHelper.schemaMap[lunaKey]; - if (!schema) return; - let componentInfo = appHelper.componentsMap[schema.componentName]; - const currentNode = document.querySelectorAll(`[data-luna-key=${lunaKey}]`); - (currentNode || []).forEach((item) => { - item.setAttribute('data-active', 'true'); - if (componentInfo && componentInfo.isContainer && schema && (!schema.children || !schema.children.length)) { - item.setAttribute('data-nochild', 'true'); - } - }); - // for debug - let ctx = this.appHelper.schemaHelper.compCtxMap[lunaKey]; - let ref = this.appHelper.schemaHelper.compThisMap[lunaKey]; - let t = { - ctx, - schema, - ref, - }; - t.__proto__ = ctx; - window.parent.t = window.t = t; - }; - - handleDesignModeChange = (designMode) => { - this.appHelper.set('designMode', designMode); - this.forceUpdate(); - }; - - handlePreviewChange = (isPreview) => { - this.appHelper.set('isPreview', isPreview); - this.forceUpdate(); - }; - - handleUndoRedo = (schema) => { - this.appHelper.schemaHelper.reset(schema); - this.autoSelectComponent(); - }; - - handleSchemaReset = (schema) => { - this.appHelper.schemaHelper.reset(schema); - this.appHelper.emit('behavior.record'); - this.autoSelectComponent(); - }; - - handleReset = () => { - this.updateCanvasStack(); - this.forceUpdate(); - this.updateStyle(); - }; - - handleCanvasAppHelperUpdate = () => { - this.updateCanvasAppHelper(); - this.forceUpdate(); - }; - - handleForceUpdate = () => { - this.forceUpdate(); - }; - - handleCanvasPush = ({ schema, lunaKey, name }) => { - const appHelper = this.appHelper; - appHelper.emit('canvas.stack.beforePush'); - const { canvasStack } = this.state; - const tempSchema = { - componentName: 'Temp', - fileName: 'temp', - props: {}, - children: isJSSlot(schema) ? schema.value : schema, //兼容slot - }; - const schemaHelper = new SchemaHelper(transformSchemaToPure(tempSchema), this.appHelper); - const schemaMap = this.appHelper.schemaHelper.schemaMap || {}; - const compCtxMap = this.appHelper.schemaHelper.compCtxMap || {}; - const currentComp = schemaMap[lunaKey]; - const undoRedoKey = `${lunaKey}_${canvasStack.length}`; - //若是第一层下钻需要先给最上层加上从appHelper中获取的undoRedoKey - if (canvasStack.length === 1) { - canvasStack[0].undoRedoKey = this.appHelper.undoRedoKey; - } - const currentData = { - lunaKey, - lunaPath: currentComp.__ctx.lunaPath, - name, - schema, - schemaHelper, - ctx: compCtxMap[lunaKey], - undoRedoKey, - componentName: currentComp.componentName, - }; - appHelper.set('schemaHelper', schemaHelper); - appHelper.undoRedoHelper && appHelper.undoRedoHelper.create(undoRedoKey, tempSchema); - appHelper.set('undoRedoKey', undoRedoKey); - appHelper.set('activeKey', null); - this.setState( - { - canvasStack: [...this.state.canvasStack, currentData], - }, - () => { - this.appHelper.set('canvasStack', this.state.canvasStack); - this.appHelper.emit('canvas.stack.afterPush', currentData, this.state.canvasStack); - this.autoSelectComponent(); - }, - ); - }; - - handleCanvasPop = () => { - const { canvasStack } = this.state; - if (canvasStack.length > 1) { - this.handleCanvasJump(null, true); - } - }; - - handleCanvasJump = (idx, isPop) => { - const { canvasStack } = this.state; - const appHelper = this.appHelper; - let preIdx = idx + 1; - if (isPop) { - appHelper.emit('canvas.stack.beforePop'); - preIdx = canvasStack.length - 1; - idx = preIdx - 1; - } else { - appHelper.emit('canvas.stack.beforeJump'); - } - if (idx < 0 || idx > canvasStack.length - 1) return; - const preData = canvasStack[preIdx]; - const currentData = canvasStack[idx]; - appHelper.set('schemaHelper', currentData.schemaHelper); - appHelper.set('undoRedoKey', currentData.undoRedoKey); - appHelper.undoRedoHelper && appHelper.undoRedoHelper.delete(preData.undoRedoKey); - this.setState( - { - canvasStack: canvasStack.slice(0, idx + 1), - }, - () => { - appHelper.set('canvasStack', this.state.canvasStack); - appHelper.schemaHelper.reset(appHelper.schemaHelper.schema); - appHelper.emit('behavior.record'); - appHelper.emit(`canvas.stack.${isPop ? 'afterPop' : 'afterJump'}`, preData, this.state.canvasStack); - this.autoSelectComponent(preData.lunaKey); - }, - ); - }; - - // 引擎处理函数 - - handleCompGetCtx = (schema, ctx) => { - const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey; - if (!lunaKey) return; - // console.log('+++++ getCtx', lunaKey, ctx); - this.appHelper.schemaHelper.compCtxMap[lunaKey] = ctx; - // for debug - if (this.appHelper.activeKey && lunaKey === this.appHelper.activeKey) { - let ref = this.appHelper.schemaHelper.compThisMap[lunaKey]; - let t = { - ctx, - schema, - ref, - }; - t.__proto__ = ctx; - window.parent.t = window.t = t; - } - }; - - handleCompGetRef = (schema, ref, topLevel) => { - const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey; - if (!lunaKey) return; - // console.log('----- getRef', lunaKey, ref); - const schemaHelper = this.appHelper.schemaHelper; - schemaHelper.compThisMap[lunaKey] = ref; - if (ref && !ref.__design) { - this.updateDesignMode(ref, schema, topLevel); - const didUpdate = ref.componentDidUpdate; - ref.componentDidUpdate = (...args) => { - didUpdate && didUpdate.apply(ref, args); - this.updateDesignMode(ref, schema, topLevel); - }; - const willUnmount = ref.componentWillUnmount; - ref.componentWillUnmount = (...args) => { - willUnmount && willUnmount.apply(ref, args); - // console.log('----- destroy', lunaKey, ref); - delete schemaHelper.compThisMap[lunaKey]; - delete schemaHelper.compCtxMap[lunaKey]; - }; - ref.__design = true; - } - }; - - handleDnd = (type, ev, schema) => { - const lunaKey = schema && schema.__ctx && schema.__ctx.lunaKey; - const designMode = this.appHelper.designMode; - if (!lunaKey || ![DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode)) return; - const dndHelper = this.appHelper && this.appHelper.dndHelper; - if (dndHelper) { - dndHelper[`handle${type}`](ev, lunaKey); - } - }; - - //自动选中组件 - autoSelectComponent = (lunaKey) => { - const appHelper = this.appHelper; - // 若未指定需要选中的组件,且当前有选中的组件不做处理 - if (appHelper.activeKey && !lunaKey) return; - if (!lunaKey) { - // 若没有指定的组件,且当前又没有选中组件,默认选中顶部组件,如果是下钻编辑则默认选中第一个子组件 - const schema = appHelper.schemaHelper.schema; - if (schema) { - if (schema.componentName === 'Temp') { - lunaKey = schema.children && schema.children[0] && schema.children[0].__ctx.lunaKey; - } else { - lunaKey = schema.__ctx.lunaKey; - } - } - } - appHelper.emit('material.select', lunaKey); - }; - - // 构造低代码组件 - generateLowComps = (props = this.props) => { - const { components } = props; - const { utils, constants } = this.canvasAppHelper || {}; - const componentsMap = this.appHelper.componentsMap || {}; - Object.keys(componentsMap).forEach((key) => { - const comp = componentsMap[key]; - // 对自定义组件做特殊处理 - if (comp.version === '0.0.0' && comp.code) { - let schema = parseObj(comp.code); - if (isFileSchema(schema) && schema.componentName === 'Component') { - components[comp.name] = CompFactory(schema, components, componentsMap, { - utils, - constants, - }); - } - } - }); - return components; - }; - - updateCanvasAppHelper = (props = this.props) => { - const { utils } = props; - const { entityInfo = {}, componentsMap } = this.appHelper; - this.canvasAppHelper.set({ - componentsMap, - utils: entityInfo.utils ? generateUtils(utils, parseObj(entityInfo.utils)) : utils, - constants: parseObj((entityInfo && entityInfo.constants) || {}), - }); - this.canvasAppHelper.set('components', this.generateLowComps(props)); - }; - - updateStyle = () => { - const entityInfo = this.appHelper.entityInfo || {}; - const blockSchemaMap = (this.appHelper.schemaHelper && this.appHelper.schemaHelper.blockSchemaMap) || {}; - const componentsMap = this.appHelper.componentsMap || {}; - const cssMap = {}; - // 区块中的样式 - Object.keys(blockSchemaMap).forEach((item) => { - const schema = blockSchemaMap[item]; - cssMap[schema.fileName] = schema.css || (schema.__ctx && schema.__ctx.css) || ''; - }); - // 低代码自定义组件中的样式 - Object.keys(componentsMap).forEach((item) => { - const comp = componentsMap[item]; - // 对自定义组件做特殊处理 - if (comp.version === '0.0.0' && comp.code && comp.css) { - cssMap[comp.name] = comp.css; - } - }); - cssMap.__global = entityInfo.css || ''; - if (shallowEqual(this.cacheCssMap, cssMap)) return; - this.cacheCssMap = cssMap; - const { __global, ...other } = cssMap; - addCssTag( - 'luna-canvas-style', - `${__global}\n${Object.keys(other || {}) - .map((item) => cssMap[item]) - .join('\n')}`, - ); - }; - - updateCanvasStack = () => { - const { canvasStack } = this.state; - if (canvasStack.length < 2) return; - for (let idx = canvasStack.length - 1; idx > 0; idx--) { - const currentData = canvasStack[idx]; - const { lunaPath, name, schemaHelper, schema } = currentData; - const preData = canvasStack[idx - 1]; - let data = schemaHelper.getPureSchema().children; - // 如果情况内容则删除属性 - if (isEmpty(data)) { - jsonuri.rm( - preData.schemaHelper.schema, - name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`, - ); - continue; - } - if (isJSSlot(schema)) { - data = { - ...schema, - value: data, - }; - } else if (name !== 'children') { - data = { - type: 'JSSlot', - value: data, - }; - } - jsonuri.set( - preData.schemaHelper.schema, - name === 'children' ? `${lunaPath}/children` : `${lunaPath}/props/${name.replace('.', '/')}`, - data, - ); - } - }; - - updateDesignMode = (ref, schema, topLevel) => { - if (!ref || (ref && ref.current === null) || !schema.__ctx) return; - const { engine } = this.props; - const appHelper = this.appHelper; - const { activeKey, isPreview, viewPortConfig } = appHelper; - const designMode = isPreview ? 'preview' : appHelper.designMode; - const node = engine.findDOMNode(ref.current || ref); - - if (!node || !node.getAttribute) return; - // 渲染引擎可以通过设置__disableDesignMode属性的方式阻止组件的可视模式; - const hasDesignMode = - [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(designMode) && !ref.props.__disableDesignMode; - node.setAttribute('data-design-mode', designMode && hasDesignMode ? `luna-design-${designMode}` : ''); - if (topLevel) { - node.setAttribute('top-container', true); - } - const lunaKey = schema.__ctx.lunaKey; - let instanceName = schema.componentName + (window.parent.__isDebug ? (lunaKey || '_').split('_')[1] : ''); - switch (schema.componentName) { - case 'Page': - instanceName = '页面容器 ' + instanceName; - break; - case 'Block': - instanceName = '区块容器 ' + instanceName; - break; - case 'Component': - instanceName = '低代码组件容器 ' + instanceName; - break; - case 'Addon': - instanceName = '插件容器 ' + instanceName; - break; - case 'Temp': - instanceName = '下钻编辑器容器'; - } - - if (topLevel && viewPortConfig) { - node.style.transform = `scale(${viewPortConfig.scale ? viewPortConfig.scale / 100 : 1})`; - } - node.setAttribute('data-instance-name', instanceName); - node.setAttribute('data-luna-key', lunaKey); - node.setAttribute('data-luna-path', schema.__ctx.lunaPath); - - if (hasDesignMode) { - if (activeKey && activeKey === lunaKey) { - node.setAttribute('data-active', true); - } else { - node.removeAttribute('data-active'); - } - // 点击 - if (!node.compEvent && schema.componentName !== 'Temp') { - node.compEvent = (ev) => { - ev.stopPropagation(); - appHelper.emit('material.select', lunaKey, { isFromCanvas: true }); - }; - on(node, 'mousedown', node.compEvent, false); - } - - // drag and drop - if (!node.draggableFlag) { - if (topLevel) { - node.ondragleave = (ev) => this.handleDnd('DragLeave', ev, schema); - node.ondrop = (ev) => this.handleDnd('Drop', ev, schema); - } else { - node.setAttribute('draggable', 'true'); - node.ondragstart = (ev) => this.handleDnd('DragStart', ev, schema); - node.ondragend = (ev) => this.handleDnd('DragEnd', ev, schema); - } - node.ondragover = (ev) => this.handleDnd('DragOver', ev, schema); - node.draggableFlag = true; - } - } else { - //点击 - if (node.compEvent) { - off(node, 'mousedown', node.compEvent, false); - delete node.compEvent; - } - //drag and drop - if (node.draggableFlag) { - node.removeAttribute('draggable'); - delete node.ondragstart; - delete node.ondragover; - delete node.ondragend; - delete node.ondragleave; - delete node.ondrop; - delete node.draggableFlag; - } - } - }; - - renderCanvasStack = () => { - const { canvasStack } = this.state; - const lastIndex = canvasStack.length - 1; - const appHelper = this.appHelper; - const canvasAppHelper = this.canvasAppHelper; - const designMode = appHelper.isPreview ? 'preview' : appHelper.designMode; - const Engine = this.props.engine; - - return (canvasStack || []).map((item, idx) => ( -
- -
- )); - }; - - render() { - const { canvasStack } = this.state; - const lastIndex = canvasStack.length - 1; - const schema = canvasStack[lastIndex] && canvasStack[lastIndex].schemaHelper.schema; - - const appHelper = this.appHelper; - const { entityInfo = {}, viewPortConfig = {}, canvasPlaceholder = {} } = appHelper; - const components = this.canvasAppHelper.components || {}; - - const placeholder = { ...DEFAULT_PLACEHOLDER, ...canvasPlaceholder }; - const layoutComp = entityInfo.layoutInfo && entityInfo.layoutInfo.name; - const layoutProps = (entityInfo.layoutInfo && entityInfo.layoutInfo.realProps) || {}; - const Layout = layoutComp && components[layoutComp]; - const { hideLayout } = viewPortConfig; - const isDrillDown = canvasStack && canvasStack.length > 1; - const isSchemaEmpty = isSchema(schema) && isEmpty(schema.children); - const isSchemaNull = schema === null; - const canvasStyle = {}; - if (!isDrillDown) { - if (isSchemaEmpty) { - canvasStyle.backgroundImage = `url(${placeholder.emptyImage})`; - } else if (isSchemaNull) { - canvasStyle.backgroundImage = `url(${placeholder.nullImage})`; - } - } - return ( -
- {Layout && !hideLayout ? ( - - {this.renderCanvasStack()} - - ) : ( - this.renderCanvasStack() - )} -
- ); - } -} diff --git a/packages/react-renderer/src/comp/canvas/index.scss b/packages/react-renderer/src/comp/canvas/index.scss deleted file mode 100644 index 3961561d4..000000000 --- a/packages/react-renderer/src/comp/canvas/index.scss +++ /dev/null @@ -1,361 +0,0 @@ -/*增加标签函数*/ -@mixin labelFun($type: before) { - &:#{$type} { - content: attr(data-instance-name) !important; - position: absolute; - left: 0; - top: 0; - right: unset; - bottom: unset; - color: #666 !important; - font-size: 12px !important; - float: left; - padding: 0 5px !important; - line-height: 12px !important; - height: 12px; - overflow: hidden; - background: rgba(222, 222, 222, 0.7); - z-index: 2; - border-left: 3px solid transparent; - transform-origin: 0 0; - transform: scale(0.8); - transition: all 0.3s ease; - } - - &.luna-block, - &.luna-page, - &.luna-comp { - &:#{$type} { - border-color: #2077ff; - } - } - - &[data-active='true'] { - &:#{$type} { - color: #fff !important; - background: #1861d5 !important; - } - } - - &[data-design-mode='luna-design-border'] { - &:#{$type} { - display: none; - } - - &[data-active='true'] { - &:#{$type} { - display: block; - } - } - } -} - -.luna-canvas-inner { - height: 100%; - - &.empty, - &.null { - position: relative; - background-repeat: no-repeat; - background-position: calc(50% - 180px) 50%; - background-size: 310px 215px; - - &:after { - content: attr(data-placeholder-text); - position: absolute; - pointer-events: none; - top: 50%; - left: 50%; - margin: -40px 0 0 20px; - height: 80px; - line-height: 40px; - color: #aaa; - font-size: 24px; - white-space: pre; - } - } - - &.empty { - &.drill-down { - &:before { - display: none; - } - - &:after { - content: '请拖入组件'; - text-align: center; - left: 0; - right: 0; - margin-left: 0; - font-size: 14px; - } - } - } - - .engine-wrapper { - height: 100%; - display: none; - overflow: auto; - - &.extend, - &.border { - padding: 1px; - - > div { - padding: 1px; - } - } - - &:last-child { - display: block; - } - - &.fixed-width > div { - min-width: unset; - width: auto; - } - - &.fixed-height > div { - min-height: unset; - } - - > div { - transform-origin: left top; - min-width: 100%; - width: fit-content; - min-height: 100%; - } - } -} - -a, -span:not(.next-input-group):not(.next-input) { - &[data-design-mode*='luna-design-'] { - display: inline-block; - min-height: 16px; - } -} - -[data-luna-key] { - transition: all 0.3s ease; -} - -[data-design-mode='luna-design-border'] { - min-height: 10px; -} - -[data-design-mode='luna-design-extend'] { - min-height: 20px; -} - -[data-design-mode*='luna-design-'] { - position: relative; - outline: 1px dotted #d9d9d9; - zoom: 1; - - &:hover { - outline: 1px dotted #2077ff; - } - - [draggable='true'] { - position: relative; - } - - .next-card-body { - overflow: inherit !important; - } - - &.next-loading { - pointer-events: all !important; - } - - &[data-active='true'] { - outline: 1px solid #1861d5 !important; - - &[data-nochild='true']:not(.next-step-item):not([top-container='true']) { - min-height: 60px; - min-width: 200px; - - &:after { - content: '请拖入组件'; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - opacity: 1 !important; - visibility: visible !important; - line-height: 30px; - height: 30px; - font-size: 13px; - color: #ccc; - text-align: center; - } - } - } - - &:not(.next-tag):not(.next-icon):not(.anticon):not(.icon) { - @include labelFun(before); - } - - &.next-tag, - &.next-icon, - &.anticon, - &.icon { - @include labelFun(after); - } - - &.next-tabs-tabpane.hidden { - min-height: 0; - } - - &.ant-loop:after { - content: ''; - display: block; - clear: both; - line-height: 0; - } - - .ant-tabs-tabpane { - padding: 1px; - } - - .ide-design-placeholder { - position: relative; - text-align: center; - border: 1px dashed #d9d9d9; - outline: none; - padding: 0 !important; - min-height: 20px; - min-width: 80px; - - &:after { - content: attr(data-prop); - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - text-align: center; - line-height: 20px; - color: #e9e9e9; - } - } - - &[data-instance-name='TableGroupHeaderF'] { - clear: both; - - &:after { - content: ''; - width: 100%; - height: 0; - clear: both; - overflow: hidden; - } - } - - &[data-design-mode='luna-design-extend'] { - &[data-luna-key*='luna_'] { - &:not([class*='-input']):not([class*='-picker']):not([class*='-table']):not([class*='-switch']):not([class*='-select']):not(img):not([class*='-btn']):not(.next-tag):not(input):not([class*='-rating']):not([class*='next-menu']) { - padding: 10px; - } - - &.ant-loop { - padding: 10px 0 0; - } - } - - [class*='-form-item-control'] { - & > [data-design-mode*='luna-design-'] { - &:not(button):not(input):not([class*='-input']):not([class*='luna-comp-']) { - padding: 0 !important; - } - } - } - } -} - -#luna-canvas-effect { - position: fixed; - background: #1aab11; - z-index: 10000000; - text-align: center; - pointer-events: none; - - &:before, - &:after { - content: ''; - position: absolute; - width: 2px; - height: 2px; - border: 4px solid #1aab11; - pointer-events: none; - } - - &.left, - &.right { - width: 2px; - - &:before, - &:after { - left: -4px; - border-left-color: transparent; - border-right-color: transparent; - } - - &:before { - top: 0; - border-bottom-width: 0; - } - - &:after { - bottom: 0; - border-top-width: 0; - } - } - - &.top, - &.bottom, - &.in { - height: 2px; - - &:before, - &:after { - top: -4px; - border-top-color: transparent; - border-bottom-color: transparent; - } - - &:before { - left: 0; - border-right-width: 0; - } - - &:after { - right: 0; - border-left-width: 0; - } - } - - &.in { - b { - display: inline-block; - } - } - - b { - display: inline-block; - position: relative; - top: -12px; - margin: 0 auto; - padding: 0 10px; - color: #fff; - background: #1aab11; - height: 16px !important; - line-height: 16px !important; - font-weight: normal; - font-size: 11px; - display: none; - } -} diff --git a/packages/react-renderer/src/hoc/addonFactory.js b/packages/react-renderer/src/hoc/addonFactory.js deleted file mode 100644 index 67065239b..000000000 --- a/packages/react-renderer/src/hoc/addonFactory.js +++ /dev/null @@ -1,55 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import AddonEngine from '../engine/addonEngine'; -import BlockEngine from '../engine/blockEngine'; -import AppContext from '../context/appContext'; -import { forEach, isFileSchema } from '../utils'; -export default function addonFactory(schema, components = {}, componentsMap = {}, config = {}) { - class LNAddonView extends PureComponent { - static dislayName = 'luna-addon-factory'; - static version = config.version || '0.0.0'; - static contextType = AppContext; - static propTypes = { - forwardedRef: PropTypes.func, - }; - render() { - if (!schema || schema.componentName !== 'Addon' || !isFileSchema(schema)) { - console.warn('编辑器插件模型结构异常!'); - return null; - } - const { forwardedRef, ...otherProps } = this.props; - const props = { - ...schema.defaultProps, - ...otherProps, - __schema: schema, - ref: forwardedRef, - }; - return ( - - - - ); - } - } - const ResComp = React.forwardRef((props, ref) => ); - forEach(schema.static, (val, key) => { - ResComp[key] = val; - }); - ResComp.version = config.version || '0.0.0'; - return ResComp; -} diff --git a/packages/react-renderer/src/hoc/compFactory.js b/packages/react-renderer/src/hoc/compFactory.js deleted file mode 100644 index 49c32df7a..000000000 --- a/packages/react-renderer/src/hoc/compFactory.js +++ /dev/null @@ -1,75 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import CompEngine from '../engine/compEngine'; -import BlockEngine from '../engine/blockEngine'; -import AppContext from '../context/appContext'; -import AppHelper from '../utils/appHelper'; -import { forEach, isFileSchema } from '../utils'; -export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) { - // 自定义组件需要有自己独立的appHelper - const appHelper = new AppHelper(config); - class LNCompView extends PureComponent { - static dislayName = 'luna-comp-factory'; - static version = config.version || '0.0.0'; - static contextType = AppContext; - static propTypes = { - forwardedRef: PropTypes.func, - }; - render() { - if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) { - console.warn('自定义组件模型结构异常!'); - return null; - } - const { forwardedRef, ...otherProps } = this.props; - // 低代码组件透传应用上下文 - const appCtx = ['utils', 'constants']; - appCtx.forEach((key) => { - if (!appHelper[key] && this.context && this.context.appHelper && this.context.appHelper[key]) { - appHelper.set(key, this.context.appHelper[key]); - } - }); - const routerCtx = ['history', 'location', 'match']; - routerCtx.forEach((key) => { - if (this.context && this.context.appHelper && this.context.appHelper[key]) { - appHelper.set(key, this.context.appHelper[key]); - } - }); - // 支持通过context透传国际化配置 - const localeProps = {}; - const { locale, messages } = this.context; - if (locale && messages && messages[schema.fileName]) { - localeProps.locale = locale; - localeProps.messages = messages[schema.fileName]; - } - const props = { - ...schema.defaultProps, - ...localeProps, - ...otherProps, - __schema: schema, - ref: forwardedRef, - }; - - return ( - - - - ); - } - } - - const ResComp = React.forwardRef((props, ref) => ); - forEach(schema.static, (val, key) => { - ResComp[key] = val; - }); - ResComp.version = config.version || '0.0.0'; - return ResComp; -} diff --git a/packages/react-renderer/src/hoc/localeConfig.js b/packages/react-renderer/src/hoc/localeConfig.js deleted file mode 100644 index ccdfe3db4..000000000 --- a/packages/react-renderer/src/hoc/localeConfig.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import AppContext from '../context/appContext'; -export default function localeConfig(componentName, Component) { - class LNLocaleConfigView extends PureComponent { - static dislayName = 'luna-locale-config'; - static contextType = AppContext; - static propTypes = { - forwardedRef: PropTypes.func, - }; - render() { - const { forwardedRef, ...otherProps } = this.props; - const { locale, messages } = this.context; - const localeProps = {}; - if (locale && messages && messages[componentName]) { - localeProps.locale = locale; - localeProps.messages = messages[componentName]; - } - const props = { - ...localeProps, - ...otherProps, - ref: forwardedRef, - }; - return ; - } - } - - return React.forwardRef((props, ref) => ); -} diff --git a/packages/react-renderer/src/hoc/suspenseWrapper.js b/packages/react-renderer/src/hoc/suspenseWrapper.js deleted file mode 100644 index 6a0224af7..000000000 --- a/packages/react-renderer/src/hoc/suspenseWrapper.js +++ /dev/null @@ -1,15 +0,0 @@ -import React, { PureComponent, Suspense } from 'react'; -export default function SuspenseWrapper(fallback = null) { - return function(Component) { - class SuspenseWrapper extends PureComponent { - render() { - return ( - - - - ); - } - } - return SuspenseWrapper; - }; -} diff --git a/packages/react-renderer/src/utils/appHelper.js b/packages/react-renderer/src/utils/appHelper.js deleted file mode 100644 index 8bec5fa83..000000000 --- a/packages/react-renderer/src/utils/appHelper.js +++ /dev/null @@ -1,49 +0,0 @@ -import EventEmitter from 'events'; -import Debug from 'debug'; -let instance = null; -const debug = Debug('utils:appHelper'); -EventEmitter.defaultMaxListeners = 100; - -export default class AppHelper extends EventEmitter { - static getInstance = () => { - if (!instance) { - instance = new AppHelper(); - } - return instance; - }; - - constructor(config) { - super(); - instance = this; - Object.assign(this, config); - } - - get(key) { - return this[key]; - } - - set(key, val) { - if (typeof key === 'string') { - this[key] = val; - } else if (typeof key === 'object') { - Object.keys(key).forEach((item) => { - this[item] = key[item]; - }); - } - } - - batchOn(events, lisenter) { - if (!Array.isArray(events)) return; - events.forEach((event) => this.on(event, lisenter)); - } - - batchOnce(events, lisenter) { - if (!Array.isArray(events)) return; - events.forEach((event) => this.once(event, lisenter)); - } - - batchOff(events, lisenter) { - if (!Array.isArray(events)) return; - events.forEach((event) => this.off(event, lisenter)); - } -} diff --git a/packages/react-renderer/src/utils/dndHelper.js b/packages/react-renderer/src/utils/dndHelper.js deleted file mode 100644 index 8bd20153c..000000000 --- a/packages/react-renderer/src/utils/dndHelper.js +++ /dev/null @@ -1,574 +0,0 @@ -import ReactDOM from 'react-dom'; -import Debug from 'debug'; -import { isFileSchema, isEmpty, throttle, deepEqual } from './index'; -const DICT = { - left: '左', - right: '右', - top: '上', - bottom: '下', - in: '里', -}; -const TOP_COMPONENT = ['Page', 'Component', 'Temp']; // 顶端模块,不支持放置兄弟节点 -const debug = Debug('utils:dndHelper'); -export default class DndHelper { - constructor(appHelper) { - this.appHelper = appHelper; - this.dragDom = null; - this.canvasEffectDom = null; - this.treeEffectDom = null; - this.containrDom = null; - this.sourceEntity = null; - this.tempEntity = null; - this.dragInfo = null; - this.canvasClearTimer = null; - this.treeClearTimer = null; - this.isDragging = false; - this.dragOverFunc = throttle(this.dragOverFunc, 50); - } - - setCanvasWin(win) { - this.canvasWin = win; - if (this.canvasEffectDom) { - this.canvasWin.document.body.appendChild(this.canvasEffectDom); - } - } - - emit(msg, ...args) { - this.appHelper && this.appHelper.emit(msg, ...args); - } - - dragOverFunc(ev, schemaOrNode, isTree) { - if (!this.isDragging || !this.sourceEntity) return; - const entity = isTree - ? this.getTreeEntity(schemaOrNode, ev) - : { - target: ev.currentTarget, - schema: schemaOrNode, - }; - if (this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaKey === entity.schema.__ctx.lunaKey) - return; - let dragInfo = null; - if (isTree) { - dragInfo = this.getTreeDragInfo(ev, entity); - } else { - dragInfo = this.getDragInfo(ev, entity); - } - if (!dragInfo || deepEqual(this.dragInfo, dragInfo)) return; - this.dragInfo = dragInfo; - this.tempEntity = dragInfo.entity; - this.clearEffect(isTree); - this.addEffect(isTree); - } - - changeCanvas() { - debug('change canvas', this.sourceEntity, this.tempEntity); - if (!this.sourceEntity || !this.tempEntity) return; - if (this.sourceEntity.isAdd) { - debug('add material', this.sourceEntity.schema, this.tempEntity.schema.__ctx.lunaKey, this.dragInfo.position); - this.emit('material.add', { - schema: this.sourceEntity.schema, - targetKey: this.tempEntity.schema.__ctx.lunaKey, - direction: this.dragInfo.position, - }); - } else { - this.emit('material.move', { - lunaKey: this.sourceEntity.schema.__ctx.lunaKey, - targetKey: this.tempEntity.schema.__ctx.lunaKey, - direction: this.dragInfo.position, - }); - } - } - - getTreeEntity(node, ev) { - if (!node) return; - const schemaHelper = this.appHelper.schemaHelper; - const lunaKey = node.props.eventKey; - const schema = schemaHelper.schemaMap[lunaKey]; - if (!schema) return; - const ref = schemaHelper.compThisMap[lunaKey]; - const currentTarget = ev.currentTarget; - return { - schema, - target: ref && ReactDOM.findDOMNode(ref), - treeNodeTarget: currentTarget, - }; - } - - getDragTagDom(tagName) { - if (!this.dragDom) { - const dragDom = document.createElement('div'); - dragDom.id = 'luna-drag-dom'; - dragDom.style.height = '24px'; - dragDom.style.position = 'absolute'; - dragDom.style.zIndex = 10000000; - dragDom.style.transform = 'translateY(-10000px)'; - dragDom.style.background = 'rgba(0, 0, 0, .5)'; - dragDom.style.lineHeight = '24px'; - dragDom.style.color = '#fff'; - dragDom.style.padding = '0px 10px'; - dragDom.style.display = 'inline-block'; - document.body.appendChild(dragDom); - this.dragDom = dragDom; - } - this.dragDom.innerHTML = ` ${tagName}`; - return this.dragDom; - } - - getCanvasEffectDom() { - if (!this.canvasWin) { - throw new Error('should set the canvasWin first'); - } - if (this.canvasClearTimer) { - clearTimeout(this.canvasClearTimer); - this.canvasClearTimer = null; - } - - const { position } = this.dragInfo; - let canvasEffectDom = this.canvasEffectDom; - if (!canvasEffectDom) { - canvasEffectDom = document.createElement('div'); - this.canvasWin.document.body.appendChild(canvasEffectDom); - this.canvasEffectDom = canvasEffectDom; - } - canvasEffectDom.id = 'luna-canvas-effect'; - canvasEffectDom.innerHTML = `${DICT[position]}`; - canvasEffectDom.className = position; - canvasEffectDom.style.display = 'block'; - - return canvasEffectDom; - } - - getTreeEffectDom() { - if (this.treeClearTimer) { - clearTimeout(this.treeClearTimer); - this.treeClearTimer = null; - } - let treeEffectDom = this.treeEffectDom; - if (!treeEffectDom) { - treeEffectDom = document.createElement('div'); - this.treeEffectDom = treeEffectDom; - } - treeEffectDom.id = 'luna-tree-effect'; - treeEffectDom.style.display = 'block'; - return treeEffectDom; - } - - getLunaContainerDom(target) { - if (!target) return null; - let parent = target.parentNode; - while (parent && (!parent.dataset || !parent.dataset.lunaKey)) { - parent = parent.parentNode; - } - return parent; - } - - clearCompTreeEffect() { - const container = document.querySelector('.luna-comp-tree'); - if (!container) return; - - let treeItems = container.querySelectorAll('.tree-item'); - (treeItems || []).forEach((item) => { - const classList = item.classList; - if (classList) { - classList.remove('top'); - classList.remove('in'); - classList.remove('bottom'); - classList.remove('tree-item'); - } - }); - } - - getDragInfo(ev, entity) { - if (!this.sourceEntity || !entity) return null; - const { target, schema } = entity; - const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath; - const targetPath = schema.__ctx.lunaPath; - const sourceTarget = this.sourceEntity.target; - - if (sourcePath === targetPath) return null; - if (targetPath && targetPath.startsWith(sourcePath)) return null; - const componentsMap = this.appHelper.get('componentsMap'); - // if (!componentsMap || !componentsMap[schema.componentName]) return null; - let isContainer = - (componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件 - if (schema.children && typeof schema.children !== 'object') { - //如果children是文本, 非模型结构,则非容器; - isContainer = false; - } - const rect = target.getBoundingClientRect(); - const isSupportIn = - isContainer && - (!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children))); - const sourceIsInline = sourceTarget && ['inline-block', 'inline'].includes(getComputedStyle(sourceTarget).display); - const isInline = ['inline-block', 'inline'].includes(getComputedStyle(target).display) && sourceIsInline; - const measure = isInline ? 'width' : 'height'; - - let sn = 0; - let position = 'top'; - if (isContainer) { - sn = isSupportIn ? rect[measure] * 0.25 : Math.min(rect[measure] * 0.5, 10); - } else { - sn = rect[measure] * 0.5; - } - if (TOP_COMPONENT.includes(schema.componentName)) { - // 顶端组件,拖拽over时,只能放在其内部 - position = 'in'; - } else if (isInline && !isContainer) { - if (Math.abs(ev.clientX - rect.left) <= sn) { - position = 'left'; - } else if (Math.abs(ev.clientX - rect.right) <= sn) { - position = 'right'; - } - } else { - if (Math.abs(ev.clientY - rect.top) <= sn) { - position = 'top'; - } else if (Math.abs(ev.clientY - rect.bottom) <= sn) { - position = 'bottom'; - } else { - position = 'in'; - } - } - - // 判断是否是相邻元素, 往左|上拖 - const isPrevSibling = sourceTarget === target.nextElementSibling; - if (isPrevSibling) { - if (position === 'right') position = 'left'; - if (position === 'bottom') { - position = isContainer ? 'in' : 'top'; - } - } - // 判断是否相邻元素,往右|下拖 - const isPostSibling = sourceTarget === target.previousElementSibling; - if (isPostSibling) { - if (position === 'left') position = 'right'; - if (position === 'top') { - position = isContainer ? 'in' : 'bottom'; - } - } - - //如果是容器组件,且包含有子组件,且是in状态,进行智能识别处理; - let subChildren = []; - const getChildren = (node) => { - if (!node || !node.childNodes || node.childNodes.length === 0) return; - node.childNodes.forEach((child) => { - if (child === sourceTarget) return; - if (child && child.getAttribute && child.getAttribute('draggable')) { - const isInline = ['inline', 'inline-block'].includes(getComputedStyle(child).display) && sourceIsInline; - const rect = child.getBoundingClientRect(); - const l = Math.abs(ev.clientX - rect.left); - const r = Math.abs(ev.clientX - rect.right); - const t = Math.abs(ev.clientY - rect.top); - const b = Math.abs(ev.clientY - rect.bottom); - const minXDistance = Math.min(l, r); - const minYDistance = Math.min(t, b); - subChildren.push({ - lunaKey: child.dataset.lunaKey, - node: child, - minDistance: isInline ? [minXDistance, minYDistance] : [minYDistance, minXDistance], - position: isInline ? (l > r ? 'right' : 'left') : b > t ? 'top' : 'bottom', - }); - } else { - getChildren(child); - } - }); - }; - if (position === 'in' && isContainer && !isSupportIn) { - getChildren(target); - subChildren = subChildren.sort((a, b) => { - if (a.minDistance[0] === b.minDistance[0]) { - return a.minDistance[1] - b.minDistance[1]; - } - return a.minDistance[0] - b.minDistance[0]; - }); - const tempChild = subChildren[0]; - if (tempChild) { - if (sourceTarget === tempChild.node.nextElementSibling && ['bottom', 'right'].includes(tempChild.position)) - return null; - if (sourceTarget === tempChild.node.previousElementSibling && ['top', 'left'].includes(tempChild.position)) - return null; - position = tempChild.position; - entity = { - target: tempChild.node, - schema: this.appHelper.schemaHelper.schemaMap[tempChild.lunaKey], - }; - } - } - - const containrDom = position === 'in' ? entity.target : this.getLunaContainerDom(entity.target); - if (this.containrDom !== containrDom) { - if (this.containrDom) { - this.containrDom.style.outline = ''; - } - this.containrDom = containrDom; - } - if (this.containrDom) { - containrDom.style.outline = '1px solid #1aab11'; - } - // debug('drag info:', position, isSupportIn, isContainer, entity); - return { - position, - isSupportIn, - isContainer, - entity, - }; - } - - getTreeDragInfo(ev, entity) { - if (!this.sourceEntity || !entity) return null; - const { schema, treeNodeTarget } = entity; - const sourcePath = this.sourceEntity.schema.__ctx && this.sourceEntity.schema.__ctx.lunaPath; - const targetPath = schema.__ctx.lunaPath; - if (sourcePath === targetPath) return null; - if (targetPath && targetPath.startsWith(sourcePath)) return null; - const componentsMap = this.appHelper.get('componentsMap'); - // if (!componentsMap || !componentsMap[schema.componentName]) return null; - let isContainer = - (componentsMap[schema.componentName] && componentsMap[schema.componentName].isContainer) || isFileSchema(schema); //是否是容器组件 - if (schema.children && typeof schema.children !== 'object') { - //如果children是文本, 非模型结构,则非容器; - isContainer = false; - } - const rect = treeNodeTarget.getBoundingClientRect(); - const isSupportIn = - isContainer && - (!schema.children || (schema.children && typeof schema.children === 'object' && isEmpty(schema.children))); - - const sn = isContainer && isSupportIn ? rect.height * 0.25 : rect.height * 0.5; - let position = 'in'; - if (Math.abs(ev.clientY - rect.top) <= sn) { - position = 'top'; - } else if (Math.abs(ev.clientY - rect.bottom) <= sn) { - position = 'bottom'; - } - return { - position, - isSupportIn, - isContainer, - entity, - }; - } - - addEffect(isTree) { - if (!this.tempEntity) return; - const { position } = this.dragInfo; - const { target, treeNodeTarget } = this.tempEntity; - // this.clearCompTreeEffect(); - if (isTree) { - //画父元素外框 - let status = true; - let node = treeNodeTarget.parentNode; - while (status) { - if (node && node.parentNode) { - if (node.parentNode.tagName == 'LI' && node.parentNode.classList.contains('next-tree-node')) { - status = false; - if (this.treeNodeTargetParent !== node.parentNode || position === 'in') { - this.treeNodeTargetParent && this.treeNodeTargetParent.classList.remove('selected'); - } - this.treeNodeTargetParent = node.parentNode; - if (position !== 'in') this.treeNodeTargetParent.classList.add('selected'); - } else { - node = node.parentNode; - } - } else { - status = false; - } - } - treeNodeTarget.appendChild(this.getTreeEffectDom()); - this.treeEffectDom.className = position; - } else { - const effectDom = this.getCanvasEffectDom(); - const rect = target.getBoundingClientRect(); - effectDom.style.left = (position === 'right' ? rect.right : rect.left) + 'px'; - effectDom.style.top = - (position === 'bottom' ? rect.bottom : position === 'in' ? (rect.top + rect.bottom) / 2 : rect.top) + 'px'; - effectDom.style.height = ['top', 'in', 'bottom'].includes(position) ? '2px' : rect.height + 'px'; - effectDom.style.width = ['left', 'right'].includes(position) ? '2px' : rect.width + 'px'; - } - } - - clearCanvasEffect() { - if (this.canvasEffectDom) { - this.canvasEffectDom.style.display = 'none'; - } - if (this.containrDom) { - this.containrDom.style.outline = ''; - } - } - - clearTreeEffect() { - if (this.treeEffectDom) { - this.treeEffectDom.style.display = 'none'; - } - if (this.treeNodeTargetParent) { - this.treeNodeTargetParent.classList.remove('selected'); - } - const tempTarget = this.tempEntity && this.tempEntity.treeNodeTarget; - const classList = tempTarget && tempTarget.classList; - if (classList) { - classList.remove('top'); - classList.remove('bottom'); - classList.remove('in'); - classList.remove('tree-item'); - } - } - - clearEffect(isTree) { - if (this.isDragging) { - // if (isTree) { - if (this.treeClearTimer) { - clearTimeout(this.treeClearTimer); - this.treeClearTimer = null; - } - this.treeClearTimer = setTimeout(() => { - this.clearTreeEffect(); - }, 300); - // } else { - if (this.canvasClearTimer) { - clearTimeout(this.canvasClearTimer); - this.canvasClearTimer = null; - } - this.canvasClearTimer = setTimeout(() => { - this.clearCanvasEffect(); - }, 300); - // } - } else { - // if (isTree) { - this.clearTreeEffect(); - // } else { - this.clearCanvasEffect(); - // } - } - } - - handleDragStart(ev, lunaKey) { - ev.stopPropagation(); - const target = ev.currentTarget; - target.style.filter = 'blur(2px)'; - const schema = this.appHelper.schemaHelper.schemaMap[lunaKey]; - ev.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0); - this.sourceEntity = { - target, - schema, - }; - this.isDragging = true; - } - - handleDragEnd(ev) { - ev.stopPropagation(); - ev.preventDefault(); - this.isDragging = false; - if (!this.sourceEntity) return; - if (this.sourceEntity.target) { - this.sourceEntity.target.style.filter = ''; - } - this.clearEffect(); - } - - handleDragOver(ev, lunaKey) { - ev.preventDefault(); - ev.stopPropagation(); - this.isDragging = true; - const schema = this.appHelper.schemaHelper.schemaMap[lunaKey]; - this.dragOverFunc( - { - clientX: ev.clientX, - clientY: ev.clientY, - currentTarget: ev.currentTarget, - }, - schema, - ); - } - - handleDragLeave(ev) { - //避免移动到treeEffectDom上的抖动 - ev.stopPropagation(); - if (!this.tempEntity) return; - const rect = ev.target.getBoundingClientRect(); - // 如果鼠标位置还在当前元素范围内则不认为是dragLeave - if (ev.x >= rect.left && ev.x <= rect.right && ev.y >= rect.top && ev.y <= rect.bottom) return; - debug('canvas drag leave', ev); - this.clearEffect(); - this.dragInfo = null; - this.isDragging = false; - } - - handleDrop(ev) { - ev.stopPropagation(); - debug('drop+++++'); - this.isDragging = false; - this.changeCanvas(); - this.clearEffect(); - } - - handleTreeDragStart(ev) { - const { event, node } = ev; - event.stopPropagation(); - const lunaKey = node.props.eventKey; - const schema = this.appHelper.schemaHelper.schemaMap[lunaKey]; - if (!schema) return; - - event.dataTransfer.setDragImage(this.getDragTagDom(schema.componentName), 0, 0); - this.sourceEntity = this.getTreeEntity(node, event); - if (this.sourceEntity.target) { - this.sourceEntity.target.style.filter = 'blur(2px)'; - } - this.isDragging = true; - } - - handleTreeDragEnd(ev) { - const { event } = ev; - event.stopPropagation(); - event.preventDefault(); - this.isDragging = false; - if (!this.sourceEntity) return; - if (this.sourceEntity.target) { - this.sourceEntity.target.style.filter = ''; - } - this.clearEffect(true); - } - - handleTreeDragOver(ev) { - const { event, node } = ev; - event.preventDefault(); - event.stopPropagation(); - this.isDragging = true; - this.dragOverFunc( - { - clientX: event.clientX, - clientY: event.clientY, - currentTarget: event.currentTarget.children[0], - }, - node, - true, - ); - } - - handleTreeDragLeave(ev) { - const { event } = ev; - event.stopPropagation(); - if (!this.tempEntity) return; - //避免移动到treeEffectDom上的抖动 - if (this.treeEffectDom && this.treeEffectDom.parentNode.parentNode === event.currentTarget) return; - debug('++++ drag leave tree', ev, this.isDragging); - this.clearEffect(true); - this.isDragging = false; - } - - handleTreeDrop(ev) { - const { event } = ev; - event.stopPropagation(); - this.isDragging = false; - this.changeCanvas(); - this.clearEffect(true); - } - - handleResourceDragStart(ev, title, schema) { - ev.stopPropagation(); - ev.dataTransfer.setDragImage(this.getDragTagDom(title), -2, -2); - this.sourceEntity = { - isAdd: true, - schema, - }; - this.isDragging = true; - } -} diff --git a/packages/react-renderer/src/utils/postMessager.js b/packages/react-renderer/src/utils/postMessager.js deleted file mode 100644 index 05cb33bab..000000000 --- a/packages/react-renderer/src/utils/postMessager.js +++ /dev/null @@ -1,59 +0,0 @@ -import EventEmitter from 'events'; -import Debug from 'debug'; -const debug = Debug('utils:postMessager'); -EventEmitter.defaultMaxListeners = 100; - -export class InnerMessager extends EventEmitter { - constructor() { - super(); - this.handleReceive = this.handleReceive.bind(this); - window.addEventListener('message', this.handleReceive, false); - } - - sendMsg(type, data, targetOrigin = '*') { - window.parent && - window.parent.postMessage( - { - type, - data, - }, - targetOrigin, - ); - } - - handleReceive(e) { - if (!e.data || !e.data.type) return; - this.emit(e.data.type, e.data.data); - } - - destroy() { - window.removeEventListener('message', this.handleReceive); - } -} - -export class OuterMessager extends EventEmitter { - constructor(innerWindow) { - super(); - this.innerWindow = innerWindow; - this.handleReceive = this.handleReceive.bind(this); - window.addEventListener('message', this.handleReceive, false); - } - sendMsg(type, data, targetOrigin = '*') { - this.innerWindow && - this.innerWindow.postMessage( - { - type, - data, - }, - targetOrigin, - ); - } - - handleReceive(e) { - if (!e.data || !e.data.type) return; - this.emit(e.data.type, e.data.data); - } - destroy() { - window.removeEventListener('message', this.handleReceive); - } -} diff --git a/packages/react-renderer/src/utils/schemaHelper.js b/packages/react-renderer/src/utils/schemaHelper.js deleted file mode 100644 index 37c247802..000000000 --- a/packages/react-renderer/src/utils/schemaHelper.js +++ /dev/null @@ -1,482 +0,0 @@ -import { forEach } from '@ali/b3-one/lib/obj'; -import { - clone, - fastClone, - jsonuri, - isSchema, - isFileSchema, - isJSFunction, - isJSExpression, - parseObj, - transformSchemaToPure, - transformSchemaToStandard, - isEmpty, - moveArrayItem, - serialize, - deepEqual, -} from './index'; -import Debug from 'debug'; -import compFactory from '../hoc/compFactory'; -const debug = Debug('utils:schemaHelper'); -let keyIndex = 0; -export default class SchemaHelper { - constructor(schema, appHelper) { - this.appHelper = appHelper; - this.reset(schema, true); - } - - reset(schema, isInit) { - debug('start reset'); - this.emit('schemaHelper.schema.beforeReset'); - this.schemaMap = {}; - this.blockSchemaMap = {}; - this.compThisMap = {}; - this.blockTree = {}; - this.compTreeMap = {}; - this.compCtxMap = {}; - this.rebuild(schema, isInit); - this.emit('schemaHelper.schema.afterReset'); - } - - add(schema, targetKey, direction) { - this.emit('schemaHelper.material.beforeAdd'); - const targetSchema = this.schemaMap[targetKey]; - if (isEmpty(schema) || !targetSchema) return; - let targetPath = targetSchema.__ctx.lunaPath; - if (targetPath === '' && direction !== 'in') { - console.warn('add error'); - return; - } - let newSchema = []; - if (Array.isArray(schema)) { - newSchema = schema.filter((item) => isSchema(item, true)); - } else if (isSchema(schema)) { - newSchema = [schema]; - } else { - console.error('模型结构异常'); - return; - } - if (direction === 'in') { - const targetNode = jsonuri.get(this.schema, targetPath); - targetNode.children = (targetNode.children || []).concat(newSchema); - //jsonuri.set(this.schema, targetPath, targetNode); - } else { - direction = ['left', 'top'].includes(direction) ? 'before' : 'after'; - newSchema.reverse().forEach((item) => { - jsonuri.insert(this.schema, targetPath, item, direction); - }); - } - const addKey = `luna_${keyIndex + 1}`; - this.rebuild(this.schema); - this.emit('schemaHelper.material.afterAdd', addKey); - return addKey; - } - - remove(lunaKey) { - this.emit('schemaHelper.material.beforeRemove'); - const schema = this.schemaMap[lunaKey]; - if (!schema) return; - const lunaPath = schema.__ctx.lunaPath; - if (lunaPath === '') { - console.warn('root node can not be removed'); - return; - } - - jsonuri.rm(this.schema, lunaPath); - delete this.schemaMap[lunaKey]; - delete this.blockSchemaMap[lunaKey]; - this.rebuild(this.schema); - this.emit('schemaHelper.material.afterRemove'); - } - - move(lunaKey, targetKey, direction) { - this.emit('schemaHelper.material.beforeMove'); - debug('start move'); - const schema = this.schemaMap[lunaKey]; - const targetSchema = this.schemaMap[targetKey]; - if (!schema || !targetSchema) return; - let lunaPath = schema.__ctx.lunaPath; - let targetPath = targetSchema.__ctx.lunaPath; - if (lunaPath === '' || (targetPath === '' && direction !== 'in')) { - console.warn('move error'); - return; - } - const res = /(.*)\/(\d+)$/.exec(lunaPath); - const prefix = res && res[1]; - const attr = res && res[2]; - if (!prefix || !attr) { - console.warn('异常结构'); - return; - } - const sourceIdx = parseInt(attr); - const reg = new RegExp(`^${prefix}/(\\d+)$`); - const regRes = reg.exec(targetPath); - const sourceParent = jsonuri.get(this.schema, prefix); - direction = direction === 'in' ? 'in' : ['left', 'top'].includes(direction) ? 'before' : 'after'; - if (regRes && regRes[1] && direction !== 'in') { - const distIdx = parseInt(regRes[1]); - moveArrayItem(sourceParent, sourceIdx, distIdx, direction); - } else { - if (direction === 'in') { - const targetNode = jsonuri.get(this.schema, targetPath); - targetNode.children = targetNode.children || []; - if (Array.isArray(targetNode.children)) { - targetNode.children.push(schema); - } - jsonuri.set(this.schema, targetPath, targetNode); - } else { - jsonuri.insert(this.schema, targetPath, schema, direction); - } - sourceParent.splice(sourceIdx, 1); - } - this.rebuild(this.schema); - this.emit('schemaHelper.material.afterMove'); - } - - //组件上移 下移 - // direction 取值 down/up - slide(lunaKey, direction) { - const schema = this.schemaMap[lunaKey]; - if (!schema || !direction) return; - const lunaPath = schema.__ctx && schema.__ctx.lunaPath; - if (!lunaPath) return; - if (direction === 'up' && lunaPath.endsWith('/0')) return; - const targetPath = lunaPath.replace(/\/(\d+)$/, (res, idx) => { - return `/${direction === 'down' ? parseInt(idx) + 1 : parseInt(idx) - 1}`; - }); - const targetSchema = this.getSchemaByPath(targetPath); - const targetKey = targetSchema && targetSchema.__ctx && targetSchema.__ctx.lunaKey; - if (!targetKey) return; - this.move(lunaKey, targetKey, direction === 'down' ? 'bottom' : 'top'); - } - - // 快速复制 - copy(lunaKey) { - this.emit('schemaHelper.material.beforeCopy'); - const schema = this.schemaMap[lunaKey]; - if (!schema) return; - const newSchema = transformSchemaToPure(fastClone(schema)); - delete newSchema.__ctx; - const addKey = this.add(newSchema, schema.__ctx.lunaKey, 'bottom'); - this.emit('schemaHelper.material.afterCopy', addKey); - return addKey; - } - - update(lunaKey, props) { - this.emit('schemaHelper.material.beforeUpdate'); - const schema = this.schemaMap[lunaKey]; - if (!schema) return; - const { - __state, - __defaultProps, - __fileName, - __scss, - __loop, - __loopArgs, - __condition, - __lifeCycles, - __methods, - __dataSource, - children, - ...otherProps - } = props; - debug('update props', props); - - //自定义组件才处理defaultProps - if (schema.componentName === 'Component' && '__defaultProps' in props) { - if (!__defaultProps || typeof __defaultProps !== 'object' || isEmpty(__defaultProps)) { - delete schema.defaultProps; - } else { - schema.defaultProps = __defaultProps; - } - this.appHelper.components[schema.fileName.replace(/^\w/, (a) => a.toUpperCase())] = compFactory(schema); - } - - // 如果loop值没有设置有效值,则删除schema中这个的字段 - if ('__loop' in props) { - if (!__loop || isEmpty(__loop)) { - delete schema.loop; - } else { - schema.loop = __loop; - } - } - - // 指定循环上下文变量名 - if ('__loopArgs' in props) { - if ( - __loopArgs === undefined || - (typeof __loopArgs === 'object' && isEmpty(__loopArgs)) || - !Array.isArray(__loopArgs) || - __loopArgs.every((item) => !item) - ) { - delete schema.loopArgs; - } else { - schema.loopArgs = __loopArgs; - } - } - - // 判断条件 - if ('__condition' in props) { - if (__condition === undefined) { - delete schema.condition; - } else { - schema.condition = __condition; - } - } - - // 处理容器类组件需要考虑的字段 - if (isFileSchema(schema)) { - // filename - if ('__fileName' in props) { - schema.fileName = __fileName; - } - // state - if ('__state' in props) { - // 重走生命周期 - schema.__ctx && ++schema.__ctx.idx; - if (!__state || typeof __state !== 'object' || isEmpty(__state)) { - delete schema.state; - } else { - schema.state = __state; - } - } - // 生命周期 - if ('__lifeCycles' in props) { - if (!__lifeCycles || typeof __lifeCycles !== 'object' || isEmpty(__lifeCycles)) { - delete schema.lifeCycles; - } else { - schema.lifeCycles = __lifeCycles; - } - } - // 自定义方法 - if ('__methods' in props) { - if (!__methods || typeof __methods !== 'object' || isEmpty(__methods)) { - delete schema.methods; - } else { - schema.methods = __methods; - } - } - - // 数据源设置 - if ('__dataSource' in props) { - if (this.needContainerReload(schema.dataSource, __dataSource)) { - schema.__ctx && ++schema.__ctx.idx; - } - if (__dataSource === undefined || (typeof __dataSource === 'object' && isEmpty(__dataSource))) { - delete schema.dataSource; - } else { - schema.dataSource = __dataSource; - } - } - - // 如果scss值没有设置有效值,则删除schema中这个的字段 - if ('__scss' in props) { - if (!__scss) { - delete schema.scss; - } else { - schema.scss = __scss; - } - } - } - - // 子组件 - if ('children' in props) { - if (children === undefined || (typeof children === 'object' && isEmpty(children))) { - delete schema.children; - } else { - schema.children = children; - } - } - - schema.props = { - ...schema.props, - ...otherProps, - }; - - //过滤undefined属性 - Object.keys(schema.props).map((key) => { - if (schema.props[key] === undefined) { - delete schema.props[key]; - } - }); - - this.rebuild(this.schema); - this.emit('schemaHelper.material.afterUpdate'); - } - - createSchema(componentName, props, isContainer) { - const schema = { - componentName, - props: props || {}, - __ctx: { - lunaKey: ++this.lunaKey, - }, - }; - if (isContainer) { - schema.children = []; - } - return schema; - } - - rebuild(schema, isInit) { - if (!isFileSchema(schema)) { - debug('top schema should be a file type'); - //对于null的schema特殊处理一下 - if (schema === null) { - this.schema = schema; - this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`); - } - return; - } - this.blockTree = null; - this.compTreeMap = {}; - this.compTree = null; - this.schemaMap = {}; - this.blockSchemaMap = {}; - this.compCtxMap = {}; - const buildSchema = (schema, parentBlockNode, parentCompNode, path = '') => { - if (Array.isArray(schema)) { - return schema.map((item, idx) => buildSchema(item, parentBlockNode, parentCompNode, `${path}/${idx}`)); - } else if (typeof schema === 'object') { - // 对于undefined及null直接返回 - if (!schema) return schema; - //JSFunction转函数 - if (isJSFunction(schema)) { - if (typeof schema.value === 'string') { - let tarFun = parseObj(schema.value); - if (typeof tarFun === 'function') { - return tarFun; - } - } else if (typeof schema.value === 'function') { - return schema.value; - } - return schema; - } - //如果是对象且是JSExpression - if (isJSExpression(schema)) { - return '{{' + schema.value + '}}'; - } - const res = {}; - if (isSchema(schema)) { - res.__ctx = schema.__ctx; - if (!res.__ctx) { - const lunaKey = `luna_${++keyIndex}`; - res.__ctx = { - idx: 0, - lunaKey, - lunaPath: path, - parentKey: parentCompNode && parentCompNode.lunaKey, - blockKey: parentBlockNode && parentBlockNode.lunaKey, - }; - } else { - res.__ctx.lunaPath = path; - } - const label = schema.componentName + (schema.fileName ? '-' + schema.fileName : ''); - const lunaKey = res.__ctx && res.__ctx.lunaKey; - this.schemaMap[lunaKey] = res; - if (isFileSchema(schema)) { - this.blockSchemaMap[lunaKey] = res; - - const blockNode = { - label, - lunaKey, - isFile: true, - children: [], - }; - this.compTreeMap[lunaKey] = blockNode; - const compNode = clone(blockNode); - if (parentBlockNode) { - parentBlockNode.children.push(blockNode); - } else { - this.blockTree = blockNode; - } - parentBlockNode = blockNode; - if (parentCompNode) { - parentCompNode.children.push(compNode); - } else { - this.compTree = compNode; - } - parentCompNode = compNode; - } else { - const compNode = { - label, - lunaKey, - children: [], - }; - parentCompNode.children.push(compNode); - parentCompNode = compNode; - } - } - forEach(schema, (val, key) => { - if (key.startsWith('__')) { - res[key] = val; - } else { - res[key] = buildSchema(val, parentBlockNode, parentCompNode, `${path}/${key}`); - } - }); - return res; - } - return schema; - }; - this.emit(`schemaHelper.schema.${isInit ? 'beforeInit' : 'beforeUpdate'}`); - this.schema = buildSchema(schema); - this.emit(`schemaHelper.schema.${isInit ? 'afterInit' : 'afterUpdate'}`); - } - - needContainerReload(preData = {}, nextData = {}) { - if ( - typeof preData.dataHandler === 'function' && - typeof nextData.dataHandler === 'function' && - preData.dataHandler.toString() !== nextData.dataHandler.toString() - ) { - return true; - } else if (preData.dataHandler !== nextData.dataHandler) { - return true; - } - return !deepEqual( - (preData.list || []).filter((item) => item.isInit), - (nextData.list || []).filter((item) => item.isInit), - (pre, next) => { - if (typeof pre === 'function' && next === 'function') { - return pre.toString() === next.toString(); - } - }, - ); - } - - emit(msg, ...args) { - this.appHelper && this.appHelper.emit(msg, ...args); - } - - get(key) { - return this[key]; - } - - getSchemaByPath(path) { - return jsonuri.get(this.schema, path); - } - - getSchema() { - return this.schema; - } - - getPureSchema() { - return transformSchemaToPure(this.schema); - } - - getPureSchemaStr() { - return serialize(this.getPureSchema(), { - unsafe: true, - }); - } - - getStandardSchema() { - return transformSchemaToStandard(this.schema); - } - - getStandardSchemaStr() { - return serialize(this.getStandardSchema(), { - unsafe: true, - }); - } -} diff --git a/packages/react-renderer/src/utils/storageHelper.js b/packages/react-renderer/src/utils/storageHelper.js deleted file mode 100644 index 7c815b0d6..000000000 --- a/packages/react-renderer/src/utils/storageHelper.js +++ /dev/null @@ -1,81 +0,0 @@ -import localforage from 'localforage'; -import Debug from 'debug'; -import { serialize } from './index'; - -const debug = Debug('utils:storageHelper'); -export default class StorageHelper { - constructor(name) { - this.store = localforage.createInstance(name); - } - - getItem(key) { - if (!this.store) { - throw new Error('store instance not exist'); - } - return this.store.getItem(key); - } - - setItem(key, value) { - if (!this.store) { - throw new Error('store instance not exist'); - } - return this.store.setItem(key, value); - } - - removeItem(key) { - if (!this.store) { - throw new Error('store instance not exist'); - } - return this.store.removeItem(key); - } - - clear() { - if (!this.store) { - throw new Error('store instance not exist'); - } - return this.store.clear(); - } - - addHistory(key, code, limit = 10) { - return new Promise((resolve, reject) => { - key = '__luna_history_' + key; - this.store - .getItem(key) - .then((res) => { - let codeStr = serialize(code, { - unsafe: true, - }); - if (res && res[0] && res[0].code) { - if (codeStr === res[0].code) return; - } - res = res || []; - let newId = 1; - if (res && res[0] && res[0].id) { - newId = res[0].id + 1; - } - res.unshift({ - id: newId, - time: +new Date(), - code: codeStr, - }); - this.store - .setItem(key, res.slice(0, limit)) - .then((res) => { - resolve(res); - }) - .catch(reject); - }) - .catch(reject); - }); - } - - getHistory(key) { - key = '__luna_history_' + key; - return this.store.getItem(key); - } - - clearHistory(key) { - key = '__luna_history_' + key; - this.store.removeItem(key); - } -} diff --git a/packages/react-renderer/src/utils/undoRedoHelper.js b/packages/react-renderer/src/utils/undoRedoHelper.js deleted file mode 100644 index 4cd352591..000000000 --- a/packages/react-renderer/src/utils/undoRedoHelper.js +++ /dev/null @@ -1,88 +0,0 @@ -import Debug from 'debug'; -import { fastClone } from './index'; -const DEFAULT_CONFIG = { - limit: 20, -}; -const debug = Debug('utils:undoRedoHelper'); -export default class UndoRedoHelper { - constructor(config) { - this.config = { ...DEFAULT_CONFIG, ...config }; - this.data = {}; - } - - create(key, value, forceCreate) { - if (!this.data[key] || forceCreate) { - this.data[key] = { - list: [fastClone(value)], - idx: 0, - }; - } - return this.data[key]; - } - - delete(key) { - delete this.data[key]; - } - - resetRecord(key, value) { - const data = this.data[key]; - if (!data || !data.list) return; - data.list = data.list.slice(0, data.idx + 1); - data.list[data.idx] = fastClone(value); - } - - record(key, value) { - const data = this.data[key]; - const limit = this.config.limit; - if (!data || !data.list) return; - data.list = data.list.slice(0, data.idx + 1); - if (data.list.length >= limit) { - data.list.shift(); - } - data.list.push(fastClone(value)); - ++data.idx; - } - - undo(key) { - const data = this.data[key]; - if (!data || !data.list) return null; - //若没有前置操作,返回当前数据 - if (data.idx <= 0) return data.list[data.idx]; - --data.idx; - return data.list[data.idx]; - } - redo(key) { - const data = this.data[key]; - if (!data || !data.list) return null; - //若没有后续操作,返回当前数据 - if (data.idx >= data.list.length - 1) return data.list[data.idx]; - ++data.idx; - return data.list[data.idx]; - } - - past(key) { - const data = this.data[key]; - if (!data || !data.list || data.idx <= 0) return null; - return data.list[data.idx - 1]; - } - - present(key) { - const data = this.data[key]; - if (!data || !data.list) return null; - return data.list[data.idx]; - } - - future(key) { - const data = this.data[key]; - if (!data || !data.list || data.idx >= data.list.length - 1) return null; - return data.list[data.idx + 1]; - } - - get(key) { - return { - past: this.past(key), - present: this.present(key), - future: this.future(key), - }; - } -} diff --git a/packages/react-renderer/src/utils/wsHelper.js b/packages/react-renderer/src/utils/wsHelper.js deleted file mode 100644 index 436080a4d..000000000 --- a/packages/react-renderer/src/utils/wsHelper.js +++ /dev/null @@ -1,87 +0,0 @@ -import Debug from 'debug'; -import client from 'socket.io-client'; -import { parseUrl } from '@ali/b3-one/lib/url'; -const debug = Debug('utils:wsHelper'); - -export default class WSHelper { - constructor(appHelper, namespace, options) { - this.appHelper = appHelper; - this.ws = null; - this.init(namespace, options); - } - - init(namespace = '/', options = {}) { - if (this.ws) { - this.close(); - } - const urlInfo = parseUrl(); - const ws = (this.ws = client(namespace, { - reconnectionDelay: 3000, - transports: ['websocket'], - query: urlInfo.params, - ...options, - })); - const appHelper = this.appHelper; - debug('ws.init'); - - ws.on('connect', (msg) => { - appHelper.emit('wsHelper.connect.success', msg); - debug('ws.connect'); - }); - - ws.on('error', (msg) => { - appHelper.emit('wsHelper.connect.error', msg); - debug('ws.error', msg); - }); - - ws.on('disconnect', (msg) => { - appHelper.emit('wsHelper.connect.break', msg); - debug('ws.disconnect', msg); - }); - - ws.on('reconnecting', (msg) => { - appHelper.emit('wsHelper.connect.retry', msg); - debug('ws.reconnecting', msg); - }); - - ws.on('ping', (msg) => { - debug('ws.ping', msg); - }); - - ws.on('pong', (msg) => { - debug('ws.pong', msg); - }); - - ws.on('data', (msg) => { - appHelper.emit('wsHelper.data.receive', msg); - if (msg.eventName) { - appHelper.emit(`wsHelper.result.${msg.eventName}`, msg); - } - debug('ws.data', msg); - }); - } - - close() { - if (!this.ws) return; - this.ws.close(); - this.ws = null; - this.appHelper.emit('wsHelper.connect.close'); - } - - send(eventName, ...args) { - return new Promise((resolve, reject) => { - try { - this.appHelper.emit('wsHelper.data.request', { - eventName, - params: args, - }); - this.appHelper.once(`wsHelper.result.${eventName}`, resolve); - this.ws && this.ws.emit(eventName, ...args); - debug('ws.send', eventName); - } catch (err) { - console.error('websocket error:', err); - reject(err); - } - }); - } -} From d03844c706544d8199d3197c078ca89b7e83dae7 Mon Sep 17 00:00:00 2001 From: "zude.hzd" Date: Sun, 19 Apr 2020 22:13:58 +0800 Subject: [PATCH 2/7] add source-editor pannel --- packages/demo/build.plugin.js | 12 + packages/demo/package.json | 2 + packages/demo/skeleton.config.js | 10 +- packages/demo/src/editor/config/components.js | 6 +- packages/demo/src/editor/config/skeleton.js | 28 +- packages/plugin-source-editor/CHANGELOG.md | 20 ++ packages/plugin-source-editor/README.md | 1 + packages/plugin-source-editor/build.json | 9 + packages/plugin-source-editor/package.json | 41 +++ packages/plugin-source-editor/src/index.scss | 23 ++ packages/plugin-source-editor/src/index.tsx | 246 ++++++++++++++++++ .../plugin-source-editor/src/transform.ts | 98 +++++++ packages/plugin-source-editor/tsconfig.json | 9 + 13 files changed, 497 insertions(+), 8 deletions(-) create mode 100644 packages/plugin-source-editor/CHANGELOG.md create mode 100644 packages/plugin-source-editor/README.md create mode 100644 packages/plugin-source-editor/build.json create mode 100644 packages/plugin-source-editor/package.json create mode 100644 packages/plugin-source-editor/src/index.scss create mode 100644 packages/plugin-source-editor/src/index.tsx create mode 100644 packages/plugin-source-editor/src/transform.ts create mode 100644 packages/plugin-source-editor/tsconfig.json diff --git a/packages/demo/build.plugin.js b/packages/demo/build.plugin.js index 0fbf67f53..50ac34ddd 100644 --- a/packages/demo/build.plugin.js +++ b/packages/demo/build.plugin.js @@ -1,4 +1,6 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); + module.exports = ({ onGetWebpackConfig }) => { onGetWebpackConfig((config) => { @@ -7,6 +9,16 @@ module.exports = ({ onGetWebpackConfig }) => { .use(TsconfigPathsPlugin, [{ configFile: "./tsconfig.json" }]); + + + config + // 定义插件名称 + .plugin('MonacoWebpackPlugin') + // 第一项为具体插件,第二项为插件参数 + .use(new MonacoWebpackPlugin({ + languages:["javascript","css","json"] + }), []); + config.plugins.delete('hot'); config.devServer.hot(false); }); diff --git a/packages/demo/package.json b/packages/demo/package.json index bd8af2d92..bdd8a4759 100644 --- a/packages/demo/package.json +++ b/packages/demo/package.json @@ -18,6 +18,7 @@ "@ali/lowcode-plugin-event-bind-dialog": "^0.8.0", "@ali/lowcode-plugin-outline-pane": "^0.8.7", "@ali/lowcode-plugin-sample-logo": "^0.8.0", + "@ali/lowcode-plugin-source-editor":"^0.8.2", "@ali/lowcode-plugin-sample-preview": "^0.8.6", "@ali/lowcode-plugin-settings-pane": "^0.8.8", "@ali/lowcode-plugin-undo-redo": "^0.8.0", @@ -41,6 +42,7 @@ "build-plugin-fusion": "^0.1.0", "build-plugin-moment-locales": "^0.1.0", "build-plugin-react-app": "^1.1.2", + "monaco-editor-webpack-plugin":"^1.9.0", "tsconfig-paths-webpack-plugin": "^3.2.0" } } diff --git a/packages/demo/skeleton.config.js b/packages/demo/skeleton.config.js index 4dd4cc1c0..b649fd023 100644 --- a/packages/demo/skeleton.config.js +++ b/packages/demo/skeleton.config.js @@ -83,17 +83,18 @@ module.exports = { pluginProps: { } }, + { - pluginKey: 'outlinePane', + pluginKey: 'soueceEditor', type: 'PanelIcon', props: { align: 'top', icon: 'shuxingkongjian', - title: '大纲树' + title: '源码面板' }, config: { - package: '@ali/lowcode-plugin-outline-pane', - version: '^0.8.0' + package: '@ali/lowcode-plugin-source-editor', + version: '^0.8.2' }, pluginProps: {} }, @@ -137,6 +138,7 @@ module.exports = { version: '^0.8.0' } } + ] }, hooks: [], diff --git a/packages/demo/src/editor/config/components.js b/packages/demo/src/editor/config/components.js index 9648a7faf..348e048b7 100644 --- a/packages/demo/src/editor/config/components.js +++ b/packages/demo/src/editor/config/components.js @@ -8,6 +8,7 @@ import zhEn from '@ali/lowcode-plugin-zh-en'; import settingsPane from '@ali/lowcode-plugin-settings-pane'; import designer from '@ali/lowcode-plugin-designer'; import eventBindDialog from '@ali/lowcode-plugin-event-bind-dialog'; +import sourceEditor from '@ali/lowcode-plugin-source-editor' export default { LowcodeSkeleton, logo, @@ -18,5 +19,6 @@ export default { zhEn, settingsPane, designer, - eventBindDialog -}; \ No newline at end of file + eventBindDialog, + sourceEditor +}; diff --git a/packages/demo/src/editor/config/skeleton.js b/packages/demo/src/editor/config/skeleton.js index 4a8e417cc..65d182436 100644 --- a/packages/demo/src/editor/config/skeleton.js +++ b/packages/demo/src/editor/config/skeleton.js @@ -90,7 +90,30 @@ export default { "version": "^0.8.0" }, "pluginProps": {} - }, { + }, + + { + "pluginKey": "sourceEditor", + "type": "PanelIcon", + "props": { + "align": "top", + "icon": "zujianku", + "title": "组件库", + "panelProps":{ + "floatable": true, + "defaultWidth":500 + + }, + + }, + "config": { + "package": "@ali/lowcode-plugin-source-editor", + "version": "^0.8.0" + }, + "pluginProps": {} + }, + + { "pluginKey": "zhEn", "type": "Custom", "props": { @@ -124,7 +147,8 @@ export default { "package": "@ali/lowcode-plugin-event-bind-dialog", "version": "^0.8.0" } - }] + }, + ] }, "hooks": [], "shortCuts": [], diff --git a/packages/plugin-source-editor/CHANGELOG.md b/packages/plugin-source-editor/CHANGELOG.md new file mode 100644 index 000000000..7c5e8d83c --- /dev/null +++ b/packages/plugin-source-editor/CHANGELOG.md @@ -0,0 +1,20 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +## [0.8.2](https://gitlab.alibaba-inc.com/ali-lowcode/ali-lowcode-engine/compare/@ali/lowcode-plugin-variable-bind-dialog@0.8.1...@ali/lowcode-plugin-variable-bind-dialog@0.8.2) (2020-03-30) + + + + +**Note:** Version bump only for package @ali/lowcode-plugin-source-editor + + +## 0.8.1 (2020-03-30) + + + + +**Note:** Version bump only for package @ali/lowcode-plugin-source-editor diff --git a/packages/plugin-source-editor/README.md b/packages/plugin-source-editor/README.md new file mode 100644 index 000000000..8a6fb13f0 --- /dev/null +++ b/packages/plugin-source-editor/README.md @@ -0,0 +1 @@ +## todo diff --git a/packages/plugin-source-editor/build.json b/packages/plugin-source-editor/build.json new file mode 100644 index 000000000..e791d5b6b --- /dev/null +++ b/packages/plugin-source-editor/build.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "build-plugin-component", + "build-plugin-fusion", + ["build-plugin-moment-locales", { + "locales": ["zh-cn"] + }] + ] +} diff --git a/packages/plugin-source-editor/package.json b/packages/plugin-source-editor/package.json new file mode 100644 index 000000000..19c1c9178 --- /dev/null +++ b/packages/plugin-source-editor/package.json @@ -0,0 +1,41 @@ +{ + "name": "@ali/lowcode-plugin-source-editor", + "version": "0.8.2", + "description": "alibaba lowcode editor source-editor plugin", + "files": [ + "es", + "lib" + ], + "main": "lib/index.js", + "module": "es/index.js", + "scripts": { + "build": "build-scripts build --skip-demo", + "test": "ava", + "test:snapshot": "ava --update-snapshots" + }, + "keywords": [ + "lowcode", + "editor" + ], + "author": "zude.hzd", + "dependencies": { + "@ali/lowcode-editor-core": "^0.8.0", + "@alifd/next": "^1.19.16", + "react": "^16.8.1", + "react-dom": "^16.8.1", + "prettier":"^1.18.2", + "js-beautify": "^1.10.1", + "react-monaco-editor": "^0.36.0" + }, + "devDependencies": { + "@alib/build-scripts": "^0.1.3", + "@types/react": "^16.9.13", + "@types/react-dom": "^16.9.4", + "build-plugin-component": "^0.2.7-1", + "build-plugin-fusion": "^0.1.0", + "build-plugin-moment-locales": "^0.1.0" + }, + "publishConfig": { + "registry": "https://registry.npm.alibaba-inc.com" + } +} diff --git a/packages/plugin-source-editor/src/index.scss b/packages/plugin-source-editor/src/index.scss new file mode 100644 index 000000000..02b902227 --- /dev/null +++ b/packages/plugin-source-editor/src/index.scss @@ -0,0 +1,23 @@ +.source-editor-container{ + height: 100%; + + + .next-tabs { + -webkit-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + height: 100%; + } + + .next-tabs-content{ + height: 100%; + } + + .next-tabs-tabpane.active { + visibility: visible; + opacity: 1; + height: 100%; + } + +} + diff --git a/packages/plugin-source-editor/src/index.tsx b/packages/plugin-source-editor/src/index.tsx new file mode 100644 index 000000000..f1dba0d4e --- /dev/null +++ b/packages/plugin-source-editor/src/index.tsx @@ -0,0 +1,246 @@ +import { Component, isValidElement, ReactElement, ReactNode } from 'react'; +import { Tab, Search, Input, Button } from '@alifd/next'; +import Editor from '@ali/lowcode-editor-core'; +import { js_beautify, css_beautify } from 'js-beautify'; +import MonacoEditor from 'react-monaco-editor'; + +// import lolizer from './sorceEditorPlugin', + +import { Designer } from '@ali/lowcode-designer'; +const TAB_KEY = { + JS_TAB: 'js_tab', + CSS_TAB: 'css_tab', +}; + +import './index.scss'; +import transfrom from './transform'; + +const defaultEditorOption = { + width: '100%', + height: '96%', + options: { + readOnly: false, + automaticLayout: true, + folding: true, //默认开启折叠代码功能 + lineNumbers: 'on', + wordWrap: 'off', + formatOnPaste: true, + fontSize: 12, + tabSize: 2, + scrollBeyondLastLine: false, + fixedOverflowWidgets: false, + snippetSuggestions: 'top', + minimap: { + enabled: false, + }, + scrollbar: { + vertical: 'auto', + horizontal: 'auto', + }, + } +}; + +export default class SourceEditor extends Component<{ + editor: Editor; +}> { + private monocoEditer:Object; + private editorCmd:Object; + + state = { + isShow: false, + tabKey: TAB_KEY.JS_TAB + } + + componentWillMount() { + const { editor } = this.props; + editor.on('leftPanel.show', (key: String) => { + if (key === 'sourceEditor' && !this.monocoEditer) { + this.setState({ + isShow: true, + }); + } + }); + + // 添加函数 + editor.on('sourceEditor.addFunction',(params:Object)=>{ + this.callEditorEvent('sourceEditor.addFunction',params); + }) + + editor.once('designer.mount', (designer: Designer) => { + // let schema = designer.project.getSchema(); + // mock data + let schema = { + componentTree: [ + { + state: { + // 初始state: 选填 对象类型/变量表达式 + btnText: 'submit', // 默认数据值: 选填 变量表达式 + }, + css: 'body {font-size: 12px;} .botton{widht:100px;color:#ff00ff}', //css样式描述: 选填 + lifeCycles: { + //生命周期: 选填 对象类型 + didMount: { + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('did mount');\n\t}", + }, + willUnmount: { + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('will umount');\n\t}", + }, + }, + methods: { + //自定义方法对象: 选填 对象类型 + testFunc: { + //自定义方法: 选填 函数类型 + type: 'JSExpression', + value: "function() {\n \t\tconsole.log('testFunc');\n \t}", + }, + }, + }, + ], + }; + + this.initCode(schema); + }); + + + setTimeout (()=>{ + editor.emit('sourceEditor.addFunction',{ + functionName:'testgaga' + }) + },3000) + + } + + callEditorEvent = (eventName,params) => { + if (!this.monocoEditer){ + this.editorCmd = { + eventName, + params + }; + return; + } + + if (eventName === 'sourceEditor.addFunction'){ + this.addFunction(params); + } + + } + + initCode = (schema) => { + let jsCode = js_beautify(transfrom.schema2Code(schema),{ indent_size: 2, indent_empty_lines: true }); + let css; + + if (schema.componentTree[0].css) { + css = css_beautify(schema.componentTree[0].css,{ indent_size: 2 }); + } + + this.setState({ + jsCode, + css, + selectTab: TAB_KEY.JS_TAB, + }); + + }; + + addFunction (params){ + const count = this.monocoEditer.getModel().getLineCount() || 0; + const range = new monaco.Range(count, 1, count, 1); + const functionCode = transfrom.getNewFunctionCode(params.functionName); + this.monocoEditer.executeEdits('log-source', [{ identifier: 'event_id', range:range , text: functionCode, forceMoveMarkers:true }]); + + this.updateCode(this.monocoEditer.getModel().getValue()) + } + + editorDidMount = (editor, monaco) => { + console.log('editorDidMount', editor); + this.monocoEditer = editor; + + if (this.editorCmd){ + this.callEditorEvent(this.editorCmd.eventName,this.editorCmd.params); + } + + // var commandId = editor.addCommand( + // 0, + // function() { + // // services available in `ctx` + // alert('my command is executing!'); + // }, + // '', + // ); + + // monaco.languages.registerCodeLensProvider('javascript', { + // provideCodeLenses: function(model, token) { + // return { + // lenses: [ + // { + // range: { + // startLineNumber: 1, + // startColumn: 1, + // endLineNumber: 1, + // endColumn: 1, + // }, + // id: 'First Line', + // command: { + // id: commandId, + // title: 'First Line', + // }, + // }, + // ], + // }; + // }, + // resolveCodeLens: function(model, codeLens, token) { + // return codeLens; + // }, + // }); + }; + + onTabChange = (key) => { + this.setState({ + selectTab: key, + }); + }; + + updateCode = (newCode) => { + const { selectTab } = this.state; + if (selectTab === TAB_KEY.JS_TAB) { + this.setState({ + jsCode: newCode, + }); + } else { + this.setState({ + css: newCode, + }); + } + + transfrom.code2Schema(newCode); + } + + render() { + const { isShow, selectTab, jsCode, css } = this.state; + const tabs = [ + { tab: 'index.js', key: TAB_KEY.JS_TAB }, + { tab: 'style.css', key: TAB_KEY.CSS_TAB }, + ]; + + return ( +
+ + {tabs.map((item) => ( + + {isShow && ( + this.updateCode(newCode)} + editorDidMount={this.editorDidMount} + /> + )} + + ))} + +
+ ); + } +} diff --git a/packages/plugin-source-editor/src/transform.ts b/packages/plugin-source-editor/src/transform.ts new file mode 100644 index 000000000..35a87934a --- /dev/null +++ b/packages/plugin-source-editor/src/transform.ts @@ -0,0 +1,98 @@ +import walkSourcePlugin from './sorceEditorPlugin'; + +const transfrom = { + schema2Code(schema: Object) { + let componentSchema = schema.componentTree[0]; + let code = +`export default class { + ${initStateCode(componentSchema)} + ${initLifeCycleCode(componentSchema)} + ${initMethodsCode(componentSchema)} +}`; + console.log(code); + return code; + }, + + code2Schema(code: String) { + + let newCode = code.replace(/export default class/,'class A'); + + let A,a; + try { + A = eval('('+newCode + ')'); + a = new A(); + }catch(e){ + return '' + } + + + let functionNameList = Object.getOwnPropertyNames(a.__proto__); + + let functionMap = {}; + + functionNameList.map((functionName)=>{ + if (functionName != 'constructor'){ + let functionCode = a[functionName].toString().replace(new RegExp(functionName),'function'); + functionMap[functionName] = functionCode; + } + }) + + console.log(JSON.stringify(a.state)); + + console.log(functionMap); + + }, + + getNewFunctionCode(functionName:String){ + return `\n\t${functionName}(){\n\t}\n` + } +}; + + +function initStateCode(componentSchema:Object) { + if (componentSchema.state){ + return `state = ${JSON.stringify(componentSchema.state)}` + } + + return ''; +} + +function initLifeCycleCode(componentSchema: Object) { + if (componentSchema.lifeCycles) { + let lifeCycles = componentSchema.lifeCycles; + let codeList = []; + + for (let key in lifeCycles) { + codeList.push(createFunctionCode(key, lifeCycles[key])); + } + + return codeList.join(''); + } else { + return ''; + } +} + +function initMethodsCode(componentSchema: Object) { + if (componentSchema.methods) { + let methods = componentSchema.methods; + let codeList = []; + + for (let key in methods) { + codeList.push(createFunctionCode(key, methods[key])); + } + + return codeList.join(''); + } else { + return ''; + } +} + +function createFunctionCode(functionName: String, functionNode: Object) { + if (functionNode.type === 'JSExpression') { + let functionCode = functionNode.value; + functionCode = functionCode.replace(/function/, functionName); + return functionCode; + } +} + +export default transfrom; diff --git a/packages/plugin-source-editor/tsconfig.json b/packages/plugin-source-editor/tsconfig.json new file mode 100644 index 000000000..c37b76ecc --- /dev/null +++ b/packages/plugin-source-editor/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": [ + "./src/" + ] +} From fd100c9c3e295b4daa263aabe077fb5229bb0328 Mon Sep 17 00:00:00 2001 From: "wuyue.xht" Date: Sun, 19 Apr 2020 22:36:58 +0800 Subject: [PATCH 3/7] feat: add init and ready lifecycles --- packages/runtime/src/core/provider/index.ts | 61 +++++++++++++++++---- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/packages/runtime/src/core/provider/index.ts b/packages/runtime/src/core/provider/index.ts index fb3512c68..79016f2ab 100644 --- a/packages/runtime/src/core/provider/index.ts +++ b/packages/runtime/src/core/provider/index.ts @@ -1,4 +1,5 @@ import { IAppConfig, IUtils, IComponents, HistoryMode } from '../run'; +import EventEmitter from '@ali/offline-events'; interface IConstants { [key: string]: any; @@ -100,15 +101,18 @@ export interface I18n { type Locale = 'zh-CN' | 'en-US'; -// export interface IProvider { -// init?(): void; -// getAppData?(appkey: string): Promise; -// getPageData?(pageId: string): Promise; -// getLazyComponent?(pageId: string, props: any): any; -// createApp?(): void; -// } +export interface IProvider { + init(): void; + ready(): void; + onReady(cb: any): void; + async(): Promise; + getAppData(): Promise; + getPageData(pageId: string): Promise; + getLazyComponent(pageId: string, props: any): any; + createApp(): void; +} -export default class Provider { +export default class Provider implements IProvider { private components: IComponents = {}; private utils: IUtils = {}; private constants: IConstants = {}; @@ -118,7 +122,10 @@ export default class Provider { private history: HistoryMode = 'hash'; private containerId = ''; private i18n: I18n | null = null; + private homePage = ''; private lazyElementsMap: { [key: string]: any } = {}; + private sectionalRender = false; + private emitter: EventEmitter = new EventEmitter(); constructor() { this.init(); @@ -153,8 +160,24 @@ export default class Provider { }); } - async init() { + init() { console.log('init'); + // 默认 ready,当重载了init时需手动触发 this.ready() + this.ready(); + } + + ready(params?: any) { + if (params && typeof params === 'function') { + params = params(); + } + this.emitter.emit('ready', params || ''); + } + + onReady(cb: (params?: any) => void) { + if (!cb || typeof cb !== 'function') { + return; + } + this.emitter.on('ready', cb); } getAppData(): any { @@ -230,7 +253,7 @@ export default class Provider { this.containerId = id; } - setI18n(i18n: I18n) { + setI18n(i18n: I18n | undefined) { if (!i18n) { return; } @@ -244,6 +267,16 @@ export default class Provider { this.lazyElementsMap[pageId] = cache; } + setHomePage(pageId: string) { + if (pageId) { + this.homePage = pageId; + } + } + + setSectionalRender() { + this.sectionalRender = true; + } + getComponents() { return this.components; } @@ -305,10 +338,18 @@ export default class Provider { return locale ? this.i18n[locale] : this.i18n; } + getHomePage() { + return this.homePage; + } + getlazyElement(pageId: string) { if (!pageId) { return; } return this.lazyElementsMap[pageId]; } + + isSectionalRender() { + return this.sectionalRender; + } } From 84642355d44ddf2902b4e178442b9baf605b872a Mon Sep 17 00:00:00 2001 From: "wuyue.xht" Date: Sun, 19 Apr 2020 22:37:57 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AElayouts=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/src/core/container.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/core/container.ts b/packages/runtime/src/core/container.ts index 677fd32ad..e8deee816 100644 --- a/packages/runtime/src/core/container.ts +++ b/packages/runtime/src/core/container.ts @@ -8,7 +8,7 @@ export interface ILayoutOptions { export default class Container { private renderer: ReactType | null = null; - private layouts: { [key: string]: ReactType } = {}; + private layouts: { [key: string]: { content: ReactType; props: any } } = {}; private loading: ReactType | null = null; private provider: any; @@ -20,11 +20,11 @@ export default class Container { if (!options) { return; } - const { componentName } = options; + const { componentName, props = {} } = options; if (!componentName || !Layout) { return; } - this.layouts[componentName] = Layout; + this.layouts[componentName] = { content: Layout, props }; } registerLoading(component: ReactType) { From e96934ae4c91d419c1f35f3628cd02c258e1518e Mon Sep 17 00:00:00 2001 From: "wuyue.xht" Date: Sun, 19 Apr 2020 22:38:26 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20=E9=80=8F=E5=87=BAloading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/src/core/provider/react/lazy-component.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/core/provider/react/lazy-component.tsx b/packages/runtime/src/core/provider/react/lazy-component.tsx index 72119ccb8..37c111097 100644 --- a/packages/runtime/src/core/provider/react/lazy-component.tsx +++ b/packages/runtime/src/core/provider/react/lazy-component.tsx @@ -38,6 +38,6 @@ export default class LazyComponent extends Component { // loading扩展点 return createElement(Loading); } - return createElement(Renderer as any, { schema, ...restProps }); + return createElement(Renderer as any, { schema, loading: Loading ? createElement(Loading) : null, ...restProps }); } } From 94690c389b3f63d6968e80d8fca26419c5b89f26 Mon Sep 17 00:00:00 2001 From: "wuyue.xht" Date: Sun, 19 Apr 2020 22:39:42 +0800 Subject: [PATCH 6/7] =?UTF-8?q?chore:=20=E5=A3=B0=E6=98=8EgetProvider?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E8=BF=94=E5=9B=9E=E5=80=BC=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/src/core/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/core/index.ts b/packages/runtime/src/core/index.ts index 076fbc2ce..6160a6a20 100644 --- a/packages/runtime/src/core/index.ts +++ b/packages/runtime/src/core/index.ts @@ -1,5 +1,6 @@ import { ReactType } from 'react'; import Container, { ILayoutOptions } from './container'; +import { IProvider } from './provider'; import run from './run'; class App { @@ -41,7 +42,7 @@ class App { return this.container.getLoading(); } - getProvider() { + getProvider(): IProvider { return this.container.getProvider(); } } From 0a421518cf7d5eae2aab820a5c08c668cff8a059 Mon Sep 17 00:00:00 2001 From: "wuyue.xht" Date: Sun, 19 Apr 2020 22:39:56 +0800 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/runtime/package.json | 5 +- .../runtime/src/core/provider/react/index.ts | 66 ++++++++++++------- packages/runtime/src/core/run.ts | 27 ++++---- 3 files changed, 59 insertions(+), 39 deletions(-) diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 191b3e633..2c667549f 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@ali/lowcode-runtime", - "version": "0.8.9", + "version": "0.8.12", "description": "Runtime for Ali lowCode engine", "files": [ "es", @@ -25,7 +25,8 @@ }, "license": "MIT", "dependencies": { - "@ali/recore": "^1.6.9" + "@ali/recore": "^1.6.9", + "@ali/offline-events": "^1.0.0" }, "devDependencies": { "@alib/build-scripts": "^0.1.18", diff --git a/packages/runtime/src/core/provider/react/index.ts b/packages/runtime/src/core/provider/react/index.ts index 3bff84f94..1c0a3fb07 100644 --- a/packages/runtime/src/core/provider/react/index.ts +++ b/packages/runtime/src/core/provider/react/index.ts @@ -1,4 +1,4 @@ -import { createElement, ReactElement } from 'react'; +import { createElement, ReactType, ReactElement } from 'react'; import { Router } from '@ali/recore'; import app from '../../index'; import Provider from '..'; @@ -7,33 +7,66 @@ import LazyComponent from './lazy-component'; export default class ReactProvider extends Provider { // 定制构造根组件的逻辑,如切换路由机制 createApp() { + const RouterView = this.getRouterView(); + let App; + const layoutConfig = this.getLayoutConfig(); + if (!layoutConfig || !layoutConfig.componentName) { + App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null); + return App; + } + const { componentName: layoutName, props: layoutProps } = layoutConfig; + const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {}; + const sectionalRender = this.isSectionalRender(); + if (!sectionalRender && Layout) { + App = (props: any) => + createElement( + Layout, + { ...layoutProps, ...extraLayoutProps }, + RouterView ? createElement(RouterView, props) : null, + ); + } else { + App = (props: any) => (RouterView ? createElement(RouterView, props) : null); + } + return App; + } + + // 内置实现 for 动态化渲染 + getRouterView(): ReactType | null { const routerConfig = this.getRouterConfig(); if (!routerConfig) { - return; + return null; } - const routes: Array<{ path: string; children: any; exact: boolean; keepAlive: boolean }> = []; - let homePageId = ''; + const routes: Array<{ + path: string; + children: any; + exact: boolean; + defined: { keepAlive: boolean; [key: string]: any }; + }> = []; + let homePageId = this.getHomePage(); Object.keys(routerConfig).forEach((pageId: string, idx: number) => { if (!pageId) { return; } const path = routerConfig[pageId]; - if (idx === 0 || path === '/') { - homePageId = pageId; - } routes.push({ path, children: (props: any) => this.getLazyComponent(pageId, props), exact: true, - keepAlive: true, + defined: { keepAlive: true }, }); + if (homePageId) { + return; + } + if (idx === 0 || path === '/') { + homePageId = pageId; + } }); if (homePageId) { routes.push({ path: '**', children: (props: any) => this.getLazyComponent(homePageId, { ...props }), exact: true, - keepAlive: true, + defined: { keepAlive: true }, }); } const RouterView = (props: any) => { @@ -45,20 +78,7 @@ export default class ReactProvider extends Provider { ...props, }); }; - let App; - const layoutConfig = this.getLayoutConfig(); - if (!layoutConfig || !layoutConfig.componentName) { - App = (props: any) => createElement(RouterView, { ...props }); - return App; - } - const { componentName: layoutName, props: layoutProps } = layoutConfig; - const Layout = app.getLayout(layoutName); - if (Layout) { - App = (props: any) => createElement(Layout, layoutProps, RouterView({ props })); - } else { - App = (props: any) => createElement(RouterView, props); - } - return App; + return RouterView; } getLazyComponent(pageId: string, props: any): ReactElement | null { diff --git a/packages/runtime/src/core/run.ts b/packages/runtime/src/core/run.ts index 3fd4a364e..7cc7ab98f 100644 --- a/packages/runtime/src/core/run.ts +++ b/packages/runtime/src/core/run.ts @@ -46,21 +46,20 @@ function transformConfig(config: IAppConfig | (() => IAppConfig)): IRecoreAppCon }; } -export default function run(config?: IAppConfig | (() => IAppConfig)) { +export default function run() { const provider = app.getProvider(); - if (config) { - config = transformConfig(config); - const App = provider.createApp(); - runApp(App, config); - return; + if (!provider) { + throw new Error(''); } - const promise = provider.async(); - promise.then((config: IAppConfig) => { - if (!config) { - return; - } - const App = provider.createApp(); - config = transformConfig(config); - runApp(App, config); + provider.onReady(() => { + const promise = provider.async(); + promise.then((config: IAppConfig) => { + if (!config) { + return; + } + const App = provider.createApp(); + config = transformConfig(config); + runApp(App, config); + }); }); }