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,
},
}
}