refactor and allow for condition and style settings
This commit is contained in:
parent
56018b1375
commit
3ac7c90fb8
|
@ -60,8 +60,12 @@
|
||||||
$: highlightedSettings = $builderStore.highlightedSettings
|
$: highlightedSettings = $builderStore.highlightedSettings
|
||||||
$: if (highlightedSettings?.length) {
|
$: if (highlightedSettings?.length) {
|
||||||
const settings = highlightedSettings.map(s => s.key)
|
const settings = highlightedSettings.map(s => s.key)
|
||||||
if (settings.length === 1 && settings[0] === "_conditions") {
|
if (settings.includes("_conditions")) {
|
||||||
section = "conditions"
|
section = "conditions"
|
||||||
|
} else if (settings.includes("_styles")) {
|
||||||
|
section = "styles"
|
||||||
|
} else if (settings.includes("_settings")) {
|
||||||
|
section = "settings"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
let tempValue
|
let tempValue
|
||||||
let drawer
|
let drawer
|
||||||
|
|
||||||
$: highlightCondition = $builderStore.highlightedSettings?.find(
|
$: highlighted = $builderStore.highlightedSettings?.find(
|
||||||
setting => setting.key === "_conditions"
|
setting => setting.key === "_conditions"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DetailSummary name={"Conditions"} collapsible={false}>
|
<DetailSummary name={"Conditions"} collapsible={false}>
|
||||||
<div class:highlighted={highlightCondition}>
|
<div class:highlighted>
|
||||||
<ActionButton fullWidth on:click={openDrawer}>{conditionText}</ActionButton>
|
<ActionButton fullWidth on:click={openDrawer}>{conditionText}</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableBinding,
|
runtimeToReadableBinding,
|
||||||
} from "@/dataBinding"
|
} from "@/dataBinding"
|
||||||
|
import { builderStore } from "@/stores/builder"
|
||||||
|
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
export let componentDefinition
|
export let componentDefinition
|
||||||
|
@ -32,6 +33,10 @@
|
||||||
|
|
||||||
$: icon = componentDefinition?.icon
|
$: icon = componentDefinition?.icon
|
||||||
|
|
||||||
|
$: highlighted = $builderStore.highlightedSettings?.find(
|
||||||
|
setting => setting.key === "_styles"
|
||||||
|
)
|
||||||
|
|
||||||
const openDrawer = () => {
|
const openDrawer = () => {
|
||||||
tempValue = runtimeToReadableBinding(
|
tempValue = runtimeToReadableBinding(
|
||||||
bindings,
|
bindings,
|
||||||
|
@ -55,7 +60,7 @@
|
||||||
name={`Custom CSS${componentInstance?._styles?.custom ? " *" : ""}`}
|
name={`Custom CSS${componentInstance?._styles?.custom ? " *" : ""}`}
|
||||||
collapsible={false}
|
collapsible={false}
|
||||||
>
|
>
|
||||||
<div>
|
<div class:highlighted>
|
||||||
<ActionButton on:click={openDrawer}>Edit custom CSS</ActionButton>
|
<ActionButton on:click={openDrawer}>Edit custom CSS</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
</DetailSummary>
|
</DetailSummary>
|
||||||
|
@ -97,4 +102,16 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-m);
|
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>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte"
|
||||||
import { Select, Link } from "@budibase/bbui"
|
import { Select, Link } from "@budibase/bbui"
|
||||||
|
import type { Component } from "@budibase/types"
|
||||||
import { getAllStateVariables } from "@/dataBinding"
|
import { getAllStateVariables } from "@/dataBinding"
|
||||||
import {
|
import {
|
||||||
componentStore,
|
componentStore,
|
||||||
|
@ -12,7 +14,6 @@
|
||||||
findHBSBlocks,
|
findHBSBlocks,
|
||||||
isJSBinding,
|
isJSBinding,
|
||||||
} from "@budibase/string-templates"
|
} from "@budibase/string-templates"
|
||||||
import { onMount } from "svelte"
|
|
||||||
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
import DrawerBindableInput from "@/components/common/bindings/DrawerBindableInput.svelte"
|
||||||
|
|
||||||
type ComponentUsingState = {
|
type ComponentUsingState = {
|
||||||
|
@ -30,15 +31,12 @@
|
||||||
let editorError: string | null = null
|
let editorError: string | null = null
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (selectedKey) {
|
|
||||||
searchComponents(selectedKey)
|
|
||||||
}
|
|
||||||
previewStore.requestComponentContext()
|
previewStore.requestComponentContext()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$: $selectedScreen, selectedKey && searchComponents(selectedKey)
|
||||||
$: {
|
$: {
|
||||||
const previewContext = $previewStore.selectedComponentContext || {}
|
const previewContext = $previewStore.selectedComponentContext || {}
|
||||||
|
|
||||||
if (selectedKey && previewContext.state) {
|
if (selectedKey && previewContext.state) {
|
||||||
// It's unlikely value will ever be populated immediately as preview never has state values on load
|
// It's unlikely value will ever be populated immediately as preview never has state values on load
|
||||||
editorValue = previewContext.state[selectedKey] ?? null
|
editorValue = previewContext.state[selectedKey] ?? null
|
||||||
|
@ -50,7 +48,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const findComponentsUpdatingState = (
|
const findComponentsUpdatingState = (
|
||||||
component: any,
|
component: Component,
|
||||||
stateKey: string
|
stateKey: string
|
||||||
): ComponentUsingState[] => {
|
): ComponentUsingState[] => {
|
||||||
let foundComponents: ComponentUsingState[] = []
|
let foundComponents: ComponentUsingState[] = []
|
||||||
|
@ -66,7 +64,7 @@
|
||||||
handler.parameters?.key === stateKey
|
handler.parameters?.key === stateKey
|
||||||
) {
|
) {
|
||||||
foundComponents.push({
|
foundComponents.push({
|
||||||
id: component._id,
|
id: component._id!,
|
||||||
name: component._instanceName,
|
name: component._instanceName,
|
||||||
settings: [eventType],
|
settings: [eventType],
|
||||||
})
|
})
|
||||||
|
@ -86,13 +84,7 @@
|
||||||
return foundComponents
|
return foundComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
const findComponentsUsingState = (
|
const hasStateBinding = (value: string, stateKey: string): boolean => {
|
||||||
component: any,
|
|
||||||
stateKey: string
|
|
||||||
): ComponentUsingState[] => {
|
|
||||||
let componentsUsingState: ComponentUsingState[] = []
|
|
||||||
|
|
||||||
const processValue = (value: string): boolean => {
|
|
||||||
const bindings = findHBSBlocks(value).map(binding => {
|
const bindings = findHBSBlocks(value).map(binding => {
|
||||||
const sanitizedBinding = binding.replace(/\\"/g, '"')
|
const sanitizedBinding = binding.replace(/\\"/g, '"')
|
||||||
return isJSBinding(sanitizedBinding)
|
return isJSBinding(sanitizedBinding)
|
||||||
|
@ -102,61 +94,62 @@
|
||||||
return bindings.join(" ").includes(stateKey)
|
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
|
const checkConditions = (conditions: any[], stateKey: string): boolean => {
|
||||||
for (const [setting, value] of Object.entries(componentSettings)) {
|
return conditions.some(condition =>
|
||||||
if (typeof value === "string" && processValue(value)) {
|
[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({
|
componentsUsingState.push({
|
||||||
id: component._id,
|
id: component._id,
|
||||||
name: `${component._instanceName} (${setting})`,
|
name: `${component._instanceName} (${setting})`,
|
||||||
settings: [setting],
|
settings: [setting],
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// Check conditions
|
if (_conditions?.length > 0 && checkConditions(_conditions, stateKey)) {
|
||||||
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)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
componentsUsingState.push({
|
componentsUsingState.push({
|
||||||
id: component._id,
|
id: component._id,
|
||||||
name: `${component._instanceName} (conditions)`,
|
name: `${component._instanceName} (conditions)`,
|
||||||
settings: ["_conditions"],
|
settings: ["_conditions"],
|
||||||
})
|
})
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check styles
|
if (_styles && checkStyles(_styles, stateKey)) {
|
||||||
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) {
|
|
||||||
componentsUsingState.push({
|
componentsUsingState.push({
|
||||||
id: component._id,
|
id: component._id,
|
||||||
name: `${component._instanceName} (styles)`,
|
name: `${component._instanceName} (styles)`,
|
||||||
settings: ["_styles"],
|
settings: ["_styles"],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_children) {
|
if (_children) {
|
||||||
for (let child of _children) {
|
for (let child of _children) {
|
||||||
|
@ -170,7 +163,7 @@
|
||||||
return componentsUsingState
|
return componentsUsingState
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchComponents = (stateKey: string) => {
|
const searchComponents = (stateKey: string | undefined) => {
|
||||||
if (!stateKey || !$selectedScreen?.props) {
|
if (!stateKey || !$selectedScreen?.props) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -223,7 +216,7 @@
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<Select
|
<Select
|
||||||
label="State variables"
|
label="State variables"
|
||||||
value={selectedKey}
|
bind:value={selectedKey}
|
||||||
placeholder="Type here..."
|
placeholder="Type here..."
|
||||||
options={keyOptions}
|
options={keyOptions}
|
||||||
on:change={handleStateKeySelect}
|
on:change={handleStateKeySelect}
|
||||||
|
@ -245,8 +238,8 @@
|
||||||
{#if componentsUsingState.length > 0}
|
{#if componentsUsingState.length > 0}
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<span class="text">Updates:</span>
|
<span class="text">Updates:</span>
|
||||||
{#each componentsUsingState as component, i}
|
<div class="updates-section">
|
||||||
{#if i > 0}{", "}{/if}
|
{#each componentsUsingState as component}
|
||||||
<button
|
<button
|
||||||
class="component-link updates-colour"
|
class="component-link updates-colour"
|
||||||
on:click={() => onClickComponentLink(component)}
|
on:click={() => onClickComponentLink(component)}
|
||||||
|
@ -255,19 +248,21 @@
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if componentsUpdatingState.length > 0}
|
{#if componentsUpdatingState.length > 0}
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<span class="text">Controlled by:</span>
|
<span class="text">Controlled by:</span>
|
||||||
{#each componentsUpdatingState as component, i}
|
<div class="updates-section">
|
||||||
{#if i > 0}{", "}{/if}
|
{#each componentsUpdatingState as component}
|
||||||
<button
|
<button
|
||||||
class="component-link controlled-by-colour"
|
class="component-link controlled-by-colour"
|
||||||
on:click={() => onClickComponentLink(component)}
|
on:click={() => onClickComponentLink(component)}
|
||||||
>
|
>
|
||||||
{component.name}
|
{component.name}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}git
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div style="opacity: 0.5; ">
|
<div style="opacity: 0.5; ">
|
||||||
|
@ -291,6 +286,8 @@
|
||||||
gap: var(--spacing-m);
|
gap: var(--spacing-m);
|
||||||
}
|
}
|
||||||
.section {
|
.section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
gap: var(--spacing-s);
|
gap: var(--spacing-s);
|
||||||
}
|
}
|
||||||
.text {
|
.text {
|
||||||
|
@ -313,16 +310,23 @@
|
||||||
color: #e87400;
|
color: #e87400;
|
||||||
}
|
}
|
||||||
.component-link {
|
.component-link {
|
||||||
display: inline;
|
display: inline-block;
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
color: var(--spectrum-global-color-white);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: var(--spectrum-global-dimension-font-size-50);
|
font-size: var(--spectrum-global-dimension-font-size-50);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.component-link:hover {
|
.component-link:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.updates-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: var(--spacing-xs);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue