budibase/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte

154 lines
3.8 KiB
Svelte

<script>
import { Button, Icon, Drawer, Body } from "@budibase/bbui"
import { store, currentAsset } from "builderStore"
import {
getBindableProperties,
readableToRuntimeBinding,
runtimeToReadableBinding,
} from "builderStore/dataBinding"
import BindingPanel from "components/design/PropertiesPanel/BindingPanel.svelte"
export let label = ""
export let bindable = true
export let componentInstance = {}
export let control = null
export let key = ""
export let type = ""
export let value = null
export let props = {}
export let onChange = () => {}
let bindingDrawer
let temporaryBindableValue = value
let anchor
let valid
$: bindableProperties = getBindableProperties(
$currentAsset.props,
$store.selectedComponentId
)
$: safeValue = getSafeValue(value, props.defaultValue, bindableProperties)
$: replaceBindings = val => readableToRuntimeBinding(bindableProperties, val)
const handleClose = () => {
handleChange(temporaryBindableValue)
bindingDrawer.hide()
}
// Handle a value change of any type
// String values have any bindings handled
const handleChange = value => {
let innerVal = value
if (value && typeof value === "object") {
if ("detail" in value) {
innerVal = value.detail
} else if ("target" in value) {
innerVal = value.target.value
}
}
if (typeof innerVal === "string") {
onChange(replaceBindings(innerVal))
} else {
onChange(innerVal)
}
}
// The "safe" value is the value with eny bindings made readable
// If there is no value set, any default value is used
const getSafeValue = (value, defaultValue, bindableProperties) => {
const enriched = runtimeToReadableBinding(bindableProperties, value)
return enriched == null && defaultValue !== undefined
? defaultValue
: enriched
}
</script>
<div class="property-control" bind:this={anchor}>
<div class="label">{label}</div>
<div data-cy={`${key}-prop-control`} class="control">
<svelte:component
this={control}
{componentInstance}
value={safeValue}
on:change={handleChange}
onChange={handleChange}
{...props}
name={key} />
</div>
{#if bindable && !key.startsWith('_') && type === 'text'}
<div
class="icon"
data-cy={`${key}-binding-button`}
on:click={bindingDrawer.show}>
<Icon name="lightning" />
</div>
{/if}
</div>
<Drawer bind:this={bindingDrawer} title="Bindings">
<div slot="description">
<Body extraSmall grey>
Add the objects on the left to enrich your text.
</Body>
</div>
<heading slot="buttons">
<Button thin blue disabled={!valid} on:click={handleClose}>Save</Button>
</heading>
<div slot="body">
<BindingPanel
bind:valid
value={safeValue}
close={handleClose}
on:update={e => (temporaryBindableValue = e.detail)}
{bindableProperties} />
</div>
</Drawer>
<style>
.property-control {
position: relative;
display: flex;
flex-flow: row;
align-items: center;
}
.label {
display: flex;
align-items: center;
font-size: 12px;
font-weight: 400;
flex: 0 0 80px;
text-align: left;
color: var(--ink);
margin-right: auto;
text-transform: capitalize;
}
.control {
flex: 1;
display: flex;
padding-left: 2px;
overflow: hidden;
}
.icon {
right: 2px;
top: 2px;
bottom: 2px;
position: absolute;
align-items: center;
display: flex;
box-sizing: border-box;
padding-left: var(--spacing-xs);
border-left: 1px solid var(--grey-4);
background-color: var(--grey-2);
border-top-right-radius: var(--border-radius-m);
border-bottom-right-radius: var(--border-radius-m);
color: var(--grey-7);
font-size: 14px;
}
.icon:hover {
color: var(--ink);
cursor: pointer;
}
</style>