Edit component pane improvements
This commit is contained in:
parent
3bcef7f668
commit
0d7d9f471e
|
@ -26,6 +26,10 @@ import {writable} from "svelte/store";
|
|||
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
|
||||
import api from "./api";
|
||||
import { isRootComponent } from "../userInterface/pagesParsing/searchComponents";
|
||||
import {
|
||||
getComponentInfo,
|
||||
getNewComponentInfo
|
||||
} from "../userInterface/pagesParsing/createProps";
|
||||
|
||||
export const getStore = () => {
|
||||
|
||||
|
@ -40,6 +44,8 @@ export const getStore = () => {
|
|||
unauthenticatedUi:{},
|
||||
allComponents:[],
|
||||
currentFrontEndItem:null,
|
||||
currentComponentInfo:null,
|
||||
currentComponentIsNew:false,
|
||||
currentNodeIsNew: false,
|
||||
errors: [],
|
||||
activeNav: "database",
|
||||
|
@ -75,6 +81,7 @@ export const getStore = () => {
|
|||
store.deleteDerivedComponent = deleteDerivedComponent(store);
|
||||
store.setCurrentComponent = setCurrentComponent(store);
|
||||
store.setCurrentPage = setCurrentPage(store);
|
||||
store.createDerivedComponent = createDerivedComponent(store);
|
||||
return store;
|
||||
}
|
||||
|
||||
|
@ -384,6 +391,18 @@ const saveDerivedComponent = store => (derivedComponent) => {
|
|||
})
|
||||
};
|
||||
|
||||
const createDerivedComponent = store => (componentName) => {
|
||||
store.update(s => {
|
||||
const newComponentInfo = getNewComponentInfo(
|
||||
s.allComponents, componentName);
|
||||
|
||||
s.currentFrontEndItem = newComponentInfo.component;
|
||||
s.currentComponentInfo = newComponentInfo;
|
||||
s.currentComponentIsNew = true;
|
||||
return s;
|
||||
});
|
||||
}
|
||||
|
||||
const deleteDerivedComponent = store => name => {
|
||||
store.update(s => {
|
||||
|
||||
|
@ -392,6 +411,9 @@ const deleteDerivedComponent = store => name => {
|
|||
]);
|
||||
|
||||
s.allComponents = allComponents;
|
||||
if(s.currentFrontEndItem.name === name) {
|
||||
s.currentFrontEndItem = null;
|
||||
}
|
||||
|
||||
api.delete(`/_builder/api/${s.appname}/derivedcomponent/${name}`);
|
||||
|
||||
|
@ -502,6 +524,8 @@ const setCurrentComponent = store => component => {
|
|||
store.update(s => {
|
||||
s.currentFrontEndItem = component;
|
||||
s.currentFrontEndIsComponent = true;
|
||||
s.currentComponentIsNew = false;
|
||||
s.currentComponentInfo = getComponentInfo(s.allComponents, component.name);
|
||||
return s;
|
||||
})
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ const addAttributes = (node, attributes) => {
|
|||
|
||||
</script>
|
||||
|
||||
<button style="{style} color:{color}"
|
||||
<button style="{style} color:{color} --hovercolor:{hoverColor}"
|
||||
on:click
|
||||
use:addAttributes={attributes}>
|
||||
{@html getIcon(icon, size)}
|
||||
|
@ -53,6 +53,15 @@ button {
|
|||
border-style: none;
|
||||
background-color: rgba(0,0,0,0);
|
||||
cursor: pointer;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
color: var(--hovercolor);
|
||||
}
|
||||
|
||||
button:active {
|
||||
outline:none;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,136 @@
|
|||
<script>
|
||||
import {
|
||||
last
|
||||
} from "lodash/fp";
|
||||
import IconButton from "../common/IconButton.svelte";
|
||||
import ComponentSearch from "./ComponentSearch.svelte";
|
||||
import Button from "../common/Button.svelte";
|
||||
import ButtonGroup from "../common/ButtonGroup.svelte";
|
||||
import UIkit from "uikit";
|
||||
import {
|
||||
getComponentInfo
|
||||
} from "./pagesParsing/createProps";
|
||||
import { store } from "../builderStore";
|
||||
|
||||
const emptyProps = () => ({_component:""})
|
||||
|
||||
export let props = emptyProps();
|
||||
export let onValueChanged = () => {};
|
||||
export let label = ""
|
||||
export let disabled = false;
|
||||
|
||||
const CHOOSE_COMPONENT = "choose_component";
|
||||
const CLEAR_COMPONENT = "clear_component";
|
||||
|
||||
let allComponents;
|
||||
let modalElement;
|
||||
let modalAction;
|
||||
|
||||
store.subscribe(s => {
|
||||
allComponents = s.allComponents;
|
||||
});
|
||||
|
||||
$: componentSelected = props._component.length > 0;
|
||||
$: shortName = last(props._component.split("/"));
|
||||
|
||||
const chooseComponent = () => {
|
||||
modalAction = CHOOSE_COMPONENT;
|
||||
showDialog();
|
||||
}
|
||||
|
||||
const clearComponent = () => {
|
||||
modalAction = CLEAR_COMPONENT;
|
||||
showDialog();
|
||||
}
|
||||
|
||||
const onComponentChosen = (component) => {
|
||||
const componentInfo = getComponentInfo(allComponents, component.name);
|
||||
props = componentInfo.fullProps;
|
||||
onValueChanged(props);
|
||||
hideDialog();
|
||||
}
|
||||
|
||||
const hideDialog = () => {
|
||||
UIkit.modal(modalElement).hide();
|
||||
}
|
||||
|
||||
const showDialog = () => {
|
||||
UIkit.modal(modalElement).show();
|
||||
}
|
||||
|
||||
const confirmClearComponent = () => {
|
||||
props = emptyProps();
|
||||
onValueChanged(emptyProps());
|
||||
hideDialog();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<label class="uk-form-label">{label}</label>
|
||||
<div class="root uk-form-controls">
|
||||
<div class:selectedname={componentSelected}>
|
||||
{componentSelected ? shortName : "(none)"}
|
||||
</div>
|
||||
<div>
|
||||
{#if !disabled && componentSelected}
|
||||
<IconButton icon="edit" />
|
||||
|
||||
<IconButton icon="trash"
|
||||
on:click={clearComponent} />
|
||||
{:else if !disabled && !componentSelected}
|
||||
<IconButton icon="plus"
|
||||
on:click={chooseComponent} />
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div bind:this={modalElement} uk-modal>
|
||||
<div class="uk-modal-dialog">
|
||||
|
||||
{#if modalAction === CHOOSE_COMPONENT}
|
||||
<div class="uk-modal-body">
|
||||
<ComponentSearch {onComponentChosen} />
|
||||
</div>
|
||||
{:else if modalAction === CLEAR_COMPONENT}
|
||||
<div class="uk-modal-body">
|
||||
Clear this component ?
|
||||
</div>
|
||||
<div class="uk-modal-footer">
|
||||
<ButtonGroup>
|
||||
<Button grouped
|
||||
on:click={hideDialog}
|
||||
color="secondary" >Cancel</Button>
|
||||
<Button grouped
|
||||
on:click={confirmClearComponent}>OK</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.root {
|
||||
display: grid;
|
||||
grid-template-columns: [name] 1fr [actions] auto;
|
||||
}
|
||||
|
||||
.root > div:nth-child(1) {
|
||||
grid-column-start: name;
|
||||
color: var(--secondary50);
|
||||
}
|
||||
|
||||
.root > div:nth-child(2) {
|
||||
grid-column-start: actions;
|
||||
}
|
||||
|
||||
.selectedname {
|
||||
font-weight: bold;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,12 +1,17 @@
|
|||
<script>
|
||||
|
||||
import { searchAllComponents } from "./pagesParsing/searchComponents";
|
||||
import { store } from "../builderStore";
|
||||
|
||||
export let allComponents = [];
|
||||
export let onComponentChosen = () => {};
|
||||
|
||||
let allComponents = [];
|
||||
let phrase = "";
|
||||
|
||||
store.subscribe(s => {
|
||||
allComponents = s.allComponents;
|
||||
});
|
||||
|
||||
$: filteredComponents =
|
||||
!phrase
|
||||
? []
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
<script>
|
||||
|
||||
import PropsView from "./PropsView.svelte";
|
||||
import { store } from "../builderStore";
|
||||
import { isRootComponent } from "./pagesParsing/searchComponents";
|
||||
import IconButton from "../common/IconButton.svelte";
|
||||
import Textbox from "../common/Textbox.svelte";
|
||||
import UIkit from "uikit";
|
||||
import { pipe } from "../common/core";
|
||||
import {
|
||||
getComponentInfo
|
||||
} from "./pagesParsing/createProps";
|
||||
import Button from "../common/Button.svelte";
|
||||
import ButtonGroup from "../common/ButtonGroup.svelte";
|
||||
|
||||
import {
|
||||
cloneDeep,
|
||||
join,
|
||||
split,
|
||||
map,
|
||||
keys,
|
||||
isUndefined,
|
||||
last
|
||||
} from "lodash/fp";
|
||||
import { assign } from "lodash";
|
||||
|
||||
let component;
|
||||
let name = "";
|
||||
let description = "";
|
||||
let tagsString = "";
|
||||
let nameInvalid = "";
|
||||
let componentDetailsExpanded = false;
|
||||
let componentInfo;
|
||||
let modalElement
|
||||
let propsValidationErrors = [];
|
||||
$: shortName = last(name.split("/"));
|
||||
|
||||
store.subscribe(s => {
|
||||
component = s.currentFrontEndItem;
|
||||
if(!component) return;
|
||||
name = component.name;
|
||||
description = component.description;
|
||||
tagsString = join(", ")(component.tags);
|
||||
componentInfo = s.currentComponentInfo;
|
||||
componentDetailsExpanded = s.currentComponentIsNew;
|
||||
});
|
||||
|
||||
const save = () => {
|
||||
|
||||
if(!validate()) return;
|
||||
|
||||
component.name = name;
|
||||
component.description = description;
|
||||
component.tags = pipe(tagsString, [
|
||||
split(","),
|
||||
map(s => s.trim())
|
||||
]);
|
||||
|
||||
store.saveDerivedComponent(component);
|
||||
}
|
||||
|
||||
const deleteComponent = () => {
|
||||
showDialog();
|
||||
}
|
||||
|
||||
const confirmDeleteComponent = () => {
|
||||
store.deleteDerivedComponent(component.name);
|
||||
hideDialog();
|
||||
}
|
||||
|
||||
const onPropsValidate = result => {
|
||||
propsValidationErrors = result;
|
||||
}
|
||||
|
||||
const onPropsChanged = props => {
|
||||
assign(component.props, props);
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const fieldInvalid = (field, err) =>
|
||||
errors[field] = err;
|
||||
const fieldValid = field =>
|
||||
errors[field] && delete errors[field];
|
||||
|
||||
if(!name) nameInvalid = "component name i not supplied";
|
||||
else nameInvalid = "";
|
||||
|
||||
return (!nameInvalid && propsValidationErrors.length === 0);
|
||||
}
|
||||
|
||||
const hideDialog = () => {
|
||||
UIkit.modal(modalElement).hide();
|
||||
}
|
||||
|
||||
const showDialog = () => {
|
||||
UIkit.modal(modalElement).show();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
||||
<div class="title">
|
||||
<div>{shortName}</div>
|
||||
<div>
|
||||
<IconButton icon="save"
|
||||
on:click={save}
|
||||
color="var(--primary100)"
|
||||
hoverColor="red"/>
|
||||
<IconButton icon="trash"
|
||||
on:click={deleteComponent}
|
||||
color="var(--primary100)"
|
||||
hoverColor="red"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
|
||||
<div class="section-header" on:click={() => componentDetailsExpanded = !componentDetailsExpanded}>
|
||||
<span style="margin-right: 7px">Component Details</span>
|
||||
<IconButton icon={componentDetailsExpanded ? "chevron-down" : "chevron-right"}/>
|
||||
</div>
|
||||
|
||||
{#if componentDetailsExpanded}
|
||||
<div>
|
||||
<Textbox label="Name"
|
||||
infoText="use forward slash to store in subfolders"
|
||||
bind:text={name}
|
||||
hasError={!!nameInvalid}/>
|
||||
<div class="info-text"></div>
|
||||
<Textbox label="Description"
|
||||
bind:text={description}/>
|
||||
<Textbox label="Tags"
|
||||
infoText="comma separated"
|
||||
bind:text={tagsString}/>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<p class="section-header"><span>Properties</span></p>
|
||||
|
||||
|
||||
<PropsView onValidate={onPropsValidate}
|
||||
{componentInfo}
|
||||
{onPropsChanged}/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div bind:this={modalElement} uk-modal>
|
||||
<div class="uk-modal-dialog">
|
||||
|
||||
<div class="uk-modal-header">
|
||||
Delete {component.name} ?
|
||||
</div>
|
||||
|
||||
<div class="uk-modal-body">
|
||||
Are you sure you want to delete this component ?
|
||||
</div>
|
||||
|
||||
<div class="uk-modal-footer">
|
||||
<ButtonGroup>
|
||||
<Button grouped
|
||||
on:click={confirmDeleteComponent}>
|
||||
OK
|
||||
</Button>
|
||||
<Button grouped
|
||||
on:click={hideDialog}
|
||||
color="secondary" >
|
||||
Cancel
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.root {
|
||||
height: 100%;
|
||||
border-style: solid;
|
||||
border-color: var(--lightslate);
|
||||
border-width: 0px 0px 0px 1px;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.title {
|
||||
background-color: white;
|
||||
padding: 3px;
|
||||
display: grid;
|
||||
grid-template-columns: [name] 1fr [actions] auto;
|
||||
}
|
||||
|
||||
.title > div:nth-child(1) {
|
||||
grid-column-start: name;
|
||||
color: var(--secondary100);
|
||||
}
|
||||
|
||||
.title > div:nth-child(2) {
|
||||
grid-column-start: actions;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
font-style: italic;
|
||||
color: var(--slate);
|
||||
border-style: solid;
|
||||
border-color: var(--lightslate);
|
||||
border-width: 0px 0px 1px 0px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -23,66 +23,26 @@ import {
|
|||
} from "lodash/fp";
|
||||
import { assign } from "lodash";
|
||||
|
||||
let component;
|
||||
|
||||
|
||||
let modalElement;
|
||||
let errors = {};
|
||||
let componentInfo;
|
||||
let allComponents;
|
||||
|
||||
let name = "";
|
||||
let description = "";
|
||||
let tagsString = "";
|
||||
let propsValidationErrors = [];
|
||||
let inheritedProps;
|
||||
let nameInvalid = "";
|
||||
let propsDefinition;
|
||||
store.subscribe(s => {
|
||||
allComponents = s.allComponents;
|
||||
})
|
||||
|
||||
const onBasedOnChosen = (allComponents) => (c) => {
|
||||
componentInfo = getNewComponentInfo(allComponents, c.name);
|
||||
tagsString = join(", ")(componentInfo.component.tags);
|
||||
inheritedProps = componentInfo.inheritedProps;
|
||||
propsDefinition = componentInfo.propsDefinition;
|
||||
component = componentInfo.component;
|
||||
}
|
||||
|
||||
const createComponent = () => {
|
||||
|
||||
if(!validate()) return;
|
||||
|
||||
component.name = name;
|
||||
component.description = description;
|
||||
component.tags = pipe(tagsString, [
|
||||
split(","),
|
||||
map(s => s.trim())
|
||||
]);
|
||||
|
||||
store.saveDerivedComponent(component);
|
||||
close();
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
component = null;
|
||||
componentInfo = null;
|
||||
export const close = () => {
|
||||
UIkit.modal(modalElement).hide();
|
||||
}
|
||||
|
||||
const onPropsValidate = result => {
|
||||
propsValidationErrors = result;
|
||||
export const show = () => {
|
||||
UIkit.modal(modalElement).show();
|
||||
}
|
||||
|
||||
const onPropsChanged = props => {
|
||||
assign(component.props, props);
|
||||
}
|
||||
|
||||
const validate = () => {
|
||||
const fieldInvalid = (field, err) =>
|
||||
errors[field] = err;
|
||||
const fieldValid = field =>
|
||||
errors[field] && delete errors[field];
|
||||
|
||||
if(!name) nameInvalid = "component name i not supplied";
|
||||
else nameInvalid = "";
|
||||
|
||||
return (!nameInvalid && propsValidationErrors.length === 0);
|
||||
const onComponentChosen = (c) => {
|
||||
store.createDerivedComponent(c.name);
|
||||
close();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -95,49 +55,8 @@ const validate = () => {
|
|||
</div>
|
||||
|
||||
<div class="uk-modal-body">
|
||||
<form class="uk-form-horizontal">
|
||||
{#if componentInfo}
|
||||
|
||||
<Textbox label="Name"
|
||||
infoText="use forward slash to store in subfolders"
|
||||
bind:text={name}
|
||||
hasError={!!nameInvalid}/>
|
||||
<div class="info-text"></div>
|
||||
<Textbox label="Description"
|
||||
bind:text={description}/>
|
||||
<Textbox label="Tags"
|
||||
infoText="comma separated"
|
||||
bind:text={tagsString}/>
|
||||
<p class="uk-heading-line props-header"><span>Properties</span></p>
|
||||
<PropsView allComponents={$store.allComponents}
|
||||
onValidate={onPropsValidate}
|
||||
showTitle={false}
|
||||
{componentInfo}
|
||||
{onPropsChanged} />
|
||||
|
||||
|
||||
{:else}
|
||||
|
||||
|
||||
<ComponentSearch allComponents={$store.allComponents}
|
||||
onComponentChosen={onBasedOnChosen($store.allComponents)} />
|
||||
|
||||
|
||||
{/if}
|
||||
</form>
|
||||
<ComponentSearch onComponentChosen={onComponentChosen} />
|
||||
</div>
|
||||
{#if component}
|
||||
<div class="uk-modal-footer">
|
||||
<ButtonGroup>
|
||||
<Button grouped
|
||||
on:click={close}
|
||||
color="secondary" >Cancel</Button>
|
||||
<Button grouped
|
||||
on:click={createComponent}>Create Component</Button>
|
||||
</ButtonGroup>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -146,8 +65,4 @@ h1 {
|
|||
font-size:1.2em;
|
||||
}
|
||||
|
||||
.props-header {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,54 @@
|
|||
<script>
|
||||
|
||||
import Checkbox from "../common/Checkbox.svelte";
|
||||
import Textbox from "../common/Textbox.svelte";
|
||||
import Dropdown from "../common/Dropdown.svelte";
|
||||
import ComponentPropSelector from "./ComponentPropSelector.svelte";
|
||||
|
||||
export let errors = [];
|
||||
export let setProp = () => {};
|
||||
export let fieldHasError =() => {};
|
||||
export let propDef = {};
|
||||
export let props = {};
|
||||
export let disabled;
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<div class="root">
|
||||
|
||||
|
||||
{#if propDef.type === "bool"}
|
||||
<Checkbox label={propDef.____name}
|
||||
checked={props[propDef.____name]}
|
||||
on:change={ev => setProp(propDef.____name, ev.target.checked)}
|
||||
hasError={fieldHasError(propDef.____name)} />
|
||||
{:else if propDef.type === "options"}
|
||||
<Dropdown label={propDef.____name}
|
||||
selected={props[propDef.____name]}
|
||||
options={propDef.options}
|
||||
on:change={ev => setProp(propDef.____name, ev.target.value)}
|
||||
hasError={fieldHasError(propDef.____name)}/>
|
||||
{:else if propDef.type === "component"}
|
||||
<ComponentPropSelector label={propDef.____name}
|
||||
props={props[propDef.____name]}
|
||||
{disabled}
|
||||
onValueChanged={props => setProp(propDef.____name, props)}/>
|
||||
{:else}
|
||||
<Textbox label={propDef.____name}
|
||||
text={props[propDef.____name]}
|
||||
on:change={ev => setProp(propDef.____name, ev.target.value)}
|
||||
margin={false}
|
||||
hasError={fieldHasError(propDef.____name)}
|
||||
{disabled}/>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.root {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -6,58 +6,66 @@ import {
|
|||
some,
|
||||
includes,
|
||||
cloneDeep,
|
||||
isEqual
|
||||
isEqual,
|
||||
sortBy,
|
||||
filter
|
||||
} from "lodash/fp";
|
||||
import { pipe } from "../common/core";
|
||||
import { getComponentInfo } from "./pagesParsing/createProps";
|
||||
import {
|
||||
getComponentInfo ,
|
||||
getInstanceProps
|
||||
} from "./pagesParsing/createProps";
|
||||
import { getExactComponent } from "./pagesParsing/searchComponents";
|
||||
import Checkbox from "../common/Checkbox.svelte";
|
||||
import Textbox from "../common/Textbox.svelte";
|
||||
import Dropdown from "../common/Dropdown.svelte";
|
||||
import { validateProps } from "./pagesParsing/validateProps";
|
||||
import ComponentPropSelector from "./ComponentPropSelector.svelte";
|
||||
import PropControl from "./PropControl.svelte";
|
||||
import IconButton from "../common/IconButton.svelte";
|
||||
|
||||
export let allComponents;
|
||||
export let shouldValidate = true;
|
||||
export let onValidate = () => {};
|
||||
export let showTitle = true;
|
||||
export let componentInfo;
|
||||
export let component;
|
||||
export let instanceProps = null;
|
||||
export let onPropsChanged = () => {};
|
||||
|
||||
let errors = [];
|
||||
let fields = [];
|
||||
let props = {};
|
||||
let propsDefinitionArray = [];
|
||||
|
||||
$: {
|
||||
if(componentInfo || component)
|
||||
{
|
||||
if(!componentInfo || (component &&
|
||||
component.name !== componentInfo.component.name)) {
|
||||
componentInfo = getComponentInfo(allComponents, component.name);
|
||||
}
|
||||
|
||||
props = cloneDeep(componentInfo.fullProps);
|
||||
|
||||
propsDefinitionArray = pipe(componentInfo.propsDefinition, [
|
||||
keys,
|
||||
map(k => ({...componentInfo.propsDefinition[k], ____name:k}))
|
||||
]);
|
||||
|
||||
fields = pipe(componentInfo.propsDefinition,[
|
||||
keys,
|
||||
map(k => componentInfo.propsDefinition[k])
|
||||
]);
|
||||
}
|
||||
}
|
||||
let propsDefinitions = [];
|
||||
let inheritedPropsDefinitions = [];
|
||||
let inheritedExpanded = false;
|
||||
|
||||
const isPropInherited = name =>
|
||||
includes(name)(componentInfo.inheritedProps);
|
||||
|
||||
let setProp = (name) => (ev, targetValue="value") => {
|
||||
$: {
|
||||
if(componentInfo)
|
||||
{
|
||||
props = instanceProps
|
||||
? getInstanceProps(componentInfo, instanceProps)
|
||||
: cloneDeep(componentInfo.fullProps);
|
||||
|
||||
propsDefinitions = pipe(componentInfo.propsDefinition, [
|
||||
keys,
|
||||
filter(k => !isPropInherited(k)),
|
||||
map(k => ({...componentInfo.propsDefinition[k], ____name:k})),
|
||||
sortBy("____name")
|
||||
]);
|
||||
|
||||
inheritedPropsDefinitions = pipe(componentInfo.propsDefinition, [
|
||||
keys,
|
||||
filter(k => isPropInherited(k)),
|
||||
map(k => ({...componentInfo.propsDefinition[k], ____name:k})),
|
||||
sortBy("____name")
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let setProp = (name, value) => {
|
||||
const newProps = cloneDeep(props);
|
||||
newProps[name] = ev.target[targetValue];
|
||||
|
||||
newProps[name] = value;
|
||||
|
||||
const finalProps = {};
|
||||
|
||||
|
@ -82,37 +90,48 @@ const validate = (finalProps) => {
|
|||
const fieldHasError = (propName) =>
|
||||
some(e => e.propName === propName)(errors);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
||||
{#if showTitle=true}
|
||||
<div class="title">{componentInfo.component.name}</div>
|
||||
<div class="component-description">{componentInfo.component.description || ""}</div>
|
||||
{/if}
|
||||
{#each propsDefinitionArray as propDef}
|
||||
<form class="uk-form-stacked prop-row ">
|
||||
{#if propDef.type === "bool"}
|
||||
<Checkbox label={propDef.____name}
|
||||
checked={props[propDef.____name]}
|
||||
on:change={setProp(propDef.____name, "checked")}
|
||||
hasError={fieldHasError(propDef.____name)} />
|
||||
{:else if propDef.type === "options"}
|
||||
<Dropdown label={propDef.____name}
|
||||
selected={props[propDef.____name]}
|
||||
options={propDef.options}
|
||||
on:change={setProp(propDef.____name)}
|
||||
hasError={fieldHasError(propDef.____name)}/>
|
||||
{:else}
|
||||
<Textbox label={propDef.____name}
|
||||
text={props[propDef.____name]}
|
||||
on:change={setProp(propDef.____name)}
|
||||
margin={false}
|
||||
hasError={fieldHasError(propDef.____name)}
|
||||
disabled={isPropInherited(propDef.____name)} />
|
||||
{/if}
|
||||
<form class="uk-form-stacked">
|
||||
{#each propsDefinitions as propDef}
|
||||
|
||||
<PropControl {errors}
|
||||
{setProp}
|
||||
{fieldHasError}
|
||||
{propDef}
|
||||
{props}
|
||||
disabled={false} />
|
||||
|
||||
{/each}
|
||||
|
||||
{#if inheritedPropsDefinitions.length > 0}
|
||||
<div class="inherited-title">
|
||||
<div>Inherited</div>
|
||||
<div>
|
||||
<IconButton icon={inheritedExpanded ? "chevron-down" : "chevron-right"}
|
||||
on:click={() => inheritedExpanded = !inheritedExpanded}/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if inheritedExpanded}
|
||||
{#each inheritedPropsDefinitions as propDef}
|
||||
|
||||
<PropControl {errors}
|
||||
{setProp}
|
||||
{fieldHasError}
|
||||
{propDef}
|
||||
{props}
|
||||
disabled={true} />
|
||||
|
||||
{/each}
|
||||
{/if}
|
||||
</form>
|
||||
{/each}
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -124,19 +143,24 @@ const fieldHasError = (propName) =>
|
|||
font-size:10pt;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
.inherited-title {
|
||||
margin-top: 40px;
|
||||
display: grid;
|
||||
grid-template-columns: [name] 1fr [actions] auto;
|
||||
border-style: solid;
|
||||
border-width: 0px 0px 1px 0px;
|
||||
border-color: var(--lightslate);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.prop-row {
|
||||
padding: 7px 3px;
|
||||
}
|
||||
|
||||
.component-description {
|
||||
font-size: 0.9em;
|
||||
.inherited-title > div:nth-child(1) {
|
||||
grid-column-start: name;
|
||||
color: var(--slate);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.inherited-title > div:nth-child(2) {
|
||||
grid-column-start: actions;
|
||||
color: var(--secondary100);
|
||||
}
|
||||
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import ComponentsHierarchy from "./ComponentsHierarchy.svelte";
|
||||
import PagesList from "./PagesList.svelte"
|
||||
import PropsView from "./PropsView.svelte";
|
||||
import EditComponent from "./EditComponent.svelte";
|
||||
import { store } from "../builderStore";
|
||||
import getIcon from "../common/icon";
|
||||
import { isRootComponent } from "./pagesParsing/searchComponents";
|
||||
|
@ -10,9 +10,9 @@ import IconButton from "../common/IconButton.svelte";
|
|||
import Modal from "../common/Modal.svelte";
|
||||
import NewComponent from "./NewComponent.svelte";
|
||||
|
||||
let isCreatingNewComponent = false;
|
||||
let newComponentPicker;
|
||||
const newComponent = () => {
|
||||
isCreatingNewComponent = true;
|
||||
newComponentPicker.show();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -27,8 +27,7 @@ const newComponent = () => {
|
|||
<span>COMPONENTS</span>
|
||||
<div>
|
||||
<IconButton icon="plus"
|
||||
on:click={newComponent}
|
||||
attributes={{"uk-toggle" : "target: #new-component-modal" }}/>
|
||||
on:click={newComponent}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-items-container">
|
||||
|
@ -58,15 +57,14 @@ const newComponent = () => {
|
|||
|
||||
<div class="properties-pane">
|
||||
{#if $store.currentFrontEndItem && !isRootComponent($store.currentFrontEndItem)}
|
||||
<PropsView allComponents={$store.allComponents}
|
||||
component={$store.currentFrontEndItem}/>
|
||||
<EditComponent />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<NewComponent bind:isCreatingNewComponent={isCreatingNewComponent}/>
|
||||
<NewComponent bind:this={newComponentPicker}/>
|
||||
|
||||
|
||||
<style>
|
||||
|
@ -100,7 +98,6 @@ const newComponent = () => {
|
|||
grid-column-start: properties;
|
||||
background-color: var(--primary10);
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.pages-list-container {
|
||||
|
|
|
@ -39,7 +39,7 @@ export const createPropDefinitionForDerived = (allComponents, componentName) =>
|
|||
|
||||
export const traverseForProps = getComponentInfo;
|
||||
|
||||
export const getFinalProps = (componentInfo, props) => {
|
||||
export const getInstanceProps = (componentInfo, props) => {
|
||||
const finalProps = cloneDeep(componentInfo.fullProps);
|
||||
|
||||
for(let p in props) {
|
||||
|
@ -89,7 +89,7 @@ export const getComponentInfo = (allComponents, cname, stack=[], subComponentPro
|
|||
]);
|
||||
|
||||
return ({
|
||||
propsDefinition:component.props,
|
||||
propsDefinition:expandPropsDefinition(component.props),
|
||||
inheritedProps,
|
||||
rootDefaultProps: p.props,
|
||||
unsetProps,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {
|
||||
getFinalProps,
|
||||
getInstanceProps,
|
||||
getComponentInfo
|
||||
} from "../src/userInterface/pagesParsing/createProps";
|
||||
import {
|
||||
|
@ -34,8 +34,8 @@ describe("getComponentInfo", () => {
|
|||
|
||||
});
|
||||
|
||||
it("getFinalProps should set supplied props on top of default props", () => {
|
||||
const result = getFinalProps(
|
||||
it("getInstanceProps should set supplied props on top of default props", () => {
|
||||
const result = getInstanceProps(
|
||||
getComponentInfo(
|
||||
allComponents(),
|
||||
"budibase-components/TextBox"),
|
||||
|
|
Loading…
Reference in New Issue