Use a container as the DND placeholder and use approx size when dragging into grids

This commit is contained in:
Andrew Kingston 2022-10-19 14:39:28 +01:00
parent 645235be96
commit 9a94e9da7c
9 changed files with 108 additions and 74 deletions

View File

@ -446,12 +446,7 @@ export const getFrontendStore = () => {
_id: Helpers.uuid(),
_component: definition.component,
_styles: {
normal: {
"grid-column-start": 1,
"grid-column-end": 2,
"grid-row-start": 1,
"grid-row-end": 2,
},
normal: {},
hover: {},
active: {},
},

View File

@ -87,10 +87,9 @@
"showSettingsBar": true,
"size": {
"width": 400,
"height": 100
"height": 200
},
"styles": [
"grid",
"padding",
"size",
"background",

View File

@ -35,6 +35,7 @@
export let isScreen = false
export let isBlock = false
export let parent = null
export let parentType = null
// Get parent contexts
const context = getContext("context")
@ -165,23 +166,35 @@
$: pad = pad || (interactive && hasChildren && inDndPath)
$: $dndIsDragging, (pad = false)
// We can apply additional styles automatically if required.
// One use case for this is ensuring grid children have proper styles to
// display properly inside a grid.
$: additionalStyles = getAdditionalStyles(
instance._styles?.normal || {},
parentType,
definition
)
// Compute overall styles
$: styles = {
...instance._styles,
normal: {
...instance._styles?.normal,
...additionalStyles,
},
custom: customCSS,
id,
empty: emptyState,
interactive,
draggable,
editable,
}
// Update component context
$: store.set({
id,
children: children.length,
styles: {
...instance._styles,
normal: {
...instance._styles?.normal,
...(selected ? $builderStore.gridStyles : null),
},
custom: customCSS,
id,
empty: emptyState,
interactive,
draggable,
editable,
},
styles,
empty: emptyState,
selected,
name,
@ -442,6 +455,54 @@
})
}
const getAdditionalStyles = (styles, parentType, definition) => {
let newStyles = {}
// Ensure grid styles are set
if (parentType?.endsWith("/grid")) {
newStyles = {
...newStyles,
overflow: "hidden",
width: "auto",
height: "auto",
}
// Guess rough grid size from definition size
let columns = 6
let rows = 4
if (definition.size?.width) {
columns = Math.round(definition.size.width / 100)
}
if (definition.size?.height) {
rows = Math.round(definition.size.height / 100)
}
// Ensure grid position styles are set
if (!styles["grid-column-start"]) {
newStyles["grid-column-start"] = 1
}
if (!styles["grid-column-end"]) {
newStyles["grid-column-end"] = columns + 1
}
if (!styles["grid-row-start"]) {
newStyles["grid-row-start"] = 1
}
if (!styles["grid-row-end"]) {
newStyles["grid-row-end"] = rows + 1
}
// Ensure grid end styles aren't before grid start styles
if (newStyles["grid-column-end"] <= newStyles["grid-column-start"]) {
newStyles["grid-column-end"] = newStyles["grid-column-start"] + 1
}
if (newStyles["grid-row-end"] <= newStyles["grid-row-start"]) {
newStyles["grid-row-end"] = newStyles["grid-row-start"] + 1
}
}
return newStyles
}
onMount(() => {
if (
$appStore.isDevApp &&
@ -450,6 +511,7 @@
componentStore.actions.registerInstance(id, {
component: instance._component,
getSettings: () => cachedSettings,
getStyles: () => styles,
getRawSettings: () => ({ ...staticSettings, ...dynamicSettings }),
getDataContext: () => get(context),
reload: () => initialise(instance, true),
@ -490,7 +552,11 @@
<ComponentPlaceholder />
{:else if children.length}
{#each children as child (child._id)}
<svelte:self instance={child} parent={id} />
<svelte:self
instance={child}
parent={id}
parentType={instance._component}
/>
{/each}
{:else if emptyState}
{#if isScreen}

View File

@ -1,33 +0,0 @@
<script>
import { dndBounds } from "stores"
import { DNDPlaceholderID } from "constants"
$: style = getStyle($dndBounds)
const getStyle = bounds => {
if (!bounds) {
return null
}
return `--height: ${bounds.height}px; --width: ${bounds.width}px;`
}
</script>
{#if style}
<div class="wrapper">
<div class="placeholder" id={DNDPlaceholderID} {style} />
</div>
{/if}
<style>
.wrapper {
overflow: hidden;
}
.placeholder {
display: block;
height: var(--height);
width: var(--width);
max-height: 100%;
max-width: 100%;
opacity: 0;
}
</style>

View File

@ -6,7 +6,8 @@
let left, top, height, width
const updatePosition = () => {
const node = document.getElementById(DNDPlaceholderID)
const node =
document.getElementsByClassName(DNDPlaceholderID)[0]?.childNodes[0]
if (!node) {
height = 0
width = 0

View File

@ -1,6 +1,6 @@
<script>
import { onMount, onDestroy } from "svelte"
import { builderStore, screenStore } from "stores"
import { builderStore, componentStore, screenStore } from "stores"
import { Utils } from "@budibase/frontend-core"
import { findComponentById } from "utils/components.js"
@ -157,16 +157,14 @@
return
}
const compDef = findComponentById(
$screenStore.activeScreen.props,
dragInfo.id
)
if (!compDef) {
const instance = componentStore.actions.getComponentInstance(dragInfo.id)
if (!instance) {
return
}
const styles = instance.getStyles()
const domGrid = getDOMNode(dragInfo.gridId)
if (domGrid) {
const getStyle = x => parseInt(compDef._styles.normal?.[x] || "0")
const getStyle = x => parseInt(styles?.normal?.[x] || "0")
dragInfo.grid = {
startX: e.clientX,
startY: e.clientY,

View File

@ -32,5 +32,4 @@ export const ActionTypes = {
}
export const DNDPlaceholderID = "dnd-placeholder"
export const DNDPlaceholderType = "dnd-placeholder"
export const ScreenslotType = "screenslot"

View File

@ -5,9 +5,8 @@ import { devToolsStore } from "./devTools"
import { screenStore } from "./screens"
import { builderStore } from "./builder"
import Router from "../components/Router.svelte"
import DNDPlaceholder from "../components/preview/DNDPlaceholder.svelte"
import * as AppComponents from "../components/app/index.js"
import { DNDPlaceholderType, ScreenslotType } from "../constants.js"
import { ScreenslotType } from "../constants.js"
const budibasePrefix = "@budibase/standard-components/"
@ -103,8 +102,6 @@ const createComponentStore = () => {
// Screenslot is an edge case
if (type === ScreenslotType) {
type = `${budibasePrefix}${type}`
} else if (type === DNDPlaceholderType) {
return {}
}
// Handle built-in components
@ -124,8 +121,6 @@ const createComponentStore = () => {
}
if (type === ScreenslotType) {
return Router
} else if (type === DNDPlaceholderType) {
return DNDPlaceholder
}
// Handle budibase components
@ -140,6 +135,10 @@ const createComponentStore = () => {
return customComponentManifest?.[type]?.Component
}
const getComponentInstance = id => {
return get(store).mountedComponents[id]
}
const registerCustomComponent = ({ Component, schema, version }) => {
if (!Component || !schema?.schema?.name || !version) {
return
@ -171,6 +170,7 @@ const createComponentStore = () => {
getComponentById,
getComponentDefinition,
getComponentConstructor,
getComponentInstance,
registerCustomComponent,
},
}

View File

@ -2,11 +2,11 @@ import { derived } from "svelte/store"
import { routeStore } from "./routes"
import { builderStore } from "./builder"
import { appStore } from "./app"
import { dndIndex, dndParent, dndIsNewComponent } from "./dnd.js"
import { dndIndex, dndParent, dndIsNewComponent, dndBounds } from "./dnd.js"
import { RoleUtils } from "@budibase/frontend-core"
import { findComponentById, findComponentParent } from "../utils/components.js"
import { Helpers } from "@budibase/bbui"
import { DNDPlaceholderID, DNDPlaceholderType } from "constants"
import { DNDPlaceholderID } from "constants"
const createScreenStore = () => {
const store = derived(
@ -17,6 +17,7 @@ const createScreenStore = () => {
dndParent,
dndIndex,
dndIsNewComponent,
dndBounds,
],
([
$appStore,
@ -25,6 +26,7 @@ const createScreenStore = () => {
$dndParent,
$dndIndex,
$dndIsNewComponent,
$dndBounds,
]) => {
let activeLayout, activeScreen
let screens
@ -79,8 +81,15 @@ const createScreenStore = () => {
// Insert placeholder component
const placeholder = {
_component: DNDPlaceholderID,
_id: DNDPlaceholderType,
_component: "@budibase/standard-components/container",
_id: DNDPlaceholderID,
_styles: {
normal: {
width: `${$dndBounds?.width || 666}px`,
height: `${$dndBounds?.height || 666}px`,
opacity: 0,
},
},
static: true,
}
let parent = findComponentById(activeScreen.props, $dndParent)