Add new data bindings for context bindings and most work for component bindings
This commit is contained in:
parent
9c25955dd8
commit
6a758e3b2d
|
@ -1,4 +1,4 @@
|
||||||
packages/builder/src/userInterface/CurrentItemPreview.svelte
|
packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte
|
||||||
public
|
public
|
||||||
dist
|
dist
|
||||||
packages/server/builder
|
packages/server/builder
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { get } from "svelte/store"
|
||||||
|
import { backendUiStore, store } from "builderStore"
|
||||||
|
import { findAllMatchingComponents, findComponentPath } from "./storeUtils"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all bindable data context fields and instance fields.
|
||||||
|
*/
|
||||||
|
export const getBindableProperties = (rootComponent, componentId) => {
|
||||||
|
const bindableContexts = getBindableContexts(rootComponent, componentId)
|
||||||
|
const bindableComponents = getBindableComponents(rootComponent)
|
||||||
|
return [...bindableContexts, ...bindableComponents]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all bindable data contexts. These are fields of schemas of data contexts
|
||||||
|
* provided by data provider components, such as lists or row detail components.
|
||||||
|
*/
|
||||||
|
export const getBindableContexts = (rootComponent, componentId) => {
|
||||||
|
if (!rootComponent || !componentId) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the component tree leading up to this component
|
||||||
|
const path = findComponentPath(rootComponent, componentId)
|
||||||
|
path.pop()
|
||||||
|
|
||||||
|
// Extract any components which provide data contexts
|
||||||
|
const dataProviders = path.filter(component => {
|
||||||
|
const def = store.actions.components.getDefinition(component._component)
|
||||||
|
return def?.dataProvider
|
||||||
|
})
|
||||||
|
|
||||||
|
let contexts = []
|
||||||
|
dataProviders.forEach(provider => {
|
||||||
|
if (!provider.datasource) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { schema, table } = getSchemaForDatasource(provider.datasource)
|
||||||
|
Object.entries(schema).forEach(([key, schema]) => {
|
||||||
|
// Replace certain bindings with a new property to help display components
|
||||||
|
let runtimeBoundKey = key
|
||||||
|
if (schema.type === "link") {
|
||||||
|
runtimeBoundKey = `${key}_count`
|
||||||
|
} else if (schema.type === "attachment") {
|
||||||
|
runtimeBoundKey = `${key}_first`
|
||||||
|
}
|
||||||
|
|
||||||
|
contexts.push({
|
||||||
|
type: "context",
|
||||||
|
runtimeBinding: `${provider._id}.${runtimeBoundKey}`,
|
||||||
|
readableBinding: `${provider._instanceName}.${table.name}.${key}`,
|
||||||
|
fieldSchema: schema,
|
||||||
|
providerId: provider._id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return contexts
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all bindable components. These are form components which allow their
|
||||||
|
* values to be bound to.
|
||||||
|
*/
|
||||||
|
export const getBindableComponents = rootComponent => {
|
||||||
|
if (!rootComponent) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const componentSelector = component => {
|
||||||
|
const type = component._component
|
||||||
|
const definition = store.actions.components.getDefinition(type)
|
||||||
|
return definition.bindable
|
||||||
|
}
|
||||||
|
const components = findAllMatchingComponents(rootComponent, componentSelector)
|
||||||
|
console.log(components)
|
||||||
|
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a schema for a datasource object.
|
||||||
|
*/
|
||||||
|
const getSchemaForDatasource = datasource => {
|
||||||
|
const tables = get(backendUiStore).tables
|
||||||
|
const { type } = datasource
|
||||||
|
const table = tables.find(table => table._id === datasource.tableId)
|
||||||
|
let schema = {}
|
||||||
|
if (table) {
|
||||||
|
if (type === "table") {
|
||||||
|
schema = table.schema ?? {}
|
||||||
|
} else if (type === "view") {
|
||||||
|
schema = table.views?.[datasource.name]?.schema ?? {}
|
||||||
|
} else if (type === "link") {
|
||||||
|
schema = table.schema ?? {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { schema, table }
|
||||||
|
}
|
|
@ -1,48 +0,0 @@
|
||||||
import { walkProps } from "./storeUtils"
|
|
||||||
import { get_capitalised_name } from "../helpers"
|
|
||||||
import { get } from "svelte/store"
|
|
||||||
import { allScreens } from "builderStore"
|
|
||||||
import { FrontendTypes } from "../constants"
|
|
||||||
import { currentAsset } from "."
|
|
||||||
|
|
||||||
export default function(component, state) {
|
|
||||||
const capitalised = get_capitalised_name(
|
|
||||||
component.name || component._component
|
|
||||||
)
|
|
||||||
|
|
||||||
const matchingComponents = []
|
|
||||||
|
|
||||||
const findMatches = props => {
|
|
||||||
walkProps(props, c => {
|
|
||||||
const thisInstanceName = get_capitalised_name(c._instanceName)
|
|
||||||
if ((thisInstanceName || "").startsWith(capitalised)) {
|
|
||||||
matchingComponents.push(thisInstanceName)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// check layouts first
|
|
||||||
for (let layout of state.layouts) {
|
|
||||||
findMatches(layout.props)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if viewing screen, check current screen for duplicate
|
|
||||||
if (state.currentFrontEndType === FrontendTypes.SCREEN) {
|
|
||||||
findMatches(get(currentAsset).props)
|
|
||||||
} else {
|
|
||||||
// viewing a layout - need to find against all screens
|
|
||||||
for (let screen of get(allScreens)) {
|
|
||||||
findMatches(screen.props)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let index = 1
|
|
||||||
let name
|
|
||||||
while (!name) {
|
|
||||||
const tryName = `${capitalised || "Copy"} ${index}`
|
|
||||||
if (!matchingComponents.includes(tryName)) name = tryName
|
|
||||||
index++
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
|
@ -30,9 +30,10 @@ export function runtimeToReadableBinding(bindableProperties, textWithBindings) {
|
||||||
const binding = bindableProperties.find(({ runtimeBinding }) => {
|
const binding = bindableProperties.find(({ runtimeBinding }) => {
|
||||||
return v === `{{ ${runtimeBinding} }}`
|
return v === `{{ ${runtimeBinding} }}`
|
||||||
})
|
})
|
||||||
if (binding) {
|
temp = temp.replace(
|
||||||
temp = temp.replace(v, `{{ ${binding.readableBinding} }}`)
|
v,
|
||||||
}
|
`{{ ${binding?.readableBinding ?? "Invalid binding"} }}`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return temp
|
return temp
|
||||||
|
|
|
@ -497,7 +497,10 @@ export const getFrontendStore = () => {
|
||||||
const path = findComponentPath(selectedAsset.props, component._id) || []
|
const path = findComponentPath(selectedAsset.props, component._id) || []
|
||||||
|
|
||||||
// Remove root entry since it's the screen or layout
|
// Remove root entry since it's the screen or layout
|
||||||
return path.slice(1).join("/")
|
return path
|
||||||
|
.slice(1)
|
||||||
|
.map(component => component._id)
|
||||||
|
.join("/")
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
save: async (url, title) => {
|
save: async (url, title) => {
|
||||||
|
|
|
@ -40,22 +40,45 @@ export const findComponentParent = (rootComponent, id, parentComponent) => {
|
||||||
*/
|
*/
|
||||||
export const findComponentPath = (rootComponent, id, path = []) => {
|
export const findComponentPath = (rootComponent, id, path = []) => {
|
||||||
if (!rootComponent || !id) {
|
if (!rootComponent || !id) {
|
||||||
return null
|
return []
|
||||||
}
|
}
|
||||||
if (rootComponent._id === id) {
|
if (rootComponent._id === id) {
|
||||||
return [...path, id]
|
return [...path, rootComponent]
|
||||||
}
|
}
|
||||||
if (!rootComponent._children) {
|
if (!rootComponent._children) {
|
||||||
return null
|
return []
|
||||||
}
|
}
|
||||||
for (const child of rootComponent._children) {
|
for (const child of rootComponent._children) {
|
||||||
const newPath = [...path, rootComponent._id]
|
const newPath = [...path, rootComponent]
|
||||||
const childResult = findComponentPath(child, id, newPath)
|
const childResult = findComponentPath(child, id, newPath)
|
||||||
if (childResult != null) {
|
if (childResult?.length) {
|
||||||
return childResult
|
return childResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recurses through the component tree and finds all components of a certain
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
export const findAllMatchingComponents = (rootComponent, selector) => {
|
||||||
|
if (!rootComponent || !selector) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
let components = []
|
||||||
|
if (rootComponent._children) {
|
||||||
|
rootComponent._children.forEach(child => {
|
||||||
|
components = [
|
||||||
|
...components,
|
||||||
|
...findAllMatchingComponents(child, selector),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (selector(rootComponent)) {
|
||||||
|
components.push(rootComponent)
|
||||||
|
}
|
||||||
|
return components.reverse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,12 +1,32 @@
|
||||||
[
|
[
|
||||||
|
"container",
|
||||||
|
"grid",
|
||||||
|
"list",
|
||||||
{
|
{
|
||||||
"name": "Category",
|
"name": "Cards",
|
||||||
"icon": "ri-file-edit-line",
|
"icon": "ri-file-edit-line",
|
||||||
"children": [
|
"children": [
|
||||||
"container"
|
"card",
|
||||||
|
"stackedlist"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"grid",
|
{
|
||||||
"screenslot",
|
"name": "Forms",
|
||||||
"button"
|
"icon": "ri-file-edit-line",
|
||||||
|
"children": [
|
||||||
|
"form",
|
||||||
|
"input",
|
||||||
|
"richtext",
|
||||||
|
"datepicker"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"button",
|
||||||
|
"text",
|
||||||
|
{
|
||||||
|
"name": "Other",
|
||||||
|
"icon": "ri-file-edit-line",
|
||||||
|
"children": [
|
||||||
|
"screenslot"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
|
@ -77,18 +77,16 @@ export default function() {
|
||||||
|
|
||||||
// Stop if the target and source are the same
|
// Stop if the target and source are the same
|
||||||
if (state.targetComponent === state.dragged) {
|
if (state.targetComponent === state.dragged) {
|
||||||
console.log("same component")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Stop if the target or source are null
|
// Stop if the target or source are null
|
||||||
if (!state.targetComponent || !state.dragged) {
|
if (!state.targetComponent || !state.dragged) {
|
||||||
console.log("null component")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Stop if the target is a child of source
|
// Stop if the target is a child of source
|
||||||
const path = findComponentPath(state.dragged, state.targetComponent._id)
|
const path = findComponentPath(state.dragged, state.targetComponent._id)
|
||||||
if (path?.includes(state.targetComponent._id)) {
|
const ids = path.map(component => component._id)
|
||||||
console.log("target is child of course")
|
if (ids.includes(state.targetComponent._id)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<script>
|
<script>
|
||||||
import { Icon } from "@budibase/bbui"
|
import { Icon } from "@budibase/bbui"
|
||||||
import Input from "./Input.svelte"
|
import Input from "./Input.svelte"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
import {
|
import {
|
||||||
readableToRuntimeBinding,
|
readableToRuntimeBinding,
|
||||||
runtimeToReadableBinding,
|
runtimeToReadableBinding,
|
||||||
|
@ -15,67 +15,48 @@
|
||||||
export let componentInstance = {}
|
export let componentInstance = {}
|
||||||
export let control = null
|
export let control = null
|
||||||
export let key = ""
|
export let key = ""
|
||||||
export let value
|
export let type = ""
|
||||||
|
export let value = null
|
||||||
export let props = {}
|
export let props = {}
|
||||||
export let onChange = () => {}
|
export let onChange = () => {}
|
||||||
|
|
||||||
let temporaryBindableValue = value
|
let temporaryBindableValue = value
|
||||||
let bindableProperties = []
|
|
||||||
let anchor
|
let anchor
|
||||||
let dropdown
|
let dropdown
|
||||||
|
|
||||||
function handleClose() {
|
$: bindableProperties = getBindableProperties(
|
||||||
handleChange(key, temporaryBindableValue)
|
$currentAsset.props,
|
||||||
}
|
$store.selectedComponentId
|
||||||
|
)
|
||||||
|
$: safeValue = getSafeValue(value, props.defaultValue, bindableProperties)
|
||||||
|
$: replaceBindings = val => readableToRuntimeBinding(bindableProperties, val)
|
||||||
|
|
||||||
function getBindableProperties() {
|
// Handle a value change of any type
|
||||||
// Get all bindableProperties
|
// String values have any bindings handled
|
||||||
bindableProperties = fetchBindableProperties({
|
const handleChange = value => {
|
||||||
componentInstanceId: $store.selectedComponentId,
|
let innerVal = value
|
||||||
components: $store.components,
|
if (value && typeof value === "object") {
|
||||||
screen: $currentAsset,
|
if ("detail" in value) {
|
||||||
tables: $backendUiStore.tables,
|
innerVal = value.detail
|
||||||
})
|
} else if ("target" in value) {
|
||||||
}
|
innerVal = value.target.value
|
||||||
|
|
||||||
function replaceBindings(textWithBindings) {
|
|
||||||
getBindableProperties()
|
|
||||||
textWithBindings = readableToRuntimeBinding(
|
|
||||||
bindableProperties,
|
|
||||||
textWithBindings
|
|
||||||
)
|
|
||||||
onChange(key, textWithBindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleChange(key, v) {
|
|
||||||
let innerVal = v
|
|
||||||
if (typeof v === "object") {
|
|
||||||
if ("detail" in v) {
|
|
||||||
innerVal = v.detail
|
|
||||||
} else if ("target" in v) {
|
|
||||||
innerVal = props.valueKey ? v.target[props.valueKey] : v.target.value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof innerVal === "string") {
|
if (typeof innerVal === "string") {
|
||||||
replaceBindings(innerVal)
|
onChange(replaceBindings(innerVal))
|
||||||
} else {
|
} else {
|
||||||
onChange(key, innerVal)
|
onChange(innerVal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeValue = () => {
|
// The "safe" value is the value with eny bindings made readable
|
||||||
getBindableProperties()
|
// If there is no value set, any default value is used
|
||||||
|
const getSafeValue = (value, defaultValue, bindableProperties) => {
|
||||||
let temp = runtimeToReadableBinding(bindableProperties, value)
|
const enriched = runtimeToReadableBinding(bindableProperties, value)
|
||||||
|
return enriched == null && defaultValue !== undefined
|
||||||
return value == null && props.initialValue !== undefined
|
? defaultValue
|
||||||
? props.initialValue
|
: enriched
|
||||||
: temp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Incase the component has a different value key name
|
|
||||||
const handlevalueKey = value =>
|
|
||||||
props.valueKey ? { [props.valueKey]: safeValue() } : { value: safeValue() }
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="property-control" bind:this={anchor}>
|
<div class="property-control" bind:this={anchor}>
|
||||||
|
@ -84,13 +65,13 @@
|
||||||
<svelte:component
|
<svelte:component
|
||||||
this={control}
|
this={control}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{...handlevalueKey(value)}
|
value={safeValue}
|
||||||
on:change={val => handleChange(key, val)}
|
on:change={handleChange}
|
||||||
onChange={val => handleChange(key, val)}
|
onChange={handleChange}
|
||||||
{...props}
|
{...props}
|
||||||
name={key} />
|
name={key} />
|
||||||
</div>
|
</div>
|
||||||
{#if bindable && !key.startsWith('_') && control === Input}
|
{#if bindable && !key.startsWith('_') && type === 'text'}
|
||||||
<div
|
<div
|
||||||
class="icon"
|
class="icon"
|
||||||
data-cy={`${key}-binding-button`}
|
data-cy={`${key}-binding-button`}
|
||||||
|
@ -99,14 +80,14 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if control == Input}
|
{#if type === 'text'}
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
on:close={handleClose}
|
on:close={() => handleChange(temporaryBindableValue)}
|
||||||
bind:this={dropdown}
|
bind:this={dropdown}
|
||||||
{anchor}
|
{anchor}
|
||||||
align="right">
|
align="right">
|
||||||
<BindingDropdown
|
<BindingDropdown
|
||||||
{...handlevalueKey(value)}
|
value={safeValue}
|
||||||
close={dropdown.hide}
|
close={dropdown.hide}
|
||||||
on:update={e => (temporaryBindableValue = e.detail)}
|
on:update={e => (temporaryBindableValue = e.detail)}
|
||||||
{bindableProperties} />
|
{bindableProperties} />
|
||||||
|
|
|
@ -22,11 +22,12 @@
|
||||||
<div>
|
<div>
|
||||||
{#each properties as prop}
|
{#each properties as prop}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
|
bindable={false}
|
||||||
label={`${prop.label}${hasPropChanged(style, prop) ? ' *' : ''}`}
|
label={`${prop.label}${hasPropChanged(style, prop) ? ' *' : ''}`}
|
||||||
control={prop.control}
|
control={prop.control}
|
||||||
key={prop.key}
|
key={prop.key}
|
||||||
value={style[prop.key]}
|
value={style[prop.key]}
|
||||||
onChange={(key, value) => onStyleChanged(styleCategory, key, value)}
|
onChange={value => onStyleChanged(styleCategory, prop.key, value)}
|
||||||
props={{ options: prop.options, placeholder: prop.placeholder }} />
|
props={{ options: prop.options, placeholder: prop.placeholder }} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { Icon, DropdownMenu, Heading } from "@budibase/bbui"
|
import { Icon, DropdownMenu, Heading } from "@budibase/bbui"
|
||||||
import { createEventDispatcher } from "svelte"
|
import { createEventDispatcher } from "svelte"
|
||||||
import { store, backendUiStore, currentAsset } from "builderStore"
|
import { store, backendUiStore, currentAsset } from "builderStore"
|
||||||
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
import { getBindableProperties } from "builderStore/dataBinding"
|
||||||
|
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let anchorRight, dropdownRight
|
let anchorRight, dropdownRight
|
||||||
|
@ -31,18 +31,17 @@
|
||||||
return [...acc, ...viewsArr]
|
return [...acc, ...viewsArr]
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
$: bindableProperties = fetchBindableProperties({
|
$: bindableProperties = getBindableProperties(
|
||||||
componentInstanceId: $store.selectedComponentId,
|
$currentAsset.props,
|
||||||
components: $store.components,
|
$store.selectedComponentId
|
||||||
screen: $currentAsset,
|
)
|
||||||
tables: $backendUiStore.tables,
|
$: console.log(bindableProperties)
|
||||||
})
|
|
||||||
|
|
||||||
$: links = bindableProperties
|
$: links = bindableProperties
|
||||||
.filter(x => x.fieldSchema?.type === "link")
|
.filter(x => x.fieldSchema?.type === "link")
|
||||||
.map(property => {
|
.map(property => {
|
||||||
return {
|
return {
|
||||||
providerId: property.instance._id,
|
providerId: property.providerId,
|
||||||
label: property.readableBinding,
|
label: property.readableBinding,
|
||||||
fieldName: property.fieldSchema.name,
|
fieldName: property.fieldSchema.name,
|
||||||
name: `all_${property.fieldSchema.tableId}`,
|
name: `all_${property.fieldSchema.tableId}`,
|
||||||
|
|
|
@ -25,6 +25,13 @@
|
||||||
export let onScreenPropChange = () => {}
|
export let onScreenPropChange = () => {}
|
||||||
export let showDisplayName = false
|
export let showDisplayName = false
|
||||||
|
|
||||||
|
const layoutDefinition = []
|
||||||
|
const screenDefinition = [
|
||||||
|
{ key: "description", label: "Description", control: Input },
|
||||||
|
{ key: "routing.route", label: "Route", control: Input },
|
||||||
|
{ key: "routing.roleId", label: "Access", control: RoleSelect },
|
||||||
|
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
||||||
|
]
|
||||||
const assetProps = [
|
const assetProps = [
|
||||||
"title",
|
"title",
|
||||||
"description",
|
"description",
|
||||||
|
@ -34,12 +41,15 @@
|
||||||
]
|
]
|
||||||
|
|
||||||
$: settings = componentDefinition?.settings ?? []
|
$: settings = componentDefinition?.settings ?? []
|
||||||
|
$: isLayout = assetInstance && assetInstance.favicon
|
||||||
|
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
|
||||||
|
|
||||||
const controlMap = {
|
const controlMap = {
|
||||||
text: Input,
|
text: Input,
|
||||||
select: OptionSelect,
|
select: OptionSelect,
|
||||||
datasource: TableViewSelect,
|
datasource: TableViewSelect,
|
||||||
detailURL: DetailScreenSelect,
|
screen: ScreenSelect,
|
||||||
|
detailScreen: DetailScreenSelect,
|
||||||
boolean: Checkbox,
|
boolean: Checkbox,
|
||||||
number: Input,
|
number: Input,
|
||||||
event: EventsEditor,
|
event: EventsEditor,
|
||||||
|
@ -48,17 +58,6 @@
|
||||||
return controlMap[type]
|
return controlMap[type]
|
||||||
}
|
}
|
||||||
|
|
||||||
const propExistsOnComponentDef = prop =>
|
|
||||||
assetProps.includes(prop) || prop in (componentDefinition?.props ?? {})
|
|
||||||
|
|
||||||
const layoutDefinition = []
|
|
||||||
const screenDefinition = [
|
|
||||||
{ key: "description", label: "Description", control: Input },
|
|
||||||
{ key: "routing.route", label: "Route", control: Input },
|
|
||||||
{ key: "routing.roleId", label: "Access", control: RoleSelect },
|
|
||||||
{ key: "layoutId", label: "Layout", control: LayoutSelect },
|
|
||||||
]
|
|
||||||
|
|
||||||
const canRenderControl = setting => {
|
const canRenderControl = setting => {
|
||||||
const control = getControl(setting?.type)
|
const control = getControl(setting?.type)
|
||||||
if (!control) {
|
if (!control) {
|
||||||
|
@ -70,29 +69,27 @@
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isLayout = assetInstance && assetInstance.favicon
|
const onInstanceNameChange = name => {
|
||||||
$: assetDefinition = isLayout ? layoutDefinition : screenDefinition
|
|
||||||
|
|
||||||
const onInstanceNameChange = (_, name) => {
|
|
||||||
onChange("_instanceName", name)
|
onChange("_instanceName", name)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="settings-view-container">
|
<div class="settings-view-container">
|
||||||
{#if assetInstance}
|
{#if assetInstance}
|
||||||
{#each assetDefinition as def}
|
{#each assetDefinition as def (`${componentInstance._id}-${def.key}`)}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
bindable={false}
|
bindable={false}
|
||||||
control={def.control}
|
control={def.control}
|
||||||
label={def.label}
|
label={def.label}
|
||||||
key={def.key}
|
key={def.key}
|
||||||
value={get(assetInstance, def.key)}
|
value={get(assetInstance, def.key)}
|
||||||
onChange={onScreenPropChange} />
|
onChange={val => onScreenPropChange(def.key, val)} />
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if showDisplayName}
|
{#if showDisplayName}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
|
bindable={false}
|
||||||
control={Input}
|
control={Input}
|
||||||
label="Name"
|
label="Name"
|
||||||
key="_instanceName"
|
key="_instanceName"
|
||||||
|
@ -101,15 +98,16 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if settings && settings.length > 0}
|
{#if settings && settings.length > 0}
|
||||||
{#each settings as setting}
|
{#each settings as setting (`${componentInstance._id}-${setting.key}`)}
|
||||||
{#if canRenderControl(setting)}
|
{#if canRenderControl(setting)}
|
||||||
<PropertyControl
|
<PropertyControl
|
||||||
|
type={setting.type}
|
||||||
control={getControl(setting.type)}
|
control={getControl(setting.type)}
|
||||||
label={setting.label}
|
label={setting.label}
|
||||||
key={setting.key}
|
key={setting.key}
|
||||||
value={componentInstance[setting.key] ?? componentInstance[setting.key]?.defaultValue}
|
value={componentInstance[setting.key] ?? componentInstance[setting.key]?.defaultValue}
|
||||||
{componentInstance}
|
{componentInstance}
|
||||||
{onChange}
|
onChange={val => onChange(setting.key, val)}
|
||||||
props={{ options: setting.options }} />
|
props={{ options: setting.options }} />
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -1,225 +1,10 @@
|
||||||
import Input from "./PropertiesPanel/PropertyControls/Input.svelte"
|
|
||||||
import OptionSelect from "./PropertiesPanel/PropertyControls/OptionSelect.svelte"
|
|
||||||
import MultiTableViewFieldSelect from "./PropertiesPanel/PropertyControls/MultiTableViewFieldSelect.svelte"
|
|
||||||
import Checkbox from "../common/Checkbox.svelte"
|
|
||||||
import TableSelect from "components/userInterface/PropertyControls/TableSelect.svelte"
|
|
||||||
import TableViewSelect from "components/userInterface/PropertyControls/TableViewSelect.svelte"
|
|
||||||
import TableViewFieldSelect from "components/userInterface/PropertyControls/TableViewFieldSelect.svelte"
|
|
||||||
import Event from "components/userInterface/PropertyControls/EventsEditor/EventPropertyControl.svelte"
|
|
||||||
import ScreenSelect from "components/userInterface/PropertyControls/ScreenSelect.svelte"
|
|
||||||
import DetailScreenSelect from "components/userInterface/PropertyControls/DetailScreenSelect.svelte"
|
|
||||||
import { IconSelect } from "components/userInterface/PropertyControls/IconSelect"
|
|
||||||
import Colorpicker from "@budibase/colorpicker"
|
|
||||||
|
|
||||||
import { all } from "./propertyCategories.js"
|
|
||||||
/*
|
|
||||||
{ label: "N/A ", value: "N/A" },
|
|
||||||
{ label: "Flex", value: "flex" },
|
|
||||||
{ label: "Inline Flex", value: "inline-flex" },
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
categories: [
|
categories: [
|
||||||
{
|
|
||||||
name: "Repeater",
|
|
||||||
_component: "@budibase/standard-components/list",
|
|
||||||
description: "Renders all children once per row, of a given table",
|
|
||||||
icon: "ri-list-check-2",
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [
|
|
||||||
{
|
|
||||||
label: "Data",
|
|
||||||
key: "datasource",
|
|
||||||
control: TableViewSelect,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
children: [],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "Form",
|
|
||||||
icon: "ri-file-edit-line",
|
|
||||||
isCategory: true,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
_component: "@budibase/standard-components/form",
|
|
||||||
name: "Form",
|
|
||||||
icon: "ri-file-edit-line",
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "@budibase/standard-components/textfield",
|
|
||||||
name: "Text Field",
|
|
||||||
description:
|
|
||||||
"A textfield component that allows the user to input text.",
|
|
||||||
icon: "ri-edit-box-line",
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [
|
|
||||||
{ label: "Label", key: "label", control: Input },
|
|
||||||
{
|
|
||||||
label: "Type",
|
|
||||||
key: "type",
|
|
||||||
control: OptionSelect,
|
|
||||||
options: ["text", "password"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// _component: "@budibase/standard-components/richtext",
|
|
||||||
// name: "Rich Text",
|
|
||||||
// description:
|
|
||||||
// "A component that allows the user to enter long form text.",
|
|
||||||
// icon: "ri-edit-box-line",
|
|
||||||
// properties: {
|
|
||||||
// design: { ...all },
|
|
||||||
// settings: [],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// _component: "@budibase/standard-components/datepicker",
|
|
||||||
// name: "Date Picker",
|
|
||||||
// description: "A basic date picker component",
|
|
||||||
// icon: "ri-calendar-line",
|
|
||||||
// children: [],
|
|
||||||
// properties: {
|
|
||||||
// design: { ...all },
|
|
||||||
// settings: [
|
|
||||||
// { label: "Placeholder", key: "placeholder", control: Input },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Card",
|
name: "Card",
|
||||||
icon: "ri-archive-drawer-line",
|
icon: "ri-archive-drawer-line",
|
||||||
isCategory: true,
|
isCategory: true,
|
||||||
children: [
|
children: [
|
||||||
{
|
|
||||||
_component: "@budibase/standard-components/stackedlist",
|
|
||||||
name: "Stacked List",
|
|
||||||
icon: "ri-archive-drawer-line",
|
|
||||||
description:
|
|
||||||
"A basic card component that can contain content and actions.",
|
|
||||||
children: [],
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [
|
|
||||||
{
|
|
||||||
label: "Image",
|
|
||||||
key: "imageUrl",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "{{{context.Image}}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Heading",
|
|
||||||
key: "heading",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "{{context.Heading}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Text 1",
|
|
||||||
key: "text1",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "{{context.Text 1}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Text 2",
|
|
||||||
key: "text2",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "{{context.Text 2}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Text 3",
|
|
||||||
key: "text3",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "{{context.Text 3}}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Link URL",
|
|
||||||
key: "destinationUrl",
|
|
||||||
control: ScreenSelect,
|
|
||||||
placeholder: "/table/_id",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "@budibase/standard-components/card",
|
|
||||||
name: "Vertical",
|
|
||||||
description:
|
|
||||||
"A basic card component that can contain content and actions.",
|
|
||||||
icon: "ri-layout-column-line",
|
|
||||||
children: [],
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [
|
|
||||||
{
|
|
||||||
label: "Image",
|
|
||||||
key: "imageUrl",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "Image",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Heading",
|
|
||||||
key: "heading",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "Heading",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Description",
|
|
||||||
key: "description",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "Description",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Link Text",
|
|
||||||
key: "linkText",
|
|
||||||
control: Input,
|
|
||||||
placeholder: "Link Text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Link Url",
|
|
||||||
key: "linkUrl",
|
|
||||||
control: ScreenSelect,
|
|
||||||
placeholder: "Link URL",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Link Color",
|
|
||||||
key: "linkColor",
|
|
||||||
control: Colorpicker,
|
|
||||||
defaultValue: "#000",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Hover Color",
|
|
||||||
key: "linkHoverColor",
|
|
||||||
control: Colorpicker,
|
|
||||||
defaultValue: "#222",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Image Height",
|
|
||||||
key: "imageHeight",
|
|
||||||
control: OptionSelect,
|
|
||||||
options: ["12rem", "16rem", "20rem", "24rem"],
|
|
||||||
placeholder: "Image Height",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Card Width",
|
|
||||||
key: "cardWidth",
|
|
||||||
control: OptionSelect,
|
|
||||||
options: ["16rem", "20rem", "24rem"],
|
|
||||||
placeholder: "Card Width",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/cardhorizontal",
|
_component: "@budibase/standard-components/cardhorizontal",
|
||||||
name: "Horizontal",
|
name: "Horizontal",
|
||||||
|
@ -957,40 +742,7 @@ export default {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
_component: "@budibase/standard-components/text",
|
|
||||||
name: "Paragraph",
|
|
||||||
description: "A component for displaying paragraph text.",
|
|
||||||
icon: "ri-paragraph",
|
|
||||||
properties: {
|
|
||||||
design: { ...all },
|
|
||||||
settings: [
|
|
||||||
{
|
|
||||||
label: "Text",
|
|
||||||
key: "text",
|
|
||||||
control: Input,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Type",
|
|
||||||
key: "type",
|
|
||||||
control: OptionSelect,
|
|
||||||
options: [
|
|
||||||
"none",
|
|
||||||
"bold",
|
|
||||||
"strong",
|
|
||||||
"italic",
|
|
||||||
"emphasis",
|
|
||||||
"mark",
|
|
||||||
"small",
|
|
||||||
"del",
|
|
||||||
"ins",
|
|
||||||
"sub",
|
|
||||||
"sup",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
_component: "@budibase/standard-components/image",
|
_component: "@budibase/standard-components/image",
|
||||||
name: "Image",
|
name: "Image",
|
||||||
|
|
|
@ -36,57 +36,6 @@
|
||||||
"logon"
|
"logon"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"input": {
|
|
||||||
"name": "Textfield",
|
|
||||||
"bindable": "value",
|
|
||||||
"description": "An HTML input",
|
|
||||||
"props": {
|
|
||||||
"type": {
|
|
||||||
"type": "options",
|
|
||||||
"options": [
|
|
||||||
"text",
|
|
||||||
"password",
|
|
||||||
"checkbox",
|
|
||||||
"color",
|
|
||||||
"date",
|
|
||||||
"datetime-local",
|
|
||||||
"email",
|
|
||||||
"file",
|
|
||||||
"hidden",
|
|
||||||
"image",
|
|
||||||
"month",
|
|
||||||
"number",
|
|
||||||
"radio",
|
|
||||||
"range",
|
|
||||||
"reset",
|
|
||||||
"search",
|
|
||||||
"submit",
|
|
||||||
"tel",
|
|
||||||
"time",
|
|
||||||
"week"
|
|
||||||
],
|
|
||||||
"default": "text"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"form"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"text": {
|
|
||||||
"name": "Text",
|
|
||||||
"description": "stylable block of text",
|
|
||||||
"props": {
|
|
||||||
"text": "string",
|
|
||||||
"type": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "none"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"div",
|
|
||||||
"container"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"richtext": {
|
"richtext": {
|
||||||
"name": "Rich Text",
|
"name": "Rich Text",
|
||||||
"description": "A component that allows the user to enter long form text.",
|
"description": "A component that allows the user to enter long form text.",
|
||||||
|
@ -109,40 +58,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"dataform": {
|
|
||||||
"name": "Form",
|
|
||||||
"description": "an HTML table that fetches data from a table or view and displays it.",
|
|
||||||
"data": true,
|
|
||||||
"props": {}
|
|
||||||
},
|
|
||||||
"dataformwide": {
|
|
||||||
"name": "Form Wide",
|
|
||||||
"description": "an HTML table that fetches data from a table or view and displays it.",
|
|
||||||
"data": true,
|
|
||||||
"props": {}
|
|
||||||
},
|
|
||||||
"list": {
|
|
||||||
"name": "Repeater",
|
|
||||||
"description": "A configurable data list that attaches to your backend tables.",
|
|
||||||
"context": "datasource",
|
|
||||||
"children": true,
|
|
||||||
"data": true,
|
|
||||||
"props": {
|
|
||||||
"datasource": "tables"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stackedlist": {
|
|
||||||
"name": "Stacked List",
|
|
||||||
"description": "A stacked list component for displaying information",
|
|
||||||
"props": {
|
|
||||||
"imageUrl": "string",
|
|
||||||
"heading": "string",
|
|
||||||
"text1": "string",
|
|
||||||
"text2": "string",
|
|
||||||
"text3": "string",
|
|
||||||
"destinationUrl": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"rowdetail": {
|
"rowdetail": {
|
||||||
"name": "Row Detail",
|
"name": "Row Detail",
|
||||||
"description": "Loads a row, using an ID in the url",
|
"description": "Loads a row, using an ID in the url",
|
||||||
|
@ -165,43 +81,6 @@
|
||||||
"table": "tables"
|
"table": "tables"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"card": {
|
|
||||||
"name": "Card",
|
|
||||||
"props": {
|
|
||||||
"imageUrl": "string",
|
|
||||||
"heading": "string",
|
|
||||||
"description": "string",
|
|
||||||
"linkText": "string",
|
|
||||||
"linkUrl": "string",
|
|
||||||
"linkColor": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "#000"
|
|
||||||
},
|
|
||||||
"linkHoverColor": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "#000"
|
|
||||||
},
|
|
||||||
"imageHeight": {
|
|
||||||
"type": "options",
|
|
||||||
"default": "20rem",
|
|
||||||
"options": [
|
|
||||||
"12rem",
|
|
||||||
"16rem",
|
|
||||||
"20rem",
|
|
||||||
"24rem"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"cardWidth": {
|
|
||||||
"type": "options",
|
|
||||||
"default": "20rem",
|
|
||||||
"options": [
|
|
||||||
"16rem",
|
|
||||||
"20rem",
|
|
||||||
"24rem"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cardstat": {
|
"cardstat": {
|
||||||
"name": "Stat Card",
|
"name": "Stat Card",
|
||||||
"props": {
|
"props": {
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
"key": "datasource"
|
"key": "datasource"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "detailURL",
|
"type": "detailScreen",
|
||||||
"label": "Detail URL",
|
"label": "Detail URL",
|
||||||
"key": "detailUrl"
|
"key": "detailUrl"
|
||||||
},
|
},
|
||||||
|
@ -90,8 +90,7 @@
|
||||||
{
|
{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"label": "Disabled",
|
"label": "Disabled",
|
||||||
"key": "disabled",
|
"key": "disabled"
|
||||||
"valueKey": "checked"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "event",
|
"type": "event",
|
||||||
|
@ -99,5 +98,176 @@
|
||||||
"key": "onClick"
|
"key": "onClick"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"name": "Repeater",
|
||||||
|
"description": "A configurable data list that attaches to your backend tables.",
|
||||||
|
"icon": "ri-list-check-2",
|
||||||
|
"styleable": true,
|
||||||
|
"hasChildren": true,
|
||||||
|
"dataProvider": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "datasource",
|
||||||
|
"label": "Data",
|
||||||
|
"key": "datasource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"name": "Form",
|
||||||
|
"icon": "ri-file-edit-line",
|
||||||
|
"styleable": true
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"name": "Text Field",
|
||||||
|
"description": "A textfield component that allows the user to input text.",
|
||||||
|
"icon": "ri-edit-box-line",
|
||||||
|
"styleable": true,
|
||||||
|
"bindable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Label",
|
||||||
|
"key": "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Type",
|
||||||
|
"key": "type",
|
||||||
|
"defaultValue": "text",
|
||||||
|
"options": ["text", "password"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"richtext": {
|
||||||
|
"name": "Rich Text",
|
||||||
|
"description": "A component that allows the user to enter long form text.",
|
||||||
|
"icon": "ri-edit-box-line",
|
||||||
|
"styleable": true,
|
||||||
|
"bindable": true
|
||||||
|
},
|
||||||
|
"datepicker": {
|
||||||
|
"name": "Date Picker",
|
||||||
|
"description": "A basic date picker component",
|
||||||
|
"icon": "ri-calendar-line",
|
||||||
|
"styleable": true,
|
||||||
|
"bindable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Placeholder",
|
||||||
|
"key": "placeholder"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"stackedlist": {
|
||||||
|
"name": "Stacked List",
|
||||||
|
"icon": "ri-archive-drawer-line",
|
||||||
|
"description": "A basic card component that can contain content and actions.",
|
||||||
|
"styleable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Image",
|
||||||
|
"key": "imageUrl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Heading",
|
||||||
|
"key": "heading"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Text 1",
|
||||||
|
"key": "text1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Text 2",
|
||||||
|
"key": "text2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Text 3",
|
||||||
|
"key": "text3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "screen",
|
||||||
|
"label": "Link URL",
|
||||||
|
"key": "destinationUrl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"card": {
|
||||||
|
"name": "Vertical Card",
|
||||||
|
"description": "A basic card component that can contain content and actions.",
|
||||||
|
"icon": "ri-layout-column-line",
|
||||||
|
"styleable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Image",
|
||||||
|
"key": "imageUrl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Heading",
|
||||||
|
"key": "heading"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Description",
|
||||||
|
"key": "description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Link Text",
|
||||||
|
"key": "linkText"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "screen",
|
||||||
|
"label": "Link Url",
|
||||||
|
"key": "linkUrl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "Link Color",
|
||||||
|
"key": "linkColor",
|
||||||
|
"defaultValue": "#000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "color",
|
||||||
|
"label": "Hover Color",
|
||||||
|
"key": "linkHoverColor",
|
||||||
|
"defaultValue": "#222"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Image Height",
|
||||||
|
"key": "imageHeight",
|
||||||
|
"options": ["auto", "12rem", "16rem", "20rem", "24rem"],
|
||||||
|
"defaultValue": "auto"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "select",
|
||||||
|
"label": "Card Width",
|
||||||
|
"key": "cardWidth",
|
||||||
|
"options": ["16rem", "20rem", "24rem"],
|
||||||
|
"defaultValue": "20rem"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"name": "Paragraph",
|
||||||
|
"description": "A component for displaying paragraph text.",
|
||||||
|
"icon": "ri-paragraph",
|
||||||
|
"styleable": true,
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"label": "Text",
|
||||||
|
"key": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
import { cssVars } from "./helpers"
|
|
||||||
|
|
||||||
const { styleable } = getContext("sdk")
|
const { styleable } = getContext("sdk")
|
||||||
const component = getContext("component")
|
const component = getContext("component")
|
||||||
|
@ -16,22 +15,21 @@
|
||||||
export let imageHeight
|
export let imageHeight
|
||||||
export let cardWidth
|
export let cardWidth
|
||||||
|
|
||||||
$: cssVariables = {
|
$: cardStyles = {
|
||||||
imageHeight,
|
...$component.styles,
|
||||||
cardWidth,
|
normal: {
|
||||||
|
...$component.styles.normal,
|
||||||
|
width: cardWidth,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
$: showImage = !!imageUrl
|
$: showImage = !!imageUrl
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div class="container" use:styleable={cardStyles}>
|
||||||
use:cssVars={cssVariables}
|
|
||||||
class="container"
|
|
||||||
use:styleable={$component.styles}
|
|
||||||
style="--cardWidth: {cardWidth}">
|
|
||||||
{#if showImage}
|
{#if showImage}
|
||||||
<img
|
<img
|
||||||
style="--imageWidth: {imageWidth}; --imageHeight: {imageHeight}"
|
style="--imageHeight: {imageHeight}"
|
||||||
class="image"
|
class="image"
|
||||||
src={imageUrl}
|
src={imageUrl}
|
||||||
alt="" />
|
alt="" />
|
||||||
|
|
|
@ -9,23 +9,24 @@ export { default as container } from "./Container.svelte"
|
||||||
export { default as grid } from "./grid/Component.svelte"
|
export { default as grid } from "./grid/Component.svelte"
|
||||||
export { default as screenslot } from "./ScreenSlot.svelte"
|
export { default as screenslot } from "./ScreenSlot.svelte"
|
||||||
export { default as button } from "./Button.svelte"
|
export { default as button } from "./Button.svelte"
|
||||||
|
export { default as input } from "./Input.svelte"
|
||||||
|
export { default as richtext } from "./RichText.svelte"
|
||||||
|
export { default as list } from "./List.svelte"
|
||||||
|
export { default as stackedlist } from "./StackedList.svelte"
|
||||||
|
export { default as card } from "./Card.svelte"
|
||||||
|
export { default as form } from "./DataFormWide.svelte"
|
||||||
|
export { default as datepicker } from "./DatePicker.svelte"
|
||||||
|
export { default as text } from "./Text.svelte"
|
||||||
|
|
||||||
// export { default as text } from "./Text.svelte"
|
|
||||||
// export { default as heading } from "./Heading.svelte"
|
// export { default as heading } from "./Heading.svelte"
|
||||||
// export { default as input } from "./Input.svelte"
|
|
||||||
// export { default as richtext } from "./RichText.svelte"
|
|
||||||
// export { default as login } from "./Login.svelte"
|
// export { default as login } from "./Login.svelte"
|
||||||
// export { default as link } from "./Link.svelte"
|
// export { default as link } from "./Link.svelte"
|
||||||
// export { default as image } from "./Image.svelte"
|
// export { default as image } from "./Image.svelte"
|
||||||
// export { default as navigation } from "./Navigation.svelte"
|
// export { default as navigation } from "./Navigation.svelte"
|
||||||
// export { default as list } from "./List.svelte"
|
|
||||||
// export { default as embed } from "./Embed.svelte"
|
// export { default as embed } from "./Embed.svelte"
|
||||||
// export { default as stackedlist } from "./StackedList.svelte"
|
|
||||||
// export { default as card } from "./Card.svelte"
|
|
||||||
// export { default as cardhorizontal } from "./CardHorizontal.svelte"
|
// export { default as cardhorizontal } from "./CardHorizontal.svelte"
|
||||||
// export { default as cardstat } from "./CardStat.svelte"
|
// export { default as cardstat } from "./CardStat.svelte"
|
||||||
// export { default as rowdetail } from "./RowDetail.svelte"
|
// export { default as rowdetail } from "./RowDetail.svelte"
|
||||||
// export { default as newrow } from "./NewRow.svelte"
|
// export { default as newrow } from "./NewRow.svelte"
|
||||||
// export { default as datepicker } from "./DatePicker.svelte"
|
|
||||||
// export { default as icon } from "./Icon.svelte"
|
// export { default as icon } from "./Icon.svelte"
|
||||||
// export * from "./charts"
|
// export * from "./charts"
|
||||||
|
|
Loading…
Reference in New Issue