Skip to content

Commit

Permalink
feat(vue-component, runtime): 使用 app.resolveComponent 获取组件 (#631)
Browse files Browse the repository at this point in the history
  • Loading branch information
aldlss authored Sep 3, 2024
1 parent 18741d3 commit 53456d4
Show file tree
Hide file tree
Showing 21 changed files with 184 additions and 31 deletions.
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions runtime/vue-runtime-help/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
},
"devDependencies": {
"@types/node": "^18.19.0",
"@vue/test-utils": "^2.4.6",
"rimraf": "^3.0.2"
}
}
67 changes: 67 additions & 0 deletions runtime/vue-runtime-help/src/hooks/use-component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { inject } from 'vue-demi';

import type Core from '@tmagic/core';
import { toLine } from '@tmagic/utils';

interface UseComponentOptions {
/** 组件类型 */
componentType?: string;
/** App 实例 */
app?: Core;
}

/**
* 通过组件类型在 App 内获取组件
* @param options 若为字符串则为组件类型,若为对象则为参数选项
* @returns 得到的组件,若未找到则返回带 magic-ui- 前缀的组件类型
*/
export function useComponent<Component = any>(options: string | UseComponentOptions = '') {
let componentType: string | undefined;
let app: Core | undefined;
let component: Component | undefined;

if (typeof options === 'string') {
componentType = options;
} else {
({ componentType, app } = options);
}

if (!componentType || componentType === '') {
componentType = 'container';
}
if (!app) {
app = inject('app');
}

component = resolveComponent({ componentType, app });
if (!component && !componentType.startsWith('magic-ui-')) {
componentType = `magic-ui-${toLine(componentType)}`;
component = resolveComponent({ componentType, app });
}

return component ?? componentType;
}

type resolveComponentOptions = Required<Pick<UseComponentOptions, 'componentType'>> & UseComponentOptions;

function resolveComponent<Component = any>({ componentType, app }: resolveComponentOptions): Component | undefined {
return app?.resolveComponent(componentType);
}
1 change: 1 addition & 0 deletions runtime/vue-runtime-help/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './hooks/use-editor-dsl';
export * from './hooks/use-dsl';
export * from './hooks/use-app';
export { useComponent } from './hooks/use-component';
55 changes: 55 additions & 0 deletions runtime/vue-runtime-help/tests/use-component.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { describe, expect, test } from 'vitest';
import { defineComponent, isVue3, provide } from 'vue-demi';
import { mount } from '@vue/test-utils';

import Core from '@tmagic/core';

import { useComponent } from '../src';

describe('useComponent', () => {
const app = new Core({});
const fooComponent = 'foo-component';
app.registerComponent('foo', fooComponent);
const containerComponent = {};
app.registerComponent('magic-ui-container', containerComponent);

test('string para', () => {
const component = useComponent('foo');
expect(component).toEqual('magic-ui-foo');
});

test('object para and can find component', () => {
const component = useComponent({ componentType: 'foo', app });
expect(component).toEqual(fooComponent);
});

test('without app and can not find component', () => {
const component = useComponent({ componentType: 'foo' });
expect(component).toEqual('magic-ui-foo');
});

test('with magic-ui- componentType and can not find component', () => {
const component = useComponent({ componentType: 'magic-ui-foo', app });
expect(component).toEqual('magic-ui-foo');
});

test.runIf(isVue3)('auto inject and empty para', () => {
const child = defineComponent({
setup() {
const component = useComponent();
expect(component).toEqual(containerComponent);
},
});

const parent = defineComponent({
template: '<child-com></child-com>',
components: { 'child-com': child },
setup() {
provide('app', app);
},
});

const vueApp = mount(parent);
vueApp.unmount();
});
});
1 change: 1 addition & 0 deletions runtime/vue2/dev.vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default defineConfig({
{ find: /^@tmagic\/data-source/, replacement: path.join(__dirname, '../../packages/data-source/src/index.ts') },
{ find: /^@tmagic\/dep/, replacement: path.join(__dirname, '../../packages/dep/src/index.ts') },
{ find: /^@tmagic\/schema/, replacement: path.join(__dirname, '../../packages/schema/src/index.ts') },
{ find: /^@tmagic\/vue-runtime-help/, replacement: path.join(__dirname, '../vue-runtime-help/src/index.ts') },
],
},

