Add generic block structure with support for writing blocks like normal svelte components rather than a JSON builder
This commit is contained in:
parent
e9dd47b562
commit
e6ffccaff7
|
@ -2576,7 +2576,6 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"tablewithsearch": {
|
"tablewithsearch": {
|
||||||
"block": true,
|
|
||||||
"name": "Table with search",
|
"name": "Table with search",
|
||||||
"icon": "Table",
|
"icon": "Table",
|
||||||
"styles": ["size"],
|
"styles": ["size"],
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
// Get contexts
|
// Get contexts
|
||||||
const context = getContext("context")
|
const context = getContext("context")
|
||||||
const insideScreenslot = !!getContext("screenslot")
|
const insideScreenslot = !!getContext("screenslot")
|
||||||
|
const insideBlock = !!getContext("block")
|
||||||
|
|
||||||
// Create component context
|
// Create component context
|
||||||
const componentStore = writable({})
|
const componentStore = writable({})
|
||||||
|
@ -53,7 +54,8 @@
|
||||||
$: name = instance._instanceName
|
$: name = instance._instanceName
|
||||||
$: interactive =
|
$: interactive =
|
||||||
$builderStore.inBuilder &&
|
$builderStore.inBuilder &&
|
||||||
($builderStore.previewType === "layout" || insideScreenslot)
|
($builderStore.previewType === "layout" || insideScreenslot) &&
|
||||||
|
!insideBlock
|
||||||
$: empty = interactive && !children.length && definition?.hasChildren
|
$: empty = interactive && !children.length && definition?.hasChildren
|
||||||
$: emptyState = empty && definition?.showEmptyState !== false
|
$: emptyState = empty && definition?.showEmptyState !== false
|
||||||
$: rawProps = getRawProps(instance)
|
$: rawProps = getRawProps(instance)
|
||||||
|
@ -197,6 +199,8 @@
|
||||||
{/each}
|
{/each}
|
||||||
{:else if emptyState}
|
{:else if emptyState}
|
||||||
<Placeholder />
|
<Placeholder />
|
||||||
|
{:else if insideBlock}
|
||||||
|
<slot />
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:component>
|
</svelte:component>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -234,7 +234,7 @@
|
||||||
<ProgressCircle />
|
<ProgressCircle />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
{#if !$component.children}
|
{#if $component.emptyState}
|
||||||
<Placeholder />
|
<Placeholder />
|
||||||
{:else}
|
{:else}
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script>
|
||||||
|
import { getContext, setContext } from "svelte"
|
||||||
|
|
||||||
|
const component = getContext("component")
|
||||||
|
const { styleable } = getContext("sdk")
|
||||||
|
|
||||||
|
setContext("block", {
|
||||||
|
id: $component.id,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div use:styleable={$component.styles}>
|
||||||
|
<slot />
|
||||||
|
</div>
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte"
|
||||||
|
import { generate } from "shortid"
|
||||||
|
import Component from "components/Component.svelte"
|
||||||
|
|
||||||
|
export let type
|
||||||
|
export let props
|
||||||
|
export let styles
|
||||||
|
export let id
|
||||||
|
|
||||||
|
const block = getContext("block")
|
||||||
|
const rand = generate()
|
||||||
|
|
||||||
|
$: id = block.id + rand
|
||||||
|
$: instance = createInstance(type, props, id)
|
||||||
|
|
||||||
|
const createInstance = (type, props, id) => {
|
||||||
|
return {
|
||||||
|
_component: `@budibase/standard-components/${type}`,
|
||||||
|
_id: id,
|
||||||
|
_styles: {
|
||||||
|
normal: {
|
||||||
|
...styles,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Component {instance}>
|
||||||
|
<slot />
|
||||||
|
</Component>
|
|
@ -1,99 +1,89 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import Block from "./Block.svelte"
|
||||||
import { BlockBuilder } from "./block-builder"
|
import BlockComponent from "./BlockComponent.svelte"
|
||||||
import Component from "components/Component.svelte"
|
|
||||||
|
|
||||||
// Common props
|
|
||||||
export let searchColumns
|
|
||||||
export let dataSource
|
export let dataSource
|
||||||
|
export let searchColumns
|
||||||
// Data provider props
|
|
||||||
export let filter
|
export let filter
|
||||||
export let sortColumn
|
export let sortColumn
|
||||||
export let sortOrder
|
export let sortOrder
|
||||||
export let paginate
|
export let paginate
|
||||||
|
|
||||||
// Table props
|
|
||||||
export let tableColumns
|
export let tableColumns
|
||||||
export let showAutoColumns
|
export let showAutoColumns
|
||||||
export let rowCount
|
export let rowCount
|
||||||
export let quiet
|
export let quiet
|
||||||
export let size
|
export let size
|
||||||
|
|
||||||
const { styleable } = getContext("sdk")
|
let formId
|
||||||
const component = getContext("component")
|
let dataProviderId
|
||||||
|
|
||||||
let instance
|
$: enrichedFilter = enrichFilter(filter, searchColumns, formId)
|
||||||
$: {
|
|
||||||
const builder = new BlockBuilder($component)
|
|
||||||
|
|
||||||
const form = builder.createComponent("form", {
|
|
||||||
dataSource,
|
|
||||||
})
|
|
||||||
|
|
||||||
let newFilter = [...(filter || [])]
|
|
||||||
|
|
||||||
// Add search bar if required
|
|
||||||
if (searchColumns?.length) {
|
|
||||||
const searchContainer = builder
|
|
||||||
.createComponent("container", {
|
|
||||||
direction: "row",
|
|
||||||
hAlign: "right",
|
|
||||||
vAlign: "middle",
|
|
||||||
gap: "M",
|
|
||||||
wrap: true,
|
|
||||||
})
|
|
||||||
.setStyles({
|
|
||||||
"margin-bottom": "20px",
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const enrichFilter = (filter, searchColumns, formId) => {
|
||||||
|
let enrichedFilter = [...(filter || [])]
|
||||||
searchColumns?.forEach(column => {
|
searchColumns?.forEach(column => {
|
||||||
const field = builder.createComponent("stringfield", {
|
enrichedFilter.push({
|
||||||
field: column,
|
|
||||||
placeholder: column,
|
|
||||||
label: column,
|
|
||||||
})
|
|
||||||
|
|
||||||
searchContainer.addChild(field)
|
|
||||||
|
|
||||||
newFilter.push({
|
|
||||||
field: column,
|
field: column,
|
||||||
operator: "equal",
|
operator: "equal",
|
||||||
type: "string",
|
type: "string",
|
||||||
valueType: "Binding",
|
valueType: "Binding",
|
||||||
value: `{{ [${form.id}].[${column}] }}`,
|
value: `{{ [${formId}].[${column}] }}`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
return enrichedFilter
|
||||||
form.addChild(searchContainer)
|
|
||||||
}
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
const dataProvider = builder.createComponent("dataprovider", {
|
<Block>
|
||||||
|
<BlockComponent type="form" bind:id={formId} props={{ dataSource }}>
|
||||||
|
{#if searchColumns?.length}
|
||||||
|
<div class="search">
|
||||||
|
{#each searchColumns as column}
|
||||||
|
<BlockComponent
|
||||||
|
type="stringfield"
|
||||||
|
props={{
|
||||||
|
field: column,
|
||||||
|
placeholder: column,
|
||||||
|
label: column,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<BlockComponent
|
||||||
|
type="dataprovider"
|
||||||
|
bind:id={dataProviderId}
|
||||||
|
props={{
|
||||||
dataSource,
|
dataSource,
|
||||||
filter: newFilter,
|
filter: enrichedFilter,
|
||||||
sortColumn,
|
sortColumn,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
paginate,
|
paginate,
|
||||||
limit: rowCount,
|
limit: rowCount,
|
||||||
})
|
}}
|
||||||
|
>
|
||||||
const table = builder.createComponent("table", {
|
<BlockComponent
|
||||||
dataProvider: `{{ literal [${dataProvider.id}] }}`,
|
type="table"
|
||||||
|
props={{
|
||||||
|
dataProvider: `{{ literal [${dataProviderId}] }}`,
|
||||||
columns: tableColumns,
|
columns: tableColumns,
|
||||||
showAutoColumns,
|
showAutoColumns,
|
||||||
rowCount,
|
rowCount,
|
||||||
quiet,
|
quiet,
|
||||||
size,
|
size,
|
||||||
})
|
}}
|
||||||
|
/>
|
||||||
|
</BlockComponent>
|
||||||
|
</BlockComponent>
|
||||||
|
</Block>
|
||||||
|
|
||||||
dataProvider.addChild(table)
|
<style>
|
||||||
|
.search {
|
||||||
form.addChild(dataProvider)
|
display: flex;
|
||||||
instance = form.build()
|
flex-direction: row;
|
||||||
console.log("new instance")
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
gap: 10px;
|
||||||
}
|
}
|
||||||
</script>
|
</style>
|
||||||
|
|
||||||
<div use:styleable={$component.styles}>
|
|
||||||
<Component {instance} />
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -64,9 +64,7 @@ export const styleable = (node, styles = {}) => {
|
||||||
// Handler to select a component in the builder when clicking it in the
|
// Handler to select a component in the builder when clicking it in the
|
||||||
// builder preview
|
// builder preview
|
||||||
selectComponent = event => {
|
selectComponent = event => {
|
||||||
if (newStyles.interactive) {
|
|
||||||
builderStore.actions.selectComponent(componentId)
|
builderStore.actions.selectComponent(componentId)
|
||||||
}
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
return false
|
return false
|
||||||
|
@ -77,7 +75,7 @@ export const styleable = (node, styles = {}) => {
|
||||||
node.addEventListener("mouseout", applyNormalStyles)
|
node.addEventListener("mouseout", applyNormalStyles)
|
||||||
|
|
||||||
// Add builder preview click listener
|
// Add builder preview click listener
|
||||||
if (get(builderStore).inBuilder) {
|
if (newStyles.interactive) {
|
||||||
node.addEventListener("click", selectComponent, false)
|
node.addEventListener("click", selectComponent, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,12 +87,8 @@ export const styleable = (node, styles = {}) => {
|
||||||
const removeListeners = () => {
|
const removeListeners = () => {
|
||||||
node.removeEventListener("mouseover", applyHoverStyles)
|
node.removeEventListener("mouseover", applyHoverStyles)
|
||||||
node.removeEventListener("mouseout", applyNormalStyles)
|
node.removeEventListener("mouseout", applyNormalStyles)
|
||||||
|
|
||||||
// Remove builder preview click listener
|
|
||||||
if (get(builderStore).inBuilder) {
|
|
||||||
node.removeEventListener("click", selectComponent)
|
node.removeEventListener("click", selectComponent)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Apply initial styles
|
// Apply initial styles
|
||||||
setupStyles(styles)
|
setupStyles(styles)
|
||||||
|
|
Loading…
Reference in New Issue