diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte index 94a303ead4..0ce9e096f2 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPreview.svelte @@ -132,8 +132,8 @@ hoverStore.hover(data.id, false) } else if (type === "update-prop") { await componentStore.updateSetting(data.prop, data.value) - } else if (type === "update-meta-styles") { - await componentStore.updateMetaStyles(data.styles, data.id) + } else if (type === "update-styles") { + await componentStore.updateStyles(data.styles, data.id) } else if (type === "delete-component" && data.id) { // Legacy type, can be deleted in future confirmDeleteComponent(data.id) diff --git a/packages/builder/src/stores/builder/components.js b/packages/builder/src/stores/builder/components.js index a35169a646..c281c73dfe 100644 --- a/packages/builder/src/stores/builder/components.js +++ b/packages/builder/src/stores/builder/components.js @@ -64,7 +64,6 @@ export class ComponentStore extends BudiStore { this.moveDown = this.moveDown.bind(this) this.updateStyle = this.updateStyle.bind(this) this.updateStyles = this.updateStyles.bind(this) - this.updateMetaStyles = this.updateMetaStyles.bind(this) this.updateCustomStyle = this.updateCustomStyle.bind(this) this.updateConditions = this.updateConditions.bind(this) this.requestEjectBlock = this.requestEjectBlock.bind(this) @@ -979,16 +978,6 @@ export class ComponentStore extends BudiStore { await this.patch(patchFn, id) } - async updateMetaStyles(styles, id) { - const patchFn = component => { - component._styles.meta = { - ...component._styles.meta, - ...styles, - } - } - await this.patch(patchFn, id) - } - async updateCustomStyle(style) { await this.patch(component => { component._styles.custom = style diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 8231c0005f..1c18fd4801 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -118,7 +118,9 @@ "height": 200 }, "grid": { - "fill": true + "hAlign": "stretch", + "vAlign": "stretch", + "showControls": false }, "styles": ["padding", "size", "background", "border", "shadow"], "settings": [ @@ -2790,6 +2792,10 @@ "width": 400, "height": 400 }, + "grid": { + "hAlign": "stretch", + "vAlign": "stretch" + }, "settings": [ { "type": "select", @@ -6915,6 +6921,10 @@ "width": 400, "height": 400 }, + "grid": { + "hAlign": "stretch", + "vAlign": "start" + }, "settings": [ { "type": "table", @@ -7256,6 +7266,11 @@ "width": 600, "height": 400 }, + "grid": { + "hAlign": "stretch", + "vAlign": "stretch", + "showControls": false + }, "settings": [ { "type": "dataSource", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 340cc6e577..771cb8b0e6 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -40,6 +40,7 @@ getActionDependentContextKeys, } from "../utils/buttonActions.js" import { buildStyleString } from "utils/styleable.js" + import { getBaseGridVars } from "utils/grid.js" export let instance = {} export let isLayout = false @@ -103,7 +104,7 @@ let settingsDefinitionMap let missingRequiredSettings = false - // Temporary meta styles which can be added in the app preview for things like + // Temporary styles which can be added in the app preview for things like // DND. We clear these whenever a new instance is received. let ephemeralStyles @@ -197,14 +198,14 @@ $: currentTheme = $context?.device?.theme $: darkMode = !currentTheme?.includes("light") - // Build meta styles and stringify to apply to the wrapper node - $: definitionMetaStyles = getDefinitonMetaStyles(definition) - $: metaStyles = { - ...definitionMetaStyles, - ...instance._styles?.meta, + // Build up full styles and split them into variables and non-variables + $: baseStyles = getBaseStyles(definition) + $: parsedStyles = parseStyles({ + ...baseStyles, + ...instance._styles?.normal, ...ephemeralStyles, - } - $: metaCSS = buildStyleString(metaStyles) + }) + $: wrapperCSS = buildStyleString(parsedStyles.variables) // Update component context $: store.set({ @@ -212,7 +213,7 @@ children: children.length, styles: { ...instance._styles, - meta: metaStyles, + normal: parsedStyles.nonVariables, custom: customCSS, id, empty: emptyState, @@ -612,7 +613,7 @@ } } - const select = e => { + const handleWrapperClick = e => { if (isBlock) { return } @@ -620,19 +621,21 @@ builderStore.actions.selectComponent(id) } - // Util to generate meta styles based on component definition - const alignToStyleMap = { - start: "flex-start", - center: "center", - end: "flex-end", - stretch: "stretch", + // 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 } } - const getDefinitonMetaStyles = definition => { - const gridHAlign = definition.grid?.hAlign || "stretch" - const gridVAlign = definition.grid?.vAlign || "center" + + // Generates any required base styles based on the component definition + const getBaseStyles = definition => { return { - ["align-items"]: alignToStyleMap[gridHAlign], - ["justify-content"]: alignToStyleMap[gridVAlign], + ...getBaseGridVars(definition), } } @@ -684,9 +687,9 @@ data-name={name} data-icon={icon} data-parent={$component.id} - style={metaCSS} + style={wrapperCSS} {draggable} - on:click={select} + on:click={handleWrapperClick} > {#if errorState} .component) { display: flex; overflow: hidden; - flex-direction: column; - justify-content: center; - align-items: stretch; /* On desktop, use desktop metadata and fall back to mobile */ + /* Position vars */ --col-start: var(--grid-desktop-col-start, var(--grid-mobile-col-start, 1)); --col-end: var(--grid-desktop-col-end, var(--grid-mobile-col-end, 2)); --row-start: var(--grid-desktop-row-start, var(--grid-mobile-row-start, 1)); --row-end: var(--grid-desktop-row-end, var(--grid-mobile-row-end, 2)); + /* 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) + ); + /* Ensure grid metadata falls within limits */ grid-column-start: min(max(1, var(--col-start)), var(--cols)) !important; grid-column-end: min( @@ -114,20 +120,32 @@ ) !important; grid-row-start: min(max(1, var(--row-start)), var(--rows)) !important; grid-row-end: min(max(2, var(--row-end)), calc(var(--rows) + 1)) !important; + + /* Flex container styles */ + flex-direction: column; + align-items: var(--h-align); + justify-content: var(--v-align); } /* On mobile, use mobile metadata and fall back to desktop */ .grid.mobile :global(> .component) { + /* Position vars */ --col-start: var(--grid-mobile-col-start, var(--grid-desktop-col-start, 1)); --col-end: var(--grid-mobile-col-end, var(--grid-desktop-col-end, 2)); --row-start: var(--grid-mobile-row-start, var(--grid-desktop-row-start, 1)); --row-end: var(--grid-mobile-row-end, var(--grid-desktop-row-end, 2)); + + /* 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) + ); } /* Handle grid children which need to fill the outer component wrapper */ - .grid :global(> .component.fill > *) { - width: 100%; - height: 100%; - flex: 1 1 0; + .grid :global(> .component > *) { + flex: var(--child-flex) !important; } diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 4a3f698703..41e3ea4a2f 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -2,53 +2,20 @@ import { onMount, onDestroy } from "svelte" import { builderStore, componentStore } from "stores" import { Utils, memo } from "@budibase/frontend-core" - import { isGridEvent, getGridParentID } from "utils/grid" + import { + isGridEvent, + getGridParentID, + getGridVar, + getDefaultGridVarValue, + getOtherDeviceGridVar, + } from "utils/grid" - // Enum for device preview type, included in CSS variables - const Devices = { - Desktop: "desktop", - Mobile: "mobile", - } - - // Generates the CSS variable for a certain grid param suffix, for the current - // device - const getCSSVar = suffix => { - const device = - $builderStore.previewDevice === Devices.Mobile - ? Devices.Mobile - : Devices.Desktop - return `--grid-${device}-${suffix}` - } - - // Generates the CSS variable for a certain grid param suffix, for the other - // device variant than the one included in this variable - const getOtherDeviceCSSVar = cssVar => { - if (cssVar.includes(Devices.Desktop)) { - return cssVar.replace(Devices.Desktop, Devices.Mobile) - } else { - return cssVar.replace(Devices.Mobile, Devices.Desktop) - } - } - - // Gets the default value for a certain grid CSS variable - const getDefaultValue = cssVar => { - return cssVar.endsWith("-start") ? 1 : 2 - } - - // Enums for our grid CSS variables, for the current device - const Vars = { - get ColStart() { - return getCSSVar("col-start") - }, - get ColEnd() { - return getCSSVar("col-end") - }, - get RowStart() { - return getCSSVar("row-start") - }, - get RowEnd() { - return getCSSVar("row-end") - }, + // Grid CSS variables + $: vars = { + colStart: $getGridVar("col-start"), + colEnd: $getGridVar("col-end"), + rowStart: $getGridVar("row-start"), + rowEnd: $getGridVar("row-end"), } let dragInfo @@ -97,34 +64,34 @@ deltaX = minMax(deltaX, 1 - colStart, cols + 1 - colEnd) deltaY = minMax(deltaY, 1 - rowStart, rows + 1 - rowEnd) const newStyles = { - [Vars.ColStart]: colStart + deltaX, - [Vars.ColEnd]: colEnd + deltaX, - [Vars.RowStart]: rowStart + deltaY, - [Vars.RowEnd]: rowEnd + deltaY, + [vars.colStart]: colStart + deltaX, + [vars.colEnd]: colEnd + deltaX, + [vars.rowStart]: rowStart + deltaY, + [vars.rowEnd]: rowEnd + deltaY, } gridStyles.set(newStyles) } else if (mode === "resize") { let newStyles = {} if (side === "right") { - newStyles[Vars.ColEnd] = Math.max(colEnd + deltaX, colStart + 1) + newStyles[vars.colEnd] = Math.max(colEnd + deltaX, colStart + 1) } else if (side === "left") { - newStyles[Vars.ColStart] = Math.min(colStart + deltaX, colEnd - 1) + newStyles[vars.colStart] = Math.min(colStart + deltaX, colEnd - 1) } else if (side === "top") { - newStyles[Vars.RowStart] = Math.min(rowStart + deltaY, rowEnd - 1) + newStyles[vars.rowStart] = Math.min(rowStart + deltaY, rowEnd - 1) } else if (side === "bottom") { - newStyles[Vars.RowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) + newStyles[vars.rowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) } else if (side === "bottom-right") { - newStyles[Vars.ColEnd] = Math.max(colEnd + deltaX, colStart + 1) - newStyles[Vars.RowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) + newStyles[vars.colEnd] = Math.max(colEnd + deltaX, colStart + 1) + newStyles[vars.rowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) } else if (side === "bottom-left") { - newStyles[Vars.ColStart] = Math.min(colStart + deltaX, colEnd - 1) - newStyles[Vars.RowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) + newStyles[vars.colStart] = Math.min(colStart + deltaX, colEnd - 1) + newStyles[vars.rowEnd] = Math.max(rowEnd + deltaY, rowStart + 1) } else if (side === "top-right") { - newStyles[Vars.ColEnd] = Math.max(colEnd + deltaX, colStart + 1) - newStyles[Vars.RowStart] = Math.min(rowStart + deltaY, rowEnd - 1) + newStyles[vars.colEnd] = Math.max(colEnd + deltaX, colStart + 1) + newStyles[vars.rowStart] = Math.min(rowStart + deltaY, rowEnd - 1) } else if (side === "top-left") { - newStyles[Vars.ColStart] = Math.min(colStart + deltaX, colEnd - 1) - newStyles[Vars.RowStart] = Math.min(rowStart + deltaY, rowEnd - 1) + newStyles[vars.colStart] = Math.min(colStart + deltaX, colEnd - 1) + newStyles[vars.rowStart] = Math.min(rowStart + deltaY, rowEnd - 1) } gridStyles.set(newStyles) } @@ -197,20 +164,21 @@ const getCurrent = cssVar => { let style = styles?.getPropertyValue(cssVar) if (!style) { - style = styles?.getPropertyValue(getOtherDeviceCSSVar(cssVar)) + style = styles?.getPropertyValue(getOtherDeviceGridVar(cssVar)) } - return parseInt(style || getDefaultValue(cssVar)) + return parseInt(style || getDefaultGridVarValue(cssVar)) } dragInfo.grid = { startX: e.clientX, startY: e.clientY, // Ensure things are within limits - rowStart: minMax(getCurrent(Vars.RowStart), 1, gridRows), - rowEnd: minMax(getCurrent(Vars.RowEnd), 2, gridRows + 1), - colStart: minMax(getCurrent(Vars.ColStart), 1, gridCols), - colEnd: minMax(getCurrent(Vars.ColEnd), 2, gridCols + 1), + rowStart: minMax(getCurrent(vars.rowStart), 1, gridRows), + rowEnd: minMax(getCurrent(vars.rowEnd), 2, gridRows + 1), + colStart: minMax(getCurrent(vars.colStart), 1, gridCols), + colEnd: minMax(getCurrent(vars.colEnd), 2, gridCols + 1), } + console.log(dragInfo.grid) handleEvent(e) } } @@ -226,7 +194,7 @@ const stopDragging = async () => { // Save changes if ($gridStyles) { - await builderStore.actions.updateMetaStyles($gridStyles, dragInfo.id) + await builderStore.actions.updateStyles($gridStyles, dragInfo.id) } // Reset listener diff --git a/packages/client/src/components/preview/GridStylesButton.svelte b/packages/client/src/components/preview/GridStylesButton.svelte new file mode 100644 index 0000000000..7e436bdebc --- /dev/null +++ b/packages/client/src/components/preview/GridStylesButton.svelte @@ -0,0 +1,48 @@ + + + + +
{ + builderStore.actions.updateStyles( + { [style]: value }, + $componentStore.selectedComponent._id + ) + }} +> + +
+ + diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index e80cb0eaca..540204f817 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -1,11 +1,13 @@