budibase/packages/builder/src/components/design/settings/controls/EditComponentPopover.svelte

144 lines
3.6 KiB
Svelte

<script>
import { Icon, Popover, Layout } from "@budibase/bbui"
import { store } from "builderStore"
import { cloneDeep } from "lodash/fp"
import { createEventDispatcher } from "svelte"
import ComponentSettingsSection from "../../../../pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte"
import { getContext } from "svelte"
export let anchor
export let componentInstance
export let componentBindings
export let bindings
export let parseSettings
export let disabled
const draggable = getContext("draggable")
const dispatch = createEventDispatcher()
let popover
let drawers = []
let open = false
// Auto hide the component when another item is selected
$: if (open && $draggable.selected !== componentInstance._id) {
popover.hide()
}
// Open automatically if the component is marked as selected
$: if (!open && $draggable.selected === componentInstance._id && popover) {
popover.show()
open = true
}
$: componentDef = store.actions.components.getDefinition(
componentInstance._component
)
$: parsedComponentDef = processComponentDefinitionSettings(componentDef)
const processComponentDefinitionSettings = componentDef => {
if (!componentDef) {
return {}
}
const clone = cloneDeep(componentDef)
if (typeof parseSettings === "function") {
clone.settings = parseSettings(clone.settings)
}
return clone
}
const updateSetting = async (setting, value) => {
const nestedComponentInstance = cloneDeep(componentInstance)
const patchFn = store.actions.components.updateComponentSetting(
setting.key,
value
)
patchFn(nestedComponentInstance)
dispatch("change", nestedComponentInstance)
}
const customPositionHandler = (anchorBounds, eleBounds, cfg) => {
let { left, top } = cfg
let percentageOffset = 30
// left-outside
left = anchorBounds.left - eleBounds.width - 18
// shift up from the anchor, if space allows
let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset
let defaultTop = anchorBounds.top - offsetPos
if (window.innerHeight - defaultTop < eleBounds.height) {
top = window.innerHeight - eleBounds.height - 5
} else {
top = anchorBounds.top - offsetPos
}
return { ...cfg, left, top }
}
</script>
<Icon
name="Settings"
hoverable
size="S"
on:click={() => {
if (!open) {
popover.show()
open = true
}
}}
/>
<Popover
bind:this={popover}
on:open={() => {
drawers = []
$draggable.actions.select(componentInstance._id)
}}
on:close={() => {
open = false
if ($draggable.selected === componentInstance._id) {
$draggable.actions.select()
}
}}
{anchor}
align="left-outside"
showPopover={drawers.length === 0}
clickOutsideOverride={drawers.length > 0}
maxHeight={600}
handlePostionUpdate={customPositionHandler}
>
<span class="popover-wrap">
<Layout noPadding noGap>
<slot name="header" />
<ComponentSettingsSection
includeHidden
{componentInstance}
componentDefinition={parsedComponentDef}
isScreen={false}
onUpdateSetting={updateSetting}
showSectionTitle={false}
showInstanceName={false}
{bindings}
{componentBindings}
on:drawerShow={e => {
drawers = [...drawers, e.detail]
}}
on:drawerHide={() => {
drawers = drawers.slice(0, -1)
}}
/>
</Layout>
</span>
</Popover>
<style>
.popover-wrap {
background-color: var(--spectrum-alias-background-color-primary);
}
</style>