Add initial DND implementation with working functionality for dropping inside components
This commit is contained in:
parent
a8ba00e514
commit
0ce0f5c823
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import { get } from "svelte/store"
|
||||
import { store, currentAsset } from "builderStore"
|
||||
import iframeTemplate from "./iframeTemplate"
|
||||
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
||||
|
@ -7,6 +8,7 @@
|
|||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import { ProgressCircle, Layout, Heading, Body } from "@budibase/bbui"
|
||||
import ErrorSVG from "assets/error.svg?raw"
|
||||
import { findComponent } from "builderStore/storeUtils"
|
||||
|
||||
let iframe
|
||||
let layout
|
||||
|
@ -111,6 +113,20 @@
|
|||
// Wait for this event to show the client library if intelligent
|
||||
// loading is supported
|
||||
loading = false
|
||||
} else if (type === "move-component") {
|
||||
// Copy
|
||||
const sourceComponent = findComponent(
|
||||
get(currentAsset).props,
|
||||
data.componentId
|
||||
)
|
||||
const destinationComponent = findComponent(
|
||||
get(currentAsset).props,
|
||||
data.destinationComponentId
|
||||
)
|
||||
if (sourceComponent && destinationComponent) {
|
||||
store.actions.components.copy(sourceComponent, true)
|
||||
store.actions.components.paste(destinationComponent, data.mode)
|
||||
}
|
||||
} else {
|
||||
console.warning(`Client sent unknown event type: ${type}`)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
|
||||
import HoverIndicator from "components/preview/HoverIndicator.svelte"
|
||||
import CustomThemeWrapper from "./CustomThemeWrapper.svelte"
|
||||
import DNDHandler from "components/preview/DNDHandler.svelte"
|
||||
import ErrorSVG from "../../../builder/assets/error.svg"
|
||||
|
||||
// Provide contexts
|
||||
|
@ -122,6 +123,7 @@
|
|||
{#if $builderStore.inBuilder}
|
||||
<SelectionIndicator />
|
||||
<HoverIndicator />
|
||||
<DNDHandler />
|
||||
{/if}
|
||||
</div>
|
||||
</StateBindingsProvider>
|
||||
|
|
|
@ -178,6 +178,7 @@
|
|||
data-type={interactive ? "component" : ""}
|
||||
data-id={id}
|
||||
data-name={name}
|
||||
data-droppable={definition?.hasChildren || false}
|
||||
>
|
||||
<svelte:component this={constructor} {...componentSettings}>
|
||||
{#if children.length}
|
||||
|
@ -196,4 +197,7 @@
|
|||
.component {
|
||||
display: contents;
|
||||
}
|
||||
.component > :global(*:hover) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
<script>
|
||||
import { onMount } from "svelte"
|
||||
import IndicatorSet from "./IndicatorSet.svelte"
|
||||
import { builderStore } from "stores"
|
||||
|
||||
let dragTarget
|
||||
let dropTarget
|
||||
|
||||
// Callback when initially starting a drag on a draggable component
|
||||
const onDragStart = e => {
|
||||
dragTarget = e.target.dataset.componentId
|
||||
e.target.style.opacity = 0.5
|
||||
}
|
||||
|
||||
// Callback when drag stops (whether dropped or not)
|
||||
const onDragEnd = e => {
|
||||
// reset the transparency
|
||||
dragTarget = null
|
||||
e.target.style.opacity = ""
|
||||
dropTarget = null
|
||||
}
|
||||
|
||||
// Callback when on top of a component
|
||||
const onDragOver = e => {
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
// Callback when entering a potential drop target
|
||||
const onDragEnter = e => {
|
||||
const element = e.target.closest("[data-type='component']")
|
||||
if (element && element.dataset.droppable === "true") {
|
||||
dropTarget = element.dataset.id
|
||||
} else {
|
||||
dropTarget = null
|
||||
}
|
||||
}
|
||||
|
||||
// Callback when leaving a potential drop target.
|
||||
// Since we don't style our targets, we don't need to unset anything.
|
||||
const onDragLeave = () => {}
|
||||
|
||||
// Callback when dropping a drag on top of some component
|
||||
const onDrop = e => {
|
||||
e.preventDefault()
|
||||
|
||||
// Check if the target is droppable
|
||||
const element = e.target.closest("[data-type='component']")
|
||||
if (element && element.dataset.droppable === "true") {
|
||||
builderStore.actions.moveComponent(dragTarget, dropTarget, "inside")
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Events fired on the draggable target
|
||||
document.addEventListener("dragstart", onDragStart, false)
|
||||
document.addEventListener("dragend", onDragEnd, false)
|
||||
|
||||
// Events fired on the drop targets
|
||||
document.addEventListener("dragover", onDragOver, false)
|
||||
document.addEventListener("dragenter", onDragEnter, false)
|
||||
document.addEventListener("dragleave", onDragLeave, false)
|
||||
document.addEventListener("drop", onDrop, false)
|
||||
|
||||
return () => {
|
||||
// Events fired on the draggable target
|
||||
document.removeEventListener("dragstart", onDragStart, false)
|
||||
document.removeEventListener("dragend", onDragEnd, false)
|
||||
|
||||
// Events fired on the drop targets
|
||||
document.removeEventListener("dragover", onDragOver, false)
|
||||
document.removeEventListener("dragenter", onDragEnter, false)
|
||||
document.removeEventListener("dragleave", onDragLeave, false)
|
||||
document.removeEventListener("drop", onDrop, false)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<IndicatorSet
|
||||
componentId={dropTarget}
|
||||
color="var(--spectrum-global-color-static-red-600)"
|
||||
zIndex="930"
|
||||
transition
|
||||
/>
|
|
@ -64,13 +64,18 @@ const createBuilderStore = () => {
|
|||
dispatchEvent("preview-loaded")
|
||||
},
|
||||
setSelectedPath: path => {
|
||||
console.log("set to ")
|
||||
console.log(path)
|
||||
writableStore.update(state => {
|
||||
state.selectedPath = path
|
||||
return state
|
||||
})
|
||||
},
|
||||
moveComponent: (componentId, destinationComponentId, mode) => {
|
||||
dispatchEvent("move-component", {
|
||||
componentId,
|
||||
destinationComponentId,
|
||||
mode,
|
||||
})
|
||||
},
|
||||
}
|
||||
return {
|
||||
...writableStore,
|
||||
|
|
|
@ -23,6 +23,8 @@ export const styleable = (node, styles = {}) => {
|
|||
let applyHoverStyles
|
||||
let selectComponent
|
||||
|
||||
node.setAttribute("draggable", true)
|
||||
|
||||
// Creates event listeners and applies initial styles
|
||||
const setupStyles = (newStyles = {}) => {
|
||||
// Use empty state styles as base styles if required, but let them, get
|
||||
|
|
Loading…
Reference in New Issue