Updated approach to focus behaviour. Placeholder now updates to direct the user to the next required field they haven't entered
This commit is contained in:
parent
e786a0d122
commit
dbbf7afcd0
|
@ -33,7 +33,7 @@
|
||||||
let focus = false
|
let focus = false
|
||||||
let pickerButton
|
let pickerButton
|
||||||
|
|
||||||
$: focus = autofocus && pickerButton
|
$: focus = autofocus && pickerButton !== null
|
||||||
|
|
||||||
$: sortedOptions = getSortedOptions(options, getOptionLabel, sort)
|
$: sortedOptions = getSortedOptions(options, getOptionLabel, sort)
|
||||||
$: filteredOptions = getFilteredOptions(
|
$: filteredOptions = getFilteredOptions(
|
||||||
|
@ -88,6 +88,14 @@
|
||||||
class:is-focused={focus}
|
class:is-focused={focus}
|
||||||
bind:this={pickerButton}
|
bind:this={pickerButton}
|
||||||
on:mousedown={onClick}
|
on:mousedown={onClick}
|
||||||
|
on:keydown={e => {
|
||||||
|
var keycode = e.key
|
||||||
|
if (focus) {
|
||||||
|
if (keycode === "Enter") {
|
||||||
|
onClick(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
on:focus={() => {
|
on:focus={() => {
|
||||||
focus = true
|
focus = true
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -417,28 +417,12 @@ export const getFrontendStore = () => {
|
||||||
}
|
}
|
||||||
parentComponent._children.push(componentInstance)
|
parentComponent._children.push(componentInstance)
|
||||||
|
|
||||||
const definition = store.actions.components.getDefinition(componentName)
|
|
||||||
|
|
||||||
// Save components and update UI
|
// Save components and update UI
|
||||||
await store.actions.preview.saveSelected()
|
await store.actions.preview.saveSelected()
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
state.currentView = "component"
|
state.currentView = "component"
|
||||||
state.selectedComponentId = componentInstance._id
|
state.selectedComponentId = componentInstance._id
|
||||||
|
|
||||||
const focusSetting = definition.settings.filter(setting => {
|
|
||||||
return setting.required
|
|
||||||
})
|
|
||||||
const mappedSettings = focusSetting.map(setting => {
|
|
||||||
return {
|
|
||||||
key: setting.key,
|
|
||||||
target: state.selectedComponentId,
|
|
||||||
location: "component_settings",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (focusSetting.length) {
|
|
||||||
state.builderFocus = mappedSettings
|
|
||||||
}
|
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import ResetFieldsButton from "./PropertyControls/ResetFieldsButton.svelte"
|
import ResetFieldsButton from "./PropertyControls/ResetFieldsButton.svelte"
|
||||||
import { getComponentForSettingType } from "./PropertyControls/componentSettings"
|
import { getComponentForSettingType } from "./PropertyControls/componentSettings"
|
||||||
import { Utils } from "@budibase/frontend-core"
|
import { Utils } from "@budibase/frontend-core"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
export let componentDefinition
|
export let componentDefinition
|
||||||
export let componentInstance
|
export let componentInstance
|
||||||
|
@ -78,8 +79,41 @@
|
||||||
if (!$store.builderFocus) {
|
if (!$store.builderFocus) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return setting.required === true
|
return (
|
||||||
|
setting.required === true && $store.builderFocus[0].key === setting.key
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const emptyFields = (definition, options) => {
|
||||||
|
if (!options) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return definition?.settings
|
||||||
|
? definition.settings.filter(setting => {
|
||||||
|
return (
|
||||||
|
setting.required &&
|
||||||
|
(!options[setting.key] || options[setting.key] == "")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = emptyFields(componentDefinition, componentInstance)[0]
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
store.update(state => ({
|
||||||
|
...state,
|
||||||
|
builderFocus: [
|
||||||
|
{
|
||||||
|
location: "component_settings",
|
||||||
|
key: target.key,
|
||||||
|
target: componentInstance._id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each sections as section, idx (section.name)}
|
{#each sections as section, idx (section.name)}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
export let otherSources
|
export let otherSources
|
||||||
export let showAllQueries
|
export let showAllQueries
|
||||||
export let bindings = []
|
export let bindings = []
|
||||||
|
export let autofocus = false
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
const arrayTypes = ["attachment", "array"]
|
const arrayTypes = ["attachment", "array"]
|
||||||
|
@ -158,6 +159,7 @@
|
||||||
value={text}
|
value={text}
|
||||||
options={[text]}
|
options={[text]}
|
||||||
on:click={dropdownRight.show}
|
on:click={dropdownRight.show}
|
||||||
|
{autofocus}
|
||||||
/>
|
/>
|
||||||
{#if value?.type === "query"}
|
{#if value?.type === "query"}
|
||||||
<i class="ri-settings-5-line" on:click={openQueryParamsDrawer} />
|
<i class="ri-settings-5-line" on:click={openQueryParamsDrawer} />
|
||||||
|
|
|
@ -975,7 +975,8 @@
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "URL",
|
"label": "URL",
|
||||||
"key": "url"
|
"key": "url",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "select",
|
"type": "select",
|
||||||
|
@ -3255,7 +3256,8 @@
|
||||||
{
|
{
|
||||||
"type": "dataSource",
|
"type": "dataSource",
|
||||||
"label": "Data",
|
"label": "Data",
|
||||||
"key": "dataSource"
|
"key": "dataSource",
|
||||||
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
|
|
|
@ -154,6 +154,7 @@
|
||||||
selected,
|
selected,
|
||||||
name,
|
name,
|
||||||
editing,
|
editing,
|
||||||
|
type: instance._component,
|
||||||
})
|
})
|
||||||
|
|
||||||
const initialise = instance => {
|
const initialise = instance => {
|
||||||
|
|
|
@ -28,25 +28,7 @@
|
||||||
class="placeholder"
|
class="placeholder"
|
||||||
use:styleable={{ ...$component.styles, empty: true }}
|
use:styleable={{ ...$component.styles, empty: true }}
|
||||||
>
|
>
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add the <mark>URL</mark> and start updating your background image
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "url",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -28,25 +28,7 @@
|
||||||
/>
|
/>
|
||||||
{:else if $builderStore.inBuilder}
|
{:else if $builderStore.inBuilder}
|
||||||
<div use:styleable={styles}>
|
<div use:styleable={styles}>
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add the <mark>Icon</mark> in the settings menu
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "icon",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -15,25 +15,7 @@
|
||||||
class="placeholder"
|
class="placeholder"
|
||||||
use:styleable={{ ...$component.styles, empty: true }}
|
use:styleable={{ ...$component.styles, empty: true }}
|
||||||
>
|
>
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add the <mark>URL</mark> and start updating your image
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "url",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -82,31 +82,7 @@
|
||||||
{:else if $builderStore.inBuilder || componentText}
|
{:else if $builderStore.inBuilder || componentText}
|
||||||
{#if !url && !text}
|
{#if !url && !text}
|
||||||
<div use:styleable={{ ...$component.styles, empty: true }}>
|
<div use:styleable={{ ...$component.styles, empty: true }}>
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add the <mark>URL</mark> and <mark>Text</mark> settings and start
|
|
||||||
using your link
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "url",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "text",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
</div>
|
</div>
|
||||||
{:else if externalLink || openInNewTab}
|
{:else if externalLink || openInNewTab}
|
||||||
<a
|
<a
|
||||||
|
|
|
@ -14,25 +14,6 @@
|
||||||
{#if value}
|
{#if value}
|
||||||
<MarkdownViewer {value} {height} />
|
<MarkdownViewer {value} {height} />
|
||||||
{:else if $builderStore.inBuilder}
|
{:else if $builderStore.inBuilder}
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add some <mark>Markdown</mark> in the field setting to start using your
|
|
||||||
component
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "value",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,18 +1,71 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
import Manifest from "manifest.json"
|
||||||
|
import { builderStore } from "stores"
|
||||||
|
|
||||||
const { builderStore } = getContext("sdk")
|
const { componentStore } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
|
||||||
export let text
|
export let text
|
||||||
|
|
||||||
|
$: componentInstance = componentStore.actions.getComponentById($component.id)
|
||||||
|
|
||||||
|
const getComponentKey = compId => {
|
||||||
|
if (!compId) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const prefix = "@budibase/standard-components/"
|
||||||
|
let componentKey = compId.replace(prefix, "")
|
||||||
|
return componentKey
|
||||||
|
}
|
||||||
|
|
||||||
|
//Corify this somewhere
|
||||||
|
const emptyFields = (definition, options) => {
|
||||||
|
if (!options) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return definition?.settings
|
||||||
|
? definition.settings.filter(setting => {
|
||||||
|
return (
|
||||||
|
setting.required &&
|
||||||
|
(!options[setting.key] || options[setting.key] == "")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
const definition = Manifest[getComponentKey($component.type)]
|
||||||
|
$: focus_setting = emptyFields(definition, componentInstance)[0]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
<div class="placeholder_wrap">
|
<div class="placeholder_wrap">
|
||||||
{#if !$$slots.content}
|
{#if componentInstance && focus_setting}
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
Add the <mark>{focus_setting?.label}</mark> setting to start using your
|
||||||
|
component
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="showMe spectrum-Link"
|
||||||
|
on:click={() => {
|
||||||
|
builderStore.actions.setFocus([
|
||||||
|
{
|
||||||
|
location: "component_settings",
|
||||||
|
key: focus_setting.key,
|
||||||
|
target: $component.id,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show me
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
{text || $component.name || "Placeholder"}
|
{text || $component.name || "Placeholder"}
|
||||||
|
<!-- {#if definition.hasChildren}
|
||||||
|
<span>: Add a component or two!</span>
|
||||||
|
{/if} -->
|
||||||
{/if}
|
{/if}
|
||||||
<slot name="content" />
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{#if $component.empty}
|
{#if $component.empty}
|
||||||
<Placeholder text={$component.name} />
|
<Placeholder />
|
||||||
{:else}
|
{:else}
|
||||||
<BlockComponent
|
<BlockComponent
|
||||||
type="repeater"
|
type="repeater"
|
||||||
|
|
|
@ -13,35 +13,7 @@
|
||||||
<div use:chart={options} use:styleable={$component.styles} />
|
<div use:chart={options} use:styleable={$component.styles} />
|
||||||
{:else if $builderStore.inBuilder}
|
{:else if $builderStore.inBuilder}
|
||||||
<div use:styleable={$component.styles}>
|
<div use:styleable={$component.styles}>
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Use the settings panel start building your chart
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "dataProvider",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "valueColumns",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "dataColumns",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -77,26 +77,7 @@
|
||||||
<Placeholder text="Form components need to be wrapped in a form" />
|
<Placeholder text="Form components need to be wrapped in a form" />
|
||||||
{:else if !fieldState}
|
{:else if !fieldState}
|
||||||
{#if $builderStore.inBuilder}
|
{#if $builderStore.inBuilder}
|
||||||
<Placeholder>
|
<Placeholder />
|
||||||
<div slot="content">
|
|
||||||
Add the <mark>Field</mark> setting to start using your
|
|
||||||
component
|
|
||||||
<span
|
|
||||||
class="showMe spectrum-Link"
|
|
||||||
on:click={() => {
|
|
||||||
builderStore.actions.setFocus([
|
|
||||||
{
|
|
||||||
location: "component_settings",
|
|
||||||
key: "field",
|
|
||||||
target: $component.id,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Show me
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Placeholder>
|
|
||||||
{/if}
|
{/if}
|
||||||
{:else if schemaType && schemaType !== type && type !== "options"}
|
{:else if schemaType && schemaType !== type && type !== "options"}
|
||||||
<Placeholder
|
<Placeholder
|
||||||
|
|
Loading…
Reference in New Issue