build: change build-scripts to vite

This commit is contained in:
1ncounter 2024-03-27 10:39:41 +08:00
parent 50465d6499
commit 17f736b130
146 changed files with 2026 additions and 1695 deletions

View File

@ -4,7 +4,10 @@
"mainEntryPointFilePath": "<projectFolder>/temp/index.d.ts",
"compiler": {
"tsconfigFilePath": "<projectFolder>/tsconfig.declaration.json"
"tsconfigFilePath": "<projectFolder>/tsconfig.declaration.json",
"overrideTsconfig": {
"baseUrl": "<projectFolder>/temp"
}
},
"dtsRollup": {

View File

@ -1 +0,0 @@
module.exports = require('../../babel.config');

View File

@ -1,5 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce"
]
}

View File

@ -1,9 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
],
"babelPlugins": [
["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
]
}

View File

@ -1,54 +0,0 @@
const fs = require('fs');
const { join } = require('path');
const esModules = [].join('|');
const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
const jestConfig = {
// transform: {
// '^.+\\.[jt]sx?$': 'babel-jest',
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
// testMatch: ['**/node-children.test.ts'],
// testMatch: ['**/plugin-manager.test.ts'],
// testMatch: ['**/history/history.test.ts'],
// testMatch: ['**/document-model.test.ts'],
// testMatch: ['**/prop.test.ts'],
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
// testMatch: ['**/document/node/node.add.test.ts'],
// testMatch: ['**/setting-field.test.ts'],
// testMatch: ['**/node.test.ts'],
// testMatch: ['**/builtin-hotkey.test.ts'],
// testMatch: ['**/selection.test.ts'],
// testMatch: ['**/plugin/sequencify.test.ts'],
// testMatch: ['**/builtin-simulator/utils/parse-metadata.test.ts'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
setupFiles: ['./tests/fixtures/unhandled-rejection.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
collectCoverage: false,
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/icons/**',
'!src/locale/**',
'!src/builtin-simulator/utils/**',
'!src/plugin/sequencify.ts',
'!src/document/node/exclusive-group.ts',
'!src/document/node/props/value-to-source.ts',
'!src/builtin-simulator/live-editing/live-editing.ts',
'!src/designer/offset-observer.ts',
'!src/designer/clipboard.ts',
'!src/designer/scroller.ts',
'!src/builtin-simulator/host.ts',
'!**/node_modules/**',
'!**/vendor/**',
],
};
// 只对本仓库内的 pkg 做 mapping
jestConfig.moduleNameMapper = {};
jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';
module.exports = jestConfig;

View File

@ -2,47 +2,56 @@
"name": "@alilc/lowcode-designer",
"version": "2.0.0-beta.0",
"description": "Designer for Ali LowCode Engine",
"main": "lib/index.js",
"module": "es/index.js",
"type": "module",
"main": "dist/designer.cjs",
"module": "dist/designer.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/designer.js",
"require": "./dist/designer.cjs",
"types": "./dist/index.d.ts"
}
},
"files": [
"lib",
"es"
"dist",
"src",
"package.json"
],
"scripts": {
"build": "build-scripts build",
"test": "build-scripts test --config build.test.json",
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
"build": "vite build",
"build-dts": "tsc -p tsconfig.declaration.json && node ../../scripts/rollup-dts.mjs",
"test": "vitest",
"test:cov": ""
},
"license": "MIT",
"dependencies": {
"@alilc/lowcode-editor-core": "1.3.2",
"@alilc/lowcode-types": "1.3.2",
"@alilc/lowcode-utils": "1.3.2",
"classnames": "^2.2.6",
"react": "^16",
"react-dom": "^16.7.0",
"@alilc/lowcode-editor-core": "workspace:*",
"@alilc/lowcode-types": "workspace:*",
"@alilc/lowcode-utils": "workspace:*",
"@alifd/next": "^1.27.8",
"classnames": "^2.5.1",
"lodash-es": "^4.17.20",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ric-shim": "^1.0.1",
"semver": "^7.3.5"
"semver": "^7.6.0",
"events": "^3.3.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.29",
"@testing-library/react": "^11.2.2",
"@types/classnames": "^2.2.7",
"@types/enzyme": "^3.10.12",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/jest": "^26.0.16",
"@types/lodash": "^4.14.165",
"@types/medium-editor": "^5.0.3",
"@types/node": "^13.7.1",
"@types/react": "^16",
"@types/react-dom": "^16",
"@types/semver": "7.3.9",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"jest": "^26.6.3",
"lodash": "^4.17.20",
"moment": "^2.29.1",
"typescript": "^4.0.3"
"@testing-library/react": "^14.2.2",
"@types/lodash-es": "^4.14.165",
"@types/prop-types": "^15.7.12",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/semver": "7.5.8",
"less": "^4.2.0"
},
"peerDependencies": {
"@alifd/next": "^1.27.8",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public",

View File

@ -35,9 +35,7 @@ export class BorderDetectingInstance extends PureComponent<{
return (
<div className={className} style={style}>
<Title title={title} className="lc-borders-title" />
{
isLocked ? (<Title title={intl('locked')} className="lc-borders-status" />) : null
}
{isLocked ? <Title title={intl('locked')} className="lc-borders-status" /> : null}
</div>
);
}
@ -77,7 +75,10 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
const { current } = this;
const canHoverHook = current?.componentMeta.advanced.callbacks?.onHoverHook;
const canHover = (canHoverHook && typeof canHoverHook === 'function') ? canHoverHook(current.internalToShellNode()) : true;
const canHover =
canHoverHook && typeof canHoverHook === 'function'
? canHoverHook(current.internalToShellNode()!)
: true;
if (!canHover || !current || host.viewport.scrolling || host.liveEditing.editing) {
return null;
@ -104,7 +105,7 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
);
}
const lockedNode = getClosestNode(current, (n) => {
const lockedNode = getClosestNode(current as any, (n) => {
// 假如当前节点就是 locked 状态,要从当前节点的父节点开始查找
return !!(current?.isLocked ? n.parent?.isLocked : n.isLocked);
});
@ -118,7 +119,10 @@ export class BorderDetecting extends Component<{ host: BuiltinSimulatorHost }> {
scrollX={this.scrollX}
scrollY={this.scrollY}
// @ts-ignore
rect={host.computeComponentInstanceRect(host.getComponentInstances(lockedNode)[0], lockedNode.componentMeta.rootSelector)}
rect={host.computeComponentInstanceRect(
host.getComponentInstances(lockedNode)![0],
lockedNode.componentMeta.rootSelector,
)}
isLocked={lockedNode?.getId() !== current.getId()}
/>
);

View File

@ -89,7 +89,12 @@ export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost;
return null;
}
return (
<BoxResizingInstance key={observed.id} dragging={this.dragging} designer={designer} observed={observed} />
<BoxResizingInstance
key={observed.id}
dragging={this.dragging}
designer={designer}
observed={observed}
/>
);
})}
</Fragment>
@ -135,41 +140,38 @@ export class BoxResizingInstance extends Component<{
// this.hoveringCapture.setBoundary(this.outline);
this.willBind();
const resize = (e: MouseEvent, direction: string, node: INode, moveX: number, moveY: number) => {
const resize = (
e: MouseEvent,
direction: string,
node: INode,
moveX: number,
moveY: number,
) => {
const { advanced } = node.componentMeta;
if (
advanced.callbacks &&
typeof advanced.callbacks.onResize === 'function'
) {
if (advanced.callbacks && typeof advanced.callbacks.onResize === 'function') {
(e as any).trigger = direction;
(e as any).deltaX = moveX;
(e as any).deltaY = moveY;
const cbNode = node?.isNode ? node.internalToShellNode() : node;
advanced.callbacks.onResize(e, cbNode);
advanced.callbacks.onResize(e as any, cbNode);
}
};
const resizeStart = (e: MouseEvent, direction: string, node: INode) => {
const { advanced } = node.componentMeta;
if (
advanced.callbacks &&
typeof advanced.callbacks.onResizeStart === 'function'
) {
if (advanced.callbacks && typeof advanced.callbacks.onResizeStart === 'function') {
(e as any).trigger = direction;
const cbNode = node?.isNode ? node.internalToShellNode() : node;
advanced.callbacks.onResizeStart(e, cbNode);
advanced.callbacks.onResizeStart(e as any, cbNode);
}
};
const resizeEnd = (e: MouseEvent, direction: string, node: INode) => {
const { advanced } = node.componentMeta;
if (
advanced.callbacks &&
typeof advanced.callbacks.onResizeEnd === 'function'
) {
if (advanced.callbacks && typeof advanced.callbacks.onResizeEnd === 'function') {
(e as any).trigger = direction;
const cbNode = node?.isNode ? node.internalToShellNode() : node;
advanced.callbacks.onResizeEnd(e, cbNode);
advanced.callbacks.onResizeEnd(e as any, cbNode as any);
}
const editor = node.document?.designer.editor;
@ -241,14 +243,16 @@ export class BoxResizingInstance extends Component<{
let offsetTop = 0;
let offsetLeft = 0;
if (observed.hasOffset) {
offsetWidth = observed.offsetWidth;
offsetHeight = observed.offsetHeight;
offsetWidth = observed.offsetWidth!;
offsetHeight = observed.offsetHeight!;
offsetTop = observed.offsetTop;
offsetLeft = observed.offsetLeft;
const { node } = observed;
const metadata = node.componentMeta.getMetadata();
if (metadata.configure?.advanced?.getResizingHandlers) {
triggerVisible = metadata.configure.advanced.getResizingHandlers(node.internalToShellNode());
triggerVisible = metadata.configure.advanced.getResizingHandlers(
node.internalToShellNode(),
);
}
}
triggerVisible = normalizeTriggers(triggerVisible);

View File

@ -1,7 +1,6 @@
import {
Component,
Fragment,
ReactNodeArray,
isValidElement,
cloneElement,
createElement,
@ -54,11 +53,8 @@ export class BorderSelectingInstance extends Component<{
}
return (
<div
className={className}
style={style}
>
{(!dragging && !hideComponentAction) ? <Toolbar observed={observed} /> : null}
<div className={className} style={style}>
{!dragging && !hideComponentAction ? <Toolbar observed={observed} /> : null}
</div>
);
}
@ -68,7 +64,7 @@ export class BorderSelectingInstance extends Component<{
class Toolbar extends Component<{ observed: OffsetObserver }> {
render() {
const { observed } = this.props;
const { height, width } = observed.viewport;
const { height, width } = observed.viewport!;
const BAR_HEIGHT = 20;
const MARGIN = 1;
const BORDER = 2;
@ -81,7 +77,7 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
top: -SPACE_HEIGHT,
height: BAR_HEIGHT,
};
} else if (observed.bottom + SPACE_HEIGHT < height) {
} else if (observed.bottom! + SPACE_HEIGHT < height) {
style = {
bottom: -SPACE_HEIGHT,
height: BAR_HEIGHT,
@ -93,21 +89,24 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
};
}
// 计算 toolbar 的左/右位置
if (SPACE_MINIMUM_WIDTH > observed.left + observed.width) {
if (SPACE_MINIMUM_WIDTH > observed.left + observed.width!) {
style.left = Math.max(-BORDER, observed.left - width - BORDER);
} else {
style.right = Math.max(-BORDER, observed.right - width - BORDER);
style.right = Math.max(-BORDER, observed.right! - width - BORDER);
style.justifyContent = 'flex-start';
}
const { node } = observed;
const actions: ReactNodeArray = [];
const actions: ReactNode[] = [];
node.componentMeta.availableActions.forEach((action) => {
const { important = true, condition, content, name } = action;
if (node.isSlot() && (name === 'copy' || name === 'remove')) {
// FIXME: need this?
return;
}
if (important && (typeof condition === 'function' ? condition(node) !== false : condition !== false)) {
if (
important &&
(typeof condition === 'function' ? condition(node) !== false : condition !== false)
) {
actions.push(createAction(content, name, node));
}
});
@ -120,7 +119,11 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
}
}
function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject, key: string, node: INode) {
function createAction(
content: ReactNode | ComponentType<any> | IPublicTypeActionContentObject,
key: string,
node: INode,
) {
if (isValidElement<{ key: string; node: INode }>(content)) {
return cloneElement(content, { key, node });
}
@ -148,7 +151,7 @@ function createAction(content: ReactNode | ComponentType<any> | IPublicTypeActio
}}
>
{icon && createIcon(icon, { key, node: node.internalToShellNode() })}
<Tip>{title}</Tip>
<Tip>{title as any}</Tip>
</div>
);
}
@ -187,7 +190,13 @@ export class BorderSelectingForNode extends Component<{ host: ISimulatorHost; no
if (!observed) {
return null;
}
return <BorderSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
return (
<BorderSelectingInstance
key={observed.id}
dragging={this.dragging}
observed={observed}
/>
);
})}
</Fragment>
);

View File

@ -52,7 +52,7 @@ export default class DragResizeEngine {
if (!sourceDocument || sourceDocument === document) {
return e;
}
const srcSim = masterSensors.find(sim => sim.contentDocument === sourceDocument);
const srcSim = masterSensors.find((sim) => sim.contentDocument === sourceDocument);
if (srcSim) {
return srcSim.viewport.toGlobalPoint(e);
}
@ -61,7 +61,7 @@ export default class DragResizeEngine {
const over = (e: MouseEvent) => {
const handleEvents = makeEventsHandler(e, masterSensors);
handleEvents(doc => {
handleEvents((doc) => {
doc.removeEventListener('mousemove', move, true);
doc.removeEventListener('mouseup', over, true);
});
@ -77,7 +77,7 @@ export default class DragResizeEngine {
node = boost(e);
startEvent = createResizeEvent(e);
const handleEvents = makeEventsHandler(e, masterSensors);
handleEvents(doc => {
handleEvents((doc) => {
doc.addEventListener('mousemove', move, true);
doc.addEventListener('mouseup', over, true);
});
@ -87,9 +87,9 @@ export default class DragResizeEngine {
this.designer.detecting.enable = false;
cursor.addState('ew-resize');
};
shell.addEventListener('mousedown', mousedown);
shell.addEventListener('mousedown', mousedown as any);
return () => {
shell.removeEventListener('mousedown', mousedown);
shell.removeEventListener('mousedown', mousedown as any);
};
}
@ -118,7 +118,7 @@ export default class DragResizeEngine {
private getMasterSensors(): ISimulatorHost[] {
return this.designer.project.documents
.map(doc => {
.map((doc) => {
if (doc.active && doc.simulator?.sensorAvailable) {
return doc.simulator;
}

View File

@ -1,14 +1,15 @@
import { Component } from 'react';
import { observer } from '@alilc/lowcode-editor-core';
import { BuiltinSimulatorHost } from '../host';
import {
DropLocation,
isVertical,
} from '../../designer';
import { DropLocation, isVertical } from '../../designer';
import { ISimulatorHost } from '../../simulator';
import { INode } from '../../document';
import './insertion.less';
import { IPublicTypeNodeData, IPublicTypeNodeSchema, IPublicTypeLocationChildrenDetail, IPublicTypeRect } from '@alilc/lowcode-types';
import {
IPublicTypeNodeData,
IPublicTypeLocationChildrenDetail,
IPublicTypeRect,
} from '@alilc/lowcode-types';
import { isLocationChildrenDetail } from '@alilc/lowcode-utils';
interface InsertionData {
@ -23,7 +24,11 @@ interface InsertionData {
/**
* (INode)
*/
function processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IPublicTypeLocationChildrenDetail): InsertionData {
function processChildrenDetail(
sim: ISimulatorHost,
container: INode,
detail: IPublicTypeLocationChildrenDetail,
): InsertionData {
let edge = detail.edge || null;
if (!edge) {
@ -40,7 +45,7 @@ function processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IP
if (detail.near) {
const { node, pos, rect, align } = detail.near;
ret.nearRect = rect || sim.computeRect(node);
ret.nearRect = rect || sim.computeRect(node as any);
ret.nearNode = node;
if (pos === 'replace') {
// FIXME: ret.nearRect mybe null
@ -65,10 +70,10 @@ function processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IP
ret.insertType = 'cover';
return ret;
}
let nearNode = container.children.get(index);
let nearNode = container.children?.get(index);
if (!nearNode) {
// index = 0, eg. nochild,
nearNode = container.children.get(index > 0 ? index - 1 : 0);
nearNode = container.children?.get(index > 0 ? index - 1 : 0);
if (!nearNode) {
ret.insertType = 'cover';
ret.coverRect = edge;
@ -95,7 +100,7 @@ function processChildrenDetail(sim: ISimulatorHost, container: INode, detail: IP
* detail "坐标"
*/
function processDetail({ target, detail, document }: DropLocation): InsertionData {
const sim = document.simulator;
const sim = document!.simulator;
if (!sim) {
return {};
}
@ -126,7 +131,7 @@ export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
}
const { scale, scrollX, scrollY } = host.viewport;
const { edge, insertType, coverRect, nearRect, vertical, nearNode } = processDetail(loc);
const { edge, insertType, coverRect, nearRect, vertical, nearNode } = processDetail(loc as any);
if (!edge) {
return null;
@ -159,7 +164,7 @@ export class InsertionView extends Component<{ host: BuiltinSimulatorHost }> {
y = ((insertType === 'before' ? nearRect.top : nearRect.bottom) + scrollY) * scale;
style.width = nearRect.width * scale;
}
if (y === 0 && (nearNode as IPublicTypeNodeSchema)?.componentMeta?.isTopFixed) {
if (y === 0 && (nearNode as any)?.componentMeta?.isTopFixed) {
return null;
}
}

View File

@ -14,11 +14,7 @@ import {
IEventBus,
} from '@alilc/lowcode-editor-core';
import {
ISimulatorHost,
Component,
DropContainer,
} from '../simulator';
import { ISimulatorHost, Component, DropContainer } from '../simulator';
import Viewport from './viewport';
import { createSimulator } from './create-simulator';
import { Node, INode, contains, isRootNode, isLowCodeComponent } from '../document';
@ -71,7 +67,7 @@ import { LiveEditing } from './live-editing/live-editing';
import { IProject, Project } from '../project';
import { IScroller } from '../designer/scroller';
import { isElementNode, isDOMNodeVisible } from '../utils/misc';
import { debounce } from 'lodash';
import { debounce } from 'lodash-es';
const logger = new Logger({ level: 'warn', bizName: 'designer' });
@ -352,24 +348,30 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
*/
connect(
renderer: BuiltinSimulatorRenderer,
effect: (reaction: IReactionPublic) => void, options?: IReactionOptions,
effect: (reaction: IReactionPublic) => void,
options?: IReactionOptions<any, boolean>,
) {
this._renderer = renderer;
return autorun(effect, options);
}
reaction(expression: (reaction: IReactionPublic) => unknown, effect: (value: unknown, prev: unknown, reaction: IReactionPublic) => void,
opts?: IReactionOptions | undefined): IReactionDisposer {
reaction(
expression: (reaction: IReactionPublic) => unknown,
effect: (value: unknown, prev: unknown, reaction: IReactionPublic) => void,
opts?: IReactionOptions<any, boolean> | undefined,
): IReactionDisposer {
return reaction(expression, effect, opts);
}
autorun(effect: (reaction: IReactionPublic) => void, options?: IReactionOptions): IReactionDisposer {
autorun(
effect: (reaction: IReactionPublic) => void,
options?: IReactionOptions<any, boolean>,
): IReactionDisposer {
return autorun(effect, options);
}
purge(): void {
// todo
}
mountViewport(viewport: HTMLElement | null) {
@ -450,11 +452,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const vendors = [
// required & use once
assetBundle(
this.get('environment') ||
defaultEnvironment,
AssetLevel.Environment,
),
assetBundle(this.get('environment') || defaultEnvironment, AssetLevel.Environment),
// required & use once
assetBundle(this.get('extraEnvironment'), AssetLevel.Environment),
@ -463,11 +461,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// required & TODO: think of update
assetBundle(this.theme, AssetLevel.Theme),
// required & use once
assetBundle(
this.get('simulatorUrl') ||
defaultSimulatorUrl,
AssetLevel.Runtime,
),
assetBundle(this.get('simulatorUrl') || defaultSimulatorUrl, AssetLevel.Runtime),
];
// wait 准备 iframe 内容、依赖库注入
@ -555,8 +549,8 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return;
}
// FIXME: dirty fix remove label-for fro liveEditing
downEvent.target?.removeAttribute('for');
const nodeInst = this.getNodeInstanceFromElement(downEvent.target);
(downEvent.target as any)?.removeAttribute('for');
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as any);
const { focusNode } = documentModel;
const node = getClosestClickableNode(nodeInst?.node || focusNode, downEvent);
// 如果找不到可点击的节点,直接返回
@ -572,7 +566,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const isRGLNode = rglNode?.isRGLContainer;
if (isRGLNode) {
// 如果拖拽的是磁铁块的右下角 handle则直接跳过
if (downEvent.target?.classList.contains('react-resizable-handle')) return;
if ((downEvent.target as any)?.classList.contains('react-resizable-handle')) return;
// 禁止多选
isMulti = false;
designer.dragon.emitter.emit('rgl.switch', {
@ -649,7 +643,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
{
type: IPublicEnumDragObjectType.Node,
nodes,
},
} as any,
downEvent,
isRGLNode ? rglNode : undefined,
);
@ -697,10 +691,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
'.next-calendar-table',
'.editor-container', // 富文本组件
];
const ignoreSelectors = customizeIgnoreSelectors?.(defaultIgnoreSelectors, e) || defaultIgnoreSelectors;
const ignoreSelectors =
customizeIgnoreSelectors?.(defaultIgnoreSelectors, e) || defaultIgnoreSelectors;
const ignoreSelectorsString = ignoreSelectors.join(',');
// 提供了 customizeIgnoreSelectors 的情况下,忽略 isFormEvent() 判断
if ((!customizeIgnoreSelectors && isFormEvent(e)) || target?.closest(ignoreSelectorsString)) {
if (
(!customizeIgnoreSelectors && isFormEvent(e)) ||
(target as any)?.closest(ignoreSelectorsString)
) {
e.preventDefault();
e.stopPropagation();
}
@ -918,7 +916,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
* @see ISimulator
*/
getComponentInstances(node: INode, context?: IPublicTypeNodeInstance): IPublicTypeComponentInstance[] | null {
getComponentInstances(
node: INode,
context?: IPublicTypeNodeInstance,
): IPublicTypeComponentInstance[] | null {
const docId = node.document?.id;
if (!docId) {
return null;
@ -966,7 +967,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
* @see ISimulator
*/
computeComponentInstanceRect(instance: IPublicTypeComponentInstance, selector?: string): IPublicTypeRect | null {
computeComponentInstanceRect(
instance: IPublicTypeComponentInstance,
selector?: string,
): IPublicTypeRect | null {
const renderer = this.renderer!;
const elements = this.findDOMNodes(instance, selector);
if (!elements) {
@ -1032,7 +1036,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
* @see ISimulator
*/
findDOMNodes(instance: IPublicTypeComponentInstance, selector?: string): Array<Element | Text> | null {
findDOMNodes(
instance: IPublicTypeComponentInstance,
selector?: string,
): Array<Element | Text> | null {
const elements = this._renderer?.findDOMNodes(instance);
if (!elements) {
return null;
@ -1051,7 +1058,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
* DOM simulator
*/
getNodeInstanceFromElement(target: Element | null): IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | null {
getNodeInstanceFromElement(
target: Element | null,
): IPublicTypeNodeInstance<IPublicTypeComponentInstance, INode> | null {
if (!target) {
return null;
}
@ -1191,9 +1200,12 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const nodes = dragObject?.nodes;
const operationalNodes = nodes?.filter((node) => {
const operationalNodes = nodes?.filter((node: any) => {
const onMoveHook = node.componentMeta?.advanced.callbacks?.onMoveHook;
const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook(node.internalToShellNode()) : true;
const canMove =
onMoveHook && typeof onMoveHook === 'function'
? onMoveHook(node.internalToShellNode())
: true;
let parentContainerNode: INode | null = null;
let parentNode = node.parent;
@ -1207,9 +1219,16 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
parentNode = parentNode.parent;
}
const onChildMoveHook = parentContainerNode?.componentMeta?.advanced.callbacks?.onChildMoveHook;
const onChildMoveHook =
parentContainerNode?.componentMeta?.advanced.callbacks?.onChildMoveHook;
const childrenCanMove = onChildMoveHook && parentContainerNode && typeof onChildMoveHook === 'function' ? onChildMoveHook(node.internalToShellNode(), parentContainerNode.internalToShellNode()) : true;
const childrenCanMove =
onChildMoveHook && parentContainerNode && typeof onChildMoveHook === 'function'
? onChildMoveHook(
node!.internalToShellNode(),
(parentContainerNode as any).internalToShellNode(),
)
: true;
return canMove && childrenCanMove;
});
@ -1225,16 +1244,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return null;
}
const dropContainer = this.getDropContainer(e);
const lockedNode = getClosestNode(dropContainer?.container, (node) => node.isLocked);
const lockedNode = getClosestNode(dropContainer?.container as any, (node) => node.isLocked);
if (lockedNode) return null;
if (
!dropContainer
) {
if (!dropContainer) {
return null;
}
if (isLocationData(dropContainer)) {
return this.designer.createLocation(dropContainer);
return this.designer.createLocation(dropContainer as any);
}
const { container, instance: containerInstance } = dropContainer;
@ -1267,7 +1284,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
e.dragObject &&
e.dragObject.nodes &&
e.dragObject.nodes.length &&
e.dragObject.nodes[0].componentMeta.isModal &&
e.dragObject.nodes[0]?.componentMeta?.isModal &&
document.focusNode
) {
return this.designer.createLocation({
@ -1296,8 +1313,9 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const inst = instances
? instances.length > 1
? instances.find(
(_inst) => this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance,
)
(_inst) =>
this.getClosestNodeInstance(_inst, container.id)?.instance === containerInstance,
)
: instances[0]
: null;
const rect = inst
@ -1420,7 +1438,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
// get common parent, avoid drop container contains by dragObject
const drillDownExcludes = new Set<INode>();
if (isDragNodeObject(dragObject)) {
const { nodes } = dragObject;
const { nodes } = dragObject as any;
let i = nodes.length;
let p: any = container;
while (i-- > 0) {
@ -1495,14 +1513,14 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
const { dragObject } = e;
const document = this.currentDocument!;
const { focusNode } = document;
if (isRootNode(container) || container.contains(focusNode)) {
if (isRootNode(container) || container.contains(focusNode!)) {
return document.checkNesting(focusNode!, dragObject as any);
}
const meta = (container as Node).componentMeta;
// FIXME: get containerInstance for accept logic use
const acceptable: boolean = this.isAcceptable(container);
const acceptable: boolean = this.isAcceptable();
if (!meta.isContainer && !acceptable) {
return false;
}
@ -1514,10 +1532,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
/**
*
*/
getNearByContainer(
{ container, instance }: DropContainer,
drillDownExcludes: Set<INode>,
) {
getNearByContainer({ container, instance }: DropContainer, drillDownExcludes: Set<INode>) {
const { children } = container;
if (!children || children.isEmpty()) {
return null;

View File

@ -59,21 +59,23 @@ export class LiveEditing {
const editor = node.document?.designer.editor;
const npm = node?.componentMeta?.npm;
const selected =
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
node?.componentMeta?.componentName ||
'';
editor?.eventBus.emit('designer.builtinSimulator.liveEditing', {
selected,
});
let setterPropElement = getSetterPropElement(targetElement, rootElement);
let propTarget = setterPropElement?.dataset.setterProp;
let matched: (IPublicTypePluginConfig & { propElement?: HTMLElement }) | undefined | null;
let matched: (IPublicTypePluginConfig & { propElement?: HTMLElement }) | undefined | null | any;
if (liveTextEditing) {
if (propTarget) {
// 已埋点命中 data-setter-prop="proptarget", 从 liveTextEditing 读取配置mode|onSaveContent
matched = liveTextEditing.find(config => config.propTarget == propTarget);
matched = liveTextEditing.find((config) => config.propTarget == propTarget);
} else {
// 执行 embedTextEditing selector 规则,获得第一个节点 是否 contains e.target若匹配读取配置
matched = liveTextEditing.find(config => {
matched = liveTextEditing.find((config) => {
if (!config.selector) {
return false;
}
@ -89,7 +91,8 @@ export class LiveEditing {
});
if (matched) {
propTarget = matched.propTarget;
setterPropElement = matched.propElement || queryPropElement(rootElement, targetElement, matched.selector);
setterPropElement =
matched.propElement || queryPropElement(rootElement, targetElement, matched.selector);
}
}
@ -117,9 +120,15 @@ export class LiveEditing {
// 4. 监听 blur 事件
// 5. 设置编辑锁定disable hover | disable select | disable canvas drag
const onSaveContent = matched?.onSaveContent || saveHandlers.find(item => item.condition(prop))?.onSaveContent || defaultSaveContent;
const onSaveContent =
matched?.onSaveContent ||
saveHandlers.find((item) => item.condition(prop as any))?.onSaveContent ||
defaultSaveContent;
setterPropElement.setAttribute('contenteditable', matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only');
setterPropElement.setAttribute(
'contenteditable',
matched?.mode && matched.mode !== 'plaintext' ? 'true' : 'plaintext-only',
);
setterPropElement.classList.add('engine-live-editing');
// be sure
setterPropElement.focus();
@ -134,7 +143,7 @@ export class LiveEditing {
switch (e.code) {
case 'Enter':
break;
// TODO: check is richtext?
// TODO: check is richtext?
case 'Escape':
break;
case 'Tab':
@ -157,7 +166,7 @@ export class LiveEditing {
setterPropElement!.removeEventListener('keydown', keydown, true);
};
this._editing = prop;
this._editing = prop as any;
}
// TODO: process enter | esc events & joint the FocusTracker
@ -186,9 +195,11 @@ export class LiveEditing {
}
}
export type SpecificRule = (target: EditingTarget) => (IPublicTypeLiveTextEditingConfig & {
propElement?: HTMLElement;
}) | null;
export type SpecificRule = (target: EditingTarget) =>
| (IPublicTypeLiveTextEditingConfig & {
propElement?: HTMLElement;
})
| null;
export interface SaveHandler {
condition: (prop: Prop) => boolean;
@ -223,7 +234,9 @@ function queryPropElement(rootElement: HTMLElement, targetElement: HTMLElement,
}
if (!propElement.contains(targetElement)) {
// try selectorAll
propElement = Array.from(rootElement.querySelectorAll(selector)).find(item => item.contains(targetElement)) as HTMLElement;
propElement = Array.from(rootElement.querySelectorAll(selector)).find((item) =>
item.contains(targetElement),
) as HTMLElement;
if (!propElement) {
return null;
}

View File

@ -2,10 +2,9 @@ import { Overlay } from '@alifd/next';
import React, { MouseEvent } from 'react';
import { Title, observer } from '@alilc/lowcode-editor-core';
import { canClickNode } from '@alilc/lowcode-utils';
import { INode } from '../../document';
import './index.less';
import { INode } from '@alilc/lowcode-designer';
const { Popup } = Overlay;
export interface IProps {
@ -80,17 +79,21 @@ export default class InstanceNodeSelector extends React.Component<IProps, IState
}
};
onMouseOver = (node: INode) => (_: any, flag = true) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
onMouseOver =
(node: INode) =>
(_: any, flag = true) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
onMouseOut = (node: INode) => (_: any, flag = false) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
onMouseOut =
(node: INode) =>
(_: any, flag = false) => {
if (node && typeof node.hover === 'function') {
node.hover(flag);
}
};
renderNodes = () => {
const nodes = this.state.parentNodes;

View File

@ -10,12 +10,12 @@ export const getClosestClickableNode = (
currentNode: INode | undefined | null,
event: MouseEvent,
) => {
let node = currentNode;
let node = currentNode as any;
while (node) {
// 判断当前节点是否可点击
let canClick = canClickNode(node, event);
let canClick = canClickNode(node, event as any);
// eslint-disable-next-line no-loop-func
const lockedNode = getClosestNode(node!, (n) => {
const lockedNode: any = getClosestNode(node, (n) => {
// 假如当前节点就是 locked 状态,要从当前节点的父节点开始查找
return !!(node?.isLocked ? n.parent?.isLocked : n.isLocked);
});

View File

@ -18,11 +18,7 @@ import { deprecate, isRegExp, isTitleConfig, isNode } from '@alilc/lowcode-utils
import { computed, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
import { Node, INode } from './document';
import { Designer } from './designer';
import {
IconContainer,
IconPage,
IconComponent,
} from './icons';
import { IconContainer, IconPage, IconComponent } from './icons';
export function ensureAList(list?: string | string[]): string[] | null {
if (!list) {
@ -138,7 +134,7 @@ export class ComponentMeta implements IComponentMeta {
private _isTopFixed?: boolean;
get isTopFixed(): boolean {
return !!(this._isTopFixed);
return !!this._isTopFixed;
}
private parentWhitelist?: IPublicTypeNestingFilter | null;
@ -155,7 +151,7 @@ export class ComponentMeta implements IComponentMeta {
if (isTitleConfig(this._title)) {
return (this._title?.label as any) || this.componentName;
}
return this._title || this.componentName;
return (this._title as any) || this.componentName;
}
@computed get icon() {
@ -184,7 +180,10 @@ export class ComponentMeta implements IComponentMeta {
*/
prototype?: any;
constructor(readonly designer: Designer, metadata: IPublicTypeComponentMetadata) {
constructor(
readonly designer: Designer,
metadata: IPublicTypeComponentMetadata,
) {
this.parseMetadata(metadata);
}
@ -287,8 +286,8 @@ export class ComponentMeta implements IComponentMeta {
}
private transformMetadata(
metadta: IPublicTypeComponentMetadata,
): IPublicTypeTransformedComponentMetadata {
metadta: IPublicTypeComponentMetadata,
): IPublicTypeTransformedComponentMetadata {
const registeredTransducers = this.designer.componentActions.getRegisteredMetadataTransducers();
const result = registeredTransducers.reduce((prevMetadata, current) => {
return current(prevMetadata);
@ -351,7 +350,10 @@ export class ComponentMeta implements IComponentMeta {
return true;
}
checkNestingDown(my: INode, target: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[]): boolean {
checkNestingDown(
my: INode,
target: INode | IPublicTypeNodeSchema | IPublicTypeNodeSchema[],
): boolean {
// 检查父子关系,直接约束型,在画布中拖拽直接掠过目标容器
if (this.childWhitelist) {
const _target: any = !Array.isArray(target) ? [target] : target;
@ -372,14 +374,15 @@ export class ComponentMeta implements IComponentMeta {
this.emitter.removeListener('metadata_change', fn);
};
}
}
export function isComponentMeta(obj: any): obj is ComponentMeta {
return obj && obj.isComponentMeta;
}
function preprocessMetadata(metadata: IPublicTypeComponentMetadata): IPublicTypeTransformedComponentMetadata {
function preprocessMetadata(
metadata: IPublicTypeComponentMetadata,
): IPublicTypeTransformedComponentMetadata {
if (metadata.configure) {
if (Array.isArray(metadata.configure)) {
return {

View File

@ -1,6 +1,17 @@
import { IPublicTypeContextMenuAction, IPublicEnumContextMenuType, IPublicTypeContextMenuItem, IPublicApiMaterial, IPublicModelPluginContext } from '@alilc/lowcode-types';
import {
IPublicTypeContextMenuAction,
IPublicEnumContextMenuType,
IPublicTypeContextMenuItem,
IPublicApiMaterial,
IPublicModelPluginContext,
} from '@alilc/lowcode-types';
import { IDesigner, INode } from './designer';
import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties, uniqueId } from '@alilc/lowcode-utils';
import {
createContextMenu,
parseContextMenuAsReactNode,
parseContextMenuProperties,
uniqueId,
} from '@alilc/lowcode-utils';
import { Menu } from '@alifd/next';
import { engineConfig } from '@alilc/lowcode-editor-core';
import './context-menu-actions.scss';
@ -22,16 +33,14 @@ export class GlobalContextMenuActions {
return;
}
this.enableContextMenu = enable;
this.dispose.forEach(d => d());
this.dispose.forEach((d) => d());
if (enable) {
this.initEvent();
}
});
}
handleContextMenu = (
event: MouseEvent,
) => {
handleContextMenu = (event: MouseEvent) => {
event.stopPropagation();
event.preventDefault();
@ -46,7 +55,9 @@ export class GlobalContextMenuActions {
const destroy = () => {
destroyFn?.();
};
const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get('pluginContext') as IPublicModelPluginContext;
const pluginContext: IPublicModelPluginContext = contextMenu.designer.editor.get(
'pluginContext',
) as IPublicModelPluginContext;
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
nodes: [],
@ -69,7 +80,7 @@ export class GlobalContextMenuActions {
const target = event.target;
const { top, left } = target?.getBoundingClientRect();
const { top, left } = (target as any)?.getBoundingClientRect();
const menuInstance = Menu.create({
target: event.target,
@ -113,7 +124,7 @@ export class ContextMenuActions {
enableContextMenu: boolean;
id: string = uniqueId('contextMenu');;
id: string = uniqueId('contextMenu');
constructor(designer: IDesigner) {
this.designer = designer;
@ -124,7 +135,7 @@ export class ContextMenuActions {
return;
}
this.enableContextMenu = enable;
this.dispose.forEach(d => d());
this.dispose.forEach((d) => d());
if (enable) {
this.initEvent();
}
@ -133,10 +144,7 @@ export class ContextMenuActions {
globalContextMenuActions.registerContextMenuActions(this);
}
handleContextMenu = (
nodes: INode[],
event: MouseEvent,
) => {
handleContextMenu = (nodes: INode[], event: MouseEvent) => {
const designer = this.designer;
event.stopPropagation();
event.preventDefault();
@ -152,10 +160,12 @@ export class ContextMenuActions {
destroyFn?.();
};
const pluginContext: IPublicModelPluginContext = this.designer.editor.get('pluginContext') as IPublicModelPluginContext;
const pluginContext: IPublicModelPluginContext = this.designer.editor.get(
'pluginContext',
) as IPublicModelPluginContext;
const menus: IPublicTypeContextMenuItem[] = parseContextMenuProperties(actions, {
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
nodes: nodes.map((d) => designer.shellModelFactory.createNode(d)!),
destroy,
event,
pluginContext,
@ -169,7 +179,7 @@ export class ContextMenuActions {
const menuNode = parseContextMenuAsReactNode(layoutMenu, {
destroy,
nodes: nodes.map(d => designer.shellModelFactory.createNode(d)!),
nodes: nodes.map((d) => designer.shellModelFactory.createNode(d)!),
pluginContext,
});
@ -182,26 +192,25 @@ export class ContextMenuActions {
initEvent() {
const designer = this.designer;
this.dispose.push(
designer.editor.eventBus.on('designer.builtinSimulator.contextmenu', ({
node,
originalEvent,
}: {
node: INode;
originalEvent: MouseEvent;
}) => {
originalEvent.stopPropagation();
originalEvent.preventDefault();
// 如果右键的节点不在 当前选中的节点中,选中该节点
if (!designer.currentSelection?.has(node.id)) {
designer.currentSelection?.select(node.id);
}
const nodes = designer.currentSelection?.getNodes();
this.handleContextMenu(nodes, originalEvent);
}),
designer.editor.eventBus.on(
'designer.builtinSimulator.contextmenu',
({ node, originalEvent }: { node: INode; originalEvent: MouseEvent }) => {
originalEvent.stopPropagation();
originalEvent.preventDefault();
// 如果右键的节点不在 当前选中的节点中,选中该节点
if (!designer.currentSelection?.has(node.id)) {
designer.currentSelection?.select(node.id);
}
const nodes = designer.currentSelection?.getNodes() ?? [];
this.handleContextMenu(nodes, originalEvent);
},
),
);
}
addMenuAction: IPublicApiMaterial['addContextMenuOption'] = (action: IPublicTypeContextMenuAction) => {
addMenuAction: IPublicApiMaterial['addContextMenuOption'] = (
action: IPublicTypeContextMenuAction,
) => {
this.actions.push({
type: IPublicEnumContextMenuType.MENU_ITEM,
...action,
@ -215,9 +224,11 @@ export class ContextMenuActions {
}
};
adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout'] = (fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) => {
adjustMenuLayout: IPublicApiMaterial['adjustContextMenuLayout'] = (
fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[],
) => {
adjustMenuLayoutFn = fn;
};
}
export interface IContextMenuActions extends ContextMenuActions {}
export interface IContextMenuActions extends ContextMenuActions {}

View File

@ -1,23 +1,21 @@
import { INode } from '../document/node/node';
import { obx, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import {
IPublicTypeActiveTarget,
IPublicModelActiveTracker,
} from '@alilc/lowcode-types';
import { IPublicTypeActiveTarget, IPublicModelActiveTracker } from '@alilc/lowcode-types';
import { isNode } from '@alilc/lowcode-utils';
export interface IActiveTracker extends Omit< IPublicModelActiveTracker, 'track' | 'onChange' > {
_target: ActiveTarget | INode;
export interface IActiveTracker extends Omit<IPublicModelActiveTracker, 'track' | 'onChange'> {
_target?: ActiveTarget | INode;
track(originalTarget: ActiveTarget | INode): void;
onChange(fn: (target: ActiveTarget) => void): () => void;
}
export interface ActiveTarget extends Omit< IPublicTypeActiveTarget, 'node' > {
export interface ActiveTarget extends Omit<IPublicTypeActiveTarget, 'node'> {
node: INode;
}
// @ts-ignore
export class ActiveTracker implements IActiveTracker {
@obx.ref private _target?: ActiveTarget | INode;

View File

@ -4,7 +4,11 @@ import { Designer } from '../designer';
import { isDragNodeObject } from '../dragon';
import { isSimulatorHost } from '../../simulator';
import './ghost.less';
import { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicModelDragObject } from '@alilc/lowcode-types';
import {
IPublicTypeI18nData,
IPublicTypeNodeSchema,
IPublicModelDragObject,
} from '@alilc/lowcode-types';
type offBinding = () => any;
@ -26,15 +30,15 @@ export default class DragGhost extends Component<{ designer: Designer }> {
super(props);
makeObservable(this);
this.dispose = [
this.dragon.onDragstart(e => {
this.dragon.onDragstart((e) => {
if (e.originalEvent.type.slice(0, 4) === 'drag') {
return;
}
this.titles = this.getTitles(e.dragObject);
this.titles = this.getTitles(e.dragObject!) as any;
this.x = e.globalX;
this.y = e.globalY;
}),
this.dragon.onDrag(e => {
this.dragon.onDrag((e) => {
this.x = e.globalX;
this.y = e.globalY;
if (isSimulatorHost(e.sensor)) {
@ -56,17 +60,20 @@ export default class DragGhost extends Component<{ designer: Designer }> {
getTitles(dragObject: IPublicModelDragObject) {
if (isDragNodeObject(dragObject)) {
return dragObject.nodes.map((node) => node.title);
return dragObject.nodes.map((node) => node?.title);
}
const dataList = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
const dataList = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data!];
return dataList.map((item: IPublicTypeNodeSchema, i) => (this.props.designer.getComponentMeta(item.componentName).title));
return dataList.map(
(item: IPublicTypeNodeSchema) =>
this.props.designer.getComponentMeta(item.componentName).title,
);
}
componentWillUnmount() {
if (this.dispose) {
this.dispose.forEach(off => off());
this.dispose.forEach((off) => off());
}
}

View File

@ -43,7 +43,11 @@ export function isDragNodeDataObject(obj: any): obj is IPublicTypeDragNodeDataOb
* @deprecated use same function in @alilc/lowcode-utils
*/
export function isDragAnyObject(obj: any): obj is IPublicTypeDragAnyObject {
return obj && obj.type !== IPublicEnumDragObjectType.NodeData && obj.type !== IPublicEnumDragObjectType.Node;
return (
obj &&
obj.type !== IPublicEnumDragObjectType.NodeData &&
obj.type !== IPublicEnumDragObjectType.Node
);
}
export function isLocateEvent(e: any): e is ILocateEvent {
@ -88,7 +92,7 @@ function getSourceSensor(dragObject: IPublicModelDragObject): ISimulatorHost | n
if (!isDragNodeObject(dragObject)) {
return null;
}
return dragObject.nodes[0]?.document?.simulator || null;
return (dragObject.nodes[0]?.document as any)?.simulator || null;
}
function isDragEvent(e: any): e is DragEvent {
@ -98,10 +102,7 @@ function isDragEvent(e: any): e is DragEvent {
/**
* Drag-on
*/
export class Dragon implements IPublicModelDragon<
INode,
ILocateEvent
> {
export class Dragon implements IPublicModelDragon<INode, ILocateEvent> {
private sensors: IPublicModelSensor[] = [];
private nodeInstPointerEvents: boolean;
@ -139,6 +140,7 @@ export class Dragon implements IPublicModelDragon<
* @param shell container element
* @param boost boost got a drag object
*/
// @ts-ignore
from(shell: Element, boost: (e: MouseEvent) => IPublicModelDragObject | null) {
const mousedown = (e: MouseEvent) => {
// ESC or RightClick
@ -166,13 +168,20 @@ export class Dragon implements IPublicModelDragon<
* @param dragObject
* @param boostEvent
*/
boost(dragObject: IPublicModelDragObject, boostEvent: MouseEvent | DragEvent, fromRglNode?: INode | IPublicModelNode) {
boost(
dragObject: IPublicModelDragObject,
boostEvent: MouseEvent | DragEvent,
fromRglNode?: INode | IPublicModelNode,
) {
const { designer } = this;
const masterSensors = this.getMasterSensors();
const handleEvents = makeEventsHandler(boostEvent, masterSensors);
const newBie = !isDragNodeObject(dragObject);
const forceCopyState =
isDragNodeObject(dragObject) && dragObject.nodes.some((node: Node | IPublicModelNode) => (typeof node.isSlot === 'function' ? node.isSlot() : node.isSlot));
isDragNodeObject(dragObject) &&
dragObject.nodes.some((node: Node | IPublicModelNode) =>
typeof node.isSlot === 'function' ? node.isSlot() : node.isSlot,
);
const isBoostFromDragAPI = isDragEvent(boostEvent);
let lastSensor: IPublicModelSensor | undefined;
@ -238,14 +247,14 @@ export class Dragon implements IPublicModelDragon<
}
lastArrive = e;
const { isRGL, rglNode } = getRGL(e);
const { isRGL, rglNode } = getRGL(e) as any;
const locateEvent = createLocateEvent(e);
const sensor = chooseSensor(locateEvent);
/* istanbul ignore next */
if (isRGL) {
// 禁止被拖拽元素的阻断
const nodeInst = dragObject.nodes[0].getDOMNode();
const nodeInst = dragObject?.nodes?.[0]?.getDOMNode();
if (nodeInst && nodeInst.style) {
this.nodeInstPointerEvents = true;
nodeInst.style.pointerEvents = 'none';
@ -263,7 +272,7 @@ export class Dragon implements IPublicModelDragon<
this.emitter.emit('rgl.add.placeholder', {
rglNode,
fromRglNode,
node: locateEvent.dragObject?.nodes[0],
node: locateEvent.dragObject?.nodes?.[0],
event: e,
});
designer.clearLocation();
@ -337,7 +346,7 @@ export class Dragon implements IPublicModelDragon<
const over = (e?: any) => {
// 禁止被拖拽元素的阻断
if (this.nodeInstPointerEvents) {
const nodeInst = dragObject.nodes[0].getDOMNode();
const nodeInst = dragObject?.nodes?.[0]?.getDOMNode();
if (nodeInst && nodeInst.style) {
nodeInst.style.pointerEvents = '';
}
@ -346,18 +355,18 @@ export class Dragon implements IPublicModelDragon<
// 发送drop事件
if (e) {
const { isRGL, rglNode } = getRGL(e);
const { isRGL, rglNode } = getRGL(e) as any;
/* istanbul ignore next */
if (isRGL && this._canDrop && this._dragging) {
const tarNode = dragObject.nodes[0];
if (rglNode.id !== tarNode.id) {
const tarNode = dragObject?.nodes?.[0];
if (rglNode.id !== tarNode?.id) {
// 避免死循环
this.emitter.emit('rgl.drop', {
rglNode,
node: tarNode,
});
const selection = designer.project.currentDocument?.selection;
selection?.select(tarNode.id);
selection?.select(tarNode!.id);
}
}
}
@ -429,7 +438,7 @@ export class Dragon implements IPublicModelDragon<
if (!sourceDocument || sourceDocument === document) {
evt.globalX = e.clientX;
evt.globalY = e.clientY;
} else /* istanbul ignore next */ {
} /* istanbul ignore next */ else {
// event from simulator sandbox
let srcSim: ISimulatorHost | undefined;
const lastSim = lastSensor && isSimulatorHost(lastSensor) ? lastSensor : null;
@ -463,7 +472,9 @@ export class Dragon implements IPublicModelDragon<
/* istanbul ignore next */
const chooseSensor = (e: ILocateEvent) => {
// this.sensors will change on dragstart
const sensors: IPublicModelSensor[] = this.sensors.concat(masterSensors as IPublicModelSensor[]);
const sensors: IPublicModelSensor[] = this.sensors.concat(
masterSensors as IPublicModelSensor[],
);
let sensor =
e.sensor && e.sensor.isEnter(e)
? e.sensor
@ -475,7 +486,7 @@ export class Dragon implements IPublicModelDragon<
} else if (e.sensor) {
sensor = e.sensor;
} else if (sourceSensor) {
sensor = sourceSensor;
sensor = sourceSensor as any;
}
}
if (sensor !== lastSensor) {
@ -634,4 +645,4 @@ export class Dragon implements IPublicModelDragon<
}
}
export interface IDragon extends Dragon { }
export interface IDragon extends Dragon {}

View File

@ -60,7 +60,10 @@ export function isChildInline(child: Element | Text, win?: Window) {
return true;
}
const style = (win || getWindow(child)).getComputedStyle(child);
return /^inline/.test(style.getPropertyValue('display')) || /^(left|right)$/.test(style.getPropertyValue('float'));
return (
/^inline/.test(style.getPropertyValue('display')) ||
/^(left|right)$/.test(style.getPropertyValue('float'))
);
}
export function getRectTarget(rect: IPublicTypeRect | null) {
@ -99,7 +102,6 @@ export function getWindow(elem: Element | Document): Window {
return (isDocument(elem) ? elem : elem.ownerDocument!).defaultView!;
}
export interface IDropLocation extends Omit<IPublicModelDropLocation, 'target' | 'clone'> {
readonly source: string;
get target(): INode;
@ -126,7 +128,7 @@ export class DropLocation implements IDropLocation {
this.target = target;
this.detail = detail;
this.source = source;
this.event = event;
this.event = event as any;
}
clone(event: ILocateEvent): IDropLocation {

View File

@ -75,14 +75,14 @@ export class OffsetObserver {
@computed get offsetHeight() {
if (!this.viewport?.scrolling || this.lastOffsetHeight == null) {
this.lastOffsetHeight = this.isRoot ? (this.viewport?.height || 0) : this.height;
this.lastOffsetHeight = this.isRoot ? this.viewport?.height || 0 : this.height;
}
return this.lastOffsetHeight;
}
@computed get offsetWidth() {
if (!(this.viewport?.scrolling || 0) || this.lastOffsetWidth == null) {
this.lastOffsetWidth = this.isRoot ? (this.viewport?.width || 0) : this.width;
this.lastOffsetWidth = this.isRoot ? this.viewport?.width || 0 : this.width;
}
return this.lastOffsetWidth;
}

View File

@ -10,17 +10,19 @@ import {
IPublicModelSettingField,
IBaseModelSettingField,
} from '@alilc/lowcode-types';
import type {
IPublicTypeSetValueOptions,
} from '@alilc/lowcode-types';
import type { IPublicTypeSetValueOptions } from '@alilc/lowcode-types';
import { Transducer } from './utils';
import { ISettingPropEntry, SettingPropEntry } from './setting-prop-entry';
import { computed, obx, makeObservable, action, untracked, intl } from '@alilc/lowcode-editor-core';
import { cloneDeep, isCustomView, isDynamicSetter, isJSExpression } from '@alilc/lowcode-utils';
import { ISettingTopEntry } from './setting-top-entry';
import { IComponentMeta, INode } from '@alilc/lowcode-designer';
import { IComponentMeta } from '../../component-meta';
import { INode } from '../../document';
function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, config: IPublicTypeFieldConfig) {
function getSettingFieldCollectorKey(
parent: ISettingTopEntry | ISettingField,
config: IPublicTypeFieldConfig,
) {
let cur = parent;
const path = [config.name];
while (cur !== parent.top) {
@ -32,12 +34,13 @@ function getSettingFieldCollectorKey(parent: ISettingTopEntry | ISettingField, c
return path.join('.');
}
export interface ISettingField extends ISettingPropEntry, Omit<IBaseModelSettingField<
ISettingTopEntry,
ISettingField,
IComponentMeta,
INode
>, 'setValue' | 'key' | 'node'> {
// @ts-ignore
export interface ISettingField
extends ISettingPropEntry,
Omit<
IBaseModelSettingField<ISettingTopEntry, ISettingField, IComponentMeta, INode>,
'setValue' | 'key' | 'node'
> {
readonly isSettingField: true;
readonly isRequired: boolean;
@ -96,7 +99,7 @@ export class SettingField extends SettingPropEntry implements ISettingField {
// ==== dynamic properties ====
private _title?: IPublicTypeTitleContent;
get title() {
get title(): any {
return (
this._title || (typeof this.name === 'number' ? `${intl('Item')} ${this.name}` : this.name)
);
@ -132,11 +135,11 @@ export class SettingField extends SettingPropEntry implements ISettingField {
this.initItems(items, settingFieldCollector);
}
if (this.type !== 'group' && settingFieldCollector && config.name) {
settingFieldCollector(getSettingFieldCollectorKey(parent, config), this);
settingFieldCollector(getSettingFieldCollectorKey(parent, config), this as any);
}
// compatiable old config
this.transducer = new Transducer(this, { setter });
this.transducer = new Transducer(this as any, { setter });
}
@computed get setter(): IPublicTypeSetterType | null {
@ -179,8 +182,8 @@ export class SettingField extends SettingPropEntry implements ISettingField {
if (isCustomView(item)) {
return item;
}
return new SettingField(this, item, settingFieldCollector);
});
return new SettingField(this as any, item, settingFieldCollector);
}) as any;
}
private disposeItems() {
@ -190,8 +193,8 @@ export class SettingField extends SettingPropEntry implements ISettingField {
// 创建子配置项,通常用于 object/array 类型数据
createField(config: IPublicTypeFieldConfig): ISettingField {
this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this);
return new SettingField(this, config, this.settingFieldCollector);
this.settingFieldCollector?.(getSettingFieldCollectorKey(this.parent, config), this as any);
return new SettingField(this as any, config, this.settingFieldCollector) as ISettingField;
}
purge() {
@ -307,7 +310,7 @@ export class SettingField extends SettingPropEntry implements ISettingField {
}
onEffect(action: () => void): IPublicTypeDisposable {
return this.designer!.autorun(action, true);
return this.designer!.autorun(action);
}
internalToShellField() {

View File

@ -1,5 +1,19 @@
import { obx, computed, makeObservable, runInAction, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import { GlobalEvent, IPublicApiSetters, IPublicModelEditor, IPublicModelSettingField, IPublicTypeFieldExtraProps, IPublicTypeSetValueOptions } from '@alilc/lowcode-types';
import {
obx,
computed,
makeObservable,
runInAction,
IEventBus,
createModuleEventBus,
} from '@alilc/lowcode-editor-core';
import {
GlobalEvent,
IPublicApiSetters,
IPublicModelEditor,
IPublicModelSettingField,
IPublicTypeFieldExtraProps,
IPublicTypeSetValueOptions,
} from '@alilc/lowcode-types';
import { uniqueId, isJSExpression } from '@alilc/lowcode-utils';
import { ISettingEntry } from './setting-entry-type';
import { INode } from '../../document';
@ -33,7 +47,12 @@ export interface ISettingPropEntry extends ISettingEntry {
remove(): void;
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions): void;
setValue(
val: any,
isHotValue?: boolean,
force?: boolean,
extraOptions?: IPublicTypeSetValueOptions,
): void;
internalToShellField(): IPublicModelSettingField;
}
@ -83,7 +102,11 @@ export class SettingPropEntry implements ISettingPropEntry {
extraProps: IPublicTypeFieldExtraProps = {};
constructor(readonly parent: ISettingTopEntry | ISettingField, name: string | number | undefined, type?: 'field' | 'group') {
constructor(
readonly parent: ISettingTopEntry | ISettingField,
name: string | number | undefined,
type?: 'field' | 'group',
) {
makeObservable(this);
if (type == null) {
const c = typeof name === 'string' ? name.slice(0, 1) : '';
@ -206,7 +229,12 @@ export class SettingPropEntry implements ISettingPropEntry {
/**
*
*/
setValue(val: any, isHotValue?: boolean, force?: boolean, extraOptions?: IPublicTypeSetValueOptions) {
setValue(
val: any,
isHotValue?: boolean,
force?: boolean,
extraOptions?: IPublicTypeSetValueOptions,
) {
const oldValue = this.getValue();
if (this.type === 'field') {
this.name?.toString() && this.parent.setPropValue(this.name, val);
@ -329,7 +357,7 @@ export class SettingPropEntry implements ISettingPropEntry {
}
notifyValueChange(oldValue: any, newValue: any) {
this.editor.eventBus.emit(GlobalEvent.Node.Prop.Change, {
this.editor.eventBus.emit(GlobalEvent.Node.Prop.InnerChange, {
node: this.getNode(),
prop: this,
oldValue,

View File

@ -1,4 +1,9 @@
import { IPublicTypeCustomView, IPublicModelEditor, IPublicModelSettingTopEntry, IPublicApiSetters } from '@alilc/lowcode-types';
import {
IPublicTypeCustomView,
IPublicModelEditor,
IPublicModelSettingTopEntry,
IPublicApiSetters,
} from '@alilc/lowcode-types';
import { isCustomView } from '@alilc/lowcode-utils';
import { computed, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import { ISettingEntry } from './setting-entry-type';
@ -14,10 +19,9 @@ function generateSessionId(nodes: INode[]) {
.join(',');
}
export interface ISettingTopEntry extends ISettingEntry, IPublicModelSettingTopEntry<
INode,
ISettingField
> {
export interface ISettingTopEntry
extends ISettingEntry,
IPublicModelSettingTopEntry<INode, ISettingField> {
readonly top: ISettingTopEntry;
readonly parent: ISettingTopEntry;
@ -48,16 +52,16 @@ export class SettingTopEntry implements ISettingTopEntry {
readonly path = [];
readonly top = this;
readonly top = this as ISettingTopEntry;
readonly parent = this;
readonly parent = this as ISettingTopEntry;
get componentMeta() {
return this._componentMeta;
}
get items() {
return this._items;
return this._items as any;
}
/**
@ -95,7 +99,10 @@ export class SettingTopEntry implements ISettingTopEntry {
disposeFunctions: any[] = [];
constructor(readonly editor: IPublicModelEditor, readonly nodes: INode[]) {
constructor(
readonly editor: IPublicModelEditor,
readonly nodes: INode[],
) {
if (!Array.isArray(nodes) || nodes.length < 1) {
throw new ReferenceError('nodes should not be empty');
}
@ -145,7 +152,7 @@ export class SettingTopEntry implements ISettingTopEntry {
if (isCustomView(item)) {
return item;
}
return new SettingField(this, item as any, settingFieldCollector);
return new SettingField(this as ISettingTopEntry, item as any, settingFieldCollector);
});
this._settingFieldMap = settingFieldMap;
}
@ -177,7 +184,10 @@ export class SettingTopEntry implements ISettingTopEntry {
*/
get(propName: string | number): ISettingField | null {
if (!propName) return null;
return this._settingFieldMap[propName] || (new SettingField(this, { name: propName }));
return (
this._settingFieldMap[propName] ||
new SettingField(this as ISettingTopEntry, { name: propName })
);
}
/**
@ -244,7 +254,7 @@ export class SettingTopEntry implements ISettingTopEntry {
this.disposeItems();
this._settingFieldMap = {};
this.emitter.removeAllListeners();
this.disposeFunctions.forEach(f => f());
this.disposeFunctions.forEach((f) => f());
this.disposeFunctions = [];
}
@ -253,21 +263,15 @@ export class SettingTopEntry implements ISettingTopEntry {
}
// ==== copy some Node api =====
getStatus() {
getStatus() {}
}
setStatus() {
}
setStatus() {}
getChildren() {
// this.nodes.map()
}
getDOMNode() {
}
getDOMNode() {}
getId() {
return this.id;

View File

@ -4,11 +4,11 @@ import { IPublicTypeFieldConfig, IPublicTypeSetterConfig } from '@alilc/lowcode-
import { isSetterConfig, isDynamicSetter } from '@alilc/lowcode-utils';
import { ISettingField } from './setting-field';
function getHotterFromSetter(setter) {
return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line
function getHotterFromSetter(setter: any) {
return (setter && (setter.Hotter || (setter.type && setter.type.Hotter))) || []; // eslint-disable-line
}
function getTransducerFromSetter(setter) {
function getTransducerFromSetter(setter: any) {
return (
(setter &&
(setter.transducer ||
@ -18,15 +18,15 @@ function getTransducerFromSetter(setter) {
); // eslint-disable-line
}
function combineTransducer(transducer, arr, context) {
function combineTransducer(transducer: any, arr: any, context: any) {
if (!transducer && Array.isArray(arr)) {
const [toHot, toNative] = arr;
transducer = { toHot, toNative };
}
return {
toHot: (transducer && transducer.toHot || (x => x)).bind(context), // eslint-disable-line
toNative: (transducer && transducer.toNative || (x => x)).bind(context), // eslint-disable-line
toHot: ((transducer && transducer.toHot) || ((x: any) => x)).bind(context), // eslint-disable-line
toNative: ((transducer && transducer.toNative) || ((x: any) => x)).bind(context), // eslint-disable-line
};
}
@ -43,9 +43,9 @@ export class Transducer {
// 3. IPublicTypeSetterConfig[]
if (Array.isArray(setter)) {
setter = setter[0];
} else if (isValidElement(setter) && setter.type.displayName === 'MixedSetter') {
setter = setter.props?.setters?.[0];
} else if (typeof setter === 'object' && setter.componentName === 'MixedSetter') {
} else if (isValidElement(setter) && (setter.type as any).displayName === 'MixedSetter') {
setter = (setter.props as any)?.setters?.[0];
} else if (typeof setter === 'object' && (setter as any).componentName === 'MixedSetter') {
setter = Array.isArray(setter?.props?.setters) && setter.props.setters[0];
}
@ -71,18 +71,24 @@ export class Transducer {
if (isDynamicSetter(setter) && isDynamic) {
try {
setter = setter.call(context.internalToShellField(), context.internalToShellField());
} catch (e) { console.error(e); }
} catch (e) {
console.error(e);
}
}
this.setterTransducer = combineTransducer(getTransducerFromSetter(setter), getHotterFromSetter(setter), context);
this.setterTransducer = combineTransducer(
getTransducerFromSetter(setter),
getHotterFromSetter(setter),
context,
);
this.context = context;
}
toHot(data) {
toHot(data: any) {
return this.setterTransducer.toHot(data);
}
toNative(data) {
toNative(data: any) {
return this.setterTransducer.toNative(data);
}
}

View File

@ -20,12 +20,8 @@ import {
IPublicTypeOnChangeOptions,
IPublicTypeDisposable,
} from '@alilc/lowcode-types';
import type {
IPublicTypeRootSchema,
} from '@alilc/lowcode-types';
import type {
IDropLocation,
} from '@alilc/lowcode-designer';
import type { IPublicTypeRootSchema } from '@alilc/lowcode-types';
import type { IDropLocation } from '../designer/location';
import {
uniqueId,
isPlainObject,
@ -50,36 +46,40 @@ import { EDITOR_EVENT } from '../types';
export type GetDataType<T, NodeType> = T extends undefined
? NodeType extends {
schema: infer R;
}
? R
: any
schema: infer R;
}
? R
: any
: T;
export class DocumentModel implements Omit<IPublicModelDocumentModel<
ISelection,
IHistory,
INode,
IDropLocation,
IModalNodesManager,
IProject
>,
'detecting' |
'checkNesting' |
'getNodeById' |
// 以下属性在内部的 document 中不存在
'exportSchema' |
'importSchema' |
'onAddNode' |
'onRemoveNode' |
'onChangeDetecting' |
'onChangeSelection' |
'onChangeNodeProp' |
'onImportSchema' |
'isDetectingNode' |
'onFocusNodeChanged' |
'onDropLocationChanged'
> {
export class DocumentModel
implements
Omit<
IPublicModelDocumentModel<
ISelection,
IHistory,
INode,
IDropLocation,
IModalNodesManager,
IProject
>,
| 'detecting'
| 'checkNesting'
| 'getNodeById'
// 以下属性在内部的 document 中不存在
| 'exportSchema'
| 'importSchema'
| 'onAddNode'
| 'onRemoveNode'
| 'onChangeDetecting'
| 'onChangeSelection'
| 'onChangeNodeProp'
| 'onImportSchema'
| 'isDetectingNode'
| 'onFocusNodeChanged'
| 'onDropLocationChanged'
>
{
/**
* Page/Component/Block
*/
@ -179,10 +179,10 @@ IProject
set dropLocation(loc: IDropLocation | null) {
this._dropLocation = loc;
// pub event
this.designer.editor.eventBus.emit(
'document.dropLocation.changed',
{ document: this, location: loc },
);
this.designer.editor.eventBus.emit('document.dropLocation.changed', {
document: this,
location: loc,
});
}
/**
@ -282,7 +282,9 @@ IProject
};
}
onChangeNodeChildren(fn: (info: IPublicTypeOnChangeOptions<INode>) => void): IPublicTypeDisposable {
onChangeNodeChildren(
fn: (info: IPublicTypeOnChangeOptions<INode>) => void,
): IPublicTypeDisposable {
this.designer.editor?.eventBus.on(EDITOR_EVENT.NODE_CHILDREN_CHANGE, fn);
return () => {
@ -401,14 +403,24 @@ IProject
/**
*
*/
insertNode(parent: INode, thing: INode | IPublicTypeNodeData, at?: number | null, copy?: boolean): INode | null {
insertNode(
parent: INode,
thing: INode | IPublicTypeNodeData,
at?: number | null,
copy?: boolean,
): INode | null {
return insertChild(parent, thing, at, copy);
}
/**
*
*/
insertNodes(parent: INode, thing: INode[] | IPublicTypeNodeData[], at?: number | null, copy?: boolean) {
insertNodes(
parent: INode,
thing: INode[] | IPublicTypeNodeData[],
at?: number | null,
copy?: boolean,
) {
return insertChildren(parent, thing, at, copy);
}
@ -473,7 +485,7 @@ IProject
const drillDownNodeId = this._drillDownNode?.id;
runWithGlobalEventOff(() => {
// TODO: 暂时用饱和式删除,原因是 Slot 节点并不是树节点,无法正常递归删除
this.nodes.forEach(node => {
this.nodes.forEach((node) => {
if (node.isRoot()) return;
this.internalRemoveAndPurgeNode(node, true);
});
@ -486,14 +498,20 @@ IProject
});
}
export(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize): IPublicTypeRootSchema | undefined {
export(
stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Serilize,
): IPublicTypeRootSchema | undefined {
stage = compatStage(stage);
// 置顶只作用于 Page 的第一级子节点,目前还用不到里层的置顶;如果后面有需要可以考虑将这段写到 node-children 中的 export
const currentSchema = this.rootNode?.export<IPublicTypeRootSchema>(stage);
if (Array.isArray(currentSchema?.children) && currentSchema?.children?.length && currentSchema?.children?.length > 0) {
if (
Array.isArray(currentSchema?.children) &&
currentSchema?.children?.length &&
currentSchema?.children?.length > 0
) {
const FixedTopNodeIndex = currentSchema?.children
.filter(i => isPlainObject(i))
.findIndex((i => (i as IPublicTypeNodeSchema).props?.__isTopFixed__));
.filter((i) => isPlainObject(i))
.findIndex((i) => (i as IPublicTypeNodeSchema).props?.__isTopFixed__);
if (FixedTopNodeIndex > 0) {
const FixedTopNode = currentSchema?.children.splice(FixedTopNodeIndex, 1);
currentSchema?.children.unshift(FixedTopNode[0]);
@ -598,7 +616,11 @@ IProject
checkNesting(
dropTarget: INode,
dragObject: IPublicTypeDragNodeObject | IPublicTypeNodeSchema | INode | IPublicTypeDragNodeDataObject,
dragObject:
| IPublicTypeDragNodeObject
| IPublicTypeNodeSchema
| INode
| IPublicTypeDragNodeDataObject,
): boolean {
let items: Array<INode | IPublicTypeNodeSchema>;
if (isDragNodeDataObject(dragObject)) {
@ -611,7 +633,9 @@ IProject
console.warn('the dragObject is not in the correct type, dragObject:', dragObject);
return true;
}
return items.every((item) => this.checkNestingDown(dropTarget, item) && this.checkNestingUp(dropTarget, item));
return items.every(
(item) => this.checkNestingDown(dropTarget, item) && this.checkNestingUp(dropTarget, item),
);
}
/**
@ -619,7 +643,10 @@ IProject
* Will be deleted in version 2.0.0.
* Use checkNesting method instead.
*/
checkDropTarget(dropTarget: INode, dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject): boolean {
checkDropTarget(
dropTarget: INode,
dragObject: IPublicTypeDragNodeObject | IPublicTypeDragNodeDataObject,
): boolean {
let items: Array<INode | IPublicTypeNodeSchema>;
if (isDragNodeDataObject(dragObject)) {
items = Array.isArray(dragObject.data) ? dragObject.data : [dragObject.data];
@ -686,7 +713,7 @@ IProject
/**
* @deprecated
*/
*/
/* istanbul ignore next */
exportAddonData() {
const addons: {
@ -722,10 +749,7 @@ IProject
}
/* istanbul ignore next */
acceptRootNodeVisitor(
visitorName = 'default',
visitorFn: (node: IRootNode) => any,
) {
acceptRootNodeVisitor(visitorName = 'default', visitorFn: (node: IRootNode) => any) {
let visitorResult = {};
if (!visitorName) {
/* eslint-disable-next-line no-console */
@ -753,7 +777,7 @@ IProject
// 组件去重
const exsitingMap: { [componentName: string]: boolean } = {};
for (const node of this._nodesMap.values()) {
const { componentName } = node || {};
const componentName: string = node.componentName;
if (componentName === 'Slot') continue;
if (!exsitingMap[componentName]) {
exsitingMap[componentName] = true;
@ -855,4 +879,4 @@ export function isPageSchema(obj: any): obj is IPublicTypePageSchema {
return obj?.componentName === 'Page';
}
export interface IDocumentModel extends DocumentModel {}
export interface IDocumentModel extends DocumentModel {}

View File

@ -8,7 +8,7 @@ import { BuiltinSimulatorHostView } from '../builtin-simulator';
export class DocumentView extends Component<{ document: IDocumentModel }> {
render() {
const { document } = this.props;
const { simulatorProps } = document;
const { simulatorProps } = document as any;
const Simulator = document.designer.simulatorComponent || BuiltinSimulatorHostView;
return (
<div

View File

@ -1,5 +1,15 @@
import { ReactElement } from 'react';
import { obx, computed, autorun, makeObservable, runInAction, wrapWithEventSwitch, action, createModuleEventBus, IEventBus } from '@alilc/lowcode-editor-core';
import {
obx,
computed,
autorun,
makeObservable,
runInAction,
wrapWithEventSwitch,
action,
createModuleEventBus,
IEventBus,
} from '@alilc/lowcode-editor-core';
import {
IPublicTypeNodeSchema,
IPublicTypePropsMap,
@ -18,7 +28,7 @@ import {
IBaseModelNode,
} from '@alilc/lowcode-types';
import { compatStage, isDOMText, isJSExpression, isNode, isNodeSchema } from '@alilc/lowcode-utils';
import { ISettingTopEntry } from '@alilc/lowcode-designer';
import { ISettingTopEntry } from '../../designer/setting/setting-top-entry';
import { Props, getConvertedExtraKey, IProps } from './props/props';
import type { IDocumentModel } from '../document-model';
import { NodeChildren, INodeChildren } from './node-children';
@ -86,34 +96,38 @@ export interface IBaseNode extends Node {}
* isLocked
* hidden
*/
export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema> implements Omit<IBaseModelNode<
IDocumentModel,
IBaseNode,
INodeChildren,
IComponentMeta,
ISettingTopEntry,
IProps,
IProp,
IExclusiveGroup
>,
'isRoot' |
'isPage' |
'isComponent' |
'isModal' |
'isSlot' |
'isParental' |
'isLeaf' |
'settingEntry' |
// 在内部的 node 模型中不存在
'getExtraPropValue' |
'setExtraPropValue' |
'exportSchema' |
'visible' |
'importSchema' |
// 内外实现有差异
'isContainer' |
'isEmpty'
> {
export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
implements
Omit<
IBaseModelNode<
IDocumentModel,
IBaseNode,
INodeChildren,
IComponentMeta,
ISettingTopEntry,
IProps,
IProp,
IExclusiveGroup
>,
| 'isRoot'
| 'isPage'
| 'isComponent'
| 'isModal'
| 'isSlot'
| 'isParental'
| 'isLeaf'
| 'settingEntry'
// 在内部的 node 模型中不存在
| 'getExtraPropValue'
| 'setExtraPropValue'
| 'exportSchema'
| 'visible'
| 'importSchema'
// 内外实现有差异
| 'isContainer'
| 'isEmpty'
>
{
private emitter: IEventBus;
/**
@ -269,7 +283,10 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
pseudo: false,
};
constructor(readonly document: IDocumentModel, nodeSchema: Schema) {
constructor(
readonly document: IDocumentModel,
nodeSchema: Schema,
) {
makeObservable(this);
const { componentName, id, children, props, ...extras } = nodeSchema;
this.id = document.nextId(id);
@ -282,10 +299,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
this.props = new Props(this, props, extras);
this._children = new NodeChildren(this as INode, this.initialChildren(children));
this._children.internalInitParent();
this.props.merge(
this.upgradeProps(this.initProps(props || {})),
this.upgradeProps(extras),
);
this.props.merge(this.upgradeProps(this.initProps(props || {})), this.upgradeProps(extras));
this.setupAutoruns();
}
@ -310,12 +324,18 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
*/
@action
private initBuiltinProps() {
this.props.has(getConvertedExtraKey('hidden')) || this.props.add(false, getConvertedExtraKey('hidden'));
this.props.has(getConvertedExtraKey('title')) || this.props.add('', getConvertedExtraKey('title'));
this.props.has(getConvertedExtraKey('isLocked')) || this.props.add(false, getConvertedExtraKey('isLocked'));
this.props.has(getConvertedExtraKey('condition')) || this.props.add(true, getConvertedExtraKey('condition'));
this.props.has(getConvertedExtraKey('conditionGroup')) || this.props.add('', getConvertedExtraKey('conditionGroup'));
this.props.has(getConvertedExtraKey('loop')) || this.props.add(undefined, getConvertedExtraKey('loop'));
this.props.has(getConvertedExtraKey('hidden')) ||
this.props.add(false, getConvertedExtraKey('hidden'));
this.props.has(getConvertedExtraKey('title')) ||
this.props.add('', getConvertedExtraKey('title'));
this.props.has(getConvertedExtraKey('isLocked')) ||
this.props.add(false, getConvertedExtraKey('isLocked'));
this.props.has(getConvertedExtraKey('condition')) ||
this.props.add(true, getConvertedExtraKey('condition'));
this.props.has(getConvertedExtraKey('conditionGroup')) ||
this.props.add('', getConvertedExtraKey('conditionGroup'));
this.props.has(getConvertedExtraKey('loop')) ||
this.props.add(undefined, getConvertedExtraKey('loop'));
}
@action
@ -340,7 +360,9 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
});
}
private initialChildren(children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined): IPublicTypeNodeData[] {
private initialChildren(
children: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined,
): IPublicTypeNodeData[] {
const { initialChildren } = this.componentMeta.advanced;
if (children == null) {
@ -527,9 +549,13 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
}
if (this.isSlot()) {
this.parent.removeSlot(this);
this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });
this.parent.children?.internalDelete(this, purge, useMutator, {
suppressRemoveEvent: true,
});
} else {
this.parent.children?.internalDelete(this, purge, useMutator, { suppressRemoveEvent: true });
this.parent.children?.internalDelete(this, purge, useMutator, {
suppressRemoveEvent: true,
});
}
}
}
@ -550,7 +576,8 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
canSelect(): boolean {
const onSelectHook = this.componentMeta?.advanced?.callbacks?.onSelectHook;
const canSelect = typeof onSelectHook === 'function' ? onSelectHook(this.internalToShellNode()!) : true;
const canSelect =
typeof onSelectHook === 'function' ? onSelectHook(this.internalToShellNode()!) : true;
return canSelect;
}
@ -845,7 +872,10 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
/**
* schema
*/
export<T = IPublicTypeNodeSchema>(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save, options: any = {}): T {
export<T = IPublicTypeNodeSchema>(
stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Save,
options: any = {},
): T {
stage = compatStage(stage);
const baseSchema: any = {
componentName: this.componentName,
@ -999,12 +1029,11 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
*/
canPerformAction(actionName: string): boolean {
const availableActions =
this.componentMeta?.availableActions?.filter((action: IPublicTypeComponentAction) => {
const { condition } = action;
return typeof condition === 'function' ?
condition(this) !== false :
condition !== false;
})
this.componentMeta?.availableActions
?.filter((action: IPublicTypeComponentAction) => {
const { condition } = action;
return typeof condition === 'function' ? condition(this) !== false : condition !== false;
})
.map((action: IPublicTypeComponentAction) => action.name) || [];
return availableActions.indexOf(actionName) >= 0;
@ -1061,7 +1090,9 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
return this.props;
}
onChildrenChange(fn: (param?: { type: string; node: INode }) => void): IPublicTypeDisposable | undefined {
onChildrenChange(
fn: (param?: { type: string; node: INode }) => void,
): IPublicTypeDisposable | undefined {
const wrappedFunc = wrapWithEventSwitch(fn);
return this.children?.onChange(wrappedFunc);
}
@ -1131,7 +1162,7 @@ export class Node<Schema extends IPublicTypeNodeSchema = IPublicTypeNodeSchema>
const isContainerNode = this.isContainer();
const isEmptyNode = this.isEmpty();
const isRGLContainerNode = this.isRGLContainer;
const isRGLNode = (this.getParent()?.isRGLContainer) as boolean;
const isRGLNode = this.getParent()?.isRGLContainer as boolean;
const isRGL = isRGLContainerNode || (isRGLNode && (!isContainerNode || !isEmptyNode));
let rglNode = isRGLContainerNode ? this : isRGL ? this?.getParent() : null;
return { isContainerNode, isEmptyNode, isRGLContainerNode, isRGLNode, isRGL, rglNode };
@ -1294,7 +1325,13 @@ export interface ISlotNode extends Node<IPublicTypeSlotSchema> {}
export interface IPageNode extends Node<IPublicTypePageSchema> {}
export interface IComponentNode extends Node<IPublicTypeComponentSchema> {}
export interface IRootNode extends Node<IPublicTypePageSchema | IPublicTypeComponentSchema> {}
export interface INode extends Node<IPublicTypePageSchema | IPublicTypeSlotSchema | IPublicTypeComponentSchema | IPublicTypeNodeSchema> {}
export interface INode
extends Node<
| IPublicTypePageSchema
| IPublicTypeSlotSchema
| IPublicTypeComponentSchema
| IPublicTypeNodeSchema
> {}
export function isRootNode(node: INode): node is IRootNode {
return node && node.isRootNode;

View File

@ -48,7 +48,7 @@ export class Selection implements ISelection {
selectAll(ids: string[]) {
const selectIds: string[] = [];
ids.forEach(d => {
ids.forEach((d) => {
const node = this.doc.getNode(d);
if (node?.canSelect()) {
@ -125,7 +125,7 @@ export class Selection implements ISelection {
containsNode(node: INode, excludeRoot = false) {
for (const id of this._selected) {
const parent = this.doc.getNode(id);
if (excludeRoot && parent?.contains(this.doc.focusNode)) {
if (excludeRoot && parent?.contains(this.doc.focusNode!)) {
continue;
}
if (parent?.contains(node)) {
@ -157,7 +157,7 @@ export class Selection implements ISelection {
for (const id of this._selected) {
const node = this.doc.getNode(id);
// 排除根节点
if (!node || (!includeRoot && node.contains(this.doc.focusNode))) {
if (!node || (!includeRoot && node.contains(this.doc.focusNode!))) {
continue;
}
let i = nodes.length;

1
packages/designer/src/module.d.ts vendored Normal file
View File

@ -0,0 +1 @@
declare module 'ric-shim';

View File

@ -23,7 +23,25 @@ import {
const logger = getLogger({ level: 'warn', bizName: 'designer:pluginManager' });
// 保留的事件前缀
const RESERVED_EVENT_PREFIX = ['designer', 'editor', 'skeleton', 'renderer', 'render', 'utils', 'plugin', 'engine', 'editor-core', 'engine-core', 'plugins', 'event', 'events', 'log', 'logger', 'ctx', 'context'];
const RESERVED_EVENT_PREFIX = [
'designer',
'editor',
'skeleton',
'renderer',
'render',
'utils',
'plugin',
'engine',
'editor-core',
'engine-core',
'plugins',
'event',
'events',
'log',
'logger',
'ctx',
'context',
];
export class LowCodePluginManager implements ILowCodePluginManager {
private plugins: ILowCodePluginRuntime[] = [];
@ -35,7 +53,10 @@ export class LowCodePluginManager implements ILowCodePluginManager {
contextApiAssembler: ILowCodePluginContextApiAssembler;
constructor(contextApiAssembler: ILowCodePluginContextApiAssembler, readonly viewName = 'global') {
constructor(
contextApiAssembler: ILowCodePluginContextApiAssembler,
readonly viewName = 'global',
) {
this.contextApiAssembler = contextApiAssembler;
}
@ -79,24 +100,30 @@ export class LowCodePluginManager implements ILowCodePluginManager {
const isReservedPrefix = RESERVED_EVENT_PREFIX.find((item) => item === eventPrefix);
if (isReservedPrefix) {
meta.eventPrefix = undefined;
logger.warn(`plugin ${pluginName} is trying to use ${eventPrefix} as event prefix, which is a reserved event prefix, please use another one`);
logger.warn(
`plugin ${pluginName} is trying to use ${eventPrefix} as event prefix, which is a reserved event prefix, please use another one`,
);
}
const ctx = this._getLowCodePluginContext({ pluginName, meta });
const customFilterValidOptions = engineConfig.get('customPluginFilterOptions', filterValidOptions);
const customFilterValidOptions = engineConfig.get(
'customPluginFilterOptions',
filterValidOptions,
);
const pluginTransducer = engineConfig.get('customPluginTransducer', null);
const newPluginModel = pluginTransducer ? await pluginTransducer(pluginModel, ctx, options) : pluginModel;
const newOptions = customFilterValidOptions(options, newPluginModel.meta?.preferenceDeclaration);
const newPluginModel = pluginTransducer
? await pluginTransducer(pluginModel, ctx, options)
: pluginModel;
const newOptions = customFilterValidOptions(
options,
newPluginModel.meta?.preferenceDeclaration,
);
const config = newPluginModel(ctx, newOptions);
// compat the legacy way to declare pluginName
// @ts-ignore
pluginName = pluginName || config.name;
invariant(
pluginName,
'pluginConfigCreator.pluginName required',
config,
);
invariant(pluginName, 'pluginConfigCreator.pluginName required', config);
ctx.setPreference(pluginName, preferenceDeclaration);
ctx.setPreference(pluginName, preferenceDeclaration!);
const allowOverride = registerOptions?.override === true;
@ -119,7 +146,9 @@ export class LowCodePluginManager implements ILowCodePluginManager {
const engineVersionExp = engines && engines.lowcodeEngine;
if (engineVersionExp && !this.isEngineVersionMatched(engineVersionExp)) {
throw new Error(`plugin ${pluginName} skipped, engine check failed, current engine version is ${engineConfig.get('ENGINE_VERSION')}, meta.engines.lowcodeEngine is ${engineVersionExp}`);
throw new Error(
`plugin ${pluginName} skipped, engine check failed, current engine version is ${engineConfig.get('ENGINE_VERSION')}, meta.engines.lowcodeEngine is ${engineVersionExp}`,
);
}
const plugin = new LowCodePluginRuntime(pluginName, this, config, meta);
@ -188,7 +217,9 @@ export class LowCodePluginManager implements ILowCodePluginManager {
return this.pluginsMap.size;
}
getPluginPreference(pluginName: string): Record<string, IPublicTypePreferenceValueType> | null | undefined {
getPluginPreference(
pluginName: string,
): Record<string, IPublicTypePreferenceValueType> | null | undefined {
if (!this.pluginPreference) {
return null;
}

View File

@ -1,5 +1,8 @@
import { isPlainObject } from 'lodash';
import { IPublicTypePluginRegisterOptions, IPublicTypePluginDeclaration } from '@alilc/lowcode-types';
import { isPlainObject } from 'lodash-es';
import {
IPublicTypePluginRegisterOptions,
IPublicTypePluginDeclaration,
} from '@alilc/lowcode-types';
export function isValidPreferenceKey(
key: string,
@ -17,10 +20,7 @@ export function isLowCodeRegisterOptions(opts: any): opts is IPublicTypePluginRe
return opts && ('autoInit' in opts || 'override' in opts);
}
export function filterValidOptions(
opts: any,
preferenceDeclaration: IPublicTypePluginDeclaration,
) {
export function filterValidOptions(opts: any, preferenceDeclaration: IPublicTypePluginDeclaration) {
if (!opts || !isPlainObject(opts)) return opts;
const filteredOpts = {} as any;
Object.keys(opts).forEach((key) => {
@ -32,4 +32,4 @@ export function filterValidOptions(
}
});
return filteredOpts;
}
}

View File

@ -28,7 +28,7 @@ export function sequence({
}
const node = tasks[name];
if (!node) {
missing.push([parentName, name].filter((d => !!d)).join('.'));
missing.push([parentName, name].filter((d) => !!d).join('.'));
} else if (nest.indexOf(name) > -1) {
nest.push(name);
recursive.push(nest.slice(0));
@ -64,7 +64,7 @@ export default function (tasks: ITaks, names: string[]) {
missing,
recursive,
nest: [],
});
} as any);
if (missing.length || recursive.length) {
results = []; // results are incomplete at best, completely wrong at worst, remove them to avoid confusion

View File

@ -1,19 +1,7 @@
import React from 'react';
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import '../fixtures/window';
import { Editor } from '@alilc/lowcode-editor-core';
import { Project } from '../../src/project/project';
import { Node } from '../../src/document/node/node';
import TestRenderer from 'react-test-renderer';
import { configure, render, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { Designer } from '../../src/designer/designer';
import formSchema from '../fixtures/schema/form';
import { getMockRenderer } from '../utils';
import { isSimulatorRenderer } from '../../src/builtin-simulator/renderer';
describe('renderer 测试', () => {
it('renderer', () => {
expect(isSimulatorRenderer(getMockRenderer())).toBeTruthy();

View File

@ -1,5 +1,4 @@
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import { set, cloneDeep } from 'lodash-es';
import '../../fixtures/window';
import { Project, IProject } from '../../../src/project/project';
import { Node, INode } from '../../../src/document/node/node';
@ -22,7 +21,9 @@ jest.mock('../../../src/designer/designer', () => {
},
};
},
transformProps(props) { return props; },
transformProps(props) {
return props;
},
createSettingEntry: mockCreateSettingEntry,
postEvent() {},
};
@ -40,9 +41,7 @@ describe('schema 生成节点模型测试', () => {
let project: IProject;
beforeEach(() => {
project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
});
@ -56,8 +55,10 @@ describe('schema 生成节点模型测试', () => {
const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length;
expect(nodesMap?.size).toBe(expectedNodeCnt);
ids.forEach(id => {
expect(nodesMap?.get(id)?.componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
ids.forEach((id) => {
expect(nodesMap?.get(id)?.componentName).toBe(
getNodeFromSchemaById(formSchema, id).componentName,
);
});
const pageNode = currentDocument?.getNode('page');
@ -66,7 +67,7 @@ describe('schema 生成节点模型测试', () => {
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
nodesMap.forEach(node => {
nodesMap.forEach((node) => {
// 触发 getter
node.settingEntry;
});
@ -245,16 +246,14 @@ describe('schema 生成节点模型测试', () => {
expect(pageNode?.isPage()).toBe(true);
expect(pageNode?.isComponent()).toBe(false);
expect(pageNode?.isSlot()).toBe(false);
expect(pageNode?.title).toBe('hey, i\' a page!');
expect(pageNode?.title).toBe("hey, i' a page!");
});
describe('节点新增insertNode', () => {
let project: Project;
beforeEach(() => {
project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
});
@ -292,14 +291,19 @@ describe('schema 生成节点模型测试', () => {
const { currentDocument } = project;
const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap?.get('form');
formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
}, 0);
formNode &&
currentDocument?.insertNode(
formNode,
{
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
},
0,
);
expect(nodesMap?.size).toBe(ids.length + 1);
expect(formNode?.children?.length).toBe(4);
const insertedNode = formNode?.children?.get(0);
@ -318,14 +322,19 @@ describe('schema 生成节点模型测试', () => {
const { currentDocument } = project;
const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap?.get('form');
formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
}, 1);
formNode &&
currentDocument?.insertNode(
formNode,
{
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
},
1,
);
expect(nodesMap?.size).toBe(ids.length + 1);
expect(formNode?.children?.length).toBe(4);
const insertedNode = formNode?.children?.get(1);
@ -380,14 +389,15 @@ describe('schema 生成节点模型测试', () => {
const { currentDocument } = project;
const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap?.get('form');
formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
});
formNode &&
currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
});
expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');
expect(nodesMap?.size).toBe(ids.length + 1);
});
@ -398,14 +408,15 @@ describe('schema 生成节点模型测试', () => {
const { currentDocument } = project;
const nodesMap = currentDocument?.nodesMap;
const formNode = nodesMap?.get('form');
formNode && currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
});
formNode &&
currentDocument?.insertNode(formNode, {
componentName: 'TextInput',
id: 'nodeschema-id1',
props: {
propA: 'haha',
propB: 3,
},
});
expect(nodesMap?.get('nodeschema-id1')?.componentName).toBe('TextInput');
expect(nodesMap?.size).toBe(ids.length + 1);
});
@ -463,9 +474,7 @@ describe('schema 生成节点模型测试', () => {
let project: Project;
beforeEach(() => {
project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
});
@ -477,22 +486,26 @@ describe('schema 生成节点模型测试', () => {
const formNode = nodesMap?.get('form') as Node;
const formNode2 = currentDocument?.getNode('form');
expect(formNode).toEqual(formNode2);
currentDocument?.insertNodes(formNode, [
{
componentName: 'TextInput',
props: {
propA: 'haha2',
propB: 3,
currentDocument?.insertNodes(
formNode,
[
{
componentName: 'TextInput',
props: {
propA: 'haha2',
propB: 3,
},
},
},
{
componentName: 'TextInput2',
props: {
propA: 'haha',
propB: 3,
{
componentName: 'TextInput2',
props: {
propA: 'haha',
propB: 3,
},
},
},
], 1);
],
1,
);
expect(nodesMap?.size).toBe(ids.length + 2);
expect(formNode.children?.length).toBe(5);
const insertedNode1 = formNode.children?.get(1);
@ -552,11 +565,13 @@ describe('schema 生成节点模型测试', () => {
describe('block ❌ | component ❌ | slot ✅', () => {
it('基本的 slot 创建', () => {
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');
const formSchemaWithSlot = set(
cloneDeep(formSchema),
'children[0].children[0].props.title.type',
'JSSlot',
);
const project = new Project(designer, {
componentsTree: [
formSchemaWithSlot,
],
componentsTree: [formSchemaWithSlot],
});
project.open();
expect(project).toBeTruthy();

View File

@ -1,5 +1,4 @@
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import { set, cloneDeep } from 'lodash-es';
import '../../fixtures/window';
import { Project } from '../../../src/project/project';
import { Designer } from '../../../src/designer/designer';
@ -21,7 +20,9 @@ jest.mock('../../../src/designer/designer', () => {
},
};
},
transformProps(props) { return props; },
transformProps(props) {
return props;
},
createSettingEntry: mockCreateSettingEntry,
postEvent() {},
};
@ -37,9 +38,7 @@ beforeAll(() => {
describe('节点模型删除测试', () => {
it('删除叶子节点', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -62,12 +61,13 @@ describe('节点模型删除测试', () => {
});
it('删除叶子节点,带有 slot', () => {
const formSchemaWithSlot = set(cloneDeep(formSchema),
'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');
const formSchemaWithSlot = set(
cloneDeep(formSchema),
'children[1].children[0].children[2].children[1].props.greeting.type',
'JSSlot',
);
const project = new Project(designer, {
componentsTree: [
formSchemaWithSlot,
],
componentsTree: [formSchemaWithSlot],
});
project.open();
expect(project).toBeTruthy();
@ -84,9 +84,7 @@ describe('节点模型删除测试', () => {
it('删除分支节点', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -102,12 +100,13 @@ describe('节点模型删除测试', () => {
});
it('删除分支节点,带有 slot', () => {
const formSchemaWithSlot = set(cloneDeep(formSchema),
'children[1].children[0].children[2].children[1].props.greeting.type', 'JSSlot');
const formSchemaWithSlot = set(
cloneDeep(formSchema),
'children[1].children[0].children[2].children[1].props.greeting.type',
'JSSlot',
);
const project = new Project(designer, {
componentsTree: [
formSchemaWithSlot,
],
componentsTree: [formSchemaWithSlot],
});
project.open();
expect(project).toBeTruthy();

View File

@ -1,11 +1,7 @@
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import '../fixtures/window';
import { Project } from '../../src/project/project';
import { Node } from '../../src/document/node/node';
import { Designer } from '../../src/designer/designer';
import formSchema from '../fixtures/schema/form';
import { getIdsFromSchema, getNodeFromSchemaById } from '../utils';
const mockCreateSettingEntry = jest.fn();
jest.mock('../../src/designer/designer', () => {
@ -22,7 +18,9 @@ jest.mock('../../src/designer/designer', () => {
},
};
},
transformProps(props) { return props; },
transformProps(props) {
return props;
},
createSettingEntry: mockCreateSettingEntry,
postEvent() {},
};
@ -38,9 +36,7 @@ beforeAll(() => {
describe('选择区测试', () => {
it('常规方法', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -92,9 +88,7 @@ describe('选择区测试', () => {
it('add 方法', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -124,9 +118,7 @@ describe('选择区测试', () => {
it('selectAll 包含不存在的 id', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -140,9 +132,7 @@ describe('选择区测试', () => {
it('dispose 方法 - 选中的节点没有被删除的', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -160,9 +150,7 @@ describe('选择区测试', () => {
it('containsNode 方法', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -190,9 +178,7 @@ describe('选择区测试', () => {
it('containsNode 方法 - excludeRoot: true', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -213,9 +199,7 @@ describe('选择区测试', () => {
it('containsNode 方法 - excludeRoot: true', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -239,9 +223,7 @@ describe('选择区测试', () => {
it('getNodes', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
const { currentDocument } = project;
@ -255,9 +237,7 @@ describe('选择区测试', () => {
it('getTopNodes - BeforeOrAfter', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
const { currentDocument } = project;
@ -269,9 +249,7 @@ describe('选择区测试', () => {
});
it('getTopNodes', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
const { currentDocument } = project;

View File

@ -1,5 +1,4 @@
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import { set, cloneDeep } from 'lodash-es';
import '../fixtures/window';
import { Editor } from '@alilc/lowcode-editor-core';
import { Project } from '../../src/project/project';
@ -22,7 +21,9 @@ jest.mock('../../src/designer/designer', () => {
},
};
},
transformProps(props) { return props; },
transformProps(props) {
return props;
},
createSettingEntry: mockCreateSettingEntry,
postEvent() {},
};
@ -44,9 +45,7 @@ describe('schema 生成节点模型测试', () => {
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -55,13 +54,15 @@ describe('schema 生成节点模型测试', () => {
const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length;
expect(nodesMap.size).toBe(expectedNodeCnt);
ids.forEach(id => {
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
ids.forEach((id) => {
expect(nodesMap.get(id).componentName).toBe(
getNodeFromSchemaById(formSchema, id).componentName,
);
});
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
nodesMap.forEach(node => {
nodesMap.forEach((node) => {
// 触发 getter
node.settingEntry;
});
@ -70,9 +71,7 @@ describe('schema 生成节点模型测试', () => {
it('onSimulatorReady works', () => {
const project = new Project(designer, {
componentsTree: [
formSchema,
],
componentsTree: [formSchema],
});
project.open();
expect(project).toBeTruthy();
@ -103,23 +102,26 @@ describe('schema 生成节点模型测试', () => {
const project = new Project(designer);
expect(project).toBeTruthy();
// trigger autoOpen case
project.load({
componentsTree: [
formSchema,
],
}, true);
project.load(
{
componentsTree: [formSchema],
},
true,
);
const { currentDocument } = project;
const { nodesMap } = currentDocument;
const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length;
expect(nodesMap.size).toBe(expectedNodeCnt);
ids.forEach(id => {
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
ids.forEach((id) => {
expect(nodesMap.get(id).componentName).toBe(
getNodeFromSchemaById(formSchema, id).componentName,
);
});
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
nodesMap.forEach(node => {
nodesMap.forEach((node) => {
// 触发 getter
node.settingEntry;
});
@ -129,31 +131,34 @@ describe('schema 生成节点模型测试', () => {
const project = new Project(designer);
expect(project).toBeTruthy();
// trigger autoOpen case
project.load({
componentsTree: [
{
...formSchema,
fileName: 'demoFile1',
project.load(
{
componentsTree: [
{
...formSchema,
fileName: 'demoFile1',
},
{
...formSchema,
fileName: 'demoFile2',
},
],
config: {
layout: {
props: {
tabBar: {
items: [
{
path: '/demoFile2',
},
],
},
},
},
},
{
...formSchema,
fileName: 'demoFile2',
}
],
config: {
layout: {
props: {
tabBar: {
items: [
{
path: '/demoFile2',
}
],
}
}
}
}
}, true);
},
true,
);
const { currentDocument } = project;
expect(currentDocument.fileName).toBe('demoFile2');
});
@ -162,23 +167,25 @@ describe('schema 生成节点模型测试', () => {
const project = new Project(designer);
expect(project).toBeTruthy();
// trigger autoOpen case
project.load({
componentsTree: [
{
...formSchema,
fileName: 'demoFile1',
},
{
...formSchema,
fileName: 'demoFile2',
}
],
}, 'demoFile2');
project.load(
{
componentsTree: [
{
...formSchema,
fileName: 'demoFile1',
},
{
...formSchema,
fileName: 'demoFile2',
},
],
},
'demoFile2',
);
const { currentDocument } = project;
expect(currentDocument.fileName).toBe('demoFile2');
});
it('setSchema works', () => {
const project = new Project(designer);
project.open();
@ -204,13 +211,15 @@ describe('schema 生成节点模型测试', () => {
const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length;
expect(nodesMap.size).toBe(expectedNodeCnt);
ids.forEach(id => {
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
ids.forEach((id) => {
expect(nodesMap.get(id).componentName).toBe(
getNodeFromSchemaById(formSchema, id).componentName,
);
});
const exportSchema = currentDocument?.export(1);
expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
nodesMap.forEach(node => {
nodesMap.forEach((node) => {
// 触发 getter
node.settingEntry;
});
@ -271,11 +280,13 @@ describe('schema 生成节点模型测试', () => {
describe('block ❌ | component ❌ | slot ✅', () => {
it('基本的节点模型初始化,模型导出,初始化传入 schema', () => {
const formSchemaWithSlot = set(cloneDeep(formSchema), 'children[0].children[0].props.title.type', 'JSSlot');
const formSchemaWithSlot = set(
cloneDeep(formSchema),
'children[0].children[0].props.title.type',
'JSSlot',
);
const project = new Project(designer, {
componentsTree: [
formSchemaWithSlot,
],
componentsTree: [formSchemaWithSlot],
});
project.open();
expect(project).toBeTruthy();
@ -290,7 +301,5 @@ describe('schema 生成节点模型测试', () => {
});
});
describe.skip('多 document 测试', () => {
});
describe.skip('多 document 测试', () => {});
});

View File

@ -1,4 +1,4 @@
import lodashSet from 'lodash/set';
import { set as lodashSet } from 'lodash-es';
export function set(obj: any, path: any, val: any) {
if (typeof path === 'string' && path.startsWith('prototype')) {
@ -17,7 +17,7 @@ export function set(obj: any, path: any, val: any) {
}
export function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
return new Promise((resolve) => setTimeout(resolve, ms));
}
export function delayObxTick() {

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "temp",
"stripInternal": true,
"paths": {}
}
}

View File

@ -1,12 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib",
"types": ["node","jest"]
"outDir": "dist"
},
"include": [
"./src/",
"./tests/"
],
"exclude": ["**/lib", "**/es", "node_modules"]
"include": ["src"]
}

View File

@ -0,0 +1,23 @@
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
import react from '@vitejs/plugin-react';
import { devDependencies, peerDependencies } from './package.json';
const externals = [...Object.keys(peerDependencies), ...Object.keys(devDependencies)];
export default defineConfig({
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(import.meta.dirname, 'src/index.ts'),
name: 'LowCodeDesigner',
formats: ['es', 'cjs'],
// the proper extensions will be added
fileName: 'designer',
},
rollupOptions: {
external: externals,
},
},
plugins: [react()],
});

View File

View File

@ -3,18 +3,30 @@
"version": "2.0.0-beta.0",
"description": "Core Api for Ali lowCode engine",
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"main": "dist/editorCore.js",
"module": "dist/editorCore.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/editorCore.js",
"types": "./dist/index.d.ts"
}
},
"sideEffects": [
"*.css",
"*.less"
],
"files": [
"lib",
"es"
"dist",
"src",
"package.json"
],
"scripts": {
"build": "tsc",
"test": "build-scripts test --config build.test.json",
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
"build": "vite build",
"build-dts": "tsc -p tsconfig.declaration.json && node ../../scripts/rollup-dts.mjs",
"test": "vitest",
"test:cov": ""
},
"dependencies": {
"@alifd/next": "^1.27.8",
@ -29,16 +41,18 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"store": "^2.0.12",
"strict-event-emitter-types": "^2.0.0"
"strict-event-emitter-types": "^2.0.0",
"events": "^3.3.0"
},
"devDependencies": {
"@alilc/lowcode-datasource-types": "^1.0.1",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/store": "^2.0.2"
"@types/store": "^2.0.2",
"less": "^4.2.0"
},
"peerDependencies": {
"@alifd/next": "^1.27.8",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},

View File

@ -1,5 +1,3 @@
/* eslint-disable no-console */
/* eslint-disable max-len */
import { StrictEventEmitter } from 'strict-event-emitter-types';
import { EventEmitter } from 'events';
import { EventBus, IEventBus } from './event-bus';
@ -39,6 +37,7 @@ const AssetsCache: {
[key: string]: IPublicTypeRemoteComponentDescription;
} = {};
// @ts-ignore
export declare interface Editor extends StrictEventEmitter<EventEmitter, GlobalEvent.EventConfig> {
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
once(event: string | symbol, listener: (...args: any[]) => void): this;

View File

@ -1,5 +1,6 @@
import { observer } from 'mobx-react';
import { configure } from 'mobx';
import * as mobx from 'mobx';
configure({ enforceActions: 'never' });
@ -19,5 +20,4 @@ export {
} from 'mobx';
export type { IReactionDisposer, IReactionPublic, IReactionOptions } from 'mobx';
export * as mobx from 'mobx';
export { observer };
export { observer, mobx };

View File

@ -106,7 +106,11 @@ export class TipItem extends Component {
render() {
const tip: IPublicTypeTipConfig = tipHandler.tip || ({} as any);
const className = classNames('lc-tip', tip.className, tip && tip.theme ? `lc-theme-${tip.theme}` : null);
const className = classNames(
'lc-tip',
tip.className,
tip && tip.theme ? `lc-theme-${tip.theme}` : null,
);
this.originClassName = className;
@ -118,7 +122,7 @@ export class TipItem extends Component {
}}
>
<i className="lc-arrow" />
<div className="lc-tip-content">{intl(tip.children)}</div>
<div className="lc-tip-content">{intl((tip as any).children)}</div>
</div>
);
}

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "temp",
"stripInternal": true,
"paths": {}
}
}

View File

@ -1,10 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"paths": {
"@alilc/lowcode-*": ["packages/*"]
}
"outDir": "dist"
},
"include": ["src"]
}

View File

@ -0,0 +1,23 @@
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
import react from '@vitejs/plugin-react';
import { devDependencies, peerDependencies } from './package.json';
const externals = [...Object.keys(peerDependencies), ...Object.keys(devDependencies)];
export default defineConfig({
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(import.meta.dirname, 'src/index.ts'),
name: 'LowCodeEditorCore',
formats: ['es'],
// the proper extensions will be added
fileName: 'editorCore',
},
rollupOptions: {
external: externals,
},
},
plugins: [react()],
});

View File

View File

@ -1,9 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce",
"build-plugin-fusion",
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
}]
]
}

View File

@ -1,9 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
],
"babelPlugins": [
["@babel/plugin-proposal-private-property-in-object", { "loose": true }]
]
}

View File

@ -1,29 +0,0 @@
const fs = require('fs');
const { join } = require('path');
const esModules = [].join('|');
const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
const jestConfig = {
// transform: {
// '^.+\\.[jt]sx?$': 'babel-jest',
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
collectCoverage: false,
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!**/node_modules/**',
'!**/vendor/**',
],
};
// 只对本仓库内的 pkg 做 mapping
jestConfig.moduleNameMapper = {};
jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';
module.exports = jestConfig;

View File

@ -1,38 +1,55 @@
{
"name": "@alilc/lowcode-editor-skeleton",
"version": "1.3.2",
"version": "2.0.0-beta.0",
"description": "alibaba lowcode editor skeleton",
"main": "lib/index.js",
"module": "es/index.js",
"stylePath": "style.js",
"type": "module",
"main": "dist/designer.cjs",
"module": "dist/designer.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/designer.js",
"require": "./dist/designer.cjs",
"types": "./dist/index.d.ts"
}
},
"sideEffects": [
"*.css"
],
"files": [
"lib",
"es"
"dist",
"src",
"package.json"
],
"scripts": {
"test": "build-scripts test --config build.test.json",
"build": "build-scripts build"
"build": "vite build",
"build-dts": "tsc -p tsconfig.declaration.json && node ../../scripts/rollup-dts.mjs",
"test": "vitest"
},
"keywords": [
"lowcode",
"editor"
],
"dependencies": {
"@alifd/next": "^1.20.12",
"@alilc/lowcode-designer": "1.3.2",
"@alilc/lowcode-editor-core": "1.3.2",
"@alilc/lowcode-types": "1.3.2",
"@alilc/lowcode-utils": "1.3.2",
"@alifd/next": "^1.27.8",
"@alilc/lowcode-designer": "workspace:*",
"@alilc/lowcode-editor-core": "workspace:*",
"@alilc/lowcode-types": "workspace:*",
"@alilc/lowcode-utils": "workspace:*",
"classnames": "^2.2.6",
"react": "^16.8.1",
"react-dom": "^16.8.1"
"lodash-es": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.3",
"@types/react": "^16.9.13",
"@types/react-dom": "^16.9.4",
"build-plugin-fusion": "^0.1.0",
"build-plugin-moment-locales": "^0.1.0"
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
},
"peerDependencies": {
"@alifd/next": "^1.27.8",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public",

View File

@ -1,6 +1,5 @@
/* eslint-disable react/no-unused-prop-types */
import { Component, ErrorInfo, MouseEvent } from 'react';
import { isObject } from 'lodash';
import { Component, ErrorInfo, MouseEvent, type ReactNode } from 'react';
import { isObject } from 'lodash-es';
import classNames from 'classnames';
import { Icon } from '@alifd/next';
import { Title } from '@alilc/lowcode-editor-core';
@ -25,6 +24,7 @@ export interface FieldProps {
tip?: any;
onExpandChange?: (expandState: boolean) => void;
onClear?: () => void;
children?: ReactNode;
}
export class Field extends Component<FieldProps> {
@ -116,22 +116,37 @@ export class Field extends Component<FieldProps> {
getTipContent(propName: string, tip?: any): any {
let tipContent = (
<div>
<div>{intl('Attribute: ')}{propName}</div>
<div>
{intl('Attribute: ')}
{propName}
</div>
</div>
);
if (isObject(tip)) {
tipContent = (
<div>
<div>{intl('Attribute: ')}{propName}</div>
<div>{intl('Description: ')}{(tip as any).content}</div>
<div>
{intl('Attribute: ')}
{propName}
</div>
<div>
{intl('Description: ')}
{(tip as any).content}
</div>
</div>
);
} else if (tip) {
tipContent = (
<div>
<div>{intl('Attribute: ')}{propName}</div>
<div>{intl('Description: ')}{tip}</div>
<div>
{intl('Attribute: ')}
{propName}
</div>
<div>
{intl('Description: ')}
{tip}
</div>
</div>
);
}
@ -149,7 +164,7 @@ export class Field extends Component<FieldProps> {
return null;
}
const { className, children, meta, title, valueState, name: propName, tip } = this.props;
const { className, children, meta, title, name: propName, tip } = this.props;
const { display, collapsed } = this.state;
const isAccordion = display === 'accordion';
let hostName = '';
@ -167,22 +182,23 @@ export class Field extends Component<FieldProps> {
})}
id={id}
>
{
display !== 'plain' && (
<div className="lc-field-head" onClick={isAccordion ? this.toggleExpand : undefined}>
<div className="lc-field-title">
{createValueState(valueState, this.handleClear)}
<Title
title={title || ''}
onClick={this.clickHandler}
/>
<InlineTip position="top">{tipContent}</InlineTip>
</div>
{isAccordion && <Icon className="lc-field-icon" type="arrow-up" size="xs" />}
{display !== 'plain' && (
<div className="lc-field-head" onClick={isAccordion ? this.toggleExpand : undefined}>
<div className="lc-field-title">
{createValueState()}
<Title title={title || ''} onClick={this.clickHandler} />
<InlineTip position="top">{tipContent}</InlineTip>
</div>
)
}
<div key="body" ref={(shell) => { this.body = shell; }} className="lc-field-body">
{isAccordion && <Icon className="lc-field-icon" type="arrow-up" size="xs" />}
</div>
)}
<div
key="body"
ref={(shell) => {
this.body = shell;
}}
className="lc-field-body"
>
{children}
</div>
</div>

View File

@ -8,18 +8,17 @@ export interface PopupExtProps {
width?: number;
hasMask?: boolean;
trigger?: ReactNode;
canCloseByOutSideClick?: boolean
canCloseByOutSideClick?: boolean;
className?: string;
safeNode?: string[];
}
interface PopupProps extends PopupExtProps{
content?: ReactNode,
title?: ReactNode,
actionKey?: string
interface PopupProps extends PopupExtProps {
content?: ReactNode;
title?: ReactNode;
actionKey?: string;
}
export const PopupContext = createContext<PopupPipe>({} as any);
export class PopupPipe {
@ -84,6 +83,7 @@ export default class PopupService extends Component<{
actionKey?: string;
safeId?: string;
popupContainer?: string;
children?: ReactNode;
}> {
private popupPipe = this.props.popupPipe || new PopupPipe();
@ -103,9 +103,9 @@ export default class PopupService extends Component<{
}
interface StateType extends PopupProps {
visible?: boolean,
offsetX?: number,
pos?: {top: number, height: number}
visible?: boolean;
offsetX?: number;
pos?: { top: number; height: number };
}
export class PopupContent extends PureComponent<{ safeId?: string; popupContainer?: string }> {
static contextType = PopupContext;
@ -153,7 +153,18 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine
};
render() {
const { content, visible, title, actionKey, pos, offsetX, width = 360, hasMask = false, canCloseByOutSideClick = true, safeNode = [] } = this.state;
const {
content,
visible,
title,
actionKey,
pos,
offsetX,
width = 360,
hasMask = false,
canCloseByOutSideClick = true,
safeNode = [],
} = this.state;
if (!visible) {
return null;
}
@ -171,7 +182,7 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine
visible={visible}
offset={[offsetX, 0]}
hasMask={hasMask}
onVisibleChange={(_visible, type) => {
onVisibleChange={(_visible: boolean, type: string) => {
if (avoidLaterHidden) {
return;
}
@ -186,15 +197,12 @@ export class PopupContent extends PureComponent<{ safeId?: string; popupContaine
onClose={this.onClose}
id={this.props.safeId}
safeNode={[id, ...safeNode]}
closeable
container={this.props.popupContainer}
>
<div className="lc-ballon-title">{title}</div>
<div className="lc-ballon-content">
<PopupService actionKey={actionKey} safeId={id} popupContainer={this.popupContainerId}>
<ConfigProvider popupContainer={this.popupContainerId}>
{content}
</ConfigProvider>
<ConfigProvider popupContainer={this.popupContainerId}>{content}</ConfigProvider>
</PopupService>
</div>
<div id={this.popupContainerId} />

View File

@ -1,5 +1,13 @@
import { Node, Designer, Selection, SettingTopEntry } from '@alilc/lowcode-designer';
import { Editor, obx, computed, makeObservable, action, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import {
Editor,
obx,
computed,
makeObservable,
action,
IEventBus,
createModuleEventBus,
} from '@alilc/lowcode-editor-core';
function generateSessionId(nodes: Node[]) {
return nodes
@ -72,9 +80,9 @@ export class SettingsMain {
// 当节点只有一个时,复用 node 上挂载的 settingEntry不会产生平行的两个实例这样在整个系统中对
// 某个节点操作的 SettingTopEntry 只有一个实例,后续的 getProp() 也会拿到相同的 SettingField 实例
if (nodes.length === 1) {
this._settings = nodes[0].settingEntry;
this._settings = nodes[0].settingEntry as any;
} else {
this._settings = this.designer.createSettingEntry(nodes);
this._settings = this.designer.createSettingEntry(nodes) as any;
}
}

View File

@ -1,9 +1,25 @@
import { Component, MouseEvent, Fragment, ReactNode } from 'react';
import { shallowIntl, observer, obx, engineConfig, runInAction } from '@alilc/lowcode-editor-core';
import { createContent, isJSSlot, isSetterConfig, shouldUseVariableSetter } from '@alilc/lowcode-utils';
import { Skeleton, Stage } from '@alilc/lowcode-editor-skeleton';
import { IPublicApiSetters, IPublicTypeCustomView, IPublicTypeDynamicProps } from '@alilc/lowcode-types';
import { ISettingEntry, IComponentMeta, ISettingField, isSettingField, ISettingTopEntry } from '@alilc/lowcode-designer';
import {
createContent,
isJSSlot,
isSetterConfig,
shouldUseVariableSetter,
} from '@alilc/lowcode-utils';
import { Skeleton } from '../../skeleton';
import { Stage } from '../../widget/stage';
import {
IPublicApiSetters,
IPublicTypeCustomView,
IPublicTypeDynamicProps,
} from '@alilc/lowcode-types';
import {
ISettingEntry,
IComponentMeta,
ISettingField,
isSettingField,
ISettingTopEntry,
} from '@alilc/lowcode-designer';
import { createField } from '../field';
import PopupService, { PopupPipe } from '../popup';
import { SkeletonContext } from '../../context';
@ -24,10 +40,14 @@ function isStandardComponent(componentMeta: IComponentMeta | null) {
*/
function isInitialValueNotEmpty(initialValue: any) {
if (isJSSlot(initialValue)) {
// @ts-ignore visible 为 false 代表默认不展示
return initialValue.visible !== false && Array.isArray(initialValue.value) && initialValue.value.length > 0;
return (
// @ts-ignore visible 为 false 代表默认不展示
initialValue.visible !== false &&
Array.isArray(initialValue.value) &&
initialValue.value.length > 0
);
}
return (initialValue !== undefined && initialValue !== null);
return initialValue !== undefined && initialValue !== null;
}
type SettingFieldViewProps = { field: ISettingField };
@ -61,7 +81,11 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
stages.add({
type: 'Widget',
name: stageName,
content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>,
content: (
<Fragment>
{field.items.map((item, index) => createSettingFieldView(item, field, index))}
</Fragment>
),
props: {
title: field.title,
},
@ -79,7 +103,9 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
const { extraProps } = this.field;
const { condition } = extraProps;
try {
return typeof condition === 'function' ? condition(this.field.internalToShellField()) !== false : true;
return typeof condition === 'function'
? condition(this.field.internalToShellField()) !== false
: true;
} catch (error) {
console.error('exception when condition (hidden) is excuted', error);
}
@ -111,16 +137,18 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
const { defaultValue } = extraProps;
const { setter } = this.field;
let setterProps: {
setters?: (ReactNode | string)[];
} & Record<string, unknown> | IPublicTypeDynamicProps = {};
let setterProps:
| ({
setters?: (ReactNode | string)[];
} & Record<string, unknown>)
| IPublicTypeDynamicProps = {};
let setterType: any;
let initialValue: any = null;
if (Array.isArray(setter)) {
setterType = 'MixedSetter';
setterProps = {
setters: setter,
setters: setter as any,
};
} else if (isSetterConfig(setter)) {
setterType = setter.componentName;
@ -154,7 +182,8 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
// 根据是否支持变量配置做相应的更改
const supportVariable = this.field.extraProps?.supportVariable;
// supportVariableGlobally 只对标准组件生效vc 需要单独配置
const supportVariableGlobally = engineConfig.get('supportVariableGlobally', false) && isStandardComponent(componentMeta);
const supportVariableGlobally =
engineConfig.get('supportVariableGlobally', false) && isStandardComponent(componentMeta);
const isUseVariableSetter = shouldUseVariableSetter(supportVariable, supportVariableGlobally);
if (isUseVariableSetter === false) {
return {
@ -172,10 +201,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
} else {
setterType = 'MixedSetter';
setterProps = {
setters: [
setter,
'VariableSetter',
],
setters: [setter as any, 'VariableSetter'],
};
}
return {
@ -191,7 +217,8 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
initDefaultValue() {
const { initialValue } = this.setterInfo;
if (this.state?.fromOnChange ||
if (
this.state?.fromOnChange ||
!isInitialValueNotEmpty(initialValue) ||
this.ignoreDefaultValue ||
this.value !== undefined
@ -200,7 +227,10 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
}
// 当前 field 没有 value 值时,将 initialValue 写入 field
// 之所以用 initialValue而不是 defaultValue 是为了保持跟 props.onInitial 的逻辑一致
const _initialValue = typeof initialValue === 'function' ? initialValue(this.field.internalToShellField()) : initialValue;
const _initialValue =
typeof initialValue === 'function'
? initialValue(this.field.internalToShellField())
: initialValue;
this.field.setValue(_initialValue);
}
@ -217,11 +247,7 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
return null;
}
const {
setterProps = {},
setterType,
initialValue = null,
} = this.setterInfo;
const { setterProps = {}, setterType, initialValue = null } = this.setterInfo;
const value = this.value;
@ -243,44 +269,47 @@ class SettingFieldView extends Component<SettingFieldViewProps, SettingFieldView
...extraProps,
},
!stageName &&
this.setters?.createSetterContent(setterType, {
...shallowIntl(setterProps),
forceInline: extraProps.forceInline,
key: field.id,
// === injection
prop: field.internalToShellField(), // for compatible vision
selected: field.top?.getNode()?.internalToShellNode(),
field: field.internalToShellField(),
// === IO
value, // reaction point
initialValue,
onChange: (value: any) => {
this.setState({
fromOnChange: true,
// eslint-disable-next-line react/no-unused-state
value,
});
field.setValue(value, true);
if (onChangeAPI) onChangeAPI(value, field.internalToShellField());
},
onInitial: () => {
if (initialValue == null) {
return;
}
const value = typeof initialValue === 'function' ? initialValue(field.internalToShellField()) : initialValue;
this.setState({
// eslint-disable-next-line react/no-unused-state
value,
});
field.setValue(value, true);
},
this.setters?.createSetterContent(setterType, {
...shallowIntl(setterProps),
forceInline: extraProps.forceInline,
key: field.id,
// === injection
prop: field.internalToShellField(), // for compatible vision
selected: field.top?.getNode()?.internalToShellNode(),
field: field.internalToShellField(),
// === IO
value, // reaction point
initialValue,
onChange: (value: any) => {
this.setState({
fromOnChange: true,
// eslint-disable-next-line react/no-unused-state
value,
});
field.setValue(value, true);
if (onChangeAPI) onChangeAPI(value, field.internalToShellField());
},
onInitial: () => {
if (initialValue == null) {
return;
}
const value =
typeof initialValue === 'function'
? initialValue(field.internalToShellField())
: initialValue;
this.setState({
// eslint-disable-next-line react/no-unused-state
value,
});
field.setValue(value, true);
},
removeProp: () => {
if (field.name) {
field.parent.clearPropValue(field.name);
}
},
}),
removeProp: () => {
if (field.name) {
field.parent.clearPropValue(field.name);
}
},
}),
extraProps.forceInline ? 'plain' : extraProps.display,
);
}
@ -311,7 +340,11 @@ class SettingGroupView extends Component<SettingGroupViewProps> {
stages.add({
type: 'Widget',
name: stageName,
content: <Fragment>{field.items.map((item, index) => createSettingFieldView(item, field, index))}</Fragment>,
content: (
<Fragment>
{field.items.map((item, index) => createSettingFieldView(item, field, index))}
</Fragment>
),
props: {
title: field.title,
},
@ -325,7 +358,10 @@ class SettingGroupView extends Component<SettingGroupViewProps> {
const { field } = this.props;
const { extraProps } = field;
const { condition, display } = extraProps;
const visible = field.isSingle && typeof condition === 'function' ? condition(field.internalToShellField()) !== false : true;
const visible =
field.isSingle && typeof condition === 'function'
? condition(field.internalToShellField()) !== false
: true;
if (!visible) {
return null;
@ -349,7 +385,11 @@ class SettingGroupView extends Component<SettingGroupViewProps> {
}
}
export function createSettingFieldView(field: ISettingField | IPublicTypeCustomView, fieldEntry: ISettingEntry, index?: number) {
export function createSettingFieldView(
field: ISettingField | IPublicTypeCustomView,
fieldEntry: ISettingEntry,
index?: number,
) {
if (isSettingField(field)) {
if (field.isGroup) {
return <SettingGroupView field={field} key={field.id} />;
@ -411,10 +451,6 @@ export class SettingsPane extends Component<SettingsPaneProps> {
}
};
private popStage() {
this.currentStage = this.currentStage?.getPrevious();
}
render() {
const { target } = this.props;
const { items } = target;

View File

@ -1,6 +1,14 @@
import React, { Component } from 'react';
import { Tab, Breadcrumb } from '@alifd/next';
import { Title, observer, Editor, obx, globalContext, engineConfig, makeObservable } from '@alilc/lowcode-editor-core';
import {
Title,
observer,
Editor,
obx,
globalContext,
engineConfig,
makeObservable,
} from '@alilc/lowcode-editor-core';
import { Node, SettingField, isSettingField, INode } from '@alilc/lowcode-designer';
import classNames from 'classnames';
import { SettingsMain } from './main';
@ -16,7 +24,10 @@ interface ISettingsPrimaryPaneProps {
}
@observer
export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, { shouldIgnoreRoot: boolean }> {
export class SettingsPrimaryPane extends Component<
ISettingsPrimaryPaneProps,
{ shouldIgnoreRoot: boolean }
> {
state = {
shouldIgnoreRoot: false,
};
@ -93,27 +104,29 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
l === 2
? {}
: {
onMouseOver: hoverNode.bind(null, _node, true),
onMouseOut: hoverNode.bind(null, _node, false),
onClick: () => {
if (!_node) {
return;
}
selectNode.call(null, _node);
const getName = (node: any) => {
const npm = node?.componentMeta?.npm;
return [npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
node?.componentMeta?.componentName ||
'';
};
const selected = getName(current);
const target = getName(_node);
editor?.eventBus.emit('skeleton.settingsPane.Breadcrumb', {
selected,
target,
});
},
};
onMouseOver: hoverNode.bind(null, _node, true),
onMouseOut: hoverNode.bind(null, _node, false),
onClick: () => {
if (!_node) {
return;
}
selectNode.call(null, _node);
const getName = (node: any) => {
const npm = node?.componentMeta?.npm;
return (
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') ||
node?.componentMeta?.componentName ||
''
);
};
const selected = getName(current);
const target = getName(_node);
editor?.eventBus.emit('skeleton.settingsPane.Breadcrumb', {
selected,
target,
});
},
};
items.unshift(
<Breadcrumb.Item {...props} key={node.id}>
<Title title={node.title} />
@ -179,7 +192,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
}
const { items } = settings;
if (items.length > 5 || items.some((item) => !isSettingField(item) || !item.isGroup)) {
if (items.length > 5 || items.some((item: any) => !isSettingField(item) || !item.isGroup)) {
return (
<div className="lc-settings-main">
{this.renderBreadcrumb()}
@ -188,6 +201,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
{(skeleton) => {
if (skeleton) {
return (
// @ts-ignore
<StageBox skeleton={skeleton} target={settings} key={settings.id}>
<SettingsPane target={settings} usePopup={false} />
</StageBox>
@ -211,19 +225,18 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
className="lc-settings-tab-item"
title={<Title title={field.title} />}
key={field.name}
onClick={
() => {
editor?.eventBus.emit('skeleton.settingsPane.change', {
name: field.name,
title: field.title,
});
}
}
onClick={() => {
editor?.eventBus.emit('skeleton.settingsPane.change', {
name: field.name,
title: field.title,
});
}}
>
<SkeletonContext.Consumer>
{(skeleton) => {
if (skeleton) {
return (
// @ts-ignore
<StageBox skeleton={skeleton} target={field} key={field.id}>
<SettingsPane target={field} key={field.id} usePopup={false} />
</StageBox>
@ -243,7 +256,7 @@ export class SettingsPrimaryPane extends Component<ISettingsPrimaryPaneProps, {
});
return (
<div className={className}>
{ this.renderBreadcrumb() }
{this.renderBreadcrumb()}
<Tab
activeKey={activeKey}
onChange={(tabKey) => {

View File

@ -1,28 +1,34 @@
function getHotterFromSetter(setter) {
return setter && (setter.Hotter || (setter.type && setter.type.Hotter)) || []; // eslint-disable-line
function getHotterFromSetter(setter: any) {
return (setter && (setter.Hotter || (setter.type && setter.type.Hotter))) || []; // eslint-disable-line
}
function getTransducerFromSetter(setter) {
return setter && (
setter.transducer || setter.Transducer
|| (setter.type && (setter.type.transducer || setter.type.Transducer))
) || null; // eslint-disable-line
function getTransducerFromSetter(setter: any) {
return (
(setter &&
(setter.transducer ||
setter.Transducer ||
(setter.type && (setter.type.transducer || setter.type.Transducer)))) ||
null
); // eslint-disable-line
}
function combineTransducer(transducer, arr, context) {
function combineTransducer(transducer: any, arr: any, context: any) {
if (!transducer && Array.isArray(arr)) {
const [toHot, toNative] = arr;
transducer = { toHot, toNative };
}
return {
toHot: (transducer && transducer.toHot || (x => x)).bind(context), // eslint-disable-line
toNative: (transducer && transducer.toNative || (x => x)).bind(context), // eslint-disable-line
toHot: ((transducer && transducer.toHot) || ((x: any) => x)).bind(context), // eslint-disable-line
toNative: ((transducer && transducer.toNative) || ((x: any) => x)).bind(context), // eslint-disable-line
};
}
export class Transducer {
constructor(context, config) {
context: any;
setterTransducer: any;
constructor(context: any, config: any) {
this.setterTransducer = combineTransducer(
getTransducerFromSetter(config.setter),
getHotterFromSetter(config.setter),
@ -31,11 +37,11 @@ export class Transducer {
this.context = context;
}
toHot(data) {
toHot(data: any) {
return this.setterTransducer.toHot(data);
}
toNative(data) {
toNative(data: any) {
return this.setterTransducer.toNative(data);
}
}

View File

@ -104,8 +104,12 @@ export default class StageBox extends Component<StageBoxProps> {
let contentRefer = null;
if (refer) {
contentCurrent = <Stage key={stage.getId()} stage={stage} direction={refer.direction} current />;
contentRefer = <Stage key={refer?.stage?.getId()} stage={refer?.stage} direction={refer.direction} />;
contentCurrent = (
<Stage key={stage.getId()} stage={stage} direction={refer.direction} current />
);
contentRefer = (
<Stage key={refer?.stage?.getId()} stage={refer?.stage} direction={refer.direction} />
);
} else {
contentCurrent = <Stage key={stage.getId()} stage={stage} current />;
}
@ -117,12 +121,10 @@ export default class StageBox extends Component<StageBoxProps> {
}}
className={className}
>
{/* @ts-ignore */}
<PopupService popupPipe={this.popupPipe}>
{contentRefer}
{contentCurrent}
</PopupService>
</div>
);

View File

@ -78,9 +78,17 @@ export default class Stage extends Component<StageProps> {
const stageBacker = stage?.hasBack() ? (
<div className="skeleton-stagebox-stagebacker">
<IconArrow className="skeleton-stagebox-stage-arrow" size="medium" data-stage-target="stageback" />
<span className="skeleton-stagebox-stage-title">{newTitle}</span>
<IconExit className="skeleton-stagebox-stage-exit" size="medium" data-stage-target="stageexit" />
<IconArrow
className="skeleton-stagebox-stage-arrow"
size="medium"
data-stage-target="stageback"
/>
<span className="skeleton-stagebox-stage-title">{newTitle as any}</span>
<IconExit
className="skeleton-stagebox-stage-exit"
size="medium"
data-stage-target="stageexit"
/>
</div>
) : null;

View File

@ -6,7 +6,7 @@ import { IconFloat } from '../../icons/float';
import { Panel } from '../../widget/panel';
export default class PanelOperationRow extends Component<{ panel: Panel }> {
constructor(props) {
constructor(props: any) {
super(props);
makeObservable(this);
}
@ -36,8 +36,8 @@ export default class PanelOperationRow extends Component<{ panel: Panel }> {
const hideTitleBar = panel?.config.props?.hideTitleBar;
const areaName = panel?.parent?.name;
const area = panel.skeleton[areaName];
const areaName = panel?.parent?.name ?? '';
const area = (panel.skeleton as any)[areaName];
return (
<Fragment>

View File

@ -3,7 +3,7 @@ import { SVGIcon, IconProps } from '@alilc/lowcode-utils';
export function IconSlot(props: IconProps) {
return (
<SVGIcon viewBox="0 0 1024 1024" {...props}>
<path d="M682.325333 135.509333V204.8H819.2v613.376h-614.741333V204.8h136.874666v-69.290667h-206.165333v752.298667h754.346667V135.509333z" c="Q29weXJpZ2h0IChjKSAyMDIwLXByZXNlbnQgQWxpYmFiYSBJbmMu" />
<path d="M682.325333 135.509333V204.8H819.2v613.376h-614.741333V204.8h136.874666v-69.290667h-206.165333v752.298667h754.346667V135.509333z" />
<path d="M512 512m-170.325333 0a170.325333 170.325333 0 1 0 340.650666 0 170.325333 170.325333 0 1 0-340.650666 0Z" />
</SVGIcon>
);

View File

@ -9,3 +9,4 @@ export * from './context';
export * from './register-defaults';
export * from './widget';
export * from './layouts';
export * from './event';

View File

@ -1,7 +1,7 @@
import { Component, Fragment } from 'react';
import classNames from 'classnames';
import { observer } from '@alilc/lowcode-editor-core';
import { Area } from '@alilc/lowcode-editor-skeleton';
import { Area } from '../area';
@observer
export default class SubTopArea extends Component<{ area: Area; itemClassName?: string }> {
@ -13,9 +13,10 @@ export default class SubTopArea extends Component<{ area: Area; itemClassName?:
}
return (
<div className={classNames('lc-workspace-sub-top-area lc-sub-top-area engine-actionpane', {
'lc-area-visible': area.visible,
})}
<div
className={classNames('lc-workspace-sub-top-area lc-sub-top-area engine-actionpane', {
'lc-area-visible': area.visible,
})}
>
<Contents area={area} itemClassName={itemClassName} />
</div>
@ -30,38 +31,43 @@ class Contents extends Component<{ area: Area; itemClassName?: string }> {
const left: any[] = [];
const center: any[] = [];
const right: any[] = [];
area.container.items.slice().sort((a, b) => {
const index1 = a.config?.index || 0;
const index2 = b.config?.index || 0;
return index1 === index2 ? 0 : (index1 > index2 ? 1 : -1);
}).forEach(item => {
const content = (
<div className={itemClassName || ''} key={`top-area-${item.name}`}>
{item.content}
</div>
);
if (item.align === 'center') {
center.push(content);
} else if (item.align === 'left') {
left.push(content);
} else {
right.push(content);
}
});
area.container.items
.slice()
.sort((a, b) => {
const index1 = a.config?.index || 0;
const index2 = b.config?.index || 0;
return index1 === index2 ? 0 : index1 > index2 ? 1 : -1;
})
.forEach((item) => {
const content = (
<div className={itemClassName || ''} key={`top-area-${item.name}`}>
{item.content}
</div>
);
if (item.align === 'center') {
center.push(content);
} else if (item.align === 'left') {
left.push(content);
} else {
right.push(content);
}
});
let children = [];
if (left && left.length) {
children.push(<div className="lc-workspace-sub-top-area-left lc-sub-top-area-left">{left}</div>);
children.push(
<div className="lc-workspace-sub-top-area-left lc-sub-top-area-left">{left}</div>,
);
}
if (center && center.length) {
children.push(<div className="lc-workspace-sub-top-area-center lc-sub-top-area-center">{center}</div>);
children.push(
<div className="lc-workspace-sub-top-area-center lc-sub-top-area-center">{center}</div>,
);
}
if (right && right.length) {
children.push(<div className="lc-workspace-sub-top-area-right lc-sub-top-area-right">{right}</div>);
children.push(
<div className="lc-workspace-sub-top-area-right lc-sub-top-area-right">{right}</div>,
);
}
return (
<Fragment>
{children}
</Fragment>
);
return <Fragment>{children}</Fragment>;
}
}

View File

@ -0,0 +1 @@
declare module 'ric-shim';

View File

@ -36,27 +36,29 @@ function transformStringToFunction(str: string) {
fn = new Function(fnBody)();
} catch (e) {
logger.error(str);
logger.error(e.message);
logger.error((e as Error).message);
}
return fn;
}
function parseJSFunc(obj: any, enableAllowedKeys = true) {
if (!obj) return;
Object.keys(obj).forEach(key => {
Object.keys(obj).forEach((key) => {
const item = obj[key];
if (isJSFunction(item)) {
obj[key] = transformStringToFunction(item.value);
} else if (Array.isArray(item)) {
item.forEach(o => parseJSFunc(o, enableAllowedKeys));
item.forEach((o) => parseJSFunc(o, enableAllowedKeys));
} else if (isPlainObject(item)) {
parseJSFunc(item, enableAllowedKeys);
}
});
}
export default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata {
export default function (
metadata: IPublicTypeTransformedComponentMetadata,
): IPublicTypeTransformedComponentMetadata {
parseJSFunc(metadata, false);
return metadata;
}
}

View File

@ -21,7 +21,7 @@ function propConfigToFieldConfig(propConfig: IPublicTypePropConfig): IPublicType
'zh-CN': description?.slice(0, 10) || name,
},
tip: description ? `${name} | ${description}` : undefined,
};
} as any;
return {
title,
...propConfig,
@ -65,7 +65,8 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
const dataSource = ((propType as IPublicTypeOneOf).value || []).map((value, index) => {
const t = typeof value;
return {
label: t === 'string' || t === 'number' || t === 'boolean' ? String(value) : `value ${index}`,
label:
t === 'string' || t === 'number' || t === 'boolean' ? String(value) : `value ${index}`,
value,
};
});
@ -93,7 +94,9 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
};
case 'shape':
case 'exact':
const items = ((propType as any).value || []).map((item: any) => propConfigToFieldConfig(item));
const items = ((propType as any).value || []).map((item: any) =>
propConfigToFieldConfig(item),
);
return {
componentName: 'ObjectSetter',
props: {
@ -110,7 +113,11 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
if (initial == null && item.setter && typeof item.setter === 'object') {
initial = (item.setter as any).initialValue;
}
data[item.name] = initial ? (typeof initial === 'function' ? initial(field) : initial) : null;
data[item.name] = initial
? typeof initial === 'function'
? initial(field)
: initial
: null;
});
return data;
},
@ -121,7 +128,9 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
componentName: 'ObjectSetter',
props: {
config: {
extraSetter: propTypeToSetter(typeName === 'objectOf' ? (propType as IPublicTypeObjectOf).value : 'any'),
extraSetter: propTypeToSetter(
typeName === 'objectOf' ? (propType as IPublicTypeObjectOf).value : 'any',
),
},
},
isRequired,
@ -132,7 +141,9 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
return {
componentName: 'ArraySetter',
props: {
itemSetter: propTypeToSetter(typeName === 'arrayOf' ? (propType as IPublicTypeArrayOf).value : 'any'),
itemSetter: propTypeToSetter(
typeName === 'arrayOf' ? (propType as IPublicTypeArrayOf).value : 'any',
),
},
isRequired,
initialValue: [],
@ -157,7 +168,7 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
isRequired,
};
default:
// do nothing
// do nothing
}
return {
componentName: 'MixedSetter',
@ -168,7 +179,9 @@ function propTypeToSetter(propType: IPublicTypePropType): IPublicTypeSetterType
const EVENT_RE = /^on|after|before[A-Z][\w]*$/;
export default function (metadata: IPublicTypeTransformedComponentMetadata): IPublicTypeTransformedComponentMetadata {
export default function (
metadata: IPublicTypeTransformedComponentMetadata,
): IPublicTypeTransformedComponentMetadata {
const { configure = {} } = metadata;
// TODO types后续补充
let extendsProps: any = null;

View File

@ -1,7 +1,7 @@
import { ReactNode, createElement } from 'react';
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
import { uniqueId, createContent } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell';
import { getEvent } from '../event';
import { DockConfig } from '../types';
import { ISkeleton } from '../skeleton';
import { DockView, WidgetView } from '../components/widget-views';
@ -59,7 +59,10 @@ export class Dock implements IWidget {
return this._body;
}
constructor(readonly skeleton: ISkeleton, readonly config: DockConfig) {
constructor(
readonly skeleton: ISkeleton,
readonly config: DockConfig,
) {
makeObservable(this);
const { props = {}, name } = config;
this.name = name;

View File

@ -1,9 +1,19 @@
import { createElement, ReactNode } from 'react';
import { obx, computed, makeObservable, IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
import {
obx,
computed,
makeObservable,
IEventBus,
createModuleEventBus,
} from '@alilc/lowcode-editor-core';
import { uniqueId, createContent } from '@alilc/lowcode-utils';
import { IPublicTypeHelpTipConfig, IPublicTypePanelConfig, IPublicTypeTitleContent } from '@alilc/lowcode-types';
import {
IPublicTypeHelpTipConfig,
IPublicTypePanelConfig,
IPublicTypeTitleContent,
} from '@alilc/lowcode-types';
import { WidgetContainer } from './widget-container';
import { getEvent } from '@alilc/lowcode-shell';
import { getEvent } from '../event';
import { TitledPanelView, TabsPanelView, PanelView } from '../components/widget-views';
import { ISkeleton } from '../skeleton';
import { composeTitle } from './utils';
@ -49,7 +59,7 @@ export class Panel implements IWidget {
}
const { content, contentProps } = this.config;
return createContent(content, {
return createContent(content as any, {
...contentProps,
editor: getEvent(this.skeleton.editor),
config: this.config,
@ -80,7 +90,10 @@ export class Panel implements IWidget {
@obx.ref public parent?: WidgetContainer;
constructor(readonly skeleton: ISkeleton, readonly config: IPublicTypePanelConfig) {
constructor(
readonly skeleton: ISkeleton,
readonly config: IPublicTypePanelConfig,
) {
makeObservable(this);
const { name, content, props = {} } = config;
const { hideTitleBar, title, icon, description, help } = props;
@ -108,8 +121,8 @@ export class Panel implements IWidget {
props.onInit.call(this, this);
}
if (typeof content !== 'string' && content && content.onInit) {
content.onInit.call(this, this);
if (typeof content !== 'string' && content && (content as any).onInit) {
(content as any).onInit.call(this, this);
}
// todo: process shortcut
}
@ -217,7 +230,7 @@ export class Panel implements IWidget {
}
getAssocDocks(): PanelDock[] {
return this.skeleton.widgets.filter(item => {
return this.skeleton.widgets.filter((item) => {
return isPanelDock(item) && item.panelName === this.name;
}) as any;
}

View File

@ -2,13 +2,19 @@ import { IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from '@alilc
import { isI18nData, isTitleConfig } from '@alilc/lowcode-utils';
import { isValidElement } from 'react';
export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicTypeIconType, tip?: TipContent, tipAsTitle?: boolean, noIcon?: boolean) {
export function composeTitle(
title?: IPublicTypeTitleContent,
icon?: IPublicTypeIconType,
tip?: TipContent,
tipAsTitle?: boolean,
noIcon?: boolean,
) {
let _title: IPublicTypeTitleContent | undefined;
if (!title) {
_title = {};
if (!icon || tipAsTitle) {
_title = {
label: tip,
label: tip as any,
};
tip = undefined;
}
@ -19,7 +25,7 @@ export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicType
if (icon || tip) {
if (typeof _title !== 'object' || isValidElement(_title) || isI18nData(_title)) {
if (isValidElement(_title)) {
if (_title.type === 'svg' || _title.type.getIcon) {
if (_title.type === 'svg' || (_title.type as any).getIcon) {
if (!icon) {
icon = _title;
}
@ -32,7 +38,7 @@ export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicType
}
}
_title = {
label: _title,
label: _title as any,
icon,
tip,
};
@ -41,7 +47,7 @@ export function composeTitle(title?: IPublicTypeTitleContent, icon?: IPublicType
..._title,
icon,
tip,
};
} as any;
}
}
if (isTitleConfig(_title) && noIcon) {

View File

@ -1,7 +1,7 @@
import { ReactNode, createElement } from 'react';
import { makeObservable, obx } from '@alilc/lowcode-editor-core';
import { createContent, uniqueId } from '@alilc/lowcode-utils';
import { getEvent } from '@alilc/lowcode-shell';
import { getEvent } from '../event';
import { WidgetConfig } from '../types';
import { ISkeleton } from '../skeleton';
import { WidgetView } from '../components/widget-views';
@ -71,7 +71,10 @@ export class Widget implements IWidget {
readonly title: IPublicTypeTitleContent;
constructor(readonly skeleton: ISkeleton, readonly config: WidgetConfig) {
constructor(
readonly skeleton: ISkeleton,
readonly config: WidgetConfig,
) {
makeObservable(this);
const { props = {}, name } = config;
this.name = name;

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "temp",
"stripInternal": true,
"paths": {}
}
}

View File

@ -0,0 +1,23 @@
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
import react from '@vitejs/plugin-react';
import { devDependencies, peerDependencies } from './package.json';
const externals = [...Object.keys(peerDependencies), ...Object.keys(devDependencies)];
export default defineConfig({
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(import.meta.dirname, 'src/index.ts'),
name: 'LowCodeEditorSkeleton',
formats: ['es', 'cjs'],
// the proper extensions will be added
fileName: 'editorSkeleton',
},
rollupOptions: {
external: externals,
},
},
plugins: [react()],
});

View File

@ -1 +0,0 @@
module.exports = require('../../babel.config');

View File

@ -1,19 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce",
[
"build-plugin-fusion",
{
"themePackage": "@alifd/theme-lowcode-light",
"externalNext": "umd"
}
],
[
"build-plugin-moment-locales",
{
"locales": ["zh-cn"]
}
],
"./build.plugin.js"
]
}

View File

@ -1,40 +0,0 @@
const { execSync } = require('child_process');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
// get version from git branch name,
// e.g. release/1.0.7 => 1.0.7
// release/1.0.7-beta => 1.0.7 (beta)
// release/1.0.7-beta.0 => 1.0.7 (beta)
function getVersion() {
const gitBranchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' });
const reBranchVersion = /^(?:[\w-]+\/)(\d+\.\d+\.\d+)(-?beta)?(?:\.\d+)?$/im;
const match = reBranchVersion.exec(gitBranchName);
if (!match) {
console.warn(`[engine] gitBranchName: ${gitBranchName}`);
return 'N/A';
}
const [_, version, beta] = match;
return beta && beta.endsWith('beta') ? `${version}-beta` : version;
}
const releaseVersion = getVersion();
module.exports = ({ context, onGetWebpackConfig }) => {
onGetWebpackConfig((config) => {
config.resolve.plugin('tsconfigpaths').use(TsconfigPathsPlugin, [
{
configFile: './tsconfig.json',
},
]);
config.plugin('define').use(context.webpack.DefinePlugin, [
{
VERSION_PLACEHOLDER: JSON.stringify(releaseVersion),
},
]);
config.plugins.delete('hot');
config.devServer.hot(false);
});
};

View File

@ -1,19 +0,0 @@
{
"plugins": [
[
"@alilc/build-plugin-lce",
{
"filename": "editor-preset-vision",
"library": "LowcodeEditor",
"libraryTarget": "umd",
"externals": {
"react": "var window.React",
"react-dom": "var window.ReactDOM",
"prop-types": "var window.PropTypes",
"rax": "var window.Rax"
}
}
],
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}

View File

@ -1,40 +0,0 @@
{
"entry": {
"engine-core": "src/index"
},
"sourceMap": true,
"library": "AliLowCodeEngine",
"libraryTarget": "umd",
"externals": {
"react": "var window.React",
"react-dom": "var window.ReactDOM",
"prop-types": "var window.PropTypes",
"@ali/visualengine": "var window.VisualEngine",
"@ali/visualengine-utils": "var window.VisualEngineUtils",
"rax": "var window.Rax",
"monaco-editor/esm/vs/editor/editor.api": "var window.monaco",
"monaco-editor/esm/vs/editor/editor.main.js": "var window.monaco",
"@alifd/next": "var Next",
"@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
"moment": "var moment",
"lodash": "var _"
},
"polyfill": false,
"outputDir": "dist",
"vendor": false,
"ignoreHtmlTemplate": true,
"plugins": [
"build-plugin-react-app",
[
"build-plugin-fusion",
{
"themePackage": "@alifd/theme-lowcode-light",
"externalNext": "umd"
}
],
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
}],
"./build.plugin.js"
]
}

View File

@ -1,27 +0,0 @@
const esModules = [
'@recore/obx-react',
// '@ali/lowcode-editor-core',
].join('|');
module.exports = {
// transform: {
// '^.+\\.[jt]sx?$': 'babel-jest',
// // '^.+\\.(ts|tsx)$': 'ts-jest',
// // '^.+\\.(js|jsx)$': 'babel-jest',
// },
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
collectCoverage: false,
collectCoverageFrom: [
'src/**/*.{ts,tsx}',
'!src/**/*.d.ts',
'!src/base/**',
'!src/fields/**',
'!src/prop.ts',
'!**/node_modules/**',
'!**/vendor/**',
],
};

View File

@ -29,16 +29,16 @@
"@alilc/lowcode-shell": "1.3.2",
"@alilc/lowcode-utils": "1.3.2",
"@alilc/lowcode-workspace": "1.3.2",
"react": "^16.8.1",
"react-dom": "^16.8.1"
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"@alifd/theme-lowcode-dark": "^0.2.0",
"@alifd/theme-lowcode-light": "^0.2.0",
"@types/domready": "^1.0.0",
"@types/react": "^16.8.3",
"@types/react-dom": "^16.8.2",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"build-plugin-fusion": "0.1.17-beta.0",
"build-plugin-moment-locales": "^0.1.0",
"build-plugin-react-app": "^1.8.0",

View File

@ -1,9 +0,0 @@
{
"plugins": [
"@alilc/build-plugin-lce",
"build-plugin-fusion",
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
}]
]
}

View File

@ -1,19 +0,0 @@
{
"plugins": [
[
"@alilc/build-plugin-lce",
{
"filename": "editor-preset-vision",
"library": "LowcodeEditor",
"libraryTarget": "umd",
"externals": {
"react": "var window.React",
"react-dom": "var window.ReactDOM",
"prop-types": "var window.PropTypes",
"rax": "var window.Rax"
}
}
],
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}

View File

@ -1,22 +0,0 @@
const fs = require('fs');
const { join } = require('path');
const esModules = [].join('|');
const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
const jestConfig = {
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
collectCoverage: true,
collectCoverageFrom: [
'src/**/*.ts',
'src/**/*.tsx',
],
};
// 只对本仓库内的 pkg 做 mapping
jestConfig.moduleNameMapper = {};
jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '<rootDir>/../$1/src';
module.exports = jestConfig;

View File

@ -1,39 +1,46 @@
{
"name": "@alilc/lowcode-plugin-command",
"version": "1.3.2",
"version": "2.0.0-beta.0",
"description": "> TODO: description",
"author": "liujuping <liujup@foxmail.com>",
"homepage": "https://github.com/alibaba/lowcode-engine#readme",
"license": "ISC",
"main": "lib/index.js",
"module": "es/index.js",
"directories": {
"lib": "lib",
"test": "__tests__"
"type": "module",
"main": "dist/command.cjs",
"module": "dist/command.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/command.js",
"require": "./dist/command.cjs",
"types": "./dist/index.d.ts"
}
},
"files": [
"lib",
"es"
"dist",
"src",
"package.json"
],
"sideEffects": [
"*.css"
],
"scripts": {
"build": "vite build",
"build-dts": "tsc -p tsconfig.declaration.json && node ../../scripts/rollup-dts.mjs",
"test": "vitest"
},
"bugs": {
"url": "https://github.com/alibaba/lowcode-engine/issues"
},
"dependencies": {
"@alilc/lowcode-types": "workspace:*",
"@alilc/lowcode-utils": "workspace:*"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/alibaba/lowcode-engine.git"
},
"scripts": {
"test": "build-scripts test --config build.test.json --jest-passWithNoTests",
"build": "build-scripts build"
},
"bugs": {
"url": "https://github.com/alibaba/lowcode-engine/issues"
},
"dependencies": {
"@alilc/lowcode-types": "1.3.2",
"@alilc/lowcode-utils": "1.3.2"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18"
}
}

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "temp",
"stripInternal": true,
"paths": {}
}
}

View File

@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src"]
}

View File

@ -0,0 +1,15 @@
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
export default defineConfig({
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(import.meta.dirname, 'src/index.ts'),
name: 'LowCodePluginCommand',
formats: ['es', 'cjs'],
// the proper extensions will be added
fileName: 'plugin-command',
},
},
});

View File

View File

@ -1,16 +1,27 @@
{
"name": "@alilc/lowcode-plugin-designer",
"version": "1.3.2",
"version": "2.0.0-beta.0",
"description": "alibaba lowcode editor designer plugin",
"type": "module",
"main": "dist/designer.cjs",
"module": "dist/designer.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/designer.js",
"require": "./dist/designer.cjs",
"types": "./dist/index.d.ts"
}
},
"files": [
"es",
"lib"
"dist",
"src",
"package.json"
],
"main": "lib/index.js",
"module": "es/index.js",
"stylePath": "style.js",
"scripts": {
"build": "build-scripts build"
"build": "vite build",
"build-dts": "tsc -p tsconfig.declaration.json && node ../../scripts/rollup-dts.mjs",
"test": "vitest"
},
"keywords": [
"lowcode",
@ -18,16 +29,19 @@
],
"author": "xiayang.xy",
"dependencies": {
"@alilc/lowcode-designer": "1.3.2",
"@alilc/lowcode-editor-core": "1.3.2",
"@alilc/lowcode-utils": "1.3.2",
"react": "^16.8.1",
"react-dom": "^16.8.1"
"@alilc/lowcode-designer": "workspace:*",
"@alilc/lowcode-editor-core": "workspace:*",
"@alilc/lowcode-utils": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.3",
"@types/react": "^16.9.13",
"@types/react-dom": "^16.9.4"
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
},
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"publishConfig": {
"access": "public",

View File

@ -13,6 +13,7 @@ export interface PluginProps {
interface DesignerPluginState {
componentMetadatas?: any[] | null;
library?: any[] | null;
utilsMetadata?: any[] | null;
extraEnvironment?: any[] | null;
renderEnv?: string;
device?: string;
@ -29,6 +30,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
state: DesignerPluginState = {
componentMetadatas: null,
utilsMetadata: null,
library: null,
extraEnvironment: null,
renderEnv: 'default',
@ -58,7 +60,8 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
const deviceClassName = engineConfig.get('deviceClassName') || editor.get('deviceClassName');
const simulatorUrl = engineConfig.get('simulatorUrl') || editor.get('simulatorUrl');
// @TODO setupAssets 里设置 requestHandlersMap 不太合适
const requestHandlersMap = engineConfig.get('requestHandlersMap') || editor.get('requestHandlersMap');
const requestHandlersMap =
engineConfig.get('requestHandlersMap') || editor.get('requestHandlersMap');
if (!this._mounted) {
return;
}
@ -139,6 +142,7 @@ export default class DesignerPlugin extends PureComponent<PluginProps, DesignerP
name={editor.viewName}
designer={editor.get('designer')}
componentMetadatas={componentMetadatas}
shellModelFactory={{} as any}
simulatorProps={{
library,
utilsMetadata,

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"declaration": true,
"outDir": "temp",
"stripInternal": true,
"paths": {}
}
}

View File

@ -1,9 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "lib"
"outDir": "dist"
},
"include": [
"./src/"
]
"include": ["src"]
}

View File

@ -0,0 +1,23 @@
import { defineConfig } from 'vite';
import { resolve } from 'node:path';
import react from '@vitejs/plugin-react';
import { devDependencies, peerDependencies } from './package.json';
const externals = [...Object.keys(peerDependencies), ...Object.keys(devDependencies)];
export default defineConfig({
build: {
lib: {
// Could also be a dictionary or array of multiple entry points
entry: resolve(import.meta.dirname, 'src/index.tsx'),
name: 'LowCodePluginDesigner',
formats: ['es', 'cjs'],
// the proper extensions will be added
fileName: 'plugin-designer',
},
rollupOptions: {
external: externals,
},
},
plugins: [react()],
});

Some files were not shown because too many files have changed in this diff Show More