refactor and allow for condition and style settings

This commit is contained in:
Peter Clement 2025-01-23 14:59:25 +00:00
parent 56018b1375
commit 3ac7c90fb8
4 changed files with 119 additions and 94 deletions

View File

@ -60,8 +60,12 @@
$: highlightedSettings = $builderStore.highlightedSettings
$: if (highlightedSettings?.length) {
const settings = highlightedSettings.map(s => s.key)
if (settings.length === 1 && settings[0] === "_conditions") {
if (settings.includes("_conditions")) {
section = "conditions"
} else if (settings.includes("_styles")) {
section = "styles"
} else if (settings.includes("_settings")) {
section = "settings"
}
}
</script>

View File

@ -19,7 +19,7 @@
let tempValue
let drawer
$: highlightCondition = $builderStore.highlightedSettings?.find(
$: highlighted = $builderStore.highlightedSettings?.find(
setting => setting.key === "_conditions"
)
@ -57,7 +57,7 @@
/>
<DetailSummary name={"Conditions"} collapsible={false}>
<div class:highlighted={highlightCondition}>
<div class:highlighted>
<ActionButton fullWidth on:click={openDrawer}>{conditionText}</ActionButton>
</div>
</DetailSummary>

View File

@ -16,6 +16,7 @@
readableToRuntimeBinding,
runtimeToReadableBinding,
} from "@/dataBinding"
import { builderStore } from "@/stores/builder"
export let componentInstance
export let componentDefinition
@ -32,6 +33,10 @@
$: icon = componentDefinition?.icon
$: highlighted = $builderStore.highlightedSettings?.find(
setting => setting.key === "_styles"
)
const openDrawer = () => {
tempValue = runtimeToReadableBinding(
bindings,
@ -55,7 +60,7 @@
name={`Custom CSS${componentInstance?._styles?.custom ? " *" : ""}`}
collapsible={false}
>
<div>
<div class:highlighted>
<ActionButton on:click={openDrawer}>Edit custom CSS</ActionButton>
</div>
</DetailSummary>
@ -97,4 +102,16 @@
align-items: center;
gap: var(--spacing-m);
}
.highlighted {
background: var(--spectrum-global-color-gray-300);
border-left: 4px solid var(--spectrum-semantic-informative-color-background);
transition: background 130ms ease-out, border-color 130ms ease-out;
margin-top: -3.5px;
margin-bottom: -3.5px;
padding-bottom: 3.5px;
padding-top: 3.5px;
padding-left: 5px;
padding-right: 5px;
}
</style>

View File

@ -1,5 +1,7 @@
<script lang="ts">
import { onMount } from "svelte"
import { Select, Link } from "@budibase/bbui"
import type { Component } from "@budibase/types"
import { getAllStateVariables } from "@/dataBinding"
import {
componentStore,
@ -12,7 +14,6 @@
findHBSBlocks,
isJSBinding,
} from "@budibase/string-templates"
import { onMount } from "svelte"
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
type ComponentUsingState = {
@ -30,15 +31,12 @@
let editorError: string | null = null
onMount(() => {
if (selectedKey) {
searchComponents(selectedKey)
}
previewStore.requestComponentContext()
})
$: $selectedScreen, selectedKey && searchComponents(selectedKey)
$: {
const previewContext = $previewStore.selectedComponentContext || {}
if (selectedKey && previewContext.state) {
// It's unlikely value will ever be populated immediately as preview never has state values on load
editorValue = previewContext.state[selectedKey] ?? null
@ -50,7 +48,7 @@
}
const findComponentsUpdatingState = (
component: any,
component: Component,
stateKey: string
): ComponentUsingState[] => {
let foundComponents: ComponentUsingState[] = []
@ -66,7 +64,7 @@
handler.parameters?.key === stateKey
) {
foundComponents.push({
id: component._id,
id: component._id!,
name: component._instanceName,
settings: [eventType],
})
@ -86,13 +84,7 @@
return foundComponents
}
const findComponentsUsingState = (
component: any,
stateKey: string
): ComponentUsingState[] => {
let componentsUsingState: ComponentUsingState[] = []
const processValue = (value: string): boolean => {
const hasStateBinding = (value: string, stateKey: string): boolean => {
const bindings = findHBSBlocks(value).map(binding => {
const sanitizedBinding = binding.replace(/\\"/g, '"')
return isJSBinding(sanitizedBinding)
@ -102,61 +94,62 @@
return bindings.join(" ").includes(stateKey)
}
const { _children, ...componentSettings } = component
const getSettingsWithState = (component: any, stateKey: string): string[] => {
const settingsWithState: string[] = []
for (const [setting, value] of Object.entries(component)) {
if (typeof value === "string" && hasStateBinding(value, stateKey)) {
settingsWithState.push(setting)
}
}
return settingsWithState
}
// Check normal settings
for (const [setting, value] of Object.entries(componentSettings)) {
if (typeof value === "string" && processValue(value)) {
const checkConditions = (conditions: any[], stateKey: string): boolean => {
return conditions.some(condition =>
[condition.referenceValue, condition.newValue].some(
value => typeof value === "string" && hasStateBinding(value, stateKey)
)
)
}
const checkStyles = (styles: any, stateKey: string): boolean => {
return (
typeof styles?.custom === "string" &&
hasStateBinding(styles.custom, stateKey)
)
}
const findComponentsUsingState = (
component: any,
stateKey: string
): ComponentUsingState[] => {
let componentsUsingState: ComponentUsingState[] = []
const { _children, _styles, _conditions, ...componentSettings } = component
const settingsWithState = getSettingsWithState(componentSettings, stateKey)
settingsWithState.forEach(setting => {
componentsUsingState.push({
id: component._id,
name: `${component._instanceName} (${setting})`,
settings: [setting],
})
}
}
})
// Check conditions
if (component._conditions?.length > 0) {
for (const condition of component._conditions) {
const conditionValues = [condition.referenceValue, condition.newValue]
if (
conditionValues.some(
value => typeof value === "string" && processValue(value)
)
) {
if (_conditions?.length > 0 && checkConditions(_conditions, stateKey)) {
componentsUsingState.push({
id: component._id,
name: `${component._instanceName} (conditions)`,
settings: ["_conditions"],
})
break
}
}
}
// Check styles
if (component._styles) {
const checkStyleObject = (obj: any) => {
for (const [, value] of Object.entries(obj)) {
if (typeof value === "string" && processValue(value)) {
return true
}
}
return false
}
const hasStateInStyles = Object.values(component._styles).some(styleObj =>
checkStyleObject(styleObj)
)
if (hasStateInStyles) {
if (_styles && checkStyles(_styles, stateKey)) {
componentsUsingState.push({
id: component._id,
name: `${component._instanceName} (styles)`,
settings: ["_styles"],
})
}
}
if (_children) {
for (let child of _children) {
@ -170,7 +163,7 @@
return componentsUsingState
}
const searchComponents = (stateKey: string) => {
const searchComponents = (stateKey: string | undefined) => {
if (!stateKey || !$selectedScreen?.props) {
return
}
@ -223,7 +216,7 @@
<div class="section">
<Select
label="State variables"
value={selectedKey}
bind:value={selectedKey}
placeholder="Type here..."
options={keyOptions}
on:change={handleStateKeySelect}
@ -245,8 +238,8 @@
{#if componentsUsingState.length > 0}
<div class="section">
<span class="text">Updates:</span>
{#each componentsUsingState as component, i}
{#if i > 0}{", "}{/if}
<div class="updates-section">
{#each componentsUsingState as component}
<button
class="component-link updates-colour"
on:click={() => onClickComponentLink(component)}
@ -255,19 +248,21 @@
</button>
{/each}
</div>
</div>
{/if}
{#if componentsUpdatingState.length > 0}
<div class="section">
<span class="text">Controlled by:</span>
{#each componentsUpdatingState as component, i}
{#if i > 0}{", "}{/if}
<div class="updates-section">
{#each componentsUpdatingState as component}
<button
class="component-link controlled-by-colour"
on:click={() => onClickComponentLink(component)}
>
{component.name}
</button>
{/each}
{/each}git
</div>
</div>
{/if}
<div style="opacity: 0.5; ">
@ -291,6 +286,8 @@
gap: var(--spacing-m);
}
.section {
display: flex;
flex-direction: column;
gap: var(--spacing-s);
}
.text {
@ -313,16 +310,23 @@
color: #e87400;
}
.component-link {
display: inline;
display: inline-block;
border: none;
background: none;
text-decoration: underline;
color: var(--spectrum-global-color-white);
cursor: pointer;
font-size: var(--spectrum-global-dimension-font-size-50);
padding: 0;
white-space: nowrap;
}
.component-link:hover {
text-decoration: underline;
}
.updates-section {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-xs);
}
</style>