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