Allow grid DND without selecting components
This commit is contained in:
parent
0e63a403bc
commit
465d10a8be
|
@ -542,12 +542,11 @@ export const getFrontendStore = () => {
|
||||||
},
|
},
|
||||||
patch: async (patchFn, componentId, screenId) => {
|
patch: async (patchFn, componentId, screenId) => {
|
||||||
// Use selected component by default
|
// Use selected component by default
|
||||||
if (!componentId && !screenId) {
|
if (!componentId || !screenId) {
|
||||||
const state = get(store)
|
const state = get(store)
|
||||||
componentId = state.selectedComponentId
|
componentId = componentId || state.selectedComponentId
|
||||||
screenId = state.selectedScreenId
|
screenId = screenId || state.selectedScreenId
|
||||||
}
|
}
|
||||||
// Invalid if only a screen or component ID provided
|
|
||||||
if (!componentId || !screenId || !patchFn) {
|
if (!componentId || !screenId || !patchFn) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -902,13 +901,14 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateStyles: async styles => {
|
updateStyles: async (styles, id) => {
|
||||||
await store.actions.components.patch(component => {
|
const patchFn = component => {
|
||||||
component._styles.normal = {
|
component._styles.normal = {
|
||||||
...component._styles.normal,
|
...component._styles.normal,
|
||||||
...styles,
|
...styles,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
await store.actions.components.patch(patchFn, id)
|
||||||
},
|
},
|
||||||
updateCustomStyle: async style => {
|
updateCustomStyle: async style => {
|
||||||
await store.actions.components.patch(component => {
|
await store.actions.components.patch(component => {
|
||||||
|
|
|
@ -156,7 +156,7 @@
|
||||||
} else if (type === "update-prop") {
|
} else if (type === "update-prop") {
|
||||||
await store.actions.components.updateSetting(data.prop, data.value)
|
await store.actions.components.updateSetting(data.prop, data.value)
|
||||||
} else if (type === "update-styles") {
|
} else if (type === "update-styles") {
|
||||||
await store.actions.components.updateStyles(data.styles)
|
await store.actions.components.updateStyles(data.styles, data.id)
|
||||||
} else if (type === "delete-component" && data.id) {
|
} else if (type === "delete-component" && data.id) {
|
||||||
// Legacy type, can be deleted in future
|
// Legacy type, can be deleted in future
|
||||||
confirmDeleteComponent(data.id)
|
confirmDeleteComponent(data.id)
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
componentStore,
|
componentStore,
|
||||||
appStore,
|
appStore,
|
||||||
dndComponentPath,
|
dndComponentPath,
|
||||||
|
dndIsDragging,
|
||||||
} from "stores"
|
} from "stores"
|
||||||
import { Helpers } from "@budibase/bbui"
|
import { Helpers } from "@budibase/bbui"
|
||||||
import { getActiveConditions, reduceConditionActions } from "utils/conditions"
|
import { getActiveConditions, reduceConditionActions } from "utils/conditions"
|
||||||
|
@ -162,7 +163,7 @@
|
||||||
// nested layers. Only reset this when dragging stops.
|
// nested layers. Only reset this when dragging stops.
|
||||||
let pad = false
|
let pad = false
|
||||||
$: pad = pad || (interactive && hasChildren && inDndPath)
|
$: pad = pad || (interactive && hasChildren && inDndPath)
|
||||||
$: $builderStore.dragging, (pad = false)
|
$: $dndIsDragging, (pad = false)
|
||||||
|
|
||||||
// Update component context
|
// Update component context
|
||||||
$: store.set({
|
$: store.set({
|
||||||
|
|
|
@ -2,7 +2,13 @@
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import IndicatorSet from "./IndicatorSet.svelte"
|
import IndicatorSet from "./IndicatorSet.svelte"
|
||||||
import { builderStore, screenStore, dndStore, dndParent } from "stores"
|
import {
|
||||||
|
builderStore,
|
||||||
|
screenStore,
|
||||||
|
dndStore,
|
||||||
|
dndParent,
|
||||||
|
dndIsDragging,
|
||||||
|
} from "stores"
|
||||||
import DNDPlaceholderOverlay from "./DNDPlaceholderOverlay.svelte"
|
import DNDPlaceholderOverlay from "./DNDPlaceholderOverlay.svelte"
|
||||||
import { Utils } from "@budibase/frontend-core"
|
import { Utils } from "@budibase/frontend-core"
|
||||||
import { findComponentById } from "utils/components.js"
|
import { findComponentById } from "utils/components.js"
|
||||||
|
@ -49,7 +55,6 @@
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
dndStore.actions.reset()
|
dndStore.actions.reset()
|
||||||
builderStore.actions.setDragging(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback when initially starting a drag on a draggable component
|
// Callback when initially starting a drag on a draggable component
|
||||||
|
@ -85,7 +90,6 @@
|
||||||
index,
|
index,
|
||||||
})
|
})
|
||||||
builderStore.actions.selectComponent(id)
|
builderStore.actions.selectComponent(id)
|
||||||
builderStore.actions.setDragging(true)
|
|
||||||
|
|
||||||
// Set initial drop info to show placeholder exactly where the dragged
|
// Set initial drop info to show placeholder exactly where the dragged
|
||||||
// component is.
|
// component is.
|
||||||
|
@ -329,6 +333,6 @@
|
||||||
prefix="Inside"
|
prefix="Inside"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{#if $builderStore.dragging}
|
{#if $dndIsDragging}
|
||||||
<DNDPlaceholderOverlay />
|
<DNDPlaceholderOverlay />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import { builderStore, componentStore } from "stores"
|
import { builderStore, screenStore } from "stores"
|
||||||
import { Utils } from "@budibase/frontend-core"
|
import { Utils } from "@budibase/frontend-core"
|
||||||
|
import { findComponentById } from "utils/components.js"
|
||||||
|
|
||||||
let dragInfo
|
let dragInfo
|
||||||
let gridStyles
|
let gridStyles
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
const stopDragging = () => {
|
const stopDragging = () => {
|
||||||
// Save changes
|
// Save changes
|
||||||
if (gridStyles) {
|
if (gridStyles) {
|
||||||
builderStore.actions.updateStyles(gridStyles)
|
builderStore.actions.updateStyles(gridStyles, dragInfo.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset listener
|
// Reset listener
|
||||||
|
@ -43,7 +44,6 @@
|
||||||
// Reset state
|
// Reset state
|
||||||
dragInfo = null
|
dragInfo = null
|
||||||
gridStyles = null
|
gridStyles = null
|
||||||
builderStore.actions.setDragging(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback when initially starting a drag on a draggable component
|
// Callback when initially starting a drag on a draggable component
|
||||||
|
@ -84,8 +84,6 @@
|
||||||
mode,
|
mode,
|
||||||
side,
|
side,
|
||||||
}
|
}
|
||||||
// builderStore.actions.selectComponent(dragInfo.id)
|
|
||||||
// builderStore.actions.setDragging(true)
|
|
||||||
|
|
||||||
// Add event handler to clear all drag state when dragging ends
|
// Add event handler to clear all drag state when dragging ends
|
||||||
dragInfo.domTarget.addEventListener("dragend", stopDragging)
|
dragInfo.domTarget.addEventListener("dragend", stopDragging)
|
||||||
|
@ -98,7 +96,13 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const compDef = $componentStore.selectedComponent
|
const compDef = findComponentById(
|
||||||
|
$screenStore.activeScreen.props,
|
||||||
|
dragInfo.id
|
||||||
|
)
|
||||||
|
if (!compDef) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const domGrid = getDOMNode(dragInfo.gridId)
|
const domGrid = getDOMNode(dragInfo.gridId)
|
||||||
if (domGrid) {
|
if (domGrid) {
|
||||||
const getStyle = x => parseInt(compDef._styles.normal?.[x] || "0")
|
const getStyle = x => parseInt(compDef._styles.normal?.[x] || "0")
|
||||||
|
|
|
@ -1,14 +1,31 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, onDestroy } from "svelte"
|
import { onMount, onDestroy } from "svelte"
|
||||||
import IndicatorSet from "./IndicatorSet.svelte"
|
import IndicatorSet from "./IndicatorSet.svelte"
|
||||||
import { builderStore } from "stores"
|
import { builderStore, dndIsDragging } from "stores"
|
||||||
|
|
||||||
let componentId
|
let componentId
|
||||||
$: zIndex = componentId === $builderStore.selectedComponentId ? 900 : 920
|
$: zIndex = componentId === $builderStore.selectedComponentId ? 900 : 920
|
||||||
|
|
||||||
const onMouseOver = e => {
|
const onMouseOver = e => {
|
||||||
|
// Ignore if dragging
|
||||||
|
if (e.buttons > 0) {
|
||||||
|
console.log("ignore")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let newId
|
||||||
|
|
||||||
|
if (e.target.classList.contains("anchor")) {
|
||||||
|
// Handle resize anchors
|
||||||
|
newId = e.target.dataset.id
|
||||||
|
console.log("anchor", newId)
|
||||||
|
} else {
|
||||||
|
// Handle normal components
|
||||||
const element = e.target.closest(".interactive.component")
|
const element = e.target.closest(".interactive.component")
|
||||||
const newId = element?.dataset?.id
|
newId = element?.dataset?.id
|
||||||
|
console.log("normal", newId)
|
||||||
|
}
|
||||||
|
|
||||||
if (newId !== componentId) {
|
if (newId !== componentId) {
|
||||||
componentId = newId
|
componentId = newId
|
||||||
}
|
}
|
||||||
|
@ -30,8 +47,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<IndicatorSet
|
<IndicatorSet
|
||||||
componentId={$builderStore.dragging ? null : componentId}
|
componentId={$dndIsDragging ? null : componentId}
|
||||||
color="var(--spectrum-global-color-static-blue-200)"
|
color="var(--spectrum-global-color-static-blue-200)"
|
||||||
transition
|
transition
|
||||||
{zIndex}
|
{zIndex}
|
||||||
|
allowResizeAnchors
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -60,7 +60,9 @@
|
||||||
class="anchor {side}"
|
class="anchor {side}"
|
||||||
data-side={side}
|
data-side={side}
|
||||||
data-id={componentId}
|
data-id={componentId}
|
||||||
/>
|
>
|
||||||
|
<div class="anchor-inner" />
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -131,52 +133,61 @@
|
||||||
|
|
||||||
/* Anchor */
|
/* Anchor */
|
||||||
.anchor {
|
.anchor {
|
||||||
|
--size: 24px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 10px;
|
width: var(--size);
|
||||||
height: 10px;
|
height: var(--size);
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--color);
|
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.anchor-inner {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: white;
|
||||||
|
border: 2px solid var(--color);
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
.anchor.right {
|
.anchor.right {
|
||||||
right: -6px;
|
right: calc(var(--size) / -2 - 1px);
|
||||||
top: calc(50% - 5px);
|
top: calc(50% - var(--size) / 2);
|
||||||
cursor: e-resize;
|
cursor: e-resize;
|
||||||
}
|
}
|
||||||
.anchor.left {
|
.anchor.left {
|
||||||
left: -6px;
|
left: calc(var(--size) / -2 - 1px);
|
||||||
top: calc(50% - 5px);
|
top: calc(50% - var(--size) / 2);
|
||||||
cursor: w-resize;
|
cursor: w-resize;
|
||||||
}
|
}
|
||||||
.anchor.bottom {
|
.anchor.bottom {
|
||||||
left: calc(50% - 5px);
|
left: calc(50% - var(--size) / 2 + 1px);
|
||||||
bottom: -6px;
|
bottom: calc(var(--size) / -2 - 1px);
|
||||||
cursor: s-resize;
|
cursor: s-resize;
|
||||||
}
|
}
|
||||||
.anchor.top {
|
.anchor.top {
|
||||||
left: calc(50% - 5px);
|
left: calc(50% - var(--size) / 2 + 1px);
|
||||||
top: -6px;
|
top: calc(var(--size) / -2 - 1px);
|
||||||
cursor: n-resize;
|
cursor: n-resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.anchor.bottom-right {
|
.anchor.bottom-right {
|
||||||
right: -6px;
|
right: calc(var(--size) / -2 - 1px);
|
||||||
bottom: -6px;
|
bottom: calc(var(--size) / -2 - 1px);
|
||||||
cursor: se-resize;
|
cursor: se-resize;
|
||||||
}
|
}
|
||||||
.anchor.bottom-left {
|
.anchor.bottom-left {
|
||||||
left: -6px;
|
left: calc(var(--size) / -2 - 1px);
|
||||||
bottom: -6px;
|
bottom: calc(var(--size) / -2 - 1px);
|
||||||
cursor: sw-resize;
|
cursor: sw-resize;
|
||||||
}
|
}
|
||||||
.anchor.top-right {
|
.anchor.top-right {
|
||||||
right: -6px;
|
right: calc(var(--size) / -2 - 1px);
|
||||||
top: -6px;
|
top: calc(var(--size) / -2 - 1px);
|
||||||
cursor: ne-resize;
|
cursor: ne-resize;
|
||||||
}
|
}
|
||||||
.anchor.top-left {
|
.anchor.top-left {
|
||||||
left: -6px;
|
left: calc(var(--size) / -2 - 1px);
|
||||||
top: -6px;
|
top: calc(var(--size) / -2 - 1px);
|
||||||
cursor: nw-resize;
|
cursor: nw-resize;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import SettingsButton from "./SettingsButton.svelte"
|
import SettingsButton from "./SettingsButton.svelte"
|
||||||
import SettingsColorPicker from "./SettingsColorPicker.svelte"
|
import SettingsColorPicker from "./SettingsColorPicker.svelte"
|
||||||
import SettingsPicker from "./SettingsPicker.svelte"
|
import SettingsPicker from "./SettingsPicker.svelte"
|
||||||
import { builderStore, componentStore } from "stores"
|
import { builderStore, componentStore, dndIsDragging } from "stores"
|
||||||
import { domDebounce } from "utils/domDebounce"
|
import { domDebounce } from "utils/domDebounce"
|
||||||
|
|
||||||
const verticalOffset = 36
|
const verticalOffset = 36
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
let measured = false
|
let measured = false
|
||||||
|
|
||||||
$: definition = $componentStore.selectedComponentDefinition
|
$: definition = $componentStore.selectedComponentDefinition
|
||||||
$: showBar = definition?.showSettingsBar && !$builderStore.dragging
|
$: showBar = definition?.showSettingsBar && !$dndIsDragging
|
||||||
$: settings = getBarSettings(definition)
|
$: settings = getBarSettings(definition)
|
||||||
|
|
||||||
const getBarSettings = definition => {
|
const getBarSettings = definition => {
|
||||||
|
|
|
@ -19,7 +19,6 @@ const createBuilderStore = () => {
|
||||||
navigation: null,
|
navigation: null,
|
||||||
hiddenComponentIds: [],
|
hiddenComponentIds: [],
|
||||||
usedPlugins: null,
|
usedPlugins: null,
|
||||||
dragging: false,
|
|
||||||
|
|
||||||
// Legacy - allow the builder to specify a layout
|
// Legacy - allow the builder to specify a layout
|
||||||
layout: null,
|
layout: null,
|
||||||
|
@ -41,8 +40,8 @@ const createBuilderStore = () => {
|
||||||
updateProp: (prop, value) => {
|
updateProp: (prop, value) => {
|
||||||
dispatchEvent("update-prop", { prop, value })
|
dispatchEvent("update-prop", { prop, value })
|
||||||
},
|
},
|
||||||
updateStyles: styles => {
|
updateStyles: (styles, id) => {
|
||||||
dispatchEvent("update-styles", { styles })
|
dispatchEvent("update-styles", { styles, id })
|
||||||
},
|
},
|
||||||
keyDown: (key, ctrlKey) => {
|
keyDown: (key, ctrlKey) => {
|
||||||
dispatchEvent("key-down", { key, ctrlKey })
|
dispatchEvent("key-down", { key, ctrlKey })
|
||||||
|
@ -112,12 +111,6 @@ const createBuilderStore = () => {
|
||||||
// Notify the builder so we can reload component definitions
|
// Notify the builder so we can reload component definitions
|
||||||
dispatchEvent("reload-plugin")
|
dispatchEvent("reload-plugin")
|
||||||
},
|
},
|
||||||
setDragging: dragging => {
|
|
||||||
store.update(state => {
|
|
||||||
state.dragging = dragging
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...store,
|
...store,
|
||||||
|
|
|
@ -87,3 +87,4 @@ export const dndIsNewComponent = derived(
|
||||||
dndStore,
|
dndStore,
|
||||||
$dndStore => $dndStore.source?.newComponentType != null
|
$dndStore => $dndStore.source?.newComponentType != null
|
||||||
)
|
)
|
||||||
|
export const dndIsDragging = derived(dndStore, $dndStore => !!$dndStore.source)
|
||||||
|
|
|
@ -21,6 +21,7 @@ export {
|
||||||
dndParent,
|
dndParent,
|
||||||
dndBounds,
|
dndBounds,
|
||||||
dndIsNewComponent,
|
dndIsNewComponent,
|
||||||
|
dndIsDragging,
|
||||||
} from "./dnd"
|
} from "./dnd"
|
||||||
|
|
||||||
// Context stores are layered and duplicated, so it is not a singleton
|
// Context stores are layered and duplicated, so it is not a singleton
|
||||||
|
|
Loading…
Reference in New Issue