+
{/if}
diff --git a/packages/client/src/components/Screen.svelte b/packages/client/src/components/Screen.svelte
index ac17556113..6a65e89afd 100644
--- a/packages/client/src/components/Screen.svelte
+++ b/packages/client/src/components/Screen.svelte
@@ -11,8 +11,11 @@
// Redirect to home page if no matching route
$: screenDefinition == null && routeStore.actions.navigate("/")
+
+ // Make a screen array so we can use keying to properly re-render each screen
+ $: screens = screenDefinition ? [screenDefinition] : []
-{#if screenDefinition}
-
-{/if}
+{#each screens as screen (screen._id)}
+
+{/each}
diff --git a/packages/client/src/index.js b/packages/client/src/index.js
index e925c3e273..2925e950f6 100644
--- a/packages/client/src/index.js
+++ b/packages/client/src/index.js
@@ -1,16 +1,22 @@
import ClientApp from "./components/ClientApp.svelte"
+import { builderStore } from "./store"
let app
const loadBudibase = () => {
- // Destroy old app if one exists
- if (app) {
- app.$destroy()
- }
- // Create new app
- app = new ClientApp({
- target: window.document.body,
+ // Update builder store with any builder flags
+ builderStore.set({
+ inBuilder: !!window["##BUDIBASE_IN_BUILDER##"],
+ page: window["##BUDIBASE_PREVIEW_PAGE##"],
+ screen: window["##BUDIBASE_PREVIEW_SCREEN##"],
})
+
+ // Create app if one hasn't been created yet
+ if (!app) {
+ app = new ClientApp({
+ target: window.document.body,
+ })
+ }
}
// Attach to window so the HTML template can call this when it loads
diff --git a/packages/client/src/store/builder.js b/packages/client/src/store/builder.js
new file mode 100644
index 0000000000..4b197596be
--- /dev/null
+++ b/packages/client/src/store/builder.js
@@ -0,0 +1,12 @@
+import { writable } from "svelte/store"
+
+const createBuilderStore = () => {
+ const initialState = {
+ inBuilder: false,
+ page: null,
+ screen: null,
+ }
+ return writable(initialState)
+}
+
+export const builderStore = createBuilderStore()
diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js
index a0683ba47e..4416ca809a 100644
--- a/packages/client/src/store/index.js
+++ b/packages/client/src/store/index.js
@@ -2,3 +2,4 @@ export { authStore } from "./auth"
export { routeStore } from "./routes"
export { screenStore } from "./screens"
export { createDataContextStore } from "./dataContext"
+export { builderStore } from "./builder"
diff --git a/packages/client/src/store/screens.js b/packages/client/src/store/screens.js
index a39a67e3d4..f19736756a 100644
--- a/packages/client/src/store/screens.js
+++ b/packages/client/src/store/screens.js
@@ -1,5 +1,6 @@
import { writable, derived } from "svelte/store"
import { routeStore } from "./routes"
+import { builderStore } from "./builder"
import * as API from "../api"
import { getAppId } from "../utils"
@@ -8,36 +9,37 @@ const createScreenStore = () => {
screens: [],
page: {},
})
- const store = derived([config, routeStore], ([$config, $routeStore]) => {
- const { screens, page } = $config
- const activeScreen =
- screens.length === 1
- ? screens[0]
- : screens.find(
+ const store = derived(
+ [config, routeStore, builderStore],
+ ([$config, $routeStore, $builderStore]) => {
+ let page
+ let activeScreen
+ if ($builderStore.inBuilder) {
+ // Use builder defined definitions if inside the builder preview
+ page = $builderStore.page
+ activeScreen = $builderStore.screen
+ } else {
+ // Otherwise find the correct screen by matching the current route
+ page = $config.page
+ const { screens } = $config
+ if (screens.length === 1) {
+ activeScreen = screens[0]
+ } else {
+ activeScreen = screens.find(
screen => screen.routing.route === $routeStore.activeRoute
)
- return {
- screens,
- page,
- activeScreen,
+ }
+ }
+ return { page, activeScreen }
}
- })
+ )
const fetchScreens = async () => {
- let screens
- let page
- const inBuilder = !!window["##BUDIBASE_IN_BUILDER##"]
- if (inBuilder) {
- // Load screen and page from the window object if in the builder
- screens = [window["##BUDIBASE_PREVIEW_SCREEN##"]]
- page = window["##BUDIBASE_PREVIEW_PAGE##"]
- } else {
- // Otherwise load from API
- const appDefinition = await API.fetchAppDefinition(getAppId())
- screens = appDefinition.screens
- page = appDefinition.page
- }
- config.set({ screens, page })
+ const appDefinition = await API.fetchAppDefinition(getAppId())
+ config.set({
+ screens: appDefinition.screens,
+ page: appDefinition.page,
+ })
}
return {
diff --git a/packages/client/src/utils/styleable.js b/packages/client/src/utils/styleable.js
index 8f1d7ac3e1..fa81308cb2 100644
--- a/packages/client/src/utils/styleable.js
+++ b/packages/client/src/utils/styleable.js
@@ -1,7 +1,13 @@
+import { getContext } from "svelte"
+import { get } from "svelte/store"
+
+/**
+ * Helper to build a CSS string from a style object
+ */
const buildStyleString = styles => {
let str = ""
Object.entries(styles).forEach(([style, value]) => {
- if (style && value) {
+ if (style && value != null) {
str += `${style}: ${value}; `
}
})
@@ -12,35 +18,52 @@ const buildStyleString = styles => {
* Svelte action to apply correct component styles.
*/
export const styleable = (node, styles = {}) => {
- const normalStyles = styles.normal || {}
- const hoverStyles = {
- ...normalStyles,
- ...styles.hover,
+ let applyNormalStyles
+ let applyHoverStyles
+
+ // Creates event listeners and applies initial styles
+ const setupStyles = newStyles => {
+ const normalStyles = newStyles.normal || {}
+ const hoverStyles = {
+ ...normalStyles,
+ ...newStyles.hover,
+ }
+
+ applyNormalStyles = () => {
+ node.style = buildStyleString(normalStyles)
+ }
+
+ applyHoverStyles = () => {
+ node.style = buildStyleString(hoverStyles)
+ }
+
+ // Add listeners to toggle hover styles
+ node.addEventListener("mouseover", applyHoverStyles)
+ node.addEventListener("mouseout", applyNormalStyles)
+ node.setAttribute("data-bb-id", newStyles.id)
+
+ // Apply initial normal styles
+ applyNormalStyles()
}
- function applyNormalStyles() {
- node.style = buildStyleString(normalStyles)
+ // Removes the current event listeners
+ const removeListeners = () => {
+ node.removeEventListener("mouseover", applyHoverStyles)
+ node.removeEventListener("mouseout", applyNormalStyles)
}
- function applyHoverStyles() {
- node.style = buildStyleString(hoverStyles)
- }
-
- // Add listeners to toggle hover styles
- node.addEventListener("mouseover", applyHoverStyles)
- node.addEventListener("mouseout", applyNormalStyles)
-
- // Apply normal styles initially
- applyNormalStyles()
-
- // Also apply data tags so we know how to reference each component
- node.setAttribute("data-bb-id", styles.id)
+ // Apply initial styles
+ setupStyles(styles)
return {
- // Clean up event listeners when component is destroyed
+ // Clean up old listeners and apply new ones on update
+ update: newStyles => {
+ removeListeners()
+ setupStyles(newStyles)
+ },
+ // Clean up listeners when component is destroyed
destroy: () => {
- node.removeEventListener("mouseover", applyHoverStyles)
- node.removeEventListener("mouseout", applyNormalStyles)
+ removeListeners()
},
}
}
diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte
index e23adf6c15..6dbbcfc4cf 100644
--- a/packages/standard-components/src/Button.svelte
+++ b/packages/standard-components/src/Button.svelte
@@ -9,7 +9,7 @@
export let text
-