Vue

Vue 3 with Vite. Install the packages, tell the compiler about the custom element, copy the fonts, and wrap the element in a component with v-model.

npm install ./vendor/rd-designer-1.0.0.tgz ./vendor/rd-core-1.0.0.tgz ./vendor/rd-fonts-1.0.0.tgz
npm install ./vendor/rd-fonts-cjk-1.0.0.tgz   # optional: Chinese, Japanese, Korean

Configure the compiler#

Tell the Vue compiler that report-designer is a custom element (vite.config.ts):

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [vue({ template: { compilerOptions: { isCustomElement: (tag) => tag === 'report-designer' } } })],
});

A wrapper component with v-model#

A wrapper component with v-model for the template. Don't name the file ReportDesigner.vue: a component can refer to itself by its file name, which would make <report-designer> inside it resolve to the wrapper instead of the custom element.

<script setup lang="ts">
import '@rd/designer';   // registers <report-designer>
import type { Template, TemplateChangeDetail } from '@rd/designer';

const template = defineModel<Template | null>({ default: null });
const props = withDefaults(defineProps<{
    schema?: object | null;
    lang?: string;
    fontBaseUrl?: string;
}>(), { schema: null, lang: '', fontBaseUrl: '/rd-fonts/' });
const emit = defineEmits<{ save: [template: Template] }>();

function onTemplateChange(e: Event) {
    template.value = (e as CustomEvent<TemplateChangeDetail>).detail.template;
}

function onSave(e: Event) {
    emit('save', (e as CustomEvent<TemplateChangeDetail>).detail.template);
}
</script>

<template>
    <!-- .prop binds DOM properties (objects); plain attributes stay strings. -->
    <report-designer
        :template.prop="template"
        :schema.prop="props.schema"
        :lang="props.lang"
        :font-base-url="props.fontBaseUrl"
        style="display: block; height: 100%"
        @template-change="onTemplateChange"
        @save="onSave"
    />
</template>

Use it in a page#

Keep the template in a shallowRef: a deep reactive proxy is unnecessary for a JSON document you only replace.

<script setup lang="ts">
import { onMounted, shallowRef } from 'vue';

import type { Template } from '@rd/designer';

import RdDesigner from './RdDesigner.vue';

const props = defineProps<{ templateId: string }>();
const template = shallowRef<Template | null>(null);
const schema = bolSchema;   // your data contract

onMounted(async () => {
    template.value = await loadTemplate(props.templateId);
});

async function save(t: Template) {
    await saveTemplate(props.templateId, t);
}
</script>

<template>
    <div style="height: 100vh">
        <RdDesigner v-model="template" :schema="schema" @save="save" />
    </div>
</template>

Copy the fonts#

Before building, copy the contents of node_modules/@rd/fonts/fonts/ and, if installed, node_modules/@rd/fonts-cjk/fonts/ into public/rd-fonts/, and keep font-base-url="/rd-fonts/".