fix: 处理 slot 开启/关闭操作中, 无法正常创建 slot 的bug

feat: 支持 didDropOut 特性
This commit is contained in:
力皓 2020-10-26 10:52:04 +08:00
parent 5c141e8eb0
commit 3e86d09160
9 changed files with 40 additions and 85 deletions

View File

@ -1,8 +1,5 @@
{ {
"plugins": [ "plugins": [
[
"build-plugin-component" "build-plugin-component"
],
"./build.plugin.js"
] ]
} }

View File

@ -1,7 +0,0 @@
module.exports = ({ onGetJestConfig }) => {
// console.log('== test ==');
onGetJestConfig((jestConfig) => {
// console.log(jestConfig);
return jestConfig;
});
};

View File

@ -0,0 +1,5 @@
{
"plugins": [
"@ali/lowcode-test-mate/plugin/index.ts"
]
}

View File

@ -22,6 +22,7 @@ import { TransformStage } from './transform-stage';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { SettingTopEntry } from 'designer/src/designer'; import { SettingTopEntry } from 'designer/src/designer';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { includeSlot, removeSlot } from '../../utils/slot';
/** /**
* *
@ -709,6 +710,11 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
addSlot(slotNode: Node) { addSlot(slotNode: Node) {
slotNode.internalSetParent(this as ParentalNode, true); slotNode.internalSetParent(this as ParentalNode, true);
const slotName = slotNode?.getExtraProp('name')?.getAsString();
// 一个组件下的所有 slot相同 slotName 的 slot 应该是唯一的
if (includeSlot(this, slotName)) {
removeSlot(this, slotName);
}
this._slots.push(slotNode); this._slots.push(slotNode);
} }

View File

@ -6,7 +6,6 @@ import { valueToSource } from './value-to-source';
import { Props } from './props'; import { Props } from './props';
import { SlotNode, Node } from '../node'; import { SlotNode, Node } from '../node';
import { TransformStage } from '../transform-stage'; import { TransformStage } from '../transform-stage';
import { includesSlot } from '../../../utils/slot';
export const UNSET = Symbol.for('unset'); export const UNSET = Symbol.for('unset');
export type UNSET = typeof UNSET; export type UNSET = typeof UNSET;
@ -118,7 +117,7 @@ export class Prop implements IPropParent {
} }
if (type === 'slot') { if (type === 'slot') {
const schema = this._slotNode!.export(stage); const schema = this._slotNode?.export(stage) || {};
if (stage === TransformStage.Render) { if (stage === TransformStage.Render) {
return { return {
type: 'JSSlot', type: 'JSSlot',
@ -294,12 +293,10 @@ export class Prop implements IPropParent {
this._slotNode.import(slotSchema); this._slotNode.import(slotSchema);
} else { } else {
const { owner } = this.props; const { owner } = this.props;
if (!includesSlot(owner, data.name)) {
this._slotNode = owner.document.createNode<SlotNode>(slotSchema); this._slotNode = owner.document.createNode<SlotNode>(slotSchema);
owner.addSlot(this._slotNode); owner.addSlot(this._slotNode);
this._slotNode.internalSetSlotFor(this); this._slotNode.internalSetSlotFor(this);
} }
}
this.dispose(); this.dispose();
} }

View File

@ -1,8 +1,19 @@
import { Node } from '../document/node/node'; import { Node } from '../document/node/node';
export function includesSlot(node: Node, slotName: string | undefined): boolean { export function includeSlot(node: Node, slotName: string | undefined): boolean {
const { slots = [] } = node; const { slots = [] } = node;
return slots.some(slot => { return slots.some(slot => {
return slotName && slotName === slot?.getExtraProp('name')?.getAsString(); return slotName && slotName === slot?.getExtraProp('name')?.getAsString();
}); });
} }
export function removeSlot(node: Node, slotName: string | undefined): boolean {
const { slots = [] } = node;
return slots.some((slot, idx) => {
if (slotName && slotName === slot?.getExtraProp('name')?.getAsString()) {
slots.splice(idx, 1);
return true;
}
return false;
});
}

View File

@ -1,3 +1,4 @@
import set from 'lodash.set';
import '../fixtures/window'; import '../fixtures/window';
import { Project } from '../../src/project/project'; import { Project } from '../../src/project/project';
// import { Node } from '../../../src/document/node/node'; // import { Node } from '../../../src/document/node/node';
@ -27,39 +28,11 @@ jest.mock('../../src/designer/designer', () => {
let designer = null; let designer = null;
beforeAll(() => { beforeAll(() => {
designer = new Designer({} as any); designer = new Designer({});
}); });
describe('schema 渲染测试', () => { describe('schema 生成节点模型测试', () => {
it('最简单的例子,练手用', () => { it.only('block ❌ | component ❌ | slot ❌', () => {
const project = new Project(designer, {
componentsTree: [{
componentName: 'Page',
id: 'page_id',
props: {
name: 'haha',
},
children: [{
componentName: 'Div',
id: 'div_id',
props: {
name: 'div from haha',
},
}],
}],
} as any);
project.open();
expect(project).toBeTruthy();
const { currentDocument } = project;
const { nodesMap } = currentDocument;
// console.log(project.currentDocument.nodesMap.get('div_id').props.items);
expect(nodesMap.has('page_id')).toBeTruthy;
expect(nodesMap.has('div_id')).toBeTruthy;
expect(mockCreateSettingEntry).toBeCalledTimes(2);
// console.log(currentDocument.export(3));
});
it.only('普通场景,无 block / component无 slot', () => {
const project = new Project(designer, { const project = new Project(designer, {
componentsTree: [ componentsTree: [
formSchema, formSchema,
@ -70,15 +43,15 @@ describe('schema 渲染测试', () => {
const { currentDocument } = project; const { currentDocument } = project;
const { nodesMap } = currentDocument; const { nodesMap } = currentDocument;
const ids = getIdsFromSchema(formSchema); const ids = getIdsFromSchema(formSchema);
const expectedNodeCnt = ids.length;
expect(nodesMap.size).toBe(expectedNodeCnt);
ids.forEach(id => { ids.forEach(id => {
expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName); expect(nodesMap.get(id).componentName).toBe(getNodeFromSchemaById(formSchema, id).componentName);
}); });
// console.log(nodesMap.get('node_k1ow3cb9').componentName, getNodeFromSchemaById(formSchema, 'node_k1ow3cb9').componentName)
console.log(nodesMap.size); const exportSchema = currentDocument?.export(1);
// expect(nodesMap.has('page_id')).toBeTruthy; expect(getIdsFromSchema(exportSchema).length).toBe(expectedNodeCnt);
// expect(nodesMap.has('div_id')).toBeTruthy; expect(mockCreateSettingEntry).toBeCalledTimes(expectedNodeCnt);
// expect(mockCreateSettingEntry).toBeCalledTimes(2);
// console.log(currentDocument.export(3));
}); });
it('普通场景,无 block / component有 slot', () => {}); it('普通场景,无 block / component有 slot', () => {});

View File

@ -1,28 +1 @@
export function getIdsFromSchema(schema, ids = []) { export { getIdsFromSchema, getNodeFromSchemaById } from '@ali/lowcode-test-mate/es/utils';
if (!schema) return ids;
const { componentName, id, children } = schema;
if (componentName) {
ids.push(id);
}
if (Array.isArray(children) && children.length > 0) {
children.forEach(node => getIdsFromSchema(node, ids));
}
return ids;
}
export function getNodeFromSchemaById(schema, _id) {
if (!schema) return null;
const { id, children } = schema;
let retNode = null;
if (_id === id) return schema;
if (Array.isArray(children) && children.length > 0) {
children.some(node => {
retNode = getNodeFromSchemaById(node, _id);
if (retNode) {
return true;
}
return false;
});
}
return retNode;
}

View File

@ -54,5 +54,5 @@
"publishConfig": { "publishConfig": {
"registry": "http://registry.npm.alibaba-inc.com" "registry": "http://registry.npm.alibaba-inc.com"
}, },
"homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-react-renderer@0.13.1-6/build/index.html" "homepage": "https://unpkg.alibaba-inc.com/@ali/lowcode-react-renderer@0.13.1-7/build/index.html"
} }