Expand Down
6 changes: 4 additions & 2 deletions runtime/vue2/page/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<magic-ui-page :config="pageConfig"></magic-ui-page>
<component :is="pageComponent" :config="pageConfig"></component>
</template>

<script lang="ts">
Expand All @@ -8,14 +8,15 @@ import { defineComponent, inject } from 'vue';
import type { Page } from '@tmagic/core';
import type Core from '@tmagic/core';
import { addParamToUrl } from '@tmagic/utils';
import { useDsl } from '@tmagic/vue-runtime-help';
import { useComponent, useDsl } from '@tmagic/vue-runtime-help';
export default defineComponent({
name: 'App',
setup() {
const app = inject<Core | undefined>('app');
const { pageConfig } = useDsl(app);
const pageComponent = useComponent('page');
app?.on('page-change', (page?: Page) => {
if (!page) {
Expand All @@ -25,6 +26,7 @@ export default defineComponent({
});
return {
pageComponent,
pageConfig,
};
},
Expand Down
4 changes: 2 additions & 2 deletions runtime/vue2/page/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ const app = new Core({

app.setDesignWidth(app.env.isWeb ? window.document.documentElement.getBoundingClientRect().width : 375);

Object.keys(components).forEach((type: string) => {
Vue.component(`magic-ui-${type}`, components[type]);
Object.entries(components).forEach(([type, component]: [string, any]) => {
app.registerComponent(type, component);
});

Object.values(plugins).forEach((plugin: any) => {
Expand Down
6 changes: 4 additions & 2 deletions runtime/vue2/playground/App.vue
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<template>
<magic-ui-page v-if="pageConfig" :key="pageConfig.id" :config="pageConfig"></magic-ui-page>
<component v-if="pageConfig" :is="pageComponent" :key="pageConfig.id" :config="pageConfig"></component>
</template>

<script lang="ts">
import { defineComponent, inject } from 'vue';
import type Core from '@tmagic/core';
import { useEditorDsl } from '@tmagic/vue-runtime-help';
import { useComponent, useEditorDsl } from '@tmagic/vue-runtime-help';
export default defineComponent({
setup() {
const app = inject<Core | undefined>('app');
const { pageConfig } = useEditorDsl(app);
const pageComponent = useComponent('page');
return {
pageComponent,
pageConfig,
};
},
Expand Down
2 changes: 1 addition & 1 deletion runtime/vue2/playground/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Promise.all([
}

Object.entries(components.default).forEach(([type, component]: [string, any]) => {
Vue.component(`magic-ui-${type}`, component);
app.registerComponent(type, component);
});

Object.entries(dataSources).forEach(([type, ds]: [string, any]) => {
Expand Down
6 changes: 4 additions & 2 deletions runtime/vue3/page/App.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<template>
<magic-ui-page :config="pageConfig"></magic-ui-page>
<component :is="pageComponent" :config="(pageConfig as MPage)"></component>
</template>

<script lang="ts" setup>
import { inject } from 'vue';
import { MPage } from 'packages/schema/types';
import type { Page } from '@tmagic/core';
import type Core from '@tmagic/core';
import { addParamToUrl } from '@tmagic/utils';
import { useDsl } from '@tmagic/vue-runtime-help';
import { useComponent, useDsl } from '@tmagic/vue-runtime-help';
const app = inject<Core | undefined>('app');
const { pageConfig } = useDsl(app);
const pageComponent = useComponent('page');
app?.on('page-change', (page?: Page) => {
if (!page) {
Expand Down
2 changes: 1 addition & 1 deletion runtime/vue3/page/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const app = new Core({
app.setDesignWidth(app.env.isWeb ? window.document.documentElement.getBoundingClientRect().width : 375);

Object.entries(components).forEach(([type, component]: [string, any]) => {
vueApp.component(`magic-ui-${type}`, defineAsyncComponent(component));
app.registerComponent(type, defineAsyncComponent(component));
});

Object.values(plugins).forEach((plugin: any) => {
Expand Down
5 changes: 3 additions & 2 deletions runtime/vue3/playground/App.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<template>
<magic-ui-page v-if="pageConfig" :key="pageConfig.id" :config="pageConfig"></magic-ui-page>
<component v-if="pageConfig" :is="pageComponent" :key="pageConfig.id" :config="pageConfig"></component>
</template>

<script lang="ts" setup>
import { inject } from 'vue';
import type Core from '@tmagic/core';
import { useEditorDsl } from '@tmagic/vue-runtime-help';
import { useComponent, useEditorDsl } from '@tmagic/vue-runtime-help';
const app = inject<Core | undefined>('app');
const { pageConfig } = useEditorDsl(app);
const pageComponent = useComponent('page');
</script>
2 changes: 1 addition & 1 deletion runtime/vue3/playground/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Promise.all([
}

Object.entries(components.default).forEach(([type, component]: [string, any]) => {
vueApp.component(`magic-ui-${type}`, component);
app.registerComponent(type, component);
});

Object.entries(dataSources.default).forEach(([type, ds]: [string, any]) => {
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default defineConfig({
plugins: [Vue()],

test: {
include: ['./packages/*/tests/**'],
include: ['./packages/*/tests/**', './runtime/*/tests/**'],
environment: 'jsdom',
environmentMatchGlobs: [['packages/cli/**', 'node']],
coverage: {
Expand Down
5 changes: 3 additions & 2 deletions vue-components/container/src/Container.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<component
v-if="display(item)"
:key="item.id"
:is="`magic-ui-${toLine(item.type)}`"
:is="useComponent({ componentType: item.type, app })"
:data-tmagic-id="item.id"
:data-tmagic-iterator-index="iteratorIndex"
:data-tmagic-iterator-container-id="iteratorContainerId"
Expand All @@ -27,7 +27,7 @@ import { computed, defineComponent, type PropType } from 'vue-demi';
import type { Id, MContainer } from '@tmagic/schema';
import { IS_DSL_NODE_KEY, toLine } from '@tmagic/utils';
import { useApp } from '@tmagic/vue-runtime-help';
import { useApp, useComponent } from '@tmagic/vue-runtime-help';
interface ContainerSchema extends Omit<MContainer, 'id'> {
id?: Id;
Expand Down Expand Up @@ -82,6 +82,7 @@ export default defineComponent({
display,
toLine,
useComponent,
};
},
});
Expand Down
10 changes: 7 additions & 3 deletions vue-components/iterator-container/src/IteratorContainer.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<template>
<div>
<magic-ui-container
<component
:is="containerComponent"
v-for="(item, index) in configs"
:iterator-index="[...(iteratorIndex || []), index]"
:iterator-container-id="[...(iteratorContainerId || []), config.id]"
:key="index"
:config="item"
></magic-ui-container>
></component>
</div>
</template>

Expand All @@ -15,7 +16,7 @@ import { computed, defineComponent, type PropType, watch } from 'vue-demi';
import type { IteratorContainer as TMagicIteratorContainer } from '@tmagic/core';
import type { Id, MIteratorContainer, MNode } from '@tmagic/schema';
import { useApp } from '@tmagic/vue-runtime-help';
import { useApp, useComponent } from '@tmagic/vue-runtime-help';
interface IteratorContainerSchema extends Omit<MIteratorContainer, 'id'> {
id?: Id;
Expand Down Expand Up @@ -52,6 +53,8 @@ export default defineComponent({
methods: {},
});
const containerComponent = useComponent({ componentType: 'container', app });
const configs = computed<IteratorItemSchema[]>(() => {
let { iteratorData = [] } = props.config;
const { itemConfig, dsField, items } = props.config;
Expand Down Expand Up @@ -115,6 +118,7 @@ export default defineComponent({
return {
configs,
containerComponent,
};
},
});
Expand Down
Loading

0 comments on commit 53456d4

Please sign in to comment.