From a3431e6884612b095501ee964d4813ac7420666d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 26 Jul 2024 15:41:07 +0100 Subject: [PATCH 001/112] Add initial work on grid layouts in containers --- packages/client/manifest.json | 101 ++++++++++++++---- .../client/src/components/app/Repeater.svelte | 2 +- .../components/app/container/Container.svelte | 12 +++ .../FlexContainer.svelte} | 0 .../GridContainer.svelte} | 3 + packages/client/src/components/app/index.js | 3 +- .../components/preview/GridDNDHandler.svelte | 2 +- .../components/preview/IndicatorSet.svelte | 16 ++- 8 files changed, 103 insertions(+), 36 deletions(-) create mode 100644 packages/client/src/components/app/container/Container.svelte rename packages/client/src/components/app/{Container.svelte => container/FlexContainer.svelte} (100%) rename packages/client/src/components/app/{Grid.svelte => container/GridContainer.svelte} (97%) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 37f9c681d6..2559671bab 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -119,6 +119,48 @@ }, "styles": ["padding", "size", "background", "border", "shadow"], "settings": [ + { + "type": "select", + "label": "Layout", + "key": "layout", + "showInBar": true, + "barStyle": "buttons", + "options": [ + { + "label": "Flex", + "value": "flex", + "barIcon": "ModernGridView", + "barTitle": "Flex layout" + }, + { + "label": "Grid", + "value": "grid", + "barIcon": "ViewGrid", + "barTitle": "Grid layout" + } + ], + "defaultValue": "flex" + }, + { + "type": "number", + "label": "Columns", + "key": "cols", + "placeholder": 12, + "dependsOn": { + "setting": "layout", + "value": "grid" + } + }, + { + "type": "number", + "label": "Rows", + "key": "rows", + "placeholder": 12, + "dependsOn": { + "setting": "layout", + "value": "grid" + } + }, { "type": "select", "label": "Direction", @@ -139,7 +181,12 @@ "barTitle": "Row layout" } ], - "defaultValue": "column" + "defaultValue": "column", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "select", @@ -173,7 +220,12 @@ "barTitle": "Align stretched horizontally" } ], - "defaultValue": "stretch" + "defaultValue": "stretch", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "select", @@ -207,7 +259,12 @@ "barTitle": "Align stretched vertically" } ], - "defaultValue": "top" + "defaultValue": "top", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "select", @@ -229,7 +286,12 @@ "barTitle": "Grow container" } ], - "defaultValue": "shrink" + "defaultValue": "shrink", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "select", @@ -255,7 +317,12 @@ "value": "L" } ], - "defaultValue": "M" + "defaultValue": "M", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "boolean", @@ -263,7 +330,12 @@ "key": "wrap", "showInBar": true, "barIcon": "ModernGridView", - "barTitle": "Wrap" + "barTitle": "Wrap", + "dependsOn": { + "setting": "layout", + "value": "grid", + "invert": true + } }, { "type": "event", @@ -7167,23 +7239,6 @@ "scope": "local" } }, - "grid": { - "name": "Grid", - "icon": "ViewGrid", - "hasChildren": true, - "settings": [ - { - "type": "number", - "key": "cols", - "label": "Columns" - }, - { - "type": "number", - "key": "rows", - "label": "Rows" - } - ] - }, "gridblock": { "name": "Table", "icon": "Table", diff --git a/packages/client/src/components/app/Repeater.svelte b/packages/client/src/components/app/Repeater.svelte index 2d07342cf5..0b9f011a6e 100644 --- a/packages/client/src/components/app/Repeater.svelte +++ b/packages/client/src/components/app/Repeater.svelte @@ -1,7 +1,7 @@ + + + + diff --git a/packages/client/src/components/app/Container.svelte b/packages/client/src/components/app/container/FlexContainer.svelte similarity index 100% rename from packages/client/src/components/app/Container.svelte rename to packages/client/src/components/app/container/FlexContainer.svelte diff --git a/packages/client/src/components/app/Grid.svelte b/packages/client/src/components/app/container/GridContainer.svelte similarity index 97% rename from packages/client/src/components/app/Grid.svelte rename to packages/client/src/components/app/container/GridContainer.svelte index adc050d330..870a593b46 100644 --- a/packages/client/src/components/app/Grid.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -7,6 +7,9 @@ export let cols = 12 export let rows = 12 + $: cols = cols || 12 + $: rows = rows || 12 + // Deliberately non-reactive as we want this fixed whenever the grid renders const defaultColSpan = Math.ceil((cols + 1) / 2) const defaultRowSpan = Math.ceil((rows + 1) / 2) diff --git a/packages/client/src/components/app/index.js b/packages/client/src/components/app/index.js index 6d9df6e588..63cdb95ac1 100644 --- a/packages/client/src/components/app/index.js +++ b/packages/client/src/components/app/index.js @@ -13,7 +13,7 @@ import "@spectrum-css/page/dist/index-vars.css" export { default as Placeholder } from "./Placeholder.svelte" // User facing components -export { default as container } from "./Container.svelte" +export { default as container } from "./container/Container.svelte" export { default as section } from "./Section.svelte" export { default as dataprovider } from "./DataProvider.svelte" export { default as divider } from "./Divider.svelte" @@ -35,7 +35,6 @@ export { default as spectrumcard } from "./SpectrumCard.svelte" export { default as tag } from "./Tag.svelte" export { default as markdownviewer } from "./MarkdownViewer.svelte" export { default as embeddedmap } from "./embedded-map/EmbeddedMap.svelte" -export { default as grid } from "./Grid.svelte" export { default as sidepanel } from "./SidePanel.svelte" export { default as modal } from "./Modal.svelte" export { default as gridblock } from "./GridBlock.svelte" diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index df0ccb814e..28ef068cfc 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -25,7 +25,7 @@ e.target .closest?.(".component") ?.parentNode.closest(".component") - ?.childNodes[0].classList.contains("grid") || + ?.childNodes[0].classList?.contains("grid") || e.target.classList.contains("anchor") ) } diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index 2b941b2662..2a346742f1 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -1,7 +1,6 @@ From f58e05b5093eb8c2369b34deb72754ee09c93106 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 29 Jul 2024 14:45:33 +0100 Subject: [PATCH 002/112] Improve performance --- .../components/preview/GridDNDHandler.svelte | 25 ++++++++----------- .../components/preview/IndicatorSet.svelte | 11 +++++++- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 28ef068cfc..266a86c867 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -1,21 +1,20 @@ diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index c5109c6bca..e80cb0eaca 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -4,7 +4,8 @@ import SettingsColorPicker from "./SettingsColorPicker.svelte" import SettingsPicker from "./SettingsPicker.svelte" import { builderStore, componentStore, dndIsDragging } from "stores" - import { domDebounce } from "utils/domDebounce" + import { Utils } from "@budibase/frontend-core" + import { isGridChild } from "utils/grid" const verticalOffset = 36 const horizontalOffset = 2 @@ -49,8 +50,10 @@ return } const id = $builderStore.selectedComponentId - const parent = document.getElementsByClassName(id)?.[0] - const element = parent?.children?.[0] + let element = document.getElementsByClassName(id)?.[0] + if (!isGridChild(element)) { + element = element?.children?.[0] + } // The settings bar is higher in the dom tree than the selection indicators // as we want to be able to render the settings bar wider than the screen, @@ -111,7 +114,7 @@ measured = true } } - const debouncedUpdate = domDebounce(updatePosition) + const debouncedUpdate = Utils.domDebounce(updatePosition) onMount(() => { debouncedUpdate() diff --git a/packages/client/src/utils/domDebounce.js b/packages/client/src/utils/domDebounce.js deleted file mode 100644 index b15d2698b4..0000000000 --- a/packages/client/src/utils/domDebounce.js +++ /dev/null @@ -1,14 +0,0 @@ -export const domDebounce = (callback, extractParams = x => x) => { - let active = false - let lastParams - return (...params) => { - lastParams = extractParams(...params) - if (!active) { - active = true - requestAnimationFrame(() => { - callback(lastParams) - active = false - }) - } - } -} diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js new file mode 100644 index 0000000000..03c48505ce --- /dev/null +++ b/packages/client/src/utils/grid.js @@ -0,0 +1,20 @@ +export const isGridEvent = e => { + return ( + e.target + .closest?.(".component") + ?.parentNode.closest(".component") + ?.childNodes[0]?.classList?.contains("grid") || + e.target.classList.contains("anchor") + ) +} + +export const isGridChild = node => { + return node + ?.closest(".component") + ?.parentNode.closest(".component") + ?.childNodes[0]?.classList?.contains("grid") +} + +export const getGridParentID = node => { + return node?.closest(".grid")?.parentNode.dataset.id +} From cb3c6678596544182aefec600e72a3f224c87942 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 10:35:57 +0100 Subject: [PATCH 010/112] Large refactor of grid css variable handling to simplify everything --- .../[screenId]/_components/AppPreview.svelte | 4 +- .../builder/src/stores/builder/components.js | 11 -- packages/client/manifest.json | 17 ++- .../client/src/components/Component.svelte | 49 ++++---- .../app/container/GridContainer.svelte | 32 ++++-- .../components/preview/GridDNDHandler.svelte | 106 ++++++------------ .../preview/GridStylesButton.svelte | 48 ++++++++ .../src/components/preview/SettingsBar.svelte | 66 ++++++++++- .../components/preview/SettingsButton.svelte | 1 + packages/client/src/stores/builder.js | 4 +- packages/client/src/utils/grid.js | 85 ++++++++++++++ 11 files changed, 306 insertions(+), 117 deletions(-) create mode 100644 packages/client/src/components/preview/GridStylesButton.svelte 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 @@ From fc2fb812051c5fbd88f5f580dce09f57cfe96566 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 10:43:25 +0100 Subject: [PATCH 012/112] Fix bug with responsive css variables --- packages/client/src/utils/grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index c83b580795..a357f86de4 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -20,7 +20,7 @@ const Devices = { // Generates the CSS variable for a certain grid param suffix, for the current // device -const previewDevice = derived(builderStore, $store => $store.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}` From 0ea9b157c789487e9c5bc71511eb57ac4902f9fc Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 13:58:29 +0100 Subject: [PATCH 013/112] Further refactoring to grid nested layouts --- .../client/src/components/Component.svelte | 6 ++-- .../app/container/GridContainer.svelte | 2 +- .../preview/GridStylesButton.svelte | 11 +++---- .../src/components/preview/SettingsBar.svelte | 31 +++++++++++++++---- .../components/preview/SettingsButton.svelte | 11 +++---- .../preview/SettingsColorPicker.svelte | 5 +-- .../components/preview/SettingsPicker.svelte | 5 +-- packages/client/src/utils/grid.js | 10 +++--- 8 files changed, 50 insertions(+), 31 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 771cb8b0e6..85c6dc6e36 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -200,11 +200,12 @@ // Build up full styles and split them into variables and non-variables $: baseStyles = getBaseStyles(definition) - $: parsedStyles = parseStyles({ + $: styles = { ...baseStyles, ...instance._styles?.normal, ...ephemeralStyles, - }) + } + $: parsedStyles = parseStyles(styles) $: wrapperCSS = buildStyleString(parsedStyles.variables) // Update component context @@ -214,6 +215,7 @@ styles: { ...instance._styles, normal: parsedStyles.nonVariables, + variables: parsedStyles.variables, custom: customCSS, id, empty: emptyState, diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index a5450ffe4c..3e58fef787 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -95,7 +95,7 @@ /* Ensure all top level children have grid styles applied */ .grid :global(> .component) { display: flex; - overflow: hidden; + overflow: auto; /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ diff --git a/packages/client/src/components/preview/GridStylesButton.svelte b/packages/client/src/components/preview/GridStylesButton.svelte index 0a313bba53..e168754f3b 100644 --- a/packages/client/src/components/preview/GridStylesButton.svelte +++ b/packages/client/src/components/preview/GridStylesButton.svelte @@ -1,14 +1,16 @@ @@ -18,10 +20,7 @@ {title} class:active on:click={() => { - builderStore.actions.updateStyles( - { [style]: value }, - $componentStore.selectedComponent._id - ) + builderStore.actions.updateStyles({ [style]: value }, componentId) }} > diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index 540204f817..1fecec5376 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -20,11 +20,12 @@ // TODO: respect dependsOn keys - $: id = $builderStore.selectedComponentId - $: parent = findComponentParent($builderStore.screen.props, id) - $: instance = componentStore.actions.getComponentInstance(id) - $: state = $instance?.state + $: componentId = $builderStore.selectedComponentId + $: component = $componentStore.selectedComponent $: definition = $componentStore.selectedComponentDefinition + $: parent = findComponentParent($builderStore.screen.props, componentId) + $: instance = componentStore.actions.getComponentInstance(componentId) + $: state = $instance?.state $: showBar = definition?.showSettingsBar !== false && !$dndIsDragging && @@ -36,12 +37,13 @@ } } $: settings = getBarSettings(definition) - $: isRoot = id === $builderStore.screen?.props?._id + $: isRoot = componentId === $builderStore.screen?.props?._id $: insideGrid = parent?._component.endsWith("/container") && parent.layout === "grid" $: showGridStyles = insideGrid && definition?.grid?.showControls !== false $: gridHAlignVar = $getGridVar("h-align") $: gridVAlignVar = $getGridVar("v-align") + $: gridStyles = $state?.styles?.variables const getBarSettings = definition => { let allSettings = [] @@ -141,7 +143,7 @@ {#if showBar}
@@ -151,24 +153,32 @@ value="start" icon="AlignLeft" title="Align left" + {gridStyles} + {componentId} />
{/if} @@ -206,6 +224,7 @@ value={option.value} icon={option.barIcon} title={option.barTitle || option.label} + {component} /> {/each} {:else} diff --git a/packages/client/src/components/preview/SettingsButton.svelte b/packages/client/src/components/preview/SettingsButton.svelte index 446a367282..a93ffb77af 100644 --- a/packages/client/src/components/preview/SettingsButton.svelte +++ b/packages/client/src/components/preview/SettingsButton.svelte @@ -1,18 +1,19 @@ @@ -20,7 +21,6 @@
{ if (prop) { @@ -50,7 +50,4 @@ background-color: rgba(13, 102, 208, 0.1); color: var(--spectrum-global-color-blue-600); } - .rotate { - transform: rotate(90deg); - } diff --git a/packages/client/src/components/preview/SettingsColorPicker.svelte b/packages/client/src/components/preview/SettingsColorPicker.svelte index b078d048d2..a292d7d838 100644 --- a/packages/client/src/components/preview/SettingsColorPicker.svelte +++ b/packages/client/src/components/preview/SettingsColorPicker.svelte @@ -1,10 +1,11 @@
diff --git a/packages/client/src/components/preview/SettingsPicker.svelte b/packages/client/src/components/preview/SettingsPicker.svelte index 8b83729fde..3900d065e8 100644 --- a/packages/client/src/components/preview/SettingsPicker.svelte +++ b/packages/client/src/components/preview/SettingsPicker.svelte @@ -1,12 +1,13 @@
diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index a357f86de4..5879232e89 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -1,5 +1,5 @@ -import { builderStore } from "stores" -import { derived, get } from "svelte/store" +import { builderStore, componentStore } from "stores" +import { derived, get, readable } from "svelte/store" /** * We use CSS variables on components to control positioning and layout of @@ -91,13 +91,13 @@ export const getBaseGridVars = definition => { } // Gets the current value of a certain grid CSS variable for a component -export const getGridVarValue = (component, variable) => { +export const getGridVarValue = (styles, variable) => { // Try the desired variable - let val = component?._styles?.normal?.[variable] + let val = styles?.[variable] // Otherwise try the other device variables if (!val) { - val = component?._styles?.normal?.[getOtherDeviceGridVar(variable)] + val = styles?.[getOtherDeviceGridVar(variable)] } // Otherwise use the default From e385c7291c0beb74a8611a8872d05c122ff978c9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 14:12:46 +0100 Subject: [PATCH 014/112] Fix some crashes and improve pixel alignment --- packages/client/src/components/preview/Indicator.svelte | 2 +- .../client/src/components/preview/IndicatorSet.svelte | 9 ++++----- packages/client/src/utils/grid.js | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/client/src/components/preview/Indicator.svelte b/packages/client/src/components/preview/Indicator.svelte index 0480ea91ce..ae6ed081a5 100644 --- a/packages/client/src/components/preview/Indicator.svelte +++ b/packages/client/src/components/preview/Indicator.svelte @@ -69,7 +69,7 @@ z-index: var(--zIndex); border: 2px solid var(--color); pointer-events: none; - border-radius: 4px; + border-radius: 2px; } .indicator.withText { border-top-left-radius: 0; diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index e437ba84b6..aff62a76a7 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -37,7 +37,6 @@ let callbackCount = 0 $: visibleIndicators = state.indicators.filter(x => x.visible) - $: offset = $builderStore.inBuilder ? 0 : 2 // Update position when any props change $: config.set({ @@ -150,10 +149,10 @@ const elBounds = child.getBoundingClientRect() nextState.indicators.push({ - top: elBounds.top + scrollY - deviceBounds.top - offset, - left: elBounds.left + scrollX - deviceBounds.left - offset, - width: elBounds.width + 4, - height: elBounds.height + 4, + top: Math.round(elBounds.top + scrollY - deviceBounds.top + 1), + left: Math.round(elBounds.left + scrollX - deviceBounds.left + 1), + width: Math.round(elBounds.width + 2), + height: Math.round(elBounds.height + 2), visible: false, insideSidePanel: !!child.closest(".side-panel"), insideModal: !!child.closest(".modal-content"), diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 5879232e89..91b4d0a525 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -77,8 +77,8 @@ const alignmentToStyleMap = { stretch: "stretch", } export const getBaseGridVars = definition => { - const gridHAlign = definition.grid?.hAlign || "stretch" - const gridVAlign = definition.grid?.vAlign || "center" + const gridHAlign = definition?.grid?.hAlign || "stretch" + const gridVAlign = definition?.grid?.vAlign || "center" const flexStyles = gridVAlign === "stretch" ? "1 1 0" : "0 0 auto" return { ["--grid-desktop-h-align"]: alignmentToStyleMap[gridHAlign], From de9b80e23dd8a4a6a5abfa96a64ab0b56925a7e2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 15:03:29 +0100 Subject: [PATCH 015/112] Multiple style improvements and pixel layout fixes --- packages/client/src/components/ClientApp.svelte | 16 +++++----------- packages/client/src/components/Component.svelte | 3 ++- .../app/container/GridContainer.svelte | 1 + .../src/components/preview/Indicator.svelte | 9 +++++---- .../src/components/preview/IndicatorSet.svelte | 7 ++++--- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index 763c8ef771..d0369192a0 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -356,22 +356,16 @@ } /* Preview styles */ - /* The additional 6px of size is to account for 4px padding and 2px border */ #clip-root.preview { - padding: 2px; + padding: 6px; } #clip-root.tablet-preview { - width: calc(1024px + 6px); - height: calc(768px + 6px); + width: calc(1024px + 12px); + height: calc(768px + 12px); } #clip-root.mobile-preview { - width: calc(390px + 6px); - height: calc(844px + 6px); - } - - .preview #app-root { - border: 1px solid var(--spectrum-global-color-gray-300); - border-radius: 4px; + width: calc(390px + 12px); + height: calc(844px + 12px); } /* Print styles */ diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 85c6dc6e36..6ff6fa00fc 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -619,6 +619,7 @@ if (isBlock) { return } + console.log("select", id) e.stopPropagation() builderStore.actions.selectComponent(id) } @@ -691,7 +692,7 @@ data-parent={$component.id} style={wrapperCSS} {draggable} - on:click={handleWrapperClick} + on:click|self={handleWrapperClick} > {#if errorState} .component) { display: flex; overflow: auto; + pointer-events: all; /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ diff --git a/packages/client/src/components/preview/Indicator.svelte b/packages/client/src/components/preview/Indicator.svelte index ae6ed081a5..d93ecaa02b 100644 --- a/packages/client/src/components/preview/Indicator.svelte +++ b/packages/client/src/components/preview/Indicator.svelte @@ -69,7 +69,7 @@ z-index: var(--zIndex); border: 2px solid var(--color); pointer-events: none; - border-radius: 2px; + border-radius: 4px; } .indicator.withText { border-top-left-radius: 0; @@ -123,7 +123,7 @@ /* Anchor */ .anchor { - --size: 24px; + --size: 20px; position: absolute; width: var(--size); height: var(--size); @@ -133,11 +133,12 @@ border-radius: 50%; } .anchor-inner { - width: 12px; - height: 12px; + width: calc(var(--size) / 2); + height: calc(var(--size) / 2); background: white; border: 2px solid var(--color); pointer-events: none; + border-radius: 2px; } .anchor.right { right: calc(var(--size) / -2 - 1px); diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index aff62a76a7..6d7918244a 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -11,6 +11,8 @@ export let prefix = null export let allowResizeAnchors = false + // Offset = 6 (clip-root padding) - 1 (half the border thickness) + const offset = 6 - 1 const config = memo($$props) const errorColor = "var(--spectrum-global-color-static-red-600)" const defaultState = () => ({ @@ -146,11 +148,10 @@ }) observer.observe(child) observers.push(observer) - const elBounds = child.getBoundingClientRect() nextState.indicators.push({ - top: Math.round(elBounds.top + scrollY - deviceBounds.top + 1), - left: Math.round(elBounds.left + scrollX - deviceBounds.left + 1), + top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset), + left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset), width: Math.round(elBounds.width + 2), height: Math.round(elBounds.height + 2), visible: false, From 8540f4020ba2a2af55f4656d4d836dda2c300552 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 15:34:15 +0100 Subject: [PATCH 016/112] Improve client preview styles to work with increase client padding --- .../[screenId]/_components/AppPreview.svelte | 22 ++++++++++++++----- .../src/components/ClientAppSkeleton.svelte | 1 - 2 files changed, 16 insertions(+), 7 deletions(-) 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 0ce9e096f2..a5d14062dc 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 @@ -275,6 +275,7 @@ src="/app/preview" class:hidden={loading || error} /> +
.loading { position: absolute; - container-type: inline-size; - width: 100%; - height: 100%; - border: 2px solid transparent; - box-sizing: border-box; + width: calc(100% - 12px); + height: calc(100% - 12px); + left: 6px; + top: 6px; } .loading.tablet { @@ -318,7 +318,6 @@ display: grid; place-items: center; position: relative; - overflow: hidden; margin: auto; height: 100%; } @@ -363,6 +362,17 @@ height: 100%; } + .underlay { + position: absolute; + background: var(--spectrum-global-color-gray-200); + z-index: -1; + --offset: 2px; + width: calc(100% - 12px + 2 * var(--offset)); + height: calc(100% - 12px + 2 * var(--offset)); + left: calc(6px - var(--offset)); + top: calc(6px - var(--offset)); + } + .add-component { position: absolute; bottom: 20px; diff --git a/packages/frontend-core/src/components/ClientAppSkeleton.svelte b/packages/frontend-core/src/components/ClientAppSkeleton.svelte index a1c90d2db7..f867fccddb 100644 --- a/packages/frontend-core/src/components/ClientAppSkeleton.svelte +++ b/packages/frontend-core/src/components/ClientAppSkeleton.svelte @@ -58,7 +58,6 @@ height: 100%; display: flex; flex-direction: column; - border-radius: 4px; overflow: hidden; background-color: var(--spectrum-global-color-gray-200); } From 940e2b5a940257bc965eea8808bea5482ecbf1a8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 31 Jul 2024 15:53:40 +0100 Subject: [PATCH 017/112] Improve client loading states, skeleton and underlay --- .../[screenId]/_components/AppPreview.svelte | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) 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 a5d14062dc..0e2eb2ceac 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 @@ -246,13 +246,13 @@ -
+
{#if loading} -
+
diff --git a/packages/client/src/components/Screen.svelte b/packages/client/src/components/Screen.svelte index ab1cc7812d..ac0af9f3b2 100644 --- a/packages/client/src/components/Screen.svelte +++ b/packages/client/src/components/Screen.svelte @@ -13,29 +13,10 @@ const onLoadActions = memo() // Get the screen definition for the current route - $: screenDefinition = getScreenDefinition($screenStore.activeScreen) + $: screenDefinition = $screenStore.activeScreen?.props $: onLoadActions.set($screenStore.activeScreen?.onLoad) $: runOnLoadActions($onLoadActions, params) - const getScreenDefinition = activeScreen => { - if (!activeScreen) { - return null - } - - // Enrich screen definition with some builder screen props and styles - return { - ...activeScreen.props, - layout: activeScreen.layout, - _styles: { - ...activeScreen.props._styles, - normal: { - ...activeScreen.props._styles?.normal, - flex: "1 1 auto", - }, - }, - } - } - // Enrich and execute any on load actions. // We manually construct the full context here as this component is the // one that provides the url context, so it is not available in $context yet diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index cc2a086b2e..3fbe3ed20c 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -37,7 +37,6 @@ export let openLogoLinkInNewTab export let textAlign export let embedded = false - export let pageLayout = "flex" const NavigationClasses = { Top: "top", @@ -319,7 +318,7 @@ } }} > -
+
@@ -481,7 +480,7 @@ position: relative; padding: 32px; } - .main.layout--grid { + .main:has(> .grid) { padding-top: 0; padding-bottom: 0; } diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index 6d7918244a..12ee3ad334 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -1,9 +1,10 @@ From 64c182df0f4026faef8de8499ee597accdabb615 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 1 Aug 2024 12:06:22 +0100 Subject: [PATCH 025/112] Fix indicator positioning in preview --- packages/client/src/components/preview/IndicatorSet.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index b2ad873005..464be3bb16 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -1,7 +1,7 @@ diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index c8535899af..6b00221f9e 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -40,7 +40,10 @@ $: isRoot = componentId === $builderStore.screen?.props?._id $: insideGrid = parent?._component.endsWith("/container") && parent.layout === "grid" - $: showGridStyles = insideGrid && definition?.grid?.showControls !== false + $: showGridStyles = + insideGrid && + (definition?.grid?.hAlign !== "stretch" || + definition?.grid?.vAlign !== "stretch") $: gridHAlignVar = $getGridVar("h-align") $: gridVAlignVar = $getGridVar("v-align") $: gridStyles = $state?.styles diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index d5be908edb..4fa8a3e49b 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -70,23 +70,17 @@ export const getGridParentID = node => { } // Generates the base set of grid CSS vars from a component definition -const alignmentToStyleMap = { - start: "flex-start", - center: "center", - end: "flex-end", - stretch: "stretch", -} export const getBaseGridVars = definition => { const gridHAlign = definition?.grid?.hAlign || "stretch" const gridVAlign = definition?.grid?.vAlign || "center" const flexStyles = gridVAlign === "stretch" ? "1 1 0" : "0 0 auto" return { - ["--grid-desktop-h-align"]: alignmentToStyleMap[gridHAlign], - ["--grid-mobile-h-align"]: alignmentToStyleMap[gridHAlign], - ["--grid-desktop-v-align"]: alignmentToStyleMap[gridVAlign], - ["--grid-mobile-v-align"]: alignmentToStyleMap[gridVAlign], - ["--grid-desktop-child-flex"]: flexStyles, - ["--grid-mobile-child-flex"]: flexStyles, + "--grid-desktop-h-align": gridHAlign, + "--grid-mobile-h-align": gridHAlign, + "--grid-desktop-v-align": gridVAlign, + "--grid-mobile-v-align": gridVAlign, + "--grid-desktop-child-flex": flexStyles, + "--grid-mobile-child-flex": flexStyles, } } From 5cc4002f326a3a3584928486d2b0b8ee9224a3ad Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 09:22:04 +0100 Subject: [PATCH 030/112] Add better support for auto sizing error state components in grid layouts --- packages/client/manifest.json | 4 ++-- packages/client/src/components/Component.svelte | 10 +++++----- packages/client/src/utils/grid.js | 16 ++++++++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 9b3939854c..46595279b4 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5344,11 +5344,11 @@ "hasChildren": false, "size": { "width": 600, - "height": 400 + "height": 420 }, "grid": { "hAlign": "stretch", - "vAlign": "stretch" + "vAlign": "center" }, "settings": [ { diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index d45b320b35..7aea6ce6b9 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -199,7 +199,7 @@ $: darkMode = !currentTheme?.includes("light") // Build up full styles and split them into variables and non-variables - $: baseStyles = getBaseStyles(definition) + $: baseStyles = getBaseStyles(definition, errorState) $: styles = { ...baseStyles, ...instance._styles?.normal, @@ -632,11 +632,11 @@ } // Generates any required base styles based on the component definition - const getBaseStyles = definition => { + const getBaseStyles = (definition, errored = false) => { return { - "--default-width": definition.size?.width || 100, - "--default-height": definition.size?.height || 100, - ...getBaseGridVars(definition), + "--default-width": errored ? 500 : definition.size?.width || 100, + "--default-height": errored ? 60 : definition.size?.height || 100, + ...getBaseGridVars(definition, errored), } } diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 4fa8a3e49b..3052199656 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -70,15 +70,15 @@ export const getGridParentID = node => { } // Generates the base set of grid CSS vars from a component definition -export const getBaseGridVars = definition => { - const gridHAlign = definition?.grid?.hAlign || "stretch" - const gridVAlign = definition?.grid?.vAlign || "center" - const flexStyles = gridVAlign === "stretch" ? "1 1 0" : "0 0 auto" +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": gridHAlign, - "--grid-mobile-h-align": gridHAlign, - "--grid-desktop-v-align": gridVAlign, - "--grid-mobile-v-align": gridVAlign, + "--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, } From 8dd0658f182f2766e4bf1a575683810ba7f3d51d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 09:23:47 +0100 Subject: [PATCH 031/112] Fix component autosizing not working on mobile grids --- .../app/container/GridContainer.svelte | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 0df7b46f43..2152bdf42f 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -115,8 +115,7 @@ --grid-desktop-col-end, var( --grid-mobile-col-end, - /* Our final*/ - round(up, calc(var(--default-width) / var(--col-size) + 1)) + round(up, calc(var(--default-width) / var(--col-size) + 1)) ) ); --row-start: var(--grid-desktop-row-start, var(--grid-mobile-row-start, 1)); @@ -128,7 +127,7 @@ ) ); - /* Flex vars */ + /* 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( @@ -153,11 +152,23 @@ /* On mobile, use mobile metadata and fall back to desktop */ .grid.mobile :global(> .component) { - /* Position vars */ + /* 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)); + --col-end: var( + --grid-mobile-col-end, + var( + --grid-desktop-col-end, + round(up, calc(var(--default-width) / var(--col-size) + 1)) + ) + ); --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)); + --row-end: var( + --grid-mobile-row-end, + var( + --grid-desktop-row-end, + round(up, calc(var(--default-height) / var(--row-size) + 1)) + ) + ); /* Flex vars */ --h-align: var(--grid-mobile-h-align, var(--grid-desktop-h-align, stretch)); From 3630c738372f056d692e8082457a1e6eccb9a0c2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 09:40:12 +0100 Subject: [PATCH 032/112] Fix flashing of missing component settings panel when deleting components --- .../design/[screenId]/_layout.svelte | 6 +++- .../builder/src/stores/builder/components.js | 29 ++++++++++--------- .../preview/GridStylesButton.svelte | 1 - 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index ac87b53db2..c3f3ef71f5 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -2,7 +2,11 @@ import AppPanel from "./_components/AppPanel.svelte" import * as routify from "@roxi/routify" import { syncURLToState } from "helpers/urlStateSync" - import { screenStore, selectedScreen } from "stores/builder" + import { + screenStore, + selectedScreen, + selectedComponent, + } from "stores/builder" import { onDestroy } from "svelte" import LeftPanel from "./_components/LeftPanel.svelte" diff --git a/packages/builder/src/stores/builder/components.js b/packages/builder/src/stores/builder/components.js index c281c73dfe..21ea255b74 100644 --- a/packages/builder/src/stores/builder/components.js +++ b/packages/builder/src/stores/builder/components.js @@ -574,15 +574,26 @@ export class ComponentStore extends BudiStore { return } - // Determine the next component to select after deletion + // Determine the next component to select, and select it before deletion + // to avoid an intermediate state of no component selection const state = get(this.store) - let nextSelectedComponentId + let nextId if (state.selectedComponentId === component._id) { - nextSelectedComponentId = this.getNext() - if (!nextSelectedComponentId) { - nextSelectedComponentId = this.getPrevious() + nextId = this.getNext() + if (!nextId) { + nextId = this.getPrevious() } } + if (nextId) { + // If this is the nav, select the screen instead + if (nextId.endsWith("-navigation")) { + nextId = nextId.replace("-navigation", "-screen") + } + this.update(state => { + state.selectedComponentId = nextId + return state + }) + } // Patch screen await screenStore.patch(screen => { @@ -601,14 +612,6 @@ export class ComponentStore extends BudiStore { child => child._id !== component._id ) }) - - // Update selected component if required - if (nextSelectedComponentId) { - this.update(state => { - state.selectedComponentId = nextSelectedComponentId - return state - }) - } } copy(component, cut = false, selectParent = true) { diff --git a/packages/client/src/components/preview/GridStylesButton.svelte b/packages/client/src/components/preview/GridStylesButton.svelte index 809efd7971..e168754f3b 100644 --- a/packages/client/src/components/preview/GridStylesButton.svelte +++ b/packages/client/src/components/preview/GridStylesButton.svelte @@ -11,7 +11,6 @@ export let componentId $: currentValue = getGridVarValue(gridStyles, style) - $: console.log(style, currentValue, value) $: active = currentValue === value From 2bc4d3a6da66847aa342afec798230e14eb2f680 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 10:00:49 +0100 Subject: [PATCH 033/112] Improve more component compatibility with grid layouts --- .../app/[application]/design/[screenId]/_layout.svelte | 6 +----- packages/client/manifest.json | 10 +++++++++- packages/client/src/components/app/ButtonGroup.svelte | 5 +++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index c3f3ef71f5..ac87b53db2 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -2,11 +2,7 @@ import AppPanel from "./_components/AppPanel.svelte" import * as routify from "@roxi/routify" import { syncURLToState } from "helpers/urlStateSync" - import { - screenStore, - selectedScreen, - selectedComponent, - } from "stores/builder" + import { screenStore, selectedScreen } from "stores/builder" import { onDestroy } from "svelte" import LeftPanel from "./_components/LeftPanel.svelte" diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 46595279b4..f61ed7d1bc 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -388,6 +388,14 @@ "name": "Button group", "icon": "Button", "hasChildren": false, + "size": { + "width": 200, + "height": 60 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "stretch" + }, "settings": [ { "section": true, @@ -570,7 +578,7 @@ "icon": "Button", "editable": true, "size": { - "width": 105, + "width": 120, "height": 32 }, "grid": { diff --git a/packages/client/src/components/app/ButtonGroup.svelte b/packages/client/src/components/app/ButtonGroup.svelte index 2cf6b3db7d..b3523cdd21 100644 --- a/packages/client/src/components/app/ButtonGroup.svelte +++ b/packages/client/src/components/app/ButtonGroup.svelte @@ -19,6 +19,11 @@ gap, wrap: true, }} + styles={{ + normal: { + height: "100%", + }, + }} > {#each buttons as { text, type, quiet, disabled, onClick, size, icon, gap }} Date: Fri, 2 Aug 2024 10:35:35 +0100 Subject: [PATCH 034/112] Fix tag component being totally broken --- packages/bbui/package.json | 1 + packages/client/manifest.json | 4 + packages/client/src/components/app/Tag.svelte | 3 + yarn.lock | 228 ++++++++++++++++-- 4 files changed, 215 insertions(+), 21 deletions(-) diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 1b3510cf3b..0830f8ab6f 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -72,6 +72,7 @@ "@spectrum-css/switch": "1.0.2", "@spectrum-css/table": "3.0.1", "@spectrum-css/tabs": "3.2.12", + "@spectrum-css/tag": "3.0.0", "@spectrum-css/tags": "3.0.2", "@spectrum-css/textfield": "3.0.1", "@spectrum-css/toast": "3.0.1", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index f61ed7d1bc..533da51f22 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -1245,6 +1245,10 @@ "width": 100, "height": 25 }, + "grid": { + "hAlign": "center", + "vAlign": "center" + }, "settings": [ { "type": "text", diff --git a/packages/client/src/components/app/Tag.svelte b/packages/client/src/components/app/Tag.svelte index 4644161506..f7d071ac79 100644 --- a/packages/client/src/components/app/Tag.svelte +++ b/packages/client/src/components/app/Tag.svelte @@ -57,4 +57,7 @@ .spectrum-Tag--sizeL { padding: 0 var(--spectrum-global-dimension-size-150); } + .spectrum-Tag-label { + height: auto; + } diff --git a/yarn.lock b/yarn.lock index 2d69b37cc6..f04ff376c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5067,6 +5067,11 @@ resolved "https://registry.yarnpkg.com/@spectrum-css/tabs/-/tabs-3.2.12.tgz#9b08f23d5aa881b3441af7757800c7173e5685ff" integrity sha512-rPFUW9SSW4+3/UJ3UrtY2/l3sQvlqB1fqxHLPDjgykvbfrnMejcCTNV4ZrFNHXpE/6+kGnk+yVViSPtWGwJzkA== +"@spectrum-css/tag@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@spectrum-css/tag/-/tag-3.0.0.tgz#b2e335dc526713b83f3e995e8d1d4fc84a3fc4df" + integrity sha512-a9z7ZTAWPonkWRNY5kxVaO6bxu9de3qUZWJ9Bl1YBlwWc8Fy1L7XqT4Wq3pW+4sktUbUUqqPYPIXK9xEFDofEw== + "@spectrum-css/tags@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@spectrum-css/tags/-/tags-3.0.2.tgz#5bf35fb79c97cd9344de485bd4626ad5b9f07757" @@ -6707,22 +6712,39 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== -acorn-jsx@^5.3.2: +acorn-jsx-walk@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/acorn-jsx-walk/-/acorn-jsx-walk-2.0.0.tgz#a5ed648264e68282d7c2aead80216bfdf232573a" + integrity sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA== + +acorn-jsx@5.3.2, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-loose@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/acorn-loose/-/acorn-loose-8.4.0.tgz#26d3e219756d1e180d006f5bcc8d261a28530f55" + integrity sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ== + dependencies: + acorn "^8.11.0" + +acorn-walk@8.3.3, acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0, acorn-walk@^8.3.2: + version "8.3.3" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" + integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== + dependencies: + acorn "^8.11.0" + acorn-walk@^7.1.1: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0, acorn-walk@^8.3.2: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== - dependencies: - acorn "^8.11.0" +acorn@8.12.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== acorn@^5.2.1, acorn@^5.7.3: version "5.7.4" @@ -6791,6 +6813,16 @@ ajv-formats@^2.0.2: dependencies: ajv "^8.0.0" +ajv@8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -8484,6 +8516,11 @@ combos@^0.2.0: resolved "https://registry.yarnpkg.com/combos/-/combos-0.2.0.tgz#dc31c5a899b42293d55fe19c064d3e6e207ba4f7" integrity sha512-Z6YfvgiTCERWJTj3wQiXamFhssdvz1n4ok447rS330lw3uL72WAx8IvrLU7xiE71uyb5WF8JEP+BWB5KhOoGeg== +commander@12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" @@ -9551,6 +9588,34 @@ depd@^1.1.0, depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== +dependency-cruiser@^16.3.7: + version "16.3.10" + resolved "https://registry.yarnpkg.com/dependency-cruiser/-/dependency-cruiser-16.3.10.tgz#fe26a50d5e10a4496bc2b70d027fca6ded48814f" + integrity sha512-WkCnibHBfvaiaQ+S46LZ6h4AR6oj42Vsf5/0Vgtrwdwn7ZekMJdZ/ALoTwNp/RaGlKW+MbV/fhSZOvmhAWVWzQ== + dependencies: + acorn "8.12.1" + acorn-jsx "5.3.2" + acorn-jsx-walk "2.0.0" + acorn-loose "8.4.0" + acorn-walk "8.3.3" + ajv "8.17.1" + commander "12.1.0" + enhanced-resolve "5.17.1" + ignore "5.3.1" + interpret "^3.1.1" + is-installed-globally "1.0.0" + json5 "2.2.3" + memoize "10.0.0" + picocolors "1.0.1" + picomatch "4.0.2" + prompts "2.4.2" + rechoir "^0.8.0" + safe-regex "2.1.1" + semver "^7.6.3" + teamcity-service-messages "0.1.14" + tsconfig-paths-webpack-plugin "4.1.0" + watskeburt "4.1.0" + dependency-tree@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-9.0.0.tgz#9288dd6daf35f6510c1ea30d9894b75369aa50a2" @@ -10221,6 +10286,14 @@ engine.io@~6.5.2: engine.io-parser "~5.2.1" ws "~8.17.1" +enhanced-resolve@5.17.1, enhanced-resolve@^5.7.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enhanced-resolve@^5.8.3: version "5.14.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz#de684b6803724477a4af5d74ccae5de52c25f6b3" @@ -11016,6 +11089,11 @@ fast-text-encoding@^1.0.0: resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz#0aa25f7f638222e3396d72bf936afcf1d42d6867" integrity sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fast-url-parser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" @@ -11877,6 +11955,13 @@ global-agent@3.0.0: semver "^7.3.2" serialize-error "^7.0.1" +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== + dependencies: + ini "4.1.1" + global-dirs@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" @@ -12541,6 +12626,11 @@ ignore-walk@^6.0.0: dependencies: minimatch "^7.4.2" +ignore@5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.4: version "5.3.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" @@ -12666,6 +12756,11 @@ ini@2.0.0: resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + ini@^1.3.2, ini@^1.3.4, ini@^1.3.8, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -12743,6 +12838,11 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" @@ -12973,6 +13073,14 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-installed-globally@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-1.0.0.tgz#08952c43758c33d815692392f7f8437b9e436d5a" + integrity sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ== + dependencies: + global-directory "^4.0.1" + is-path-inside "^4.0.0" + is-installed-globally@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -13060,6 +13168,11 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-path-inside@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-4.0.0.tgz#805aeb62c47c1b12fc3fd13bfb3ed1e7430071db" + integrity sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA== + is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -14084,6 +14197,11 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== +json5@2.2.3, json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -14091,11 +14209,6 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.2.1, json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - jsonc-parser@3.2.0, jsonc-parser@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -15441,6 +15554,13 @@ memdown@^5.1.0: ltgt "~2.2.0" safe-buffer "~5.2.0" +memoize@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/memoize/-/memoize-10.0.0.tgz#43fa66b2022363c7c50cf5dfab732a808a3d7147" + integrity sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA== + dependencies: + mimic-function "^5.0.0" + memory-pager@^1.0.2: version "1.5.0" resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" @@ -15549,6 +15669,11 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-function@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" + integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== + mimic-response@^1.0.0, mimic-response@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" @@ -17412,15 +17537,20 @@ phin@^2.9.1: resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== +picocolors@1.0.1, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picocolors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" - integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picomatch@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -18385,7 +18515,7 @@ promise.series@^0.2.0: resolved "https://registry.yarnpkg.com/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" integrity sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ== -prompts@^2.0.1: +prompts@2.4.2, prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -18952,6 +19082,11 @@ regenerator-transform@^0.15.1: dependencies: "@babel/runtime" "^7.8.4" +regexp-tree@~0.1.1: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" @@ -19492,6 +19627,13 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" +safe-regex@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" + integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== + dependencies: + regexp-tree "~0.1.1" + safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1: version "2.4.3" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" @@ -19603,7 +19745,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@~2.3.1: +"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1, semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.0.0, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3, semver@~2.3.1: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ== @@ -20287,7 +20429,16 @@ string-similarity@^4.0.4: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -20378,7 +20529,7 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -20392,6 +20543,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -20867,6 +21025,11 @@ tarn@^3.0.1, tarn@^3.0.2: resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693" integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ== +teamcity-service-messages@0.1.14: + version "0.1.14" + resolved "https://registry.yarnpkg.com/teamcity-service-messages/-/teamcity-service-messages-0.1.14.tgz#193d420a5e4aef8e5e50b8c39e7865e08fbb5d8a" + integrity sha512-29aQwaHqm8RMX74u2o/h1KbMLP89FjNiMxD9wbF2BbWOnbM+q+d1sCEC+MqCc4QW3NJykn77OMpTFw/xTHIc0w== + tedious@^16.4.0: version "16.7.1" resolved "https://registry.yarnpkg.com/tedious/-/tedious-16.7.1.tgz#1190f30fd99a413f1dc9250dee4835cf0788b650" @@ -21258,6 +21421,15 @@ ts-node@10.8.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tsconfig-paths-webpack-plugin@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763" + integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^4.1.2" + tsconfig-paths@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.0.0.tgz#1082f5d99fd127b72397eef4809e4dd06d229b64" @@ -22037,6 +22209,11 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +watskeburt@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/watskeburt/-/watskeburt-4.1.0.tgz#3c0227669be646a97424b631164b1afe3d4d5344" + integrity sha512-KkY5H51ajqy9HYYI+u9SIURcWnqeVVhdH0I+ab6aXPGHfZYxgRCwnR6Lm3+TYB6jJVt5jFqw4GAKmwf1zHmGQw== + wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -22282,7 +22459,7 @@ worker-farm@1.7.0: dependencies: errno "~0.1.7" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -22300,6 +22477,15 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 0ba00a5117b67719d979894a7ba0bf265c0d3a7d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 16:13:49 +0100 Subject: [PATCH 035/112] Move most grid specific logic into a dedicated file to avoid polluting rest of the codebase --- .../_components/Screen/GeneralPanel.svelte | 4 +- packages/client/manifest.json | 16 +++ .../client/src/components/ClientApp.svelte | 6 +- .../client/src/components/Component.svelte | 51 ++------ .../client/src/components/app/Layout.svelte | 2 +- .../app/container/GridContainer.svelte | 36 ++---- .../components/preview/GridDNDHandler.svelte | 15 ++- .../src/components/preview/SettingsBar.svelte | 6 +- packages/client/src/utils/grid.js | 122 ++++++++++++++---- 9 files changed, 160 insertions(+), 98 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index 00032cb23a..2a5211a253 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -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, diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 533da51f22..10503f30ac 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -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", diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index d0369192a0..118aa483ab 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -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; diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 7aea6ce6b9..6e184bde7e 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -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} .grid) { + .main:has(.screenslot-dom > .component > .grid) { padding-top: 0; padding-bottom: 0; } diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 2152bdf42f..b16fc88dbf 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -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; } diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 7e2cbd50c8..12631b980a 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -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 diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index 6b00221f9e..cd11529cfa 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -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 => { diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 3052199656..d3b16aeafd 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -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() + }, + } +} From 1bce9855d006589b4c6d5a9cf3b03749953f6674 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 2 Aug 2024 16:44:18 +0100 Subject: [PATCH 036/112] More improvements --- .../components/preview/GridDNDHandler.svelte | 13 ++-- .../preview/GridStylesButton.svelte | 17 ++++- .../src/components/preview/SettingsBar.svelte | 16 ++--- packages/client/src/utils/grid.js | 66 ++++--------------- 4 files changed, 38 insertions(+), 74 deletions(-) diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 12631b980a..114e131eb3 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -5,8 +5,8 @@ import { isGridEvent, getGridParentID, - gridCSSVars, - GridVars, + GridParams, + getGridVar, } from "utils/grid" // Smallest possible 1x1 transparent GIF @@ -19,11 +19,12 @@ let id // Grid CSS variables + $: device = $builderStore.previewDevice $: vars = { - colStart: $gridCSSVars[GridVars.ColStart], - colEnd: $gridCSSVars[GridVars.ColEnd], - rowStart: $gridCSSVars[GridVars.RowStart], - rowEnd: $gridCSSVars[GridVars.RowEnd], + colStart: getGridVar(device, GridParams.ColStart), + colEnd: getGridVar(device, GridParams.ColEnd), + rowStart: getGridVar(device, GridParams.RowStart), + rowEnd: getGridVar(device, GridParams.RowEnd), } // Some memoisation of primitive types for performance diff --git a/packages/client/src/components/preview/GridStylesButton.svelte b/packages/client/src/components/preview/GridStylesButton.svelte index e168754f3b..0dff88f23a 100644 --- a/packages/client/src/components/preview/GridStylesButton.svelte +++ b/packages/client/src/components/preview/GridStylesButton.svelte @@ -1,17 +1,28 @@ diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index cd11529cfa..df714681e9 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -7,7 +7,7 @@ import { builderStore, componentStore, dndIsDragging } from "stores" import { Utils } from "@budibase/frontend-core" import { findComponentParent } from "utils/components" - import { gridCSSVars, GridVars } from "utils/grid" + import { getGridVar, GridParams } from "utils/grid" const verticalOffset = 36 const horizontalOffset = 2 @@ -44,9 +44,9 @@ insideGrid && (definition?.grid?.hAlign !== "stretch" || definition?.grid?.vAlign !== "stretch") - $: gridHAlignVar = $gridCSSVars[GridVars.HAlign] - $: gridVAlignVar = $gridCSSVars[GridVars.VAlign] - $: gridStyles = $state?.styles + $: device = $builderStore.previewDevice + $: gridHAlignVar = getGridVar(device, GridParams.HAlign) + $: gridVAlignVar = getGridVar(device, GridParams.VAlign) const getBarSettings = definition => { let allSettings = [] @@ -156,7 +156,6 @@ value="start" icon="AlignLeft" title="Align left" - {gridStyles} {componentId} />
@@ -189,7 +185,6 @@ value="start" icon="AlignTop" title="Align top" - {gridStyles} {componentId} />
diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index d3b16aeafd..88e8477d2d 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -1,5 +1,4 @@ import { builderStore } from "stores" -import { derived } from "svelte/store" import { buildStyleString } from "utils/styleable.js" /** @@ -11,10 +10,13 @@ import { buildStyleString } from "utils/styleable.js" * * Component definitions define their default layout preference via the * `grid.hAlign` and `grid.vAlign` keys in the manifest. + * + * We also apply grid-[mobile/desktop]-grow CSS classes to component wrapper + * DOM nodes to use later in selectors, to control the sizing of children. */ // Enum representing the different CSS variables we use for grid metadata -export const GridVars = { +export const GridParams = { HAlign: "h-align", VAlign: "v-align", ColStart: "col-start", @@ -35,38 +37,8 @@ const Devices = { Mobile: "mobile", } -// A derived map of all CSS variables for the current device -const previewDevice = derived(builderStore, $store => $store.previewDevice) -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 => { - 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 -export const getDefaultGridVarValue = cssVar => { - if (cssVar.includes("align")) { - return cssVar.includes("-h-") ? "stretch" : "center" - } else { - return cssVar.endsWith("-start") ? 1 : 2 - } -} +export const getGridVar = (device, param) => `--grid-${device}-${param}` // Determines whether a JS event originated from immediately within a grid export const isGridEvent = e => { @@ -92,32 +64,18 @@ export const getGridParentID = node => { return node?.parentNode?.closest(".grid")?.parentNode.dataset.id } -// Gets the current value of a certain grid CSS variable for a component -export const getGridVarValue = (styles, variable) => { - // Try the desired variable - let val = styles?.variables?.[variable] - - // Otherwise try the other device variables - if (!val) { - val = styles?.[getOtherDeviceGridVar(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 + // Applies the required listeners, CSS and classes to a component DOM node 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() + e.stopPropagation() builderStore.actions.selectComponent(id) } @@ -145,13 +103,14 @@ export const gridLayout = (node, metadata) => { 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" + vars[getGridVar(Devices.Desktop, GridParams.VAlign)] === "stretch" + ) + node.classList.toggle( + GridClasses.MobileFill, + vars[getGridVar(Devices.Mobile, GridParams.VAlign)] === "stretch" ) - node.classList.toggle(GridClasses.MobileFill, vars[mobileVar] === "stretch") // Add a listener to select this node on click if (interactive) { @@ -159,6 +118,7 @@ export const gridLayout = (node, metadata) => { } } + // Removes the previously set up listeners const removeListeners = () => { node.removeEventListener("click", selectComponent) } From 8a6d4c0bf6f5cb9b36be94b76ce9249d6108e3c1 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Sat, 3 Aug 2024 09:44:32 +0100 Subject: [PATCH 037/112] Update remaining components with sizes and grid metadata --- packages/client/manifest.json | 47 ++++++++++++++++--- .../src/components/app/BackgroundImage.svelte | 17 ++----- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 10503f30ac..6f665a80d7 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -1326,6 +1326,7 @@ "icon": "Images", "hasChildren": true, "styles": ["size"], + "showEmptyState": false, "size": { "width": 400, "height": 300 @@ -1765,7 +1766,11 @@ "icon": "GraphBarVertical", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -1934,7 +1939,11 @@ "icon": "GraphTrend", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -2098,7 +2107,11 @@ "icon": "GraphAreaStacked", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -2274,7 +2287,11 @@ "icon": "GraphPie", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -2414,7 +2431,11 @@ "icon": "GraphDonut", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -2554,7 +2575,11 @@ "icon": "GraphBarVerticalStacked", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -2671,7 +2696,11 @@ "icon": "Histogram", "size": { "width": 600, - "height": 400 + "height": 420 + }, + "grid": { + "hAlign": "stretch", + "vAlign": "center" }, "settings": [ { @@ -4425,6 +4454,10 @@ "width": 400, "height": 320 }, + "grid": { + "hAlign": "stretch", + "vAlign": "stretch" + }, "settings": [ { "type": "dataProvider", diff --git a/packages/client/src/components/app/BackgroundImage.svelte b/packages/client/src/components/app/BackgroundImage.svelte index df6459c417..07216bf9ca 100644 --- a/packages/client/src/components/app/BackgroundImage.svelte +++ b/packages/client/src/components/app/BackgroundImage.svelte @@ -19,20 +19,11 @@ } -{#if url} -
-
- -
+
+
+
-{:else if $builderStore.inBuilder} -
- -
-{/if} +
diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 114e131eb3..f723d9ad29 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -41,7 +41,7 @@ // Util to get the inner DOM node by a component ID const getDOMNode = id => { const component = document.getElementsByClassName(id)[0] - return [...component?.children][0] + return Array.from(component?.children || [])[0] } const getComponentStyles = gridStyles => { From df77aa3f83515f3c2d1d4728d57235a1907a3d4a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:07:20 +0100 Subject: [PATCH 047/112] Update when grid lines are shown, show sibling borders, add component padding, remove row and column settings --- .../_components/Screen/GeneralPanel.svelte | 26 ------ packages/client/manifest.json | 26 ------ .../client/src/components/app/Layout.svelte | 4 +- .../app/container/GridContainer.svelte | 88 ++++++++++++++----- .../components/preview/GridDNDHandler.svelte | 59 ++++++++----- packages/client/src/utils/grid.js | 4 +- 6 files changed, 107 insertions(+), 100 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index 2a5211a253..020dc11ae8 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -96,32 +96,6 @@ }, ] - // Add grid layout settings if required - if (screen.props.layout === "grid") { - settings = settings.concat([ - { - key: "props.cols", - label: "Columns", - control: Stepper, - defaultValue: 24, - props: { - min: 2, - max: 50, - }, - }, - { - key: "props.rows", - label: "Rows", - control: Stepper, - defaultValue: 24, - props: { - min: 2, - max: 50, - }, - }, - ]) - } - return settings } diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 6f665a80d7..8ca9698bcf 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -145,32 +145,6 @@ ], "defaultValue": "flex" }, - { - "type": "number", - "label": "Columns", - "key": "cols", - "placeholder": 12, - "defaultValue": 12, - "min": 2, - "max": 50, - "dependsOn": { - "setting": "layout", - "value": "grid" - } - }, - { - "type": "number", - "label": "Rows", - "key": "rows", - "placeholder": 12, - "defaultValue": 12, - "min": 2, - "max": 50, - "dependsOn": { - "setting": "layout", - "value": "grid" - } - }, { "type": "select", "label": "Direction", diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 9cfa74cbb0..34de8122c8 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -480,10 +480,10 @@ position: relative; padding: 32px; } - .main:has(.screenslot-dom > .component > .grid) { + /* .main:has(.screenslot-dom > .component > .grid) { padding-top: 0; padding-bottom: 0; - } + }*/ .layout--none .main { padding: 0; } diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index cfe6f7d7bf..b46e763277 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -2,19 +2,18 @@ import { getContext } from "svelte" const component = getContext("component") - const { styleable, builderStore } = getContext("sdk") + const { styleable } = getContext("sdk") const context = getContext("context") - export let cols = 12 - export let rows = 12 + const cols = 12 + const rowHeight = 24 let width let height - $: cols = cols || 12 - $: rows = rows || 12 $: mobile = $context.device.mobile $: empty = $component.empty + $: rows = Math.max(1, Math.floor(height / rowHeight)) $: colSize = width / cols $: rowSize = height / rows @@ -22,7 +21,6 @@
- {#if $builderStore.inBuilder} -
- {#each { length: cols * rows } as _} -
- {/each} -
- {/if} +
+ {#each { length: cols * rows } as _} +
+ {/each} +
{#if !empty} @@ -57,32 +53,53 @@ .grid { position: relative; height: 400px; - gap: 0; - } - .grid.builder { - background: var(--spectrum-alias-background-color-secondary); + --spacing: 10; } + .grid, .underlay { display: grid; grid-template-rows: repeat(var(--rows), 1fr); grid-template-columns: repeat(var(--cols), 1fr); + gap: 0; } .underlay { + display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; - border: 1px solid var(--spectrum-global-color-gray-900); - opacity: 0.07; + border-top: 1px solid var(--spectrum-global-color-gray-900); + border-left: 1px solid var(--spectrum-global-color-gray-900); + opacity: 0.1; pointer-events: none; } .underlay { z-index: 0; } .placeholder { - border: 1px solid var(--spectrum-global-color-gray-900); + border-bottom: 1px solid var(--spectrum-global-color-gray-900); + border-right: 1px solid var(--spectrum-global-color-gray-900); + } + + /* Highlight grid lines when resizing children */ + :global(.grid.highlight > .underlay) { + display: grid; + } + + /* Highlight sibling borders when resizing childern */ + :global(.grid.highlight > .component:not(.dragging):after) { + content: ""; + display: block; + position: absolute; + height: 100%; + width: 100%; + border: 1px solid var(--spectrum-global-color-static-blue-200); + pointer-events: none; + z-index: 1; + top: 0; + left: 0; } /* Ensure all top level children have grid styles applied */ @@ -90,6 +107,9 @@ display: flex; overflow: auto; pointer-events: all; + position: relative; + padding: 5px; + margin: 5px; /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ @@ -98,7 +118,12 @@ --grid-desktop-col-end, var( --grid-mobile-col-end, - round(up, calc(var(--default-width) / var(--col-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-width)) / var(--col-size) + 1 + ) + ) ) ); --row-start: var(--grid-desktop-row-start, var(--grid-mobile-row-start, 1)); @@ -106,7 +131,12 @@ --grid-desktop-row-end, var( --grid-mobile-row-end, - round(up, calc(var(--default-height) / var(--row-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-height)) / var(--row-size) + 1 + ) + ) ) ); @@ -137,7 +167,12 @@ --grid-mobile-col-end, var( --grid-desktop-col-end, - round(up, calc(var(--default-width) / var(--col-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-width)) / var(--col-size) + 1 + ) + ) ) ); --row-start: var(--grid-mobile-row-start, var(--grid-desktop-row-start, 1)); @@ -145,7 +180,12 @@ --grid-mobile-row-end, var( --grid-desktop-row-end, - round(up, calc(var(--default-height) / var(--row-size) + 1)) + round( + up, + calc( + (var(--spacing) * 2 + var(--default-height)) / var(--row-size) + 1 + ) + ) ) ); diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index f723d9ad29..fe004982d3 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -4,7 +4,7 @@ import { Utils, memo } from "@budibase/frontend-core" import { isGridEvent, - getGridParentID, + getGridParent, GridParams, getGridVar, } from "utils/grid" @@ -62,6 +62,9 @@ const { startX, startY, rowStart, rowEnd, colStart, colEnd } = grid const domGrid = getDOMNode(gridId) + if (!domGrid) { + return + } const cols = parseInt(domGrid.dataset.cols) const rows = parseInt(domGrid.dataset.rows) const { width, height } = domGrid.getBoundingClientRect() @@ -107,7 +110,7 @@ } gridStyles.set(newStyles) } - }, 100) + }, 10) const handleEvent = e => { e.preventDefault() @@ -140,16 +143,20 @@ // Find grid parent const domComponent = getDOMNode(id) - const gridId = getGridParentID(domComponent) - if (!gridId) { + const domGrid = getGridParent(domComponent) + if (!domGrid) { return } + // Apply active class to grid + domComponent.parentNode.classList.add("dragging") + domGrid.classList.add("highlight") + // Update state dragInfo = { domTarget: e.target, id, - gridId, + gridId: domGrid.parentNode.dataset.id, mode, side, } @@ -168,22 +175,23 @@ const { id, gridId } = dragInfo const domComponent = getDOMNode(id) const domGrid = getDOMNode(gridId) + if (!domComponent || !domGrid) { + return + } const gridCols = parseInt(domGrid.dataset.cols) const gridRows = parseInt(domGrid.dataset.rows) const styles = getComputedStyle(domComponent.parentNode) - if (domGrid) { - dragInfo.grid = { - startX: e.clientX, - startY: e.clientY, + dragInfo.grid = { + startX: e.clientX, + startY: e.clientY, - // Ensure things are within limits - rowStart: minMax(styles["grid-row-start"], 1, gridRows), - rowEnd: minMax(styles["grid-row-end"], 2, gridRows + 1), - colStart: minMax(styles["grid-column-start"], 1, gridCols), - colEnd: minMax(styles["grid-column-end"], 2, gridCols + 1), - } - handleEvent(e) + // Ensure things are within limits + rowStart: minMax(styles["grid-row-start"], 1, gridRows), + rowEnd: minMax(styles["grid-row-end"], 2, gridRows + 1), + colStart: minMax(styles["grid-column-start"], 1, gridCols), + colEnd: minMax(styles["grid-column-end"], 2, gridCols + 1), } + handleEvent(e) } const onDragOver = e => { @@ -195,15 +203,26 @@ // Callback when drag stops (whether dropped or not) const stopDragging = async () => { + if (!dragInfo) { + return + } + const { id, gridId, domTarget } = dragInfo + // Save changes if ($gridStyles) { - await builderStore.actions.updateStyles($gridStyles, dragInfo.id) + await builderStore.actions.updateStyles($gridStyles, id) } - // Reset listener - if (dragInfo?.domTarget) { - dragInfo.domTarget.removeEventListener("dragend", stopDragging) + // Reset DOM + const domComponent = getDOMNode(id) + if (domComponent) { + domComponent.parentNode.classList.remove("dragging") } + const domGrid = getDOMNode(gridId) + if (domGrid) { + domGrid.classList.remove("highlight") + } + domTarget.removeEventListener("dragend", stopDragging) // Reset state dragInfo = null diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 1d80e49696..54c5e2c24f 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -60,8 +60,8 @@ export const isGridChild = node => { } // Gets the component ID of the closest parent grid -export const getGridParentID = node => { - return node?.parentNode?.closest(".grid")?.parentNode.dataset.id +export const getGridParent = node => { + return node?.parentNode?.closest(".grid") } // Svelte action to apply required class names and styles to our component From d3b7a06871c5ac959ba24437aff3a131ffa537af Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:17:01 +0100 Subject: [PATCH 048/112] Ensure nav accounts for grid layout padding --- packages/client/src/components/app/Layout.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 34de8122c8..4a49dabbe9 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -414,6 +414,9 @@ color: var(--navTextColor); opacity: 1; } + .layout:has(.screenslot-dom > .component > .grid) .nav { + padding: 24px 42px 20px 42px; + } .nav :global(h1) { color: var(--navTextColor); @@ -480,10 +483,7 @@ position: relative; padding: 32px; } - /* .main:has(.screenslot-dom > .component > .grid) { - padding-top: 0; - padding-bottom: 0; - }*/ + .layout--none .main { padding: 0; } From cacc2ab087e73e59922e33b5abacd1818ebe6f18 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:28:58 +0100 Subject: [PATCH 049/112] Fix issues with nesting grids inside grids --- .../components/app/container/GridContainer.svelte | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index b46e763277..89e39394ce 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -54,6 +54,20 @@ position: relative; height: 400px; --spacing: 10; + + /* + Prevent cross-grid variable inheritance. The other variables for alignment + are always set on each component, so we don't need to worry about + 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, From 73079e44175f45f15a8f3b1accb3cec934d1851b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:43:22 +0100 Subject: [PATCH 050/112] Fix some layout edge cases --- packages/client/src/components/app/Layout.svelte | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 4a49dabbe9..72121640a6 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -406,6 +406,9 @@ max-width: 100%; gap: var(--spacing-xl); } + .nav.size--max { + padding: 10px; + } .nav :global(.spectrum-Icon) { color: var(--navTextColor); opacity: 0.75; @@ -414,10 +417,6 @@ color: var(--navTextColor); opacity: 1; } - .layout:has(.screenslot-dom > .component > .grid) .nav { - padding: 24px 42px 20px 42px; - } - .nav :global(h1) { color: var(--navTextColor); } @@ -483,6 +482,9 @@ position: relative; padding: 32px; } + .main:not(.size--max):has(.screenslot-dom > .component > .grid) { + padding: 22px; + } .layout--none .main { padding: 0; @@ -614,6 +616,10 @@ .mobile:not(.layout--none) .main { padding: 16px; } + .mobile:not(.layout--none) + .main:not(.size--max):has(.screenslot-dom > .component > .grid) { + padding: 6px; + } .mobile .main.size--max { padding: 0; } From 4c7f65a811e9bf302d2128d166e047e901e6f07f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:48:00 +0100 Subject: [PATCH 051/112] Add more styles to forms --- packages/client/manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 8ca9698bcf..f232318c53 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2825,7 +2825,7 @@ "UpdateFieldValue", "ScrollTo" ], - "styles": ["size"], + "styles": ["padding", "size", "background", "border", "shadow"], "size": { "width": 400, "height": 400 @@ -6804,7 +6804,7 @@ "hAlign": "stretch", "vAlign": "start" }, - "styles": ["size"], + "styles": ["padding", "size", "background", "border", "shadow"], "settings": [ { "type": "table", @@ -6988,7 +6988,7 @@ "formblock": { "name": "Form Block", "icon": "Form", - "styles": ["size"], + "styles": ["padding", "size", "background", "border", "shadow"], "block": true, "info": "Form blocks are only compatible with internal or SQL tables", "size": { From 8e04e85df2cdf07cb9389c6cc9145acbdd95be04 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 6 Aug 2024 11:48:47 +0100 Subject: [PATCH 052/112] Lint --- .../[componentId]/_components/Screen/GeneralPanel.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index 020dc11ae8..62fe593602 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -6,7 +6,6 @@ Checkbox, Banner, Select, - Stepper, notifications, } from "@budibase/bbui" import PropertyControl from "components/design/settings/controls/PropertyControl.svelte" From 5eebbd56f6110ba0f2090ba0bfc918731504f1c2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 8 Aug 2024 16:15:05 +0100 Subject: [PATCH 053/112] Reduce spacing between components in grids to 16px from 20px --- .../src/components/app/container/GridContainer.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 89e39394ce..cb2c285b84 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -53,7 +53,7 @@ .grid { position: relative; height: 400px; - --spacing: 10; + --spacing: 8; /* Prevent cross-grid variable inheritance. The other variables for alignment @@ -122,8 +122,8 @@ overflow: auto; pointer-events: all; position: relative; - padding: 5px; - margin: 5px; + padding: 4px; + margin: 4px; /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ From 618b65e3faf6e6f89edc2e568da9438233b38cf9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 8 Aug 2024 16:23:55 +0100 Subject: [PATCH 054/112] Use outline rather than pseudo elements for highlighting grid children --- .../components/app/container/GridContainer.svelte | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index cb2c285b84..f3682179c4 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -103,17 +103,8 @@ } /* Highlight sibling borders when resizing childern */ - :global(.grid.highlight > .component:not(.dragging):after) { - content: ""; - display: block; - position: absolute; - height: 100%; - width: 100%; - border: 1px solid var(--spectrum-global-color-static-blue-200); - pointer-events: none; - z-index: 1; - top: 0; - left: 0; + :global(.grid.highlight > .component:not(.dragging)) { + outline: 1px solid var(--spectrum-global-color-static-blue-200); } /* Ensure all top level children have grid styles applied */ From cdc2092264aed0672dc92136fae570fce4a126b6 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 8 Aug 2024 16:30:31 +0100 Subject: [PATCH 055/112] Only apply grid action when component is an immediate child of a grid container --- packages/client/src/components/Component.svelte | 9 ++++++++- packages/client/src/utils/grid.js | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 0a216bd675..8083678482 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -42,6 +42,7 @@ import { gridLayout } from "utils/grid.js" export let instance = {} + export let parent = null export let isLayout = false export let isRoot = false export let isBlock = false @@ -194,14 +195,20 @@ $: pad = pad || (interactive && hasChildren && inDndPath) $: $dndIsDragging, (pad = false) + // Themes $: currentTheme = $context?.device?.theme $: darkMode = !currentTheme?.includes("light") + // Apply ephemeral styles (such as when resizing grid components) $: normalStyles = { ...instance._styles?.normal, ...ephemeralStyles, } + + // Metadata to pass into grid action to apply CSS $: gridMetadata = { + active: + parent?._component.endsWith("/container") && parent?.layout === "grid", id, interactive, styles: normalStyles, @@ -672,7 +679,7 @@ {#if children.length} {#each children as child (child._id)} - + {/each} {:else if emptyState} {#if isRoot} diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 54c5e2c24f..d974e31899 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -71,7 +71,11 @@ export const gridLayout = (node, metadata) => { // Applies the required listeners, CSS and classes to a component DOM node const applyMetadata = metadata => { - const { id, styles, interactive, errored, definition, draggable } = metadata + const { id, styles, interactive, errored, definition, draggable, active } = + metadata + if (!active) { + return + } // Callback to select the component when clicking on the wrapper selectComponent = e => { From 8a022bb21e33ba9ada656024fa0c840f494273a8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 9 Aug 2024 08:48:32 +0100 Subject: [PATCH 056/112] Use single CSS variable for grid spacing to reduce duplication --- packages/client/src/components/app/Layout.svelte | 7 +++++-- .../src/components/app/container/GridContainer.svelte | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index 72121640a6..a1ce77df72 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -352,6 +352,9 @@ z-index: 1; overflow: hidden; position: relative; + + /* Deliberately unitless as we need to do unitless calculations in grids */ + --grid-spacing: 4; } .component { display: contents; @@ -407,7 +410,7 @@ gap: var(--spacing-xl); } .nav.size--max { - padding: 10px; + padding: calc(var(--grid-spacing) * 2px); } .nav :global(.spectrum-Icon) { color: var(--navTextColor); @@ -483,7 +486,7 @@ padding: 32px; } .main:not(.size--max):has(.screenslot-dom > .component > .grid) { - padding: 22px; + padding: calc(32px - var(--grid-spacing) * 2px); } .layout--none .main { diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index f3682179c4..6df0fdd2d4 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -53,7 +53,6 @@ .grid { position: relative; height: 400px; - --spacing: 8; /* Prevent cross-grid variable inheritance. The other variables for alignment @@ -113,8 +112,8 @@ overflow: auto; pointer-events: all; position: relative; - padding: 4px; - margin: 4px; + padding: calc(var(--grid-spacing) * 1px); + margin: calc(var(--grid-spacing) * 1px); /* On desktop, use desktop metadata and fall back to mobile */ /* Position vars */ @@ -126,7 +125,8 @@ round( up, calc( - (var(--spacing) * 2 + var(--default-width)) / var(--col-size) + 1 + (var(--grid-spacing) * 2 + var(--default-width)) / var(--col-size) + + 1 ) ) ) @@ -139,7 +139,8 @@ round( up, calc( - (var(--spacing) * 2 + var(--default-height)) / var(--row-size) + 1 + (var(--grid-spacing) * 2 + var(--default-height)) / var(--row-size) + + 1 ) ) ) From 86061543dde386888bfb60474ec818bc36875248 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 9 Aug 2024 08:52:03 +0100 Subject: [PATCH 057/112] Slightly improve the look and behaviour of working with grid components --- .../client/src/components/app/container/GridContainer.svelte | 2 +- packages/client/src/components/preview/GridDNDHandler.svelte | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 6df0fdd2d4..8e8621c1a6 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -103,7 +103,7 @@ /* Highlight sibling borders when resizing childern */ :global(.grid.highlight > .component:not(.dragging)) { - outline: 1px solid var(--spectrum-global-color-static-blue-200); + outline: 2px solid var(--spectrum-global-color-static-blue-200); } /* Ensure all top level children have grid styles applied */ diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index fe004982d3..0a3ecad72c 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -147,6 +147,7 @@ if (!domGrid) { return } + builderStore.actions.selectComponent(id) // Apply active class to grid domComponent.parentNode.classList.add("dragging") From 46beead098feffdefc546eb3796b6f839d8c8feb Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 9 Aug 2024 09:14:53 +0100 Subject: [PATCH 058/112] Update the style of edge anchors --- .../src/components/preview/Indicator.svelte | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/packages/client/src/components/preview/Indicator.svelte b/packages/client/src/components/preview/Indicator.svelte index d93ecaa02b..605611d3a1 100644 --- a/packages/client/src/components/preview/Indicator.svelte +++ b/packages/client/src/components/preview/Indicator.svelte @@ -131,6 +131,7 @@ display: grid; place-items: center; border-radius: 50%; + transform: translateX(-50%) translateY(-50%); } .anchor-inner { width: calc(var(--size) / 2); @@ -140,45 +141,66 @@ pointer-events: none; border-radius: 2px; } + + /* Thinner anchors for each edge */ + .anchor.right, + .anchor.left { + height: calc(var(--size) * 2); + } + .anchor.top, + .anchor.bottom { + width: calc(var(--size) * 2); + } + .anchor.right .anchor-inner, + .anchor.left .anchor-inner { + height: calc(var(--size) * 1.4); + width: calc(var(--size) * 0.3); + } + .anchor.top .anchor-inner, + .anchor.bottom .anchor-inner { + width: calc(var(--size) * 1.4); + height: calc(var(--size) * 0.3); + } + + /* Anchor positions */ .anchor.right { - right: calc(var(--size) / -2 - 1px); - top: calc(50% - var(--size) / 2); + left: calc(100% + 1px); + top: 50%; cursor: e-resize; } .anchor.left { - left: calc(var(--size) / -2 - 1px); - top: calc(50% - var(--size) / 2); + left: -1px; + top: 50%; cursor: w-resize; } .anchor.bottom { - left: calc(50% - var(--size) / 2 + 1px); - bottom: calc(var(--size) / -2 - 1px); + left: 50%; + top: calc(100% + 1px); cursor: s-resize; } .anchor.top { - left: calc(50% - var(--size) / 2 + 1px); - top: calc(var(--size) / -2 - 1px); + left: 50%; + top: -1px; cursor: n-resize; } - .anchor.bottom-right { - right: calc(var(--size) / -2 - 1px); - bottom: calc(var(--size) / -2 - 1px); + top: 100%; + left: 100%; cursor: se-resize; } .anchor.bottom-left { - left: calc(var(--size) / -2 - 1px); - bottom: calc(var(--size) / -2 - 1px); + left: 0; + top: 100%; cursor: sw-resize; } .anchor.top-right { - right: calc(var(--size) / -2 - 1px); - top: calc(var(--size) / -2 - 1px); + left: 100%; + top: 0; cursor: ne-resize; } .anchor.top-left { - left: calc(var(--size) / -2 - 1px); - top: calc(var(--size) / -2 - 1px); + left: 0; + top: 0; cursor: nw-resize; } From aaa33acc1c2ada8c44412e872ab42cc33497856a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 9 Aug 2024 18:04:23 +0100 Subject: [PATCH 059/112] Rework grid layouts to automatically grow as required --- .../app/container/GridContainer.svelte | 169 ++++++++++++------ .../components/preview/GridDNDHandler.svelte | 66 ++++--- packages/client/src/constants.js | 3 + packages/client/src/utils/grid.js | 24 ++- 4 files changed, 183 insertions(+), 79 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 8e8621c1a6..d97e7ceafb 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -1,50 +1,136 @@
-
- {#each { length: cols * rows } as _} -
- {/each} -
+ {#if $builderStore.inBuilder} +
+ {#each { length: GridColumns * rows } as _, idx} +
+ {/each} +
+ {/if} - {#if !empty} + {#if !empty && mounted} {/if}
@@ -52,7 +138,6 @@ diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index e86f163dba..357e9ff084 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -198,7 +198,7 @@ overflow: hidden; height: 410px; } - div.in-builder :global(*) { - pointer-events: none; + div.in-builder { + pointer-events: none !important; } diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 0caee53953..a5ff8e0c27 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -36,7 +36,6 @@ // Set ephemeral styles $: instance = componentStore.actions.getComponentInstance(id) $: $instance?.setEphemeralStyles(enrichComponentStyles($styles)) - $: $styles, console.log("new styles") // Sugar for a combination of both min and max const minMax = (value, min, max) => Math.min(max, Math.max(min, value)) From d77e4381cc84892b964a3e667d8b7a0f127d982a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 09:55:12 +0100 Subject: [PATCH 070/112] Speed up memo stores --- packages/frontend-core/src/utils/memo.js | 25 ++++++++---------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/packages/frontend-core/src/utils/memo.js b/packages/frontend-core/src/utils/memo.js index ba0e3f3490..b99af15c2c 100644 --- a/packages/frontend-core/src/utils/memo.js +++ b/packages/frontend-core/src/utils/memo.js @@ -4,32 +4,23 @@ import { writable, get, derived } from "svelte/store" // subscribed children will only fire when a new value is actually set export const memo = initialValue => { const store = writable(initialValue) + let currentJSON = null - const tryUpdateValue = (newValue, currentValue) => { - // Sanity check for primitive equality - if (currentValue === newValue) { - return - } - - // Otherwise deep compare via JSON stringify - const currentString = JSON.stringify(currentValue) - const newString = JSON.stringify(newValue) - if (currentString !== newString) { + const tryUpdateValue = newValue => { + const newJSON = JSON.stringify(newValue) + if (newJSON !== currentJSON) { store.set(newValue) + currentJSON = newJSON } } return { subscribe: store.subscribe, - set: newValue => { - const currentValue = get(store) - tryUpdateValue(newValue, currentValue) - }, + set: tryUpdateValue, update: updateFn => { - const currentValue = get(store) - let mutableCurrentValue = JSON.parse(JSON.stringify(currentValue)) + let mutableCurrentValue = JSON.parse(currentJSON) const newValue = updateFn(mutableCurrentValue) - tryUpdateValue(newValue, currentValue) + tryUpdateValue(newValue) }, } } From 5b8846208b441b8331c8859a6bd984ef8f3d7cf6 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 09:55:45 +0100 Subject: [PATCH 071/112] Prevent pointer events on non-dragged grid children to reduce hit test load --- .../client/src/components/app/container/GridContainer.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 981a321e14..09fd15d599 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -177,6 +177,7 @@ /* Highlight sibling borders when resizing childern */ :global(.grid.highlight > .component:not(.dragging)) { outline: 2px solid var(--spectrum-global-color-static-blue-200); + pointer-events: none !important; } /* Ensure all top level children have grid styles applied */ From 9f951bab20b16e491fe5ad45cc9a561a2142a2c4 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 10:24:14 +0100 Subject: [PATCH 072/112] Revert indicator sets to use IntersectionObservers when multiple indicators are required --- .../components/preview/IndicatorSet.svelte | 61 +++++++++++++++++-- .../src/components/preview/SettingsBar.svelte | 2 +- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index 6c899cb4fd..3c34d0de5d 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -33,7 +33,12 @@ let interval let state = defaultState() let observing = false + let updating = false + let observers = [] + let callbackCount = 0 + let nextState + $: visibleIndicators = state.indicators.filter(x => x.visible) $: offset = $builderStore.inBuilder ? 5 : -1 $: config.set({ componentId, @@ -70,7 +75,25 @@ return isGridChild(document.getElementsByClassName(id)[0]) } + const createIntersectionCallback = idx => entries => { + if (callbackCount >= observers.length) { + return + } + nextState.indicators[idx].visible = + nextState.indicators[idx].insideModal || + nextState.indicators[idx].insideSidePanel || + entries[0].isIntersecting + if (++callbackCount === observers.length) { + state = nextState + updating = false + } + } + const updatePosition = () => { + if (updating) { + return + } + // Sanity check if (!componentId) { state = defaultState() @@ -81,13 +104,17 @@ state = defaultState() return } + updating = true + callbackCount = 0 + observers.forEach(o => o.disconnect()) + observers = [] + nextState = defaultState() // Start observing if this is the first time we've seen our component // in the DOM if (!observing) { observeChanges(componentId) } - let nextState = defaultState() // Check if we're inside a grid if (allowResizeAnchors) { @@ -114,6 +141,7 @@ const children = Array.from(document.getElementsByClassName(className)) .filter(x => x != null) .slice(0, 100) + const multi = children.length > 1 // If there aren't any nodes then reset if (!children.length) { @@ -123,16 +151,39 @@ const device = document.getElementById("app-root") const deviceBounds = device.getBoundingClientRect() - nextState.indicators = children.map(child => { + nextState.indicators = children.map((child, idx) => { const elBounds = child.getBoundingClientRect() - return { + let indicator = { top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset), left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset), width: Math.round(elBounds.width + 2), height: Math.round(elBounds.height + 2), + visible: true, } + + // If observing more than one node then we need to use an intersection + // observer to determine whether each indicator should be visible + if (multi) { + const callback = createIntersectionCallback(idx) + const observer = new IntersectionObserver(callback, { + threshold: 1, + root: device, + }) + observer.observe(child) + observers.push(observer) + indicator.visible = false + indicator.insideSidePanel = !!child.closest(".side-panel") + indicator.insideModal = !!child.closest(".modal-content") + } + + return indicator }) - state = nextState + + // Immediately apply the update if we're just observing a single node + if (!multi) { + state = nextState + updating = false + } } const debouncedUpdate = Utils.domDebounce(updatePosition) @@ -149,7 +200,7 @@ }) -{#each state.indicators as indicator, idx} +{#each visibleIndicators as indicator, idx} Date: Mon, 12 Aug 2024 10:48:38 +0100 Subject: [PATCH 073/112] Allow grid containers to use their natural height as a min height --- .../app/container/GridContainer.svelte | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 09fd15d599..39358484a6 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -9,22 +9,26 @@ const context = getContext("context") let width + let height let ref let rows = 1 let children = writable({}) let mounted = false let styles = memo({}) - $: rows = calculateRequiredRows($children, mobile) + $: requiredRows = calculateRequiredRows($children, mobile) + $: requiredHeight = requiredRows * GridRowHeight + $: availableRows = Math.floor(height / GridRowHeight) + $: rows = Math.max(requiredRows, availableRows) $: mobile = $context.device.mobile $: empty = $component.empty $: colSize = width / GridColumns - $: height = rows * GridRowHeight $: styles.set({ ...$component.styles, normal: { ...$component.styles?.normal, - "--height": `${height}px`, + "--height": `${requiredHeight}px`, + "--min-height": $component.styles?.normal?.height || 0, "--cols": GridColumns, "--rows": rows, "--col-size": colSize, @@ -118,6 +122,7 @@ class="grid" class:mobile bind:clientWidth={width} + bind:clientHeight={height} use:styleable={$styles} data-cols={GridColumns} data-col-size={colSize} @@ -140,12 +145,13 @@ .grid, .underlay { height: var(--height) !important; - min-height: 0 !important; + min-height: var(--min-height) !important; max-height: none !important; display: grid; + gap: 0; grid-template-rows: repeat(var(--rows), calc(var(--row-size) * 1px)); grid-template-columns: repeat(var(--cols), 1fr); - gap: 0; + position: relative; } .underlay { display: none; From 51db5ac9a993864fa6f936e2be7271b0c5350b3c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 11:00:59 +0100 Subject: [PATCH 074/112] Lint --- packages/client/src/components/Component.svelte | 2 +- packages/client/src/utils/grid.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 7a8188864f..3d081f5a61 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -54,7 +54,7 @@ const component = getContext("component") // Create component context - const store = memo({}) + const store = writable({}) setContext("component", store) // Ref to the svelte component diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 3f2336f1cf..4e474b4d50 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -1,5 +1,4 @@ -import { GridSpacing } from "constants" -import { GridRowHeight } from "constants" +import { GridSpacing, GridRowHeight } from "constants" import { builderStore } from "stores" import { buildStyleString } from "utils/styleable.js" From 47e4c668eccb20882e911a6a364deaada596ebd3 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 14:01:33 +0100 Subject: [PATCH 075/112] Tidy up --- .../client/src/components/app/container/GridContainer.svelte | 4 ++-- packages/client/src/components/preview/IndicatorSet.svelte | 3 +-- packages/client/src/utils/grid.js | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 39358484a6..b1d00e6c07 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -5,7 +5,7 @@ import { memo } from "@budibase/frontend-core" const component = getContext("component") - const { styleable, builderStore } = getContext("sdk") + const { styleable } = getContext("sdk") const context = getContext("context") let width @@ -127,7 +127,7 @@ data-cols={GridColumns} data-col-size={colSize} > - {#if $builderStore.inBuilder} + {#if inBuilder}
{#each { length: GridColumns * rows } as _, idx}
diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index 3c34d0de5d..de7fc0f66c 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -14,6 +14,7 @@ // Offset = 6 (clip-root padding) - 1 (half the border thickness) const config = memo($$props) const errorColor = "var(--spectrum-global-color-static-red-600)" + const observer = new MutationObserver(() => debouncedUpdate()) const defaultState = () => ({ // Cached props componentId, @@ -54,8 +55,6 @@ // Observe style changes $: observeChanges(componentId) - const observer = new MutationObserver(() => debouncedUpdate()) - const observeChanges = id => { observer.disconnect() observing = false diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index 4e474b4d50..a7ca3e5286 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -135,6 +135,9 @@ export const gridLayout = (node, metadata) => { addDataTag("gridMobileHAlign", Devices.Mobile, GridParams.HAlign) addDataTag("gridDesktopVAlign", Devices.Desktop, GridParams.VAlign) addDataTag("gridMobileVAlign", Devices.Mobile, GridParams.VAlign) + if (node.dataset.insideGrid !== true) { + node.dataset.insideGrid = true + } // Apply all CSS variables to the wrapper node.style = buildStyleString(vars) From 1f99ecc5291edff974c1b2aa72c58b5e0d25320c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 14:03:31 +0100 Subject: [PATCH 076/112] Fix missing reference --- .../client/src/components/app/container/GridContainer.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index b1d00e6c07..39358484a6 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -5,7 +5,7 @@ import { memo } from "@budibase/frontend-core" const component = getContext("component") - const { styleable } = getContext("sdk") + const { styleable, builderStore } = getContext("sdk") const context = getContext("context") let width @@ -127,7 +127,7 @@ data-cols={GridColumns} data-col-size={colSize} > - {#if inBuilder} + {#if $builderStore.inBuilder}
{#each { length: GridColumns * rows } as _, idx}
From d423d530e417e80943be330b74d76e55e3055f19 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 14:45:17 +0100 Subject: [PATCH 077/112] Rewrite settings bar updates to improve performance --- .../src/components/app/GridBlock.svelte | 2 +- .../src/components/preview/SettingsBar.svelte | 204 ++++++++++-------- 2 files changed, 110 insertions(+), 96 deletions(-) diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 357e9ff084..30a35b0713 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -198,7 +198,7 @@ overflow: hidden; height: 410px; } - div.in-builder { + div.in-builder :global(> *) { pointer-events: none !important; } diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index b0c8cfcc82..09706726bb 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -11,25 +11,24 @@ const context = getContext("context") const verticalOffset = 36 const horizontalOffset = 2 + const observer = new MutationObserver(() => debouncedUpdate()) let top = 0 let left = 0 let interval let self let measured = false - let observer - + let observing = false let insideGrid = false let gridHAlign let gridVAlign + let deviceEl - // TODO: respect dependsOn keys - - $: componentId = $builderStore.selectedComponentId - $: measured, observeComputedStyles(componentId) + $: id = $builderStore.selectedComponentId + $: id, reset() $: component = $componentStore.selectedComponent $: definition = $componentStore.selectedComponentDefinition - $: instance = componentStore.actions.getComponentInstance(componentId) + $: instance = componentStore.actions.getComponentInstance(id) $: state = $instance?.state $: showBar = definition?.showSettingsBar !== false && @@ -37,7 +36,7 @@ definition && !$state?.errorState $: settings = getBarSettings(component, definition) - $: isRoot = componentId === $builderStore.screen?.props?._id + $: isRoot = id === $builderStore.screen?.props?._id $: showGridStyles = insideGrid && (definition?.grid?.hAlign !== "stretch" || @@ -47,6 +46,21 @@ $: gridHAlignVar = getGridVar(device, GridParams.HAlign) $: gridVAlignVar = getGridVar(device, GridParams.VAlign) + const reset = () => { + observer.disconnect() + measured = false + observing = false + insideGrid = false + } + + const startObserving = domBoundary => { + observer.observe(domBoundary, { + attributes: true, + attributeFilter: ["style"], + }) + observing = true + } + const getBarSettings = (component, definition) => { let allSettings = [] definition?.settings?.forEach(setting => { @@ -68,102 +82,102 @@ if (!showBar) { return } - const id = $builderStore.selectedComponentId - let element = document.getElementsByClassName(id)?.[0] - // Check if we're inside a grid - insideGrid = element?.parentNode.classList.contains("grid") + // Find DOM boundary and ensure it is valid + let domBoundary = document.getElementsByClassName(id)[0] + if (!domBoundary) { + return reset() + } + + // If we're inside a grid, allow time for buttons to render + const nextInsideGrid = domBoundary.dataset.insideGrid === "true" + if (nextInsideGrid && !insideGrid) { + insideGrid = true + return + } else { + insideGrid = nextInsideGrid + } + + // Get the correct DOM boundary depending if we're inside a grid or not if (!insideGrid) { - element = element?.children?.[0] + domBoundary = + domBoundary.getElementsByClassName(`${id}-dom`)[0] || + domBoundary.children?.[0] + } + if (!domBoundary || !self) { + return reset() } - // The settings bar is higher in the dom tree than the selection indicators - // as we want to be able to render the settings bar wider than the screen, - // or outside the screen. - // Therefore we use the clip root rather than the app root to determine - // its position. - const device = document.getElementById("clip-root") - if (element && self) { - // Batch reads to minimize reflow - const deviceBounds = device.getBoundingClientRect() - const elBounds = element.getBoundingClientRect() - const width = self.offsetWidth - const height = self.offsetHeight - const { scrollX, scrollY, innerWidth } = window + // Start observing if required + if (!observing) { + startObserving(domBoundary) + } - // Read grid metadata from data attributes - if (insideGrid) { - if (mobile) { - gridHAlign = element.dataset.gridMobileHAlign - gridVAlign = element.dataset.gridMobileVAlign - } else { - gridHAlign = element.dataset.gridDesktopHAlign - gridVAlign = element.dataset.gridDesktopVAlign - } - } + // Batch reads to minimize reflow + const deviceBounds = deviceEl.getBoundingClientRect() + const elBounds = domBoundary.getBoundingClientRect() + const width = self.offsetWidth + const height = self.offsetHeight + const { scrollX, scrollY, innerWidth } = window - // Vertically, always render above unless no room, then render inside - let newTop = elBounds.top + scrollY - verticalOffset - height - if (newTop < deviceBounds.top - 50) { - newTop = deviceBounds.top - 50 - } - if (newTop < 0) { - newTop = 0 - } - const deviceBottom = deviceBounds.top + deviceBounds.height - if (newTop > deviceBottom - 44) { - newTop = deviceBottom - 44 + // Read grid metadata from data attributes + if (insideGrid) { + if (mobile) { + gridHAlign = domBoundary.dataset.gridMobileHAlign + gridVAlign = domBoundary.dataset.gridMobileVAlign + } else { + gridHAlign = domBoundary.dataset.gridDesktopHAlign + gridVAlign = domBoundary.dataset.gridDesktopVAlign } + } - //If element is at the very top of the screen, put the bar below the element - if (elBounds.top < elBounds.height && elBounds.height < 80) { - newTop = elBounds.bottom + verticalOffset - } + // Vertically, always render above unless no room, then render inside + let newTop = elBounds.top + scrollY - verticalOffset - height + if (newTop < deviceBounds.top - 50) { + newTop = deviceBounds.top - 50 + } + if (newTop < 0) { + newTop = 0 + } + const deviceBottom = deviceBounds.top + deviceBounds.height + if (newTop > deviceBottom - 44) { + newTop = deviceBottom - 44 + } - // Horizontally, try to center first. - // Failing that, render to left edge of component. - // Failing that, render to right edge of component, - // Failing that, render to window left edge and accept defeat. - let elCenter = elBounds.left + scrollX + elBounds.width / 2 - let newLeft = elCenter - width / 2 + //If element is at the very top of the screen, put the bar below the element + if (elBounds.top < elBounds.height && elBounds.height < 80) { + newTop = elBounds.bottom + verticalOffset + } + + // Horizontally, try to center first. + // Failing that, render to left edge of component. + // Failing that, render to right edge of component, + // Failing that, render to window left edge and accept defeat. + let elCenter = elBounds.left + scrollX + elBounds.width / 2 + let newLeft = elCenter - width / 2 + if (newLeft < 0 || newLeft + width > innerWidth) { + newLeft = elBounds.left + scrollX - horizontalOffset if (newLeft < 0 || newLeft + width > innerWidth) { - newLeft = elBounds.left + scrollX - horizontalOffset + newLeft = elBounds.right + scrollX - width + horizontalOffset if (newLeft < 0 || newLeft + width > innerWidth) { - newLeft = elBounds.right + scrollX - width + horizontalOffset - if (newLeft < 0 || newLeft + width > innerWidth) { - newLeft = horizontalOffset - } + newLeft = horizontalOffset } } - - // Only update state when things changes to minimize renders - if (Math.round(newTop) !== Math.round(top)) { - top = newTop - } - if (Math.round(newLeft) !== Math.round(left)) { - left = newLeft - } - - measured = true } + + // Only update state when things changes to minimize renders + if (Math.round(newTop) !== Math.round(top)) { + top = newTop + } + if (Math.round(newLeft) !== Math.round(left)) { + left = newLeft + } + measured = true } const debouncedUpdate = Utils.domDebounce(updatePosition) - const observeComputedStyles = id => { - observer?.disconnect() - const node = document.getElementsByClassName(`${id}-dom`)[0]?.parentNode - if (node) { - observer = new MutationObserver(updatePosition) - observer.observe(node, { - attributes: true, - attributeFilter: ["style"], - childList: false, - subtree: false, - }) - } - } - onMount(() => { + deviceEl = document.getElementById("clip-root") debouncedUpdate() interval = setInterval(debouncedUpdate, 100) document.addEventListener("scroll", debouncedUpdate, true) @@ -172,7 +186,7 @@ onDestroy(() => { clearInterval(interval) document.removeEventListener("scroll", debouncedUpdate, true) - observer?.disconnect() + reset() }) @@ -190,7 +204,7 @@ icon="AlignLeft" title="Align left" active={gridHAlign === "start"} - {componentId} + componentId={id} />
{/if} From 25ff092da291c50da31f0e72d94eff9956ee7c57 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 14:54:39 +0100 Subject: [PATCH 078/112] Simplify some utils --- .../src/components/preview/GridDNDHandler.svelte | 16 +++++----------- .../src/components/preview/IndicatorSet.svelte | 6 +----- packages/client/src/utils/grid.js | 10 ---------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index a5ff8e0c27..cfcc2892af 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -40,12 +40,6 @@ // Sugar for a combination of both min and max const minMax = (value, min, max) => Math.min(max, Math.max(min, value)) - // Util to get the inner DOM node by a component ID - const getDOMNode = id => { - const component = document.getElementsByClassName(id)[0] - return Array.from(component?.children || [])[0] - } - const enrichComponentStyles = styles => { let clone = { ...styles } if (styles) { @@ -137,16 +131,16 @@ } // Find grid parent and read from DOM - const domComponent = getDOMNode(id) - const domGrid = getGridParent(domComponent) + const domComponent = document.getElementsByClassName(id)[0] + const domGrid = domComponent?.closest(".grid") if (!domGrid) { return } - const styles = getComputedStyle(domComponent.parentNode) + const styles = getComputedStyle(domComponent) // Show as active builderStore.actions.selectComponent(id) - domComponent.parentNode.classList.add("dragging") + domComponent.classList.add("dragging") domGrid.classList.add("highlight") // Update state @@ -187,7 +181,7 @@ const { id, domTarget, domGrid, domComponent } = dragInfo // Reset DOM - domComponent.parentNode.classList.remove("dragging") + domComponent.classList.remove("dragging") domGrid.classList.remove("highlight") domTarget.removeEventListener("dragend", stopDragging) diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index de7fc0f66c..af709d24ba 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -70,10 +70,6 @@ } } - const checkInsideGrid = id => { - return isGridChild(document.getElementsByClassName(id)[0]) - } - const createIntersectionCallback = idx => entries => { if (callbackCount >= observers.length) { return @@ -117,7 +113,7 @@ // Check if we're inside a grid if (allowResizeAnchors) { - nextState.insideGrid = checkInsideGrid(componentId) + nextState.insideGrid = parents[0]?.dataset.insideGrid === "true" } // Get text to display diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index a7ca3e5286..afce01bbaa 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -52,16 +52,6 @@ export const isGridEvent = e => { ) } -// Determines whether a DOM element is an immediate child of a grid -export const isGridChild = node => { - return node?.parentNode.classList.contains("grid") -} - -// Gets the component ID of the closest parent grid -export const getGridParent = node => { - return node?.parentNode?.closest(".grid") -} - // Svelte action to apply required class names and styles to our component // wrappers export const gridLayout = (node, metadata) => { From 2f3a7018ae56d804a5203c6154a8128d96a3817e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 15:29:03 +0100 Subject: [PATCH 079/112] More tidy up --- .../components/preview/GridDNDHandler.svelte | 8 +- .../components/preview/IndicatorSet.svelte | 86 +++++++++---------- .../src/components/preview/SettingsBar.svelte | 3 +- 3 files changed, 44 insertions(+), 53 deletions(-) diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index cfcc2892af..1d566f7416 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -3,13 +3,7 @@ import { builderStore, componentStore } from "stores" import { Utils, memo } from "@budibase/frontend-core" import { GridRowHeight } from "constants" - import { - isGridEvent, - getGridParent, - GridParams, - getGridVar, - Devices, - } from "utils/grid" + import { isGridEvent, GridParams, getGridVar, Devices } from "utils/grid" const context = getContext("context") diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index af709d24ba..dfea20a45f 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -3,7 +3,6 @@ import Indicator from "./Indicator.svelte" import { builderStore } from "stores" import { memo, Utils } from "@budibase/frontend-core" - import { isGridChild } from "utils/grid" export let componentId = null export let color = null @@ -14,7 +13,7 @@ // Offset = 6 (clip-root padding) - 1 (half the border thickness) const config = memo($$props) const errorColor = "var(--spectrum-global-color-static-red-600)" - const observer = new MutationObserver(() => debouncedUpdate()) + const mutationObserver = new MutationObserver(() => debouncedUpdate()) const defaultState = () => ({ // Cached props componentId, @@ -33,12 +32,13 @@ let interval let state = defaultState() - let observing = false + let observingMutations = false let updating = false - let observers = [] + let intersectionObservers = [] let callbackCount = 0 let nextState + $: componentId, reset() $: visibleIndicators = state.indicators.filter(x => x.visible) $: offset = $builderStore.inBuilder ? 5 : -1 $: config.set({ @@ -52,22 +52,18 @@ // Update position when any props change $: $config, debouncedUpdate() - // Observe style changes - $: observeChanges(componentId) + const reset = () => { + mutationObserver.disconnect() + observingMutations = false + updating = false + } - const observeChanges = id => { - observer.disconnect() - observing = false - const node = document.getElementsByClassName(id)[0] - if (node) { - observer.observe(node, { - attributes: true, - attributeFilter: ["style"], - childList: false, - subtree: false, - }) - observing = true - } + const observeMutations = element => { + mutationObserver.observe(element, { + attributes: true, + attributeFilter: ["style"], + }) + observingMutations = true } const createIntersectionCallback = idx => entries => { @@ -94,37 +90,37 @@ state = defaultState() return } - const parents = document.getElementsByClassName(componentId) - if (!parents.length) { + let elements = document.getElementsByClassName(componentId) + if (!elements.length) { state = defaultState() return } updating = true callbackCount = 0 - observers.forEach(o => o.disconnect()) - observers = [] + intersectionObservers.forEach(o => o.disconnect()) + intersectionObservers = [] nextState = defaultState() - // Start observing if this is the first time we've seen our component - // in the DOM - if (!observing) { - observeChanges(componentId) + // Start observing mutations if this is the first time we've seen our + // component in the DOM + if (!observingMutations) { + observeMutations(elements[0]) } // Check if we're inside a grid if (allowResizeAnchors) { - nextState.insideGrid = parents[0]?.dataset.insideGrid === "true" + nextState.insideGrid = elements[0]?.dataset.insideGrid === "true" } // Get text to display - nextState.text = parents[0].dataset.name + nextState.text = elements[0].dataset.name if (nextState.prefix) { nextState.text = `${nextState.prefix} ${nextState.text}` } - if (parents[0].dataset.icon) { - nextState.icon = parents[0].dataset.icon + if (elements[0].dataset.icon) { + nextState.icon = elements[0].dataset.icon } - nextState.error = parents[0].classList.contains("error") + nextState.error = elements[0].classList.contains("error") // Batch reads to minimize reflow const scrollX = window.scrollX @@ -132,22 +128,24 @@ // Extract valid children // Sanity limit of active indicators - const className = nextState.insideGrid ? componentId : `${componentId}-dom` - const children = Array.from(document.getElementsByClassName(className)) + if (!nextState.insideGrid) { + elements = document.getElementsByClassName(`${componentId}-dom`) + } + elements = Array.from(elements) .filter(x => x != null) .slice(0, 100) - const multi = children.length > 1 + const multi = elements.length > 1 // If there aren't any nodes then reset - if (!children.length) { + if (!elements.length) { state = defaultState() return } const device = document.getElementById("app-root") const deviceBounds = device.getBoundingClientRect() - nextState.indicators = children.map((child, idx) => { - const elBounds = child.getBoundingClientRect() + nextState.indicators = elements.map((element, idx) => { + const elBounds = element.getBoundingClientRect() let indicator = { top: Math.round(elBounds.top + scrollY - deviceBounds.top + offset), left: Math.round(elBounds.left + scrollX - deviceBounds.left + offset), @@ -160,15 +158,15 @@ // observer to determine whether each indicator should be visible if (multi) { const callback = createIntersectionCallback(idx) - const observer = new IntersectionObserver(callback, { + const intersectionObserver = new IntersectionObserver(callback, { threshold: 1, root: device, }) - observer.observe(child) - observers.push(observer) + intersectionObserver.observe(element) + intersectionObservers.push(intersectionObserver) indicator.visible = false - indicator.insideSidePanel = !!child.closest(".side-panel") - indicator.insideModal = !!child.closest(".modal-content") + indicator.insideSidePanel = !!element.closest(".side-panel") + indicator.insideModal = !!element.closest(".modal-content") } return indicator @@ -189,7 +187,7 @@ }) onDestroy(() => { - observer.disconnect() + mutationObserver.disconnect() clearInterval(interval) document.removeEventListener("scroll", debouncedUpdate, true) }) diff --git a/packages/client/src/components/preview/SettingsBar.svelte b/packages/client/src/components/preview/SettingsBar.svelte index 09706726bb..ec861ab5b4 100644 --- a/packages/client/src/components/preview/SettingsBar.svelte +++ b/packages/client/src/components/preview/SettingsBar.svelte @@ -22,7 +22,6 @@ let insideGrid = false let gridHAlign let gridVAlign - let deviceEl $: id = $builderStore.selectedComponentId $: id, reset() @@ -114,6 +113,7 @@ } // Batch reads to minimize reflow + const deviceEl = document.getElementById("clip-root") const deviceBounds = deviceEl.getBoundingClientRect() const elBounds = domBoundary.getBoundingClientRect() const width = self.offsetWidth @@ -177,7 +177,6 @@ const debouncedUpdate = Utils.domDebounce(updatePosition) onMount(() => { - deviceEl = document.getElementById("clip-root") debouncedUpdate() interval = setInterval(debouncedUpdate, 100) document.addEventListener("scroll", debouncedUpdate, true) From d6f33b219101508e4883b8390b5c56570873a917 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 16:13:47 +0100 Subject: [PATCH 080/112] Change how z-index is applied to the dragged element --- .../src/components/app/container/GridContainer.svelte | 5 ++++- .../src/components/preview/GridDNDHandler.svelte | 11 +---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 39358484a6..6cc95e286e 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -150,7 +150,7 @@ display: grid; gap: 0; grid-template-rows: repeat(var(--rows), calc(var(--row-size) * 1px)); - grid-template-columns: repeat(var(--cols), 1fr); + grid-template-columns: repeat(var(--cols), calc(var(--col-size) * 1px)); position: relative; } .underlay { @@ -185,6 +185,9 @@ outline: 2px solid var(--spectrum-global-color-static-blue-200); pointer-events: none !important; } + :global(.grid.highlight > .component.dragging) { + z-index: 999 !important; + } /* Ensure all top level children have grid styles applied */ .grid :global(> .component) { diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index 1d566f7416..db19c460c1 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -29,20 +29,11 @@ // Set ephemeral styles $: instance = componentStore.actions.getComponentInstance(id) - $: $instance?.setEphemeralStyles(enrichComponentStyles($styles)) + $: $instance?.setEphemeralStyles($styles) // Sugar for a combination of both min and max const minMax = (value, min, max) => Math.min(max, Math.max(min, value)) - const enrichComponentStyles = styles => { - let clone = { ...styles } - if (styles) { - clone["z-index"] = 999 - clone["pointer-events"] = "none" - } - return clone - } - const processEvent = Utils.domDebounce((mouseX, mouseY) => { if (!dragInfo?.grid) { return From 96882e7eca0309a0da43693e2bfb86f69377bcd8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 12 Aug 2024 19:27:33 +0100 Subject: [PATCH 081/112] Improve performance of styleable util --- packages/client/src/utils/styleable.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/client/src/utils/styleable.js b/packages/client/src/utils/styleable.js index dc6e8f5e26..0f484a9ab9 100644 --- a/packages/client/src/utils/styleable.js +++ b/packages/client/src/utils/styleable.js @@ -5,11 +5,11 @@ import { builderStore } from "stores" */ export const buildStyleString = (styleObject, customStyles) => { let str = "" - Object.entries(styleObject || {}).forEach(([style, value]) => { - if (style && value != null) { - str += `${style}: ${value}; ` + for (let key of Object.keys(styleObject || {})) { + if (styleObject[key] != null) { + str += `${key}:${styleObject[key]};` } - }) + } return str + (customStyles || "") } From ead4be7b88bc3052c78e8ded4fd1cb5c2221b627 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 13 Aug 2024 09:09:53 +0100 Subject: [PATCH 082/112] Add padding at bottom of grid for screen level grids --- packages/client/src/components/Screen.svelte | 2 +- .../components/app/container/GridContainer.svelte | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/Screen.svelte b/packages/client/src/components/Screen.svelte index 3c8fcf97e3..2d62b2f810 100644 --- a/packages/client/src/components/Screen.svelte +++ b/packages/client/src/components/Screen.svelte @@ -14,7 +14,7 @@ // Get the screen definition for the current route $: screen = $screenStore.activeScreen - $: screenDefinition = { cols: 24, rows: 24, ...screen?.props } + $: screenDefinition = { ...screen?.props, addEmptyRows: true } $: onLoadActions.set(screen?.onLoad) $: runOnLoadActions($onLoadActions, params) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 6cc95e286e..d14108e178 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -4,6 +4,8 @@ import { GridRowHeight, GridColumns } from "constants" import { memo } from "@budibase/frontend-core" + export let addEmptyRows = false + const component = getContext("component") const { styleable, builderStore } = getContext("sdk") const context = getContext("context") @@ -16,7 +18,7 @@ let mounted = false let styles = memo({}) - $: requiredRows = calculateRequiredRows($children, mobile) + $: requiredRows = calculateRequiredRows($children, mobile, addEmptyRows) $: requiredHeight = requiredRows * GridRowHeight $: availableRows = Math.floor(height / GridRowHeight) $: rows = Math.max(requiredRows, availableRows) @@ -39,7 +41,7 @@ // Calculates the minimum number of rows required to render all child // components, on a certain device type - const calculateRequiredRows = (children, mobile) => { + const calculateRequiredRows = (children, mobile, addEmptyRows) => { const key = mobile ? "mobileRowEnd" : "desktopRowEnd" let max = 2 for (let id of Object.keys(children)) { @@ -47,7 +49,12 @@ max = children[id][key] } } - return max - 1 + let rows = max - 1 + if (addEmptyRows) { + return Math.ceil((rows + 10) / 10) * 10 + } else { + return rows + } } // Stores metadata about a child node as constraints for determining grid size From 73cc871a5eb25db32c6687c624a4f7504ab3fb63 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 13 Aug 2024 09:14:42 +0100 Subject: [PATCH 083/112] Avoid name clashing --- .../src/components/app/container/GridContainer.svelte | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index d14108e178..3c56f9517c 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -13,7 +13,6 @@ let width let height let ref - let rows = 1 let children = writable({}) let mounted = false let styles = memo({}) @@ -49,11 +48,11 @@ max = children[id][key] } } - let rows = max - 1 + let requiredRows = max - 1 if (addEmptyRows) { - return Math.ceil((rows + 10) / 10) * 10 + return Math.ceil((requiredRows + 10) / 10) * 10 } else { - return rows + return requiredRows } } From 78953848bbfd0deb20846e2c45e549532b8984e3 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 13 Aug 2024 09:19:16 +0100 Subject: [PATCH 084/112] Fix variable name error in indicator sets --- packages/client/src/components/preview/IndicatorSet.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/preview/IndicatorSet.svelte b/packages/client/src/components/preview/IndicatorSet.svelte index dfea20a45f..4af1224622 100644 --- a/packages/client/src/components/preview/IndicatorSet.svelte +++ b/packages/client/src/components/preview/IndicatorSet.svelte @@ -67,14 +67,14 @@ } const createIntersectionCallback = idx => entries => { - if (callbackCount >= observers.length) { + if (callbackCount >= intersectionObservers.length) { return } nextState.indicators[idx].visible = nextState.indicators[idx].insideModal || nextState.indicators[idx].insideSidePanel || entries[0].isIntersecting - if (++callbackCount === observers.length) { + if (++callbackCount === intersectionObservers.length) { state = nextState updating = false } From 0875d0c5e1aebef226d8285a8fa82597aacc811f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 13 Aug 2024 09:52:10 +0100 Subject: [PATCH 085/112] Only show empty rows in grid layouts when in the builder --- .../src/components/app/container/GridContainer.svelte | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 3c56f9517c..f332e197c3 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -17,7 +17,12 @@ let mounted = false let styles = memo({}) - $: requiredRows = calculateRequiredRows($children, mobile, addEmptyRows) + $: inBuilder = $builderStore.inBuilder + $: requiredRows = calculateRequiredRows( + $children, + mobile, + addEmptyRows && inBuilder + ) $: requiredHeight = requiredRows * GridRowHeight $: availableRows = Math.floor(height / GridRowHeight) $: rows = Math.max(requiredRows, availableRows) @@ -133,7 +138,7 @@ data-cols={GridColumns} data-col-size={colSize} > - {#if $builderStore.inBuilder} + {#if inBuilder}
{#each { length: GridColumns * rows } as _, idx}
From 7a9730b120817a004a3039157591de408760a24e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 09:24:03 +0100 Subject: [PATCH 086/112] Fix ephemeral styles not clearing properly --- packages/client/src/components/Component.svelte | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 3d081f5a61..0dcf93a5dc 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -262,6 +262,9 @@ lastInstanceKey = instanceKey } + // Reset ephemeral state + ephemeralStyles = null + // Pull definition and constructor const component = instance._component constructor = componentStore.actions.getComponentConstructor(component) From 6baf784f4aed847e1957fd10c06ca212ed73192c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 09:59:02 +0100 Subject: [PATCH 087/112] Ensure images are contained when used inside grids --- .../src/components/app/container/GridContainer.svelte | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index f332e197c3..088c41b57b 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -255,4 +255,10 @@ flex: 1 1 0 !important; height: 0 !important; } + + /* Grid specific CSS overrides for certain components */ + .grid :global(> .component > img) { + object-fit: contain; + max-height: 100%; + } From d36fef5c86ae9337d1ab0e9299d97adf394c2e93 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 10:09:59 +0100 Subject: [PATCH 088/112] Fix indicators around modals and side panels when used inside grids --- packages/client/manifest.json | 88 +++++++++++++++---- .../client/src/components/Component.svelte | 3 +- .../app/container/GridContainer.svelte | 2 +- packages/client/src/utils/grid.js | 28 +++++- 4 files changed, 99 insertions(+), 22 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index f232318c53..9851fd1155 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -18,14 +18,37 @@ "numberLike": { "supported": ["number", "boolean"], "partialSupport": [ - { "type": "longform", "message": "stringAsNumber" }, - { "type": "string", "message": "stringAsNumber" }, - { "type": "bigint", "message": "stringAsNumber" }, - { "type": "options", "message": "stringAsNumber" }, - { "type": "formula", "message": "stringAsNumber" }, - { "type": "datetime", "message": "dateAsNumber" } + { + "type": "longform", + "message": "stringAsNumber" + }, + { + "type": "string", + "message": "stringAsNumber" + }, + { + "type": "bigint", + "message": "stringAsNumber" + }, + { + "type": "options", + "message": "stringAsNumber" + }, + { + "type": "formula", + "message": "stringAsNumber" + }, + { + "type": "datetime", + "message": "dateAsNumber" + } ], - "unsupported": [{ "type": "json", "message": "jsonPrimitivesOnly" }] + "unsupported": [ + { + "type": "json", + "message": "jsonPrimitivesOnly" + } + ] }, "stringLike": { "supported": [ @@ -37,19 +60,47 @@ "boolean", "datetime" ], - "unsupported": [{ "type": "json", "message": "jsonPrimitivesOnly" }] + "unsupported": [ + { + "type": "json", + "message": "jsonPrimitivesOnly" + } + ] }, "datetimeLike": { "supported": ["datetime"], "partialSupport": [ - { "type": "longform", "message": "stringAsDate" }, - { "type": "string", "message": "stringAsDate" }, - { "type": "options", "message": "stringAsDate" }, - { "type": "formula", "message": "stringAsDate" }, - { "type": "bigint", "message": "stringAsDate" }, - { "type": "number", "message": "numberAsDate" } + { + "type": "longform", + "message": "stringAsDate" + }, + { + "type": "string", + "message": "stringAsDate" + }, + { + "type": "options", + "message": "stringAsDate" + }, + { + "type": "formula", + "message": "stringAsDate" + }, + { + "type": "bigint", + "message": "stringAsDate" + }, + { + "type": "number", + "message": "numberAsDate" + } ], - "unsupported": [{ "type": "json", "message": "jsonPrimitivesOnly" }] + "unsupported": [ + { + "type": "json", + "message": "jsonPrimitivesOnly" + } + ] } }, "layout": { @@ -4292,7 +4343,10 @@ "label": "High", "value": 3136 }, - { "label": "Custom", "value": "custom" } + { + "label": "Custom", + "value": "custom" + } ] }, { @@ -7148,6 +7202,7 @@ "name": "Side Panel", "icon": "RailRight", "hasChildren": true, + "ignoresLayout": true, "illegalChildren": ["section", "sidepanel", "modal"], "showEmptyState": false, "draggable": false, @@ -7171,6 +7226,7 @@ "icon": "MBox", "hasChildren": true, "illegalChildren": ["section", "modal", "sidepanel"], + "ignoresLayout": true, "showEmptyState": false, "draggable": false, "info": "Modals are hidden by default. They will only be revealed when triggered by the 'Open Modal' action.", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 0dcf93a5dc..12dfaaf6d3 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -209,8 +209,9 @@ // Metadata to pass into grid action to apply CSS let gridMetadata = memo() $: gridMetadata.set({ - active: + insideGrid: parent?._component.endsWith("/container") && parent?.layout === "grid", + ignoresLayout: definition.ignoresLayout === true, id, interactive, styles: normalStyles, diff --git a/packages/client/src/components/app/container/GridContainer.svelte b/packages/client/src/components/app/container/GridContainer.svelte index 088c41b57b..1f68926658 100644 --- a/packages/client/src/components/app/container/GridContainer.svelte +++ b/packages/client/src/components/app/container/GridContainer.svelte @@ -201,7 +201,7 @@ } /* Ensure all top level children have grid styles applied */ - .grid :global(> .component) { + .grid :global(> .component:not(.ignores-layout)) { display: flex; overflow: auto; pointer-events: all; diff --git a/packages/client/src/utils/grid.js b/packages/client/src/utils/grid.js index afce01bbaa..b9b08a28a6 100644 --- a/packages/client/src/utils/grid.js +++ b/packages/client/src/utils/grid.js @@ -59,9 +59,24 @@ export const gridLayout = (node, metadata) => { // Applies the required listeners, CSS and classes to a component DOM node const applyMetadata = metadata => { - const { id, styles, interactive, errored, definition, draggable, active } = - metadata - if (!active) { + const { + id, + styles, + interactive, + errored, + definition, + draggable, + insideGrid, + ignoresLayout, + } = metadata + if (!insideGrid) { + return + } + + // If this component ignores layout, flag it as such so that we can avoid + // selecting it later + if (ignoresLayout) { + node.classList.add("ignores-layout") return } @@ -143,7 +158,12 @@ export const gridLayout = (node, metadata) => { // Removes the previously set up listeners const removeListeners = () => { - node.removeEventListener("click", selectComponent, false) + // By checking if this is defined we can avoid trying to remove event + // listeners on every component + if (selectComponent) { + node.removeEventListener("click", selectComponent, false) + selectComponent = null + } } applyMetadata(metadata) From 83e7b2d3e2fc3d8f46c8f567af8125738ec5ef8b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 10:16:01 +0100 Subject: [PATCH 089/112] Move side panel into correct DOM position --- .../client/src/components/app/Layout.svelte | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index a1ce77df72..76634d2df3 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -322,20 +322,22 @@
-
-
-
- +
+
+ +
From f99ae6b96efffcc9ed99c27dd2a00be73a8bbcee Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 10:26:44 +0100 Subject: [PATCH 090/112] Ensure modals are rendered in the correct DOM position --- packages/client/src/components/ClientApp.svelte | 3 --- packages/client/src/components/app/Layout.svelte | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index 118aa483ab..516f505d21 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -235,9 +235,6 @@ /> {/key} - -
+
From b62371d1be8d5c676be18caf585b5183a3743670 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Aug 2024 10:59:06 +0100 Subject: [PATCH 091/112] Allow moving grid components using the label --- packages/client/manifest.json | 28 +++++++++---------- .../components/preview/GridDNDHandler.svelte | 19 ++++++++----- .../src/components/preview/Indicator.svelte | 17 +++++++++-- packages/client/src/utils/grid.js | 9 ++++-- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 9851fd1155..db276df8bc 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -3040,7 +3040,7 @@ "editable": true, "size": { "width": 400, - "height": 32 + "height": 60 }, "settings": [ { @@ -3071,7 +3071,7 @@ "editable": true, "size": { "width": 400, - "height": 32 + "height": 60 }, "settings": [ { @@ -3207,7 +3207,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -3309,7 +3309,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -3395,7 +3395,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -3481,7 +3481,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -3695,7 +3695,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -3901,8 +3901,8 @@ "editable": true, "requiredAncestors": ["form"], "size": { - "width": 20, - "height": 20 + "width": 400, + "height": 60 }, "settings": [ { @@ -4028,7 +4028,7 @@ "editable": true, "size": { "width": 400, - "height": 150 + "height": 100 }, "settings": [ { @@ -4152,7 +4152,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -4270,7 +4270,7 @@ "styles": ["size"], "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -4430,7 +4430,7 @@ "styles": ["size"], "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { @@ -4785,7 +4785,7 @@ "editable": true, "size": { "width": 400, - "height": 50 + "height": 60 }, "settings": [ { diff --git a/packages/client/src/components/preview/GridDNDHandler.svelte b/packages/client/src/components/preview/GridDNDHandler.svelte index db19c460c1..ad3a5a3ae1 100644 --- a/packages/client/src/components/preview/GridDNDHandler.svelte +++ b/packages/client/src/components/preview/GridDNDHandler.svelte @@ -3,7 +3,13 @@ import { builderStore, componentStore } from "stores" import { Utils, memo } from "@budibase/frontend-core" import { GridRowHeight } from "constants" - import { isGridEvent, GridParams, getGridVar, Devices } from "utils/grid" + import { + isGridEvent, + GridParams, + getGridVar, + Devices, + GridDragModes, + } from "utils/grid" const context = getContext("context") @@ -49,7 +55,7 @@ let deltaX = Math.round(diffX / colSize) const diffY = mouseY - startY let deltaY = Math.round(diffY / GridRowHeight) - if (mode === "move") { + if (mode === GridDragModes.Move) { deltaX = minMax(deltaX, 1 - colStart, cols + 1 - colEnd) deltaY = Math.max(deltaY, 1 - rowStart) const newStyles = { @@ -59,7 +65,7 @@ [vars.rowEnd]: rowEnd + deltaY, } styles.set(newStyles) - } else if (mode === "resize") { + } else if (mode === GridDragModes.Resize) { let newStyles = {} if (side === "right") { newStyles[vars.colEnd] = Math.max(colEnd + deltaX, colStart + 1) @@ -103,14 +109,13 @@ // Extract state let mode, id, side - if (e.target.classList.contains("anchor")) { - // Handle resize - mode = "resize" + if (e.target.dataset.indicator === "true") { + mode = e.target.dataset.dragMode id = e.target.dataset.id side = e.target.dataset.side } else { // Handle move - mode = "move" + mode = GridDragModes.Move const component = e.target.closest(".component") id = component.dataset.id } diff --git a/packages/client/src/components/preview/Indicator.svelte b/packages/client/src/components/preview/Indicator.svelte index 112d392354..dce7945b29 100644 --- a/packages/client/src/components/preview/Indicator.svelte +++ b/packages/client/src/components/preview/Indicator.svelte @@ -1,5 +1,6 @@