diff --git a/packages/editor/.eslintrc.js b/packages/editor/.eslintrc.js index f877f9390..aa36c050d 100644 --- a/packages/editor/.eslintrc.js +++ b/packages/editor/.eslintrc.js @@ -3,6 +3,10 @@ const { tslint, deepmerge } = require('@ice/spec'); module.exports = deepmerge(tslint, { rules: { "global-require": 0, - "@typescript-eslint/interface-name-prefix": 0 + "comma-dangle": 0, + "react/sort-comp": 0, + "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".tsx", "ts"] }], + "@typescript-eslint/interface-name-prefix": 0, + "@typescript-eslint/no-explicit-any": 0 }, }); diff --git a/packages/editor/ice.config.js b/packages/editor/ice.config.js index 4222f059d..6843f35bb 100644 --- a/packages/editor/ice.config.js +++ b/packages/editor/ice.config.js @@ -12,7 +12,7 @@ module.exports = { }, plugins: [ ['ice-plugin-fusion', { - themePackage: '@alife/theme-lowcode-dark', + themePackage: '@alife/theme-lowcode-light', }], ['ice-plugin-moment-locales', { locales: ['zh-cn'], diff --git a/packages/editor/package.json b/packages/editor/package.json index 4e1f2cecb..f08656a28 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -23,13 +23,14 @@ }, "devDependencies": { "@ice/spec": "^0.1.1", - "@types/react": "^16.8.3", - "@types/react-dom": "^16.8.2", "@types/debug": "^4.1.5", "@types/events": "^3.0.0", + "@types/react": "^16.8.3", + "@types/react-dom": "^16.8.2", "@types/store": "^2.0.2", "css-modules-typescript-loader": "^2.0.4", "eslint": "^6.0.1", + "husky": "^4.2.3", "ice-plugin-fusion": "^0.1.4", "ice-plugin-moment-locales": "^0.1.0", "ice-scripts": "^2.0.0", diff --git a/packages/editor/src/config/skeleton.js b/packages/editor/src/config/skeleton.js index 4cb8a7a87..e198bf617 100644 --- a/packages/editor/src/config/skeleton.js +++ b/packages/editor/src/config/skeleton.js @@ -25,7 +25,8 @@ export default { version: '1.0.0' }, pluginProps: { - logo: 'https://img.alicdn.com/tfs/TB1mHYDxQP2gK0jSZPxXXacQpXa-112-64.png' + logo: 'https://img.alicdn.com/tfs/TB1hoI9x1H2gK0jSZFEXXcqMpXa-146-40.png', + href: '/' } }, { @@ -71,7 +72,7 @@ export default { type: 'Custom', props: { align: 'right', - width: 90 + width: 88 }, config: { package: '@ali/lowcode-plugin-undo-redo', @@ -107,8 +108,8 @@ export default { align: 'right', title: 'icon', icon: 'dengpao', - onClick: function(editor) { - alert('icon addon invoke, current activeKey: ' + editor.activeKey); + onClick(editor) { + alert(`icon addon invoke, current activeKey: ${ editor.activeKey}`); } }, config: {}, @@ -198,8 +199,8 @@ export default { align: 'bottom', title: 'icon', icon: 'dengpao', - onClick: function(editor) { - alert('icon addon invoke, current activeKey: ' + editor.activeKey); + onClick(editor) { + alert(`icon addon invoke, current activeKey: ${ editor.activeKey}`); } }, config: {}, @@ -231,7 +232,8 @@ export default { pluginKey: 'rightPanel2', type: 'TabPanel', props: { - title: '属性' + title: '属性', + icon: 'dengpao' }, config: { version: '^1.0.0' diff --git a/packages/editor/src/framework/areaManager.ts b/packages/editor/src/framework/areaManager.ts index ac7f1ed3c..1a943d310 100644 --- a/packages/editor/src/framework/areaManager.ts +++ b/packages/editor/src/framework/areaManager.ts @@ -4,26 +4,34 @@ import { clone, deepEqual } from './utils'; export default class AreaManager { private pluginStatus: PluginStatus; + private config: PluginConfig[]; - constructor(private editor: Editor, private area: string) { + + private editor: Editor; + + private area: string; + + constructor(editor: Editor, area: string) { + this.editor = editor; + this.area = area; this.config = (editor && editor.config && editor.config.plugins && editor.config.plugins[this.area]) || []; this.pluginStatus = clone(editor.pluginStatus); } public isPluginStatusUpdate(pluginType?: string): boolean { const { pluginStatus } = this.editor; - const list = pluginType ? this.config.filter(item => item.type === pluginType) : this.config; + const list = pluginType ? this.config.filter((item): boolean => item.type === pluginType) : this.config; - const isUpdate = list.some(item => !deepEqual(pluginStatus[item.pluginKey], this.pluginStatus[item.pluginKey])); + const isUpdate = list.some((item): boolean => !deepEqual(pluginStatus[item.pluginKey], this.pluginStatus[item.pluginKey])); this.pluginStatus = clone(pluginStatus); return isUpdate; } public getVisiblePluginList(pluginType?: string): PluginConfig[] { - const res = this.config.filter(item => { - return !this.pluginStatus[item.pluginKey] || this.pluginStatus[item.pluginKey].visible; + const res = this.config.filter((item): boolean => { + return !!(!this.pluginStatus[item.pluginKey] || this.pluginStatus[item.pluginKey].visible); }); - return pluginType ? res.filter(item => item.type === pluginType) : res; + return pluginType ? res.filter((item): boolean => item.type === pluginType) : res; } public getPluginConfig(): PluginConfig[] { diff --git a/packages/editor/src/framework/context.ts b/packages/editor/src/framework/context.ts index 78d3ce177..859b79dc4 100644 --- a/packages/editor/src/framework/context.ts +++ b/packages/editor/src/framework/context.ts @@ -1,3 +1,4 @@ import { createContext } from 'react'; + const context = createContext({}); export default context; diff --git a/packages/editor/src/framework/definitions.ts b/packages/editor/src/framework/definitions.ts index 9233b660c..5780d7f41 100644 --- a/packages/editor/src/framework/definitions.ts +++ b/packages/editor/src/framework/definitions.ts @@ -75,7 +75,7 @@ export type ShortCutsConfig = ShortCutConfig[]; export interface ShortCutConfig { keyboard: string; - handler: (editor: Editor, ev: React.KeyboardEventHandler, keymaster: any) => void; + handler: (editor: Editor, ev: Event, keymaster: any) => void; } export type UtilsConfig = UtilConfig[]; @@ -96,7 +96,7 @@ export interface LifeCyclesConfig { export type LocaleType = 'zh-CN' | 'zh-TW' | 'en-US' | 'ja-JP'; export interface I18nMessages { - [propName: string]: string; + [key: string]: string; } export interface I18nConfig { @@ -106,31 +106,47 @@ export interface I18nConfig { 'ja-JP'?: I18nMessages; } -export type I18nFunction = (key: string, params: any) => string; +export type I18nFunction = (key: string, params: any) => string | string[]; export interface Utils { - [propName: string]: (...args) => any; + [key: string]: (...args) => any; } -export interface PluginClass extends React.ComponentClass<{ + +export interface PluginProps { editor: Editor; + config: PluginConfig; + i18n: I18nFunction; + ref?: React.RefObject; [key: string]: any; -}> { - init?: (editor: Editor) => void; - open?: () => any; - close?: () => any; } -export interface PluginComponents { - [propName: string]: PluginClass; + +export type Plugin = React.ReactNode & { + open?: () => boolean| void| Promise; + close?: () => boolean| void| Promise; +} + +export interface PluginSet { + [key: string]: Plugin; +} + +export type PluginClass = React.ComponentType & { + init?: (editor: Editor) => void; +} + +export interface PluginClassSet { + [key: string]: PluginClass; } export interface PluginStatus { - [propName: string]: { - disabled?: boolean; - visible?: boolean; - marked?: boolean; - locked?: boolean; - }; + disabled?: boolean; + visible?: boolean; + marked?: boolean; + locked?: boolean; +} + +export interface PluginStatusSet { + [key: string]: PluginStatus; } diff --git a/packages/editor/src/framework/editor.ts b/packages/editor/src/framework/editor.ts index 6e2217884..49d9e8cb1 100644 --- a/packages/editor/src/framework/editor.ts +++ b/packages/editor/src/framework/editor.ts @@ -1,37 +1,39 @@ import Debug from 'debug'; import EventEmitter from 'events'; import store from 'store'; -import { EditorConfig, HooksConfig, LocaleType, PluginComponents, PluginStatus, Utils } from './definitions'; +import { EditorConfig, HooksConfig, LocaleType, PluginStatusSet, Utils, PluginClassSet, PluginSet } from './definitions'; import { registShortCuts, transformToPromise, unRegistShortCuts } from './utils'; // 根据url参数设置debug选项 -const res = /_?debug=(.*?)(&|$)/.exec(location.search); -if (res && res[1]) { +const debugRegRes = /_?debug=(.*?)(&|$)/.exec(location.search); +if (debugRegRes && debugRegRes[1]) { + // eslint-disable-next-line no-underscore-dangle window.__isDebug = true; - store.storage.write('debug', res[1] === 'true' ? '*' : res[1]); + store.storage.write('debug', debugRegRes[1] === 'true' ? '*' : debugRegRes[1]); } else { window.__isDebug = false; store.remove('debug'); } // 重要,用于矫正画布执行new Function的window对象上下文 -window.__newFunc = funContext => { -return new Function(funContext); +// eslint-disable-next-line no-underscore-dangle +window.__newFunc = (funContext: string): ((...args: any[]) => any) => { + return new Function(funContext); }; // 关闭浏览器前提醒,只有产生过交互才会生效 -window.onbeforeunload = function(e) { - e = e || window.event; +window.onbeforeunload = function(e: Event): string|void { + const ev = e || window.event; // 本地调试不生效 if (location.href.indexOf('localhost') > 0) { return; } const msg = '您确定要离开此页面吗?'; - e.cancelBubble = true; - e.returnValue = msg; + ev.cancelBubble = true; + ev.returnValue = true; if (e.stopPropagation) { e.stopPropagation(); e.preventDefault(); @@ -49,26 +51,41 @@ export interface HooksFuncs { } export default class Editor extends EventEmitter { - public static getInstance = (config: EditorConfig, components: PluginComponents, utils?: Utils): Editor => { + public static getInstance = (config: EditorConfig, components: PluginClassSet, utils?: Utils): Editor => { if (!instance) { instance = new Editor(config, components, utils); } return instance; }; - public pluginStatus: PluginStatus; - public plugins: PluginComponents; + public config: EditorConfig; + + public components: PluginClassSet; + + public utils: Utils; + + public pluginStatus: PluginStatusSet; + + public plugins: PluginSet; + + public locale: LocaleType; public emit: (msg: string, ...args) => void; + public on: (msg: string, handler: (...args) => void) => void; + public once: (msg: string, handler: (...args) => void) => void; + public off: (msg: string, handler: (...args) => void) => void; private hooksFuncs: HooksFuncs; - constructor(public config: EditorConfig, public components: PluginComponents, public utils?: Utils) { + constructor(config: EditorConfig, components: PluginClassSet, utils?: Utils) { super(); + this.config = config; + this.components = components; + this.utils = utils || {}; instance = this; this.init(); } @@ -82,21 +99,21 @@ export default class Editor extends EventEmitter { this.initHooks(hooks || []); this.emit('editor.beforeInit'); - const init = (lifeCycles && lifeCycles.init) || (() => {}); + const init = (lifeCycles && lifeCycles.init) || ((): void => {}); // 用户可以通过设置extensions.init自定义初始化流程; return transformToPromise(init(this)) - .then(() => { + .then((): boolean => { // 注册快捷键 registShortCuts(shortCuts, this); this.emit('editor.afterInit'); return true; }) - .catch(err => { + .catch((err): void => { console.error(err); }); } - public destroy() { + public destroy(): void { debug('destroy'); try { const { hooks = [], shortCuts = [], lifeCycles = {} } = this.config; @@ -107,7 +124,7 @@ export default class Editor extends EventEmitter { } } catch (err) { console.warn(err); - return; + } } @@ -123,7 +140,7 @@ export default class Editor extends EventEmitter { } this[key] = val; } else if (typeof key === 'object') { - Object.keys(key).forEach(item => { + Object.keys(key).forEach((item): void => { this[item] = key[item]; }); } @@ -133,26 +150,26 @@ export default class Editor extends EventEmitter { if (!Array.isArray(events)) { return; } - events.forEach(event => this.on(event, lisenter)); + events.forEach((event): void => this.on(event, lisenter)); } public batchOnce(events: string[], lisenter: (...args) => void): void { if (!Array.isArray(events)) { return; } - events.forEach(event => this.once(event, lisenter)); + events.forEach((event): void => this.once(event, lisenter)); } public batchOff(events: string[], lisenter: (...args) => void): void { if (!Array.isArray(events)) { return; } - events.forEach(event => this.off(event, lisenter)); + events.forEach((event): void => this.off(event, lisenter)); } // 销毁hooks中的消息监听 - private destroyHooks(hooks: HooksConfig = []) { - hooks.forEach((item, idx) => { + private destroyHooks(hooks: HooksConfig = []): void { + hooks.forEach((item, idx): void => { if (typeof this.hooksFuncs[idx] === 'function') { this.off(item.message, this.hooksFuncs[idx]); } @@ -162,8 +179,8 @@ export default class Editor extends EventEmitter { // 初始化hooks中的消息监听 private initHooks(hooks: HooksConfig = []): void { - this.hooksFuncs = hooks.map(item => { - const func = (...args) => { + this.hooksFuncs = hooks.map((item): ((...arg) => void) => { + const func = (...args): void => { item.handler(this, ...args); }; this[item.type](item.message, func); @@ -171,12 +188,12 @@ export default class Editor extends EventEmitter { }); } - private initPluginStatus() { + private initPluginStatus(): PluginStatusSet { const { plugins = {} } = this.config; const pluginAreas = Object.keys(plugins); - const res: PluginStatus = {}; - pluginAreas.forEach(area => { - (plugins[area] || []).forEach(plugin => { + const res: PluginStatusSet = {}; + pluginAreas.forEach((area): void => { + (plugins[area] || []).forEach((plugin): void => { if (plugin.type === 'Divider') { return; } diff --git a/packages/editor/src/framework/index.d.ts b/packages/editor/src/framework/index.d.ts new file mode 100644 index 000000000..369e95da7 --- /dev/null +++ b/packages/editor/src/framework/index.d.ts @@ -0,0 +1,4 @@ +interface Window { + __isDebug?: boolean; + __newFunc?: (funcStr: string) => ((...args: any[]) => any); +} \ No newline at end of file diff --git a/packages/editor/src/framework/index.ts b/packages/editor/src/framework/index.ts index be8b55d0a..72af6e859 100644 --- a/packages/editor/src/framework/index.ts +++ b/packages/editor/src/framework/index.ts @@ -1,9 +1,11 @@ import Editor from './editor'; -export { default as PluginFactory } from './pluginFactory'; -export { default as EditorContext } from './context'; import * as editorUtils from './utils'; import * as editorDefinitions from './definitions'; + +export { default as PluginFactory } from './pluginFactory'; +export { default as EditorContext } from './context'; + export default Editor; export const utils = editorUtils; diff --git a/packages/editor/src/framework/pluginFactory.tsx b/packages/editor/src/framework/pluginFactory.tsx index dea2cd602..d5298b913 100644 --- a/packages/editor/src/framework/pluginFactory.tsx +++ b/packages/editor/src/framework/pluginFactory.tsx @@ -1,7 +1,7 @@ import React, { createRef, PureComponent } from 'react'; import EditorContext from './context'; -import { I18nFunction, PluginConfig } from './definitions'; +import { I18nFunction, PluginConfig, PluginClass, Plugin } from './definitions'; import Editor from './editor'; import { acceptsRef, generateI18n, isEmpty, transformToPromise } from './utils'; @@ -15,18 +15,21 @@ export interface InjectedPluginProps { } export default function pluginFactory( - Comp: React.ComponentType + Comp: PluginClass ): React.ComponentType { class LowcodePlugin extends PureComponent { public static displayName = 'LowcodeEditorPlugin'; - public static defaultProps = { - config: {} - }; + public static contextType = EditorContext; + public static init = Comp.init; - public ref = createRef(); + + public ref: React.RefObject; + private editor: Editor; + private pluginKey: string; + private i18n: I18nFunction; constructor(props, context) { @@ -36,6 +39,7 @@ export default function pluginFactory( return; } const { locale, messages, editor } = props; + this.ref = createRef(); // 注册插件 this.editor = editor; this.i18n = generateI18n(locale, messages); @@ -46,7 +50,7 @@ export default function pluginFactory( }); } - public componentWillUnmount() { + public componentWillUnmount(): void { // 销毁插件 if (this.editor && this.editor.plugins) { delete this.editor.plugins[this.pluginKey]; @@ -60,14 +64,15 @@ export default function pluginFactory( return Promise.resolve(); }; - public close = () => { + public close = (): Promise => { if (this.ref && this.ref.close && typeof this.ref.close === 'function') { return transformToPromise(this.ref.close()); } return Promise.resolve(); }; - public render() { + + public render(): React.ReactNode { const { config } = this.props; const props = { i18n: this.i18n, diff --git a/packages/editor/src/framework/utils.ts b/packages/editor/src/framework/utils.ts index 794b0c9d3..13cd26f80 100644 --- a/packages/editor/src/framework/utils.ts +++ b/packages/editor/src/framework/utils.ts @@ -1,7 +1,5 @@ import IntlMessageFormat from 'intl-messageformat'; import keymaster from 'keymaster'; -import { EditorConfig, I18nFunction, I18nMessages, LocaleType, ShortCutsConfig } from './definitions'; -import Editor from './editor'; import _clone from 'lodash/cloneDeep'; import _debounce from 'lodash/debounce'; @@ -10,6 +8,10 @@ import _deepEqual from 'lodash/isEqualWith'; import _pick from 'lodash/pick'; import _throttle from 'lodash/throttle'; +import _serialize from 'serialize-javascript'; +import Editor from './editor'; +import { EditorConfig, I18nFunction, I18nMessages, LocaleType, ShortCutsConfig } from './definitions'; + export const pick = _pick; export const deepEqual = _deepEqual; export const clone = _clone; @@ -17,7 +19,6 @@ export const isEmpty = _isEmpty; export const throttle = _throttle; export const debounce = _debounce; -import _serialize from 'serialize-javascript'; export const serialize = _serialize; const ENV = { @@ -36,11 +37,16 @@ export interface IDEMessageParams { }; } +export interface Window { + sendIDEMessage: (msg: IDEMessageParams) => void; + is_theia?: boolean; +} + /* * 用于构造国际化字符串处理函数 */ export function generateI18n(locale: LocaleType = 'zh-CN', messages: I18nMessages = {}): I18nFunction { - return (key: string, values): string => { + return (key: string, values): string | string[] => { if (!messages || !messages[key]) { return ''; } @@ -57,7 +63,7 @@ export function serializeParams(obj: object): string { return ''; } const res: string[] = []; - Object.entries(obj).forEach(([key, val]) => { + Object.entries(obj).forEach(([key, val]): void => { if (val === null || val === undefined || val === '') { return; } @@ -115,8 +121,8 @@ export function getEnv(): string { // 注册快捷键 export function registShortCuts(config: ShortCutsConfig, editor: Editor): void { - (config || []).forEach(item => { - keymaster(item.keyboard, ev => { + (config || []).forEach((item): void => { + keymaster(item.keyboard, (ev: Event): void => { ev.preventDefault(); item.handler(editor, ev, keymaster); }); @@ -125,7 +131,7 @@ export function registShortCuts(config: ShortCutsConfig, editor: Editor): void { // 取消注册快捷 export function unRegistShortCuts(config: ShortCutsConfig): void { - (config || []).forEach(item => { + (config || []).forEach((item): void => { keymaster.unbind(item.keyboard); }); if (window.parent.vscode) { @@ -141,7 +147,7 @@ export function transformToPromise(input: any): Promise<{}> { if (input instanceof Promise) { return input; } - return new Promise((resolve, reject) => { + return new Promise((resolve, reject): void => { if (input || input === undefined) { resolve(); } else { @@ -161,7 +167,7 @@ export function transformArrayToMap(arr: T[], key: string, overwrite: boolean return {}; } const res = {}; - arr.forEach(item => { + arr.forEach((item): void => { const curKey = item[key]; if (item[key] === undefined) { return; @@ -187,7 +193,7 @@ export function parseSearch(search: string): Query { const str = search.replace(/^\?/, ''); const paramStr = str.split('&'); const res = {}; - paramStr.forEach(item => { + paramStr.forEach((item): void => { const regRes = item.split('='); if (regRes[0] && regRes[1]) { res[regRes[0]] = decodeURIComponent(regRes[1]); @@ -210,7 +216,7 @@ export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig const customShortCuts = transformArrayToMap(shortCuts || [], 'keyboard'); const localeList = ['zh-CN', 'zh-TW', 'en-US', 'ja-JP']; const i18nConfig = {}; - localeList.forEach(key => { + localeList.forEach((key): void => { i18nConfig[key] = { ...(defaultConfig.i18n && defaultConfig.i18n[key]), ...(i18n && i18n[key]) @@ -248,9 +254,12 @@ export function comboEditorConfig(defaultConfig: EditorConfig = {}, customConfig * 判断当前组件是否能够设置ref * @param {*} Comp 需要判断的组件 */ -export function acceptsRef(Comp: React.ComponentType) { +export function acceptsRef(Comp: React.ReactNode): boolean { const hasSymbol = typeof Symbol === 'function' && Symbol.for; const REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; + if (!Comp || typeof Comp !== 'object' || isEmpty(Comp)) { + return false; + } return ( (Comp.$$typeof && Comp.$$typeof === REACT_FORWARD_REF_TYPE) || (Comp.prototype && Comp.prototype.isReactComponent) ); diff --git a/packages/editor/src/plugins/logo/index.scss b/packages/editor/src/plugins/logo/index.scss index e2701fbca..338b4c58a 100644 --- a/packages/editor/src/plugins/logo/index.scss +++ b/packages/editor/src/plugins/logo/index.scss @@ -1,9 +1,13 @@ .lowcode-plugin-logo { - padding: 8px 16px; + padding: 14px 8px; + padding-left: 8px; .logo { + display: block; width: 56px; - height: 32px; + height: 20px; + cursor: pointer; background-size: contain; background-position: center; + background-repeat: no-repeat; } } diff --git a/packages/editor/src/plugins/logo/index.tsx b/packages/editor/src/plugins/logo/index.tsx index c02bf7a71..5a60799a0 100644 --- a/packages/editor/src/plugins/logo/index.tsx +++ b/packages/editor/src/plugins/logo/index.tsx @@ -7,12 +7,13 @@ export interface PluginProps { editor: Editor; config: PluginConfig; logo?: string; + href?: string; } export default function(props: PluginProps) { return (
-
+
); } diff --git a/packages/editor/src/skeleton/components/LeftPlugin/index.scss b/packages/editor/src/skeleton/components/LeftPlugin/index.scss index 050a8ec4d..d237581b0 100644 --- a/packages/editor/src/skeleton/components/LeftPlugin/index.scss +++ b/packages/editor/src/skeleton/components/LeftPlugin/index.scss @@ -1,22 +1,16 @@ .lowcode-left-plugin { - font-size: 16px; + font-size: 20px; text-align: center; - line-height: 36px; - height: 36px; + line-height: 44px; + height: 44px; position: relative; cursor: pointer; transition: all 0.3s ease; color: $color-text1-3; - &.collapse { - height: 40px; - border-bottom: 1px solid $color-line1-1; - opacity: 0.6; - } &.locked { color: red !important; } &:hover { - background-color: $color-brand1-1; color: $color-brand1-6; &:before { content: attr(data-tooltip); @@ -29,8 +23,8 @@ white-space: nowrap; padding: 6px 8px; border-radius: 4px; - background: rgba(0, 0, 0, 0.75); - color: #fff; + background: $balloon-tooltip-color-bg; + color: $color-text1-3; z-index: 100; } &:after { @@ -40,17 +34,18 @@ left: 40px; top: 15px; border: 5px solid transparent; - border-right-color: rgba(0, 0, 0, 0.75); + border-right: 5px solid $balloon-tooltip-color-bg; z-index: 100; } } &.active { - color: $color-white; - background-color: $color-brand1-9; + color: $color-brand1-9; &.disabled { - color: $color-white; - background-color: $color-fill1-4; + color: $color-text1-1; } + &:hover { + color: $color-brand1-6; + } } &.disabled { cursor: not-allowed; diff --git a/packages/editor/src/skeleton/components/LeftPlugin/index.tsx b/packages/editor/src/skeleton/components/LeftPlugin/index.tsx index 6d807548c..a2cfe1571 100644 --- a/packages/editor/src/skeleton/components/LeftPlugin/index.tsx +++ b/packages/editor/src/skeleton/components/LeftPlugin/index.tsx @@ -82,7 +82,7 @@ export default class LeftPlugin extends PureComponent editor.emit(`${pluginKey}.addon.activate`), 0); this.handleOpen(); onClick && onClick(); @@ -102,7 +102,7 @@ export default class LeftPlugin extends PureComponent { if (disabled) return; - //考虑到弹窗情况,延时发送消息 + // 考虑到弹窗情况,延时发送消息 clickCallback && clickCallback(); onClick && onClick(); }} @@ -169,6 +169,10 @@ export default class LeftPlugin extends PureComponent diff --git a/packages/editor/src/skeleton/components/TopIcon/index.scss b/packages/editor/src/skeleton/components/TopIcon/index.scss index 0375269d9..2dd2e3bb7 100644 --- a/packages/editor/src/skeleton/components/TopIcon/index.scss +++ b/packages/editor/src/skeleton/components/TopIcon/index.scss @@ -1,21 +1,27 @@ -.next-btn.next-large.lowcode-top-btn { +.lowcode-top-icon { + display: inline-block; width: 44px; - height: 44px; - padding: 0; - margin: 2px -2px; - text-align: center; - border-radius: 8px; - border: 1px solid transparent; + font-size: 20px; + line-height: 48px; color: $color-text1-3; + position: relative; &.disabled { cursor: not-allowed; color: $color-text1-1; + &:hover { + color: $color-text1-1; + } + } + &.active { + color: $color-brand1-9; + &:hover { + color: $color-brand1-6; + } } &.locked { color: red !important; } &:hover { - background-color: $color-brand1-1; color: $color-brand1-6; &:before { content: attr(data-tooltip); @@ -31,8 +37,8 @@ white-space: nowrap; padding: 6px 8px; border-radius: 4px; - background: rgba(0, 0, 0, 0.75); - color: #fff; + background: $balloon-tooltip-color-bg; + color: $color-text1-3; z-index: 100; } &:after { @@ -43,7 +49,7 @@ transform: translate(-50%, 0); bottom: -5px; border: 5px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.75); + border-bottom-color: $balloon-tooltip-color-bg; opacity: 1; visibility: visible; z-index: 100; diff --git a/packages/editor/src/skeleton/components/TopIcon/index.tsx b/packages/editor/src/skeleton/components/TopIcon/index.tsx index 64d27a6d7..40750d03a 100644 --- a/packages/editor/src/skeleton/components/TopIcon/index.tsx +++ b/packages/editor/src/skeleton/components/TopIcon/index.tsx @@ -13,13 +13,13 @@ export interface TopIconProps { locked?: boolean; marked?: boolean; onClick?: () => void; - showTitle?: boolean; style?: React.CSSProperties; title?: string; } export default class TopIcon extends PureComponent { static displayName = 'LowcodeTopIcon'; + static defaultProps = { active: false, className: '', @@ -28,33 +28,23 @@ export default class TopIcon extends PureComponent { id: '', locked: false, onClick: () => {}, - showTitle: false, style: {}, title: '' }; render() { - const { active, disabled, icon, locked, title, className, id, style, showTitle, onClick } = this.props; + const { active, disabled, icon, locked, title, className, id, style, onClick } = this.props; return ( - +
+ +
); } } diff --git a/packages/editor/src/skeleton/components/TopPlugin/index.tsx b/packages/editor/src/skeleton/components/TopPlugin/index.tsx index 6c4f280d0..e51893b15 100644 --- a/packages/editor/src/skeleton/components/TopPlugin/index.tsx +++ b/packages/editor/src/skeleton/components/TopPlugin/index.tsx @@ -1,7 +1,7 @@ import React, { PureComponent, Fragment } from 'react'; -import TopIcon from '../TopIcon'; import { Balloon, Badge, Dialog } from '@alifd/next'; +import TopIcon from '../TopIcon'; import './index.scss'; import { PluginConfig, PluginClass } from '../../../framework/definitions'; @@ -63,8 +63,8 @@ export default class TopPlugin extends PureComponent editor.emit(`${pluginKey}.addon.activate`), 0); + // 考虑到弹窗情况,延时发送消息 + setTimeout(() => editor.emit(`${pluginKey}.plugin.activate`), 0); this.handleOpen(); onClick && onClick(); }; @@ -95,7 +95,7 @@ export default class TopPlugin extends PureComponent { if (disabled) return; - //考虑到弹窗情况,延时发送消息 - setTimeout(() => editor.emit(`${pluginKey}.addon.activate`), 0); + // 考虑到弹窗情况,延时发送消息 + setTimeout(() => editor.emit(`${pluginKey}.plugin.activate`), 0); clickCallback && clickCallback(); onClick && onClick(); }} @@ -163,6 +163,10 @@ export default class TopPlugin extends PureComponent diff --git a/packages/editor/src/skeleton/global.scss b/packages/editor/src/skeleton/global.scss index b0ad64e06..8eb107e0f 100644 --- a/packages/editor/src/skeleton/global.scss +++ b/packages/editor/src/skeleton/global.scss @@ -18,7 +18,7 @@ body { .lowcode-editor { .lowcode-main-content { position: absolute; - top: 48px; + top: 50px; left: 0; right: 0; bottom: 0; diff --git a/packages/editor/src/skeleton/layouts/LeftArea/index.scss b/packages/editor/src/skeleton/layouts/LeftArea/index.scss index e96315458..8c69f42fc 100644 --- a/packages/editor/src/skeleton/layouts/LeftArea/index.scss +++ b/packages/editor/src/skeleton/layouts/LeftArea/index.scss @@ -1,20 +1,22 @@ .lowcode-left-area-nav { - width: 48px; + width: 50px; height: 100%; background-color: $card-background; - border-right: 1px solid $color-line1-1; + border-right: 2px solid $color-line1-1; position: relative; .top-area { position: absolute; top: 0; width: 100%; + padding: 12px 0; background-color: $card-background; max-height: 100%; } .bottom-area { position: absolute; - bottom: 20px; + bottom: 0; width: 100%; + padding: 12px 0; background-color: $card-background; max-height: calc(100% - 20px); } diff --git a/packages/editor/src/skeleton/layouts/LeftArea/nav.tsx b/packages/editor/src/skeleton/layouts/LeftArea/nav.tsx index bba8a824f..61ba3791a 100644 --- a/packages/editor/src/skeleton/layouts/LeftArea/nav.tsx +++ b/packages/editor/src/skeleton/layouts/LeftArea/nav.tsx @@ -5,6 +5,7 @@ import Editor from '../../../framework/editor'; import { PluginConfig } from '../../../framework/definitions'; import AreaManager from '../../../framework/areaManager'; import { isEmpty } from '../../../framework/utils'; + export interface LeftAreaNavProps { editor: Editor; } @@ -17,7 +18,9 @@ export default class LeftAreaNav extends PureComponent { - const { activeKey } = this.state; - if (activeKey === 'none') { - const plugin = this.editor.plugins[this.cacheActiveKey]; - if (plugin) { - plugin.open().then(() => { - this.updateActiveKey(this.cacheActiveKey); - }); - } - } else { - const plugin = this.editor.plugins[activeKey]; - if (plugin) { - plugin.close().then(() => { - this.updateActiveKey('none'); - }); - } - } - }; + // handleCollapseClick = (): void => { + // const { activeKey } = this.state; + // if (activeKey === 'none') { + // const plugin = this.editor.plugins[this.cacheActiveKey]; + // if (plugin) { + // plugin.open().then(() => { + // this.updateActiveKey(this.cacheActiveKey); + // }); + // } + // } else { + // const plugin = this.editor.plugins[activeKey]; + // if (plugin) { + // plugin.close().then(() => { + // this.updateActiveKey('none'); + // }); + // } + // } + // }; handlePluginClick = (item: PluginConfig): void => { if (item.type === 'PanelIcon') { @@ -115,7 +119,7 @@ export default class LeftAreaNav extends PureComponent = []): Array => { + renderPluginList = (list: PluginConfig[] = []): React.ReactElement[] => { const { activeKey } = this.state; return list.map((item, idx) => { const pluginStatus = this.editor.pluginStatus[item.pluginKey]; @@ -135,8 +139,8 @@ export default class LeftAreaNav extends PureComponent = []; - const bottomList: Array = []; + const topList: PluginConfig[] = []; + const bottomList: PluginConfig[] = []; const visiblePluginList = this.areaManager.getVisiblePluginList(); if (isEmpty(visiblePluginList)){ return null; @@ -154,7 +158,7 @@ export default class LeftAreaNav extends PureComponent
{this.renderPluginList(bottomList)}
- + /> */} {this.renderPluginList(topList)}
diff --git a/packages/editor/src/skeleton/layouts/RightArea/index.scss b/packages/editor/src/skeleton/layouts/RightArea/index.scss index fc7b4300a..563179f02 100644 --- a/packages/editor/src/skeleton/layouts/RightArea/index.scss +++ b/packages/editor/src/skeleton/layouts/RightArea/index.scss @@ -1,57 +1,39 @@ .lowcode-right-area { - width: 300px; + width: 262px; height: 100%; background-color: $card-background; - border-left: 1px solid $color-line1-1; - .right-plugin-title { - &.locked { - color: red !important; - } - &.active { - color: $color-brand1-9 !important; - } - &.disabled { - cursor: not-allowed; - color: $color-text1-1; - } - } + border-left: 2px solid $color-line1-1; .right-panel { overflow: auto; - border-top: 1px solid $color-line1-1; + border-top: 2px solid $color-line1-1; } //tab定义 - .next-tabs-wrapped.right-tabs { - display: flex; - flex-direction: column; - margin-top: -1px; - .next-tabs-bar { - z-index: 1; - } + .right-tabs.next-tabs { .next-tabs-nav { - display: block; - .next-tabs-tab { - &:first-child { - border-left: none; - } - font-size: 14px; + width: 100%; + .next-tabs-tab-inner { + padding-left: 0; + padding-right: 0; + } + .right-plugin-title { text-align: center; - border-right: none !important; - margin-right: 0 !important; - width: 25%; + &.locked { + color: red !important; + } &.active { - background: none; - border-bottom-color: $color-line1-1 !important; + color: $color-brand1-9 !important; + } + &.disabled { + cursor: not-allowed; + color: $color-text1-1; + } + .next-icon { + line-height: 15px; + margin-right: 2px; } } } } - .next-tabs-content { - flex: 1; - .next-tabs-tabpane.active { - height: 100%; - overflow-y: auto; - } - } } diff --git a/packages/editor/src/skeleton/layouts/RightArea/index.tsx b/packages/editor/src/skeleton/layouts/RightArea/index.tsx index 2284d643f..8f23ba2a3 100644 --- a/packages/editor/src/skeleton/layouts/RightArea/index.tsx +++ b/packages/editor/src/skeleton/layouts/RightArea/index.tsx @@ -18,6 +18,7 @@ export default class RightArea extends PureComponent (
{!!icon && ( )} {title} @@ -127,43 +124,45 @@ export default class RightArea extends PureComponent { + renderTabPanels = (list: PluginConfig[], height: string): void => { if (isEmpty(list)) { return null; } return ( - {list.map((item, idx) => { - const Comp = this.editor.components[item.pluginKey]; - return ( - - - - ); - })} - + className="right-tabs" + style={{ + height + }} + activeKey={this.state.activeKey} + lazyLoad={false} + onChange={this.handlePluginChange} + > + {list.map((item, idx) => { + const Comp = this.editor.components[item.pluginKey]; + return ( + + + + ); + })} + ); } - renderPanels = (list:PluginConfig[], height: string):void => { + renderPanels = (list: PluginConfig[], height: string): void => { return list.map((item) => { const Comp = this.editor.components[item.pluginKey]; return (
- +
); }); diff --git a/packages/editor/src/skeleton/layouts/TopArea/index.scss b/packages/editor/src/skeleton/layouts/TopArea/index.scss index 66c87c9b1..10669ba51 100644 --- a/packages/editor/src/skeleton/layouts/TopArea/index.scss +++ b/packages/editor/src/skeleton/layouts/TopArea/index.scss @@ -3,23 +3,27 @@ top: 0; left: 0; width: 100%; - height: 48px; + height: 50px; background-color: $card-background; - border-bottom: 1px solid $color-line1-1; + border-bottom: 2px solid $color-line1-1; user-select: none; .divider { max-width: 0; - margin: 8px 12px; - height: 30px; + margin: 12px 16px; + height: 24px; border-right: 1px solid $color-line1-2; } .next-col { text-align: center; } + .left-area { + padding: 0 16px; + } .right-area { position: absolute; right: 12px; top: 0; + padding: 0 16px; height: 100%; background: $card-background; } diff --git a/packages/editor/src/skeleton/layouts/TopArea/index.tsx b/packages/editor/src/skeleton/layouts/TopArea/index.tsx index df8828a9d..39adbb825 100644 --- a/packages/editor/src/skeleton/layouts/TopArea/index.tsx +++ b/packages/editor/src/skeleton/layouts/TopArea/index.tsx @@ -16,6 +16,7 @@ export default class TopArea extends PureComponent { static displayName = 'LowcodeTopArea'; private areaManager: AreaManager; + private editor: Editor; constructor(props) { @@ -27,6 +28,7 @@ export default class TopArea extends PureComponent { componentDidMount() { this.editor.on('skeleton.update', this.handleSkeletonUpdate); } + componentWillUnmount() { this.editor.off('skeleton.update', this.handleSkeletonUpdate); } @@ -38,7 +40,7 @@ export default class TopArea extends PureComponent { } }; - renderPluginList = (list: Array = []): Array => { + renderPluginList = (list: PluginConfig[] = []): React.ReactElement[] => { return list.map((item, idx) => { const isDivider = item.type === 'Divider'; return ( @@ -46,7 +48,7 @@ export default class TopArea extends PureComponent { className={isDivider ? 'divider' : ''} key={isDivider ? idx : item.pluginKey} style={{ - width: (item.props && item.props.width) || 40, + width: (item.props && item.props.width) || 36, flex: 'none' }} > @@ -59,8 +61,8 @@ export default class TopArea extends PureComponent { }; render() { - const leftList: Array = []; - const rightList: Array = []; + const leftList: PluginConfig[] = []; + const rightList: PluginConfig[] = []; const visiblePluginList = this.areaManager.getVisiblePluginList(); visiblePluginList.forEach(item => { const align = item.props && item.props.align === 'right' ? 'right' : 'left';