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>
|
<script>
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
|
import { get } from "svelte/store"
|
||||||
import { store, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import iframeTemplate from "./iframeTemplate"
|
import iframeTemplate from "./iframeTemplate"
|
||||||
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
import { Screen } from "builderStore/store/screenTemplates/utils/Screen"
|
||||||
|
@ -7,6 +8,7 @@
|
||||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||||
import { ProgressCircle, Layout, Heading, Body } from "@budibase/bbui"
|
import { ProgressCircle, Layout, Heading, Body } from "@budibase/bbui"
|
||||||
import ErrorSVG from "assets/error.svg?raw"
|
import ErrorSVG from "assets/error.svg?raw"
|
||||||
|
import { findComponent } from "builderStore/storeUtils"
|
||||||
|
|
||||||
let iframe
|
let iframe
|
||||||
let layout
|
let layout
|
||||||
|
@ -111,6 +113,20 @@
|
||||||
// Wait for this event to show the client library if intelligent
|
// Wait for this event to show the client library if intelligent
|
||||||
// loading is supported
|
// loading is supported
|
||||||
loading = false
|
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 {
|
} else {
|
||||||
console.warning(`Client sent unknown event type: ${type}`)
|
console.warning(`Client sent unknown event type: ${type}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
|
import SelectionIndicator from "components/preview/SelectionIndicator.svelte"
|
||||||
import HoverIndicator from "components/preview/HoverIndicator.svelte"
|
import HoverIndicator from "components/preview/HoverIndicator.svelte"
|
||||||
import CustomThemeWrapper from "./CustomThemeWrapper.svelte"
|
import CustomThemeWrapper from "./CustomThemeWrapper.svelte"
|
||||||
|
import DNDHandler from "components/preview/DNDHandler.svelte"
|
||||||
import ErrorSVG from "../../../builder/assets/error.svg"
|
import ErrorSVG from "../../../builder/assets/error.svg"
|
||||||
|
|
||||||
// Provide contexts
|
// Provide contexts
|
||||||
|
@ -122,6 +123,7 @@
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
<SelectionIndicator />
|
<SelectionIndicator />
|
||||||
<HoverIndicator />
|
<HoverIndicator />
|
||||||
|
<DNDHandler />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</StateBindingsProvider>
|
</StateBindingsProvider>
|
||||||
|
|
|
@ -178,6 +178,7 @@
|
||||||
data-type={interactive ? "component" : ""}
|
data-type={interactive ? "component" : ""}
|
||||||
data-id={id}
|
data-id={id}
|
||||||
data-name={name}
|
data-name={name}
|
||||||
|
data-droppable={definition?.hasChildren || false}
|
||||||
>
|
>
|
||||||
<svelte:component this={constructor} {...componentSettings}>
|
<svelte:component this={constructor} {...componentSettings}>
|
||||||
{#if children.length}
|
{#if children.length}
|
||||||
|
@ -196,4 +197,7 @@
|
||||||
.component {
|
.component {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
.component > :global(*:hover) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
</style>
|
</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")
|
dispatchEvent("preview-loaded")
|
||||||
},
|
},
|
||||||
setSelectedPath: path => {
|
setSelectedPath: path => {
|
||||||
console.log("set to ")
|
|
||||||
console.log(path)
|
|
||||||
writableStore.update(state => {
|
writableStore.update(state => {
|
||||||
state.selectedPath = path
|
state.selectedPath = path
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
moveComponent: (componentId, destinationComponentId, mode) => {
|
||||||
|
dispatchEvent("move-component", {
|
||||||
|
componentId,
|
||||||
|
destinationComponentId,
|
||||||
|
mode,
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...writableStore,
|
...writableStore,
|
||||||
|
|
|
@ -23,6 +23,8 @@ export const styleable = (node, styles = {}) => {
|
||||||
let applyHoverStyles
|
let applyHoverStyles
|
||||||
let selectComponent
|
let selectComponent
|
||||||
|
|
||||||
|
node.setAttribute("draggable", true)
|
||||||
|
|
||||||
// Creates event listeners and applies initial styles
|
// Creates event listeners and applies initial styles
|
||||||
const setupStyles = (newStyles = {}) => {
|
const setupStyles = (newStyles = {}) => {
|
||||||
// Use empty state styles as base styles if required, but let them, get
|
// Use empty state styles as base styles if required, but let them, get
|
||||||
|
|
Loading…
Reference in New Issue