diff --git a/packages/designer/src/builtins/simulator/renderer/renderer.ts b/packages/designer/src/builtins/simulator/renderer/renderer.ts index 08298fc08..40cb6647d 100644 --- a/packages/designer/src/builtins/simulator/renderer/renderer.ts +++ b/packages/designer/src/builtins/simulator/renderer/renderer.ts @@ -314,7 +314,10 @@ export interface LibraryMap { function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo }) { const components: any = {}; Object.keys(componentsMap).forEach(componentName => { - components[componentName] = findComponent(libraryMap, componentName, componentsMap[componentName]); + const component = findComponent(libraryMap, componentName, componentsMap[componentName]); + if (component) { + components[componentName] = component; + } }); return components; } diff --git a/packages/editor/package.json b/packages/editor/package.json index 9a5add364..6afb24b63 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -4,7 +4,7 @@ "description": "低代码编辑器", "dependencies": { "@ali/iceluna-addon-2": "^1.0.3", - "@ali/iceluna-addon-component-list": "^1.0.10", + "@ali/iceluna-addon-component-list": "^1.0.11", "@ali/iceluna-sdk": "^1.0.5-beta.26", "@alifd/next": "^1.x", "@alife/dpl-iceluna": "^2.3.2", diff --git a/packages/editor/src/config/assets.js b/packages/editor/src/config/assets.js index aa464b50c..7e7c40fef 100644 --- a/packages/editor/src/config/assets.js +++ b/packages/editor/src/config/assets.js @@ -13,6 +13,44 @@ export default { } }, components: { + Page: { + componentName: 'Page', + title: '页面', + configure: { + events: { + supportedLifecycles: [ + { + description: '初始化时', + name: 'constructor', + }, + { + description: '装载后', + name: 'componentDidMount', + }, + { + description: '更新时', + name: 'componentDidMount', + }, + { + description: '卸载时', + name: 'componentWillUnmount', + }, + ] + }, + component: { + isContainer: true, + } + } + }, + Div: { + componentName: 'Div', + title: '容器', + configure: { + component: { + isContainer: true, + } + } + }, Button: { componentName: 'Button', title: '按钮', @@ -164,7 +202,15 @@ export default { name: 'children', propType: 'node' } - ] + ], + configure: { + component: { + isContainer: true, + nestingRule: { + childWhitelist: 'Button' + } + } + } }, Input: { componentName: 'Input', @@ -446,7 +492,12 @@ export default { propType: 'bool', description: '是否开启预览态' } - ] + ], + configure: { + component: { + isContainer: true, + } + } }, 'Form.Item': { componentName: 'Form.Item', @@ -743,7 +794,15 @@ export default { propType: 'func', description: '预览态模式下渲染的内容\n@param {any} value 根据包裹的组件的 value 类型而决定' } - ] + ], + configure: { + component: { + isContainer: true, + nestingRule: { + parentWhitelist: 'Form' + } + } + } }, NumberPicker: { componentName: 'NumberPicker', @@ -1131,7 +1190,199 @@ export default { name: 'locale', propType: 'object' } - ] + ], + configure: { + component: { + isContainer: true, + nestingRule: { + childWhitelist: 'Select.Option' + } + }, + props: [ + { + name: 'mode', + title: '选择器模式', + setter: { + componentName: 'RadioGroupSetter', + props: { + defaultValue: 'single', + dataSource: [ + { + value: 'single', + label: 'single' + }, { + value: 'multiple', + label: 'multiple' + }, { + value: 'tag', + label: 'tag' + } + ] + } + } + }, + { + name: 'mode', + title: '选择器模式', + setter: { + componentName: 'SelectSetter', + props: { + defaultValue: 'single', + dataSource: [ + { + value: 'single', + label: 'single' + }, { + value: 'multiple', + label: 'multiple' + }, { + value: 'tag', + label: 'tag' + } + ] + } + } + }, + { + name: 'value', + title: '当前值,用于受控模式', + placeholder: '混合', + setter: { + componentName: 'MixinSetter', + props: { + types: [{ + name: 'StringSetter', + // 当前mixin setter API + props: {} + }, { + name: 'ExpressionSetter', + props: {} + }, { + name: 'RadioGroupSetter', + // 当前mixin setter API + props: { + hasClear: true, + dataSource: [{ + label: '上', + value: 't', + }, + { + label: '右', + value: 'r', + }, + { + label: '下', + value: 'b', + }, + { + label: '左', + value: 'l', + }] + } + }], + defaultType: 'SelectSetter' + }, + }, + }, + { + name: 'defaultValue', + title: '当前值,用于受控模式', + placeholder: '混合', + setter: { + componentName: 'MixinSetter', + props: { + types: [{ + name: 'StringSetter', + // 当前mixin setter API + props: {} + }, { + name: 'TextAreaSetter', + props: {} + }, { + name: 'SelectSetter', + // 当前mixin setter API + props: { + hasClear: true, + dataSource: [{ + label: '上', + value: 't', + }, + { + label: '右', + value: 'r', + }, + { + label: '下', + value: 'b', + }, + { + label: '左', + value: 'l', + }] + } + }, { + name: 'NumberSetter', + props: {} + }, { + name: 'BoolSetter', + props: {} + }], + defaultType: 'SelectSetter' + }, + }, + }, + { + name: 'hasBorder', + title: '是否有边框', + setter: { + componentName: 'BoolSetter', + props: { + defaultValue: true + } + } + }, + { + name: 'searchValue', + title: '受控搜索值,一般不需要设置\n@type {[type]}', + setter: 'TextAreaSetter' + }, + { + name: 'searchValue', + title: '受控搜索值,一般不需要设置\n@type {[type]}', + setter: 'StringSetter' + }, + { + name: 'maxTagCount', + title: '最多显示多少个 tag', + setter: 'NumberSetter' + }, + { + name: 'maxTagCount', + title: '最多显示多少个 tag', + setter: 'ExpressionSetter' + }, + { + name: 'date', + title: '测试日期', + setter: 'DateSetter' + }, + { + name: 'date', + title: '测试日期-年', + setter: 'DateYearSetter' + }, + { + name: 'date', + title: '测试日期-月', + setter: 'DateMonthSetter' + }, + { + name: 'date', + title: '测试日期-区间', + setter: 'DateRangeSetter' + } + ] + } }, 'Select.Option': { componentName: 'Select.Option', @@ -1162,7 +1413,15 @@ export default { name: 'children', propType: 'any' } - ] + ], + configure: { + component: { + isContainer: true, + nestingRule: { + parentWhitelist: 'Select' + } + } + } } }, componentList: [ @@ -1175,10 +1434,11 @@ export default { title: '按钮', icon: '', package: '@alife/next', + libraryId: 2, snippets: [ { title: 'private', - screenshort: '', + screenshot: 'https://img.alicdn.com/tfs/TB16gZhi.H1gK0jSZSyXXXtlpXa-192-144.png', schema: { componentName: 'Button', props: { @@ -1189,7 +1449,7 @@ export default { }, { title: 'secondary', - screenshort: '', + screenshot: 'https://img.alicdn.com/tfs/TB11Hkji1H2gK0jSZFEXXcqMpXa-192-144.png', schema: { componentName: 'Button', props: { @@ -1200,7 +1460,7 @@ export default { }, { title: 'normal', - screenshort: '', + screenshot: '', schema: { componentName: 'Button', props: { @@ -1219,21 +1479,74 @@ export default { children: [ { componentName: 'Input', + libraryId: 2, title: '输入框', icon: '', package: '@alife/next', snippets: [ { title: '普通', - screenshort: '', + screenshot: '', schema: { componentName: 'Input', props: {} } } ] + }, { + componentName: 'Select', + libraryId: 2, + title: '选择框', + icon: '', + package: '@alife/next', + snippets: [ + { + title: '默认', + screenshot: '', + schema: { + componentName: 'Select', + props: {} + } + } + ] + }, { + componentName: 'NumberPicker', + libraryId: 2, + title: '数字', + icon: '', + package: '@alife/next', + snippets: [ + { + title: '默认', + screenshot: '', + schema: { + componentName: 'NumberPicker', + props: {} + } + } + ] } ] + }, { + title: '其他', + icon: '', + children: [{ + componentName: 'Div', + libraryId: 3, + title: '容器', + icon: '', + snippets: [ + { + title: '默认', + screenshot: '', + schema: { + componentName: 'Div', + props: { + } + } + } + ] + }] } ] }; diff --git a/packages/editor/src/config/setters.ts b/packages/editor/src/config/setters.ts index ba8f607c0..32a404a41 100644 --- a/packages/editor/src/config/setters.ts +++ b/packages/editor/src/config/setters.ts @@ -1,6 +1,7 @@ -import { Input } from '@alifd/next'; -import NumberSetter from '../../../plugin-setters/number-setter'; -import EventsSetter from '../../../plugin-settings/src/builtin-setters/events-setter' +import { DatePicker, Input, Radio, Select, Switch, NumberPicker } from '@alifd/next'; +import ExpressionSetter from '../../../plugin-setters/src/expression-setter'; +import MixinSetter from '../../../plugin-setters/src/mixin-setter'; +import EventsSetter from '../../../plugin-setters/src/events-setter'; import { registerSetter } from '../../../plugin-settings/src'; import { createElement } from 'react'; @@ -15,7 +16,22 @@ registerSetter('ClassNameSetter', () => { }); registerSetter('EventsSetter', EventsSetter); +registerSetter('StringSetter', { component: Input, defaultProps: { placeholder: '请输入' } }); +registerSetter('NumberSetter', NumberPicker); +registerSetter('ExpressionSetter', ExpressionSetter); +registerSetter('MixinSetter', MixinSetter); +registerSetter('BoolSetter', Switch); +registerSetter('RadioGroupSetter', { + component: Radio.Group, + defaultProps: { + shape: 'button' + } +}); +registerSetter('SelectSetter', Select); -registerSetter('StringSetter', { component: Input, props: { placeholder: '请输入' } }); - -registerSetter('NumberSetter', NumberSetter as any); +// suggest: 做成 StringSetter 的一个参数, +registerSetter('TextAreaSetter', Input.TextArea); +registerSetter('DateSetter', DatePicker); +registerSetter('DateYearSetter', DatePicker.YearPicker); +registerSetter('DateMonthSetter', DatePicker.MonthPicker); +registerSetter('DateRangeSetter', DatePicker.RangePicker); diff --git a/packages/editor/src/config/skeleton.js b/packages/editor/src/config/skeleton.js index e9accff99..6fc68aa2a 100644 --- a/packages/editor/src/config/skeleton.js +++ b/packages/editor/src/config/skeleton.js @@ -315,11 +315,10 @@ export default { return { ...comp, name: comp.componentName, - libraryId: 1, snippets: comp.snippets.map(snippet => { return { name: snippet.title, - screenshort: snippet.screenshort, + screenshot: snippet.screenshot, code: JSON.stringify(snippet.schema) }; }) @@ -330,13 +329,17 @@ export default { }; const list = transformMaterial(assets.componentList); + console.log('++++', list); editor.set({ componentsMap: assets.components, componentMaterial: { library: [ { name: 'Fusion组件库', - id: 1 + id: '2' + }, { + name: '其他', + id: '3' } ], list diff --git a/packages/editor/src/plugins/designer/index.tsx b/packages/editor/src/plugins/designer/index.tsx index 3658f07fb..7c559c311 100644 --- a/packages/editor/src/plugins/designer/index.tsx +++ b/packages/editor/src/plugins/designer/index.tsx @@ -23,20 +23,7 @@ const SCHEMA = { componentName: 'Page', fileName: 'test', dataSource: { - list: [ - { - id: 'getComponentsMap', - isInit: true, - type: 'doServer', - options: { - method: 'POST', - params: { - libVersionIds: '1' - }, - uri: 'getComponentsMap' - } - } - ] + list: [] }, state: { text: 'outter' diff --git a/packages/editor/src/skeleton/components/Panel/index.scss b/packages/editor/src/skeleton/components/Panel/index.scss index 5f38863a9..8a9660638 100644 --- a/packages/editor/src/skeleton/components/Panel/index.scss +++ b/packages/editor/src/skeleton/components/Panel/index.scss @@ -16,7 +16,7 @@ position: absolute; top: 0; bottom: 0; - z-index: 99; + z-index: 999; } &.draggable { .drag-area { @@ -41,7 +41,7 @@ } &.left { &.floatable { - left: 48px; + left: 50px; } } &.right { diff --git a/packages/plugin-setters/package.json b/packages/plugin-setters/package.json index 5e02945a3..05ce25bac 100644 --- a/packages/plugin-setters/package.json +++ b/packages/plugin-setters/package.json @@ -1,5 +1,18 @@ { "dependencies": { - "@alifd/next": "^1.19.16" + "@ali/iceluna-comp-expression": "^1.0.6", + "@ali/iceluna-comp-form": "^1.0.20", + "@ali/iceluna-comp-list": "^1.0.26", + "@ali/iceluna-comp-monaco-editor": "^1.0.31", + "@ali/iceluna-comp-object-button": "^1.0.23", + "@ali/iceluna-comp-react-node": "^1.0.5", + "@ali/iceluna-sdk": "^1.0.5-beta.24", + "@alifd/next": "^1.19.16", + "@alife/next": "^1.19.16", + "acorn": "^6.4.1", + "intl-messageformat": "^8.2.1", + "monaco-editor": "^0.20.0", + "qs": "^6.9.1", + "react-monaco-editor": "^0.34.0" } } diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx b/packages/plugin-setters/src/events-setter/event-dialog.tsx similarity index 100% rename from packages/plugin-settings/src/builtin-setters/events-setter/event-dialog.tsx rename to packages/plugin-setters/src/events-setter/event-dialog.tsx diff --git a/packages/plugin-settings/src/builtin-setters/events-setter/index.tsx b/packages/plugin-setters/src/events-setter/index.tsx similarity index 64% rename from packages/plugin-settings/src/builtin-setters/events-setter/index.tsx rename to packages/plugin-setters/src/events-setter/index.tsx index 2db3851e6..4aa1fc673 100644 --- a/packages/plugin-settings/src/builtin-setters/events-setter/index.tsx +++ b/packages/plugin-setters/src/events-setter/index.tsx @@ -1,6 +1,6 @@ import { Component, isValidElement, ReactElement, ReactNode } from 'react'; import { Radio, Menu, Table, Icon, Dialog } from '@alifd/next'; -import {SettingField} from './main'; +import { SettingField } from './main'; import nativeEvents from './native-events'; import './style.less'; @@ -37,9 +37,17 @@ export default class EventsSetter extends Component<{ relatedEventName: '', }; - // TODO: getDerivedStateFromProps recieve eventDataList from prop.value + static getDerivedStateFromProps(nextProps, prevState) { + const { value } = nextProps; + if (value !== prevState.eventDataList) { + return { + value, + }; + } + return null; + } - componentWillMount() { + componentDidMount() { this.initEventBtns(); this.initEventList(); } @@ -50,30 +58,43 @@ export default class EventsSetter extends Component<{ initEventBtns() { const { definition } = this.props; let isRoot = false; + let isCustom = false; + let eventBtns = []; definition.map(item => { if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT) { isRoot = true; } + + if (item.type === DEFINITION_EVENT_TYPE.EVENTS) { + isCustom = true; + } }); + if (isRoot) { + eventBtns = [ + { + value: EVENT_CONTENTS.LIFE_CYCLE_EVENT, + label: '生命周期', + }, + ]; + } else if (isCustom) { + eventBtns = [ + { + value: EVENT_CONTENTS.COMPONENT_EVENT, + label: '组件自带事件', + }, + ]; + } else { + eventBtns = [ + { + value: EVENT_CONTENTS.NATIVE_EVENT, + label: '原生事件', + }, + ]; + } + this.setState({ - eventBtns: !isRoot - ? [ - { - value: EVENT_CONTENTS.COMPONENT_EVENT, - label: '组件自带事件', - }, - { - value: EVENT_CONTENTS.NATIVE_EVENT, - label: '原生事件', - }, - ] - : [ - { - value: EVENT_CONTENTS.LIFE_CYCLE_EVENT, - label: '生命周期', - }, - ], + eventBtns, }); } @@ -82,19 +103,28 @@ export default class EventsSetter extends Component<{ let nativeEventList = []; definition.map(item => { if (item.type === DEFINITION_EVENT_TYPE.EVENTS) { + this.checkEventListStatus(item.list, DEFINITION_EVENT_TYPE.EVENTS); this.setState({ eventList: item.list, }); } if (item.type === DEFINITION_EVENT_TYPE.NATIVE_EVENTS) { + this.checkEventListStatus( + item.list, + DEFINITION_EVENT_TYPE.NATIVE_EVENTS, + ); nativeEventList = item.list; } - if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT){ + if (item.type === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT) { + this.checkEventListStatus( + item.list, + DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT, + ); this.setState({ - lifeCycleEventList:item.list - }) + lifeCycleEventList: item.list, + }); } }); @@ -106,6 +136,35 @@ export default class EventsSetter extends Component<{ } } + checkEventListStatus = (eventList: Array, eventType: String) => { + const { eventDataList } = this.state; + if ( + eventType === DEFINITION_EVENT_TYPE.EVENTS || + eventType === DEFINITION_EVENT_TYPE.LIFE_CYCLE_EVENT + ) { + eventList.map(item => { + item.disabled = false; + eventDataList.map(eventDataItem => { + if (item.name === eventDataItem.name) { + item.disabled = true; + } + }); + }); + } else if (eventType === DEFINITION_EVENT_TYPE.NATIVE_EVENTS) { + eventDataList.map(eventDataItem => { + eventList.map(item => { + item.eventList.map(eventItem => { + if (eventItem.name === eventDataItem.name) { + item.disabled = true; + } else { + item.disabled = false; + } + }); + }); + }); + } + }; + /** * 渲染事件信息 */ @@ -126,7 +185,9 @@ export default class EventsSetter extends Component<{