2020-11-13 16:42:32 +01:00
|
|
|
<script>
|
2020-11-20 10:50:10 +01:00
|
|
|
import { getContext, setContext } from "svelte"
|
2020-11-24 10:31:54 +01:00
|
|
|
import { writable } from "svelte/store"
|
2020-11-18 20:18:18 +01:00
|
|
|
import * as ComponentLibrary from "@budibase/standard-components"
|
|
|
|
import Router from "./Router.svelte"
|
2021-01-21 11:41:30 +01:00
|
|
|
import { enrichProps, propsAreSame } from "../utils/componentProps"
|
2020-11-30 13:11:50 +01:00
|
|
|
import { bindingStore, builderStore } from "../store"
|
2020-11-13 16:42:32 +01:00
|
|
|
|
2020-11-17 13:08:24 +01:00
|
|
|
export let definition = {}
|
2021-01-21 11:41:30 +01:00
|
|
|
let componentProps = {}
|
2020-11-13 16:42:32 +01:00
|
|
|
|
2021-01-06 11:13:30 +01:00
|
|
|
// Get contexts
|
2020-11-25 19:43:58 +01:00
|
|
|
const dataContext = getContext("data")
|
2021-01-06 11:13:30 +01:00
|
|
|
const screenslotContext = getContext("screenslot")
|
2020-11-18 20:18:18 +01:00
|
|
|
|
2020-11-25 10:50:51 +01:00
|
|
|
// Create component context
|
|
|
|
const componentStore = writable({})
|
|
|
|
setContext("component", componentStore)
|
2020-11-17 13:08:24 +01:00
|
|
|
|
2020-11-20 10:50:10 +01:00
|
|
|
// Extract component definition info
|
2020-11-25 10:50:51 +01:00
|
|
|
$: constructor = getComponentConstructor(definition._component)
|
2020-11-24 10:31:54 +01:00
|
|
|
$: children = definition._children
|
2020-11-24 12:02:10 +01:00
|
|
|
$: id = definition._id
|
2020-11-25 19:43:58 +01:00
|
|
|
$: enrichedProps = enrichProps(definition, $dataContext, $bindingStore)
|
2021-01-21 11:41:30 +01:00
|
|
|
$: updateProps(enrichedProps)
|
2021-01-06 11:13:30 +01:00
|
|
|
$: styles = definition._styles
|
|
|
|
|
|
|
|
// Allow component selection in the builder preview if we're previewing a
|
|
|
|
// layout, or we're preview a screen and we're inside the screenslot
|
|
|
|
$: allowSelection =
|
|
|
|
$builderStore.previewType === "layout" || screenslotContext
|
2020-11-20 10:50:10 +01:00
|
|
|
|
2020-11-24 12:02:10 +01:00
|
|
|
// Update component context
|
2021-01-06 11:13:30 +01:00
|
|
|
$: componentStore.set({ id, styles: { ...styles, id, allowSelection } })
|
2020-11-25 10:50:51 +01:00
|
|
|
|
2021-01-21 11:41:30 +01:00
|
|
|
// Updates the component props.
|
|
|
|
// Most props are deeply compared so that svelte will only trigger reactive
|
|
|
|
// statements on props that have actually changed.
|
|
|
|
const updateProps = props => {
|
|
|
|
Object.keys(props).forEach(key => {
|
|
|
|
if (!propsAreSame(props[key], componentProps[key])) {
|
|
|
|
componentProps[key] = props[key]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-25 10:50:51 +01:00
|
|
|
// Gets the component constructor for the specified component
|
|
|
|
const getComponentConstructor = component => {
|
|
|
|
const split = component?.split("/")
|
|
|
|
const name = split?.[split.length - 1]
|
2021-01-12 21:00:35 +01:00
|
|
|
if (name === "screenslot" && $builderStore.previewType !== "layout") {
|
|
|
|
return Router
|
|
|
|
}
|
|
|
|
return ComponentLibrary[name]
|
2020-11-25 10:50:51 +01:00
|
|
|
}
|
2020-11-30 13:11:50 +01:00
|
|
|
|
|
|
|
// Returns a unique key to let svelte know when to remount components.
|
|
|
|
// If a component is selected we want to remount it every time any props
|
|
|
|
// change.
|
|
|
|
const getChildKey = childId => {
|
|
|
|
const selected = childId === $builderStore.selectedComponentId
|
|
|
|
return selected ? `${childId}-${$builderStore.previewId}` : childId
|
|
|
|
}
|
2020-11-13 16:42:32 +01:00
|
|
|
</script>
|
|
|
|
|
2020-11-17 13:08:24 +01:00
|
|
|
{#if constructor}
|
2021-01-21 11:41:30 +01:00
|
|
|
<svelte:component this={constructor} {...componentProps}>
|
2020-11-17 13:08:24 +01:00
|
|
|
{#if children && children.length}
|
2020-11-30 13:11:50 +01:00
|
|
|
{#each children as child (getChildKey(child._id))}
|
2020-11-17 13:08:24 +01:00
|
|
|
<svelte:self definition={child} />
|
|
|
|
{/each}
|
|
|
|
{/if}
|
|
|
|
</svelte:component>
|
2020-11-13 16:42:32 +01:00
|
|
|
{/if}
|