Move most grid specific logic into a dedicated file to avoid polluting rest of the codebase
This commit is contained in:
parent
dbfad2cb3a
commit
0ba00a5117
|
@ -103,7 +103,7 @@
|
|||
key: "props.cols",
|
||||
label: "Columns",
|
||||
control: Stepper,
|
||||
defaultValue: 12,
|
||||
defaultValue: 24,
|
||||
props: {
|
||||
min: 2,
|
||||
max: 50,
|
||||
|
@ -113,7 +113,7 @@
|
|||
key: "props.rows",
|
||||
label: "Rows",
|
||||
control: Stepper,
|
||||
defaultValue: 12,
|
||||
defaultValue: 24,
|
||||
props: {
|
||||
min: 2,
|
||||
max: 50,
|
||||
|
|
|
@ -1391,6 +1391,10 @@
|
|||
"width": 25,
|
||||
"height": 25
|
||||
},
|
||||
"grid": {
|
||||
"hAlign": "center",
|
||||
"vAlign": "center"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"type": "icon",
|
||||
|
@ -1704,6 +1708,10 @@
|
|||
"width": 260,
|
||||
"height": 143
|
||||
},
|
||||
"grid": {
|
||||
"hAlign": "center",
|
||||
"vAlign": "center"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"type": "text",
|
||||
|
@ -1737,6 +1745,10 @@
|
|||
"width": 400,
|
||||
"height": 100
|
||||
},
|
||||
"grid": {
|
||||
"hAlign": "stretch",
|
||||
"vAlign": "stretch"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"type": "text",
|
||||
|
@ -5240,6 +5252,10 @@
|
|||
"width": 300,
|
||||
"height": 120
|
||||
},
|
||||
"grid": {
|
||||
"hAlign": "center",
|
||||
"vAlign": "center"
|
||||
},
|
||||
"settings": [
|
||||
{
|
||||
"type": "text",
|
||||
|
|
|
@ -284,7 +284,7 @@
|
|||
visibility: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
@ -301,7 +301,7 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
@ -311,7 +311,7 @@
|
|||
}
|
||||
|
||||
#app-root {
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
|
|
@ -39,8 +39,7 @@
|
|||
getActionContextKey,
|
||||
getActionDependentContextKeys,
|
||||
} from "../utils/buttonActions.js"
|
||||
import { buildStyleString } from "utils/styleable.js"
|
||||
import { getBaseGridVars } from "utils/grid.js"
|
||||
import { gridLayout } from "utils/grid.js"
|
||||
|
||||
export let instance = {}
|
||||
export let isLayout = false
|
||||
|
@ -198,15 +197,18 @@
|
|||
$: currentTheme = $context?.device?.theme
|
||||
$: darkMode = !currentTheme?.includes("light")
|
||||
|
||||
// Build up full styles and split them into variables and non-variables
|
||||
$: baseStyles = getBaseStyles(definition, errorState)
|
||||
$: styles = {
|
||||
...baseStyles,
|
||||
$: normalStyles = {
|
||||
...instance._styles?.normal,
|
||||
...ephemeralStyles,
|
||||
}
|
||||
$: parsedStyles = parseStyles(styles)
|
||||
$: wrapperCSS = buildStyleString(parsedStyles.variables)
|
||||
$: gridMetadata = {
|
||||
id,
|
||||
interactive,
|
||||
styles: normalStyles,
|
||||
draggable,
|
||||
definition,
|
||||
errored: errorState,
|
||||
}
|
||||
|
||||
// Update component context
|
||||
$: store.set({
|
||||
|
@ -214,8 +216,7 @@
|
|||
children: children.length,
|
||||
styles: {
|
||||
...instance._styles,
|
||||
normal: parsedStyles.nonVariables,
|
||||
variables: parsedStyles.variables,
|
||||
normal: normalStyles,
|
||||
custom: customCSS,
|
||||
id,
|
||||
empty: emptyState,
|
||||
|
@ -615,31 +616,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
const handleWrapperClick = e => {
|
||||
e.stopPropagation()
|
||||
builderStore.actions.selectComponent(id)
|
||||
}
|
||||
|
||||
// Splits component styles into variables and non-variables
|
||||
const parseStyles = styles => {
|
||||
let variables = {}
|
||||
let nonVariables = {}
|
||||
for (let style of Object.keys(styles || {})) {
|
||||
const group = style.startsWith("--") ? variables : nonVariables
|
||||
group[style] = styles[style]
|
||||
}
|
||||
return { variables, nonVariables }
|
||||
}
|
||||
|
||||
// Generates any required base styles based on the component definition
|
||||
const getBaseStyles = (definition, errored = false) => {
|
||||
return {
|
||||
"--default-width": errored ? 500 : definition.size?.width || 100,
|
||||
"--default-height": errored ? 60 : definition.size?.height || 100,
|
||||
...getBaseGridVars(definition, errored),
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
// Register this component instance for external access
|
||||
if ($appStore.isDevApp) {
|
||||
|
@ -683,14 +659,11 @@
|
|||
class:parent={hasChildren}
|
||||
class:block={isBlock}
|
||||
class:error={errorState}
|
||||
class:fill={definition.grid?.fill}
|
||||
data-id={id}
|
||||
data-name={name}
|
||||
data-icon={icon}
|
||||
data-parent={$component.id}
|
||||
style={wrapperCSS}
|
||||
{draggable}
|
||||
on:click|self={interactive ? handleWrapperClick : null}
|
||||
use:gridLayout={gridMetadata}
|
||||
>
|
||||
{#if errorState}
|
||||
<ComponentErrorState
|
||||
|
|
|
@ -480,7 +480,7 @@
|
|||
position: relative;
|
||||
padding: 32px;
|
||||
}
|
||||
.main:has(> .grid) {
|
||||
.main:has(.screenslot-dom > .component > .grid) {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
|
|
@ -68,16 +68,6 @@
|
|||
position: relative;
|
||||
height: 400px;
|
||||
gap: 0;
|
||||
|
||||
/* Prevent cross-grid variable inheritance */
|
||||
/* --grid-desktop-col-start: initial;
|
||||
--grid-desktop-col-end: initial;
|
||||
--grid-desktop-row-start: initial;
|
||||
--grid-desktop-row-end: initial;
|
||||
--grid-mobile-col-start: initial;
|
||||
--grid-mobile-col-end: initial;
|
||||
--grid-mobile-row-start: initial;
|
||||
--grid-mobile-row-end: initial;*/
|
||||
}
|
||||
.grid,
|
||||
.underlay {
|
||||
|
@ -128,12 +118,8 @@
|
|||
);
|
||||
|
||||
/* Flex vars */
|
||||
--h-align: var(--grid-desktop-h-align, var(--grid-mobile-h-align, stretch));
|
||||
--v-align: var(--grid-desktop-v-align, var(--grid-mobile-v-align, center));
|
||||
--child-flex: var(
|
||||
--grid-desktop-child-flex,
|
||||
var(--grid-mobile-child-flex, 0 0 auto)
|
||||
);
|
||||
--h-align: var(--grid-desktop-h-align, var(--grid-mobile-h-align));
|
||||
--v-align: var(--grid-desktop-v-align, var(--grid-mobile-v-align));
|
||||
|
||||
/* Ensure grid metadata falls within limits */
|
||||
grid-column-start: min(max(1, var(--col-start)), var(--cols)) !important;
|
||||
|
@ -171,16 +157,20 @@
|
|||
);
|
||||
|
||||
/* Flex vars */
|
||||
--h-align: var(--grid-mobile-h-align, var(--grid-desktop-h-align, stretch));
|
||||
--v-align: var(--grid-mobile-v-align, var(--grid-desktop-v-align, center));
|
||||
--child-flex: var(
|
||||
--grid-mobile-child-flex,
|
||||
var(--grid-desktop-child-flex, 0 0 auto)
|
||||
);
|
||||
--h-align: var(--grid-mobile-h-align, var(--grid-desktop-h-align));
|
||||
--v-align: var(--grid-mobile-v-align, var(--grid-desktop-v-align));
|
||||
}
|
||||
|
||||
/* Handle grid children which need to fill the outer component wrapper */
|
||||
.grid :global(> .component > *) {
|
||||
flex: var(--child-flex) !important;
|
||||
flex: 0 0 auto !important;
|
||||
}
|
||||
.grid:not(.mobile) :global(> .component.grid-desktop-grow > *) {
|
||||
flex: 1 1 0 !important;
|
||||
height: 0 !important;
|
||||
}
|
||||
.grid.mobile :global(> .component.grid-mobile-grow > *) {
|
||||
flex: 1 1 0 !important;
|
||||
height: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
import { onMount, onDestroy } from "svelte"
|
||||
import { builderStore, componentStore } from "stores"
|
||||
import { Utils, memo } from "@budibase/frontend-core"
|
||||
import { isGridEvent, getGridParentID, getGridVar } from "utils/grid"
|
||||
import {
|
||||
isGridEvent,
|
||||
getGridParentID,
|
||||
gridCSSVars,
|
||||
GridVars,
|
||||
} from "utils/grid"
|
||||
|
||||
// Smallest possible 1x1 transparent GIF
|
||||
const ghost = new Image(1, 1)
|
||||
|
@ -15,10 +20,10 @@
|
|||
|
||||
// Grid CSS variables
|
||||
$: vars = {
|
||||
colStart: $getGridVar("col-start"),
|
||||
colEnd: $getGridVar("col-end"),
|
||||
rowStart: $getGridVar("row-start"),
|
||||
rowEnd: $getGridVar("row-end"),
|
||||
colStart: $gridCSSVars[GridVars.ColStart],
|
||||
colEnd: $gridCSSVars[GridVars.ColEnd],
|
||||
rowStart: $gridCSSVars[GridVars.RowStart],
|
||||
rowEnd: $gridCSSVars[GridVars.RowEnd],
|
||||
}
|
||||
|
||||
// Some memoisation of primitive types for performance
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import { builderStore, componentStore, dndIsDragging } from "stores"
|
||||
import { Utils } from "@budibase/frontend-core"
|
||||
import { findComponentParent } from "utils/components"
|
||||
import { getGridVar } from "utils/grid"
|
||||
import { gridCSSVars, GridVars } from "utils/grid"
|
||||
|
||||
const verticalOffset = 36
|
||||
const horizontalOffset = 2
|
||||
|
@ -44,8 +44,8 @@
|
|||
insideGrid &&
|
||||
(definition?.grid?.hAlign !== "stretch" ||
|
||||
definition?.grid?.vAlign !== "stretch")
|
||||
$: gridHAlignVar = $getGridVar("h-align")
|
||||
$: gridVAlignVar = $getGridVar("v-align")
|
||||
$: gridHAlignVar = $gridCSSVars[GridVars.HAlign]
|
||||
$: gridVAlignVar = $gridCSSVars[GridVars.VAlign]
|
||||
$: gridStyles = $state?.styles
|
||||
|
||||
const getBarSettings = definition => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { builderStore, componentStore } from "stores"
|
||||
import { derived, get, readable } from "svelte/store"
|
||||
import { builderStore } from "stores"
|
||||
import { derived } from "svelte/store"
|
||||
import { buildStyleString } from "utils/styleable.js"
|
||||
|
||||
/**
|
||||
* We use CSS variables on components to control positioning and layout of
|
||||
|
@ -12,20 +13,42 @@ import { derived, get, readable } from "svelte/store"
|
|||
* `grid.hAlign` and `grid.vAlign` keys in the manifest.
|
||||
*/
|
||||
|
||||
// Enum representing the different CSS variables we use for grid metadata
|
||||
export const GridVars = {
|
||||
HAlign: "h-align",
|
||||
VAlign: "v-align",
|
||||
ColStart: "col-start",
|
||||
ColEnd: "col-end",
|
||||
RowStart: "row-start",
|
||||
RowEnd: "row-end",
|
||||
}
|
||||
|
||||
// Classes used in selectors inside grid containers to control child styles
|
||||
export const GridClasses = {
|
||||
DesktopFill: "grid-desktop-grow",
|
||||
MobileFill: "grid-mobile-grow",
|
||||
}
|
||||
|
||||
// Enum for device preview type, included in grid CSS variables
|
||||
const Devices = {
|
||||
Desktop: "desktop",
|
||||
Mobile: "mobile",
|
||||
}
|
||||
|
||||
// Generates the CSS variable for a certain grid param suffix, for the current
|
||||
// device
|
||||
// A derived map of all CSS variables for the current device
|
||||
const previewDevice = derived(builderStore, $store => $store.previewDevice)
|
||||
export const getGridVar = derived(previewDevice, device => suffix => {
|
||||
const prefix = device === Devices.Mobile ? Devices.Mobile : Devices.Desktop
|
||||
return `--grid-${prefix}-${suffix}`
|
||||
export const gridCSSVars = derived(previewDevice, $device => {
|
||||
const device = $device === Devices.Mobile ? Devices.Mobile : Devices.Desktop
|
||||
let vars = {}
|
||||
for (let type of Object.values(GridVars)) {
|
||||
vars[type] = `--grid-${device}-${type}`
|
||||
}
|
||||
return vars
|
||||
})
|
||||
|
||||
// Builds a CSS variable name for a certain piece of grid metadata
|
||||
export const getGridCSSVar = (device, type) => `--grid-${device}-${type}`
|
||||
|
||||
// Generates the CSS variable for a certain grid param suffix, for the other
|
||||
// device variant than the one included in this variable
|
||||
export const getOtherDeviceGridVar = cssVar => {
|
||||
|
@ -69,21 +92,6 @@ export const getGridParentID = node => {
|
|||
return node?.parentNode?.closest(".grid")?.parentNode.dataset.id
|
||||
}
|
||||
|
||||
// Generates the base set of grid CSS vars from a component definition
|
||||
export const getBaseGridVars = (definition, errored = false) => {
|
||||
const hAlign = errored ? "stretch" : definition?.grid?.hAlign || "stretch"
|
||||
const vAlign = errored ? "stretch" : definition?.grid?.vAlign || "center"
|
||||
const flexStyles = vAlign === "stretch" ? "1 1 0" : "0 0 auto"
|
||||
return {
|
||||
"--grid-desktop-h-align": hAlign,
|
||||
"--grid-mobile-h-align": hAlign,
|
||||
"--grid-desktop-v-align": vAlign,
|
||||
"--grid-mobile-v-align": vAlign,
|
||||
"--grid-desktop-child-flex": flexStyles,
|
||||
"--grid-mobile-child-flex": flexStyles,
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the current value of a certain grid CSS variable for a component
|
||||
export const getGridVarValue = (styles, variable) => {
|
||||
// Try the desired variable
|
||||
|
@ -97,3 +105,73 @@ export const getGridVarValue = (styles, variable) => {
|
|||
// Otherwise use the default
|
||||
return val ? val : getDefaultGridVarValue(variable)
|
||||
}
|
||||
|
||||
// Svelte action to apply required class names and styles to our component
|
||||
// wrappers
|
||||
export const gridLayout = (node, metadata) => {
|
||||
let selectComponent
|
||||
|
||||
const applyMetadata = metadata => {
|
||||
const { id, styles, interactive, errored, definition } = metadata
|
||||
consol.log(styles)
|
||||
|
||||
// Callback to select the component when clicking on the wrapper
|
||||
selectComponent = e => {
|
||||
e.preventDefault()
|
||||
builderStore.actions.selectComponent(id)
|
||||
}
|
||||
|
||||
// Generate base set of grid CSS vars based for this component
|
||||
const hAlign = errored ? "stretch" : definition?.grid?.hAlign || "stretch"
|
||||
const vAlign = errored ? "stretch" : definition?.grid?.vAlign || "center"
|
||||
const vars = {
|
||||
"--default-width": errored ? 500 : definition.size?.width || 100,
|
||||
"--default-height": errored ? 60 : definition.size?.height || 100,
|
||||
"--grid-desktop-h-align": hAlign,
|
||||
"--grid-mobile-h-align": hAlign,
|
||||
"--grid-desktop-v-align": vAlign,
|
||||
"--grid-mobile-v-align": vAlign,
|
||||
}
|
||||
|
||||
// Extract any other CSS variables from the saved component styles
|
||||
for (let style of Object.keys(styles)) {
|
||||
if (style.startsWith("--")) {
|
||||
vars[style] = styles[style]
|
||||
delete styles[style]
|
||||
}
|
||||
}
|
||||
|
||||
// Apply all CSS variables to the wrapper
|
||||
node.style = buildStyleString(vars)
|
||||
|
||||
// Toggle classes to specify whether our children should fill
|
||||
const desktopVar = getGridCSSVar(Devices.Desktop, GridVars.VAlign)
|
||||
const mobileVar = getGridCSSVar(Devices.Mobile, GridVars.VAlign)
|
||||
node.classList.toggle(
|
||||
GridClasses.DesktopFill,
|
||||
vars[desktopVar] === "stretch"
|
||||
)
|
||||
node.classList.toggle(GridClasses.MobileFill, vars[mobileVar] === "stretch")
|
||||
|
||||
// Add a listener to select this node on click
|
||||
if (interactive) {
|
||||
node.addEventListener("click", selectComponent, false)
|
||||
}
|
||||
}
|
||||
|
||||
const removeListeners = () => {
|
||||
node.removeEventListener("click", selectComponent)
|
||||
}
|
||||
|
||||
applyMetadata(metadata)
|
||||
|
||||
return {
|
||||
update(newMetadata) {
|
||||
removeListeners()
|
||||
applyMetadata(newMetadata)
|
||||
},
|
||||
destroy() {
|
||||
removeListeners()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue