feat(frontend): Add select component to app builder (#1021)
* feat(frontend): Add select input to app builder
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import Select from 'svelte-select'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
export let id: string
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
|
||||
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let label: string
|
||||
let items: string[]
|
||||
let itemKey: string
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
result: Output<string | undefined>
|
||||
}
|
||||
|
||||
function onChange({detail}: CustomEvent) {
|
||||
outputs?.result.set(detail?.[itemKey] || undefined)
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputValue input={configuration.label} bind:value={label} />
|
||||
<InputValue input={configuration.items} bind:value={items} />
|
||||
<InputValue input={configuration.itemKey} bind:value={itemKey} />
|
||||
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<label class="block w-full">
|
||||
<div>
|
||||
{label}
|
||||
</div>
|
||||
<div>
|
||||
<Select
|
||||
on:clear={onChange}
|
||||
on:change={onChange}
|
||||
|
||||
{items}
|
||||
class="w-full"
|
||||
placeholder="Select an item"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</AlignWrapper>
|
||||
@@ -8,6 +8,7 @@
|
||||
import type { AppComponent, AppEditorContext } from '../types'
|
||||
import ButtonComponent from '../components/buttons/AppButton.svelte'
|
||||
import PieChartComponent from '../components/dataDisplay/AppPieChart.svelte'
|
||||
import SelectComponent from '../components/selectInputs/AppSelect.svelte'
|
||||
import CheckboxComponent from '../components/selectInputs/AppCheckbox.svelte'
|
||||
import TextInputComponent from '../components/textInputs/AppTextInput.svelte'
|
||||
import NumberInputComponent from '../components/numberInputs/AppNumberInput.svelte'
|
||||
@@ -29,11 +30,12 @@
|
||||
|
||||
<div
|
||||
class={classNames(
|
||||
' border overflow-auto cursor-pointer h-full bg-white',
|
||||
' border cursor-pointer h-full bg-white',
|
||||
shouldDisplayOverlay ? 'border-blue-500' : 'border-white',
|
||||
!selected && $mode !== 'preview' && !component.card ? 'border-gray-100' : '',
|
||||
$mode !== 'preview' && !$connectingInput.opened ? 'hover:border-blue-500' : '',
|
||||
component.card ? 'p-2' : '',
|
||||
component.softWrap ? '' : 'overflow-auto',
|
||||
'relative'
|
||||
)}
|
||||
>
|
||||
@@ -73,6 +75,11 @@
|
||||
bind:componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'selectcomponent'}
|
||||
<SelectComponent
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
/>
|
||||
{:else if component.type === 'formcomponent'}
|
||||
<AppForm
|
||||
{...component}
|
||||
|
||||
@@ -15,31 +15,20 @@
|
||||
|
||||
const { app } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function getMinDimensionsByComponent(componentType: string, column: number): Size {
|
||||
console.log(componentType, column)
|
||||
if (componentType === 'buttoncomponent') {
|
||||
return column === 3 ? { w: 1, h: 1 } : { w: 3, h: 1 }
|
||||
} else if (componentType === 'formcomponent') {
|
||||
return column === 3 ? { w: 2, h: 3 } : { w: 6, h: 4 }
|
||||
} else if (componentType === 'textcomponent') {
|
||||
return column === 3 ? { w: 1, h: 1 } : { w: 3, h: 1 }
|
||||
} else if (componentType === 'textinputcomponent') {
|
||||
return column === 3 ? { w: 1, h: 2 } : { w: 3, h: 2 }
|
||||
} else if (componentType === 'numberinputcomponent') {
|
||||
return column === 3 ? { w: 1, h: 2 } : { w: 3, h: 2 }
|
||||
} else if (componentType === 'barchartcomponent') {
|
||||
return column === 3 ? { w: 2, h: 4 } : { w: 6, h: 4 }
|
||||
} else if (componentType === 'piechartcomponent') {
|
||||
return column === 3 ? { w: 2, h: 4 } : { w: 6, h: 4 }
|
||||
} else if (componentType === 'tablecomponent') {
|
||||
return column === 3 ? { w: 3, h: 4 } : { w: 12, h: 4 }
|
||||
} else if (componentType === 'displaycomponent') {
|
||||
return column === 3 ? { w: 2, h: 2 } : { w: 6, h: 4 }
|
||||
} else if (componentType === 'checkboxcomponent') {
|
||||
return column === 3 ? { w: 1, h: 1 } : { w: 3, h: 1 }
|
||||
} else {
|
||||
return { w: 2, h: 1 }
|
||||
function getMinDimensionsByComponent(componentType: AppComponent['type'], column: number): Size {
|
||||
// Dimensions key formula: <mobile width>:<mobile height>-<desktop width>:<desktop height>
|
||||
const dimensions: Record<`${number}:${number}-${number}:${number}`, AppComponent['type'][]> = {
|
||||
'1:1-3:1': [ 'buttoncomponent', 'textcomponent', 'checkboxcomponent' ],
|
||||
'1:2-3:2': [ 'textinputcomponent', 'numberinputcomponent', 'selectcomponent' ],
|
||||
'2:2-6:4': [ 'displaycomponent' ],
|
||||
'2:3-6:4': [ 'formcomponent' ],
|
||||
'2:4-6:4': [ 'barchartcomponent', 'piechartcomponent' ],
|
||||
'3:4-12:4': [ 'tablecomponent' ],
|
||||
}
|
||||
// Finds the key that is associated with the component type and extracts the dimensions from it
|
||||
const [dimension] = Object.entries(dimensions).find(([_, value]) => value.includes(componentType)) || ['2:1-2:1']
|
||||
const size = dimension.split('-')[column === 3 ? 0 : 1].split(':')
|
||||
return { w: +size[0], h: +size[1] }
|
||||
}
|
||||
|
||||
function addComponent(appComponent: AppComponent) {
|
||||
|
||||
@@ -27,9 +27,9 @@ const inputs: ComponentSet = {
|
||||
label: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: 'Title',
|
||||
value: 'Label',
|
||||
fieldType: 'textarea',
|
||||
defaultValue: 'Title'
|
||||
defaultValue: 'Label'
|
||||
}
|
||||
},
|
||||
card: false
|
||||
@@ -38,17 +38,53 @@ const inputs: ComponentSet = {
|
||||
...defaultAlignement,
|
||||
id: 'checkboxcomponent',
|
||||
type: 'checkboxcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
visible: true,
|
||||
value: 'Lorem ipsum',
|
||||
value: 'Label',
|
||||
fieldType: 'textarea',
|
||||
defaultValue: 'Lorem ipsum'
|
||||
defaultValue: 'Label'
|
||||
}
|
||||
},
|
||||
componentInput: undefined,
|
||||
card: false
|
||||
},
|
||||
{
|
||||
...defaultAlignement,
|
||||
id: 'selectcomponent',
|
||||
type: 'selectcomponent',
|
||||
componentInput: undefined,
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
visible: false,
|
||||
value: 'Label',
|
||||
fieldType: 'textarea',
|
||||
defaultValue: 'Label'
|
||||
},
|
||||
items: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
defaultValue: [
|
||||
{ value: 'foo', label: 'Foo' },
|
||||
{ value: 'bar', label: 'Bar' }
|
||||
],
|
||||
value: [
|
||||
{ value: 'foo', label: 'Foo' },
|
||||
{ value: 'bar', label: 'Bar' }
|
||||
]
|
||||
},
|
||||
itemKey: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
defaultValue: 'value',
|
||||
value: 'value'
|
||||
}
|
||||
},
|
||||
card: false,
|
||||
softWrap: true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -138,7 +174,7 @@ const buttons: ComponentSet = {
|
||||
}
|
||||
|
||||
const dataDisplay: ComponentSet = {
|
||||
title: 'Data Display',
|
||||
title: 'Data Displays',
|
||||
components: [
|
||||
{
|
||||
...defaultAlignement,
|
||||
|
||||
@@ -53,6 +53,12 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
componentInput: AppInput | undefined
|
||||
configuration: Record<string, StaticAppInput | ConnectedAppInput | UserAppInput>
|
||||
card: boolean | undefined
|
||||
/**
|
||||
* If `true` then the wrapper will allow items to flow outside of it's borders.
|
||||
*
|
||||
* *For example when the component has a popup like `Select`*
|
||||
*/
|
||||
softWrap?: boolean
|
||||
// TODO: add min/max width/height
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user