1
0
Fork 0
mirror of synced 2024-06-03 02:55:14 +12:00

builder ui changes - UI builder in progress

This commit is contained in:
michael shanks 2019-08-07 09:03:49 +01:00
parent ca63769204
commit 21224b119b
33 changed files with 2666 additions and 1003 deletions

View file

@ -1,4 +1,4 @@
{
module.exports = ({
"presets": ["@babel/preset-env"],
"sourceMaps": "inline",
"retainLines": true,
@ -9,4 +9,4 @@
}
]
]
}
});

View file

@ -25,7 +25,7 @@
"node_modules"
],
"transform": {
"^.+\\.js$": "babel-jest"
"^.+js$": "babel-jest"
},
"transformIgnorePatterns": [
"/node_modules/(?!svelte).+\\.js$"
@ -41,7 +41,7 @@
"safe-buffer": "^5.1.2",
"shortid": "^2.2.8",
"string_decoder": "^1.2.0",
"uikit": "^3.1.5"
"uikit": "^3.1.7"
},
"devDependencies": {
"@babel/core": "^7.5.5",

View file

@ -34,7 +34,7 @@ const production = !process.env.ROLLUP_WATCH;
const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant",
"take", "first", "intersection", "mapValues", "isNull", "has", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy",
"keys", "orderBy", "concat", "reverse", "difference", "merge", "flatten", "each", "pull", "join", "defaultCase", "uniqBy", "every", "uniqWith", "isFunction", "groupBy",
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart"];
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike"];
const lodash_exports = ["toNumber", "flow", "isArray", "join", "replace", "trim", "dropRight", "takeRight", "head", "isUndefined", "isNull", "isNaN", "reduce", "isEmpty",
"constant", "tail", "includes", "startsWith", "findIndex", "isInteger", "isDate", "isString", "split", "clone", "keys", "isFunction", "merge", "has", "isBoolean", "isNumber",

View file

@ -72,16 +72,19 @@ const permissionChanged = perm => ev => {
<ErrorsBox {errors} />
<Textbox label="Name" bind:text={clonedLevel.name} />
<form class="uk-form-horizontal">
{#each permissionMatrix as permission}
<div>
<Checkbox label={getPermissionName(permission.permission)}
checked={permission.hasPermission}
on:change={permissionChanged(permission.permission)} />
</div>
{/each}
<Textbox label="Name" bind:text={clonedLevel.name} />
{#each permissionMatrix as permission}
<div>
<Checkbox label={getPermissionName(permission.permission)}
checked={permission.hasPermission}
on:change={permissionChanged(permission.permission)} />
</div>
{/each}
</form>
<ButtonGroup style="margin-top: 10px">
<Button color="primary" grouped on:click={save}>Save</Button>

View file

@ -70,10 +70,13 @@ const cancel = () => {
<ErrorsBox {errors} />
<Textbox label="Name" bind:text={clonedAction.name} />
<Textbox label="Behaviour Source" bind:text={clonedAction.behaviourSource} />
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} />
<form class="uk-form-horizontal">
<Textbox label="Name" bind:text={clonedAction.name} />
<Textbox label="Behaviour Source" bind:text={clonedAction.behaviourSource} />
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} />
</form>
<div class=" uk-form-stacked" style="margin-bottom: 20px">
<label class="uk-form-label">Default Options</label>

View file

@ -40,17 +40,21 @@ let save = () => {
<div>
<ErrorsBox {errors} style="margin-bottom:20px"/>
<form class="uk-form-horizontal">
<Dropdown label="Event"
options={["",...events]}
bind:selected={clonedTrigger.eventName} />
<Dropdown label="Action"
options={["",...actionNames]}
bind:selected={clonedTrigger.actionName} />
<CodeArea label="Condition (javascript)"
bind:text={clonedTrigger.condition} />
<CodeArea label="Action Options Creator (javascript)"
bind:text={clonedTrigger.optionsCreator} />
<Dropdown label="Event"
options={["",...events]}
bind:selected={clonedTrigger.eventName} />
<Dropdown label="Action"
options={["",...actionNames]}
bind:selected={clonedTrigger.actionName} />
<CodeArea label="Condition (javascript)"
bind:text={clonedTrigger.condition} />
<CodeArea label="Action Options Creator (javascript)"
bind:text={clonedTrigger.optionsCreator} />
</form>
<ButtonGroup>
<Button grouped on:click={save}>Save</Button>

View file

@ -5,7 +5,7 @@ export let label = "";
</script>
<div>{label}</div>
<textarea bind:value={text}></textarea>
<textarea class="uk-textarea" bind:value={text}></textarea>
<style>

View file

@ -6,6 +6,9 @@ import { onMount } from 'svelte';
export let value;
export let label;
export let width = "medium";
export let size = "small";
let input;
let fpInstance;
@ -22,40 +25,12 @@ onMount(() => {
return fpInstance;
})
</script>
<div class="container" >
<div class="label">{label}</div>
<input class="control" bind:this={input} />
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input uk-form-width-{width} uk-form-{size}" bind:this={input} >
</div>
</div>
<style>
.container {
display: grid;
grid-template-columns: [label] 100px [control] auto;
margin: 20px 0px;
}
.label {
grid-column-start: label;
align-self: center;
}
.control {
grid-column-start: control;
align-self: center;
margin: 0;
}
input {
width:300px;
}
</style>

View file

@ -7,53 +7,33 @@ export let options;
export let valueMember;
export let textMember;
export let multiple=false;
export let width = "medium";
export let size = "small";
const dispatch =createEventDispatcher();
</script>
<div class="container">
<div class="label">{label}</div>
{#if multiple}
<select class="control uk-select" multiple bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
{#if multiple}
<select class="uk-select uk-form-width-{width} uk-form-{size}" multiple bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
{:else}
<select class="control uk-select" bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
{/if}
{:else}
<select class="uk-select uk-form-width-{width} uk-form-{size}" bind:value={selected} on:change>
{#each options as option}
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option>
{/each}
</select>
{/if}
</div>
</div>
<style>
.container {
display: grid;
grid-template-columns: [label] 100px [control] auto;
margin: 20px 0px;
}
.label {
grid-column-start: label;
align-self: center;
}
.control {
grid-column-start: control;
align-self: center;
margin: 0;
}
select {
width:300px;
}
</style>

View file

@ -0,0 +1,30 @@
<script>
import getIcon from "./icon";
export let size = 18;
export let icon = "";
export let style = "";
export let color = "";
export let hoverColor = "";
$: borderClass = grouped
? ""
: "border-normal";
</script>
<button style="{style} color:{color}"
on:click>
{@html getIcon(icon, size)}
</button>
<style>
button {
border-style: none;
background-color: rgba(0,0,0,0);
cursor: pointer;
}
</style>

View file

@ -3,6 +3,7 @@ import UIkit from "uikit";
export let isOpen = false;
export let onClosed = () => {};
export let id = "";
let ukModal;
let listenerAdded = false;
@ -24,7 +25,7 @@ $: {
</script>
<div bind:this={ukModal} uk-modal >
<div bind:this={ukModal} uk-modal {id}>
<div class="uk-modal-dialog uk-modal-body" uk-overflow-auto>
<slot />
</div>

View file

@ -17,30 +17,10 @@ let numberText = value === null || value === undefined
</script>
<div class="container">
<div class="label">{label}</div>
<input class="control" type="text" value={value} on:change={inputChanged} >
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input" value={value} on:change={inputChanged} >
</div>
</div>
<style>
.container {
display: grid;
grid-template-columns: [label] 100px [control] auto;
margin: 20px 0px;
}
.label {
grid-column-start: label;
align-self: center;
}
.control {
grid-column-start: control;
align-self: center;
margin: 0;
}
input {
width:300px;
}
</style>

View file

@ -1,32 +1,14 @@
<script>
export let text = "";
export let label = "";
export let width = "medium";
export let size = "small";
</script>
<div class="container">
<div class="label">{label}</div>
<input class="control uk-input" bind:value={text} >
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<input class="uk-input uk-form-width-{width} uk-form-{size}" bind:value={text} >
</div>
</div>
<style>
.container {
display: grid;
grid-template-columns: [label] 100px [control] auto;
margin: 20px 0px;
}
.label {
grid-column-start: label;
align-self: center;
}
.control {
grid-column-start: control;
align-self: center;
margin: 0;
}
input {
width:300px;
}
</style>

View file

@ -17,28 +17,16 @@ $: valuesText = join("\n")(values);
</script>
<div class="container">
<div class="label">{label}</div>
<textarea class="control" value={valuesText} on:change={inputChanged} ></textarea>
<div class="uk-margin">
<label class="uk-form-label">{label}</label>
<div class="uk-form-controls">
<textarea value={valuesText} on:change={inputChanged} ></textarea>
</div>
</div>
<style>
.container {
display: grid;
grid-template-columns: [label] 100px [control] auto;
margin: 20px 0px;
}
.label {
grid-column-start: label;
align-self: center;
}
.control {
grid-column-start: control;
align-self: center;
margin: 0;
}
textarea {
width:300px;
height:200px;

View file

@ -59,49 +59,53 @@ const save = () => {
<ErrorsBox errors={errors} />
<Dropdown label="Type" bind:selected={clonedField.type} options={keys(allTypes)} on:change={typeChanged} />
<form class="uk-form-horizontal">
{#if isNew}
<Textbox label="Field Name" bind:text={clonedField.name} />
{:else}
<div style="font-weight: bold">{clonedField.name}</div>
{/if}
<Dropdown label="Type" bind:selected={clonedField.type} options={keys(allTypes)} on:change={typeChanged} />
<Textbox label="Label" bind:text={clonedField.label} />
{#if clonedField.type === "string"}
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
<ValuesList label="Values (options)" bind:values={clonedField.typeOptions.values} />
<Checkbox label="Declared Values Only" bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} />
{:else if clonedField.type === "bool"}
<Checkbox label="Allow Null" bind:checked={clonedField.typeOptions.allowNulls} />
{:else if clonedField.type === "datetime"}
<DatePicker label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<DatePicker label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
{:else if clonedField.type === "number"}
<NumberBox label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<NumberBox label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
<NumberBox label="Decimal Places" bind:value={clonedField.typeOptions.decimalPlaces} />
{:else if clonedField.type === "reference"}
<Dropdown label="Lookup Index"
options={possibleReferenceIndexes}
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.indexNodeKey} />
{#if isNew}
<Textbox label="Field Name" bind:text={clonedField.name} />
{:else}
<div style="font-weight: bold">{clonedField.name}</div>
{/if}
<Dropdown label="Reverse Reference Index"
options={possibleReverseReferenceIndexes}
multiple=true
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} />
<Textbox label="Label" bind:text={clonedField.label} />
{#if clonedField.type === "string"}
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
<ValuesList label="Values (options)" bind:values={clonedField.typeOptions.values} />
<Checkbox label="Declared Values Only" bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} />
{:else if clonedField.type === "bool"}
<Checkbox label="Allow Null" bind:checked={clonedField.typeOptions.allowNulls} />
{:else if clonedField.type === "datetime"}
<DatePicker label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<DatePicker label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
{:else if clonedField.type === "number"}
<NumberBox label="Min Value" bind:value={clonedField.typeOptions.minValue} />
<NumberBox label="Max Value" bind:value={clonedField.typeOptions.maxValue} />
<NumberBox label="Decimal Places" bind:value={clonedField.typeOptions.decimalPlaces} />
{:else if clonedField.type === "reference"}
<Dropdown label="Lookup Index"
options={possibleReferenceIndexes}
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.indexNodeKey} />
<Textbox label="Display Value" bind:text={clonedField.typeOptions.displayValue} />
<Dropdown label="Reverse Reference Index"
options={possibleReverseReferenceIndexes}
multiple=true
valueMember={n => n.nodeKey()}
textMember={n => n.name}
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} />
{:else if clonedField.type.startsWith("array")}
<NumberBox label="Min Length" bind:value={clonedField.typeOptions.minLength} />
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
{/if}
<Textbox label="Display Value" bind:text={clonedField.typeOptions.displayValue} />
{:else if clonedField.type.startsWith("array")}
<NumberBox label="Min Length" bind:value={clonedField.typeOptions.minLength} />
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} />
{/if}
</form>
<ButtonGroup style="float: right;">
<Button color="primary" grouped on:click={save}>Save</Button>

View file

@ -37,7 +37,7 @@ const toggleAllowedRecord = record => {
</script>
<div class="root">
<form class="uk-form-horizontal root">
<Textbox bind:text={index.name} label="Name"/>
<div class="allowed-records">
@ -56,7 +56,7 @@ const toggleAllowedRecord = record => {
<CodeArea bind:text={index.getShardName} label="Shard Name (javascript expression)"/>
</div>
</form>
<style>

View file

@ -84,13 +84,16 @@ let getTypeOptions = typeOptions =>
<div class="root">
<Textbox label="Name" bind:text={record.name} />
<div>{record.nodeKey()}</div>
{#if !record.isSingle}
<Textbox label="Collection Name" bind:text={record.collectionName} />
<Textbox label="Shard Factor" bind:text={record.allidsShardFactor} />
{/if}
<form class="uk-form-horizontal">
<Textbox label="Name" bind:text={record.name} />
<div>{record.nodeKey()}</div>
{#if !record.isSingle}
<Textbox label="Collection Name" bind:text={record.collectionName} />
<Textbox label="Shard Factor" bind:text={record.allidsShardFactor} />
{/if}
</form>
<h4>
Fields <span class="add-field-button" on:click={newField}>{@html getIcon("plus")}</span>
</h4>

View file

@ -32,6 +32,7 @@
--white: #FFFFFF;
--darkslate: #5C6B82;
--slate: #8B95A6;
--lightslate: rgb(203, 212, 228);
--borderradius: 2px;
--borderradiusall: 2px 2px 2px 2px;
@ -44,11 +45,10 @@
--bodytext: var(--fontnormal) "regular" var(--secondary100) 16pt;
--bigbodytext: var(--fontnormal) "regular" var(--secondary100) 20pt;
--smallbodytext: var(--fontnormal) "regular" var(--secondary100) 12pt;
--lightbodytext: var(--fontnormal) "regular" var(--darkslate) 16pt;
--lightbodytext: "regular" "normal" 16pt var(--fontnormal);
--heavybodytext: var(--fontbold) "regular" var(--secondary100) 16pt;
--quotation: var(--fontnormal) "italics" var(--darkslate) 16pt;
--smallheavybodytext: var(--fontbold) "regular" var(--secondary100) 14pt;
}
html, body {

View file

@ -0,0 +1,56 @@
<script>
import { searchAllComponents } from "./pagesParsing/searchComponents";
export let allComponents = [];
export let onComponentChosen = () => {};
let phrase = "";
$: filteredComponents =
!phrase
? []
: searchAllComponents(allComponents, phrase);
</script>
<div class="root">
<input class="uk-input" bind:value={phrase}>
<div>
{#each filteredComponents as component}
<div class="component" on:click={() => onComponentChosen(component)}>
<div class="title">{component.name}</div>
<div class="description">{component.description}</div>
</div>
{/each}
</div>
</div>
<style>
.component {
padding:5px;
border-style: solid;
border-width: 0 0 1px 0;
border-color: var(--lightslate);
cursor: pointer;
}
.component:hover {
background-color: var(--primary10);
}
.component > .title {
font-size: 13pt;
color: var(--secondary100);
}
.component > .description {
font-size: 10pt;
color: var(--primary75);
font-style: italic;
}
</style>

View file

@ -0,0 +1,41 @@
<script>
import ComponentSearch from "./ComponentSearch.svelte";
import { store } from "../builderStore";
import PropsView from "./PropsView.svelte";
import Modal from "../common/Modal.svelte";
import Textbox from "../common/Textbox.svelte";
export let isCreatingNewComponent;
let basedOnComponent;
const onBasedOnChosen = component => {
basedOnComponent = component;
}
</script>
<Modal bind:isOpen={isCreatingNewComponent} id="search-component-modal">
<div class="uk-margin">
<form class="uk-form-horizontal">
{#if basedOnComponent}
<Textbox label="name"/>
{:else}
<label class="uk-form-label" for="form-stacked-text">Based On</label>
<div class="uk-form-controls">
<ComponentSearch allComponents={$store.allComponents}
onComponentChosen={onBasedOnChosen} />
</div>
{/if}
</form>
</div>
</Modal>
<style>
</style>

View file

@ -27,13 +27,15 @@ const getPage = (s, name) => {
<style>
.root {
padding-left: 20px;
padding-bottom: 20px;
padding-bottom: 10px;
padding-left: 10px;
font-size: 16px;
color: var(--secondary50);
}
.hierarchy-item {
cursor: pointer;
padding: 5px 0px;
}
.hierarchy-item:hover {

View file

@ -13,8 +13,9 @@ import {
import {
getExactComponent
} from "./pagesParsing/searchComponents";
import Checkbox from "../common/Checkbox";
import Textbox from "../common/Textbox";
import Checkbox from "../common/Checkbox.svelte";
import Textbox from "../common/Textbox.svelte";
import Dropdown from "../common/Dropdown.svelte";
export let props;
export let allComponents;
@ -28,19 +29,33 @@ let fields = pipe(propsDefinition,[
let component = getExactComponent(allComponents, props._component);
let setProp = (name) => (ev) =>
props[name] = ev.target.checked !== undefined
? ev.target.checked
: ev.target.value;
</script>
<div class="root">
<div>{props.name}</div>
<div class="title">{component.name}</div>
<div class="component-description">{component.description || ""}</div>
{#each propsDefinition as propDef}
<form class="uk-form-horizontal prop-row ">
{#if propDef.type === "bool"}
<Checkbox label={propDef.name} />
{:else if true}
<!-- else if content here -->
<Checkbox label={propDef.name}
checked={props[propDef.name]}
on:change={setProp(propDef.name)} />
{:else if propDef.type === "options"}
<Dropdown label={propDef.name}
selected={props[propDef.name]}
options={propDef.options}
on:change={setProp(propDef.name)}/>
{:else}
<!-- else content here -->
<Textbox label={propDef.name}
bind:text={props[propDef.name]} />
{/if}
</form>
{/each}
@ -51,6 +66,19 @@ let component = getExactComponent(allComponents, props._component);
.root {
padding: 10px;
font-size:10pt;
}
.title {
font: var(--smallheavybodytext);
}
.prop-row {
padding: 7px 3px;
}
.component-description {
font: var(--lightbodytext);
}
</style>

View file

@ -2,8 +2,18 @@
import ComponentsHierarchy from "./ComponentsHierarchy.svelte";
import PagesList from "./PagesList.svelte"
import PropsView from "./PropsView.svelte";
import { store } from "../builderStore";
import getIcon from "../common/icon";
import { isRootComponent } from "./pagesParsing/searchComponents";
import IconButton from "../common/IconButton.svelte";
import Modal from "../common/Modal.svelte";
import NewComponent from "./NewComponent.svelte";
let isCreatingNewComponent = false;
const newComponent = () => {
isCreatingNewComponent = true;
}
</script>
@ -12,19 +22,27 @@ import getIcon from "../common/icon";
<div class="ui-nav">
<div class="components-list-container">
<h5>
{@html getIcon("sidebar","18")}
<span class="nav-title-inner">COMPONENTS</span>
</h5>
<ComponentsHierarchy components={$store.allComponents}/>
<div class="nav-group-header">
<div>{@html getIcon("sidebar","18")}</div>
<span>COMPONENTS</span>
<div>
<IconButton icon="plus"
on:click={newComponent} />
</div>
</div>
<div class="nav-items-container">
<ComponentsHierarchy components={$store.allComponents}/>
</div>
</div>
<div class="pages-list-container">
<h5>
{@html getIcon("grid","18")}
<span class="nav-title-inner">PAGES</span>
</h5>
<PagesList />
<div class="nav-group-header">
<div>{@html getIcon("grid","18")}</div>
<span>PAGES</span>
</div>
<div class="nav-items-container">
<PagesList />
</div>
</div>
</div>
@ -37,13 +55,24 @@ import getIcon from "../common/icon";
{/if}
</div>
<div class="properties-pane">
{#if $store.currentFrontEndItem && !isRootComponent($store.currentFrontEndItem)}
<PropsView allComponents={$store.allComponents}
props={$store.currentFrontEndItem.props}/>
{/if}
</div>
</div>
<NewComponent {isCreatingNewComponent}/>
<style>
.root {
display: grid;
grid-template-columns: [uiNav] 300px [preview] auto;
grid-template-columns: [uiNav] 250px [preview] auto [properties] 250px;
height: 100%;
width: 100%;
}
@ -66,19 +95,54 @@ import getIcon from "../common/icon";
grid-column-start: middle;
}
.properties-pane {
grid-column-start: properties;
background-color: var(--primary10);
height: 100%;
}
.pages-list-container {
padding-top: 20px;
}
h5 {
.nav-group-header {
font-size: 10pt;
padding-left: 10px;
}
.nav-title-inner {
.nav-items-container {
padding-top: 10px;
}
.nav-group-header {
display:grid;
grid-template-columns: [icon] auto [title] 1fr [button] auto;
padding: 10px 2px 0px 7px;
}
.nav-group-header>div:nth-child(1) {
padding:0px 7px 0px 0px;
vertical-align: bottom;
grid-column-start: icon;
margin-right: 5px;
}
.nav-group-header>span:nth-child(2) {
margin-left:5px;
vertical-align: bottom;
grid-column-start: title;
margin-top:auto;
}
.nav-group-header>div:nth-child(3) {
vertical-align: bottom;
grid-column-start: button;
cursor: pointer;
color: var(--slate);
}
.nav-group-header>div:nth-child(3):hover {
color: var(--primary75);
}
</style>

View file

@ -5,7 +5,8 @@ import {
keys,
uniq,
some,
keyBy
filter,
reduce
} from "lodash/fp";
import { types } from "./types";
import { assign } from "lodash";
@ -31,7 +32,8 @@ export const createPropDefinitionForDerived = (allComponents, componentName) =>
keys,
filter(k => !hasDerivedProp(k)),
reduce((obj, k) => {
obj[k] = propDef[k]
obj[k] = propDef[k];
return obj;
}, {})
])
}

View file

@ -83,17 +83,17 @@ describe("getAncestorProps", () => {
it("should return props of all ancestors and current component, in order", () => {
const components = components();
const allComponents = components();
const result = getAncestorProps(
components,
allComponents,
"common/PasswordBox"
);
expect(result).toEqual([
root[0].props,
{_component: "budibase-components/TextBox", ...components[2].props},
{_component: "common/SmallTextbox", ...components[3].props}
allComponents[0].props,
{_component: "budibase-components/TextBox", ...allComponents[2].props},
{_component: "common/SmallTextbox", ...allComponents[3].props}
]);
});

View file

@ -4,8 +4,20 @@
"name": "Textbox",
"description": "A text input, with a label",
"props": {
"label": "string"
"label": "string",
"content": "component"
},
"tags": ["textboxt", "input", "text"]
}
"tags": ["textbox", "input", "text"]
},
"button" : {
"path": "./button",
"name": "Button",
"description": "a button",
"props": {
"contentText": "string",
"contentComponent": "component",
"class": "string"
},
"tags": ["button"]
}
}

View file

@ -1,32 +1,31 @@
main.svelte-j8mzr7{height:100%;width:100%;font-family:"Lato", Helvetica, Arial, sans-serif}
.root.svelte-1rxbdcd{height:100%}.content.svelte-1rxbdcd{position:fixed;height:100%;background-color:var(--white);margin:0}
.root.svelte-jymnqv{position:fixed;margin:0 auto;text-align:center;top:20%;width:100%}.inner.svelte-jymnqv{display:inline-block;margin:auto}.logo.svelte-jymnqv{width:300px;margin-bottom:40px}.root.svelte-jymnqv .option{width:250px}.app-link.svelte-jymnqv{margin-top:10px;display:block}
.nav.svelte-n1ql72{height:100%;position:fixed;left:0px;background-color:var(--secondary100);color:var(--darkslate)}.nav.svelte-n1ql72>img.svelte-n1ql72{width:100%;margin-bottom:30px;margin-top:5px;margin-left:0px}
.root.svelte-z7gm0t{display:flex;height:100%;position:relative}.hierarchy.svelte-z7gm0t{flex:0 1 auto;background-color:var(--primary10);overflow-y:auto;height:100%}.node-container.svelte-z7gm0t{flex:1 1 auto;display:flex;flex-direction:column}.actions-header.svelte-z7gm0t{flex:0 1 auto}.node-view.svelte-z7gm0t{overflow-y:auto;flex:1 1 auto}.hierarchy-title-row.svelte-z7gm0t{padding:15px 7px;font-size:11pt;display:flex;font-weight:bold}.hierarchy-title.svelte-z7gm0t{flex:auto 1 1}
.root.svelte-1y6dy5x{padding:10px}
.root.svelte-e4n7zy{position:fixed;margin:0 auto;text-align:center;top:20%;width:100%}.inner.svelte-e4n7zy{display:inline-block;margin:auto}.logo.svelte-e4n7zy{width:300px;margin-bottom:40px}.root.svelte-e4n7zy .option{width:250px}.app-link.svelte-e4n7zy{margin-top:10px;display:block}
.root.svelte-i0dstr{height:100%}.content.svelte-i0dstr{position:fixed;height:100%;background-color:var(--white);margin:0}
h4.svelte-o0id5a{margin-top:20px}
.root.svelte-5zgcq9{display:grid;grid-template-columns:[uiNav] 300px [preview] auto;height:100%;width:100%}.ui-nav.svelte-5zgcq9{grid-column-start:uiNav;background-color:var(--primary10);height:100%}.component-preview.svelte-5zgcq9{display:grid;grid-template-rows:[top] 1fr [middle] auto [bottom] 1fr;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-column-start:preview}.component-container.svelte-5zgcq9{grid-row-start:middle;grid-column-start:middle}.pages-list-container.svelte-5zgcq9{padding-top:20px}h5.svelte-5zgcq9{font-size:10pt;padding-left:10px}.nav-title-inner.svelte-5zgcq9{margin-left:5px;vertical-align:bottom}
.border-normal.svelte-7rfkdx{border-radius:var(--borderradiusall)}.border-left.svelte-7rfkdx{border-radius:var(--borderradius) 0 0 var(--borderradius)}.border-right.svelte-7rfkdx{border-radius:0 var(--borderradius) var(--borderradius) 0}.border-middle.svelte-7rfkdx{border-radius:0}button.svelte-7rfkdx{border-style:solid;padding:7px 15px;cursor:pointer}.primary.svelte-7rfkdx{background-color:var(--primary100);border-color:var(--primary100);color:var(--white)}.primary.svelte-7rfkdx:hover{background-color:var(--primary75);border-color:var(--primary75)}.primary.svelte-7rfkdx:active{background-color:var(--primarydark);border-color:var(--primarydark)}.primary-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--primary100);color:var(--primary100)}.primary-outline.svelte-7rfkdx:hover{background-color:var(--primary10)}.primary-outline.svelte-7rfkdx:pressed{background-color:var(--primary25)}.secondary.svelte-7rfkdx{background-color:var(--secondary100);border-color:var(--secondary100);color:var(--white)}.secondary.svelte-7rfkdx:hover{background-color:var(--secondary75);border-color:var(--secondary75)}.secondary.svelte-7rfkdx:pressed{background-color:var(--secondarydark);border-color:var(--secondarydark)}.secondary-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--secondary100);color:var(--secondary100)}.secondary-outline.svelte-7rfkdx:hover{background-color:var(--secondary10)}.secondary-outline.svelte-7rfkdx:pressed{background-color:var(--secondary25)}.success.svelte-7rfkdx{background-color:var(--success100);border-color:var(--success100);color:var(--white)}.success.svelte-7rfkdx:hover{background-color:var(--success75);border-color:var(--success75)}.success.svelte-7rfkdx:pressed{background-color:var(--successdark);border-color:var(--successdark)}.success-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--success100);color:var(--success100)}.success-outline.svelte-7rfkdx:hover{background-color:var(--success10)}.success-outline.svelte-7rfkdx:pressed{background-color:var(--success25)}.deletion.svelte-7rfkdx{background-color:var(--deletion100);border-color:var(--deletion100);color:var(--white)}.deletion.svelte-7rfkdx:hover{background-color:var(--deletion75);border-color:var(--deletion75)}.deletion.svelte-7rfkdx:pressed{background-color:var(--deletiondark);border-color:var(--deletiondark)}.deletion-outline.svelte-7rfkdx{background-color:var(--white);border-color:var(--deletion100);color:var(--deletion100)}.deletion-outline.svelte-7rfkdx:hover{background-color:var(--deletion10)}.deletion-outline.svelte-7rfkdx:pressed{background-color:var(--deletion25)}
.root.svelte-1be865r{padding:10px}.edit-button.svelte-1be865r{cursor:pointer;color:var(--white)}tr.svelte-1be865r:hover .edit-button.svelte-1be865r{color:var(--secondary75)}
.nav-item.svelte-td9xyr{padding:0px 5px;display:block;padding:10px;color:var(--slate);cursor:pointer}.inner.svelte-td9xyr{padding:0px 20px 10px 0px;display:inline-block;width:100%}.nav-item.svelte-td9xyr:hover{background-color:var(--primary25)}.icon.svelte-td9xyr{font-size:0.9em;display:inline-block;position:relative;top:5px;margin-right:5px;width:100%}.active.svelte-td9xyr>div.svelte-td9xyr{background-color:var(--primary10);color:var(--secondary100)}.active.svelte-td9xyr>div.svelte-td9xyr:hover{background-color:var(--slate);color:var(--secondary100)}.active.svelte-td9xyr{background-color:white}
.root.svelte-1rctf7f{display:block;font-size:13pt;width:100%;cursor:pointer}.title.svelte-1rctf7f{font:var(--bodytext);padding-top:10px;padding-right:5px;padding-bottom:10px;color:var(--secondary100)}.title.svelte-1rctf7f:hover{background-color:var(--secondary10)}
.root.svelte-gq7l8x{height:100%;padding:15px}.fields-table.svelte-gq7l8x{margin:10px;border-collapse:collapse}.add-field-button.svelte-gq7l8x{margin-left:15px;cursor:pointer}.edit-button.svelte-gq7l8x{cursor:pointer;color:var(--white)}.edit-button.svelte-gq7l8x:hover{color:var(--secondary75)}th.svelte-gq7l8x{text-align:left}td.svelte-gq7l8x{padding:5px 30px 5px 0px;margin:0}thead.svelte-gq7l8x>tr.svelte-gq7l8x{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--secondary75);margin-bottom:20px}tbody.svelte-gq7l8x>tr.svelte-gq7l8x{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--primary10)}tbody.svelte-gq7l8x>tr.svelte-gq7l8x:hover{background-color:var(--primary10)}tbody.svelte-gq7l8x>tr:hover .edit-button.svelte-gq7l8x{color:var(--secondary75)}.index-container.svelte-gq7l8x{border-style:solid;border-width:0 0 1px 0;border-color:var(--secondary25);padding:10px;margin-bottom:5px}.index-label.svelte-gq7l8x{color:var(--slate)}.index-name.svelte-gq7l8x{font-weight:bold;color:var(--primary100)}.index-container.svelte-gq7l8x code.svelte-gq7l8x{margin:0;display:inline;background-color:var(--primary10);color:var(--secondary100);padding:3px}.index-field-row.svelte-gq7l8x{margin-top:7px}
.root.svelte-1fkfoam{height:100%;padding:15px}.allowed-records.svelte-1fkfoam{margin:20px 0px}.allowed-records.svelte-1fkfoam>span.svelte-1fkfoam{margin-right:30px}
.root.svelte-d6wwkb{display:flex}.root.svelte-d6wwkb:last-child{border-radius:0 var(--borderradius) var(--borderradius) 0}.root.svelte-d6wwkb:first-child{border-radius:var(--borderradius) 0 0 var(--borderradius)}.root.svelte-d6wwkb:not(:first-child):not(:last-child){border-radius:0}
.root.svelte-160njkp{padding:5px;top:0;width:100%}
.edit-button.svelte-1le5bpl{cursor:pointer;color:var(--white)}tr.svelte-1le5bpl:hover .edit-button.svelte-1le5bpl{color:var(--secondary75)}
.nav.svelte-lgepe1{height:100%;position:fixed;left:0px;background-color:var(--secondary100);color:var(--darkslate)}.nav.svelte-lgepe1>img.svelte-lgepe1{width:100%;margin-bottom:30px;margin-top:5px;margin-left:0px}
.root.svelte-ui57a{display:flex;height:100%;position:relative}.hierarchy.svelte-ui57a{flex:0 1 auto;background-color:var(--primary10);overflow-y:auto;height:100%}.node-container.svelte-ui57a{flex:1 1 auto;display:flex;flex-direction:column}.actions-header.svelte-ui57a{flex:0 1 auto}.node-view.svelte-ui57a{overflow-y:auto;flex:1 1 auto}.hierarchy-title-row.svelte-ui57a{padding:15px 7px;font-size:11pt;display:flex;font-weight:bold}.hierarchy-title.svelte-ui57a{flex:auto 1 1}
.root.svelte-zzs4qg{padding:10px}
.root.svelte-179wat4{display:grid;grid-template-columns:[uiNav] 250px [preview] auto [properties] 250px;height:100%;width:100%}.ui-nav.svelte-179wat4{grid-column-start:uiNav;background-color:var(--primary10);height:100%}.component-preview.svelte-179wat4{display:grid;grid-template-rows:[top] 1fr [middle] auto [bottom] 1fr;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-column-start:preview}.component-container.svelte-179wat4{grid-row-start:middle;grid-column-start:middle}.properties-pane.svelte-179wat4{grid-column-start:properties;background-color:var(--primary10);height:100%}.pages-list-container.svelte-179wat4{padding-top:20px}.nav-group-header.svelte-179wat4{font-size:10pt;padding-left:10px}.nav-items-container.svelte-179wat4{padding-top:10px}.nav-group-header.svelte-179wat4{display:grid;grid-template-columns:[icon] auto [title] 1fr [button] auto;padding:10px 2px 0px 7px}.nav-group-header.svelte-179wat4>div.svelte-179wat4:nth-child(1){padding:0px 7px 0px 0px;vertical-align:bottom;grid-column-start:icon;margin-right:5px}.nav-group-header.svelte-179wat4>span.svelte-179wat4:nth-child(2){margin-left:5px;vertical-align:bottom;grid-column-start:title;margin-top:auto}.nav-group-header.svelte-179wat4>div.svelte-179wat4:nth-child(3){vertical-align:bottom;grid-column-start:button;cursor:pointer;color:var(--slate)}.nav-group-header.svelte-179wat4>div.svelte-179wat4:nth-child(3):hover{color:var(--primary75)}
.root.svelte-1qmjs65{padding:10px}.edit-button.svelte-1qmjs65{cursor:pointer;color:var(--white)}tr.svelte-1qmjs65:hover .edit-button.svelte-1qmjs65{color:var(--secondary75)}
.root.svelte-1q40nqm{display:block;font-size:13pt;width:100%;cursor:pointer}.title.svelte-1q40nqm{font:var(--bodytext);padding-top:10px;padding-right:5px;padding-bottom:10px;color:var(--secondary100)}.title.svelte-1q40nqm:hover{background-color:var(--secondary10)}
.root.svelte-kswv5p{height:100%;padding:15px}.fields-table.svelte-kswv5p{margin:10px;border-collapse:collapse}.add-field-button.svelte-kswv5p{margin-left:15px;cursor:pointer}.edit-button.svelte-kswv5p{cursor:pointer;color:var(--white)}.edit-button.svelte-kswv5p:hover{color:var(--secondary75)}th.svelte-kswv5p{text-align:left}td.svelte-kswv5p{padding:5px 30px 5px 0px;margin:0}thead.svelte-kswv5p>tr.svelte-kswv5p{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--secondary75);margin-bottom:20px}tbody.svelte-kswv5p>tr.svelte-kswv5p{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--primary10)}tbody.svelte-kswv5p>tr.svelte-kswv5p:hover{background-color:var(--primary10)}tbody.svelte-kswv5p>tr:hover .edit-button.svelte-kswv5p{color:var(--secondary75)}.index-container.svelte-kswv5p{border-style:solid;border-width:0 0 1px 0;border-color:var(--secondary25);padding:10px;margin-bottom:5px}.index-label.svelte-kswv5p{color:var(--slate)}.index-name.svelte-kswv5p{font-weight:bold;color:var(--primary100)}.index-container.svelte-kswv5p code.svelte-kswv5p{margin:0;display:inline;background-color:var(--primary10);color:var(--secondary100);padding:3px}.index-field-row.svelte-kswv5p{margin-top:7px}
.nav-item.svelte-5cf6ht{padding:0px 5px;display:block;padding:10px;color:var(--slate);cursor:pointer}.inner.svelte-5cf6ht{padding:0px 20px 10px 0px;display:inline-block;width:100%}.nav-item.svelte-5cf6ht:hover{background-color:var(--primary25)}.icon.svelte-5cf6ht{font-size:0.9em;display:inline-block;position:relative;top:5px;margin-right:5px;width:100%}.active.svelte-5cf6ht>div.svelte-5cf6ht{background-color:var(--primary10);color:var(--secondary100)}.active.svelte-5cf6ht>div.svelte-5cf6ht:hover{background-color:var(--slate);color:var(--secondary100)}.active.svelte-5cf6ht{background-color:white}
.root.svelte-1tilbnf{padding:5px;top:0;width:100%}
.dropdown-background.svelte-179p8ge{position:fixed;top:0;left:0;width:100vw;height:100vh}.root.svelte-179p8ge{cursor:pointer;z-index:1}.dropdown-content.svelte-179p8ge{position:absolute;background-color:var(--white);min-width:160px;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);z-index:1;font-weight:normal;border-style:solid;border-width:1px;border-color:var(--secondary10)}.dropdown-content.svelte-179p8ge:not(:focus){display:none}.action-row.svelte-179p8ge{padding:7px 10px;cursor:pointer}.action-row.svelte-179p8ge:hover{background-color:var(--primary100);color:var(--white)}
.root.svelte-1ba51k0{color:var(--secondary50)}.hierarchy-item.svelte-1ba51k0{cursor:pointer;padding:5px 0px}.hierarchy-item.svelte-1ba51k0:hover{color:var(--secondary75)}.component.svelte-1ba51k0{margin-left:5px}.currentfolder.svelte-1ba51k0{color:var(--secondary100)}.selected.svelte-1ba51k0{color:var(--primary100)}.title.svelte-1ba51k0{margin-left:10px}
.edit-button.svelte-12jzg4k{cursor:pointer;color:var(--white)}tr.svelte-12jzg4k:hover .edit-button.svelte-12jzg4k{color:var(--secondary75)}
.root.svelte-6ej2ac{padding-left:20px;padding-bottom:20px;color:var(--secondary50)}.hierarchy-item.svelte-6ej2ac{cursor:pointer}.hierarchy-item.svelte-6ej2ac:hover{color:var(--secondary75)}.component.svelte-6ej2ac{margin-left:5px}.selected.svelte-6ej2ac{color:var(--primary100)}.title.svelte-6ej2ac{margin-left:10px}
textarea.svelte-1ooq0hh{padding:3px;background:var(--darkslate);color:var(--white);font-family:'Courier New', Courier, monospace;width:95%;height:100px}
.container.svelte-umifqh{display:grid;grid-template-columns:[label] 100px [control] auto;margin:20px 0px}.label.svelte-umifqh{grid-column-start:label;align-self:center}.control.svelte-umifqh{grid-column-start:control;align-self:center;margin:0}input.svelte-umifqh{width:300px}
.root.svelte-d6wwkb{display:flex}.root.svelte-d6wwkb:last-child{border-radius:0 var(--borderradius) var(--borderradius) 0}.root.svelte-d6wwkb:first-child{border-radius:var(--borderradius) 0 0 var(--borderradius)}.root.svelte-d6wwkb:not(:first-child):not(:last-child){border-radius:0}
.root.svelte-pq2tmv{height:100%;padding:15px}.allowed-records.svelte-pq2tmv{margin:20px 0px}.allowed-records.svelte-pq2tmv>span.svelte-pq2tmv{margin-right:30px}
.edit-button.svelte-neetem{cursor:pointer;color:var(--white)}tr.svelte-neetem:hover .edit-button.svelte-neetem{color:var(--secondary75)}
.edit-button.svelte-9z4fqi{cursor:pointer;color:var(--white)}tr.svelte-9z4fqi:hover .edit-button.svelte-9z4fqi{color:var(--secondary75)}
button.svelte-6dbfug{border-style:none;background-color:rgba(0,0,0,0);cursor:pointer}
.root.svelte-1hxxti1{padding:10px;font-size:10pt}.title.svelte-1hxxti1{font:var(--smallheavybodytext)}.prop-row.svelte-1hxxti1{padding:7px 3px}.component-description.svelte-1hxxti1{font:var(--lightbodytext)}
.root.svelte-ffb307{padding-bottom:10px;padding-left:10px;font-size:16px;color:var(--secondary50)}.hierarchy-item.svelte-ffb307{cursor:pointer;padding:5px 0px}.hierarchy-item.svelte-ffb307:hover{color:var(--secondary75)}.component.svelte-ffb307{margin-left:5px}.selected.svelte-ffb307{color:var(--primary100)}.title.svelte-ffb307{margin-left:10px}
.root.svelte-1cnqtw{color:var(--secondary50)}.hierarchy-item.svelte-1cnqtw{cursor:pointer;padding:5px 0px}.hierarchy-item.svelte-1cnqtw:hover{color:var(--secondary75)}.component.svelte-1cnqtw{margin-left:5px}.currentfolder.svelte-1cnqtw{color:var(--secondary100)}.selected.svelte-1cnqtw{color:var(--primary100)}.title.svelte-1cnqtw{margin-left:10px}
.error-container.svelte-jwy920{padding:10px;border-style:solid;border-color:var(--deletion100);border-radius:var(--borderradiusall);background:var(--deletion75)}.error-row.svelte-jwy920{padding:5px 0px}
.container.svelte-bm0783{display:grid;grid-template-columns:[label] 100px [control] auto;margin:20px 0px}.label.svelte-bm0783{grid-column-start:label;align-self:center}.control.svelte-bm0783{grid-column-start:control;align-self:center;margin:0}select.svelte-bm0783{width:300px}
textarea.svelte-1ooq0hh{padding:3px;background:var(--darkslate);color:var(--white);font-family:'Courier New', Courier, monospace;width:95%;height:100px}
.root.svelte-bv289q{padding:10px}.option-container.svelte-bv289q{border-style:dotted;border-width:1px;border-color:var(--primary75);padding:3px;margin-right:5px}
input.svelte-66516k{margin-right:7px}
.root.svelte-emcy8y{padding:10px}.option-container.svelte-emcy8y{border-style:dotted;border-width:1px;border-color:var(--primary75);padding:3px;margin-right:5px}
.container.svelte-1pf9x5k{display:grid;grid-template-columns:[label] 100px [control] auto;margin:20px 0px}.label.svelte-1pf9x5k{grid-column-start:label;align-self:center}.control.svelte-1pf9x5k{grid-column-start:control;align-self:center;margin:0}input.svelte-1pf9x5k{width:300px}
.container.svelte-umifqh{display:grid;grid-template-columns:[label] 100px [control] auto;margin:20px 0px}.label.svelte-umifqh{grid-column-start:label;align-self:center}.control.svelte-umifqh{grid-column-start:control;align-self:center;margin:0}input.svelte-umifqh{width:300px}
.container.svelte-85b8gk{display:grid;grid-template-columns:[label] 100px [control] auto;margin:20px 0px}.label.svelte-85b8gk{grid-column-start:label;align-self:center}.control.svelte-85b8gk{grid-column-start:control;align-self:center;margin:0}textarea.svelte-85b8gk{width:300px;height:200px}
.component.svelte-13tuzj8{padding:5px;border-style:solid;border-width:0 0 1px 0;border-color:var(--lightslate);cursor:pointer}.component.svelte-13tuzj8:hover{background-color:var(--primary10)}.component.svelte-13tuzj8>.title.svelte-13tuzj8{font-size:13pt;color:var(--secondary100)}.component.svelte-13tuzj8>.description.svelte-13tuzj8{font-size:10pt;color:var(--primary75);font-style:italic}
textarea.svelte-1wfv4cc{width:300px;height:200px}
/*# sourceMappingURL=bundle.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -32,6 +32,7 @@
--white: #FFFFFF;
--darkslate: #5C6B82;
--slate: #8B95A6;
--lightslate: rgb(203, 212, 228);
--borderradius: 2px;
--borderradiusall: 2px 2px 2px 2px;
@ -44,11 +45,10 @@
--bodytext: var(--fontnormal) "regular" var(--secondary100) 16pt;
--bigbodytext: var(--fontnormal) "regular" var(--secondary100) 20pt;
--smallbodytext: var(--fontnormal) "regular" var(--secondary100) 12pt;
--lightbodytext: var(--fontnormal) "regular" var(--darkslate) 16pt;
--lightbodytext: "regular" "normal" 16pt var(--fontnormal);
--heavybodytext: var(--fontbold) "regular" var(--secondary100) 16pt;
--quotation: var(--fontnormal) "italics" var(--darkslate) 16pt;
--smallheavybodytext: var(--fontbold) "regular" var(--secondary100) 14pt;
}
html, body {

File diff suppressed because one or more lines are too long

View file

@ -183,6 +183,9 @@ const fetchDerivedComponents = async (appPath, relativePath = "") => {
.substring(0, itemRelativePath.length - 5)
.replace(/\\/g, "/");
component.props = component.props || {};
component.props._component = component.name;
components.push(component);
} else {
const childComponents = await fetchDerivedComponents(