-
-
this.controller.mount(shell)} className="lc-outline-tree-container">
-
+ { !this.props.hideFilter &&
}
+
this.controller.mount(shell)} className={`lc-outline-tree-container ${ this.props.hideFilter ? 'lc-hidden-outline-filter' : '' }`}>
+
);
diff --git a/packages/plugin-outline-pane/src/views/style.less b/packages/plugin-outline-pane/src/views/style.less
index cd133932b9..8a38ba749b 100644
--- a/packages/plugin-outline-pane/src/views/style.less
+++ b/packages/plugin-outline-pane/src/views/style.less
@@ -3,7 +3,6 @@
width: 100%;
position: relative;
z-index: 200;
- background-color: white;
> .lc-outline-tree-container {
top: 52px;
@@ -14,10 +13,14 @@
overflow: auto;
}
+ > .lc-outline-tree-container.lc-hidden-outline-filter {
+ top: 0;
+ }
+
> .lc-outline-filter {
padding: 12px 16px;
display: flex;
- align-items: center;
+ align-items: stretch;
justify-content: right;
.lc-outline-filter-search-input {
@@ -25,9 +28,8 @@
}
.lc-outline-filter-icon {
- background: #ebecf0;
- border: 1px solid #c4c6cf;
- height: 28px;
+ background: var(--color-block-background-light, #ebecf0);
+ border: 1px solid var(--color-field-border, #c4c6cf);
display: flex;
align-items: center;
border-radius: 0 2px 2px 0;
@@ -48,20 +50,21 @@
overflow: hidden;
margin-bottom: @treeNodeHeight;
user-select: none;
+ overflow-x: scroll;
.tree-node-modal {
margin: 5px;
- border: 1px solid rgba(31, 56, 88, 0.2);
+ border: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2));
border-radius: 3px;
- box-shadow: 0 1px 4px 0 rgba(31, 56, 88, 0.15);
+ box-shadow: 0 1px 4px 0 var(--color-block-background-shallow, rgba(31, 56, 88, 0.15));
.tree-node-modal-title {
position: relative;
- background: rgba(31, 56, 88, 0.04);
+ background: var(--color-block-background-light, rgba(31, 56, 88, 0.04));
padding: 0 10px;
height: 32px;
line-height: 32px;
- border-bottom: 1px solid rgba(31, 56, 88, 0.2);
+ border-bottom: 1px solid var(--color-field-border, rgba(31, 56, 88, 0.2));
.tree-node-modal-title-visible-icon {
position: absolute;
@@ -77,7 +80,8 @@
}
}
- .tree-node-modal-radio, .tree-node-modal-radio-active {
+ .tree-node-modal-radio,
+ .tree-node-modal-radio-active {
margin-right: 4px;
opacity: 0.8;
position: absolute;
@@ -85,7 +89,7 @@
left: 6px;
}
.tree-node-modal-radio-active {
- color: #006cff;
+ color: var(--color-brand, #006cff);
}
}
@@ -104,7 +108,7 @@
&:hover {
.tree-node-branches::before {
- border-left-color: #ddd;
+ border-left-color: var(--color-line-darken, #ddd);
}
}
@@ -116,75 +120,75 @@
transform: translateZ(0);
transition: all 0.2s ease-in-out;
&.invalid {
- border-color: red;
- background-color: rgba(240, 154, 154, 0.719);
+ border-color: var(--color-error, var(--color-function-error, red));
+ background-color: var(--color-block-background-error, rgba(240, 154, 154, 0.719));
}
}
.condition-group-container {
- border-bottom: 1px solid #7b605b;
+ border-bottom: 1px solid var(--color-brown, var(--color-function-brown, #7b605b));
position: relative;
&:before {
position: absolute;
display: block;
width: 0;
- border-left: 0.5px solid #7b605b;
+ border-left: 0.5px solid var(--color-brown, var(--color-function-brown, #7b605b));
height: 100%;
top: 0;
left: 0;
content: ' ';
z-index: 2;
}
- >.condition-group-title {
+ > .condition-group-title {
text-align: center;
- background-color: #7b605b;
+ background-color: var(--color-brown, var(--color-function-brown, #7b605b));
height: 14px;
> .lc-title {
font-size: 12px;
transform: scale(0.8);
transform-origin: top;
- color: white;
- text-shadow: 0 0 2px black;
+ color: var(--color-text-reverse, white);
+ text-shadow: 0 0 2px var(--color-block-background-shallow, black);
display: block;
}
}
}
.tree-node-slots {
- border-bottom: 1px solid rgb(144, 94, 190);
+ border-bottom: 1px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));
position: relative;
&::before {
position: absolute;
display: block;
width: 0;
- border-left: 0.5px solid rgb(144, 94, 190);
+ border-left: 0.5px solid var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));
height: 100%;
top: 0;
left: 0;
content: ' ';
z-index: 2;
}
- >.tree-node-slots-title {
+ > .tree-node-slots-title {
text-align: center;
- background-color: rgb(144, 94, 190);
+ background-color: var(--color-purple, var(--color-function-purple, rgb(144, 94, 190)));
height: 14px;
> .lc-title {
font-size: 12px;
transform: scale(0.8);
transform-origin: top;
- color: white;
+ color: var(--color-text-reverse, white);
text-shadow: 0 0 2px black;
display: block;
}
}
&.insertion-at-slots {
padding-bottom: @treeNodeHeight;
- border-bottom-color: rgb(182, 55, 55);
- >.tree-node-slots-title {
- background-color: rgb(182, 55, 55);
+ border-bottom-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));
+ > .tree-node-slots-title {
+ background-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));
}
&::before {
- border-left-color: rgb(182, 55, 55);
+ border-left-color: var(--color-error-dark, var(--color-function-error-dark, rgb(182, 55, 55)));
}
}
}
@@ -240,7 +244,6 @@
.tree-node-title {
font-size: var(--font-size-text);
cursor: pointer;
- background: var(--color-pane-background);
border-bottom: 1px solid var(--color-line-normal, rgba(31, 56, 88, 0.1));
display: flex;
align-items: center;
@@ -276,7 +279,10 @@
}
}
- .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn {
+ .tree-node-hide-btn,
+ .tree-node-lock-btn,
+ .tree-node-rename-btn,
+ .tree-node-delete-btn {
opacity: 0;
color: var(--color-text);
line-height: 0;
@@ -290,18 +296,26 @@
}
}
&:hover {
- .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn {
+ .tree-node-hide-btn,
+ .tree-node-lock-btn,
+ .tree-node-rename-btn,
+ .tree-node-delete-btn {
opacity: 0.5;
}
}
html.lc-cursor-dragging & {
// FIXME: only hide hover shows
- .tree-node-hide-btn, .tree-node-lock-btn, .tree-node-rename-btn {
+ .tree-node-hide-btn,
+ .tree-node-lock-btn,
+ .tree-node-rename-btn {
display: none;
}
}
&.editing {
- & > .tree-node-hide-btn, & >.tree-node-lock-btn, & >.tree-node-rename-btn {
+ & > .tree-node-hide-btn,
+ & > .tree-node-lock-btn,
+ & > .tree-node-rename-btn,
+ & > .tree-node-delete-btn {
display: none;
}
}
@@ -312,13 +326,13 @@
align-items: center;
line-height: 0;
&.cond {
- color: rgb(179, 52, 6);
+ color: var(--color-error, var(--color-function-error, rgb(179, 52, 6)));
}
&.loop {
- color: rgb(103, 187, 187);
+ color: var(--color-success, var(--color-function-success, rgb(103, 187, 187)));
}
&.slot {
- color: rgb(211, 90, 211);
+ color: var(--color-purple, var(--color-function-purple, rgb(211, 90, 211)));
}
}
}
@@ -342,7 +356,7 @@
// 选中节点处理
&.selected {
& > .tree-node-title {
- background: var(--color-block-background-shallow);
+ background: var(--color-block-background-light);
}
& > .tree-node-branches::before {
@@ -352,7 +366,7 @@
&.hidden {
.tree-node-title-label {
- color: #9b9b9b;
+ color: var(--color-text-disabled, #9b9b9b);
}
& > .tree-node-title > .tree-node-hide-btn {
opacity: 0.8;
@@ -378,7 +392,8 @@
opacity: 0.8;
}
.tree-node-branches {
- .tree-node-lock-btn, .tree-node-hide-btn {
+ .tree-node-lock-btn,
+ .tree-node-hide-btn {
opacity: 0;
}
}
diff --git a/packages/plugin-outline-pane/src/views/tree-branches.tsx b/packages/plugin-outline-pane/src/views/tree-branches.tsx
index 210fe0af85..41bd694812 100644
--- a/packages/plugin-outline-pane/src/views/tree-branches.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-branches.tsx
@@ -2,12 +2,11 @@ import { PureComponent } from 'react';
import classNames from 'classnames';
import TreeNode from '../controllers/tree-node';
import TreeNodeView from './tree-node';
-import { IPublicModelPluginContext, IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';
+import { IPublicModelExclusiveGroup, IPublicTypeDisposable, IPublicTypeLocationChildrenDetail } from '@alilc/lowcode-types';
export default class TreeBranches extends PureComponent<{
treeNode: TreeNode;
isModal?: boolean;
- pluginContext: IPublicModelPluginContext;
expanded: boolean;
treeChildren: TreeNode[] | null;
}> {
@@ -51,12 +50,11 @@ export default class TreeBranches extends PureComponent<{
return (
{
- !isModal &&
+ !isModal &&
}
@@ -73,7 +71,6 @@ interface ITreeNodeChildrenState {
class TreeNodeChildren extends PureComponent<{
treeNode: TreeNode;
isModal?: boolean;
- pluginContext: IPublicModelPluginContext;
treeChildren: TreeNode[] | null;
}, ITreeNodeChildrenState> {
state: ITreeNodeChildrenState = {
@@ -84,8 +81,8 @@ class TreeNodeChildren extends PureComponent<{
};
offLocationChanged: IPublicTypeDisposable | undefined;
componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { project } = pluginContext;
+ const { treeNode } = this.props;
+ const { project } = treeNode.pluginContext;
const { filterWorking, matchSelf, keywords } = treeNode.filterReult;
const { dropDetail } = treeNode;
this.setState({
@@ -122,13 +119,14 @@ class TreeNodeChildren extends PureComponent<{
let groupContents: any[] = [];
let currentGrp: IPublicModelExclusiveGroup;
const { filterWorking, matchSelf, keywords } = this.state;
- const Title = this.props.pluginContext.common.editorCabin.Title;
+ const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;
const endGroup = () => {
if (groupContents.length > 0) {
children.push(
+ {/* @ts-ignore */}
);
+ groupContents.push(
);
} else {
if (index === dropIndex) {
children.push(insertion);
}
- children.push(
);
+ children.push(
);
}
});
endGroup();
@@ -191,26 +189,26 @@ class TreeNodeChildren extends PureComponent<{
class TreeNodeSlots extends PureComponent<{
treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
}> {
render() {
const { treeNode } = this.props;
if (!treeNode.hasSlots()) {
return null;
}
- const Title = this.props.pluginContext.common.editorCabin.Title;
+ const Title = this.props.treeNode.pluginContext.common.editorCabin.Title;
return (
-
+ {/* @ts-ignore */}
+
{treeNode.slots.map(tnode => (
-
+
))}
);
diff --git a/packages/plugin-outline-pane/src/views/tree-node.tsx b/packages/plugin-outline-pane/src/views/tree-node.tsx
index 712dc20fac..11bd95d12f 100644
--- a/packages/plugin-outline-pane/src/views/tree-node.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-node.tsx
@@ -4,34 +4,56 @@ import TreeNode from '../controllers/tree-node';
import TreeTitle from './tree-title';
import TreeBranches from './tree-branches';
import { IconEyeClose } from '../icons/eye-close';
-import { IPublicModelPluginContext, IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types';
+import { IPublicModelModalNodesManager, IPublicTypeDisposable } from '@alilc/lowcode-types';
+import { IOutlinePanelPluginContext } from '../controllers/tree-master';
class ModalTreeNodeView extends PureComponent<{
treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
+}, {
+ treeChildren: TreeNode[] | null;
}> {
private modalNodesManager: IPublicModelModalNodesManager | undefined | null;
- readonly pluginContext: IPublicModelPluginContext;
+ readonly pluginContext: IOutlinePanelPluginContext;
- constructor(props: any) {
+ constructor(props: {
+ treeNode: TreeNode;
+ }) {
super(props);
// 模态管理对象
- this.pluginContext = props.pluginContext;
+ this.pluginContext = props.treeNode.pluginContext;
const { project } = this.pluginContext;
this.modalNodesManager = project.currentDocument?.modalNodesManager;
+ this.state = {
+ treeChildren: this.rootTreeNode.children,
+ };
}
hideAllNodes() {
this.modalNodesManager?.hideModalNodes();
}
- render() {
+ componentDidMount(): void {
+ const { rootTreeNode } = this;
+ rootTreeNode.onExpandableChanged(() => {
+ this.setState({
+ treeChildren: rootTreeNode.children,
+ });
+ });
+ }
+
+ get rootTreeNode() {
const { treeNode } = this.props;
// 当指定了新的根节点时,要从原始的根节点去获取模态节点
const { project } = this.pluginContext;
const rootNode = project.currentDocument?.root;
const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
+
+ return rootTreeNode;
+ }
+
+ render() {
+ const { rootTreeNode } = this;
const { expanded } = rootTreeNode;
const hasVisibleModalNode = !!this.modalNodesManager?.getVisibleModalNode();
@@ -49,10 +71,9 @@ class ModalTreeNodeView extends PureComponent<{
@@ -63,7 +84,6 @@ class ModalTreeNodeView extends PureComponent<{
export default class TreeNodeView extends PureComponent<{
treeNode: TreeNode;
isModal?: boolean;
- pluginContext: IPublicModelPluginContext;
isRootNode?: boolean;
}> {
state: {
@@ -78,6 +98,9 @@ export default class TreeNodeView extends PureComponent<{
conditionFlow: boolean;
expandable: boolean;
treeChildren: TreeNode[] | null;
+ filterWorking: boolean;
+ matchChild: boolean;
+ matchSelf: boolean;
} = {
expanded: false,
selected: false,
@@ -90,6 +113,9 @@ export default class TreeNodeView extends PureComponent<{
conditionFlow: false,
expandable: false,
treeChildren: [],
+ filterWorking: false,
+ matchChild: false,
+ matchSelf: false,
};
eventOffCallbacks: Array
= [];
@@ -114,8 +140,8 @@ export default class TreeNodeView extends PureComponent<{
}
componentDidMount() {
- const { treeNode, pluginContext } = this.props;
- const { project } = pluginContext;
+ const { treeNode } = this.props;
+ const { project } = treeNode.pluginContext;
const doc = project.currentDocument;
@@ -134,6 +160,10 @@ export default class TreeNodeView extends PureComponent<{
treeChildren: treeNode.children,
});
});
+ treeNode.onFilterResultChanged(() => {
+ const { filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf } = treeNode.filterReult;
+ this.setState({ filterWorking: newFilterWorking, matchChild: newMatchChild, matchSelf: newMatchSelf });
+ });
this.eventOffCallbacks.push(
doc?.onDropLocationChanged(() => {
this.setState({
@@ -158,14 +188,14 @@ export default class TreeNodeView extends PureComponent<{
}
shouldShowModalTreeNode(): boolean {
- const { treeNode, isRootNode, pluginContext } = this.props;
+ const { treeNode, isRootNode } = this.props;
if (!isRootNode) {
// 只在 当前树 的根节点展示模态节点
return false;
}
// 当指定了新的根节点时,要从原始的根节点去获取模态节点
- const { project } = pluginContext;
+ const { project } = treeNode.pluginContext;
const rootNode = project.currentDocument?.root;
const rootTreeNode = treeNode.tree.getTreeNode(rootNode!);
const modalNodes = rootTreeNode.children?.filter((item) => {
@@ -196,7 +226,7 @@ export default class TreeNodeView extends PureComponent<{
let shouldShowModalTreeNode: boolean = this.shouldShowModalTreeNode();
// filter 处理
- const { filterWorking, matchChild, matchSelf } = treeNode.filterReult;
+ const { filterWorking, matchChild, matchSelf } = this.state;
if (!isRootNode && filterWorking && !matchChild && !matchSelf) {
// 条件过滤生效时,如果未命中本节点或子节点,则不展示该节点
// 根节点始终展示
@@ -205,7 +235,7 @@ export default class TreeNodeView extends PureComponent<{
return (
{shouldShowModalTreeNode &&
}
diff --git a/packages/plugin-outline-pane/src/views/tree-title.tsx b/packages/plugin-outline-pane/src/views/tree-title.tsx
index 6e1b14a466..f822bd644b 100644
--- a/packages/plugin-outline-pane/src/views/tree-title.tsx
+++ b/packages/plugin-outline-pane/src/views/tree-title.tsx
@@ -1,9 +1,9 @@
import { KeyboardEvent, FocusEvent, Fragment, PureComponent } from 'react';
import classNames from 'classnames';
import { createIcon } from '@alilc/lowcode-utils';
-import { IPublicModelPluginContext, IPublicApiEvent } from '@alilc/lowcode-types';
+import { IPublicApiEvent } from '@alilc/lowcode-types';
import TreeNode from '../controllers/tree-node';
-import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting } from '../icons';
+import { IconLock, IconUnlock, IconArrowRight, IconEyeClose, IconEye, IconCond, IconLoop, IconRadioActive, IconRadio, IconSetting, IconDelete } from '../icons';
function emitOutlineEvent(event: IPublicApiEvent, type: string, treeNode: TreeNode, rest?: Record) {
const node = treeNode?.node;
@@ -23,14 +23,21 @@ export default class TreeTitle extends PureComponent<{
hidden: boolean;
locked: boolean;
expandable: boolean;
- pluginContext: IPublicModelPluginContext;
}> {
state: {
editing: boolean;
title: string;
+ condition?: boolean;
+ visible?: boolean;
+ filterWorking: boolean;
+ keywords: string;
+ matchSelf: boolean;
} = {
editing: false,
title: '',
+ filterWorking: false,
+ keywords: '',
+ matchSelf: false,
};
private lastInput?: HTMLInputElement;
@@ -53,7 +60,7 @@ export default class TreeTitle extends PureComponent<{
const { treeNode } = this.props;
const value = (e.target as HTMLInputElement).value || '';
treeNode.setTitleLabel(value);
- emitOutlineEvent(this.props.pluginContext.event, 'rename', treeNode, { value });
+ emitOutlineEvent(this.props.treeNode.pluginContext.event, 'rename', treeNode, { value });
this.cancelEdit();
};
@@ -81,17 +88,38 @@ export default class TreeTitle extends PureComponent<{
this.setState({
editing: false,
title: treeNode.titleLabel,
+ condition: treeNode.condition,
+ visible: !treeNode.hidden,
});
treeNode.onTitleLabelChanged(() => {
this.setState({
title: treeNode.titleLabel,
});
});
+ treeNode.onConditionChanged(() => {
+ this.setState({
+ condition: treeNode.condition,
+ });
+ });
+ treeNode.onHiddenChanged((hidden: boolean) => {
+ this.setState({
+ visible: !hidden,
+ });
+ });
+ treeNode.onFilterResultChanged(() => {
+ const { filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf } = treeNode.filterReult;
+ this.setState({ filterWorking: newFilterWorking, keywords: newKeywords, matchSelf: newMatchSelf });
+ });
}
-
+ deleteClick = () => {
+ const { treeNode } = this.props;
+ const { node } = treeNode;
+ treeNode.deleteNode(node);
+ };
render() {
- const { treeNode, isModal, pluginContext } = this.props;
- const { editing } = this.state;
+ const { treeNode, isModal } = this.props;
+ const { pluginContext } = treeNode;
+ const { editing, filterWorking, matchSelf, keywords } = this.state;
const isCNode = !treeNode.isRoot();
const { node } = treeNode;
const { componentMeta } = node;
@@ -107,25 +135,24 @@ export default class TreeTitle extends PureComponent<{
marginLeft: -indent,
};
}
- const { filterWorking, matchSelf, keywords } = treeNode.filterReult;
const Extra = pluginContext.extraTitle;
const { intlNode, common, config } = pluginContext;
- const Tip = common.editorCabin.Tip;
- const Title = common.editorCabin.Title;
+ const { Tip, Title } = common.editorCabin;
const couldHide = availableActions.includes('hide');
const couldLock = availableActions.includes('lock');
const couldUnlock = availableActions.includes('unlock');
const shouldShowHideBtn = isCNode && isNodeParent && !isModal && couldHide;
const shouldShowLockBtn = config.get('enableCanvasLock', false) && isContainer && isCNode && isNodeParent && ((couldLock && !node.isLocked) || (couldUnlock && node.isLocked));
const shouldEditBtn = isCNode && isNodeParent;
+ const shouldDeleteBtn = isCNode && isNodeParent && node?.canPerformAction('remove');
return (
{
if (isModal) {
- if (node.visible) {
+ if (this.state.visible) {
node.document?.modalNodesManager?.setInvisible(node);
} else {
node.document?.modalNodesManager?.setVisible(node);
@@ -137,7 +164,7 @@ export default class TreeTitle extends PureComponent<{
}
}}
>
- {isModal && node.visible && (
+ {isModal && this.state.visible && (
{
node.document?.modalNodesManager?.setInvisible(node);
}}
@@ -145,7 +172,7 @@ export default class TreeTitle extends PureComponent<{
)}
- {isModal && !node.visible && (
+ {isModal && !this.state.visible && (
{
node.document?.modalNodesManager?.setVisible(node);
}}
@@ -153,7 +180,7 @@ export default class TreeTitle extends PureComponent<{
)}
- {isCNode &&
}
+ {isCNode &&
}
{createIcon(treeNode.icon)}
- {shouldShowHideBtn &&
}
- {shouldShowLockBtn &&
}
- {shouldEditBtn &&
}
+ {shouldShowHideBtn &&
}
+ {shouldShowLockBtn &&
}
+ {shouldEditBtn &&
}
+ {shouldDeleteBtn &&
}
+
+ );
+ }
+}
+class DeleteBtn extends PureComponent<{
+ treeNode: TreeNode;
+ onClick: () => void;
+}> {
+ render() {
+ const { intl, common } = this.props.treeNode.pluginContext;
+ const { Tip } = common.editorCabin;
+ return (
+
+
+ {/* @ts-ignore */}
+ {intl('Delete')}
);
}
@@ -206,18 +257,18 @@ export default class TreeTitle extends PureComponent<{
class RenameBtn extends PureComponent<{
treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
onClick: (e: any) => void;
}> {
render() {
- const { intl, common } = this.props.pluginContext;
- const Tip = common.editorCabin.Tip;
+ const { intl, common } = this.props.treeNode.pluginContext;
+ const { Tip } = common.editorCabin;
return (
+ {/* @ts-ignore */}
{intl('Rename')}
);
@@ -226,13 +277,12 @@ class RenameBtn extends PureComponent<{
class LockBtn extends PureComponent<{
treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
locked: boolean;
}> {
render() {
const { treeNode, locked } = this.props;
- const { intl, common } = this.props.pluginContext;
- const Tip = common.editorCabin.Tip;
+ const { intl, common } = this.props.treeNode.pluginContext;
+ const { Tip } = common.editorCabin;
return (
{locked ? : }
+ {/* @ts-ignore */}
{locked ? intl('Unlock') : intl('Lock')}
);
@@ -251,24 +302,24 @@ class LockBtn extends PureComponent<{
class HideBtn extends PureComponent<{
treeNode: TreeNode;
hidden: boolean;
- pluginContext: IPublicModelPluginContext;
}, {
hidden: boolean;
}> {
render() {
const { treeNode, hidden } = this.props;
- const { intl, common } = this.props.pluginContext;
- const Tip = common.editorCabin.Tip;
+ const { intl, common } = treeNode.pluginContext;
+ const { Tip } = common.editorCabin;
return (
{
e.stopPropagation();
- emitOutlineEvent(this.props.pluginContext.event, hidden ? 'show' : 'hide', treeNode);
+ emitOutlineEvent(treeNode.pluginContext.event, hidden ? 'show' : 'hide', treeNode);
treeNode.setHidden(!hidden);
}}
>
{hidden ? : }
+ {/* @ts-ignore */}
{hidden ? intl('Show') : intl('Hide')}
);
@@ -277,11 +328,9 @@ class HideBtn extends PureComponent<{
class ExpandBtn extends PureComponent<{
treeNode: TreeNode;
- pluginContext: IPublicModelPluginContext;
expanded: boolean;
expandable: boolean;
}> {
-
render() {
const { treeNode, expanded, expandable } = this.props;
if (!expandable) {
@@ -294,7 +343,7 @@ class ExpandBtn extends PureComponent<{
if (expanded) {
e.stopPropagation();
}
- emitOutlineEvent(this.props.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);
+ emitOutlineEvent(treeNode.pluginContext.event, expanded ? 'collapse' : 'expand', treeNode);
treeNode.setExpanded(!expanded);
}}
>
diff --git a/packages/plugin-outline-pane/src/views/tree.tsx b/packages/plugin-outline-pane/src/views/tree.tsx
index 930c65cce9..8428ec944c 100644
--- a/packages/plugin-outline-pane/src/views/tree.tsx
+++ b/packages/plugin-outline-pane/src/views/tree.tsx
@@ -2,7 +2,7 @@ import { MouseEvent as ReactMouseEvent, PureComponent } from 'react';
import { isFormEvent, canClickNode, isShaken } from '@alilc/lowcode-utils';
import { Tree } from '../controllers/tree';
import TreeNodeView from './tree-node';
-import { IPublicEnumDragObjectType, IPublicModelPluginContext, IPublicModelNode } from '@alilc/lowcode-types';
+import { IPublicEnumDragObjectType, IPublicModelNode } from '@alilc/lowcode-types';
import TreeNode from '../controllers/tree-node';
function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string {
@@ -20,18 +20,27 @@ function getTreeNodeIdByEvent(e: ReactMouseEvent, stop: Element): null | string
export default class TreeView extends PureComponent<{
tree: Tree;
- pluginContext: IPublicModelPluginContext;
}> {
private shell: HTMLDivElement | null = null;
+ private ignoreUpSelected = false;
+
+ private boostEvent?: MouseEvent;
+
+ state: {
+ root: TreeNode | null;
+ } = {
+ root: null,
+ };
+
private hover(e: ReactMouseEvent) {
- const { project } = this.props.pluginContext;
+ const { project } = this.props.tree.pluginContext;
const detecting = project.currentDocument?.detecting;
if (detecting?.enable) {
return;
}
const node = this.getTreeNodeFromEvent(e)?.node;
- detecting?.capture(node as any);
+ node?.id && detecting?.capture(node.id);
}
private onClick = (e: ReactMouseEvent) => {
@@ -54,7 +63,7 @@ export default class TreeView extends PureComponent<{
return;
}
- const { project, event, canvas } = this.props.pluginContext;
+ const { project, event, canvas } = this.props.tree.pluginContext;
const doc = project.currentDocument;
const selection = doc?.selection;
const focusNode = doc?.focusNode;
@@ -82,7 +91,7 @@ export default class TreeView extends PureComponent<{
private onDoubleClick = (e: ReactMouseEvent) => {
e.preventDefault();
const treeNode = this.getTreeNodeFromEvent(e);
- if (treeNode?.id === this.state.root?.id) {
+ if (treeNode?.nodeId === this.state.root?.nodeId) {
return;
}
if (!treeNode?.expanded) {
@@ -109,10 +118,6 @@ export default class TreeView extends PureComponent<{
return tree.getTreeNodeById(id);
}
- private ignoreUpSelected = false;
-
- private boostEvent?: MouseEvent;
-
private onMouseDown = (e: ReactMouseEvent) => {
if (isFormEvent(e.nativeEvent)) {
return;
@@ -127,7 +132,7 @@ export default class TreeView extends PureComponent<{
if (!canClickNode(node, e)) {
return;
}
- const { project, canvas } = this.props.pluginContext;
+ const { project, canvas } = this.props.tree.pluginContext;
const selection = project.currentDocument?.selection;
const focusNode = project.currentDocument?.focusNode;
@@ -166,22 +171,16 @@ export default class TreeView extends PureComponent<{
};
private onMouseLeave = () => {
- const { pluginContext } = this.props;
+ const { pluginContext } = this.props.tree;
const { project } = pluginContext;
const doc = project.currentDocument;
doc?.detecting.leave();
};
- state: {
- root: TreeNode | null
- } = {
- root: null,
- };
-
componentDidMount() {
- const { tree, pluginContext } = this.props;
+ const { tree } = this.props;
const { root } = tree;
- const { project } = pluginContext;
+ const { project } = tree.pluginContext;
this.setState({ root });
const doc = project.currentDocument;
doc?.onFocusNodeChanged(() => {
@@ -189,6 +188,11 @@ export default class TreeView extends PureComponent<{
root: tree.root,
});
});
+ doc?.onImportSchema(() => {
+ this.setState({
+ root: tree.root,
+ });
+ });
}
render() {
@@ -208,7 +212,6 @@ export default class TreeView extends PureComponent<{
diff --git a/packages/rax-renderer/README.md b/packages/rax-renderer/README.md
deleted file mode 100644
index 7b430de630..0000000000
--- a/packages/rax-renderer/README.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Rax Renderer
-
-Rax 渲染模块。
-
-## 安装
-
-```
-$ npm install @alilc/lowcode-rax-renderer --save
-```
-
-## 使用
-
-```js
-import { createElement, render } from 'rax';
-import DriverUniversal from 'driver-universal';
-import RaxRenderer from '@ali/lowcode-rax-renderer';
-
-const components = {
- View,
- Text
-};
-
-const schema = {
- componentName: 'Page',
- fileName: 'home',
- children: [
- {
- componentName: 'View',
- children: [
- {
- componentName: 'Text',
- props: {
- type: 'primary'
- },
- children: ['Welcome to Your Rax App']
- }
- ]
- }
- ]
-};
-
-render(
-
,
- document.getElementById('root'), { driver: DriverUniversal }
-);
-```
diff --git a/packages/rax-renderer/build.json b/packages/rax-renderer/build.json
deleted file mode 100644
index 3edf143801..0000000000
--- a/packages/rax-renderer/build.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "plugins": [
- [
- "build-plugin-rax-component",
- {
- "type": "rax",
- "targets": ["web"]
- }
- ]
- ]
-}
diff --git a/packages/rax-renderer/demo/index.jsx b/packages/rax-renderer/demo/index.jsx
deleted file mode 100644
index cfcae2a201..0000000000
--- a/packages/rax-renderer/demo/index.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { createElement, render } from 'rax';
-import DriverUniversal from 'driver-universal';
-import View from 'rax-view';
-import Text from 'rax-text';
-import { Engine } from '../src/index';
-
-const components = {
- View,
- Text,
-};
-
-const schema = {
- componentName: 'Page',
- fileName: 'home',
- props: {},
- children: [
- {
- componentName: 'View',
- props: {},
- children: [
- {
- componentName: 'Text',
- props: {
- type: 'primary',
- },
- children: ['Welcome to Your Rax App!'],
- },
- ],
- },
- ],
-};
-
-render(
, document.getElementById('root'), {
- driver: DriverUniversal,
-});
diff --git a/packages/rax-renderer/demo/miniapp/app.js b/packages/rax-renderer/demo/miniapp/app.js
deleted file mode 100644
index 3482935519..0000000000
--- a/packages/rax-renderer/demo/miniapp/app.js
+++ /dev/null
@@ -1 +0,0 @@
-App({});
diff --git a/packages/rax-renderer/demo/miniapp/app.json b/packages/rax-renderer/demo/miniapp/app.json
deleted file mode 100644
index 94127c774c..0000000000
--- a/packages/rax-renderer/demo/miniapp/app.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "pages": ["pages/index"],
- "window": {
- "defaultTitle": "demo"
- }
-}
diff --git a/packages/rax-renderer/demo/miniapp/pages/index.acss b/packages/rax-renderer/demo/miniapp/pages/index.acss
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/packages/rax-renderer/demo/miniapp/pages/index.axml b/packages/rax-renderer/demo/miniapp/pages/index.axml
deleted file mode 100644
index 41b536b4ce..0000000000
--- a/packages/rax-renderer/demo/miniapp/pages/index.axml
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/rax-renderer/demo/miniapp/pages/index.js b/packages/rax-renderer/demo/miniapp/pages/index.js
deleted file mode 100644
index 687d87e197..0000000000
--- a/packages/rax-renderer/demo/miniapp/pages/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-Page({
- onLoad() {},
- onShow() {},
-});
diff --git a/packages/rax-renderer/demo/miniapp/pages/index.json b/packages/rax-renderer/demo/miniapp/pages/index.json
deleted file mode 100644
index 89b15c54ca..0000000000
--- a/packages/rax-renderer/demo/miniapp/pages/index.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "defaultTitle": "Miniapp Rax Text demo",
- "usingComponents": {
- "my-component": "../components/Target/index"
- }
-}
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.js b/packages/rax-renderer/demo/wechat-miniprogram/app.js
deleted file mode 100644
index 3482935519..0000000000
--- a/packages/rax-renderer/demo/wechat-miniprogram/app.js
+++ /dev/null
@@ -1 +0,0 @@
-App({});
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/app.json b/packages/rax-renderer/demo/wechat-miniprogram/app.json
deleted file mode 100644
index be00ced601..0000000000
--- a/packages/rax-renderer/demo/wechat-miniprogram/app.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "pages": ["pages/index"],
- "window": {
- "title": "demo"
- }
-}
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js
deleted file mode 100644
index 687d87e197..0000000000
--- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.js
+++ /dev/null
@@ -1,4 +0,0 @@
-Page({
- onLoad() {},
- onShow() {},
-});
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json
deleted file mode 100644
index 9448c84eaf..0000000000
--- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "title": "Wechat MiniProgram Rax Text demo",
- "usingComponents": {
- "my-component": "../components/Target/index"
- }
-}
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml
deleted file mode 100644
index 41b536b4ce..0000000000
--- a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxml
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss b/packages/rax-renderer/demo/wechat-miniprogram/pages/index.wxss
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/packages/rax-renderer/package.json b/packages/rax-renderer/package.json
deleted file mode 100644
index 489cf14093..0000000000
--- a/packages/rax-renderer/package.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "name": "@alilc/lowcode-rax-renderer",
- "version": "1.1.6",
- "description": "Rax renderer for Ali lowCode engine",
- "main": "lib/index.js",
- "module": "es/index.js",
- "miniappConfig": {
- "main": "lib/miniapp/index",
- "main:wechat": "lib/wechat-miniprogram/index"
- },
- "files": [
- "dist",
- "es",
- "lib"
- ],
- "keywords": [
- "low-code",
- "lowcode",
- "Rax"
- ],
- "engines": {
- "npm": ">=3.0.0"
- },
- "peerDependencies": {
- "prop-types": "^15.7.2",
- "rax": "^1.1.0"
- },
- "scripts": {
- "start": "build-scripts start",
- "build": "build-scripts build"
- },
- "dependencies": {
- "@alilc/lowcode-renderer-core": "1.1.6",
- "@alilc/lowcode-utils": "1.1.6",
- "rax-find-dom-node": "^1.0.1"
- },
- "devDependencies": {
- "@alib/build-scripts": "^0.1.0",
- "build-plugin-rax-component": "^0.2.11",
- "driver-universal": "^3.1.3"
- },
- "publishConfig": {
- "access": "public",
- "registry": "https://registry.npmjs.org/"
- },
- "repository": {
- "type": "http",
- "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-renderer"
- },
- "license": "MIT",
- "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-rax-renderer@0.1.2/build/index.html",
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
-}
diff --git a/packages/rax-renderer/src/hoc/compFactory.tsx b/packages/rax-renderer/src/hoc/compFactory.tsx
deleted file mode 100644
index 1c821ab6d9..0000000000
--- a/packages/rax-renderer/src/hoc/compFactory.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-// @ts-nocheck
-
-import { Component, forwardRef } from 'rax';
-import PropTypes from 'prop-types';
-import { AppHelper } from '@alilc/lowcode-utils';
-import { utils, contextFactory } from '@alilc/lowcode-renderer-core';
-import componentRendererFactory from '../renderer/component';
-import blockRendererFactory from '../renderer/block';
-
-const { forEach, isFileSchema } = utils;
-
-export default function compFactory(schema, components = {}, componentsMap = {}, config = {}) {
- // 自定义组件需要有自己独立的appHelper
- const appHelper = new AppHelper(config);
- const CompRenderer = componentRendererFactory();
- const BlockRenderer = blockRendererFactory();
- const AppContext = contextFactory();
-
- class LNCompView extends Component {
- static displayName = 'LceCompFactory';
-
- static version = config.version || '0.0.0';
-
- static contextType = AppContext;
-
- static propTypes = {
- forwardedRef: PropTypes.func,
- };
-
- render() {
- if (!schema || schema.componentName !== 'Component' || !isFileSchema(schema)) {
- console.warn('自定义组件模型结构异常!');
- return null;
- }
- const { forwardedRef, ...otherProps } = this.props;
- // 低代码组件透传应用上下文
- const ctx = ['utils', 'constants', 'history', 'location', 'match'];
- ctx.forEach(key => {
- if (!appHelper[key] && this.context?.appHelper && this.context?.appHelper[key]) {
- appHelper.set(key, this.context.appHelper[key]);
- }
- });
- // 支持通过context透传国际化配置
- const localeProps = {};
- const { locale, messages } = this.context;
- if (locale && messages && messages[schema.fileName]) {
- localeProps.locale = locale;
- localeProps.messages = messages[schema.fileName];
- }
- const props = {
- ...schema.defaultProps,
- ...localeProps,
- ...otherProps,
- __schema: schema,
- ref: forwardedRef,
- };
-
- return (
-
- {context => {
- this.context = context;
- return (
-
- );
- }}
-
- );
- }
- }
-
- const ResComp = forwardRef((props, ref) =>
);
- forEach(schema.static, (val, key) => {
- ResComp[key] = val;
- });
- ResComp.version = config.version || '0.0.0';
- return ResComp;
-}
diff --git a/packages/rax-renderer/src/index.ts b/packages/rax-renderer/src/index.ts
deleted file mode 100644
index 1947aa5aec..0000000000
--- a/packages/rax-renderer/src/index.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Component, PureComponent, createElement, createContext, forwardRef } from 'rax';
-import findDOMNode from 'rax-find-dom-node';
-import {
- adapter,
- addonRendererFactory,
- tempRendererFactory,
- rendererFactory,
-} from '@alilc/lowcode-renderer-core';
-import pageRendererFactory from './renderer/page';
-import componentRendererFactory from './renderer/component';
-import blockRendererFactory from './renderer/block';
-import CompFactory from './hoc/compFactory';
-
-adapter.setRuntime({
- Component,
- PureComponent,
- createContext,
- createElement,
- forwardRef,
- findDOMNode,
-});
-
-adapter.setRenderers({
- PageRenderer: pageRendererFactory(),
- ComponentRenderer: componentRendererFactory(),
- BlockRenderer: blockRendererFactory(),
- AddonRenderer: addonRendererFactory(),
- TempRenderer: tempRendererFactory(),
-});
-
-function factory() {
- const Renderer = rendererFactory();
- return class extends Renderer {
- constructor(props: any, context: any) {
- super(props, context);
- }
-
- isValidComponent(obj: any) {
- return obj?.prototype?.setState || obj?.prototype instanceof Component;
- }
- };
-}
-
-const RaxRenderer: any = factory();
-const Engine: any = RaxRenderer;
-
-export {
- Engine,
- CompFactory,
-};
-
-export default RaxRenderer;
diff --git a/packages/rax-renderer/src/renderer/block.tsx b/packages/rax-renderer/src/renderer/block.tsx
deleted file mode 100644
index 8fa4a27316..0000000000
--- a/packages/rax-renderer/src/renderer/block.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { blockRendererFactory, types } from '@alilc/lowcode-renderer-core';
-
-const raxBlockRendererFactory: () => any = () => {
- const OriginBlock = blockRendererFactory();
- return class BlockRenderer extends OriginBlock {
- render() {
- // @ts-ignore
- const that: types.IRenderer = this;
- const { __schema, __components } = that.props;
- if (that.__checkSchema(__schema)) {
- return '区块 schema 结构异常!';
- }
- that.__debug(`render - ${__schema.fileName}`);
-
- const children = ((context) => {
- that.context = context;
- that.__generateCtx({});
- that.__render();
- return that.__renderComp((__components as any)?.Block, { blockContext: that });
- });
- return that.__renderContextConsumer(children);
- }
- };
-};
-export default raxBlockRendererFactory;
diff --git a/packages/rax-renderer/src/renderer/component.tsx b/packages/rax-renderer/src/renderer/component.tsx
deleted file mode 100644
index 9943b3c2f1..0000000000
--- a/packages/rax-renderer/src/renderer/component.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { componentRendererFactory, types } from '@alilc/lowcode-renderer-core';
-
-const raxComponentRendererFactory: () => any = () => {
- const OriginComponent = componentRendererFactory();
- return class ComponentRenderer extends OriginComponent {
- render() {
- // @ts-ignore
- const that: types.IRenderer = this;
- const { __schema, __components } = that.props;
- if (that.__checkSchema(__schema)) {
- return '自定义组件 schema 结构异常!';
- }
- that.__debug(`render - ${__schema.fileName}`);
-
- const { noContainer } = that.__parseData(__schema.props);
-
- const children = ((context) => {
- that.context = context;
- that.__generateCtx({ component: that });
- that.__render();
- // 传 null,使用内置的 div 来渲染,解决在页面中渲染 vc-component 报错的问题
- return that.__renderComp(null, {
- compContext: that,
- blockContext: that,
- });
- });
- const content = that.__renderContextConsumer(children);
-
- if (noContainer) {
- return content;
- }
-
- return that.__renderContent(content);
- }
- };
-};
-export default raxComponentRendererFactory;
diff --git a/packages/rax-renderer/src/renderer/page.tsx b/packages/rax-renderer/src/renderer/page.tsx
deleted file mode 100644
index f6ebd3f7cf..0000000000
--- a/packages/rax-renderer/src/renderer/page.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { pageRendererFactory, types } from '@alilc/lowcode-renderer-core';
-
-const raxPageRendererFactory: () => any = () => {
- const OriginPage = pageRendererFactory();
- return class PageRenderer extends OriginPage {
- async componentDidUpdate() {
- // @ts-ignore
- super.componentDidUpdate(...arguments);
- }
-
- render() {
- // @ts-ignore
- const that: types.IRenderer = this;
- const { __schema, __components } = that.props;
- if (that.__checkSchema(__schema)) {
- return '页面 schema 结构异常!';
- }
- that.__debug(`render - ${__schema?.fileName}`);
-
- const { Page } = __components as any;
- if (Page) {
- const children = ((context) => {
- that.context = context;
- that.__render();
- return that.__renderComp(Page, { pageContext: that });
- });
- return that.__renderContextConsumer(children);
- }
-
- return that.__renderContent(that.__renderContextConsumer((context) => {
- that.context = context;
- return that.__renderContextProvider({ pageContext: that });
- }));
- }
- };
-};
-
-export default raxPageRendererFactory;
\ No newline at end of file
diff --git a/packages/rax-renderer/tsconfig.json b/packages/rax-renderer/tsconfig.json
deleted file mode 100644
index 7e264d1f05..0000000000
--- a/packages/rax-renderer/tsconfig.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "compilerOptions": {
- "lib": ["es2015", "dom"],
- "target": "esnext",
- "module": "esnext",
- "moduleResolution": "node",
- "strict": false,
- "strictPropertyInitialization": false,
- "allowSyntheticDefaultImports": true,
- "esModuleInterop": true,
- "jsx": "react",
- "jsxFactory": "createElement",
- "importHelpers": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
- "sourceMap": true,
- "forceConsistentCasingInFileNames": true,
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "outDir": "lib"
- },
- "exclude": ["test", "lib", "es", "node_modules"],
- "include": [
- "src"
- ]
-}
diff --git a/packages/rax-simulator-renderer/.babelrc b/packages/rax-simulator-renderer/.babelrc
deleted file mode 100644
index e0e2e5f343..0000000000
--- a/packages/rax-simulator-renderer/.babelrc
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "plugins": [
- ["@babel/plugin-transform-react-jsx", {
- "pragma": "createElement", // default pragma is React.createElement
- "pragmaFrag": "createFragment", // default is React.Fragment
- "throwIfNamespace": false // defaults to true
- }]
- ]
-}
diff --git a/packages/rax-simulator-renderer/build.json b/packages/rax-simulator-renderer/build.json
deleted file mode 100644
index b95a17aafe..0000000000
--- a/packages/rax-simulator-renderer/build.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "plugins": ["build-plugin-component", "./build.plugin.js"]
-}
diff --git a/packages/rax-simulator-renderer/build.plugin.js b/packages/rax-simulator-renderer/build.plugin.js
deleted file mode 100644
index d613f1f56a..0000000000
--- a/packages/rax-simulator-renderer/build.plugin.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = ({ onGetWebpackConfig }) => {
- onGetWebpackConfig((config) => {
- config.performance.hints(false);
- });
-};
diff --git a/packages/rax-simulator-renderer/build.umd.json b/packages/rax-simulator-renderer/build.umd.json
deleted file mode 100644
index 833c92b246..0000000000
--- a/packages/rax-simulator-renderer/build.umd.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "entry": {
- "rax-simulator-renderer": "src/index"
- },
- "sourceMap": true,
- "library": "___RaxSimulatorRenderer___",
- "libraryTarget": "umd",
- "externals": {
- "react": "var window.React",
- "react-dom": "var window.ReactDOM",
- "prop-types": "var window.PropTypes",
- "@alifd/next": "var Next",
- "@alilc/lowcode-engine-ext": "var window.AliLowCodeEngineExt",
- "rax": "var window.Rax",
- "moment": "var moment",
- "lodash": "var _"
- },
- "polyfill": false,
- "outputDir": "dist",
- "vendor": false,
- "ignoreHtmlTemplate": true,
- "plugins": [
- "build-plugin-react-app",
- [
- "build-plugin-fusion",
- {
- "externalNext": "umd"
- }
- ],
- [
- "build-plugin-moment-locales",
- {
- "locales": ["zh-cn"]
- }
- ],
- "./build.plugin.js"
- ]
-}
diff --git a/packages/rax-simulator-renderer/package.json b/packages/rax-simulator-renderer/package.json
deleted file mode 100644
index 76954ff362..0000000000
--- a/packages/rax-simulator-renderer/package.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "name": "@alilc/lowcode-rax-simulator-renderer",
- "version": "1.1.6",
- "description": "rax simulator renderer for alibaba lowcode designer",
- "main": "lib/index.js",
- "module": "es/index.js",
- "license": "MIT",
- "files": [
- "dist"
- ],
- "scripts": {
- "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo",
- "build:umd": "build-scripts build --config build.umd.json"
- },
- "dependencies": {
- "@alilc/lowcode-designer": "1.1.6",
- "@alilc/lowcode-rax-renderer": "1.1.6",
- "@alilc/lowcode-types": "1.1.6",
- "@alilc/lowcode-utils": "1.1.6",
- "classnames": "^2.2.6",
- "driver-universal": "^3.1.3",
- "history": "^5.0.0",
- "lodash": "^4.17.19",
- "mobx": "^6.3.0",
- "mobx-react": "^7.2.0",
- "path-to-regexp": "3.2.0",
- "rax-find-dom-node": "^1.0.0",
- "react": "^16",
- "react-dom": "^16.7.0"
- },
- "devDependencies": {
- "@alib/build-scripts": "^0.1.18",
- "@babel/plugin-transform-react-jsx": "^7.10.4",
- "@types/classnames": "^2.2.7",
- "@types/node": "^13.7.1",
- "@types/rax": "^1.0.0",
- "@types/react": "^16",
- "@types/react-dom": "^16",
- "build-plugin-rax-component": "^0.2.11"
- },
- "peerDependencies": {
- "rax": "^1.1.0"
- },
- "publishConfig": {
- "access": "public",
- "registry": "https://registry.npmjs.org/"
- },
- "repository": {
- "type": "http",
- "url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/rax-simulator-renderer"
- },
- "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-rax-simulator-renderer@1.0.73/build/index.html",
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
-}
diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.less
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx b/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx
deleted file mode 100644
index 6608942c4b..0000000000
--- a/packages/rax-simulator-renderer/src/builtin-components/UnusualComponent/index.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Component } from 'rax';
-import lg from '@ali/vu-logger';
-
-import './index.less';
-
-export class UnknownComponent extends Component {
- props: {
- _componentName: string;
- };
-
- render() {
- lg.log('ERROR_NO_COMPONENT_VIEW');
- lg.error('Error component information:', this.props);
- return
组件 {this.props._componentName} 无视图,请打开控制台排查
;
- }
-}
-
-export class FaultComponent extends Component {
- props: {
- _componentName: string;
- };
-
- render() {
- return
组件 {this.props._componentName} 渲染错误,请打开控制台排查
;
- }
-}
-
-export class HiddenComponent extends Component {
- render() {
- return
在本页面不显示
;
- }
-}
-
-export default { FaultComponent, HiddenComponent, UnknownComponent };
diff --git a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx b/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx
deleted file mode 100644
index 5276b0018d..0000000000
--- a/packages/rax-simulator-renderer/src/builtin-components/leaf.tsx
+++ /dev/null
@@ -1,251 +0,0 @@
-import { Component } from 'rax';
-
-class Leaf extends Component {
- static displayName = 'Leaf';
-
- static componentMetadata = {
- componentName: 'Leaf',
- configure: {
- props: [{
- name: 'children',
- setter: 'StringSetter',
- }],
- // events/className/style/general/directives
- supports: false,
- },
- };
-
- render() {
- const { children } = this.props;
- return children;
- }
-}
-
-export default Leaf;
-
-// import { Component, createElement } from 'rax';
-// import findDOMNode from 'rax-find-dom-node';
-// import { each, get, omit } from 'lodash';
-// import { getView, setNativeNode, createNodeStyleSheet } from '../renderUtils';
-
-// import { FaultComponent, HiddenComponent, UnknownComponent } from '../UnusualComponent';
-
-// export interface ILeaf {
-// leaf: any;
-// }
-// export default class Leaf extends Component
{
-// static displayName = 'Leaf';
-
-// state = {
-// hasError: false,
-// };
-
-// willDetach: any[];
-
-// styleSheet: any;
-
-// context: any;
-// refs: any;
-
-// componentWillMount() {
-// const { leaf } = this.props;
-// this.willDetach = [
-// leaf.onPropsChange(() => {
-// // 强制刷新
-// this.setState(this.state);
-// }),
-// leaf.onChildrenChange(() => {
-// // 强制刷新
-// this.setState(this.state);
-// }),
-// leaf.onStatusChange((status: { dropping: boolean }, field: string) => {
-// // console.log({...status}, field)
-// if (status.dropping !== false) {
-// // 当 dropping 为 Insertion 对象时,强制渲染会出错,原因待查
-// return;
-// }
-// if (field === 'dragging' || field === 'dropping' || field === 'pseudo' || field === 'visibility') {
-// // 强制刷新
-// this.setState(this.state);
-// }
-// }),
-// ];
-
-// /**
-// * while props replaced
-// * bind the new event on it
-// */
-// leaf.onPropsReplace(() => {
-// this.willDetach[0]();
-// this.willDetach[0] = leaf.onPropsChange(() => {
-// // 强制刷新
-// this.setState(this.state);
-// });
-// });
-// }
-
-// componentDidMount() {
-// this.modifyDOM();
-// }
-
-// shouldComponentUpdate() {
-// // forceUpdate 的替代方案
-// return true;
-// // const pageCanRefresh = this.leaf.getPage().canRefresh();
-// // if (pageCanRefresh) {
-// // return pageCanRefresh;
-// // }
-// // const getExtProps = obj => {
-// // const { leaf, ...props } = obj;
-// // return props;
-// // };
-// // return !shallowEqual(getExtProps(this.props), getExtProps(nextProps));
-// }
-
-// componentDidUpdate() {
-// this.modifyDOM();
-// }
-
-// componentWillUnmount() {
-// if (this.willDetach) {
-// this.willDetach.forEach((off) => off());
-// }
-// setNativeNode(this.props.leaf, null);
-// }
-
-// componentDidCatch() {
-// this.setState({ hasError: true }, () => {
-// console.log('error');
-// });
-// }
-
-// modifyDOM() {
-// const shell = findDOMNode(this);
-// const { leaf } = this.props;
-// // 与 React 不同,rax 的 findDOMNode 找不到节点时,
-// // shell 会是 ,而不是 null,
-// // 所以这里进行是否为注释的判断
-// if (shell && shell.nodeType !== window.Node.COMMENT_NODE) {
-// setNativeNode(leaf, shell);
-// if (leaf.getStatus('dragging')) {
-// get(shell, 'classList').add('engine-dragging');
-// } else {
-// get(shell, 'classList').remove('engine-dragging');
-// }
-// each(get(shell, 'classList'), (cls) => {
-// if (cls.substring(0, 8) === '-pseudo-') {
-// get(shell, 'classList').remove(cls);
-// }
-// });
-// const pseudo = leaf.getStatus('pseudo');
-// if (pseudo) {
-// get(shell, 'classList').add(`-pseudo-${pseudo}`);
-// }
-// } else {
-// setNativeNode(leaf, null);
-// }
-// }
-
-// render() {
-// const props = omit(this.props, ['leaf']);
-// const { leaf } = this.props;
-// const componentName = leaf.getComponentName();
-
-// const View = getView(componentName);
-
-// const newProps = {
-// _componentName: componentName,
-// };
-
-// if (!View) {
-// return createElement(UnknownComponent, {
-// // _componentName: componentName,
-// ...newProps,
-// });
-// }
-
-// let staticProps = {
-// ...leaf.getStaticProps(false),
-// ...props,
-// _componentName: componentName,
-// _leaf: leaf,
-// componentId: leaf.getId(),
-// };
-
-// if (!leaf.isVisibleInPane()) {
-// return null;
-// }
-
-// if (!leaf.isVisible()) {
-// return createElement(HiddenComponent, {
-// ...staticProps,
-// });
-// }
-
-// if (this.state.hasError) {
-// return createElement(FaultComponent, {
-// // _componentName: componentName,
-// ...newProps,
-// });
-// }
-
-// if (this.styleSheet) {
-// this.styleSheet.parentNode.removeChild(this.styleSheet);
-// }
-
-// this.styleSheet = createNodeStyleSheet(staticProps);
-
-// if (leaf.ableToModifyChildren()) {
-// const children = leaf
-// .getChildren()
-// .filter((child: any) => child.getComponentName() !== 'Slot')
-// .map((child: any) =>
-// createElement(Leaf, {
-// key: child.getId(),
-// leaf: child,
-// }),
-// );
-// // const insertion = leaf.getStatus('dropping');
-// // InsertionGhost 都是React节点,用Rax渲染会报错,后面这些节点需要通过Rax组件来实现
-// // if (children.length < 1 && insertion && insertion.getIndex() !== null) {
-
-// // //children = [];
-// // children = [];
-// // } else if (insertion && insertion.isNearEdge()) {
-// // if (insertion.isNearAfter()) {
-// // children.push();
-// // } else {
-// // children.unshift();
-// // }
-// // }
-// staticProps = {
-// ...staticProps,
-// ...this.processSlots(this.props.leaf.getChildren()),
-// };
-
-// return createElement(
-// View,
-// {
-// ...staticProps,
-// },
-// children,
-// );
-// }
-
-// return createElement(View, {
-// ...staticProps,
-// });
-// }
-
-// processSlots(children: Rax.RaxNodeArray) {
-// const slots: any = {};
-// children &&
-// children.length &&
-// children.forEach((child: any) => {
-// if (child.getComponentName() === 'Slot') {
-// slots[child.getPropValue('slotName')] = ;
-// }
-// });
-// return slots;
-// }
-// }
diff --git a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts b/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts
deleted file mode 100644
index 10f8438fb2..0000000000
--- a/packages/rax-simulator-renderer/src/builtin-components/renderUtils.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { isObject } from 'lodash';
-import { css } from '@alilc/lowcode-utils';
-
-const { toCss } = css;
-const engine = (window as any).VisualEngine;
-const { Trunk, Viewport } = engine;
-
-export const NativeNodeCache: any = {};
-
-function ucfirst(s: string) {
- return s.charAt(0).toUpperCase() + s.substring(1);
-}
-
-export function shallowEqual(obj: { [key: string]: string }, tObj: { [key: string]: string }) {
- for (const i in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, i) && obj[i] !== tObj[i]) {
- return false;
- }
- }
- return true;
-}
-
-export function createNodeStyleSheet(props: any) {
- if (props && props.fieldId) {
- let styleProp = props.__style__;
-
- if (isObject(styleProp)) {
- styleProp = toCss(styleProp);
- }
-
- if (typeof styleProp === 'string') {
- const s = document.createElement('style');
- const cssId = `_style_pesudo_${ props.fieldId}`;
- const cssClass = `_css_pesudo_${ props.fieldId}`;
-
- props.className = cssClass;
- s.setAttribute('type', 'text/css');
- s.setAttribute('id', cssId);
- document.getElementsByTagName('head')[0].appendChild(s);
-
- s.appendChild(
- document.createTextNode(
- styleProp
- .replace(/(\d+)rpx/g, (a, b) => {
- return `${b / 2}px`;
- })
- .replace(/:root/g, `.${ cssClass}`),
- ),
- );
- return s;
- }
- }
-}
-
-export function setNativeNode(leaf: any, node: Rax.RaxNode) {
- const id = leaf.getId();
- if (NativeNodeCache[id] === node) {
- return;
- }
- NativeNodeCache[id] = node;
- leaf.mountChange();
-}
-
-export function getView(componentName: string) {
- // let view = new Trunk().getPrototypeView(componentName);
- let view = Trunk.getPrototypeView(componentName);
- if (!view) {
- return null;
- }
- const viewport = Viewport.getViewport();
- if (viewport) {
- const [mode, device] = viewport.split('-', 2).map(ucfirst);
- if (view.hasOwnProperty(device)) {
- view = view[device];
- }
-
- if (view.hasOwnProperty(mode)) {
- view = view[mode];
- }
- }
-
- return view;
-}
diff --git a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx b/packages/rax-simulator-renderer/src/builtin-components/slot.tsx
deleted file mode 100644
index 3a77491bc0..0000000000
--- a/packages/rax-simulator-renderer/src/builtin-components/slot.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Component } from 'rax';
-
-class Slot extends Component {
- static displayName = 'Slot';
-
- static componentMetadata = {
- componentName: 'Slot',
- configure: {
- props: [{
- name: '___title',
- title: {
- type: 'i18n',
- 'en-US': 'Slot Title',
- 'zh-CN': '插槽标题',
- },
- setter: 'StringSetter',
- defaultValue: '插槽容器',
- }, {
- name: '___params',
- title: {
- type: 'i18n',
- 'en-US': 'Slot Params',
- 'zh-CN': '插槽入参',
- },
- setter: {
- componentName: 'ArraySetter',
- props: {
- itemSetter: {
- componentName: 'StringSetter',
- props: {
- placeholder: {
- type: 'i18n',
- 'zh-CN': '参数名称',
- 'en-US': 'Argument Name',
- },
- },
- },
- },
- },
- }],
- // events/className/style/general/directives
- supports: false,
- },
- };
-
- render() {
- const { children } = this.props;
- return (
- {children}
- );
- }
-}
-
-export default Slot;
diff --git a/packages/rax-simulator-renderer/src/host.ts b/packages/rax-simulator-renderer/src/host.ts
deleted file mode 100644
index c5cf2e3e1c..0000000000
--- a/packages/rax-simulator-renderer/src/host.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-// NOTE: 仅做类型标注,切勿做其它用途
-import { BuiltinSimulatorHost } from '@alilc/lowcode-designer';
-
-export const host: BuiltinSimulatorHost = (window as any).LCSimulatorHost;
diff --git a/packages/rax-simulator-renderer/src/image.d.ts b/packages/rax-simulator-renderer/src/image.d.ts
deleted file mode 100644
index 7ed4ad925c..0000000000
--- a/packages/rax-simulator-renderer/src/image.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-declare module 'rax-find-dom-node';
-declare module '@alilc/lowcode-rax-renderer/lib/index';
diff --git a/packages/rax-simulator-renderer/src/index.ts b/packages/rax-simulator-renderer/src/index.ts
deleted file mode 100644
index 3a88726657..0000000000
--- a/packages/rax-simulator-renderer/src/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import renderer from './renderer';
-
-if (typeof window !== 'undefined') {
- (window as any).SimulatorRenderer = renderer;
-}
-
-export default renderer;
diff --git a/packages/rax-simulator-renderer/src/rax-use-router.js b/packages/rax-simulator-renderer/src/rax-use-router.js
deleted file mode 100644
index 9a399a9478..0000000000
--- a/packages/rax-simulator-renderer/src/rax-use-router.js
+++ /dev/null
@@ -1,288 +0,0 @@
-// Inspired by react-router and universal-router
-import { useState, useEffect, useLayoutEffect, createElement } from 'rax';
-import pathToRegexp from 'path-to-regexp';
-
-const cache = {};
-function decodeParam(val) {
- try {
- return decodeURIComponent(val);
- } catch (err) {
- return val;
- }
-}
-
-function matchPath(route, pathname, parentParams) {
- let { path, routes, exact: end = true, strict = false, sensitive = false } = route;
- // If not has path or has routes that should do not exact match
- if (path == null || routes) {
- end = false;
- }
-
- // Default path is empty
- path = path || '';
-
- const regexpCacheKey = `${path}|${end}|${strict}|${sensitive}`;
- const keysCacheKey = `${regexpCacheKey }|`;
-
- let regexp = cache[regexpCacheKey];
- const keys = cache[keysCacheKey] || [];
-
- if (!regexp) {
- regexp = pathToRegexp(path, keys, {
- end,
- strict,
- sensitive,
- });
- cache[regexpCacheKey] = regexp;
- cache[keysCacheKey] = keys;
- }
-
- const result = regexp.exec(pathname);
- if (!result) {
- return null;
- }
-
- const url = result[0];
- const params = { ...parentParams, history: router.history, location: router.history.location };
-
- for (let i = 1; i < result.length; i++) {
- const key = keys[i - 1];
- const prop = key.name;
- const value = result[i];
- if (value !== undefined || !Object.prototype.hasOwnProperty.call(params, prop)) {
- if (key.repeat) {
- params[prop] = value ? value.split(key.delimiter).map(decodeParam) : [];
- } else {
- params[prop] = value ? decodeParam(value) : value;
- }
- }
- }
-
- return {
- path: !end && url.charAt(url.length - 1) === '/' ? url.slice(1) : url,
- params,
- };
-}
-
-function matchRoute(route, baseUrl, pathname, parentParams) {
- let matched;
- let childMatches;
- let childIndex = 0;
-
- return {
- next() {
- if (!matched) {
- matched = matchPath(route, pathname, parentParams);
-
- if (matched) {
- return {
- done: false,
- $: {
- route,
- baseUrl,
- path: matched.path,
- params: matched.params,
- },
- };
- }
- }
-
- if (matched && route.routes) {
- while (childIndex < route.routes.length) {
- if (!childMatches) {
- const childRoute = route.routes[childIndex];
- childRoute.parent = route;
-
- childMatches = matchRoute(
- childRoute,
- baseUrl + matched.path,
- pathname.slice(matched.path.length),
- matched.params,
- );
- }
-
- const childMatch = childMatches.next();
- if (!childMatch.done) {
- return {
- done: false,
- $: childMatch.$,
- };
- }
-
- childMatches = null;
- childIndex++;
- }
- }
-
- return { done: true };
- },
- };
-}
-
-let _initialized = false;
-let _routerConfig = null;
-const router = {
- history: null,
- handles: [],
- errorHandler() { },
- addHandle(handle) {
- return router.handles.push(handle);
- },
- removeHandle(handleId) {
- router.handles[handleId - 1] = null;
- },
- triggerHandles(component) {
- router.handles.forEach((handle) => {
- handle && handle(component);
- });
- },
- match(fullpath) {
- if (fullpath == null) return;
-
- router.fullpath = fullpath;
-
- const parent = router.root;
- const matched = matchRoute(
- parent,
- parent.path,
- fullpath,
- );
-
- function next(parent) {
- const current = matched.next();
-
- if (current.done) {
- const error = new Error(`No match for ${fullpath}`);
- return router.errorHandler(error, router.history.location);
- }
-
- let { component } = current.$.route;
- if (typeof component === 'function') {
- component = component(current.$.params, router.history.location);
- }
- if (component instanceof Promise) {
- // Lazy loading component by import('./Foo')
- return component.then((component) => {
- // Check current fullpath avoid router has changed before lazy loading complete
- if (fullpath === router.fullpath) {
- router.triggerHandles(component);
- }
- });
- } else if (component != null) {
- router.triggerHandles(component);
- return component;
- } else {
- return next(parent);
- }
- }
-
- return next(parent);
- },
-};
-
-function matchLocation({ pathname }) {
- router.match(pathname);
-}
-
-
-function getInitialComponent(routerConfig) {
- let InitialComponent = [];
-
- if (_routerConfig === null) {
- if (process.env.NODE_ENV !== 'production') {
- if (!routerConfig) {
- throw new Error('Error: useRouter should have routerConfig, see: https://www.npmjs.com/package/rax-use-router.');
- }
- if (!routerConfig.history || !routerConfig.routes) {
- throw new Error('Error: routerConfig should contain history and routes, see: https://www.npmjs.com/package/rax-use-router.');
- }
- }
- _routerConfig = routerConfig;
- }
- if (_routerConfig.InitialComponent) {
- InitialComponent = _routerConfig.InitialComponent;
- }
- router.history = _routerConfig.history;
-
- return InitialComponent;
-}
-
-let unlisten = null;
-let handleId = null;
-let pathes = '';
-export function useRouter(routerConfig) {
- const [component, setComponent] = useState(getInitialComponent(routerConfig));
-
- let newPathes = '';
- if (routerConfig) {
- _routerConfig = routerConfig;
- const { routes } = _routerConfig;
- router.root = Array.isArray(routes) ? { routes } : routes;
- if (Array.isArray(routes)) {
- newPathes = routes.map(it => it.path).join(',');
- } else {
- newPathes = routes.path;
- }
- }
- if (_initialized && _routerConfig.history) {
- if (newPathes !== pathes) {
- matchLocation(_routerConfig.history.location);
- pathes = newPathes;
- }
- }
-
- useLayoutEffect(() => {
- if (unlisten) {
- unlisten();
- unlisten = null;
- }
-
- if (handleId) {
- router.removeHandle(handleId);
- handleId = null;
- }
-
- const { history } = _routerConfig;
- const { routes } = _routerConfig;
-
- router.root = Array.isArray(routes) ? { routes } : routes;
-
- handleId = router.addHandle((component) => {
- setComponent(component);
- });
-
- // Init path match
- if (_initialized || !_routerConfig.InitialComponent) {
- matchLocation(history.location);
- pathes = newPathes;
- }
-
- unlisten = history.listen(({ location }) => {
- matchLocation(location);
- pathes = newPathes;
- });
-
- _initialized = true;
-
- return () => {
- pathes = '';
- router.removeHandle(handleId);
- handleId = null;
- unlisten();
- unlisten = null;
- };
- }, []);
-
- return { component };
-}
-
-export function withRouter(Component) {
- function Wrapper(props) {
- const { history } = router;
- return createElement(Component, { ...props, history, location: history.location });
- }
-
- Wrapper.displayName = `withRouter(${ Component.displayName || Component.name })`;
- Wrapper.WrappedComponent = Component;
- return Wrapper;
-}
diff --git a/packages/rax-simulator-renderer/src/renderer-view.tsx b/packages/rax-simulator-renderer/src/renderer-view.tsx
deleted file mode 100644
index bc39cddea0..0000000000
--- a/packages/rax-simulator-renderer/src/renderer-view.tsx
+++ /dev/null
@@ -1,275 +0,0 @@
-import RaxRenderer from '@alilc/lowcode-rax-renderer';
-import { History } from 'history';
-import { Component, createElement, Fragment } from 'rax';
-import { useRouter } from './rax-use-router';
-import { DocumentInstance, SimulatorRendererContainer } from './renderer';
-import './renderer.less';
-import { uniqueId } from '@alilc/lowcode-utils';
-import { GlobalEvent } from '@alilc/lowcode-types';
-import { host } from './host';
-
-// patch cloneElement avoid lost keyProps
-const originCloneElement = (window as any).Rax.cloneElement;
-(window as any).Rax.cloneElement = (child: any, { _leaf, ...props }: any = {}, ...rest: any[]) => {
- if (child.ref && props.ref) {
- const dRef = props.ref;
- const cRef = child.ref;
- props.ref = (x: any) => {
- if (cRef) {
- if (typeof cRef === 'function') {
- cRef(x);
- } else {
- try {
- cRef.current = x;
- } catch (e) {
- console.error(e);
- }
- }
- }
- if (dRef) {
- if (typeof dRef === 'function') {
- dRef(x);
- } else {
- try {
- dRef.current = x;
- } catch (e) {
- console.error(e);
- }
- }
- }
- };
- }
- return originCloneElement(child, props, ...rest);
-};
-
-export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> {
- private unlisten: any;
-
- componentDidMount() {
- const { rendererContainer } = this.props;
- this.unlisten = rendererContainer.onLayoutChange(() => {
- this.forceUpdate();
- });
- }
-
- componentWillUnmount() {
- if (this.unlisten) {
- this.unlisten();
- }
- }
-
- render() {
- const { rendererContainer } = this.props;
- return (
-
-
-
- );
- }
-}
-
-export const Routes = (props: {
- rendererContainer: SimulatorRendererContainer;
- history: History;
-}) => {
- const { rendererContainer, history } = props;
- const { documentInstances } = rendererContainer;
-
- const routes = {
- history,
- routes: documentInstances.map(instance => {
- return {
- path: instance.path,
- component: (props: any) => ,
- };
- }),
- };
- const { component } = useRouter(routes);
- return component;
-};
-
-function ucfirst(s: string) {
- return s.charAt(0).toUpperCase() + s.substring(1);
-}
-function getDeviceView(view: any, device: string, mode: string) {
- if (!view || typeof view === 'string') {
- return view;
- }
-
- // compatible vision Mobile | Preview
- device = ucfirst(device);
- if (device === 'Mobile' && view.hasOwnProperty(device)) {
- view = view[device];
- }
- mode = ucfirst(mode);
- if (mode === 'Preview' && view.hasOwnProperty(mode)) {
- view = view[mode];
- }
- return view;
-}
-
-class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {
- constructor(props: any) {
- super(props);
- this.props.rendererContainer.onReRender(() => {
- this.forceUpdate();
- });
- }
-
- render() {
- const { rendererContainer, children } = this.props;
- const { layout } = rendererContainer;
-
- if (layout) {
- const { Component, props, componentName } = layout;
- if (Component) {
- return {children};
- }
- if (componentName && rendererContainer.getComponent(componentName)) {
- return createElement(
- rendererContainer.getComponent(componentName),
- {
- ...props,
- rendererContainer,
- },
- [children],
- );
- }
- }
-
- return {children};
- }
-}
-
-class Renderer extends Component<{
- rendererContainer: SimulatorRendererContainer;
- documentInstance: DocumentInstance;
-}> {
- private unlisten: any;
- private key: string;
- private startTime: number | null = null;
-
- componentWillMount() {
- this.key = uniqueId('renderer');
- }
-
- componentDidMount() {
- const { documentInstance } = this.props;
- this.unlisten = documentInstance.onReRender((params) => {
- if (params && params.shouldRemount) {
- this.key = uniqueId('renderer');
- }
- this.forceUpdate();
- });
- }
-
- componentWillUnmount() {
- if (this.unlisten) {
- this.unlisten();
- }
- }
- shouldComponentUpdate() {
- return false;
- }
-
- componentDidUpdate() {
- if (this.startTime) {
- const time = Date.now() - this.startTime;
- const nodeCount = host.designer.currentDocument?.getNodeCount?.();
- host.designer.editor?.eventBus.emit(GlobalEvent.Node.Rerender, {
- componentName: 'Renderer',
- type: 'All',
- time,
- nodeCount,
- });
- }
- }
-
- schemaChangedSymbol = false;
-
- getSchemaChangedSymbol = () => {
- return this.schemaChangedSymbol;
- };
-
- setSchemaChangedSymbol = (symbol: boolean) => {
- this.schemaChangedSymbol = symbol;
- };
-
- render() {
- const { documentInstance } = this.props;
- const { container, document } = documentInstance;
- const { designMode, device } = container;
- const { rendererContainer: renderer } = this.props;
- this.startTime = Date.now();
- this.schemaChangedSymbol = false;
-
- return (
- {
- documentInstance.mountInstance(schema.id, ref);
- }}
- thisRequiredInJSE={host.thisRequiredInJSE}
- documentId={document.id}
- getNode={(id: string) => documentInstance.getNode(id) as any}
- rendererName="PageRenderer"
- customCreateElement={(Component: any, props: any, children: any) => {
- const { __id, ...viewProps } = props;
- viewProps.componentId = __id;
- const leaf = documentInstance.getNode(__id);
- viewProps._leaf = leaf;
- viewProps._componentName = leaf?.componentName;
- // 如果是容器 && 无children && 高宽为空 增加一个占位容器,方便拖动
- if (
- !viewProps.dataSource &&
- leaf?.isContainer() &&
- (children == null || (Array.isArray(children) && !children.length)) &&
- (!viewProps.style || Object.keys(viewProps.style).length === 0)
- ) {
- children = (
-
- {viewProps.placeholder || '拖拽组件或模板到这里'}
-
- );
- }
-
- // if (viewProps._componentName === 'Menu') {
- // Object.assign(viewProps, {
- // _componentName: 'Menu',
- // className: '_css_pesudo_menu_kbrzyh0f',
- // context: { VE: (window as any).VisualLowCodeRenderer },
- // direction: undefined,
- // events: { ignored: true },
- // fieldId: 'menu_kbrzyh0f',
- // footer: '',
- // header: '',
- // mode: 'inline',
- // onItemClick: { ignored: true },
- // onSelect: { ignored: true },
- // popupAlign: 'follow',
- // selectMode: false,
- // triggerType: 'click',
- // });
- // console.info('menuprops', viewProps);
- // }
-
- return createElement(
- getDeviceView(Component, device, designMode),
- viewProps,
- leaf?.isContainer() ? (children == null ? [] : Array.isArray(children) ? children : [children]) : children,
- );
- }}
- />
- );
- }
-}
diff --git a/packages/rax-simulator-renderer/src/renderer.less b/packages/rax-simulator-renderer/src/renderer.less
deleted file mode 100644
index b71dde9896..0000000000
--- a/packages/rax-simulator-renderer/src/renderer.less
+++ /dev/null
@@ -1,125 +0,0 @@
-body, html {
- display: block;
- background: white;
- padding: 0;
- margin: 0;
-}
-
-html.engine-cursor-move, html.engine-cursor-move * {
- cursor: grabbing !important;
-}
-
-html.engine-cursor-copy, html.engine-cursor-copy * {
- cursor: copy !important;
-}
-
-html.engine-cursor-ew-resize, html.engine-cursor-ew-resize * {
- cursor: ew-resize !important;
-}
-
-::-webkit-scrollbar {
- display: none;
-}
-
-.lc-container {
- &:empty {
- background: #f2f3f5;
- color: #a7b1bd;
- outline: 1px dashed rgba(31, 56, 88, 0.2);
- outline-offset: -1px !important;
- height: 66px;
- max-height: 100%;
- min-width: 140px;
- text-align: center;
- overflow: hidden;
- display: flex;
- align-items: center;
- &:before {
- content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC';
- font-size: 14px;
- z-index: 1;
- width: 100%;
- white-space: nowrap;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- }
-}
-
-.engine-empty {
- background: #f2f3f5;
- color: #a7b1bd;
- outline: 1px dashed rgba(31, 56, 88, 0.2);
- outline-offset: -1px !important;
- height: 66px;
- max-height: 100%;
- min-width: 140px;
- text-align: center;
- overflow: hidden;
- display: flex;
- align-items: center;
-}
-
-.engine-empty:before {
- content: '\62D6\62FD\7EC4\4EF6\6216\6A21\677F\5230\8FD9\91CC';
- font-size: 14px;
- z-index: 1;
- width: 100%;
- white-space: nowrap;
- height: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.lc-container-placeholder {
- min-height: 60px;
- height: 100%;
- width: 100%;
- background-color: rgb(240, 240, 240);
- border: 1px dotted;
- color: rgb(167, 177, 189);
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 14px;
-}
-
-body.engine-document {
- &:after, &:before {
- content: "";
- display: table;
- }
- &:after {
- clear: both;
- }
-
- /*
- .next-input-group,
- .next-checkbox-group,.next-date-picker,.next-input,.next-month-picker,
- .next-number-picker,.next-radio-group,.next-range,.next-range-picker,
- .next-rating,.next-select,.next-switch,.next-time-picker,.next-upload,
- .next-year-picker,
- .next-breadcrumb-item,.next-calendar-header,.next-calendar-table {
- pointer-events: none !important;
- } */
-}
-
-.engine-live-editing {
- cursor: text;
- outline: none;
- box-shadow: 0 0 0 2px rgb(102, 188, 92);
- user-select: text;
-}
-
-/* stylelint-disable-next-line selector-max-id */
-#app {
- height: 100vh;
-}
-
-
-.luna-page {
- height: 100%;
-}
diff --git a/packages/rax-simulator-renderer/src/renderer.ts b/packages/rax-simulator-renderer/src/renderer.ts
deleted file mode 100644
index 64ec2d2c69..0000000000
--- a/packages/rax-simulator-renderer/src/renderer.ts
+++ /dev/null
@@ -1,690 +0,0 @@
-import { BuiltinSimulatorRenderer, Component, IBaseNode, IDocumentModel } from '@alilc/lowcode-designer';
-import { IPublicTypeComponentSchema, IPublicTypeNodeSchema, IPublicTypeNpmInfo, IPublicEnumTransformStage, IPublicTypeNodeInstance, IPublicTypeProjectSchema } from '@alilc/lowcode-types';
-import { Asset, compatibleLegaoSchema, cursor, isElement, isESModule, isLowcodeProjectSchema, isComponentSchema, isPlainObject, isReactComponent, setNativeSelection } from '@alilc/lowcode-utils';
-import LowCodeRenderer from '@alilc/lowcode-rax-renderer';
-import { computed, observable as obx, makeObservable, configure } from 'mobx';
-import DriverUniversal from 'driver-universal';
-import { createMemoryHistory, MemoryHistory } from 'history';
-// @ts-ignore
-import Rax, { ComponentType, createElement, render as raxRender, shared } from 'rax';
-import Leaf from './builtin-components/leaf';
-import Slot from './builtin-components/slot';
-import { host } from './host';
-import SimulatorRendererView from './renderer-view';
-import { raxFindDOMNodes } from './utils/find-dom-nodes';
-import { getClientRects } from './utils/get-client-rects';
-import loader from './utils/loader';
-import { parseQuery, withQueryParams } from './utils/url';
-import { IEventBus, createModuleEventBus } from '@alilc/lowcode-editor-core';
-
-configure({ enforceActions: 'never' });
-const { Instance } = shared;
-
-export interface LibraryMap {
- [key: string]: string;
-}
-
-const SYMBOL_VNID = Symbol('_LCNodeId');
-const SYMBOL_VDID = Symbol('_LCDocId');
-
-const INTERNAL = '_internal';
-
-function accessLibrary(library: string | object) {
- if (typeof library !== 'string') {
- return library;
- }
-
- return (window as any)[library];
-}
-
-// Slot/Leaf and Fragment|FunctionComponent polyfill(ref)
-
-const builtinComponents = {
- Slot,
- Leaf,
-};
-
-function buildComponents(
- libraryMap: LibraryMap,
- componentsMap: { [componentName: string]: IPublicTypeNpmInfo | ComponentType | IPublicTypeComponentSchema },
- createComponent: (schema: IPublicTypeProjectSchema) => Component | null,
-) {
- const components: any = {
- ...builtinComponents,
- };
- Object.keys(componentsMap).forEach((componentName) => {
- let component = componentsMap[componentName];
- if (component && (isLowcodeProjectSchema(component) || isComponentSchema(component))) {
- if (isComponentSchema(component)) {
- components[componentName] = createComponent({
- version: '',
- componentsMap: [],
- componentsTree: [component],
- });
- } else {
- components[componentName] = createComponent(component);
- }
- } else if (isReactComponent(component)) {
- components[componentName] = component;
- } else {
- component = findComponent(libraryMap, componentName, component as IPublicTypeNpmInfo);
- if (component) {
- components[componentName] = component;
- }
- }
- });
- return components;
-}
-
-let REACT_KEY = '';
-function cacheReactKey(el: Element): Element {
- if (REACT_KEY !== '') {
- return el;
- }
- // react17 采用 __reactFiber 开头
- REACT_KEY = Object.keys(el).find(
- (key) => key.startsWith('__reactInternalInstance$') || key.startsWith('__reactFiber$'),
- ) || '';
- if (!REACT_KEY && (el as HTMLElement).parentElement) {
- return cacheReactKey((el as HTMLElement).parentElement!);
- }
- return el;
-}
-
-function checkInstanceMounted(instance: any): boolean {
- if (isElement(instance)) {
- return instance.parentElement != null;
- }
- return true;
-}
-
-function isValidDesignModeRaxComponentInstance(
- raxComponentInst: any,
-): raxComponentInst is {
- props: {
- _leaf: Exclude['node'], null | undefined>;
- };
-} {
- const leaf = raxComponentInst?.props?._leaf;
- return leaf && typeof leaf === 'object' && leaf.isNode;
-}
-
-export class DocumentInstance {
- private instancesMap = new Map();
-
- private emitter: IEventBus = createModuleEventBus('DocumentInstance');
-
- get schema(): any {
- return this.document.export(IPublicEnumTransformStage.Render);
- }
-
- constructor(readonly container: SimulatorRendererContainer, readonly document: IDocumentModel) {
- makeObservable(this);
- }
-
- @computed get suspended(): any {
- return false;
- }
-
- @computed get scope(): any {
- return null;
- }
-
- get path(): string {
- return `/${ this.document.fileName}`;
- }
-
- get id() {
- return this.document.id;
- }
-
- private unmountIntance(id: string, instance: any) {
- const instances = this.instancesMap.get(id);
- if (instances) {
- const i = instances.indexOf(instance);
- if (i > -1) {
- instances.splice(i, 1);
- host.setInstance(this.document.id, id, instances);
- }
- }
- }
-
- refresh() {
- this.emitter.emit('rerender', { shouldRemount: true });
- }
-
- onReRender(fn: () => void) {
- this.emitter.on('rerender', fn);
- return () => {
- this.emitter.removeListener('renderer', fn);
- };
- }
-
- mountInstance(id: string, instance: any) {
- const docId = this.document.id;
- const { instancesMap } = this;
- if (instance == null) {
- let instances = this.instancesMap.get(id);
- if (instances) {
- instances = instances.filter(checkInstanceMounted);
- if (instances.length > 0) {
- instancesMap.set(id, instances);
- host.setInstance(this.document.id, id, instances);
- } else {
- instancesMap.delete(id);
- host.setInstance(this.document.id, id, null);
- }
- }
- return;
- }
- const unmountIntance = this.unmountIntance.bind(this);
- const origId = (instance as any)[SYMBOL_VNID];
- if (origId && origId !== id) {
- // 另外一个节点的 instance 在此被复用了,需要从原来地方卸载
- unmountIntance(origId, instance);
- }
- if (isElement(instance)) {
- cacheReactKey(instance);
- } else if (origId !== id) {
- // 涵盖 origId == null || origId !== id 的情况
- let origUnmount: any = instance.componentWillUnmount;
- if (origUnmount && origUnmount.origUnmount) {
- origUnmount = origUnmount.origUnmount;
- }
- // hack! delete instance from map
- const newUnmount = function (this: any) {
- unmountIntance(id, instance);
- origUnmount && origUnmount.call(this);
- };
- (newUnmount as any).origUnmount = origUnmount;
- instance.componentWillUnmount = newUnmount;
- }
-
- (instance as any)[SYMBOL_VNID] = id;
- (instance as any)[SYMBOL_VDID] = docId;
- let instances = this.instancesMap.get(id);
- if (instances) {
- const l = instances.length;
- instances = instances.filter(checkInstanceMounted);
- let updated = instances.length !== l;
- if (!instances.includes(instance)) {
- instances.push(instance);
- updated = true;
- }
- if (!updated) {
- return;
- }
- } else {
- instances = [instance];
- }
- instancesMap.set(id, instances);
- host.setInstance(this.document.id, id, instances);
- }
-
- mountContext(docId: string, id: string, ctx: object) {
- // this.ctxMap.set(id, ctx);
- }
-
- getComponentInstances(id: string): any[] | null {
- return this.instancesMap.get(id) || null;
- }
-
- getNode(id: string): IBaseNode | null {
- return this.document.getNode(id);
- }
-}
-
-export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
- readonly isSimulatorRenderer = true;
- private dispose?: () => void;
- readonly history: MemoryHistory;
-
- private emitter: IEventBus = createModuleEventBus('SimulatorRendererContainer');
-
- @obx.ref private _documentInstances: DocumentInstance[] = [];
- get documentInstances() {
- return this._documentInstances;
- }
-
- get currentDocumentInstance() {
- return this._documentInstances.find((item) => item.id === host.project.currentDocument?.id);
- }
-
- constructor() {
- this.dispose = host.connect(this, () => {
- // sync layout config
- this._layout = host.project.get('config').layout;
- // todo: split with others, not all should recompute
- if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
- this._libraryMap = host.libraryMap || {};
- this._componentsMap = host.designer.componentsMap;
- this.buildComponents();
- }
-
- // sync designMode
- this._designMode = host.designMode;
-
- this._locale = host.locale;
-
- // sync requestHandlersMap
- this._requestHandlersMap = host.requestHandlersMap;
-
- // sync device
- this._device = host.device;
-
- this.emitter.emit('layoutChange');
- });
- const documentInstanceMap = new Map();
- let initialEntry = '/';
- let firstRun = true;
- host.autorun(() => {
- this._documentInstances = host.project.documents.map((doc) => {
- let inst = documentInstanceMap.get(doc.id);
- if (!inst) {
- inst = new DocumentInstance(this, doc);
- documentInstanceMap.set(doc.id, inst);
- }
- return inst;
- });
-
- const path = host.project.currentDocument ? documentInstanceMap.get(host.project.currentDocument.id)!.path : '/';
- if (firstRun) {
- initialEntry = path;
- firstRun = false;
- } else {
- if (this.history.location.pathname !== path) {
- this.history.replace(path);
- }
- this.emitter.emit('layoutChange');
- }
- });
- const history = createMemoryHistory({
- initialEntries: [initialEntry],
- });
- this.history = history;
- history.listen(({ location }) => {
- host.project.open(location.pathname.slice(1));
- });
- host.componentsConsumer.consume(async (componentsAsset) => {
- if (componentsAsset) {
- await this.load(componentsAsset);
- this.buildComponents();
- }
- });
- this._appContext = {
- utils: {
- router: {
- push(path: string, params?: object) {
- history.push(withQueryParams(path, params));
- },
- replace(path: string, params?: object) {
- history.replace(withQueryParams(path, params));
- },
- back() {
- history.back();
- },
- },
- legaoBuiltins: {
- getUrlParams() {
- const { search } = history.location;
- return parseQuery(search);
- },
- },
- },
- constants: {},
- requestHandlersMap: this._requestHandlersMap,
- };
- host.injectionConsumer.consume((data) => {
- // sync utils, i18n, contants,... config
- });
- }
-
- @obx private _layout: any = null;
- @computed get layout(): any {
- // TODO: parse layout Component
- return this._layout;
- }
- set layout(value: any) {
- this._layout = value;
- }
-
- private _libraryMap: { [key: string]: string } = {};
- private buildComponents() {
- // TODO: remove this.createComponent
- this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this));
- }
- @obx.ref private _components: Record | null = {};
- @computed get components(): Record {
- // 根据 device 选择不同组件,进行响应式
- // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
- return this._components || {};
- }
- // context from: utils、constants、history、location、match
- @obx.ref private _appContext = {};
- @computed get context(): any {
- return this._appContext;
- }
- @obx.ref private _designMode: string = 'design';
- @computed get designMode(): any {
- return this._designMode;
- }
- @obx.ref private _device: string = 'default';
- @computed get device() {
- return this._device;
- }
- @obx.ref private _locale: string | undefined = undefined;
- @computed get locale() {
- return this._locale;
- }
- @obx.ref private _requestHandlersMap = null;
- @computed get requestHandlersMap(): any {
- return this._requestHandlersMap;
- }
- @obx.ref private _componentsMap = {};
- @computed get componentsMap(): any {
- return this._componentsMap;
- }
-
- /**
- * 加载资源
- */
- load(asset: Asset): Promise {
- return loader.load(asset);
- }
-
- async loadAsyncLibrary(asyncLibraryMap: Record) {
- }
-
- getComponent(componentName: string) {
- const paths = componentName.split('.');
- const subs: string[] = [];
-
- while (true) {
- const component = this._components?.[componentName];
- if (component) {
- return getSubComponent(component, subs);
- }
-
- const sub = paths.pop();
- if (!sub) {
- return null;
- }
- subs.unshift(sub);
- componentName = paths.join('.');
- }
- }
-
- getNodeInstance(dom: HTMLElement): IPublicTypeNodeInstance | null {
- const INTERNAL = '_internal';
- let instance: any = dom;
- if (!isElement(instance)) {
- return {
- docId: instance.props._leaf.document.id,
- nodeId: instance.props._leaf.getId(),
- instance,
- node: instance.props._leaf,
- };
- }
- instance = Instance.get(dom);
-
- let loopNum = 0; // 防止由于某种意外而导致死循环
- while (instance && instance[INTERNAL] && loopNum < 1000) {
- if (isValidDesignModeRaxComponentInstance(instance)) {
- // if (instance && SYMBOL_VNID in instance) {
- // const docId = (instance.props as any).schema.docId;
- return {
- docId: instance.props._leaf.document?.id || '',
- nodeId: instance.props._leaf.getId(),
- instance,
- node: instance.props._leaf,
- };
- }
-
- instance = getRaxVDomParentInstance(instance);
- loopNum += 1;
- }
-
- return null;
- }
-
- getClosestNodeInstance(from: any, nodeId?: string): IPublicTypeNodeInstance | null {
- const el: any = from;
- if (el) {
- // if (isElement(el)) {
- // el = cacheReactKey(el);
- // } else {
- // return getNodeInstance(el, specId);
- // }
- return this.getNodeInstance(el);
- }
- return null;
- }
-
- findDOMNodes(instance: any, selector?: string): Array | null {
- let el = instance;
- if (selector) {
- el = document.querySelector(selector);
- }
- try {
- return raxFindDOMNodes(el);
- } catch (e) {
- // ignore
- }
- if (el && el.type && el.props && el.props.componentId) {
- el = document.querySelector(`${el.type}[componentid=${el.props.componentId}]`);
- } else {
- console.error(instance);
- throw new Error('This instance may not a valid element');
- }
- return raxFindDOMNodes(el);
- }
-
- getClientRects(element: Element | Text) {
- return getClientRects(element);
- }
-
- setNativeSelection(enableFlag: boolean) {
- setNativeSelection(enableFlag);
- }
- setDraggingState(state: boolean) {
- cursor.setDragging(state);
- }
- setCopyState(state: boolean) {
- cursor.setCopy(state);
- }
- clearState() {
- cursor.release();
- }
-
- onLayoutChange(cb: () => void) {
- this.emitter.on('layoutChange', cb);
- return () => {
- this.emitter.removeListener('layoutChange', cb);
- };
- }
-
- onReRender(fn: () => void) {
- this.emitter.on('rerender', fn);
- return () => {
- this.emitter.removeListener('renderer', fn);
- };
- }
-
- rerender() {
- this.currentDocumentInstance?.refresh();
- }
-
- stopAutoRepaintNode() {
- }
-
- enableAutoRepaintNode() {
- }
-
- createComponent(schema: IPublicTypeProjectSchema): Component | null {
- const _schema: IPublicTypeProjectSchema = {
- ...schema,
- componentsTree: schema.componentsTree.map(compatibleLegaoSchema),
- };
-
- const componentsTreeSchema = _schema.componentsTree[0];
-
- if (componentsTreeSchema.componentName === 'Component' && componentsTreeSchema.css) {
- const doc = window.document;
- const s = doc.createElement('style');
- s.setAttribute('type', 'text/css');
- s.setAttribute('id', `Component-${componentsTreeSchema.id || ''}`);
- s.appendChild(doc.createTextNode(componentsTreeSchema.css || ''));
- doc.getElementsByTagName('head')[0].appendChild(s);
- }
-
- const renderer = this;
- const { componentsMap: components } = renderer;
-
- class LowCodeComp extends Rax.Component {
- render() {
- const extraProps = getLowCodeComponentProps(this.props);
- // @ts-ignore
- return createElement(LowCodeRenderer, {
- ...extraProps,
- schema: componentsTreeSchema,
- components,
- designMode: '',
- locale: renderer.locale,
- messages: _schema.i18n || {},
- device: renderer.device,
- appHelper: renderer.context,
- rendererName: 'LowCodeRenderer',
- thisRequiredInJSE: host.thisRequiredInJSE,
- customCreateElement: (Comp: any, props: any, children: any) => {
- const componentMeta = host.currentDocument?.getComponentMeta(Comp.displayName);
- if (componentMeta?.isModal) {
- return null;
- }
-
- const { __id, __designMode, ...viewProps } = props;
- // mock _leaf,减少性能开销
- const _leaf = {
- isEmpty: () => false,
- isMock: true,
- };
- viewProps._leaf = _leaf;
- return createElement(Comp, viewProps, children);
- },
- });
- }
- }
-
- return LowCodeComp;
- }
-
- private _running = false;
- run() {
- if (this._running) {
- return;
- }
- this._running = true;
- const containerId = 'app';
- let container = document.getElementById(containerId);
- if (!container) {
- container = document.createElement('div');
- document.body.appendChild(container);
- container.id = containerId;
- }
-
- // ==== compatiable vision
- document.documentElement.classList.add('engine-page');
- document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
-
- raxRender(createElement(SimulatorRendererView, {
- rendererContainer: this,
- }), container, {
- driver: DriverUniversal,
- });
- host.project.setRendererReady(this);
- }
-}
-
-function getSubComponent(library: any, paths: string[]) {
- const l = paths.length;
- if (l < 1 || !library) {
- return library;
- }
- let i = 0;
- let component: any;
- while (i < l) {
- const key = paths[i]!;
- let ex: any;
- try {
- component = library[key];
- } catch (e) {
- ex = e;
- component = null;
- }
- if (i === 0 && component == null && key === 'default') {
- if (ex) {
- return l === 1 ? library : null;
- }
- component = library;
- } else if (component == null) {
- return null;
- }
- library = component;
- i++;
- }
- return component;
-}
-
-function findComponent(libraryMap: LibraryMap, componentName: string, npm?: IPublicTypeNpmInfo) {
- if (!npm) {
- return accessLibrary(componentName);
- }
- // libraryName the key access to global
- // export { exportName } from xxx exportName === global.libraryName.exportName
- // export exportName from xxx exportName === global.libraryName.default || global.libraryName
- // export { exportName as componentName } from package
- // if exportName == null exportName === componentName;
- // const componentName = exportName.subName, if exportName empty subName donot use
- const exportName = npm.exportName || npm.componentName || componentName;
- const libraryName = libraryMap[npm.package] || exportName;
- const library = accessLibrary(libraryName);
- const paths = npm.exportName && npm.subName ? npm.subName.split('.') : [];
- if (npm.destructuring) {
- paths.unshift(exportName);
- } else if (isESModule(library)) {
- paths.unshift('default');
- }
- return getSubComponent(library, paths);
-}
-
-function getLowCodeComponentProps(props: any) {
- if (!props || !isPlainObject(props)) {
- return props;
- }
- const newProps: any = {};
- Object.keys(props).forEach(k => {
- if (['children', 'componentId', '__designMode', '_componentName', '_leaf'].includes(k)) {
- return;
- }
- newProps[k] = props[k];
- });
- return newProps;
-}
-
-/**
- * 获取 Rax 里面 VDOM 的上一级的实例
- * 注意:Rax 的 development 的包是带有 __parentInstance,
- * 但是 production 的包 __parentInstance 会被压缩掉,
- * 所以这里遍历下其中的所有值,尝试找到有 _internal 的那个(别的值不会带有这个属性的)
- */
-function getRaxVDomParentInstance(instance: { _internal: any }) {
- const internalInstance = instance._internal;
- return internalInstance.__parentInstance ||
- Object.values(internalInstance).find(v => (
- v !== null &&
- v !== instance &&
- typeof v === 'object' &&
- typeof (v as {_internal: unknown})._internal === 'object'
- ));
-}
-
-export default new SimulatorRendererContainer();
diff --git a/packages/rax-simulator-renderer/src/utils/create-defer.ts b/packages/rax-simulator-renderer/src/utils/create-defer.ts
deleted file mode 100644
index e7997365a0..0000000000
--- a/packages/rax-simulator-renderer/src/utils/create-defer.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-export interface Defer {
- resolve(value?: T | PromiseLike): void;
- reject(reason?: any): void;
- promise(): Promise;
-}
-
-export function createDefer(): Defer {
- const r: any = {};
- const promise = new Promise((resolve, reject) => {
- r.resolve = resolve;
- r.reject = reject;
- });
-
- r.promise = () => promise;
-
- return r;
-}
diff --git a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts b/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts
deleted file mode 100644
index 106af2efac..0000000000
--- a/packages/rax-simulator-renderer/src/utils/find-dom-nodes.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { isElement } from '@alilc/lowcode-utils';
-import findDOMNode from 'rax-find-dom-node';
-// import { isDOMNode } from './is-dom-node';
-
-export function raxFindDOMNodes(instance: any): Array | null {
- if (!instance) {
- return null;
- }
- if (isElement(instance)) {
- return [instance];
- }
- // eslint-disable-next-line react/no-find-dom-node
- const result = findDOMNode(instance);
- if (Array.isArray(result)) {
- return result;
- }
- return [result];
-}
diff --git a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts b/packages/rax-simulator-renderer/src/utils/get-client-rects.ts
deleted file mode 100644
index dd13aba81e..0000000000
--- a/packages/rax-simulator-renderer/src/utils/get-client-rects.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { isElement } from '@alilc/lowcode-utils';
-
-// a range for test TextNode clientRect
-const cycleRange = document.createRange();
-
-export function getClientRects(node: Element | Text) {
- if (isElement(node)) {
- return [node.getBoundingClientRect()];
- }
-
- cycleRange.selectNode(node);
- return Array.from(cycleRange.getClientRects());
-}
diff --git a/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts b/packages/rax-simulator-renderer/src/utils/get-closest-node-instance.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/packages/rax-simulator-renderer/src/utils/get-device-view.ts b/packages/rax-simulator-renderer/src/utils/get-device-view.ts
deleted file mode 100644
index 9005562599..0000000000
--- a/packages/rax-simulator-renderer/src/utils/get-device-view.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-function ucfirst(s: string) {
- return s.charAt(0).toUpperCase() + s.substring(1);
-}
-function getDeviceView(view: any, device: string, mode: string) {
- if (!view || typeof view === 'string') {
- return view;
- }
-
- // compatible vision Mobile | Preview
- device = ucfirst(device);
- if (device === 'Mobile' && view.hasOwnProperty(device)) {
- view = view[device];
- }
- mode = ucfirst(mode);
- if (mode === 'Preview' && view.hasOwnProperty(mode)) {
- view = view[mode];
- }
- return view;
-}
-
-export default {
- getDeviceView,
-};
diff --git a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts b/packages/rax-simulator-renderer/src/utils/is-dom-node.ts
deleted file mode 100644
index bfbeb79c1f..0000000000
--- a/packages/rax-simulator-renderer/src/utils/is-dom-node.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export function isDOMNode(node: any): node is Element | Text {
- if (!node) return false;
- return node.nodeType && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE);
-}
diff --git a/packages/rax-simulator-renderer/src/utils/loader.ts b/packages/rax-simulator-renderer/src/utils/loader.ts
deleted file mode 100644
index 436e51c441..0000000000
--- a/packages/rax-simulator-renderer/src/utils/loader.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { load, evaluate } from './script';
-import StylePoint from './style';
-import {
- Asset,
- AssetLevel,
- AssetLevels,
- AssetType,
- AssetList,
- isAssetBundle,
- isAssetItem,
- assetItem,
- AssetItem,
- isCSSUrl,
-} from '@alilc/lowcode-utils';
-
-function parseAssetList(scripts: any, styles: any, assets: AssetList, level?: AssetLevel) {
- for (const asset of assets) {
- parseAsset(scripts, styles, asset, level);
- }
-}
-
-function parseAsset(scripts: any, styles: any, asset: Asset | undefined | null, level?: AssetLevel) {
- if (!asset) {
- return;
- }
- if (Array.isArray(asset)) {
- return parseAssetList(scripts, styles, asset, level);
- }
-
- if (isAssetBundle(asset)) {
- if (asset.assets) {
- if (Array.isArray(asset.assets)) {
- parseAssetList(scripts, styles, asset.assets, asset.level || level);
- } else {
- parseAsset(scripts, styles, asset.assets, asset.level || level);
- }
- return;
- }
- return;
- }
-
- if (!isAssetItem(asset)) {
- asset = assetItem(isCSSUrl(asset) ? AssetType.CSSUrl : AssetType.JSUrl, asset, level)!;
- }
-
- let lv = asset.level || level;
-
- if (!lv || AssetLevel[lv] == null) {
- lv = AssetLevel.App;
- }
-
- asset.level = lv;
- if (asset.type === AssetType.CSSUrl || asset.type == AssetType.CSSText) {
- styles[lv].push(asset);
- } else {
- scripts[lv].push(asset);
- }
-}
-
-export class AssetLoader {
- async load(asset: Asset) {
- const styles: any = {};
- const scripts: any = {};
- AssetLevels.forEach(lv => {
- styles[lv] = [];
- scripts[lv] = [];
- });
- parseAsset(scripts, styles, asset);
- const styleQueue: AssetItem[] = styles[AssetLevel.Environment].concat(
- styles[AssetLevel.Library],
- styles[AssetLevel.Theme],
- styles[AssetLevel.Runtime],
- styles[AssetLevel.App],
- );
- const scriptQueue: AssetItem[] = scripts[AssetLevel.Environment].concat(
- scripts[AssetLevel.Library],
- scripts[AssetLevel.Theme],
- scripts[AssetLevel.Runtime],
- scripts[AssetLevel.App],
- );
- await Promise.all(
- styleQueue.map(({ content, level, type, id }) => this.loadStyle(content, level!, type === AssetType.CSSUrl, id)),
- );
- await Promise.all(scriptQueue.map(({ content, type }) => this.loadScript(content, type === AssetType.JSUrl)));
- }
-
- private stylePoints = new Map();
-
- private loadStyle(content: string | undefined | null, level: AssetLevel, isUrl?: boolean, id?: string) {
- if (!content) {
- return;
- }
- let point: StylePoint | undefined;
- if (id) {
- point = this.stylePoints.get(id);
- if (!point) {
- point = new StylePoint(level, id);
- this.stylePoints.set(id, point);
- }
- } else {
- point = new StylePoint(level);
- }
- return isUrl ? point.applyUrl(content) : point.applyText(content);
- }
-
- private loadScript(content: string | undefined | null, isUrl?: boolean) {
- if (!content) {
- return;
- }
- return isUrl ? load(content) : evaluate(content);
- }
-}
-
-export default new AssetLoader();
diff --git a/packages/rax-simulator-renderer/src/utils/script.ts b/packages/rax-simulator-renderer/src/utils/script.ts
deleted file mode 100644
index 81841ff6d2..0000000000
--- a/packages/rax-simulator-renderer/src/utils/script.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { createDefer } from './create-defer';
-
-export function evaluate(script: string) {
- const scriptEl = document.createElement('script');
- scriptEl.text = script;
- document.head.appendChild(scriptEl);
- document.head.removeChild(scriptEl);
-}
-
-export function load(url: string) {
- const node: any = document.createElement('script');
-
- // node.setAttribute('crossorigin', 'anonymous');
-
- node.onload = onload;
- node.onerror = onload;
-
- const i = createDefer();
-
- function onload(e: any) {
- node.onload = null;
- node.onerror = null;
- if (e.type === 'load') {
- i.resolve();
- } else {
- i.reject();
- }
- // document.head.removeChild(node);
- // node = null;
- }
-
- // node.async = true;
- node.src = url;
-
- document.head.appendChild(node);
-
- return i.promise();
-}
-
-export function evaluateExpression(expr: string) {
- // eslint-disable-next-line no-new-func
- const fn = new Function(expr);
- return fn();
-}
-
-export function newFunction(args: string, code: string) {
- try {
- // eslint-disable-next-line no-new-func
- return new Function(args, code);
- } catch (e) {
- console.warn('Caught error, Cant init func');
- return null;
- }
-}
diff --git a/packages/rax-simulator-renderer/src/utils/style.ts b/packages/rax-simulator-renderer/src/utils/style.ts
deleted file mode 100644
index 91dbbc6345..0000000000
--- a/packages/rax-simulator-renderer/src/utils/style.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import { createDefer } from './create-defer';
-
-export default class StylePoint {
- private lastContent: string | undefined;
-
- private lastUrl: string | undefined;
-
- private placeholder: Element | Text;
-
- constructor(readonly level: number, readonly id?: string) {
- let placeholder: any;
- if (id) {
- placeholder = document.head.querySelector(`style[data-id="${id}"]`);
- }
- if (!placeholder) {
- placeholder = document.createTextNode('');
- const meta = document.head.querySelector(`meta[level="${level}"]`);
- if (meta) {
- document.head.insertBefore(placeholder, meta);
- } else {
- document.head.appendChild(placeholder);
- }
- }
- this.placeholder = placeholder;
- }
-
- applyText(content: string) {
- if (this.lastContent === content) {
- return;
- }
- this.lastContent = content;
- this.lastUrl = undefined;
- const element = document.createElement('style');
- element.setAttribute('type', 'text/css');
- if (this.id) {
- element.setAttribute('data-id', this.id);
- }
- element.appendChild(document.createTextNode(content));
- document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);
- document.head.removeChild(this.placeholder);
- this.placeholder = element;
- }
-
- applyUrl(url: string) {
- if (this.lastUrl === url) {
- return;
- }
- this.lastContent = undefined;
- this.lastUrl = url;
- const element = document.createElement('link');
- element.onload = onload;
- element.onerror = onload;
-
- const i = createDefer();
- function onload(e: any) {
- element.onload = null;
- element.onerror = null;
- if (e.type === 'load') {
- i.resolve();
- } else {
- i.reject();
- }
- }
-
- element.href = url;
- element.rel = 'stylesheet';
- if (this.id) {
- element.setAttribute('data-id', this.id);
- }
- document.head.insertBefore(element, this.placeholder.parentNode === document.head ? this.placeholder.nextSibling : null);
- document.head.removeChild(this.placeholder);
- this.placeholder = element;
- return i.promise();
- }
-}
diff --git a/packages/rax-simulator-renderer/src/utils/url.ts b/packages/rax-simulator-renderer/src/utils/url.ts
deleted file mode 100644
index d720323b3a..0000000000
--- a/packages/rax-simulator-renderer/src/utils/url.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Parse queryString
- * @param {String} str '?q=query&b=test'
- * @return {Object}
- */
-export function parseQuery(str: string): object {
- const ret: any = {};
-
- if (typeof str !== 'string') {
- return ret;
- }
-
- const s = str.trim().replace(/^(\?|#|&)/, '');
-
- if (!s) {
- return ret;
- }
-
- s.split('&').forEach((param) => {
- const parts = param.replace(/\+/g, ' ').split('=');
- let key = parts.shift()!;
- let val: any = parts.length > 0 ? parts.join('=') : undefined;
-
- key = decodeURIComponent(key);
-
- val = val === undefined ? null : decodeURIComponent(val);
-
- if (ret[key] === undefined) {
- ret[key] = val;
- } else if (Array.isArray(ret[key])) {
- ret[key].push(val);
- } else {
- ret[key] = [ret[key], val];
- }
- });
-
- return ret;
-}
-
-/**
- * Stringify object to query parammeters
- * @param {Object} obj
- * @return {String}
- */
-export function stringifyQuery(obj: any): string {
- const param: string[] = [];
- Object.keys(obj).forEach((key) => {
- let value = obj[key];
- if (value && typeof value === 'object') {
- value = JSON.stringify(value);
- }
- param.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
- });
- return param.join('&');
-}
-
-export function uriEncode(uri: string) {
- return encodeURIComponent(uri);
-}
-
-export function uriDecode(uri: string) {
- return decodeURIComponent(uri);
-}
-
-export function withQueryParams(url: string, params?: object) {
- const queryStr = params ? stringifyQuery(params) : '';
- if (queryStr === '') {
- return url;
- }
- const urlSplit = url.split('#');
- const hash = urlSplit[1] ? `#${urlSplit[1]}` : '';
- const urlWithoutHash = urlSplit[0];
- return `${urlWithoutHash}${~urlWithoutHash.indexOf('?') ? '&' : '?'}${queryStr}${hash}`;
-}
diff --git a/packages/react-renderer/build.json b/packages/react-renderer/build.json
index e791d5b6b3..d0aec10385 100644
--- a/packages/react-renderer/build.json
+++ b/packages/react-renderer/build.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"build-plugin-fusion",
["build-plugin-moment-locales", {
"locales": ["zh-cn"]
diff --git a/packages/react-renderer/build.test.json b/packages/react-renderer/build.test.json
index dcdc891e93..9cc30d7463 100644
--- a/packages/react-renderer/build.test.json
+++ b/packages/react-renderer/build.test.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}
diff --git a/packages/react-renderer/package.json b/packages/react-renderer/package.json
index 862f69d015..625801bc25 100644
--- a/packages/react-renderer/package.json
+++ b/packages/react-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-react-renderer",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "react renderer for ali lowcode engine",
"main": "lib/index.js",
"module": "es/index.js",
@@ -12,7 +12,7 @@
"scripts": {
"test": "build-scripts test --config build.test.json",
"start": "build-scripts start",
- "build": "build-scripts build --skip-demo",
+ "build": "build-scripts build",
"build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json"
},
"keywords": [
@@ -22,7 +22,7 @@
],
"dependencies": {
"@alifd/next": "^1.21.16",
- "@alilc/lowcode-renderer-core": "1.1.6"
+ "@alilc/lowcode-renderer-core": "1.3.2"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
@@ -41,6 +41,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/react-renderer"
},
- "homepage": "https://unpkg.alibaba-inc.com/@alilc/lowcode-react-renderer@1.0.21/build/index.html",
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme",
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues"
}
diff --git a/packages/react-simulator-renderer/build.json b/packages/react-simulator-renderer/build.json
index b95a17aafe..e7ae1dcf7a 100644
--- a/packages/react-simulator-renderer/build.json
+++ b/packages/react-simulator-renderer/build.json
@@ -1,3 +1,3 @@
{
- "plugins": ["build-plugin-component", "./build.plugin.js"]
+ "plugins": ["@alilc/build-plugin-lce", "./build.plugin.js"]
}
diff --git a/packages/react-simulator-renderer/build.test.json b/packages/react-simulator-renderer/build.test.json
index dcdc891e93..9cc30d7463 100644
--- a/packages/react-simulator-renderer/build.test.json
+++ b/packages/react-simulator-renderer/build.test.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}
diff --git a/packages/react-simulator-renderer/package.json b/packages/react-simulator-renderer/package.json
index fce8d866eb..3c3950a124 100644
--- a/packages/react-simulator-renderer/package.json
+++ b/packages/react-simulator-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-react-simulator-renderer",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "react simulator renderer for alibaba lowcode designer",
"main": "lib/index.js",
"module": "es/index.js",
@@ -12,15 +12,15 @@
],
"scripts": {
"test": "build-scripts test --config build.test.json",
- "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --skip-demo",
+ "build": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build",
"build:umd": "NODE_OPTIONS=--max_old_space_size=8192 build-scripts build --config build.umd.json",
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
},
"dependencies": {
- "@alilc/lowcode-designer": "1.1.6",
- "@alilc/lowcode-react-renderer": "1.1.6",
- "@alilc/lowcode-types": "1.1.6",
- "@alilc/lowcode-utils": "1.1.6",
+ "@alilc/lowcode-designer": "1.3.2",
+ "@alilc/lowcode-react-renderer": "1.3.2",
+ "@alilc/lowcode-types": "1.3.2",
+ "@alilc/lowcode-utils": "1.3.2",
"classnames": "^2.2.6",
"mobx": "^6.3.0",
"mobx-react": "^7.2.0",
@@ -43,5 +43,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/react-simulator-renderer"
},
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues",
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme"
}
diff --git a/packages/react-simulator-renderer/src/locale/index.ts b/packages/react-simulator-renderer/src/locale/index.ts
index e4b39a347c..5f4ef01505 100644
--- a/packages/react-simulator-renderer/src/locale/index.ts
+++ b/packages/react-simulator-renderer/src/locale/index.ts
@@ -9,10 +9,10 @@ const instance: Record> = {
export function createIntl(locale: string = 'zh-CN') {
const intl = (id: string) => {
- return instance[locale][id];
+ return instance[locale]?.[id] || id;
};
- const intlNode = (id: string) => createElement('span', instance[locale][id]);
+ const intlNode = (id: string) => createElement('span', instance[locale]?.[id] || id);
return {
intl,
diff --git a/packages/react-simulator-renderer/src/renderer.ts b/packages/react-simulator-renderer/src/renderer.ts
index efebeda040..20f6e18c0b 100644
--- a/packages/react-simulator-renderer/src/renderer.ts
+++ b/packages/react-simulator-renderer/src/renderer.ts
@@ -614,7 +614,7 @@ function getNodeInstance(fiberNode: any, specId?: string): IPublicTypeNodeInstan
function checkInstanceMounted(instance: any): boolean {
if (isElement(instance)) {
- return instance.parentElement != null;
+ return instance.parentElement != null && window.document.contains(instance);
}
return true;
}
diff --git a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap
index 0ebb606dac..2f2d19f269 100644
--- a/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap
+++ b/packages/react-simulator-renderer/test/src/renderer/__snapshots__/demo.test.tsx.snap
@@ -31,6 +31,7 @@ exports[`Base should be render Text 1`] = `
behavior="NORMAL"
componentId="node_ockvuu8u916"
fieldId="text_kvuu9gl2"
+ forwardRef={[Function]}
maxLine={0}
showTitle={false}
>
diff --git a/packages/rax-simulator-renderer/babel.config.js b/packages/renderer-core/babel.config.js
similarity index 100%
rename from packages/rax-simulator-renderer/babel.config.js
rename to packages/renderer-core/babel.config.js
diff --git a/packages/renderer-core/build.json b/packages/renderer-core/build.json
index a8e42f1540..9140815c5e 100644
--- a/packages/renderer-core/build.json
+++ b/packages/renderer-core/build.json
@@ -1,7 +1,7 @@
{
"plugins": [
[
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
{
"babelPlugins": ["@babel/plugin-transform-typescript"]
}
diff --git a/packages/renderer-core/build.test.json b/packages/renderer-core/build.test.json
index dcdc891e93..9cc30d7463 100644
--- a/packages/renderer-core/build.test.json
+++ b/packages/renderer-core/build.test.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}
diff --git a/packages/renderer-core/jest.config.js b/packages/renderer-core/jest.config.js
index 652a76e708..1ea4204de5 100644
--- a/packages/renderer-core/jest.config.js
+++ b/packages/renderer-core/jest.config.js
@@ -11,6 +11,9 @@ const jestConfig = {
// },
// testMatch: ['(/tests?/.*(test))\\.[jt]s$'],
// testMatch: ['**/*/base.test.tsx'],
+ // testMatch: ['**/utils/common.test.ts'],
+ // testMatch: ['**/*/leaf.test.tsx'],
+ // testMatch: ['**/*/is-use-loop.test.ts'],
transformIgnorePatterns: [
`/node_modules/(?!${esModules})/`,
],
diff --git a/packages/renderer-core/package.json b/packages/renderer-core/package.json
index 84a63aa9a2..199eac1cac 100644
--- a/packages/renderer-core/package.json
+++ b/packages/renderer-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-renderer-core",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "renderer core",
"license": "MIT",
"main": "lib/index.js",
@@ -10,14 +10,14 @@
"es"
],
"scripts": {
- "build": "build-scripts build --skip-demo",
+ "build": "build-scripts build",
"test": "build-scripts test --config build.test.json",
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
},
"dependencies": {
"@alilc/lowcode-datasource-engine": "^1.0.0",
- "@alilc/lowcode-types": "1.1.6",
- "@alilc/lowcode-utils": "1.1.6",
+ "@alilc/lowcode-types": "1.3.2",
+ "@alilc/lowcode-utils": "1.3.2",
"classnames": "^2.2.6",
"debug": "^4.1.1",
"fetch-jsonp": "^1.1.3",
@@ -32,7 +32,7 @@
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
"@alifd/next": "^1.26.0",
- "@alilc/lowcode-designer": "1.1.6",
+ "@alilc/lowcode-designer": "1.3.2",
"@babel/plugin-transform-typescript": "^7.16.8",
"@testing-library/react": "^11.2.2",
"@types/classnames": "^2.2.11",
@@ -55,5 +55,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/renderer-core"
},
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues",
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme"
}
diff --git a/packages/renderer-core/src/adapter/index.ts b/packages/renderer-core/src/adapter/index.ts
index 12896b1372..7a56bc039e 100644
--- a/packages/renderer-core/src/adapter/index.ts
+++ b/packages/renderer-core/src/adapter/index.ts
@@ -2,7 +2,6 @@ import { IRuntime, IRendererModules, IGeneralConstructor } from '../types';
export enum Env {
React = 'react',
- Rax = 'rax',
}
class Adapter {
@@ -22,22 +21,22 @@ class Adapter {
initRuntime() {
const Component: IGeneralConstructor = class {
- setState() {}
- forceUpdate() {}
- render() {}
state: Readonly;
props: Readonly & Readonly<{ children?: any | undefined }>;
refs: Record;
context: Record;
- };
- const PureComponent = class {
setState() {}
forceUpdate() {}
render() {}
+ };
+ const PureComponent = class {
state: Readonly;
props: Readonly & Readonly<{ children?: any | undefined }>;
refs: Record;
context: Record;
+ setState() {}
+ forceUpdate() {}
+ render() {}
};
const createElement = () => {};
const createContext = () => {};
@@ -85,10 +84,6 @@ class Adapter {
return this.env === Env.React;
}
- isRax() {
- return this.env === Env.Rax;
- }
-
setRenderers(renderers: IRendererModules) {
this.renderers = renderers;
}
diff --git a/packages/renderer-core/src/hoc/index.tsx b/packages/renderer-core/src/hoc/index.tsx
index a9314060f3..4851ea486f 100644
--- a/packages/renderer-core/src/hoc/index.tsx
+++ b/packages/renderer-core/src/hoc/index.tsx
@@ -1,20 +1,88 @@
import { cloneEnumerableProperty } from '@alilc/lowcode-utils';
import adapter from '../adapter';
+import { IBaseRendererInstance, IRendererProps } from '../types';
-export function compWrapper(Comp: any) {
+interface Options {
+ baseRenderer: IBaseRendererInstance;
+ schema: any;
+}
+
+function patchDidCatch(Comp: any, { baseRenderer }: Options) {
+ if (Comp.patchedCatch) {
+ return;
+ }
+ Comp.patchedCatch = true;
+ const { PureComponent } = adapter.getRuntime();
+ // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代
+ // @see https://github.com/alibaba/rax/issues/2211
+ const originalDidCatch = Comp.prototype.componentDidCatch;
+ Comp.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) {
+ this.setState({ engineRenderError: true, error });
+ if (originalDidCatch && typeof originalDidCatch === 'function') {
+ originalDidCatch.call(this, error, errorInfo);
+ }
+ };
+
+ const { engine } = baseRenderer.context;
+ const originRender = Comp.prototype.render;
+ Comp.prototype.render = function () {
+ if (this.state && this.state.engineRenderError) {
+ this.state.engineRenderError = false;
+ return engine.createElement(engine.getFaultComponent(), {
+ ...this.props,
+ error: this.state.error,
+ componentName: this.props._componentName,
+ });
+ }
+ return originRender.call(this);
+ };
+ if (!(Comp.prototype instanceof PureComponent)) {
+ const originShouldComponentUpdate = Comp.prototype.shouldComponentUpdate;
+ Comp.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) {
+ if (nextState && nextState.engineRenderError) {
+ return true;
+ }
+ return originShouldComponentUpdate
+ ? originShouldComponentUpdate.call(this, nextProps, nextState)
+ : true;
+ };
+ }
+}
+
+const cache = new Map();
+
+export function compWrapper(Comp: any, options: Options) {
const { createElement, Component, forwardRef } = adapter.getRuntime();
- class Wrapper extends Component {
- // constructor(props: any, context: any) {
- // super(props, context);
- // }
+ if (
+ Comp?.prototype?.isReactComponent || // react
+ Comp?.prototype?.setState || // rax
+ Comp?.prototype instanceof Component
+ ) {
+ patchDidCatch(Comp, options);
+ return Comp;
+ }
+
+ if (cache.has(options.schema.id) && cache.get(options.schema.id)?.Comp === Comp) {
+ return cache.get(options.schema.id)?.WrapperComponent;
+ }
+ class Wrapper extends Component {
render() {
- return createElement(Comp, this.props);
+ return createElement(Comp, { ...this.props, ref: this.props.forwardRef });
}
}
(Wrapper as any).displayName = Comp.displayName;
- return cloneEnumerableProperty(forwardRef((props: any, ref: any) => {
- return createElement(Wrapper, { ...props, forwardRef: ref });
- }), Comp);
+ patchDidCatch(Wrapper, options);
+
+ const WrapperComponent = cloneEnumerableProperty(
+ forwardRef((props: any, ref: any) => {
+ return createElement(Wrapper, { ...props, forwardRef: ref });
+ }),
+ Comp,
+ );
+
+ cache.set(options.schema.id, { WrapperComponent, Comp });
+
+ return WrapperComponent;
}
diff --git a/packages/renderer-core/src/hoc/leaf.tsx b/packages/renderer-core/src/hoc/leaf.tsx
index 5df9880485..2bb3c0b368 100644
--- a/packages/renderer-core/src/hoc/leaf.tsx
+++ b/packages/renderer-core/src/hoc/leaf.tsx
@@ -4,6 +4,7 @@ import { isReactComponent, cloneEnumerableProperty } from '@alilc/lowcode-utils'
import { debounce } from '../utils/common';
import adapter from '../adapter';
import * as types from '../types/index';
+import logger from '../utils/logger';
export interface IComponentHocInfo {
schema: any;
@@ -102,6 +103,9 @@ function initRerenderEvent({
return;
}
cache.event.get(schema.id)?.dispose.forEach((disposeFn: any) => disposeFn && disposeFn());
+ const debounceRerender = debounce(() => {
+ container.rerender();
+ }, 20);
cache.event.set(schema.id, {
clear: false,
leaf,
@@ -111,21 +115,21 @@ function initRerenderEvent({
return;
}
__debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onPropsChange make rerender`);
- container.rerender();
+ debounceRerender();
}),
leaf?.onChildrenChange?.(() => {
if (!container.autoRepaintNode) {
return;
}
__debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onChildrenChange make rerender`);
- container.rerender();
+ debounceRerender();
}) as Function,
leaf?.onVisibleChange?.(() => {
if (!container.autoRepaintNode) {
return;
}
__debug(`${schema.componentName}[${schema.id}] leaf not render in SimulatorRendererView, leaf onVisibleChange make rerender`);
- container.rerender();
+ debounceRerender();
}),
],
});
@@ -180,7 +184,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
}
if (!isReactComponent(Comp)) {
- console.error(`${schema.componentName} component may be has errors: `, Comp);
+ logger.error(`${schema.componentName} component may be has errors: `, Comp);
}
initRerenderEvent({
@@ -190,8 +194,8 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
getNode,
});
- if (curDocumentId && cache.component.has(componentCacheId)) {
- return cache.component.get(componentCacheId);
+ if (curDocumentId && cache.component.has(componentCacheId) && (cache.component.get(componentCacheId).Comp === Comp)) {
+ return cache.component.get(componentCacheId).LeafWrapper;
}
class LeafHoc extends Component {
@@ -518,16 +522,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
}
get hasChildren(): boolean {
- let { children } = this.props;
- if (this.state.childrenInState) {
- children = this.state.nodeChildren;
- }
-
- if (Array.isArray(children)) {
- return Boolean(children && children.length);
+ if (!this.state.childrenInState) {
+ return 'children' in this.props;
}
- return Boolean(children);
+ return true;
}
get children(): any {
@@ -540,7 +539,7 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
if (this.props.children && this.props.children.length) {
return this.props.children;
}
- return [];
+ return this.props.children;
}
get leaf(): INode | undefined {
@@ -573,7 +572,11 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
delete compProps.__inner__;
- return engine.createElement(Comp, compProps, this.hasChildren ? this.children : null);
+ if (this.hasChildren) {
+ return engine.createElement(Comp, compProps, this.children);
+ }
+
+ return engine.createElement(Comp, compProps);
}
}
@@ -588,7 +591,10 @@ export function leafWrapper(Comp: types.IBaseRenderComponent, {
LeafWrapper.displayName = (Comp as any).displayName;
- cache.component.set(componentCacheId, LeafWrapper);
+ cache.component.set(componentCacheId, {
+ LeafWrapper,
+ Comp,
+ });
return LeafWrapper;
}
\ No newline at end of file
diff --git a/packages/renderer-core/src/renderer/addon.tsx b/packages/renderer-core/src/renderer/addon.tsx
index 9cb114bee4..211ec182f2 100644
--- a/packages/renderer-core/src/renderer/addon.tsx
+++ b/packages/renderer-core/src/renderer/addon.tsx
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import baseRendererFactory from './base';
import { isEmpty } from '../utils';
import { IRendererAppHelper, IBaseRendererProps, IBaseRenderComponent } from '../types';
+import logger from '../utils/logger';
export default function addonRendererFactory(): IBaseRenderComponent {
const BaseRenderer = baseRendererFactory();
@@ -32,7 +33,7 @@ export default function addonRendererFactory(): IBaseRenderComponent {
const schema = props.__schema || {};
this.state = this.__parseData(schema.state || {});
if (isEmpty(props.config) || !props.config?.addonKey) {
- console.warn('lce addon has wrong config');
+ logger.warn('lce addon has wrong config');
this.setState({
__hasError: true,
});
diff --git a/packages/renderer-core/src/renderer/base.tsx b/packages/renderer-core/src/renderer/base.tsx
index 56f58599b0..d240095604 100644
--- a/packages/renderer-core/src/renderer/base.tsx
+++ b/packages/renderer-core/src/renderer/base.tsx
@@ -4,7 +4,7 @@
import classnames from 'classnames';
import { create as createDataSourceEngine } from '@alilc/lowcode-datasource-engine/interpret';
import { IPublicTypeNodeSchema, IPublicTypeNodeData, IPublicTypeJSONValue, IPublicTypeCompositeValue } from '@alilc/lowcode-types';
-import { isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils';
+import { checkPropTypes, isI18nData, isJSExpression, isJSFunction } from '@alilc/lowcode-utils';
import adapter from '../adapter';
import divFactory from '../components/Div';
import visualDomFactory from '../components/VisualDom';
@@ -21,9 +21,7 @@ import {
isFileSchema,
transformArrayToMap,
transformStringToFunction,
- checkPropTypes,
getI18n,
- canAcceptsRef,
getFileCssName,
capitalizeFirstLetter,
DataHelper,
@@ -57,14 +55,14 @@ export function executeLifeCycleMethod(context: any, schema: IPublicTypeNodeSche
}
if (typeof fn !== 'function') {
- console.error(`生命周期${method}类型不符`, fn);
+ logger.error(`生命周期${method}类型不符`, fn);
return;
}
try {
return fn.apply(context, args);
} catch (e) {
- console.error(`[${schema.componentName}]生命周期${method}出错`, e);
+ logger.error(`[${schema.componentName}]生命周期${method}出错`, e);
}
}
@@ -131,7 +129,6 @@ export default function baseRendererFactory(): IBaseRenderComponent {
static contextType = AppContext;
- appHelper?: IRendererAppHelper;
i18n: any;
getLocale: any;
setLocale: any;
@@ -174,7 +171,6 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__beforeInit(_props: IBaseRendererProps) { }
__init(props: IBaseRendererProps) {
- this.appHelper = props.__appHelper;
this.__compScopes = {};
this.__instanceMap = {};
this.__bindCustomMethods(props);
@@ -185,7 +181,8 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__afterInit(_props: IBaseRendererProps) { }
static getDerivedStateFromProps(props: IBaseRendererProps, state: any) {
- return executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE);
+ const result = executeLifeCycleMethod(this, props?.__schema, 'getDerivedStateFromProps', [props, state], props.thisRequiredInJSE);
+ return result === undefined ? null : result;
}
async getSnapshotBeforeUpdate(...args: any[]) {
@@ -211,7 +208,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
async componentDidCatch(...args: any[]) {
this.__executeLifeCycleMethod('componentDidCatch', args);
- console.warn(args);
+ logger.warn(args);
}
reloadDataSource = () => new Promise((resolve, reject) => {
@@ -281,7 +278,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
value = this.__parseExpression(value, this);
}
if (typeof value !== 'function') {
- console.error(`custom method ${key} can not be parsed to a valid function`, value);
+ logger.error(`custom method ${key} can not be parsed to a valid function`, value);
return;
}
this[key] = value.bind(this);
@@ -372,7 +369,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
this.setLocale = (loc: string) => {
const setLocaleFn = this.appHelper?.utils?.i18n?.setLocale;
if (!setLocaleFn || typeof setLocaleFn !== 'function') {
- console.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists');
+ logger.warn('initI18nAPIs Failed, i18n only works when appHelper.utils.i18n.setLocale() exists');
return undefined;
}
return setLocaleFn(loc);
@@ -431,7 +428,14 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__createDom = () => {
const { __schema, __ctx, __components = {} } = this.props;
- const scope: any = {};
+ // merge defaultProps
+ const scopeProps = {
+ ...__schema.defaultProps,
+ ...this.props,
+ };
+ const scope: any = {
+ props: scopeProps,
+ };
scope.__proto__ = __ctx || this;
const _children = getSchemaChildren(__schema);
@@ -455,7 +459,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
* @param idx 为循环渲染的循环Index
*/
__createVirtualDom = (originalSchema: IPublicTypeNodeData | IPublicTypeNodeData[] | undefined, originalScope: any, parentInfo: INodeInfo, idx: string | number = ''): any => {
- if (!originalSchema) {
+ if (originalSchema === null || originalSchema === undefined) {
return null;
}
let scope = originalScope;
@@ -493,6 +497,11 @@ export default function baseRendererFactory(): IBaseRenderComponent {
return schema.map((item, idy) => this.__createVirtualDom(item, scope, parentInfo, (item as IPublicTypeNodeSchema)?.__ctx?.lceKey ? '' : String(idy)));
}
+ // @ts-expect-error 如果直接转换好了,可以返回
+ if (schema.$$typeof) {
+ return schema;
+ }
+
const _children = getSchemaChildren(schema);
if (!schema.componentName) {
logger.error('The componentName in the schema is invalid, please check the schema: ', schema);
@@ -510,11 +519,6 @@ export default function baseRendererFactory(): IBaseRenderComponent {
schema.children = [text];
}
- // @ts-expect-error 如果直接转换好了,可以返回
- if (schema.$$typeof) {
- return schema;
- }
-
if (!isSchema(schema)) {
return null;
}
@@ -530,7 +534,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
: {};
if (!Comp) {
- console.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components);
+ logger.error(`${schema.componentName} component is not found in components list! component list is:`, components || this.props.__container?.components);
return engine.createElement(
engine.getNotFoundComponent(),
{
@@ -547,6 +551,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
if (schema.loop != null) {
const loop = this.__parseData(schema.loop, scope);
+ if (Array.isArray(loop) && loop.length === 0) return null;
const useLoop = isUseLoop(loop, this.__designModeIsDesign);
if (useLoop) {
return this.__createLoopVirtualDom(
@@ -617,12 +622,6 @@ export default function baseRendererFactory(): IBaseRenderComponent {
});
});
- // 对于不可以接收到 ref 的组件需要做特殊处理
- if (!canAcceptsRef(Comp)) {
- Comp = compWrapper(Comp);
- components[schema.componentName] = Comp;
- }
-
otherProps.ref = (ref: any) => {
this.$(props.fieldId || props.ref, ref); // 收集ref
const refProps = props.ref;
@@ -651,7 +650,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
props.key = props.__id;
}
- let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp);
+ let child = this.__getSchemaChildrenVirtualDom(schema, scope, Comp, condition);
const renderComp = (innerProps: any) => engine.createElement(Comp, innerProps, child);
// 设计模式下的特殊处理
if (engine && [DESIGN_MODE.EXTEND, DESIGN_MODE.BORDER].includes(engine.props.designMode)) {
@@ -706,13 +705,13 @@ export default function baseRendererFactory(): IBaseRenderComponent {
*/
get __componentHOCs(): IComponentConstruct[] {
if (this.__designModeIsDesign) {
- return [leafWrapper];
+ return [leafWrapper, compWrapper];
}
- return [];
+ return [compWrapper];
}
- __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any) => {
- let children = getSchemaChildren(schema);
+ __getSchemaChildrenVirtualDom = (schema: IPublicTypeNodeSchema | undefined, scope: any, Comp: any, condition = true) => {
+ let children = condition ? getSchemaChildren(schema) : null;
// @todo 补完这里的 Element 定义 @承虎
let result: any = [];
@@ -757,7 +756,7 @@ export default function baseRendererFactory(): IBaseRenderComponent {
__createLoopVirtualDom = (schema: IPublicTypeNodeSchema, scope: any, parentInfo: INodeInfo, idx: number | string) => {
if (isFileSchema(schema)) {
- console.warn('file type not support Loop');
+ logger.warn('file type not support Loop');
return null;
}
if (!Array.isArray(schema.loop)) {
@@ -909,9 +908,6 @@ export default function baseRendererFactory(): IBaseRenderComponent {
});
return checkProps(res);
}
- if (typeof props === 'string') {
- return checkProps(props.trim());
- }
return checkProps(props);
};
@@ -1019,6 +1015,10 @@ export default function baseRendererFactory(): IBaseRenderComponent {
return !isSchema(schema) || !componentNames.includes(schema?.componentName ?? '');
};
+ get appHelper(): IRendererAppHelper {
+ return this.props.__appHelper;
+ }
+
get requestHandlersMap() {
return this.appHelper?.requestHandlersMap;
}
diff --git a/packages/renderer-core/src/renderer/component.tsx b/packages/renderer-core/src/renderer/component.tsx
index 4be33f5c19..3dfc1df33f 100644
--- a/packages/renderer-core/src/renderer/component.tsx
+++ b/packages/renderer-core/src/renderer/component.tsx
@@ -46,12 +46,5 @@ export default function componentRendererFactory(): IBaseRenderComponent {
return this.__renderComp(Component, this.__renderContextProvider({ compContext: this }));
}
-
- /** 需要重载下面几个方法,如果在低代码组件中绑定了对应的生命周期时会出现死循环 */
- componentDidMount() {}
- getSnapshotBeforeUpdate() {}
- componentDidUpdate() {}
- componentWillUnmount() {}
- componentDidCatch() {}
};
}
diff --git a/packages/renderer-core/src/renderer/page.tsx b/packages/renderer-core/src/renderer/page.tsx
index 9ba49c7233..16d55e01be 100644
--- a/packages/renderer-core/src/renderer/page.tsx
+++ b/packages/renderer-core/src/renderer/page.tsx
@@ -1,6 +1,9 @@
+import { getLogger } from '@alilc/lowcode-utils';
import baseRendererFactory from './base';
import { IBaseRendererProps, IBaseRenderComponent } from '../types';
+const logger = getLogger({ level: 'warn', bizName: 'renderer-core:page' });
+
export default function pageRendererFactory(): IBaseRenderComponent {
const BaseRenderer = baseRendererFactory();
return class PageRenderer extends BaseRenderer {
@@ -29,6 +32,11 @@ export default function pageRendererFactory(): IBaseRenderComponent {
super.componentDidUpdate?.(prevProps, _prevState, snapshot);
}
+ setState(state: any, callback?: () => void) {
+ logger.info('page set state', state);
+ super.setState(state, callback);
+ }
+
render() {
const { __schema, __components } = this.props;
if (this.__checkSchema(__schema)) {
diff --git a/packages/renderer-core/src/renderer/renderer.tsx b/packages/renderer-core/src/renderer/renderer.tsx
index 88cc0ce025..300b1cd164 100644
--- a/packages/renderer-core/src/renderer/renderer.tsx
+++ b/packages/renderer-core/src/renderer/renderer.tsx
@@ -105,52 +105,7 @@ export default function rendererFactory(): IRenderComponent {
return SetComponent;
}
- patchDidCatch(SetComponent: any) {
- if (!this.isValidComponent(SetComponent)) {
- return;
- }
- if (SetComponent.patchedCatch) {
- return;
- }
- if (!SetComponent.prototype) {
- return;
- }
- SetComponent.patchedCatch = true;
-
- // Rax 的 getDerivedStateFromError 有 BUG,这里先用 componentDidCatch 来替代
- // @see https://github.com/alibaba/rax/issues/2211
- const originalDidCatch = SetComponent.prototype.componentDidCatch;
- SetComponent.prototype.componentDidCatch = function didCatch(this: any, error: Error, errorInfo: any) {
- this.setState({ engineRenderError: true, error });
- if (originalDidCatch && typeof originalDidCatch === 'function') {
- originalDidCatch.call(this, error, errorInfo);
- }
- };
-
- const engine = this;
- const originRender = SetComponent.prototype.render;
- SetComponent.prototype.render = function () {
- if (this.state && this.state.engineRenderError) {
- this.state.engineRenderError = false;
- return engine.createElement(engine.getFaultComponent(), {
- ...this.props,
- error: this.state.error,
- });
- }
- return originRender.call(this);
- };
- const originShouldComponentUpdate = SetComponent.prototype.shouldComponentUpdate;
- SetComponent.prototype.shouldComponentUpdate = function (nextProps: IRendererProps, nextState: any) {
- if (nextState && nextState.engineRenderError) {
- return true;
- }
- return originShouldComponentUpdate ? originShouldComponentUpdate.call(this, nextProps, nextState) : true;
- };
- }
-
createElement(SetComponent: any, props: any, children?: any) {
- // TODO: enable in runtime mode?
- this.patchDidCatch(SetComponent);
return (this.props.customCreateElement || createElement)(SetComponent, props, children);
}
diff --git a/packages/renderer-core/src/renderer/temp.tsx b/packages/renderer-core/src/renderer/temp.tsx
index 83adef7e30..1432da5fd2 100644
--- a/packages/renderer-core/src/renderer/temp.tsx
+++ b/packages/renderer-core/src/renderer/temp.tsx
@@ -1,4 +1,5 @@
import { IBaseRenderComponent } from '../types';
+import logger from '../utils/logger';
import baseRendererFactory from './base';
export default function tempRendererFactory(): IBaseRenderComponent {
@@ -41,7 +42,7 @@ export default function tempRendererFactory(): IBaseRenderComponent {
}
async componentDidCatch(e: any) {
- console.warn(e);
+ logger.warn(e);
this.__debug(`componentDidCatch - ${this.props.__schema.fileName}`);
}
diff --git a/packages/renderer-core/src/types/index.ts b/packages/renderer-core/src/types/index.ts
index a49fe89920..afbec272ab 100644
--- a/packages/renderer-core/src/types/index.ts
+++ b/packages/renderer-core/src/types/index.ts
@@ -335,7 +335,6 @@ export interface IRenderComponent {
componentDidCatch(e: any): Promise | void;
shouldComponentUpdate(nextProps: IRendererProps): boolean;
isValidComponent(SetComponent: any): any;
- patchDidCatch(SetComponent: any): void;
createElement(SetComponent: any, props: any, children?: any): any;
getNotFoundComponent(): any;
getFaultComponent(): any;
diff --git a/packages/renderer-core/src/utils/common.ts b/packages/renderer-core/src/utils/common.ts
index 29381b5473..0462d358a7 100644
--- a/packages/renderer-core/src/utils/common.ts
+++ b/packages/renderer-core/src/utils/common.ts
@@ -6,16 +6,11 @@ import { isI18nData, isJSExpression } from '@alilc/lowcode-utils';
import { isEmpty } from 'lodash';
import IntlMessageFormat from 'intl-messageformat';
import pkg from '../../package.json';
-import * as ReactIs from 'react-is';
-import { default as ReactPropTypesSecret } from 'prop-types/lib/ReactPropTypesSecret';
-import { default as factoryWithTypeCheckers } from 'prop-types/factoryWithTypeCheckers';
(window as any).sdkVersion = pkg.version;
export { pick, isEqualWith as deepEqual, cloneDeep as clone, isEmpty, throttle, debounce } from 'lodash';
-const PropTypes2 = factoryWithTypeCheckers(ReactIs.isElement, true);
-
const EXPRESSION_TYPE = {
JSEXPRESSION: 'JSExpression',
JSFUNCTION: 'JSFunction',
@@ -183,31 +178,6 @@ export function transformArrayToMap(arr: any[], key: string, overwrite = true) {
return res;
}
-export function checkPropTypes(value: any, name: string, rule: any, componentName: string) {
- let ruleFunction = rule;
- if (typeof rule === 'string') {
- ruleFunction = new Function(`"use strict"; const PropTypes = arguments[0]; return ${rule}`)(PropTypes2);
- }
- if (!ruleFunction || typeof ruleFunction !== 'function') {
- console.warn('checkPropTypes should have a function type rule argument');
- return true;
- }
- const err = ruleFunction(
- {
- [name]: value,
- },
- name,
- componentName,
- 'prop',
- null,
- ReactPropTypesSecret,
- );
- if (err) {
- console.warn(err);
- }
- return !err;
-}
-
/**
* transform string to a function
* @param str function in string form
diff --git a/packages/renderer-core/src/utils/data-helper.ts b/packages/renderer-core/src/utils/data-helper.ts
index d884c13c97..41bcb9bfa0 100644
--- a/packages/renderer-core/src/utils/data-helper.ts
+++ b/packages/renderer-core/src/utils/data-helper.ts
@@ -186,7 +186,7 @@ export class DataHelper {
}
const { headers, ...otherProps } = otherOptionsObj || {};
if (!req) {
- console.warn(`getDataSource API named ${id} not exist`);
+ logger.warn(`getDataSource API named ${id} not exist`);
return;
}
@@ -215,7 +215,7 @@ export class DataHelper {
try {
callbackFn && callbackFn(res && res[id]);
} catch (e) {
- console.error('load请求回调函数报错', e);
+ logger.error('load请求回调函数报错', e);
}
return res && res[id];
})
@@ -223,7 +223,7 @@ export class DataHelper {
try {
callbackFn && callbackFn(null, err);
} catch (e) {
- console.error('load请求回调函数报错', e);
+ logger.error('load请求回调函数报错', e);
}
return err;
});
@@ -300,9 +300,9 @@ export class DataHelper {
return dataHandlerFun.call(this.host, data, error);
} catch (e) {
if (id) {
- console.error(`[${id}]单个请求数据处理函数运行出错`, e);
+ logger.error(`[${id}]单个请求数据处理函数运行出错`, e);
} else {
- console.error('请求数据处理函数运行出错', e);
+ logger.error('请求数据处理函数运行出错', e);
}
}
}
diff --git a/packages/renderer-core/src/utils/is-use-loop.ts b/packages/renderer-core/src/utils/is-use-loop.ts
index 509450d942..b6d67a802a 100644
--- a/packages/renderer-core/src/utils/is-use-loop.ts
+++ b/packages/renderer-core/src/utils/is-use-loop.ts
@@ -8,13 +8,13 @@ export default function isUseLoop(loop: null | any[] | IPublicTypeJSExpression,
return true;
}
- if (!Array.isArray(loop)) {
- return false;
- }
-
if (!isDesignMode) {
return true;
}
+ if (!Array.isArray(loop)) {
+ return false;
+ }
+
return loop.length > 0;
}
diff --git a/packages/renderer-core/tests/adapter/adapter.test.ts b/packages/renderer-core/tests/adapter/adapter.test.ts
index a838602fbe..57d92d1d42 100644
--- a/packages/renderer-core/tests/adapter/adapter.test.ts
+++ b/packages/renderer-core/tests/adapter/adapter.test.ts
@@ -79,15 +79,10 @@ describe('test src/adapter ', () => {
});
- it('setEnv/.env/isReact/isRax works', () => {
+ it('setEnv/.env/isReact works', () => {
adapter.setEnv(Env.React);
expect(adapter.env).toBe(Env.React);
expect(adapter.isReact()).toBeTruthy();
- expect(adapter.isRax()).toBeFalsy();
- adapter.setEnv(Env.Rax);
- expect(adapter.env).toBe(Env.Rax);
- expect(adapter.isRax()).toBeTruthy();
- expect(adapter.isReact()).toBeFalsy();
});
it('setRenderers/getRenderers works', () => {
diff --git a/packages/renderer-core/tests/hoc/leaf.test.tsx b/packages/renderer-core/tests/hoc/leaf.test.tsx
index 94d50f87a9..c21a10be92 100644
--- a/packages/renderer-core/tests/hoc/leaf.test.tsx
+++ b/packages/renderer-core/tests/hoc/leaf.test.tsx
@@ -83,7 +83,6 @@ beforeEach(() => {
});
component = renderer.create(
- // @ts-ignore
@@ -238,7 +237,6 @@ describe('mini unit render', () => {
nodeMap.set(textSchema.id, TextNode);
component = renderer.create(
- // @ts-ignore
@@ -285,7 +283,6 @@ describe('mini unit render', () => {
nodeMap.set(textSchema.id, TextNode);
renderer.create(
- // @ts-ignore
@@ -309,7 +306,6 @@ describe('mini unit render', () => {
});
renderer.create(
- // @ts-ignore
@@ -388,7 +384,6 @@ describe('mini unit render', () => {
};
const component = renderer.create(
- // @ts-ignore
@@ -428,7 +423,6 @@ describe('mini unit render', () => {
nodeMap.set(miniRenderSchema.id, MiniRenderDivNode);
component = renderer.create(
- // @ts-ignore
@@ -491,7 +485,6 @@ describe('onVisibleChange', () => {
describe('children', () => {
it('this.props.children is array', () => {
const component = renderer.create(
- // @ts-ignore
@@ -511,6 +504,41 @@ describe('onChildrenChange', () => {
DivNode.emitChildrenChange();
makeSnapshot(component);
});
+
+ it('children is 0', () => {
+ DivNode.schema.children = 0
+ DivNode.emitChildrenChange();
+ const componentInstance = component.root;
+ expect(componentInstance.findByType(components.Div).props.children).toEqual(0);
+ });
+
+ it('children is false', () => {
+ DivNode.schema.children = false
+ DivNode.emitChildrenChange();
+ const componentInstance = component.root;
+ expect(componentInstance.findByType(components.Div).props.children).toEqual(false);
+ });
+
+ it('children is []', () => {
+ DivNode.schema.children = []
+ DivNode.emitChildrenChange();
+ const componentInstance = component.root;
+ expect(componentInstance.findByType(components.Div).props.children).toEqual([]);
+ });
+
+ it('children is null', () => {
+ DivNode.schema.children = null
+ DivNode.emitChildrenChange();
+ const componentInstance = component.root;
+ expect(componentInstance.findByType(components.Div).props.children).toEqual(null);
+ });
+
+ it('children is undefined', () => {
+ DivNode.schema.children = undefined;
+ DivNode.emitChildrenChange();
+ const componentInstance = component.root;
+ expect(componentInstance.findByType(components.Div).props.children).toEqual(undefined);
+ });
});
describe('not render leaf', () => {
diff --git a/packages/renderer-core/tests/renderer/base.test.tsx b/packages/renderer-core/tests/renderer/base.test.tsx
index 63c5cfbb2e..3faa2bcf44 100644
--- a/packages/renderer-core/tests/renderer/base.test.tsx
+++ b/packages/renderer-core/tests/renderer/base.test.tsx
@@ -79,7 +79,6 @@ describe('Base Render methods', () => {
// const originalUtils = jest.requireActual('../../src/utils');
// mockParseExpression.mockImplementation(originalUtils.parseExpression);
const component = TestRenderer.create(
- // @ts-ignore
{
return new Promise((resolve, reject) => {
const component = renderer.create(
- // @ts-ignore
{
describe('Base Render', () => {
it('renderComp', () => {
const content = (
- // @ts-ignore
{
describe('test forEach ', () => {
it('should work', () => {
const mockFn = jest.fn();
-
+
forEach(null, mockFn);
expect(mockFn).toBeCalledTimes(0);
@@ -293,7 +292,7 @@ describe('test forEach ', () => {
forEach({ a: 1, b: 2, c: 3 }, mockFn);
expect(mockFn).toBeCalledTimes(3);
-
+
const mockFn2 = jest.fn();
forEach({ a: 1 }, mockFn2, { b: 'bbb' });
expect(mockFn2).toHaveBeenCalledWith(1, 'a');
@@ -374,7 +373,7 @@ describe('test parseThisRequiredExpression', () => {
};
const fn = logger.error = jest.fn();
parseThisRequiredExpression(mockExpression, { state: { text: 'text' } });
- expect(fn).toBeCalledWith('parseExpression.error', new ReferenceError('state is not defined'), {"type": "JSExpression", "value": "state.text"}, {"state": {"text": "text"}});
+ expect(fn).toBeCalledWith(' parseExpression.error', new ReferenceError('state is not defined'), {"type": "JSExpression", "value": "state.text"}, {"state": {"text": "text"}});
});
it('[success] JSExpression handle without this use scopeValue', () => {
@@ -461,4 +460,4 @@ describe('test parseData ', () => {
expect(result.__privateKey).toBeUndefined();
});
-});
\ No newline at end of file
+});
diff --git a/packages/renderer-core/tests/utils/data-helper.test.ts b/packages/renderer-core/tests/utils/data-helper.test.ts
index cd4508ea87..f4b388ce92 100644
--- a/packages/renderer-core/tests/utils/data-helper.test.ts
+++ b/packages/renderer-core/tests/utils/data-helper.test.ts
@@ -346,11 +346,6 @@ describe('test DataHelper ', () => {
result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);
expect(result).toStrictEqual({ data: 'mockDataValue' });
- // test exception
- const mockError = jest.fn();
- const orginalConsole = global.console;
- global.console = { error: mockError };
-
// exception with id
mockDataHandler = {
type: 'JSFunction',
@@ -358,7 +353,6 @@ describe('test DataHelper ', () => {
};
result = dataHelper.handleData('fullConfigGet', mockDataHandler, { data: 'mockDataValue' }, null);
expect(result).toBeUndefined();
- expect(mockError).toBeCalledWith('[fullConfigGet]单个请求数据处理函数运行出错', expect.anything());
// exception without id
mockDataHandler = {
@@ -367,12 +361,8 @@ describe('test DataHelper ', () => {
};
result = dataHelper.handleData(null, mockDataHandler, { data: 'mockDataValue' }, null);
expect(result).toBeUndefined();
- expect(mockError).toBeCalledWith('请求数据处理函数运行出错', expect.anything());
-
- global.console = orginalConsole;
});
-
it('updateConfig should work', () => {
const mockHost = { stateA: 'aValue'};
const mockDataSourceConfig = {
diff --git a/packages/renderer-core/tests/utils/is-use-loop.test.ts b/packages/renderer-core/tests/utils/is-use-loop.test.ts
index 5f502a2e5b..b0a614f2ee 100644
--- a/packages/renderer-core/tests/utils/is-use-loop.test.ts
+++ b/packages/renderer-core/tests/utils/is-use-loop.test.ts
@@ -5,6 +5,9 @@ describe('base test', () => {
it('designMode is true', () => {
expect(isUseLoop([], true)).toBeFalsy();
expect(isUseLoop([{}], true)).toBeTruthy();
+ expect(isUseLoop(null, true)).toBeFalsy();
+ expect(isUseLoop(undefined, true)).toBeFalsy();
+ expect(isUseLoop(0, true)).toBeFalsy();
});
it('loop is expression', () => {
@@ -21,5 +24,8 @@ describe('base test', () => {
it('designMode is false', () => {
expect(isUseLoop([], false)).toBeTruthy();
expect(isUseLoop([{}], false)).toBeTruthy();
+ expect(isUseLoop(null, false)).toBeTruthy();
+ expect(isUseLoop(undefined, false)).toBeTruthy();
+ expect(isUseLoop(0, false)).toBeTruthy();
});
});
diff --git a/packages/shell/build.json b/packages/shell/build.json
index bd5cf18dde..3e92600554 100644
--- a/packages/shell/build.json
+++ b/packages/shell/build.json
@@ -1,5 +1,5 @@
{
"plugins": [
- "build-plugin-component"
+ "@alilc/build-plugin-lce"
]
}
diff --git a/packages/shell/build.test.json b/packages/shell/build.test.json
index dcdc891e93..9cc30d7463 100644
--- a/packages/shell/build.test.json
+++ b/packages/shell/build.test.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}
diff --git a/packages/shell/package.json b/packages/shell/package.json
index 9b9cc04168..c2b62e2270 100644
--- a/packages/shell/package.json
+++ b/packages/shell/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-shell",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "Shell Layer for AliLowCodeEngine",
"main": "lib/index.js",
"module": "es/index.js",
@@ -9,18 +9,16 @@
"es"
],
"scripts": {
- "build": "build-scripts build --skip-demo",
- "test": "build-scripts test --config build.test.json",
- "test:cov": "build-scripts test --config build.test.json --jest-coverage"
+ "build": "build-scripts build"
},
"license": "MIT",
"dependencies": {
- "@alilc/lowcode-designer": "1.1.6",
- "@alilc/lowcode-editor-core": "1.1.6",
- "@alilc/lowcode-editor-skeleton": "1.1.6",
- "@alilc/lowcode-types": "1.1.6",
- "@alilc/lowcode-utils": "1.1.6",
- "@alilc/lowcode-workspace": "1.1.6",
+ "@alilc/lowcode-designer": "1.3.2",
+ "@alilc/lowcode-editor-core": "1.3.2",
+ "@alilc/lowcode-editor-skeleton": "1.3.2",
+ "@alilc/lowcode-types": "1.3.2",
+ "@alilc/lowcode-utils": "1.3.2",
+ "@alilc/lowcode-workspace": "1.3.2",
"classnames": "^2.2.6",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
@@ -50,5 +48,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
},
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues",
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme"
}
diff --git a/packages/shell/src/api/command.ts b/packages/shell/src/api/command.ts
new file mode 100644
index 0000000000..ebab4a9ff5
--- /dev/null
+++ b/packages/shell/src/api/command.ts
@@ -0,0 +1,46 @@
+import { IPublicApiCommand, IPublicModelPluginContext, IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '@alilc/lowcode-types';
+import { commandSymbol, pluginContextSymbol } from '../symbols';
+import { ICommand, ICommandOptions } from '@alilc/lowcode-editor-core';
+
+const optionsSymbol = Symbol('options');
+const commandScopeSet = new Set();
+
+export class Command implements IPublicApiCommand {
+ [commandSymbol]: ICommand;
+ [optionsSymbol]?: ICommandOptions;
+ [pluginContextSymbol]?: IPublicModelPluginContext;
+
+ constructor(innerCommand: ICommand, pluginContext?: IPublicModelPluginContext, options?: ICommandOptions) {
+ this[commandSymbol] = innerCommand;
+ this[optionsSymbol] = options;
+ this[pluginContextSymbol] = pluginContext;
+ const commandScope = options?.commandScope;
+ if (commandScope && commandScopeSet.has(commandScope)) {
+ throw new Error(`Command scope "${commandScope}" has been registered.`);
+ }
+ }
+
+ registerCommand(command: IPublicTypeCommand): void {
+ this[commandSymbol].registerCommand(command, this[optionsSymbol]);
+ }
+
+ batchExecuteCommand(commands: { name: string; args: IPublicTypeCommandHandlerArgs }[]): void {
+ this[commandSymbol].batchExecuteCommand(commands, this[pluginContextSymbol]);
+ }
+
+ executeCommand(name: string, args: IPublicTypeCommandHandlerArgs): void {
+ this[commandSymbol].executeCommand(name, args);
+ }
+
+ listCommands(): IPublicTypeListCommand[] {
+ return this[commandSymbol].listCommands();
+ }
+
+ unregisterCommand(name: string): void {
+ this[commandSymbol].unregisterCommand(name);
+ }
+
+ onCommandError(callback: (name: string, error: Error) => void): void {
+ this[commandSymbol].onCommandError(callback);
+ }
+}
diff --git a/packages/shell/src/api/common.tsx b/packages/shell/src/api/common.tsx
index 6a44dc82e7..8ce07153ad 100644
--- a/packages/shell/src/api/common.tsx
+++ b/packages/shell/src/api/common.tsx
@@ -1,4 +1,4 @@
-import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol } from '../symbols';
+import { editorSymbol, skeletonSymbol, designerCabinSymbol, designerSymbol, settingFieldSymbol, editorCabinSymbol, skeletonCabinSymbol } from '../symbols';
import {
isFormEvent as innerIsFormEvent,
compatibleLegaoSchema as innerCompatibleLegaoSchema,
@@ -25,6 +25,8 @@ import {
IPublicTypeLocationDetailType as InnerLocationDetailType,
IPublicApiCommonEditorCabin,
IPublicModelDragon,
+ IPublicModelSettingField,
+ IPublicTypeI18nData,
} from '@alilc/lowcode-types';
import {
SettingField as InnerSettingField,
@@ -35,6 +37,11 @@ import {
getConvertedExtraKey as innerGetConvertedExtraKey,
getOriginalExtraKey as innerGetOriginalExtraKey,
IDesigner,
+ DropLocation as InnerDropLocation,
+ Designer as InnerDesigner,
+ Node as InnerNode,
+ LowCodePluginManager as InnerLowCodePluginManager,
+ DesignerView as InnerDesignerView,
} from '@alilc/lowcode-designer';
import {
Skeleton as InnerSkeleton,
@@ -42,6 +49,8 @@ import {
PopupContext as InnerPopupContext,
PopupPipe as InnerPopupPipe,
Workbench as InnerWorkbench,
+ SettingsPrimaryPane as InnerSettingsPrimaryPane,
+ registerDefaults as InnerRegisterDefaults,
} from '@alilc/lowcode-editor-skeleton';
import {
Editor,
@@ -57,6 +66,10 @@ import {
untracked as innerUntracked,
computed as innerComputed,
observer as innerObserver,
+ action as innerAction,
+ runInAction as innerRunInAction,
+ engineConfig as innerEngineConfig,
+ globalContext,
} from '@alilc/lowcode-editor-core';
import { Dragon as ShellDragon } from '../model';
import { ReactNode } from 'react';
@@ -90,6 +103,11 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin {
DragObjectType: InnerDragObjectType,
isDragNodeDataObject: innerIsDragNodeDataObject,
isNode: innerIsNode,
+ DropLocation: InnerDropLocation,
+ Designer: InnerDesigner,
+ Node: InnerNode,
+ LowCodePluginManager: InnerLowCodePluginManager,
+ DesignerView: InnerDesignerView,
};
}
@@ -156,8 +174,19 @@ class DesignerCabin implements IPublicApiCommonDesignerCabin {
class SkeletonCabin implements IPublicApiCommonSkeletonCabin {
private readonly [skeletonSymbol]: InnerSkeleton;
+ readonly [skeletonCabinSymbol]: any;
+
constructor(skeleton: InnerSkeleton) {
this[skeletonSymbol] = skeleton;
+ this[skeletonCabinSymbol] = {
+ Workbench: InnerWorkbench,
+ createSettingFieldView: this.createSettingFieldView,
+ PopupContext: InnerPopupContext,
+ PopupPipe: InnerPopupPipe,
+ SettingsPrimaryPane: InnerSettingsPrimaryPane,
+ registerDefaults: InnerRegisterDefaults,
+ Skeleton: InnerSkeleton,
+ };
}
get Workbench(): any {
@@ -168,8 +197,8 @@ class SkeletonCabin implements IPublicApiCommonSkeletonCabin {
/**
* @deprecated
*/
- createSettingFieldView(item: any, field: any) {
- return innerCreateSettingFieldView(item, field);
+ createSettingFieldView(field: IPublicModelSettingField, fieldEntry: any) {
+ return innerCreateSettingFieldView((field as any)[settingFieldSymbol] || field, fieldEntry);
}
/**
@@ -233,13 +262,42 @@ class Utils implements IPublicApiCommonUtils {
} {
return innerCreateIntl(instance);
}
+
+ intl(data: IPublicTypeI18nData | string, params?: object): any {
+ return innerIntl(data, params);
+ }
}
class EditorCabin implements IPublicApiCommonEditorCabin {
private readonly [editorSymbol]: Editor;
+ /**
+ * @deprecated
+ */
+ readonly [editorCabinSymbol]: any;
+
constructor(editor: Editor) {
this[editorSymbol] = editor;
+ this[editorCabinSymbol] = {
+ Editor,
+ globalContext,
+ runInAction: innerRunInAction,
+ Title: InnerTitle,
+ Tip: InnerTip,
+ shallowIntl: innerShallowIntl,
+ createIntl: innerCreateIntl,
+ intl: innerIntl,
+ createSetterContent: this.createSetterContent.bind(this),
+ globalLocale: innerGlobalLocale,
+ obx: innerObx,
+ action: innerAction,
+ engineConfig: innerEngineConfig,
+ observable: innerObservable,
+ makeObservable: innerMakeObservable,
+ untracked: innerUntracked,
+ computed: innerComputed,
+ observer: innerObserver,
+ };
}
/**
@@ -301,6 +359,27 @@ class EditorCabin implements IPublicApiCommonEditorCabin {
return innerObx;
}
+ /**
+ * @deprecated
+ */
+ get action() {
+ return innerAction;
+ }
+
+ /**
+ * @deprecated
+ */
+ get engineConfig() {
+ return innerEngineConfig;
+ }
+
+ /**
+ * @deprecated
+ */
+ get runInAction() {
+ return innerRunInAction;
+ }
+
/**
* @deprecated
*/
diff --git a/packages/shell/src/api/commonUI.tsx b/packages/shell/src/api/commonUI.tsx
new file mode 100644
index 0000000000..69dd104b2a
--- /dev/null
+++ b/packages/shell/src/api/commonUI.tsx
@@ -0,0 +1,78 @@
+import { IPublicApiCommonUI, IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';
+import {
+ HelpTip,
+ IEditor,
+ Tip as InnerTip,
+ Title as InnerTitle,
+ } from '@alilc/lowcode-editor-core';
+import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next';
+import { ContextMenu } from '../components/context-menu';
+import { editorSymbol } from '../symbols';
+import { ReactElement } from 'react';
+
+export class CommonUI implements IPublicApiCommonUI {
+ [editorSymbol]: IEditor;
+
+ Balloon = Balloon;
+ Breadcrumb = Breadcrumb;
+ Button = Button;
+ Card = Card;
+ Checkbox = Checkbox;
+ DatePicker = DatePicker;
+ Dialog = Dialog;
+ Dropdown = Dropdown;
+ Form = Form;
+ Icon = Icon;
+ Input = Input;
+ Loading = Loading as any;
+ Message = Message;
+ Overlay = Overlay;
+ Pagination = Pagination;
+ Radio = Radio;
+ Search = Search;
+ Select = Select;
+ SplitButton = SplitButton;
+ Step = Step;
+ Switch = Switch;
+ Tab = Tab;
+ Table = Table;
+ Tree = Tree;
+ TreeSelect = TreeSelect;
+ Upload = Upload;
+ Divider = Divider;
+
+ ContextMenu: ((props: {
+ menus: IPublicTypeContextMenuAction[];
+ children: React.ReactElement[] | React.ReactElement;
+ }) => ReactElement) & {
+ create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void;
+ };
+
+ constructor(editor: IEditor) {
+ this[editorSymbol] = editor;
+
+ const innerContextMenu = (props: any) => {
+ const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;
+ return ;
+ };
+
+ innerContextMenu.create = (menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {
+ const pluginContext: IPublicModelPluginContext = editor.get('pluginContext') as IPublicModelPluginContext;
+ return ContextMenu.create(pluginContext, menus, event);
+ };
+
+ this.ContextMenu = innerContextMenu;
+ }
+
+ get Tip() {
+ return InnerTip;
+ }
+
+ get HelpTip() {
+ return HelpTip;
+ }
+
+ get Title() {
+ return InnerTitle;
+ }
+}
diff --git a/packages/shell/src/api/event.ts b/packages/shell/src/api/event.ts
index 0fb41966e7..f2adca98c1 100644
--- a/packages/shell/src/api/event.ts
+++ b/packages/shell/src/api/event.ts
@@ -36,6 +36,20 @@ export class Event implements IPublicApiEvent {
}
}
+ /**
+ * 监听事件,会在其他回调函数之前执行
+ * @param event 事件名称
+ * @param listener 事件回调
+ */
+ prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable {
+ if (isPluginEventName(event)) {
+ return this[eventBusSymbol].prependListener(event, listener);
+ } else {
+ logger.warn(`fail to prependListener event ${event}, event should have a prefix like 'somePrefix:eventName'`);
+ return () => {};
+ }
+ }
+
/**
* 取消监听事件
* @param event 事件名称
diff --git a/packages/shell/src/api/index.ts b/packages/shell/src/api/index.ts
index 4114926e19..79340f6777 100644
--- a/packages/shell/src/api/index.ts
+++ b/packages/shell/src/api/index.ts
@@ -10,4 +10,6 @@ export * from './simulator-host';
export * from './skeleton';
export * from './canvas';
export * from './workspace';
-export * from './config';
\ No newline at end of file
+export * from './config';
+export * from './commonUI';
+export * from './command';
\ No newline at end of file
diff --git a/packages/shell/src/api/material.ts b/packages/shell/src/api/material.ts
index e3ebd20ec5..284b88fbbf 100644
--- a/packages/shell/src/api/material.ts
+++ b/packages/shell/src/api/material.ts
@@ -3,7 +3,7 @@ import {
IDesigner,
isComponentMeta,
} from '@alilc/lowcode-designer';
-import { IPublicTypeAssetsJson } from '@alilc/lowcode-utils';
+import { IPublicTypeAssetsJson, getLogger } from '@alilc/lowcode-utils';
import {
IPublicTypeComponentAction,
IPublicTypeComponentMetadata,
@@ -13,12 +13,16 @@ import {
IPublicTypeNpmInfo,
IPublicModelEditor,
IPublicTypeDisposable,
+ IPublicTypeContextMenuAction,
+ IPublicTypeContextMenuItem,
} from '@alilc/lowcode-types';
import { Workspace as InnerWorkspace } from '@alilc/lowcode-workspace';
import { editorSymbol, designerSymbol } from '../symbols';
import { ComponentMeta as ShellComponentMeta } from '../model';
import { ComponentType } from 'react';
+const logger = getLogger({ level: 'warn', bizName: 'shell-material' });
+
const innerEditorSymbol = Symbol('editor');
export class Material implements IPublicApiMaterial {
private readonly [innerEditorSymbol]: IPublicModelEditor;
@@ -29,6 +33,10 @@ export class Material implements IPublicApiMaterial {
}
const workspace: InnerWorkspace = globalContext.get('workspace');
if (workspace.isActive) {
+ if (!workspace.window.editor) {
+ logger.error('Material api 调用时机出现问题,请检查');
+ return this[innerEditorSymbol];
+ }
return workspace.window.editor;
}
@@ -143,9 +151,16 @@ export class Material implements IPublicApiMaterial {
* 在设计器辅助层增加一个扩展 action
* @param action
*/
- addBuiltinComponentAction(action: IPublicTypeComponentAction) {
+ addBuiltinComponentAction = (action: IPublicTypeComponentAction) => {
this[designerSymbol].componentActions.addBuiltinComponentAction(action);
- }
+ };
+
+ /**
+ * 刷新 componentMetasMap,可触发模拟器里的 components 重新构建
+ */
+ refreshComponentMetasMap = () => {
+ this[designerSymbol].refreshComponentMetasMap();
+ };
/**
* 移除设计器辅助层的指定 action
@@ -174,7 +189,7 @@ export class Material implements IPublicApiMaterial {
onChangeAssets(fn: () => void): IPublicTypeDisposable {
const dispose = [
// 设置 assets,经过 setAssets 赋值
- this[editorSymbol].onGot('assets', fn),
+ this[editorSymbol].onChange('assets', fn),
// 增量设置 assets,经过 loadIncrementalAssets 赋值
this[editorSymbol].eventBus.on('designer.incrementalAssetsReady', fn),
];
@@ -183,4 +198,16 @@ export class Material implements IPublicApiMaterial {
dispose.forEach(d => d && d());
};
}
+
+ addContextMenuOption(option: IPublicTypeContextMenuAction) {
+ this[designerSymbol].contextMenuActions.addMenuAction(option);
+ }
+
+ removeContextMenuOption(name: string) {
+ this[designerSymbol].contextMenuActions.removeMenuAction(name);
+ }
+
+ adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]) {
+ this[designerSymbol].contextMenuActions.adjustMenuLayout(fn);
+ }
}
diff --git a/packages/shell/src/api/plugins.ts b/packages/shell/src/api/plugins.ts
index e5a79edbd4..b6f5e63717 100644
--- a/packages/shell/src/api/plugins.ts
+++ b/packages/shell/src/api/plugins.ts
@@ -66,8 +66,8 @@ export class Plugins implements IPublicApiPlugins {
return this[pluginsSymbol].has(pluginName);
}
- delete(pluginName: string) {
- this[pluginsSymbol].delete(pluginName);
+ async delete(pluginName: string) {
+ return await this[pluginsSymbol].delete(pluginName);
}
toProxy() {
diff --git a/packages/shell/src/api/project.ts b/packages/shell/src/api/project.ts
index ed45701b3c..f005d0af0c 100644
--- a/packages/shell/src/api/project.ts
+++ b/packages/shell/src/api/project.ts
@@ -18,6 +18,9 @@ import {
import { DocumentModel as ShellDocumentModel } from '../model';
import { SimulatorHost } from './simulator-host';
import { editorSymbol, projectSymbol, simulatorHostSymbol, documentSymbol } from '../symbols';
+import { getLogger } from '@alilc/lowcode-utils';
+
+const logger = getLogger({ level: 'warn', bizName: 'shell-project' });
const innerProjectSymbol = Symbol('innerProject');
export class Project implements IPublicApiProject {
@@ -29,6 +32,10 @@ export class Project implements IPublicApiProject {
}
const workspace = globalContext.get('workspace');
if (workspace.isActive) {
+ if (!workspace.window?.innerProject) {
+ logger.error('project api 调用时机出现问题,请检查');
+ return this[innerProjectSymbol];
+ }
return workspace.window.innerProject;
}
@@ -43,8 +50,8 @@ export class Project implements IPublicApiProject {
this[innerProjectSymbol] = project;
}
- static create(project: InnerProject) {
- return new Project(project);
+ static create(project: InnerProject, workspaceMode: boolean = false) {
+ return new Project(project, workspaceMode);
}
/**
@@ -225,15 +232,15 @@ export class Project implements IPublicApiProject {
*/
setConfig(key: T, value: IPublicTypeAppConfig[T]): void;
setConfig(value: IPublicTypeAppConfig): void;
- setConfig(...params: any[]): void{
- if(params.length === 2) {
+ setConfig(...params: any[]): void {
+ if (params.length === 2) {
const oldConfig = this[projectSymbol].get('config');
this[projectSymbol].set('config', {
...oldConfig,
[params[0]]: params[1],
- })
+ });
} else {
- this[projectSymbol].set('config', params[0])
+ this[projectSymbol].set('config', params[0]);
}
}
}
diff --git a/packages/shell/src/api/setters.ts b/packages/shell/src/api/setters.ts
index 553f32c4e9..b7f2d40ecf 100644
--- a/packages/shell/src/api/setters.ts
+++ b/packages/shell/src/api/setters.ts
@@ -1,27 +1,36 @@
import { IPublicTypeCustomView, IPublicApiSetters, IPublicTypeRegisteredSetter } from '@alilc/lowcode-types';
-import { Setters as InnerSetters, globalContext } from '@alilc/lowcode-editor-core';
+import { ISetters, globalContext, untracked } from '@alilc/lowcode-editor-core';
import { ReactNode } from 'react';
+import { getLogger } from '@alilc/lowcode-utils';
const innerSettersSymbol = Symbol('setters');
const settersSymbol = Symbol('setters');
+const logger = getLogger({ level: 'warn', bizName: 'shell-setters' });
+
export class Setters implements IPublicApiSetters {
- readonly [innerSettersSymbol]: InnerSetters;
+ readonly [innerSettersSymbol]: ISetters;
- get [settersSymbol](): InnerSetters {
+ get [settersSymbol](): ISetters {
if (this.workspaceMode) {
return this[innerSettersSymbol];
}
const workspace = globalContext.get('workspace');
if (workspace.isActive) {
- return workspace.window.innerSetters;
+ return untracked(() => {
+ if (!workspace.window?.innerSetters) {
+ logger.error('setter api 调用时机出现问题,请检查');
+ return this[innerSettersSymbol];
+ }
+ return workspace.window.innerSetters;
+ });
}
return this[innerSettersSymbol];
}
- constructor(innerSetters: InnerSetters, readonly workspaceMode = false) {
+ constructor(innerSetters: ISetters, readonly workspaceMode = false) {
this[innerSettersSymbol] = innerSetters;
}
@@ -38,11 +47,11 @@ export class Setters implements IPublicApiSetters {
* 获取已注册的所有 settersMap
* @returns
*/
- getSettersMap(): Map {
+ }> => {
return this[settersSymbol].getSettersMap();
- }
+ };
/**
* 注册一个 setter
@@ -57,6 +66,9 @@ export class Setters implements IPublicApiSetters {
return this[settersSymbol].registerSetter(typeOrMaps, setter);
};
+ /**
+ * @deprecated
+ */
createSetterContent = (setter: any, props: Record): ReactNode => {
return this[settersSymbol].createSetterContent(setter, props);
};
diff --git a/packages/shell/src/api/simulator-host.ts b/packages/shell/src/api/simulator-host.ts
index 3ed7448905..663ba0c668 100644
--- a/packages/shell/src/api/simulator-host.ts
+++ b/packages/shell/src/api/simulator-host.ts
@@ -2,7 +2,8 @@ import {
BuiltinSimulatorHost,
} from '@alilc/lowcode-designer';
import { simulatorHostSymbol, nodeSymbol } from '../symbols';
-import { IPublicApiSimulatorHost, IPublicModelNode } from '@alilc/lowcode-types';
+import { IPublicApiSimulatorHost, IPublicModelNode, IPublicModelSimulatorRender } from '@alilc/lowcode-types';
+import { SimulatorRender } from '../model/simulator-render';
export class SimulatorHost implements IPublicApiSimulatorHost {
private readonly [simulatorHostSymbol]: BuiltinSimulatorHost;
@@ -30,8 +31,12 @@ export class SimulatorHost implements IPublicApiSimulatorHost {
return this[simulatorHostSymbol].contentDocument;
}
- get renderer(): any {
- return this[simulatorHostSymbol].renderer;
+ get renderer(): IPublicModelSimulatorRender | undefined {
+ if (this[simulatorHostSymbol].renderer) {
+ return SimulatorRender.create(this[simulatorHostSymbol].renderer);
+ }
+
+ return undefined;
}
/**
@@ -61,7 +66,7 @@ export class SimulatorHost implements IPublicApiSimulatorHost {
}
/**
- * 刷新渲染画布
+ * 触发组件构建,并刷新渲染画布
*/
rerender(): void {
this[simulatorHostSymbol].rerender();
diff --git a/packages/shell/src/api/skeleton.ts b/packages/shell/src/api/skeleton.ts
index 928c55a0de..c61edf95d0 100644
--- a/packages/shell/src/api/skeleton.ts
+++ b/packages/shell/src/api/skeleton.ts
@@ -4,10 +4,14 @@ import {
SkeletonEvents,
} from '@alilc/lowcode-editor-skeleton';
import { skeletonSymbol } from '../symbols';
-import { IPublicApiSkeleton, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types';
+import { IPublicApiSkeleton, IPublicModelSkeletonItem, IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '@alilc/lowcode-types';
+import { getLogger } from '@alilc/lowcode-utils';
+import { SkeletonItem } from '../model/skeleton-item';
const innerSkeletonSymbol = Symbol('skeleton');
+const logger = getLogger({ level: 'warn', bizName: 'shell-skeleton' });
+
export class Skeleton implements IPublicApiSkeleton {
private readonly [innerSkeletonSymbol]: ISkeleton;
private readonly pluginName: string;
@@ -18,6 +22,10 @@ export class Skeleton implements IPublicApiSkeleton {
}
const workspace = globalContext.get('workspace');
if (workspace.isActive) {
+ if (!workspace.window?.innerSkeleton) {
+ logger.error('skeleton api 调用时机出现问题,请检查');
+ return this[innerSkeletonSymbol];
+ }
return workspace.window.innerSkeleton;
}
@@ -39,12 +47,15 @@ export class Skeleton implements IPublicApiSkeleton {
* @param extraConfig
* @returns
*/
- add(config: IPublicTypeSkeletonConfig, extraConfig?: Record) {
+ add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): IPublicModelSkeletonItem | undefined {
const configWithName = {
...config,
pluginName: this.pluginName,
};
- return this[skeletonSymbol].add(configWithName, extraConfig);
+ const item = this[skeletonSymbol].add(configWithName, extraConfig);
+ if (item) {
+ return new SkeletonItem(item);
+ }
}
/**
@@ -61,6 +72,19 @@ export class Skeleton implements IPublicApiSkeleton {
skeleton[normalizeArea(area)].container?.remove(name);
}
+ getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] {
+ return this[skeletonSymbol][normalizeArea(areaName)].container.items?.map(d => new SkeletonItem(d));
+ }
+
+ getPanel(name: string) {
+ const item = this[skeletonSymbol].getPanel(name);
+ if (!item) {
+ return;
+ }
+
+ return new SkeletonItem(item);
+ }
+
/**
* 显示面板
* @param name
@@ -130,16 +154,30 @@ export class Skeleton implements IPublicApiSkeleton {
* @param listener
* @returns
*/
- onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable {
+ onShowPanel(listener: (paneName: string, panel: IPublicModelSkeletonItem) => void): IPublicTypeDisposable {
const { editor } = this[skeletonSymbol];
editor.eventBus.on(SkeletonEvents.PANEL_SHOW, (name: any, panel: any) => {
- // 不泄漏 skeleton
- const { skeleton, ...restPanel } = panel;
- listener(name, restPanel);
+ listener(name, new SkeletonItem(panel));
});
return () => editor.eventBus.off(SkeletonEvents.PANEL_SHOW, listener);
}
+ onDisableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {
+ const { editor } = this[skeletonSymbol];
+ editor.eventBus.on(SkeletonEvents.WIDGET_DISABLE, (name: any, panel: any) => {
+ listener(name, new SkeletonItem(panel));
+ });
+ return () => editor.eventBus.off(SkeletonEvents.WIDGET_DISABLE, listener);
+ }
+
+ onEnableWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {
+ const { editor } = this[skeletonSymbol];
+ editor.eventBus.on(SkeletonEvents.WIDGET_ENABLE, (name: any, panel: any) => {
+ listener(name, new SkeletonItem(panel));
+ });
+ return () => editor.eventBus.off(SkeletonEvents.WIDGET_ENABLE, listener);
+ }
+
/**
* 监听 panel 隐藏事件
* @param listener
@@ -148,9 +186,7 @@ export class Skeleton implements IPublicApiSkeleton {
onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable {
const { editor } = this[skeletonSymbol];
editor.eventBus.on(SkeletonEvents.PANEL_HIDE, (name: any, panel: any) => {
- // 不泄漏 skeleton
- const { skeleton, ...restPanel } = panel;
- listener(name, restPanel);
+ listener(name, new SkeletonItem(panel));
});
return () => editor.eventBus.off(SkeletonEvents.PANEL_HIDE, listener);
}
@@ -163,9 +199,7 @@ export class Skeleton implements IPublicApiSkeleton {
onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {
const { editor } = this[skeletonSymbol];
editor.eventBus.on(SkeletonEvents.WIDGET_SHOW, (name: any, panel: any) => {
- // 不泄漏 skeleton
- const { skeleton, ...rest } = panel;
- listener(name, rest);
+ listener(name, new SkeletonItem(panel));
});
return () => editor.eventBus.off(SkeletonEvents.WIDGET_SHOW, listener);
}
@@ -178,15 +212,17 @@ export class Skeleton implements IPublicApiSkeleton {
onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable {
const { editor } = this[skeletonSymbol];
editor.eventBus.on(SkeletonEvents.WIDGET_HIDE, (name: any, panel: any) => {
- // 不泄漏 skeleton
- const { skeleton, ...rest } = panel;
- listener(name, rest);
+ listener(name, new SkeletonItem(panel));
});
return () => editor.eventBus.off(SkeletonEvents.WIDGET_HIDE, listener);
}
+
+ registerConfigTransducer(fn: IPublicTypeConfigTransducer, level: number, id?: string) {
+ this[skeletonSymbol].registerConfigTransducer(fn, level, id);
+ }
}
-function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' {
+function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea' | 'rightArea' | 'topArea' | 'toolbar' | 'mainArea' | 'bottomArea' | 'leftFixedArea' | 'leftFloatArea' | 'stages' | 'subTopArea' {
switch (area) {
case 'leftArea':
case 'left':
@@ -213,6 +249,8 @@ function normalizeArea(area: IPublicTypeWidgetConfigArea | undefined): 'leftArea
return 'leftFloatArea';
case 'stages':
return 'stages';
+ case 'subTopArea':
+ return 'subTopArea';
default:
throw new Error(`${area} not supported`);
}
diff --git a/packages/shell/src/api/workspace.ts b/packages/shell/src/api/workspace.ts
index 21015431f9..f5bc79009f 100644
--- a/packages/shell/src/api/workspace.ts
+++ b/packages/shell/src/api/workspace.ts
@@ -1,8 +1,9 @@
import { IPublicApiWorkspace, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
import { IWorkspace } from '@alilc/lowcode-workspace';
-import { workspaceSymbol } from '../symbols';
+import { resourceSymbol, workspaceSymbol } from '../symbols';
import { Resource as ShellResource, Window as ShellWindow } from '../model';
import { Plugins } from './plugins';
+import { Skeleton } from './skeleton';
export class Workspace implements IPublicApiWorkspace {
readonly [workspaceSymbol]: IWorkspace;
@@ -28,23 +29,60 @@ export class Workspace implements IPublicApiWorkspace {
}
get window() {
+ if (!this[workspaceSymbol].window) {
+ return null;
+ }
return new ShellWindow(this[workspaceSymbol].window);
}
+ get resourceTypeList() {
+ return Array.from(this[workspaceSymbol].resourceTypeMap.values()).map((d) => {
+ const { name: resourceName, type: resourceType } = d;
+ const {
+ description,
+ editorViews,
+ } = d.resourceTypeModel({} as any, {});
+
+ return {
+ resourceName,
+ resourceType,
+ description,
+ editorViews: editorViews.map(d => (
+ {
+ viewName: d.viewName,
+ viewType: d.viewType || 'editor',
+ }
+ )),
+ };
+ });
+ }
+
+ onWindowRendererReady(fn: () => void): IPublicTypeDisposable {
+ return this[workspaceSymbol].onWindowRendererReady(fn);
+ }
+
registerResourceType(resourceTypeModel: IPublicTypeResourceType): void {
this[workspaceSymbol].registerResourceType(resourceTypeModel);
}
- openEditorWindow(resourceName: string, title: string, extra: object, viewName?: string) {
- this[workspaceSymbol].openEditorWindow(resourceName, title, extra, viewName);
+ async openEditorWindow(): Promise {
+ if (typeof arguments[0] === 'string') {
+ await this[workspaceSymbol].openEditorWindow(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
+ } else {
+ await this[workspaceSymbol].openEditorWindowByResource(arguments[0]?.[resourceSymbol], arguments[1]);
+ }
}
openEditorWindowById(id: string) {
this[workspaceSymbol].openEditorWindowById(id);
}
- removeEditorWindow(resourceName: string, title: string) {
- this[workspaceSymbol].removeEditorWindow(resourceName, title);
+ removeEditorWindow() {
+ if (typeof arguments[0] === 'string') {
+ this[workspaceSymbol].removeEditorWindow(arguments[0], arguments[1]);
+ } else {
+ this[workspaceSymbol].removeEditorWindowByResource(arguments[0]?.[resourceSymbol]);
+ }
}
removeEditorWindowById(id: string) {
@@ -52,7 +90,11 @@ export class Workspace implements IPublicApiWorkspace {
}
get plugins() {
- return new Plugins(this[workspaceSymbol].plugins, true);
+ return new Plugins(this[workspaceSymbol].plugins, true).toProxy();
+ }
+
+ get skeleton() {
+ return new Skeleton(this[workspaceSymbol].skeleton, 'workspace', true);
}
get windows() {
@@ -66,4 +108,8 @@ export class Workspace implements IPublicApiWorkspace {
onChangeActiveWindow(fn: () => void): IPublicTypeDisposable {
return this[workspaceSymbol].onChangeActiveWindow(fn);
}
+
+ onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable {
+ return this[workspaceSymbol].onChangeActiveEditorView(fn);
+ }
}
diff --git a/packages/shell/src/components/context-menu.tsx b/packages/shell/src/components/context-menu.tsx
new file mode 100644
index 0000000000..8c7ab446ba
--- /dev/null
+++ b/packages/shell/src/components/context-menu.tsx
@@ -0,0 +1,72 @@
+import { createContextMenu, parseContextMenuAsReactNode, parseContextMenuProperties } from '@alilc/lowcode-utils';
+import { engineConfig } from '@alilc/lowcode-editor-core';
+import { IPublicModelPluginContext, IPublicTypeContextMenuAction } from '@alilc/lowcode-types';
+import React, { useCallback } from 'react';
+
+export function ContextMenu({ children, menus, pluginContext }: {
+ menus: IPublicTypeContextMenuAction[];
+ children: React.ReactElement[] | React.ReactElement;
+ pluginContext: IPublicModelPluginContext;
+}): React.ReactElement> {
+ const handleContextMenu = useCallback((event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ let destroyFn: Function | undefined;
+ const destroy = () => {
+ destroyFn?.();
+ };
+ const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {
+ destroy,
+ pluginContext,
+ }), { pluginContext });
+
+ if (!children?.length) {
+ return;
+ }
+
+ destroyFn = createContextMenu(children, { event });
+ }, [menus]);
+
+ if (!engineConfig.get('enableContextMenu')) {
+ return (
+ <>{ children }>
+ );
+ }
+
+ if (!menus) {
+ return (
+ <>{ children }>
+ );
+ }
+
+ // 克隆 children 并添加 onContextMenu 事件处理器
+ const childrenWithContextMenu = React.Children.map(children, (child) =>
+ React.cloneElement(
+ child,
+ { onContextMenu: handleContextMenu },
+ ));
+
+ return (
+ <>{childrenWithContextMenu}>
+ );
+}
+
+ContextMenu.create = (pluginContext: IPublicModelPluginContext, menus: IPublicTypeContextMenuAction[], event: MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ const children: React.ReactNode[] = parseContextMenuAsReactNode(parseContextMenuProperties(menus, {
+ pluginContext,
+ }), {
+ pluginContext,
+ });
+
+ if (!children?.length) {
+ return;
+ }
+
+ return createContextMenu(children, {
+ event,
+ });
+};
\ No newline at end of file
diff --git a/packages/shell/src/index.ts b/packages/shell/src/index.ts
index 7017ca2894..fb1e7228f3 100644
--- a/packages/shell/src/index.ts
+++ b/packages/shell/src/index.ts
@@ -10,6 +10,8 @@ import {
SettingTopEntry,
Clipboard,
SettingField,
+ Window,
+ SkeletonItem,
} from './model';
import {
Project,
@@ -26,6 +28,8 @@ import {
Workspace,
SimulatorHost,
Config,
+ CommonUI,
+ Command,
} from './api';
export * from './symbols';
@@ -50,6 +54,7 @@ export {
Selection,
Setters,
Hotkey,
+ Window,
Skeleton,
SettingField as SettingPropEntry,
SettingTopEntry,
@@ -64,4 +69,7 @@ export {
SimulatorHost,
Config,
SettingField,
+ SkeletonItem,
+ CommonUI,
+ Command,
};
diff --git a/packages/shell/src/model/active-tracker.ts b/packages/shell/src/model/active-tracker.ts
index 41871aacba..32d4c04eb9 100644
--- a/packages/shell/src/model/active-tracker.ts
+++ b/packages/shell/src/model/active-tracker.ts
@@ -12,6 +12,22 @@ export class ActiveTracker implements IPublicModelActiveTracker {
this[activeTrackerSymbol] = innerTracker;
}
+ get target() {
+ const _target = this[activeTrackerSymbol]._target;
+
+ if (!_target) {
+ return null;
+ }
+
+ const { node: innerNode, detail, instance } = _target;
+ const publicNode = ShellNode.create(innerNode);
+ return {
+ node: publicNode!,
+ detail,
+ instance,
+ };
+ }
+
onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void {
if (!fn) {
return () => {};
diff --git a/packages/shell/src/model/document-model.ts b/packages/shell/src/model/document-model.ts
index 68252e3a55..bd0ccaf75e 100644
--- a/packages/shell/src/model/document-model.ts
+++ b/packages/shell/src/model/document-model.ts
@@ -90,7 +90,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
* @returns
*/
get project(): IPublicApiProject {
- return ShellProject.create(this[documentSymbol].project);
+ return ShellProject.create(this[documentSymbol].project, true);
}
/**
@@ -164,7 +164,7 @@ export class DocumentModel implements IPublicModelDocumentModel {
* @param stage
* @returns
*/
- exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): any {
+ exportSchema(stage: IPublicEnumTransformStage = IPublicEnumTransformStage.Render): IPublicTypeRootSchema | undefined {
return this[documentSymbol].export(stage);
}
@@ -252,10 +252,11 @@ export class DocumentModel implements IPublicModelDocumentModel {
* 当前 document 新增节点事件,此时节点已经挂载到 document 上
*/
onMountNode(fn: (payload: { node: IPublicModelNode }) => void): IPublicTypeDisposable {
- this[editorSymbol].eventBus.on('node.add', fn as any);
- return () => {
- this[editorSymbol].eventBus.off('node.add', fn as any);
- };
+ return this[documentSymbol].onMountNode(({
+ node,
+ }) => {
+ fn({ node: ShellNode.create(node)! });
+ });
}
/**
diff --git a/packages/shell/src/model/editor-view.ts b/packages/shell/src/model/editor-view.ts
new file mode 100644
index 0000000000..92d1a57726
--- /dev/null
+++ b/packages/shell/src/model/editor-view.ts
@@ -0,0 +1,35 @@
+import { editorViewSymbol, pluginContextSymbol } from '../symbols';
+import { IPublicModelPluginContext } from '@alilc/lowcode-types';
+import { IViewContext } from '@alilc/lowcode-workspace';
+
+export class EditorView {
+ [editorViewSymbol]: IViewContext;
+
+ [pluginContextSymbol]: IPublicModelPluginContext;
+
+ constructor(editorView: IViewContext) {
+ this[editorViewSymbol] = editorView;
+ this[pluginContextSymbol] = this[editorViewSymbol].innerPlugins._getLowCodePluginContext({
+ pluginName: editorView.editorWindow + editorView.viewName,
+ });
+ }
+
+ toProxy() {
+ return new Proxy(this, {
+ get(target, prop, receiver) {
+ if ((target[pluginContextSymbol] as any)[prop as string]) {
+ return Reflect.get(target[pluginContextSymbol], prop, receiver);
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+ });
+ }
+
+ get viewName() {
+ return this[editorViewSymbol].viewName;
+ }
+
+ get viewType() {
+ return this[editorViewSymbol].viewType;
+ }
+}
diff --git a/packages/shell/src/model/index.ts b/packages/shell/src/model/index.ts
index cd481643e5..a15d50b549 100644
--- a/packages/shell/src/model/index.ts
+++ b/packages/shell/src/model/index.ts
@@ -19,3 +19,5 @@ export * from './active-tracker';
export * from './plugin-instance';
export * from './window';
export * from './clipboard';
+export * from './editor-view';
+export * from './skeleton-item';
diff --git a/packages/shell/src/model/node.ts b/packages/shell/src/model/node.ts
index f2cddd1ab8..29d24232eb 100644
--- a/packages/shell/src/model/node.ts
+++ b/packages/shell/src/model/node.ts
@@ -655,4 +655,24 @@ export class Node implements IPublicModelNode {
setConditionalVisible(): void {
this[nodeSymbol].setConditionalVisible();
}
+
+ getRGL() {
+ const {
+ isContainerNode,
+ isEmptyNode,
+ isRGLContainerNode,
+ isRGLNode,
+ isRGL,
+ rglNode,
+ } = this[nodeSymbol].getRGL();
+
+ return {
+ isContainerNode,
+ isEmptyNode,
+ isRGLContainerNode,
+ isRGLNode,
+ isRGL,
+ rglNode: Node.create(rglNode),
+ };
+ }
}
diff --git a/packages/shell/src/model/resource.ts b/packages/shell/src/model/resource.ts
index b2b0653981..29a385b993 100644
--- a/packages/shell/src/model/resource.ts
+++ b/packages/shell/src/model/resource.ts
@@ -13,6 +13,10 @@ export class Resource implements IPublicModelResource {
return this[resourceSymbol].title;
}
+ get id() {
+ return this[resourceSymbol].id;
+ }
+
get icon() {
return this[resourceSymbol].icon;
}
@@ -25,6 +29,10 @@ export class Resource implements IPublicModelResource {
return this[resourceSymbol].resourceType.name;
}
+ get config() {
+ return this[resourceSymbol].config;
+ }
+
get type() {
return this[resourceSymbol].resourceType.type;
}
@@ -33,6 +41,10 @@ export class Resource implements IPublicModelResource {
return this[resourceSymbol].category;
}
+ get description() {
+ return this[resourceSymbol].description;
+ }
+
get children() {
return this[resourceSymbol].children.map((child) => new Resource(child));
}
diff --git a/packages/shell/src/model/simulator-render.ts b/packages/shell/src/model/simulator-render.ts
new file mode 100644
index 0000000000..f6ae47996c
--- /dev/null
+++ b/packages/shell/src/model/simulator-render.ts
@@ -0,0 +1,23 @@
+import { IPublicModelSimulatorRender } from '@alilc/lowcode-types';
+import { simulatorRenderSymbol } from '../symbols';
+import { BuiltinSimulatorRenderer } from '@alilc/lowcode-designer';
+
+export class SimulatorRender implements IPublicModelSimulatorRender {
+ private readonly [simulatorRenderSymbol]: BuiltinSimulatorRenderer;
+
+ constructor(simulatorRender: BuiltinSimulatorRenderer) {
+ this[simulatorRenderSymbol] = simulatorRender;
+ }
+
+ static create(simulatorRender: BuiltinSimulatorRenderer): IPublicModelSimulatorRender {
+ return new SimulatorRender(simulatorRender);
+ }
+
+ get components() {
+ return this[simulatorRenderSymbol].components;
+ }
+
+ rerender() {
+ return this[simulatorRenderSymbol].rerender();
+ }
+}
\ No newline at end of file
diff --git a/packages/shell/src/model/skeleton-item.ts b/packages/shell/src/model/skeleton-item.ts
new file mode 100644
index 0000000000..7f1224c0d9
--- /dev/null
+++ b/packages/shell/src/model/skeleton-item.ts
@@ -0,0 +1,39 @@
+import { skeletonItemSymbol } from '../symbols';
+import { IPublicModelSkeletonItem } from '@alilc/lowcode-types';
+import { Dock, IWidget, Panel, PanelDock, Stage, Widget } from '@alilc/lowcode-editor-skeleton';
+
+export class SkeletonItem implements IPublicModelSkeletonItem {
+ private [skeletonItemSymbol]: IWidget | Widget | Panel | Stage | Dock | PanelDock;
+
+ constructor(skeletonItem: IWidget | Widget | Panel | Stage | Dock | PanelDock) {
+ this[skeletonItemSymbol] = skeletonItem;
+ }
+
+ get name() {
+ return this[skeletonItemSymbol].name;
+ }
+
+ get visible() {
+ return this[skeletonItemSymbol].visible;
+ }
+
+ disable() {
+ this[skeletonItemSymbol].disable?.();
+ }
+
+ enable() {
+ this[skeletonItemSymbol].enable?.();
+ }
+
+ hide() {
+ this[skeletonItemSymbol].hide();
+ }
+
+ show() {
+ this[skeletonItemSymbol].show();
+ }
+
+ toggle() {
+ this[skeletonItemSymbol].toggle();
+ }
+}
\ No newline at end of file
diff --git a/packages/shell/src/model/window.ts b/packages/shell/src/model/window.ts
index b1263d5415..1bc84e661c 100644
--- a/packages/shell/src/model/window.ts
+++ b/packages/shell/src/model/window.ts
@@ -2,6 +2,7 @@ import { windowSymbol } from '../symbols';
import { IPublicModelResource, IPublicModelWindow, IPublicTypeDisposable } from '@alilc/lowcode-types';
import { IEditorWindow } from '@alilc/lowcode-workspace';
import { Resource as ShellResource } from './resource';
+import { EditorView } from './editor-view';
export class Window implements IPublicModelWindow {
private readonly [windowSymbol]: IEditorWindow;
@@ -31,7 +32,7 @@ export class Window implements IPublicModelWindow {
}
changeViewType(viewName: string) {
- this[windowSymbol].changeViewType(viewName, false);
+ this[windowSymbol].changeViewName(viewName, false);
}
onChangeViewType(fun: (viewName: string) => void): IPublicTypeDisposable {
@@ -41,4 +42,19 @@ export class Window implements IPublicModelWindow {
async save() {
return await this[windowSymbol].save();
}
+
+ onSave(fn: () => void) {
+ return this[windowSymbol].onSave(fn);
+ }
+
+ get currentEditorView() {
+ if (this[windowSymbol]._editorView) {
+ return new EditorView(this[windowSymbol]._editorView).toProxy() as any;
+ }
+ return null;
+ }
+
+ get editorViews() {
+ return Array.from(this[windowSymbol].editorViews.values()).map(d => new EditorView(d).toProxy() as any);
+ }
}
diff --git a/packages/shell/src/symbols.ts b/packages/shell/src/symbols.ts
index 4ba6ff2369..e0f846ad36 100644
--- a/packages/shell/src/symbols.ts
+++ b/packages/shell/src/symbols.ts
@@ -21,9 +21,12 @@ export const dragonSymbol = Symbol('dragon');
export const componentMetaSymbol = Symbol('componentMeta');
export const dropLocationSymbol = Symbol('dropLocation');
export const simulatorHostSymbol = Symbol('simulatorHost');
+export const simulatorRenderSymbol = Symbol('simulatorRender');
export const dragObjectSymbol = Symbol('dragObject');
export const locateEventSymbol = Symbol('locateEvent');
export const designerCabinSymbol = Symbol('designerCabin');
+export const editorCabinSymbol = Symbol('editorCabin');
+export const skeletonCabinSymbol = Symbol('skeletonCabin');
export const hotkeySymbol = Symbol('hotkey');
export const pluginsSymbol = Symbol('plugins');
export const workspaceSymbol = Symbol('workspace');
@@ -34,3 +37,7 @@ export const resourceSymbol = Symbol('resource');
export const clipboardSymbol = Symbol('clipboard');
export const configSymbol = Symbol('configSymbol');
export const conditionGroupSymbol = Symbol('conditionGroup');
+export const editorViewSymbol = Symbol('editorView');
+export const pluginContextSymbol = Symbol('pluginContext');
+export const skeletonItemSymbol = Symbol('skeletonItem');
+export const commandSymbol = Symbol('command');
\ No newline at end of file
diff --git a/packages/types/build.json b/packages/types/build.json
index bd5cf18dde..3e92600554 100644
--- a/packages/types/build.json
+++ b/packages/types/build.json
@@ -1,5 +1,5 @@
{
"plugins": [
- "build-plugin-component"
+ "@alilc/build-plugin-lce"
]
}
diff --git a/packages/types/package.json b/packages/types/package.json
index 6d90338869..5651d427d4 100644
--- a/packages/types/package.json
+++ b/packages/types/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-types",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "Types for Ali lowCode engine",
"files": [
"es",
@@ -9,7 +9,7 @@
"main": "lib/index.js",
"module": "es/index.js",
"scripts": {
- "build": "build-scripts build --skip-demo"
+ "build": "build-scripts build"
},
"dependencies": {
"@alilc/lowcode-datasource-types": "^1.0.0",
@@ -29,5 +29,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/types"
},
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues",
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme"
}
diff --git a/packages/types/src/assets.ts b/packages/types/src/assets.ts
index 852ed00380..f0e6d35396 100644
--- a/packages/types/src/assets.ts
+++ b/packages/types/src/assets.ts
@@ -38,6 +38,7 @@ export interface AssetItem {
device?: string;
level?: AssetLevel;
id?: string;
+ scriptType?: string;
}
export type AssetList = Array;
diff --git a/packages/types/src/shell/api/command.ts b/packages/types/src/shell/api/command.ts
new file mode 100644
index 0000000000..1f8425dcef
--- /dev/null
+++ b/packages/types/src/shell/api/command.ts
@@ -0,0 +1,34 @@
+import { IPublicTypeCommand, IPublicTypeCommandHandlerArgs, IPublicTypeListCommand } from '../type';
+
+export interface IPublicApiCommand {
+
+ /**
+ * 注册一个新命令及其处理函数
+ */
+ registerCommand(command: IPublicTypeCommand): void;
+
+ /**
+ * 注销一个已存在的命令
+ */
+ unregisterCommand(name: string): void;
+
+ /**
+ * 通过名称和给定参数执行一个命令,会校验参数是否符合命令定义
+ */
+ executeCommand(name: string, args?: IPublicTypeCommandHandlerArgs): void;
+
+ /**
+ * 批量执行命令,执行完所有命令后再进行一次重绘,历史记录中只会记录一次
+ */
+ batchExecuteCommand(commands: { name: string; args?: IPublicTypeCommandHandlerArgs }[]): void;
+
+ /**
+ * 列出所有已注册的命令
+ */
+ listCommands(): IPublicTypeListCommand[];
+
+ /**
+ * 注册错误处理回调函数
+ */
+ onCommandError(callback: (name: string, error: Error) => void): void;
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/api/common.ts b/packages/types/src/shell/api/common.ts
index 60fac1606d..05ef0da17f 100644
--- a/packages/types/src/shell/api/common.ts
+++ b/packages/types/src/shell/api/common.ts
@@ -1,6 +1,6 @@
import { Component, ReactNode } from 'react';
-import { IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type';
+import { IPublicTypeI18nData, IPublicTypeNodeSchema, IPublicTypeTitleContent } from '../type';
import { IPublicEnumTransitionType } from '../enum';
export interface IPublicApiCommonUtils {
@@ -69,6 +69,11 @@ export interface IPublicApiCommonUtils {
getLocale(): string;
setLocale(locale: string): void;
};
+
+ /**
+ * i18n 转换方法
+ */
+ intl(data: IPublicTypeI18nData | string, params?: object): string;
}
export interface IPublicApiCommonSkeletonCabin {
diff --git a/packages/types/src/shell/api/commonUI.ts b/packages/types/src/shell/api/commonUI.ts
new file mode 100644
index 0000000000..5ac025fcde
--- /dev/null
+++ b/packages/types/src/shell/api/commonUI.ts
@@ -0,0 +1,74 @@
+import React, { ReactElement } from 'react';
+import { IPublicTypeContextMenuAction, IPublicTypeHelpTipConfig, IPublicTypeTipConfig, IPublicTypeTitleContent } from '../type';
+import { Balloon, Breadcrumb, Button, Card, Checkbox, DatePicker, Dialog, Dropdown, Form, Icon, Input, Loading, Message, Overlay, Pagination, Radio, Search, Select, SplitButton, Step, Switch, Tab, Table, Tree, TreeSelect, Upload, Divider } from '@alifd/next';
+import { IconProps } from '@alifd/next/types/icon';
+
+export interface IPublicApiCommonUI {
+ Balloon: typeof Balloon;
+ Breadcrumb: typeof Breadcrumb;
+ Button: typeof Button;
+ Card: typeof Card;
+ Checkbox: typeof Checkbox;
+ DatePicker: typeof DatePicker;
+ Dialog: typeof Dialog;
+ Dropdown: typeof Dropdown;
+ Form: typeof Form;
+ Icon: typeof Icon;
+ Input: typeof Input;
+ Loading: typeof Loading;
+ Message: typeof Message;
+ Overlay: typeof Overlay;
+ Pagination: typeof Pagination;
+ Radio: typeof Radio;
+ Search: typeof Search;
+ Select: typeof Select;
+ SplitButton: typeof SplitButton;
+ Step: typeof Step;
+ Switch: typeof Switch;
+ Tab: typeof Tab;
+ Table: typeof Table;
+ Tree: typeof Tree;
+ TreeSelect: typeof TreeSelect;
+ Upload: typeof Upload;
+ Divider: typeof Divider;
+
+ /**
+ * Title 组件
+ */
+ get Tip(): React.ComponentClass;
+
+ /**
+ * HelpTip 组件
+ */
+ get HelpTip(): React.VFC<{
+ help: IPublicTypeHelpTipConfig;
+
+ /**
+ * 方向
+ * @default 'top'
+ */
+ direction: IPublicTypeTipConfig['direction'];
+
+ /**
+ * 大小
+ * @default 'small'
+ */
+ size: IconProps['size'];
+ }>;
+
+ /**
+ * Tip 组件
+ */
+ get Title(): React.ComponentClass<{
+ title: IPublicTypeTitleContent | undefined;
+ match?: boolean;
+ keywords?: string | null;
+ }>;
+
+ get ContextMenu(): ((props: {
+ menus: IPublicTypeContextMenuAction[];
+ children: React.ReactElement[] | React.ReactElement;
+ }) => ReactElement) & {
+ create(menus: IPublicTypeContextMenuAction[], event: MouseEvent | React.MouseEvent): void;
+ };
+}
diff --git a/packages/types/src/shell/api/event.ts b/packages/types/src/shell/api/event.ts
index 02b8bc5b3f..5b8c59e139 100644
--- a/packages/types/src/shell/api/event.ts
+++ b/packages/types/src/shell/api/event.ts
@@ -10,6 +10,13 @@ export interface IPublicApiEvent {
*/
on(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;
+ /**
+ * 监听事件,会在其他回调函数之前执行
+ * add monitor to a event
+ * @param event 事件名称
+ * @param listener 事件回调
+ */
+ prependListener(event: string, listener: (...args: any[]) => void): IPublicTypeDisposable;
/**
* 取消监听事件
diff --git a/packages/types/src/shell/api/index.ts b/packages/types/src/shell/api/index.ts
index 3d7d765598..8f14d8dadd 100644
--- a/packages/types/src/shell/api/index.ts
+++ b/packages/types/src/shell/api/index.ts
@@ -10,3 +10,5 @@ export * from './plugins';
export * from './logger';
export * from './canvas';
export * from './workspace';
+export * from './commonUI';
+export * from './command';
\ No newline at end of file
diff --git a/packages/types/src/shell/api/material.ts b/packages/types/src/shell/api/material.ts
index 1e9f54996b..89b2b39ad1 100644
--- a/packages/types/src/shell/api/material.ts
+++ b/packages/types/src/shell/api/material.ts
@@ -1,4 +1,4 @@
-import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable } from '../type';
+import { IPublicTypeAssetsJson, IPublicTypeMetadataTransducer, IPublicTypeComponentAction, IPublicTypeNpmInfo, IPublicTypeDisposable, IPublicTypeContextMenuAction, IPublicTypeContextMenuItem } from '../type';
import { IPublicModelComponentMeta } from '../model';
import { ComponentType } from 'react';
@@ -15,7 +15,7 @@ export interface IPublicApiMaterial {
* set data for Assets
* @returns void
*/
- setAssets(assets: IPublicTypeAssetsJson): void;
+ setAssets(assets: IPublicTypeAssetsJson): Promise;
/**
* 获取「资产包」结构
@@ -122,4 +122,28 @@ export interface IPublicApiMaterial {
* @param fn
*/
onChangeAssets(fn: () => void): IPublicTypeDisposable;
+
+ /**
+ * 刷新 componentMetasMap,可触发模拟器里的 components 重新构建
+ * @since v1.1.7
+ */
+ refreshComponentMetasMap(): void;
+
+ /**
+ * 添加右键菜单项
+ * @param action
+ */
+ addContextMenuOption(action: IPublicTypeContextMenuAction): void;
+
+ /**
+ * 删除特定右键菜单项
+ * @param name
+ */
+ removeContextMenuOption(name: string): void;
+
+ /**
+ * 调整右键菜单项布局
+ * @param actions
+ */
+ adjustContextMenuLayout(fn: (actions: IPublicTypeContextMenuItem[]) => IPublicTypeContextMenuItem[]): void;
}
diff --git a/packages/types/src/shell/api/setters.ts b/packages/types/src/shell/api/setters.ts
index 9ff2e8edaf..011a9dcacd 100644
--- a/packages/types/src/shell/api/setters.ts
+++ b/packages/types/src/shell/api/setters.ts
@@ -1,6 +1,9 @@
+import { ReactNode } from 'react';
+
import { IPublicTypeRegisteredSetter, IPublicTypeCustomView } from '../type';
export interface IPublicApiSetters {
+
/**
* 获取指定 setter
* get setter by type
@@ -29,4 +32,9 @@ export interface IPublicApiSetters {
typeOrMaps: string | { [key: string]: IPublicTypeCustomView | IPublicTypeRegisteredSetter },
setter?: IPublicTypeCustomView | IPublicTypeRegisteredSetter | undefined
): void;
+
+ /**
+ * @deprecated
+ */
+ createSetterContent (setter: any, props: Record): ReactNode;
}
diff --git a/packages/types/src/shell/api/simulator-host.ts b/packages/types/src/shell/api/simulator-host.ts
index 1c0f5dec35..9137067951 100644
--- a/packages/types/src/shell/api/simulator-host.ts
+++ b/packages/types/src/shell/api/simulator-host.ts
@@ -1,7 +1,7 @@
-import { IPublicModelNode } from '../model';
-
+import { IPublicModelNode, IPublicModelSimulatorRender } from '../model';
export interface IPublicApiSimulatorHost {
+
/**
* 获取 contentWindow
* @experimental unstable api, pay extra caution when trying to use it
@@ -17,7 +17,7 @@ export interface IPublicApiSimulatorHost {
/**
* @experimental unstable api, pay extra caution when trying to use it
*/
- get renderer(): any;
+ get renderer(): IPublicModelSimulatorRender | undefined;
/**
* 设置若干用于画布渲染的变量,比如画布大小、locale 等。
diff --git a/packages/types/src/shell/api/skeleton.ts b/packages/types/src/shell/api/skeleton.ts
index b22b3586c4..1bf788e121 100644
--- a/packages/types/src/shell/api/skeleton.ts
+++ b/packages/types/src/shell/api/skeleton.ts
@@ -1,4 +1,5 @@
-import { IPublicTypeDisposable, IPublicTypeSkeletonConfig } from '../type';
+import { IPublicModelSkeletonItem } from '../model';
+import { IPublicTypeConfigTransducer, IPublicTypeDisposable, IPublicTypeSkeletonConfig, IPublicTypeWidgetConfigArea } from '../type';
export interface IPublicApiSkeleton {
@@ -9,7 +10,7 @@ export interface IPublicApiSkeleton {
* @param extraConfig
* @returns
*/
- add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): any;
+ add(config: IPublicTypeSkeletonConfig, extraConfig?: Record): IPublicModelSkeletonItem | undefined;
/**
* 移除一个面板实例
@@ -19,6 +20,19 @@ export interface IPublicApiSkeleton {
*/
remove(config: IPublicTypeSkeletonConfig): number | undefined;
+ /**
+ * 获取某个区域下的所有面板实例
+ * @param areaName IPublicTypeWidgetConfigArea
+ */
+ getAreaItems(areaName: IPublicTypeWidgetConfigArea): IPublicModelSkeletonItem[] | undefined;
+
+ /**
+ * 获取面板实例
+ * @param name 面板名称
+ * @since v1.1.10
+ */
+ getPanel(name: string): IPublicModelSkeletonItem | undefined;
+
/**
* 展示指定 Panel 实例
* show panel by name
@@ -81,7 +95,7 @@ export interface IPublicApiSkeleton {
* @param listener
* @returns
*/
- onShowPanel(listener: (...args: any[]) => void): IPublicTypeDisposable;
+ onShowPanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
/**
* 监听 Panel 实例隐藏事件
@@ -89,7 +103,19 @@ export interface IPublicApiSkeleton {
* @param listener
* @returns
*/
- onHidePanel(listener: (...args: any[]) => void): IPublicTypeDisposable;
+ onHidePanel(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
+
+ /**
+ * 监听 Widget 实例 Disable 事件
+ * @param listener
+ */
+ onDisableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
+
+ /**
+ * 监听 Widget 实例 Enable 事件
+ * @param listener
+ */
+ onEnableWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
/**
* 监听 Widget 显示事件
@@ -97,7 +123,7 @@ export interface IPublicApiSkeleton {
* @param listener
* @returns
*/
- onShowWidget(listener: (...args: any[]) => void): IPublicTypeDisposable;
+ onShowWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
/**
* 监听 Widget 隐藏事件
@@ -105,5 +131,22 @@ export interface IPublicApiSkeleton {
* @param listener
* @returns
*/
- onHideWidget(listener: (...args: any[]) => void): IPublicTypeDisposable;
+ onHideWidget(listener: (paneName?: string, panel?: IPublicModelSkeletonItem) => void): IPublicTypeDisposable;
+
+ /**
+ * 注册一个面板的配置转换器(transducer)。
+ * Registers a configuration transducer for a panel.
+ * @param {IPublicTypeConfigTransducer} transducer
+ * - 要注册的转换器函数。该函数接受一个配置对象(类型为 IPublicTypeSkeletonConfig)作为输入,并返回修改后的配置对象。
+ * - The transducer function to be registered. This function takes a configuration object (of type IPublicTypeSkeletonConfig) as input and returns a modified configuration object.
+ *
+ * @param {number} level
+ * - 转换器的优先级。优先级较高的转换器会先执行。
+ * - The priority level of the transducer. Transducers with higher priority levels are executed first.
+ *
+ * @param {string} [id]
+ * - (可选)转换器的唯一标识符。用于在需要时引用或操作特定的转换器。
+ * - (Optional) A unique identifier for the transducer. Used for referencing or manipulating a specific transducer when needed.
+ */
+ registerConfigTransducer(transducer: IPublicTypeConfigTransducer, level: number, id?: string): void;
}
diff --git a/packages/types/src/shell/api/workspace.ts b/packages/types/src/shell/api/workspace.ts
index 8c19846f70..b6e7d84cb7 100644
--- a/packages/types/src/shell/api/workspace.ts
+++ b/packages/types/src/shell/api/workspace.ts
@@ -1,19 +1,23 @@
import { IPublicModelWindow } from '../model';
-import { IPublicApiPlugins, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
+import { IPublicApiPlugins, IPublicApiSkeleton, IPublicModelResource, IPublicResourceList, IPublicTypeDisposable, IPublicTypeResourceType } from '@alilc/lowcode-types';
export interface IPublicApiWorkspace<
Plugins = IPublicApiPlugins,
- ModelWindow = IPublicModelWindow
+ Skeleton = IPublicApiSkeleton,
+ ModelWindow = IPublicModelWindow,
+ Resource = IPublicModelResource,
> {
/** 是否启用 workspace 模式 */
isActive: boolean;
/** 当前设计器窗口 */
- window: ModelWindow;
+ window: ModelWindow | null;
plugins: Plugins;
+ skeleton: Skeleton;
+
/** 当前设计器的编辑窗口 */
windows: ModelWindow[];
@@ -29,14 +33,28 @@ export interface IPublicApiWorkspace<
/** 注册资源 */
registerResourceType(resourceTypeModel: IPublicTypeResourceType): void;
+ /**
+ * 打开视图窗口
+ * @deprecated
+ */
+ openEditorWindow(resourceName: string, id: string, extra: Object, viewName?: string, sleep?: boolean): Promise;
+
/** 打开视图窗口 */
- openEditorWindow(resourceName: string, title: string, extra: Object, viewName?: string): void;
+ openEditorWindow(resource: Resource, sleep?: boolean): Promise;
/** 通过视图 id 打开窗口 */
openEditorWindowById(id: string): void;
- /** 移除视图窗口 */
- removeEditorWindow(resourceName: string, title: string): void;
+ /**
+ * 移除视图窗口
+ * @deprecated
+ */
+ removeEditorWindow(resourceName: string, id: string): void;
+
+ /**
+ * 移除视图窗口
+ */
+ removeEditorWindow(resource: Resource): void;
/** 通过视图 id 移除窗口 */
removeEditorWindowById(id: string): void;
@@ -46,4 +64,16 @@ export interface IPublicApiWorkspace<
/** active 窗口变更事件 */
onChangeActiveWindow(fn: () => void): IPublicTypeDisposable;
+
+ /**
+ * active 视图变更事件
+ * @since v1.1.7
+ */
+ onChangeActiveEditorView(fn: () => void): IPublicTypeDisposable;
+
+ /**
+ * window 下的所有视图 renderer ready 事件
+ * @since v1.1.7
+ */
+ onWindowRendererReady(fn: () => void): IPublicTypeDisposable;
}
\ No newline at end of file
diff --git a/packages/types/src/shell/enum/context-menu.ts b/packages/types/src/shell/enum/context-menu.ts
new file mode 100644
index 0000000000..fd209b1974
--- /dev/null
+++ b/packages/types/src/shell/enum/context-menu.ts
@@ -0,0 +1,7 @@
+export enum IPublicEnumContextMenuType {
+ SEPARATOR = 'separator',
+ // 'menuItem'
+ MENU_ITEM = 'menuItem',
+ // 'nodeTree'
+ NODE_TREE = 'nodeTree',
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/enum/index.ts b/packages/types/src/shell/enum/index.ts
index 5060558251..13282d0f2b 100644
--- a/packages/types/src/shell/enum/index.ts
+++ b/packages/types/src/shell/enum/index.ts
@@ -2,4 +2,6 @@ export * from './event-names';
export * from './transition-type';
export * from './transform-stage';
export * from './drag-object-type';
-export * from './prop-value-changed-type';
\ No newline at end of file
+export * from './prop-value-changed-type';
+export * from './plugin-register-level';
+export * from './context-menu';
\ No newline at end of file
diff --git a/packages/types/src/shell/enum/plugin-register-level.ts b/packages/types/src/shell/enum/plugin-register-level.ts
new file mode 100644
index 0000000000..a0d9b746bb
--- /dev/null
+++ b/packages/types/src/shell/enum/plugin-register-level.ts
@@ -0,0 +1,6 @@
+export enum IPublicEnumPluginRegisterLevel {
+ Default = 'default',
+ Workspace = 'workspace',
+ Resource = 'resource',
+ EditorView = 'editorView',
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/model/active-tracker.ts b/packages/types/src/shell/model/active-tracker.ts
index b0ceec11fb..ac116a9473 100644
--- a/packages/types/src/shell/model/active-tracker.ts
+++ b/packages/types/src/shell/model/active-tracker.ts
@@ -2,6 +2,12 @@ import { IPublicTypeActiveTarget } from '../type';
import { IPublicModelNode } from './node';
export interface IPublicModelActiveTracker {
+
+ /**
+ * @since 1.1.7
+ */
+ target: IPublicTypeActiveTarget | null;
+
onChange(fn: (target: IPublicTypeActiveTarget) => void): () => void;
track(node: IPublicModelNode): void;
diff --git a/packages/types/src/shell/model/document-model.ts b/packages/types/src/shell/model/document-model.ts
index 2ef0b532be..4c9344eb48 100644
--- a/packages/types/src/shell/model/document-model.ts
+++ b/packages/types/src/shell/model/document-model.ts
@@ -89,7 +89,7 @@ export interface IPublicModelDocumentModel<
* @param stage
* @returns
*/
- exportSchema(stage: IPublicEnumTransformStage): any;
+ exportSchema(stage: IPublicEnumTransformStage): IPublicTypeRootSchema | undefined;
/**
* 插入节点
diff --git a/packages/types/src/shell/model/dragon.ts b/packages/types/src/shell/model/dragon.ts
index 662eb6a007..917149faf3 100644
--- a/packages/types/src/shell/model/dragon.ts
+++ b/packages/types/src/shell/model/dragon.ts
@@ -1,5 +1,5 @@
/* eslint-disable max-len */
-import { IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';
+import { IPublicTypeDisposable, IPublicTypeDragNodeDataObject, IPublicTypeDragObject } from '../type';
import { IPublicModelDragObject, IPublicModelLocateEvent, IPublicModelNode } from './';
export interface IPublicModelDragon<
@@ -19,7 +19,7 @@ export interface IPublicModelDragon<
* @param func
* @returns
*/
- onDragstart(func: (e: LocateEvent) => any): () => void;
+ onDragstart(func: (e: LocateEvent) => any): IPublicTypeDisposable;
/**
* 绑定 drag 事件
@@ -27,7 +27,7 @@ export interface IPublicModelDragon<
* @param func
* @returns
*/
- onDrag(func: (e: LocateEvent) => any): () => void;
+ onDrag(func: (e: LocateEvent) => any): IPublicTypeDisposable;
/**
* 绑定 dragend 事件
@@ -35,7 +35,7 @@ export interface IPublicModelDragon<
* @param func
* @returns
*/
- onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): () => void;
+ onDragend(func: (o: { dragObject: IPublicModelDragObject; copy?: boolean }) => any): IPublicTypeDisposable;
/**
* 设置拖拽监听的区域 shell,以及自定义拖拽转换函数 boost
diff --git a/packages/types/src/shell/model/editor-view.ts b/packages/types/src/shell/model/editor-view.ts
new file mode 100644
index 0000000000..d51e4f9ff2
--- /dev/null
+++ b/packages/types/src/shell/model/editor-view.ts
@@ -0,0 +1,7 @@
+import { IPublicModelPluginContext } from './plugin-context';
+
+export interface IPublicModelEditorView extends IPublicModelPluginContext {
+ viewName: string;
+
+ viewType: 'editor' | 'webview';
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/model/editor.ts b/packages/types/src/shell/model/editor.ts
index 11d75aac75..e6171f0312 100644
--- a/packages/types/src/shell/model/editor.ts
+++ b/packages/types/src/shell/model/editor.ts
@@ -15,13 +15,27 @@ export interface IPublicModelEditor extends StrictEventEmitter void | Promise;
+ /**
+ * 获取 keyOrType 一次
+ */
onceGot: (keyOrType: KeyOrType) => Promise>;
+ /**
+ * 获取 keyOrType 多次
+ */
onGot: (
keyOrType: KeyOrType,
fn: (data: IPublicTypeEditorGetResult) => void
) => () => void;
+ /**
+ * 监听 keyOrType 变化
+ */
+ onChange: (
+ keyOrType: KeyOrType,
+ fn: (data: IPublicTypeEditorGetResult) => void
+ ) => () => void;
+
register: (data: any, key?: IPublicTypeEditorValueKey, options?: IPublicTypeEditorRegisterOptions) => void;
get eventBus(): IPublicApiEvent;
diff --git a/packages/types/src/shell/model/index.ts b/packages/types/src/shell/model/index.ts
index b62fb76b95..ffe6347ac2 100644
--- a/packages/types/src/shell/model/index.ts
+++ b/packages/types/src/shell/model/index.ts
@@ -30,3 +30,6 @@ export * from './sensor';
export * from './resource';
export * from './clipboard';
export * from './setting-field';
+export * from './editor-view';
+export * from './skeleton-item';
+export * from './simulator-render';
diff --git a/packages/types/src/shell/model/node.ts b/packages/types/src/shell/model/node.ts
index 0255376aec..9d8cec3647 100644
--- a/packages/types/src/shell/model/node.ts
+++ b/packages/types/src/shell/model/node.ts
@@ -490,6 +490,18 @@ export interface IBaseModelNode<
* 获取节点实例对应的 dom 节点
*/
getDOMNode(): HTMLElement;
+
+ /**
+ * 获取磁贴相关信息
+ */
+ getRGL(): {
+ isContainerNode: boolean;
+ isEmptyNode: boolean;
+ isRGLContainerNode: boolean;
+ isRGLNode: boolean;
+ isRGL: boolean;
+ rglNode: Node | null;
+ };
}
export interface IPublicModelNode extends IBaseModelNode {}
\ No newline at end of file
diff --git a/packages/types/src/shell/model/plugin-context.ts b/packages/types/src/shell/model/plugin-context.ts
index 5d97b54726..d4d715e96b 100644
--- a/packages/types/src/shell/model/plugin-context.ts
+++ b/packages/types/src/shell/model/plugin-context.ts
@@ -11,19 +11,14 @@ import {
IPluginPreferenceMananger,
IPublicApiPlugins,
IPublicApiWorkspace,
+ IPublicApiCommonUI,
+ IPublicApiCommand,
} from '../api';
-import { IPublicModelEngineConfig } from './';
+import { IPublicEnumPluginRegisterLevel } from '../enum';
+import { IPublicModelEngineConfig, IPublicModelWindow } from './';
export interface IPublicModelPluginContext {
- /**
- * 对于插件开发者来说,可以在 context 挂载自定义的内容,作为插件内全局上下文使用
- *
- * for plugin developers, costom properties can be add to plugin context
- * from inside plugin for convenience.
- */
- [key: string]: any;
-
/**
* 可通过该对象读取插件初始化配置
* by using this, init options can be accessed from inside plugin
@@ -108,6 +103,24 @@ export interface IPublicModelPluginContext {
* @tutorial https://lowcode-engine.cn/site/docs/api/workspace
*/
get workspace(): IPublicApiWorkspace;
+
+ /**
+ * commonUI API
+ * @tutorial https://lowcode-engine.cn/site/docs/api/commonUI
+ */
+ get commonUI(): IPublicApiCommonUI;
+
+ get command(): IPublicApiCommand;
+
+ /**
+ * 插件注册层级
+ * @since v1.1.7
+ */
+ get registerLevel(): IPublicEnumPluginRegisterLevel;
+
+ get isPluginRegisteredInWorkspace(): boolean;
+
+ get editorWindow(): IPublicModelWindow;
}
/**
diff --git a/packages/types/src/shell/model/resource.ts b/packages/types/src/shell/model/resource.ts
index e18f3d5032..acd7d056f5 100644
--- a/packages/types/src/shell/model/resource.ts
+++ b/packages/types/src/shell/model/resource.ts
@@ -5,6 +5,8 @@ export interface IBaseModelResource<
> {
get title(): string | undefined;
+ get id(): string | undefined;
+
get icon(): ReactElement | undefined;
get options(): Record;
@@ -18,6 +20,12 @@ export interface IBaseModelResource<
get children(): Resource[];
get viewName(): string | undefined;
+
+ get description(): string | undefined;
+
+ get config(): {
+ [key: string]: any;
+ } | undefined;
}
export type IPublicModelResource = IBaseModelResource;
diff --git a/packages/types/src/shell/model/simulator-render.ts b/packages/types/src/shell/model/simulator-render.ts
new file mode 100644
index 0000000000..8cf3a03c55
--- /dev/null
+++ b/packages/types/src/shell/model/simulator-render.ts
@@ -0,0 +1,14 @@
+export interface IPublicModelSimulatorRender {
+
+ /**
+ * 画布组件列表
+ */
+ components: {
+ [key: string]: any;
+ };
+
+ /**
+ * 触发画布重新渲染
+ */
+ rerender: () => void;
+}
diff --git a/packages/types/src/shell/model/skeleton-item.ts b/packages/types/src/shell/model/skeleton-item.ts
new file mode 100644
index 0000000000..beb18f2228
--- /dev/null
+++ b/packages/types/src/shell/model/skeleton-item.ts
@@ -0,0 +1,21 @@
+/**
+ * @since 1.1.7
+ */
+export interface IPublicModelSkeletonItem {
+ name: string;
+
+ visible: boolean;
+
+ disable(): void;
+
+ enable(): void;
+
+ hide(): void;
+
+ show(): void;
+
+ /**
+ * @since v1.1.10
+ */
+ toggle(): void;
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/model/window.ts b/packages/types/src/shell/model/window.ts
index bb27ce317c..95ab738bc1 100644
--- a/packages/types/src/shell/model/window.ts
+++ b/packages/types/src/shell/model/window.ts
@@ -1,6 +1,7 @@
import { ReactElement } from 'react';
import { IPublicTypeDisposable, IPublicTypeNodeSchema } from '../type';
import { IPublicModelResource } from './resource';
+import { IPublicModelEditorView } from './editor-view';
export interface IPublicModelWindow<
Resource = IPublicModelResource
@@ -18,6 +19,18 @@ export interface IPublicModelWindow<
/** 窗口资源类型 */
resource?: Resource;
+ /**
+ * 窗口当前视图
+ * @since v1.1.7
+ */
+ currentEditorView: IPublicModelEditorView | null;
+
+ /**
+ * 窗口全部视图实例
+ * @since v1.1.7
+ */
+ editorViews: IPublicModelEditorView[];
+
/** 当前窗口导入 schema */
importSchema(schema: IPublicTypeNodeSchema): void;
@@ -29,4 +42,10 @@ export interface IPublicModelWindow<
/** 窗口视图变更事件 */
onChangeViewType(fn: (viewName: string) => void): IPublicTypeDisposable;
+
+ /**
+ * 窗口视图保存事件
+ * @since 1.1.7
+ */
+ onSave(fn: () => void): IPublicTypeDisposable;
}
\ No newline at end of file
diff --git a/packages/types/src/shell/type/command.ts b/packages/types/src/shell/type/command.ts
new file mode 100644
index 0000000000..0f301bd658
--- /dev/null
+++ b/packages/types/src/shell/type/command.ts
@@ -0,0 +1,59 @@
+import { IPublicTypePropType } from './prop-types';
+
+// 定义命令处理函数的参数类型
+export interface IPublicTypeCommandHandlerArgs {
+ [key: string]: any;
+}
+
+// 定义命令参数的接口
+export interface IPublicTypeCommandParameter {
+
+ /**
+ * 参数名称
+ */
+ name: string;
+
+ /**
+ * 参数类型或详细类型描述
+ */
+ propType: string | IPublicTypePropType;
+
+ /**
+ * 参数描述
+ */
+ description: string;
+
+ /**
+ * 参数默认值(可选)
+ */
+ defaultValue?: any;
+}
+
+// 定义单个命令的接口
+export interface IPublicTypeCommand {
+
+ /**
+ * 命令名称
+ * 命名规则:commandName
+ * 使用规则:commandScope:commandName (commandScope 在插件 meta 中定义,用于区分不同插件的命令)
+ */
+ name: string;
+
+ /**
+ * 命令参数
+ */
+ parameters?: IPublicTypeCommandParameter[];
+
+ /**
+ * 命令描述
+ */
+ description?: string;
+
+ /**
+ * 命令处理函数
+ */
+ handler: (args: any) => void;
+}
+
+export interface IPublicTypeListCommand extends Pick {
+}
\ No newline at end of file
diff --git a/packages/types/src/shell/type/config-transducer.ts b/packages/types/src/shell/type/config-transducer.ts
new file mode 100644
index 0000000000..64c33a5c4e
--- /dev/null
+++ b/packages/types/src/shell/type/config-transducer.ts
@@ -0,0 +1,9 @@
+import { IPublicTypeSkeletonConfig } from '.';
+
+export interface IPublicTypeConfigTransducer {
+ (prev: IPublicTypeSkeletonConfig): IPublicTypeSkeletonConfig;
+
+ level?: number;
+
+ id?: string;
+}
diff --git a/packages/types/src/shell/type/context-menu.ts b/packages/types/src/shell/type/context-menu.ts
new file mode 100644
index 0000000000..dd6d583c25
--- /dev/null
+++ b/packages/types/src/shell/type/context-menu.ts
@@ -0,0 +1,63 @@
+import { IPublicEnumContextMenuType } from '../enum';
+import { IPublicModelNode } from '../model';
+import { IPublicTypeI18nData } from './i8n-data';
+import { IPublicTypeHelpTipConfig } from './widget-base-config';
+
+export interface IPublicTypeContextMenuItem extends Omit {
+ disabled?: boolean;
+
+ items?: Omit[];
+}
+
+export interface IPublicTypeContextMenuAction {
+
+ /**
+ * 动作的唯一标识符
+ * Unique identifier for the action
+ */
+ name: string;
+
+ /**
+ * 显示的标题,可以是字符串或国际化数据
+ * Display title, can be a string or internationalized data
+ */
+ title?: string | IPublicTypeI18nData;
+
+ /**
+ * 菜单项类型
+ * Menu item type
+ * @see IPublicEnumContextMenuType
+ * @default IPublicEnumContextMenuType.MENU_ITEM
+ */
+ type?: IPublicEnumContextMenuType;
+
+ /**
+ * 点击时执行的动作,可选
+ * Action to execute on click, optional
+ */
+ action?: (nodes?: IPublicModelNode[], event?: MouseEvent) => void;
+
+ /**
+ * 子菜单项或生成子节点的函数,可选,仅支持两级
+ * Sub-menu items or function to generate child node, optional
+ */
+ items?: Omit[] | ((nodes?: IPublicModelNode[]) => Omit[]);
+
+ /**
+ * 显示条件函数
+ * Function to determine display condition
+ */
+ condition?: (nodes?: IPublicModelNode[]) => boolean;
+
+ /**
+ * 禁用条件函数,可选
+ * Function to determine disabled condition, optional
+ */
+ disabled?: (nodes?: IPublicModelNode[]) => boolean;
+
+ /**
+ * 帮助提示,可选
+ */
+ help?: IPublicTypeHelpTipConfig;
+}
+
diff --git a/packages/types/src/shell/type/engine-options.ts b/packages/types/src/shell/type/engine-options.ts
index 195db8912b..8221c4089c 100644
--- a/packages/types/src/shell/type/engine-options.ts
+++ b/packages/types/src/shell/type/engine-options.ts
@@ -2,6 +2,7 @@ import { RequestHandlersMap } from '@alilc/lowcode-datasource-types';
import { ComponentType } from 'react';
export interface IPublicTypeEngineOptions {
+
/**
* 是否开启 condition 的能力,默认在设计器中不管 condition 是啥都正常展示
* when this is true, node that configured as conditional not renderring
@@ -40,7 +41,7 @@ export interface IPublicTypeEngineOptions {
/**
* 渲染器类型,默认值:'react'
*/
- renderEnv?: 'react' | 'rax' | string;
+ renderEnv?: 'react' | string;
/**
* 设备类型映射器,处理设计器与渲染器中 device 的映射
@@ -136,8 +137,10 @@ export interface IPublicTypeEngineOptions {
* 与 react-renderer 的 appHelper 一致,https://lowcode-engine.cn/site/docs/guide/expand/runtime/renderer#apphelper
*/
appHelper?: {
+
/** 全局公共函数 */
utils?: Record;
+
/** 全局常量 */
constants?: Record;
};
@@ -168,6 +171,24 @@ export interface IPublicTypeEngineOptions {
* 开启应用级设计模式
*/
enableWorkspaceMode?: boolean;
+
+ /**
+ * @default true
+ * 应用级设计模式下,自动打开第一个窗口
+ */
+ enableAutoOpenFirstWindow?: boolean;
+
+ /**
+ * @default false
+ * 开启右键菜单能力
+ */
+ enableContextMenu?: boolean;
+
+ /**
+ * @default false
+ * 隐藏设计器辅助层
+ */
+ hideComponentAction?: boolean;
}
/**
diff --git a/packages/types/src/shell/type/field-extra-props.ts b/packages/types/src/shell/type/field-extra-props.ts
index bfaff1a468..7aae7e0fe8 100644
--- a/packages/types/src/shell/type/field-extra-props.ts
+++ b/packages/types/src/shell/type/field-extra-props.ts
@@ -43,11 +43,6 @@ export interface IPublicTypeFieldExtraProps {
*/
autorun?: (target: IPublicModelSettingField) => void;
- /**
- * is this field is a virtual field that not save to schema
- */
- virtual?: (target: IPublicModelSettingField) => boolean;
-
/**
* default collapsed when display accordion
*/
@@ -82,5 +77,5 @@ export interface IPublicTypeFieldExtraProps {
/**
* onChange 事件
*/
- onChange?: (value: any, field: any) => void;
+ onChange?: (value: any, field: IPublicModelSettingField) => void;
}
diff --git a/packages/types/src/shell/type/index.ts b/packages/types/src/shell/type/index.ts
index b5dad9bb61..76dd389255 100644
--- a/packages/types/src/shell/type/index.ts
+++ b/packages/types/src/shell/type/index.ts
@@ -90,3 +90,7 @@ export * from './editor-view-config';
export * from './hotkey-callback-config';
export * from './hotkey-callbacks';
export * from './scrollable';
+export * from './simulator-renderer';
+export * from './config-transducer';
+export * from './context-menu';
+export * from './command';
\ No newline at end of file
diff --git a/packages/types/src/shell/type/metadata.ts b/packages/types/src/shell/type/metadata.ts
index 3122ab7d7d..c07d9802e1 100644
--- a/packages/types/src/shell/type/metadata.ts
+++ b/packages/types/src/shell/type/metadata.ts
@@ -139,6 +139,7 @@ export interface ConfigureSupportEventConfig {
name: string;
propType?: IPublicTypePropType;
description?: string;
+ template?: string;
}
/**
@@ -195,6 +196,9 @@ export interface IPublicTypeCallbacks {
onMoveHook?: (currentNode: IPublicModelNode) => boolean;
// thinkof 限制性拖拽
onHoverHook?: (currentNode: IPublicModelNode) => boolean;
+
+ /** 选中 hook,如果返回值是 false,可以控制组件不可被选中 */
+ onSelectHook?: (currentNode: IPublicModelNode) => boolean;
onChildMoveHook?: (childNode: IPublicModelNode, currentNode: IPublicModelNode) => boolean;
// events
diff --git a/packages/types/src/shell/type/node-schema.ts b/packages/types/src/shell/type/node-schema.ts
index b2520ee385..9cbd0a81ac 100644
--- a/packages/types/src/shell/type/node-schema.ts
+++ b/packages/types/src/shell/type/node-schema.ts
@@ -5,11 +5,14 @@ import { IPublicTypeCompositeValue, IPublicTypePropsMap, IPublicTypeNodeData } f
* 搭建基础协议 - 单个组件树节点描述
*/
export interface IPublicTypeNodeSchema {
+
id?: string;
+
/**
* 组件名称 必填、首字母大写
*/
componentName: string;
+
/**
* 组件属性对象
*/
@@ -17,26 +20,26 @@ export interface IPublicTypeNodeSchema {
children?: IPublicTypeNodeData | IPublicTypeNodeData[];
} & IPublicTypePropsMap; // | PropsList;
- /**
- * 组件属性对象
- */
- leadingComponents?: string;
/**
* 渲染条件
*/
condition?: IPublicTypeCompositeValue;
+
/**
* 循环数据
*/
loop?: IPublicTypeCompositeValue;
+
/**
* 循环迭代对象、索引名称 ["item", "index"]
*/
loopArgs?: [string, string];
+
/**
* 子节点
*/
children?: IPublicTypeNodeData | IPublicTypeNodeData[];
+
/**
* 是否锁定
*/
diff --git a/packages/types/src/shell/type/plugin-config.ts b/packages/types/src/shell/type/plugin-config.ts
index 8a533f8fe1..2d841dd804 100644
--- a/packages/types/src/shell/type/plugin-config.ts
+++ b/packages/types/src/shell/type/plugin-config.ts
@@ -1,5 +1,5 @@
export interface IPublicTypePluginConfig {
- init(): void;
- destroy?(): void;
+ init(): Promise | void;
+ destroy?(): Promise | void;
exports?(): any;
}
diff --git a/packages/types/src/shell/type/plugin-meta.ts b/packages/types/src/shell/type/plugin-meta.ts
index 421e59ad0a..bf7f6212e8 100644
--- a/packages/types/src/shell/type/plugin-meta.ts
+++ b/packages/types/src/shell/type/plugin-meta.ts
@@ -1,14 +1,17 @@
import { IPublicTypePluginDeclaration } from './';
export interface IPublicTypePluginMeta {
+
/**
* define dependencies which the plugin depends on
*/
dependencies?: string[];
+
/**
* specify which engine version is compatible with the plugin
*/
engines?: {
+
/** e.g. '^1.0.0' */
lowcodeEngine?: string;
};
@@ -26,4 +29,9 @@ export interface IPublicTypePluginMeta {
* event.emit('someEventName') is actually sending event with name 'myEvent:someEventName'
*/
eventPrefix?: string;
+
+ /**
+ * 如果要使用 command 注册命令,需要在插件 meta 中定义 commandScope
+ */
+ commandScope?: string;
}
diff --git a/packages/types/src/shell/type/prop-types.ts b/packages/types/src/shell/type/prop-types.ts
index a3344b0591..22d84c86fc 100644
--- a/packages/types/src/shell/type/prop-types.ts
+++ b/packages/types/src/shell/type/prop-types.ts
@@ -3,7 +3,7 @@ import { IPublicTypePropConfig } from './';
export type IPublicTypePropType = IPublicTypeBasicType | IPublicTypeRequiredType | IPublicTypeComplexType;
export type IPublicTypeBasicType = 'array' | 'bool' | 'func' | 'number' | 'object' | 'string' | 'node' | 'element' | 'any';
-export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact;
+export type IPublicTypeComplexType = IPublicTypeOneOf | IPublicTypeOneOfType | IPublicTypeArrayOf | IPublicTypeObjectOf | IPublicTypeShape | IPublicTypeExact | IPublicTypeInstanceOf;
export interface IPublicTypeRequiredType {
type: IPublicTypeBasicType;
@@ -40,3 +40,9 @@ export interface IPublicTypeExact {
value: IPublicTypePropConfig[];
isRequired?: boolean;
}
+
+export interface IPublicTypeInstanceOf {
+ type: 'instanceOf';
+ value: IPublicTypePropConfig;
+ isRequired?: boolean;
+}
diff --git a/packages/types/src/shell/type/registered-setter.ts b/packages/types/src/shell/type/registered-setter.ts
index 85cad5a803..55a90465a8 100644
--- a/packages/types/src/shell/type/registered-setter.ts
+++ b/packages/types/src/shell/type/registered-setter.ts
@@ -1,17 +1,20 @@
+import { IPublicModelSettingField } from '../model';
import { IPublicTypeCustomView, IPublicTypeTitleContent } from './';
export interface IPublicTypeRegisteredSetter {
component: IPublicTypeCustomView;
defaultProps?: object;
title?: IPublicTypeTitleContent;
+
/**
* for MixedSetter to check this setter if available
*/
- condition?: (field: any) => boolean;
+ condition?: (field: IPublicModelSettingField) => boolean;
+
/**
* for MixedSetter to manual change to this setter
*/
- initialValue?: any | ((field: any) => any);
+ initialValue?: any | ((field: IPublicModelSettingField) => any);
recommend?: boolean;
// 标识是否为动态 setter,默认为 true
isDynamic?: boolean;
diff --git a/packages/types/src/shell/type/remote-component-description.ts b/packages/types/src/shell/type/remote-component-description.ts
index 7ba5324391..2337203657 100644
--- a/packages/types/src/shell/type/remote-component-description.ts
+++ b/packages/types/src/shell/type/remote-component-description.ts
@@ -1,17 +1,21 @@
+import { Asset } from '../../assets';
import { IPublicTypeComponentMetadata, IPublicTypeReference } from './';
/**
* 远程物料描述
*/
export interface IPublicTypeRemoteComponentDescription extends IPublicTypeComponentMetadata {
+
/**
* 组件描述导出名字,可以通过 window[exportName] 获取到组件描述的 Object 内容;
*/
exportName?: string;
+
/**
* 组件描述的资源链接;
*/
- url?: string;
+ url?: Asset;
+
/**
* 组件 (库) 的 npm 信息;
*/
diff --git a/packages/types/src/shell/type/resource-list.ts b/packages/types/src/shell/type/resource-list.ts
index 5831d7b507..1d7c34232a 100644
--- a/packages/types/src/shell/type/resource-list.ts
+++ b/packages/types/src/shell/type/resource-list.ts
@@ -5,9 +5,17 @@ export interface IPublicResourceData {
/** 资源名字 */
resourceName: string;
+ /** 资源扩展配置 */
+ config?: {
+ [key: string]: any;
+ };
+
/** 资源标题 */
title?: string;
+ /** 资源 Id */
+ id?: string;
+
/** 分类 */
category?: string;
@@ -17,7 +25,7 @@ export interface IPublicResourceData {
/** 资源 icon */
icon?: ReactElement;
- /** 资源其他配置 */
+ /** 资源其他配置,资源初始化时的第二个参数 */
options: {
[key: string]: any;
};
diff --git a/packages/types/src/shell/type/resource-type-config.ts b/packages/types/src/shell/type/resource-type-config.ts
index e47afb53d5..01b49aa2bd 100644
--- a/packages/types/src/shell/type/resource-type-config.ts
+++ b/packages/types/src/shell/type/resource-type-config.ts
@@ -1,3 +1,4 @@
+import React from 'react';
import { IPublicTypeEditorView } from './editor-view';
export interface IPublicResourceTypeConfig {
@@ -6,10 +7,16 @@ export interface IPublicResourceTypeConfig {
description?: string;
/** 资源 icon 标识 */
- icon?: React.ReactElement;
+ icon?: React.ReactElement | React.FunctionComponent | React.ComponentClass;
+
+ /**
+ * 默认视图类型
+ * @deprecated
+ */
+ defaultViewType?: string;
/** 默认视图类型 */
- defaultViewType: string;
+ defaultViewName: string;
/** 资源视图 */
editorViews: IPublicTypeEditorView[];
diff --git a/packages/types/src/shell/type/resource-type.ts b/packages/types/src/shell/type/resource-type.ts
index 7cfb125aaf..7d64a4463d 100644
--- a/packages/types/src/shell/type/resource-type.ts
+++ b/packages/types/src/shell/type/resource-type.ts
@@ -4,7 +4,7 @@ import { IPublicResourceTypeConfig } from './resource-type-config';
export interface IPublicTypeResourceType {
resourceName: string;
- resourceType: 'editor' | 'webview';
+ resourceType: 'editor' | 'webview' | string;
(ctx: IPublicModelPluginContext, options: Object): IPublicResourceTypeConfig;
}
\ No newline at end of file
diff --git a/packages/types/src/shell/type/simulator-renderer.ts b/packages/types/src/shell/type/simulator-renderer.ts
new file mode 100644
index 0000000000..14aa16ab88
--- /dev/null
+++ b/packages/types/src/shell/type/simulator-renderer.ts
@@ -0,0 +1,32 @@
+import { Asset } from '../../assets';
+import {
+ IPublicTypeNodeInstance,
+ IPublicTypeProjectSchema,
+ IPublicTypeComponentSchema,
+} from './';
+
+export interface IPublicTypeSimulatorRenderer {
+ readonly isSimulatorRenderer: true;
+ autoRepaintNode?: boolean;
+ components: Record;
+ rerender: () => void;
+ createComponent(
+ schema: IPublicTypeProjectSchema,
+ ): Component | null;
+ getComponent(componentName: string): Component;
+ getClosestNodeInstance(
+ from: ComponentInstance,
+ nodeId?: string,
+ ): IPublicTypeNodeInstance | null;
+ findDOMNodes(instance: ComponentInstance): Array | null;
+ getClientRects(element: Element | Text): DOMRect[];
+ setNativeSelection(enableFlag: boolean): void;
+ setDraggingState(state: boolean): void;
+ setCopyState(state: boolean): void;
+ loadAsyncLibrary(asyncMap: { [index: string]: any }): void;
+ clearState(): void;
+ stopAutoRepaintNode(): void;
+ enableAutoRepaintNode(): void;
+ run(): void;
+ load(asset: Asset): Promise;
+}
diff --git a/packages/types/src/shell/type/tip-config.ts b/packages/types/src/shell/type/tip-config.ts
index fa82ab96f1..f8b271c909 100644
--- a/packages/types/src/shell/type/tip-config.ts
+++ b/packages/types/src/shell/type/tip-config.ts
@@ -2,8 +2,20 @@ import { IPublicTypeI18nData } from '..';
import { ReactNode } from 'react';
export interface IPublicTypeTipConfig {
+
+ /**
+ * className
+ */
className?: string;
+
+ /**
+ * tip 的内容
+ */
children?: IPublicTypeI18nData | ReactNode;
theme?: string;
+
+ /**
+ * tip 的方向
+ */
direction?: 'top' | 'bottom' | 'left' | 'right';
}
diff --git a/packages/types/src/shell/type/title-config.ts b/packages/types/src/shell/type/title-config.ts
index 571502bc5e..f8de287599 100644
--- a/packages/types/src/shell/type/title-config.ts
+++ b/packages/types/src/shell/type/title-config.ts
@@ -1,26 +1,51 @@
import { ReactNode } from 'react';
-import { IPublicTypeI18nData, IPublicTypeIconType, TipContent } from './';
+import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, TipContent } from './';
+
+export interface IPublicTypeTitleProps {
+
+ /**
+ * 标题内容
+ */
+ title: IPublicTypeTitleContent;
+
+ /**
+ * className
+ */
+ className?: string;
+
+ /**
+ * 点击事件
+ */
+ onClick?: () => void;
+ match?: boolean;
+ keywords?: string;
+}
/**
* 描述 props 的 setter title
*/
export interface IPublicTypeTitleConfig {
+
/**
* 文字描述
*/
label?: IPublicTypeI18nData | ReactNode;
+
/**
* hover 后的展现内容
*/
tip?: TipContent;
+
/**
* 文档链接,暂未实现
*/
docUrl?: string;
+
/**
* 图标
*/
icon?: IPublicTypeIconType;
+
/**
* CSS 类
*/
diff --git a/packages/types/src/shell/type/widget-base-config.ts b/packages/types/src/shell/type/widget-base-config.ts
index f8268628bc..2764ce1927 100644
--- a/packages/types/src/shell/type/widget-base-config.ts
+++ b/packages/types/src/shell/type/widget-base-config.ts
@@ -1,4 +1,27 @@
-import { IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './';
+import { ReactElement, ComponentType } from 'react';
+import { IPublicTypeI18nData, IPublicTypeIconType, IPublicTypeTitleContent, IPublicTypeWidgetConfigArea, TipContent } from './';
+
+export type IPublicTypeHelpTipConfig = string | { url?: string; content?: string | ReactElement };
+
+export interface IPublicTypePanelConfigProps extends IPublicTypePanelDockPanelProps {
+ title?: IPublicTypeTitleContent;
+ icon?: any; // 冗余字段
+ description?: string | IPublicTypeI18nData;
+ help?: IPublicTypeHelpTipConfig; // 显示问号帮助
+ hiddenWhenInit?: boolean; // when this is true, by default will be hidden
+ condition?: (widget: any) => any;
+ onInit?: (widget: any) => any;
+ onDestroy?: () => any;
+ shortcut?: string; // 只有在特定位置,可触发 toggle show
+ enableDrag?: boolean; // 是否开启通过 drag 调整 宽度
+ keepVisibleWhileDragging?: boolean; // 是否在该 panel 范围内拖拽时保持 visible 状态
+}
+
+export interface IPublicTypePanelConfig extends IPublicTypeWidgetBaseConfig {
+ type: 'Panel';
+ content?: string | ReactElement | ComponentType | IPublicTypePanelConfig[]; // as children
+ props?: IPublicTypePanelConfigProps;
+}
export interface IPublicTypeWidgetBaseConfig {
[extra: string]: any;
@@ -13,8 +36,13 @@ export interface IPublicTypeWidgetBaseConfig {
*/
area?: IPublicTypeWidgetConfigArea;
props?: Record;
- content?: any;
+ content?: string | ReactElement | ComponentType | IPublicTypePanelConfig[];
contentProps?: Record;
+
+ /**
+ * 优先级,值越小,优先级越高,优先级高的会排在前面
+ */
+ index?: number;
}
export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig {
@@ -25,7 +53,7 @@ export interface IPublicTypePanelDockConfig extends IPublicTypeWidgetBaseConfig
props?: IPublicTypePanelDockProps;
/** 面板 name, 当没有 props.title 时, 会使用 name 作为标题 */
- name?: string;
+ name: string;
}
export interface IPublicTypePanelDockProps {
diff --git a/packages/utils/build.json b/packages/utils/build.json
index bd5cf18dde..3e92600554 100644
--- a/packages/utils/build.json
+++ b/packages/utils/build.json
@@ -1,5 +1,5 @@
{
"plugins": [
- "build-plugin-component"
+ "@alilc/build-plugin-lce"
]
}
diff --git a/packages/utils/build.test.json b/packages/utils/build.test.json
index dcdc891e93..9cc30d7463 100644
--- a/packages/utils/build.test.json
+++ b/packages/utils/build.test.json
@@ -1,6 +1,6 @@
{
"plugins": [
- "build-plugin-component",
+ "@alilc/build-plugin-lce",
"@alilc/lowcode-test-mate/plugin/index.ts"
]
}
diff --git a/packages/utils/jest.config.js b/packages/utils/jest.config.js
index 0e05687d78..0631fa00c9 100644
--- a/packages/utils/jest.config.js
+++ b/packages/utils/jest.config.js
@@ -1,9 +1,21 @@
-module.exports = {
+const fs = require('fs');
+const { join } = require('path');
+const pkgNames = fs.readdirSync(join('..')).filter(pkgName => !pkgName.startsWith('.'));
+
+const jestConfig = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
- collectCoverage: true,
+ collectCoverage: false,
collectCoverageFrom: [
- 'src/**/*.{ts,tsx}',
+ 'src/**/*.ts',
+ '!src/**/*.d.ts',
'!**/node_modules/**',
'!**/vendor/**',
],
+ setupFilesAfterEnv: ['./jest.setup.js'],
};
+
+// 只对本仓库内的 pkg 做 mapping
+jestConfig.moduleNameMapper = {};
+jestConfig.moduleNameMapper[`^@alilc/lowcode\\-(${pkgNames.join('|')})$`] = '/../$1/src';
+
+module.exports = jestConfig;
\ No newline at end of file
diff --git a/packages/utils/jest.setup.js b/packages/utils/jest.setup.js
new file mode 100644
index 0000000000..7b0828bfa8
--- /dev/null
+++ b/packages/utils/jest.setup.js
@@ -0,0 +1 @@
+import '@testing-library/jest-dom';
diff --git a/packages/utils/package.json b/packages/utils/package.json
index 8043a9e109..60605d81e7 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@alilc/lowcode-utils",
- "version": "1.1.6",
+ "version": "1.3.2",
"description": "Utils for Ali lowCode engine",
"files": [
"lib",
@@ -9,20 +9,24 @@
"main": "lib/index.js",
"module": "es/index.js",
"scripts": {
- "test": "build-scripts test --config build.test.json",
- "build": "build-scripts build --skip-demo"
+ "test": "build-scripts test --config build.test.json --jest-coverage",
+ "build": "build-scripts build"
},
"dependencies": {
"@alifd/next": "^1.19.16",
- "@alilc/lowcode-types": "1.1.6",
+ "@alilc/lowcode-types": "1.3.2",
"lodash": "^4.17.21",
"mobx": "^6.3.0",
+ "prop-types": "^15.8.1",
"react": "^16"
},
"devDependencies": {
"@alib/build-scripts": "^0.1.18",
+ "@testing-library/jest-dom": "^6.1.4",
+ "@testing-library/react": "^11.2.7",
"@types/node": "^13.7.1",
- "@types/react": "^16"
+ "@types/react": "^16",
+ "react-dom": "^16.14.0"
},
"publishConfig": {
"access": "public",
@@ -32,5 +36,7 @@
"type": "http",
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/utils"
},
- "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
+ "gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6",
+ "bugs": "https://github.com/alibaba/lowcode-engine/issues",
+ "homepage": "https://github.com/alibaba/lowcode-engine/#readme"
}
diff --git a/packages/utils/src/app-helper.ts b/packages/utils/src/app-helper.ts
index d5eb2072b3..86b535c592 100644
--- a/packages/utils/src/app-helper.ts
+++ b/packages/utils/src/app-helper.ts
@@ -34,18 +34,18 @@ export class AppHelper extends EventEmitter {
}
}
- batchOn(events: Array, lisenter: (...args: any[]) => void) {
+ batchOn(events: Array, listener: (...args: any[]) => void) {
if (!Array.isArray(events)) return;
- events.forEach((event) => this.on(event, lisenter));
+ events.forEach((event) => this.on(event, listener));
}
- batchOnce(events: Array, lisenter: (...args: any[]) => void) {
+ batchOnce(events: Array, listener: (...args: any[]) => void) {
if (!Array.isArray(events)) return;
- events.forEach((event) => this.once(event, lisenter));
+ events.forEach((event) => this.once(event, listener));
}
- batchOff(events: Array