diff --git a/docs/framework/custom-components.mdx b/docs/framework/custom-components.mdx index 5ce899008..28874ad32 100644 --- a/docs/framework/custom-components.mdx +++ b/docs/framework/custom-components.mdx @@ -135,9 +135,9 @@ The code above will make Bubble Message available in the Builder. You can also have a look at the built-in component templates, since their - syntax is equivalent. They can be found in the `ui/src/components/` folder. + syntax is equivalent. They can be found in the `ui/src/components/core` folder. -Go to `ui/src/custom_components/` and open the Vue single-file components, i.e. the +Go to `ui/src/components/custom` and open the Vue single-file components, i.e. the `.vue` files. These files contain comments that will help you get started. Try editing the provided templates, you should see changes reflected. @@ -145,7 +145,7 @@ You can get started by duplicating one of these examples. Make sure you add the ### Define entrypoint -For custom component templates to be taken into account, they need to be accessible from the entrypoint. Edit `ui/src/custom_components/index.ts` to define which templates you wish to export and under which identifiers. +For custom component templates to be taken into account, they need to be accessible from the entrypoint. Edit `ui/src/components/custom/index.ts` to define which templates you wish to export and under which identifiers. ```ts // Import the templates diff --git a/src/ui/src/custom_components/BubbleMessage.vue b/src/ui/src/components/custom/BubbleMessage.vue similarity index 100% rename from src/ui/src/custom_components/BubbleMessage.vue rename to src/ui/src/components/custom/BubbleMessage.vue diff --git a/src/ui/src/custom_components/BubbleMessageAdvanced.vue b/src/ui/src/components/custom/BubbleMessageAdvanced.vue similarity index 100% rename from src/ui/src/custom_components/BubbleMessageAdvanced.vue rename to src/ui/src/components/custom/BubbleMessageAdvanced.vue diff --git a/src/ui/src/custom_components/index.ts b/src/ui/src/components/custom/index.ts similarity index 69% rename from src/ui/src/custom_components/index.ts rename to src/ui/src/components/custom/index.ts index 436ffd20a..f148e7dd3 100644 --- a/src/ui/src/custom_components/index.ts +++ b/src/ui/src/components/custom/index.ts @@ -1,11 +1,14 @@ // Import the templates +import type { TemplateMap } from "@/writerTypes"; import BubbleMessage from "./BubbleMessage.vue"; import BubbleMessageAdvanced from "./BubbleMessageAdvanced.vue"; // Export an object with the ids and the templates as default -export default { +const CUSTOM_COMPONENTS: TemplateMap = { bubblemessage: BubbleMessage, bubblemessageadvanced: BubbleMessageAdvanced, }; + +export default CUSTOM_COMPONENTS; diff --git a/src/ui/src/core/templateMap.ts b/src/ui/src/core/templateMap.ts index b05dd014a..cd3d2f966 100644 --- a/src/ui/src/core/templateMap.ts +++ b/src/ui/src/core/templateMap.ts @@ -1,3 +1,4 @@ +import type { Component as VueComponent } from "vue"; // Maps Writer Framework component types to renderable Vue components // content import CoreDataframe from "../components/core/content/CoreDataframe.vue"; @@ -69,10 +70,14 @@ import WorkflowsWorkflow from "../components/workflows/WorkflowsWorkflow.vue"; import WorkflowsNode from "../components/workflows/abstract/WorkflowsNode.vue"; import WorkflowsRoot from "@/components/workflows/WorkflowsRoot.vue"; -import { AbstractTemplate, WriterComponentDefinition } from "@/writerTypes"; +import type { + AbstractTemplate, + TemplateMap, + WriterComponentDefinition, +} from "@/writerTypes"; import { h } from "vue"; -const templateMap = { +const templateMap: TemplateMap = { root: CoreRoot, page: CorePage, sidebar: CoreSidebar, @@ -135,14 +140,14 @@ const templateMap = { const abstractTemplateMap: Record = {}; +// eslint-disable-next-line no-undef if (WRITER_LIVE_CCT === "yes") { /* - Assigns the components in custom_components to the template map, + Assigns the components in `components/custom` to the template map, allowing for live updates when developing custom component templates. */ - const liveCCT: Record = (await import("../custom_components")) - .default; + const liveCCT = (await import("../components/custom")).default; Object.entries(liveCCT).forEach(([componentType, template]) => { templateMap[`custom_${componentType}`] = template; }); @@ -157,7 +162,7 @@ function fallbackTemplate(type: string) { description: message, category: "Fallback", }, - setup(props, { slots }) { + setup(_props: never, { slots }) { return () => { return h( "div", @@ -212,7 +217,10 @@ export function getSupportedComponentTypes() { return [...Object.keys(templateMap), ...Object.keys(abstractTemplateMap)]; } -export function registerComponentTemplate(type: string, vueComponent: any) { +export function registerComponentTemplate( + type: string, + vueComponent: VueComponent, +) { templateMap[type] = vueComponent; } diff --git a/src/ui/src/writerTypes.ts b/src/ui/src/writerTypes.ts index bbe92a36f..4eb9d554a 100644 --- a/src/ui/src/writerTypes.ts +++ b/src/ui/src/writerTypes.ts @@ -1,3 +1,4 @@ +import type { Component as VueComponent } from "vue"; import { generateCore } from "./core"; import { generateBuilderManager } from "./builder/builderManager"; @@ -101,8 +102,15 @@ export type WriterComponentDefinition = { >; previewField?: string; // Which field to use for previewing in the Component Tree positionless?: boolean; // Whether this type of component is positionless (like Sidebar) - outs?: - Record; + outs?: Record< + string, + { + name: string; + description: string; + style: string; + field?: keyof WriterComponentDefinition["fields"]; + } + >; }; export type BuilderManager = ReturnType; @@ -154,3 +162,5 @@ export type AbstractTemplate = { baseType: string; writer: WriterComponentDefinition; }; + +export type TemplateMap = Record; diff --git a/src/ui/tools/custom_check.mjs b/src/ui/tools/custom_check.mjs index 49b26aa70..6ae37749c 100644 --- a/src/ui/tools/custom_check.mjs +++ b/src/ui/tools/custom_check.mjs @@ -2,7 +2,7 @@ import { importVue } from "./core.mjs"; async function checkDeclarationKey() { let hasFailed = false; - const module = await importVue("../src/custom_components/index.ts"); + const module = await importVue("../src/components/custom/index.ts"); const { checkComponentKey } = await importVue( "../src/core/loadExtensions.ts", ); @@ -17,7 +17,7 @@ async function checkDeclarationKey() { if (invalidCustomComponentKeys.length !== 0) { // eslint-disable-next-line no-console console.error( - `ERROR: Invalid component declaration: ${invalidCustomComponentKeys} into 'src/custom_components/index.ts'. Their key must be declared using only lowercase and alphanumeric characters.`, + `ERROR: Invalid component declaration: ${invalidCustomComponentKeys} into 'src/components/custom/index.ts'. Their key must be declared using only lowercase and alphanumeric characters.`, ); } return hasFailed; diff --git a/src/ui/vite.config.custom.ts b/src/ui/vite.config.custom.ts index 2534e3385..6b092c704 100644 --- a/src/ui/vite.config.custom.ts +++ b/src/ui/vite.config.custom.ts @@ -14,7 +14,7 @@ export default defineConfig({ publicDir: false, build: { lib: { - entry: ["./src/custom_components"], + entry: ["./src/components/custom"], formats: ["umd"], name: "WriterCustomComponentTemplates", fileName: (format, entryalias: string): string => {