diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index c883dd4206..64b1712b89 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -85,18 +85,8 @@ builderStore.actions.notifyLoaded() } }) - - // TODO: remove. this is a test to render the first custom component - console.log(window["##BUDIBASE_CUSTOM_COMPONENTS##"]?.[0]) - const custom = window["##BUDIBASE_CUSTOM_COMPONENTS##"]?.[0]?.Component -{#if custom} -
- -
-{/if} - {#if dataLoaded}
import { getContext, setContext, onMount, onDestroy } from "svelte" import { writable, get } from "svelte/store" - import * as AppComponents from "components/app" - import Router from "./Router.svelte" import { enrichProps, propsAreSame, @@ -180,7 +178,7 @@ // Pull definition and constructor const component = instance._component - constructor = getComponentConstructor(component) + constructor = componentStore.actions.getComponentConstructor(component) definition = componentStore.actions.getComponentDefinition(component) if (!definition) { return @@ -237,16 +235,6 @@ }) } - // Gets the component constructor for the specified component - const getComponentConstructor = component => { - const split = component?.split("/") - const name = split?.[split.length - 1] - if (name === "screenslot" && !insideScreenslot) { - return Router - } - return AppComponents[name] - } - const getSettingsDefinitionMap = settingsDefinition => { let map = {} settingsDefinition?.forEach(setting => { diff --git a/packages/client/src/components/Screen.svelte b/packages/client/src/components/Screen.svelte index 3ec8d1ea52..12e6803aea 100644 --- a/packages/client/src/components/Screen.svelte +++ b/packages/client/src/components/Screen.svelte @@ -13,7 +13,22 @@ $: routeStore.actions.setRouteParams(params || {}) // Get the screen definition for the current route - $: screenDefinition = $screenStore.activeScreen?.props + $: screenDefinition = getScreenDefinition($screenStore.activeScreen?.props) + + const getScreenDefinition = definition => { + const test = { + _component: "test", + _id: "asfdasdfefgerdgrfdg", + _styles: { + normal: {}, + }, + text: "This is a text prop!", + } + return { + ...definition, + _children: [...definition._children, test], + } + } onMount(() => { // Mark the router as loaded whenever the screen mounts diff --git a/packages/client/src/index.js b/packages/client/src/index.js index c88afe59ba..32b242bc69 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -1,5 +1,5 @@ import ClientApp from "./components/ClientApp.svelte" -import { builderStore, appStore, devToolsStore } from "./stores" +import { componentStore, builderStore, appStore, devToolsStore } from "./stores" import loadSpectrumIcons from "@budibase/bbui/spectrum-icons-rollup.js" import { get } from "svelte/store" @@ -38,6 +38,13 @@ const loadBudibase = () => { const enableDevTools = !get(builderStore).inBuilder && get(appStore).isDevApp devToolsStore.actions.setEnabled(enableDevTools) + // Register any custom components + if (window["##BUDIBASE_CUSTOM_COMPONENTS##"]) { + window["##BUDIBASE_CUSTOM_COMPONENTS##"].forEach(component => { + componentStore.actions.registerCustomComponent(component) + }) + } + // Create app if one hasn't been created yet if (!app) { app = new ClientApp({ diff --git a/packages/client/src/stores/components.js b/packages/client/src/stores/components.js index a7426113e2..2500ea2a41 100644 --- a/packages/client/src/stores/components.js +++ b/packages/client/src/stores/components.js @@ -4,6 +4,10 @@ import { findComponentById, findComponentPathById } from "../utils/components" import { devToolsStore } from "./devTools" import { screenStore } from "./screens" import { builderStore } from "./builder" +import Router from "../components/Router.svelte" +import * as AppComponents from "../components/app/index.js" + +const budibasePrefix = "@budibase/standard-components/" const createComponentStore = () => { const store = writable({}) @@ -34,6 +38,7 @@ const createComponentStore = () => { findComponentPathById(asset?.props, selectedComponentId) || [] return { + customComponentManifest: $store.customComponentManifest, selectedComponentInstance: $store[selectedComponentId], selectedComponent: component, selectedComponentDefinition: definition, @@ -68,9 +73,60 @@ const createComponentStore = () => { } const getComponentDefinition = type => { - const prefix = "@budibase/standard-components/" - type = type?.replace(prefix, "") - return type ? Manifest[type] : null + if (!type) { + return null + } + + // Screenslot is an edge case + if (type === "screenslot") { + type = `${budibasePrefix}${type}` + } + + // Handle built-in components + if (type.startsWith(budibasePrefix)) { + type = type.replace(budibasePrefix, "") + return type ? Manifest[type] : null + } + + // Handle custom components + const { customComponentManifest } = get(store) + return customComponentManifest?.[type]?.schema?.schema + } + + const getComponentConstructor = type => { + if (!type) { + return null + } + if (type === "screenslot") { + return Router + } + + // Handle budibase components + if (type.startsWith(budibasePrefix)) { + const split = type.split("/") + const name = split[split.length - 1] + return AppComponents[name] + } + + // Handle custom components + const { customComponentManifest } = get(store) + return customComponentManifest?.[type]?.Component + } + + const registerCustomComponent = ({ Component, schema }) => { + if (!Component || !schema?.schema?.name) { + return + } + store.update(state => { + if (!state.customComponentManifest) { + state.customComponentManifest = {} + } + state.customComponentManifest[schema.schema.name] = { + schema, + Component, + } + return state + }) } return { @@ -81,6 +137,8 @@ const createComponentStore = () => { isComponentRegistered, getComponentById, getComponentDefinition, + getComponentConstructor, + registerCustomComponent, }, } }