backup
This commit is contained in:
parent
21224b119b
commit
fb9f4f6158
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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", "isObjectLike"];
|
||||
"differenceBy", "intersectionBy", "isEqual", "max", "sortBy", "assign", "uniq", "trimChars", "trimCharsStart", "isObjectLike", "flattenDeep", "indexOf"];
|
||||
|
||||
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",
|
||||
|
|
|
@ -14,7 +14,7 @@ $: borderClass = grouped
|
|||
|
||||
<button class="{color} {className} {borderClass} {grouped ? "grouped" : ""}"
|
||||
style="{style}"
|
||||
on:click>
|
||||
on:click >
|
||||
<slot/>
|
||||
</button>
|
||||
|
||||
|
|
|
@ -6,15 +6,43 @@ export let icon = "";
|
|||
export let style = "";
|
||||
export let color = "";
|
||||
export let hoverColor = "";
|
||||
export let attributes = {};
|
||||
|
||||
$: borderClass = grouped
|
||||
? ""
|
||||
: "border-normal";
|
||||
|
||||
let currentAttributes = [];
|
||||
const addAttributes = (node, attributes) => {
|
||||
|
||||
const add = (_attributes) => {
|
||||
const attrs = [];
|
||||
for(let attr in _attributes) {
|
||||
node.setAttribute(attr, _attributes[attr]);
|
||||
attrs.push("uk-toggle")
|
||||
}
|
||||
currentAttributes = attrs;
|
||||
}
|
||||
|
||||
add(attributes);
|
||||
|
||||
return {
|
||||
// should implement update method
|
||||
update(attributes) {
|
||||
for(let attr of currentAttributes) {
|
||||
node.removeAttribute(attr)
|
||||
}
|
||||
add(attributes);
|
||||
},
|
||||
destroy() {}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<button style="{style} color:{color}"
|
||||
on:click>
|
||||
on:click
|
||||
use:addAttributes={attributes}>
|
||||
{@html getIcon(icon, size)}
|
||||
</button>
|
||||
|
||||
|
|
|
@ -3,12 +3,30 @@ export let text = "";
|
|||
export let label = "";
|
||||
export let width = "medium";
|
||||
export let size = "small";
|
||||
export let margin = true;
|
||||
export let infoText = "";
|
||||
export let hasError = false;
|
||||
export let disabled = false;
|
||||
</script>
|
||||
|
||||
<div class="uk-margin">
|
||||
<div class:uk-margin={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} >
|
||||
<input class="uk-input uk-form-width-{width} uk-form-{size}"
|
||||
class:uk-form-danger={hasError}
|
||||
on:change
|
||||
bind:value={text}
|
||||
{disabled}>
|
||||
</div>
|
||||
{#if infoText}
|
||||
<div class="info-text">{infoText}</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.info-text {
|
||||
font-size: 0.8em;
|
||||
color: var(--slate);
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -16,7 +16,14 @@ $: filteredComponents =
|
|||
|
||||
<div class="root">
|
||||
|
||||
<input class="uk-input" bind:value={phrase}>
|
||||
<form class="uk-search uk-search-large">
|
||||
<span uk-search-icon></span>
|
||||
<input class="uk-search-input"
|
||||
type="search"
|
||||
placeholder="Based on component..."
|
||||
bind:value={phrase}>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
{#each filteredComponents as component}
|
||||
<div class="component" on:click={() => onComponentChosen(component)}>
|
||||
|
|
|
@ -3,39 +3,152 @@
|
|||
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";
|
||||
import Button from "../common/Button.svelte";
|
||||
import ButtonGroup from "../common/ButtonGroup.svelte";
|
||||
import { pipe } from "../common/core";
|
||||
import UIkit from "uikit";
|
||||
import {
|
||||
getNewComponentInfo
|
||||
} from "./pagesParsing/createProps";
|
||||
import { isRootComponent } from "./pagesParsing/searchComponents";
|
||||
|
||||
export let isCreatingNewComponent;
|
||||
let basedOnComponent;
|
||||
import {
|
||||
cloneDeep,
|
||||
join,
|
||||
split,
|
||||
map,
|
||||
keys,
|
||||
isUndefined
|
||||
} from "lodash/fp";
|
||||
import { assign } from "lodash";
|
||||
|
||||
const onBasedOnChosen = component => {
|
||||
basedOnComponent = component;
|
||||
let component;
|
||||
let modalElement;
|
||||
let errors = {};
|
||||
let componentInfo;
|
||||
|
||||
let name = "";
|
||||
let description = "";
|
||||
let tagsString = "";
|
||||
let propsValidationErrors = [];
|
||||
let inheritedProps;
|
||||
let nameInvalid = "";
|
||||
let propsDefinition;
|
||||
|
||||
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.props._component = name;
|
||||
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;
|
||||
UIkit.modal(modalElement).hide();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<Modal bind:isOpen={isCreatingNewComponent} id="search-component-modal">
|
||||
<div class="uk-margin">
|
||||
<form class="uk-form-horizontal">
|
||||
{#if basedOnComponent}
|
||||
<div bind:this={modalElement} id="new-component-modal" uk-modal>
|
||||
<div class="uk-modal-dialog">
|
||||
|
||||
<Textbox label="name"/>
|
||||
<div class="uk-modal-header">
|
||||
<h1>New Component</h1>
|
||||
</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}
|
||||
{: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>
|
||||
onComponentChosen={onBasedOnChosen($store.allComponents)} />
|
||||
|
||||
{/if}
|
||||
</form>
|
||||
|
||||
{/if}
|
||||
</form>
|
||||
</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>
|
||||
</Modal>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
font-size:1.2em;
|
||||
}
|
||||
|
||||
.props-header {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -3,57 +3,113 @@
|
|||
import {
|
||||
keys,
|
||||
map,
|
||||
some,
|
||||
includes,
|
||||
cloneDeep,
|
||||
isEqual
|
||||
} from "lodash/fp";
|
||||
import {
|
||||
pipe
|
||||
} from "../common/core";
|
||||
import {
|
||||
createPropDefinitionForDerived
|
||||
} from "./pagesParsing/createProps";
|
||||
import {
|
||||
getExactComponent
|
||||
} from "./pagesParsing/searchComponents";
|
||||
import { pipe } from "../common/core";
|
||||
import { getComponentInfo } 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";
|
||||
|
||||
export let props;
|
||||
export let allComponents;
|
||||
export let shouldValidate = true;
|
||||
export let onValidate = () => {};
|
||||
export let showTitle = true;
|
||||
export let componentInfo;
|
||||
export let component;
|
||||
export let onPropsChanged = () => {};
|
||||
|
||||
let propsDefinition = createPropDefinitionForDerived(allComponents, props._component);
|
||||
let errors = [];
|
||||
let fields = [];
|
||||
let props = {};
|
||||
let propsDefinitionArray = [];
|
||||
|
||||
let fields = pipe(propsDefinition,[
|
||||
keys,
|
||||
map(k => propsDefinition[k])
|
||||
]);
|
||||
$: {
|
||||
if(componentInfo || component)
|
||||
{
|
||||
if(!componentInfo || (component &&
|
||||
component.name !== componentInfo.component.name)) {
|
||||
componentInfo = getComponentInfo(allComponents, component.name);
|
||||
}
|
||||
|
||||
let component = getExactComponent(allComponents, props._component);
|
||||
props = cloneDeep(componentInfo.fullProps);
|
||||
|
||||
let setProp = (name) => (ev) =>
|
||||
props[name] = ev.target.checked !== undefined
|
||||
? ev.target.checked
|
||||
: ev.target.value;
|
||||
propsDefinitionArray = pipe(componentInfo.propsDefinition, [
|
||||
keys,
|
||||
map(k => ({...componentInfo.propsDefinition[k], ____name:k}))
|
||||
]);
|
||||
|
||||
fields = pipe(componentInfo.propsDefinition,[
|
||||
keys,
|
||||
map(k => componentInfo.propsDefinition[k])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
const isPropInherited = name =>
|
||||
includes(name)(componentInfo.inheritedProps);
|
||||
|
||||
let setProp = (name) => (ev, targetValue="value") => {
|
||||
const newProps = cloneDeep(props);
|
||||
newProps[name] = ev.target[targetValue];
|
||||
|
||||
|
||||
const finalProps = {_component:props._component};
|
||||
|
||||
for(let p of componentInfo.unsetProps) {
|
||||
if(!isEqual(newProps[p])(componentInfo.rootDefaultProps[p])) {
|
||||
finalProps[p] = newProps[p];
|
||||
}
|
||||
}
|
||||
|
||||
props = newProps;
|
||||
if(validate(finalProps))
|
||||
onPropsChanged(finalProps);
|
||||
|
||||
}
|
||||
|
||||
const validate = (finalProps) => {
|
||||
errors = validateProps(componentInfo.propsDefinition, finalProps, [], false);
|
||||
onValidate(errors);
|
||||
return errors.length === 0;
|
||||
}
|
||||
|
||||
const fieldHasError = (propName) =>
|
||||
some(e => e.propName === propName)(errors);
|
||||
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
|
||||
<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 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)} />
|
||||
<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)}/>
|
||||
<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}
|
||||
bind:text={props[propDef.name]} />
|
||||
<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>
|
||||
{/each}
|
||||
|
@ -65,12 +121,12 @@ let setProp = (name) => (ev) =>
|
|||
<style>
|
||||
|
||||
.root {
|
||||
padding: 10px;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
.title {
|
||||
font: var(--smallheavybodytext);
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.prop-row {
|
||||
|
@ -78,7 +134,9 @@ let setProp = (name) => (ev) =>
|
|||
}
|
||||
|
||||
.component-description {
|
||||
font: var(--lightbodytext);
|
||||
font-size: 0.9em;
|
||||
color: var(--slate);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -27,7 +27,8 @@ const newComponent = () => {
|
|||
<span>COMPONENTS</span>
|
||||
<div>
|
||||
<IconButton icon="plus"
|
||||
on:click={newComponent} />
|
||||
on:click={newComponent}
|
||||
attributes={{"uk-toggle" : "target: #new-component-modal" }}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-items-container">
|
||||
|
@ -58,14 +59,14 @@ const newComponent = () => {
|
|||
<div class="properties-pane">
|
||||
{#if $store.currentFrontEndItem && !isRootComponent($store.currentFrontEndItem)}
|
||||
<PropsView allComponents={$store.allComponents}
|
||||
props={$store.currentFrontEndItem.props}/>
|
||||
component={$store.currentFrontEndItem}/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<NewComponent {isCreatingNewComponent}/>
|
||||
<NewComponent bind:isCreatingNewComponent={isCreatingNewComponent}/>
|
||||
|
||||
|
||||
<style>
|
||||
|
@ -99,6 +100,7 @@ const newComponent = () => {
|
|||
grid-column-start: properties;
|
||||
background-color: var(--primary10);
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.pages-list-container {
|
||||
|
|
|
@ -6,21 +6,19 @@ import {
|
|||
uniq,
|
||||
some,
|
||||
filter,
|
||||
reduce
|
||||
reduce,
|
||||
cloneDeep,
|
||||
includes
|
||||
} from "lodash/fp";
|
||||
import { types } from "./types";
|
||||
import { types, expandPropsDefinition } from "./types";
|
||||
import { assign } from "lodash";
|
||||
import { pipe } from "../../common/core";
|
||||
import { isRootComponent } from "./searchComponents";
|
||||
|
||||
export const createPropDefinitionForDerived = (allComponents, componentName) => {
|
||||
const traverseForProps = (cname, derivedProps=[]) => {
|
||||
const component = find(c => c.name === cname)(allComponents);
|
||||
if(isRootComponent(component)) return ({propDef:component.props, derivedProps});
|
||||
return traverseForProps(component.inherits, [component.props, ...derivedProps]);
|
||||
}
|
||||
|
||||
const {propDef, derivedProps} = traverseForProps(componentName);
|
||||
|
||||
const {propDef, derivedProps} = getComponentInfo(allComponents, componentName);
|
||||
|
||||
const hasDerivedProp = k => pipe(derivedProps, [
|
||||
keys,
|
||||
|
@ -34,10 +32,81 @@ export const createPropDefinitionForDerived = (allComponents, componentName) =>
|
|||
reduce((obj, k) => {
|
||||
obj[k] = propDef[k];
|
||||
return obj;
|
||||
}, {})
|
||||
}, {}),
|
||||
expandPropsDefinition
|
||||
])
|
||||
}
|
||||
|
||||
export const traverseForProps = getComponentInfo;
|
||||
|
||||
export const getFinalProps = (componentInfo, props) => {
|
||||
const finalProps = cloneDeep(componentInfo.fullProps);
|
||||
|
||||
for(let p in props) {
|
||||
finalProps[p] = props[p];
|
||||
}
|
||||
|
||||
return finalProps;
|
||||
}
|
||||
|
||||
export const getNewComponentInfo = (allComponents, inherits) => {
|
||||
const parentcomponent = find(c => c.name === inherits)(allComponents);
|
||||
const component = {
|
||||
name:"",
|
||||
description:"",
|
||||
inherits,
|
||||
props:{_component:inherits},
|
||||
tags:parentcomponent.tags
|
||||
};
|
||||
return getComponentInfo(
|
||||
allComponents,
|
||||
inherits,
|
||||
[component],
|
||||
{});
|
||||
}
|
||||
|
||||
|
||||
export const getComponentInfo = (allComponents, cname, stack=[], subComponentProps=null) => {
|
||||
const component = find(c => c.name === cname)(allComponents);
|
||||
if(isRootComponent(component)) {
|
||||
subComponentProps = subComponentProps||{};
|
||||
const p = createProps(cname, component.props, subComponentProps);
|
||||
const inheritedProps = [];
|
||||
if(stack.length > 0) {
|
||||
const targetComponent = stack[0];
|
||||
p.props._component = targetComponent.name;
|
||||
for(let prop in subComponentProps) {
|
||||
if(prop === "_component") continue;
|
||||
const hasProp = pipe(targetComponent.props, [
|
||||
keys,
|
||||
includes(prop)]);
|
||||
|
||||
if(!hasProp)
|
||||
inheritedProps.push(prop);
|
||||
}
|
||||
}
|
||||
const unsetProps = pipe(p.props, [
|
||||
keys,
|
||||
filter(k => k !== "_component" && !includes(k)(keys(subComponentProps)))
|
||||
]);
|
||||
|
||||
return ({
|
||||
propsDefinition:component.props,
|
||||
inheritedProps,
|
||||
rootDefaultProps: p.props,
|
||||
unsetProps,
|
||||
fullProps: p.props,
|
||||
errors: p.errors,
|
||||
component: stack.length > 0 ? stack[0] : component
|
||||
});
|
||||
}
|
||||
return getComponentInfo(
|
||||
allComponents,
|
||||
component.inherits,
|
||||
[...stack, component],
|
||||
{...component.props, ...subComponentProps});
|
||||
}
|
||||
|
||||
export const createProps = (componentName, propsDefinition, derivedFromProps) => {
|
||||
|
||||
const error = (propName, error) =>
|
||||
|
@ -61,7 +130,7 @@ export const createProps = (componentName, propsDefinition, derivedFromProps) =>
|
|||
}
|
||||
|
||||
if(derivedFromProps) {
|
||||
assign(props, ...derivedFromProps);
|
||||
assign(props, derivedFromProps);
|
||||
}
|
||||
|
||||
return ({
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
const defaultDef = typeName => () => ({
|
||||
type: typeName,
|
||||
required:false,
|
||||
default:types[typeName].default,
|
||||
default:types[typeName].default(),
|
||||
options: typeName === "options" ? [] : undefined,
|
||||
elementDefinition: typeName === "array" ? {} : undefined
|
||||
});
|
||||
|
@ -18,21 +18,33 @@ const propType = (defaultValue, isOfType, defaultDefinition) => ({
|
|||
isOfType, default:defaultValue, defaultDefinition
|
||||
});
|
||||
|
||||
/*export const expandPropDef = propDef => {
|
||||
const expandSingleProp = propDef => {
|
||||
const p = isString(propDef)
|
||||
? types[propDef].defaultDefinition()
|
||||
: propDef;
|
||||
|
||||
if(!isString(propDef)) {
|
||||
const def = types[propDef.type].defaultDefinition();
|
||||
assign(propDef, def);
|
||||
for(let p in def) {
|
||||
if(propDef[p] === undefined) {
|
||||
propDef[p] = def[p];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(p.type === "array" && isString(p.elementDefinition)) {
|
||||
p.elementDefinition = types[p.elementDefinition].defaultDefinition()
|
||||
if(p.type === "array") {
|
||||
p.elementDefinition = expandPropsDefinition(p.elementDefinition);
|
||||
}
|
||||
return p;
|
||||
}*/
|
||||
}
|
||||
|
||||
export const expandPropsDefinition = propsDefinition => {
|
||||
const expandedProps = {};
|
||||
for(let p in propsDefinition) {
|
||||
expandedProps[p] = expandSingleProp(propsDefinition[p]);
|
||||
}
|
||||
return expandedProps;
|
||||
}
|
||||
|
||||
const isComponent = isObjectLike;
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import {
|
|||
flatten,
|
||||
flattenDeep,
|
||||
each,
|
||||
indexOf } from "lodash/fp";
|
||||
indexOf
|
||||
} from "lodash/fp";
|
||||
import { common } from "../../../../core/src";
|
||||
|
||||
const pipe = common.$;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { createProps } from "../src/userInterface/pagesParsing/createProps";
|
||||
import {
|
||||
createProps,
|
||||
createPropsAndDefinition
|
||||
} from "../src/userInterface/pagesParsing/createProps";
|
||||
import {
|
||||
keys, some
|
||||
} from "lodash/fp";
|
||||
import { allComponents } from "./testData";
|
||||
|
||||
describe("createDefaultProps", () => {
|
||||
|
||||
|
@ -162,7 +166,7 @@ describe("createDefaultProps", () => {
|
|||
fieldName: "surname"
|
||||
};
|
||||
|
||||
const { props, errors } = createProps("some_component",propDef, [derivedFrom]);
|
||||
const { props, errors } = createProps("some_component",propDef, derivedFrom);
|
||||
|
||||
expect(errors.length).toBe(0);
|
||||
expect(props.fieldName).toBe("surname");
|
||||
|
@ -170,35 +174,4 @@ describe("createDefaultProps", () => {
|
|||
|
||||
});
|
||||
|
||||
it("should merge in derived props, last in list taking priority", () => {
|
||||
const propDef = {
|
||||
fieldName: "string",
|
||||
fieldLength: { type: "number", default: 500},
|
||||
header: "component",
|
||||
content: {
|
||||
type: "component",
|
||||
default: { _component: "childcomponent", wdith: 500 }
|
||||
}
|
||||
};
|
||||
|
||||
const derivedFrom1 = {
|
||||
_component:"root",
|
||||
fieldName: "surname",
|
||||
fieldLength: 200
|
||||
};
|
||||
|
||||
const derivedFrom2 = {
|
||||
_component:"child",
|
||||
fieldName: "forename"
|
||||
};
|
||||
|
||||
const { props, errors } = createProps("some_component",propDef, [derivedFrom1, derivedFrom2]);
|
||||
|
||||
expect(errors.length).toBe(0);
|
||||
expect(props.fieldName).toBe("forename");
|
||||
expect(props.fieldLength).toBe(200);
|
||||
expect(props._component).toBe("child");
|
||||
|
||||
});
|
||||
|
||||
})
|
|
@ -0,0 +1,44 @@
|
|||
import { expandPropsDefinition } from "../src/userInterface/pagesParsing/types";
|
||||
|
||||
const propDef = {
|
||||
label: "string",
|
||||
width: {type:"number"},
|
||||
color: {type:"string", required:true},
|
||||
child: "component",
|
||||
navitems: {
|
||||
type: "array",
|
||||
elementDefinition: {
|
||||
name: {type:"string"},
|
||||
height: "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("expandPropDefintion", () => {
|
||||
|
||||
it("should expand property defined as string, into default for that type", () => {
|
||||
|
||||
const result = expandPropsDefinition(propDef);
|
||||
|
||||
expect(result.label.type).toBe("string");
|
||||
expect(result.label.required).toBe(false);
|
||||
});
|
||||
|
||||
it("should add members to property defined as object, when members do not exist", () => {
|
||||
|
||||
const result = expandPropsDefinition(propDef);
|
||||
expect(result.width.required).toBe(false);
|
||||
});
|
||||
|
||||
it("should not override existing memebers", () => {
|
||||
|
||||
const result = expandPropsDefinition(propDef);
|
||||
expect(result.color.required).toBe(true);
|
||||
});
|
||||
|
||||
it("should also expand out elementdefinition of array", () => {
|
||||
const result = expandPropsDefinition(propDef);
|
||||
expect(result.navitems.elementDefinition.height.type).toBe("number");
|
||||
})
|
||||
|
||||
})
|
|
@ -0,0 +1,103 @@
|
|||
import {
|
||||
getFinalProps,
|
||||
getComponentInfo
|
||||
} from "../src/userInterface/pagesParsing/createProps";
|
||||
import {
|
||||
keys, some
|
||||
} from "lodash/fp";
|
||||
import { allComponents } from "./testData";
|
||||
|
||||
|
||||
|
||||
describe("getComponentInfo", () => {
|
||||
|
||||
it("should return default props for root component", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"budibase-components/TextBox");
|
||||
|
||||
expect(result.errors).toEqual([]);
|
||||
expect(result.fullProps).toEqual({
|
||||
_component: "budibase-components/TextBox",
|
||||
size: "",
|
||||
isPassword: false,
|
||||
placeholder: "",
|
||||
label:""
|
||||
});
|
||||
});
|
||||
|
||||
it("should return no inherited for root component", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"budibase-components/TextBox");
|
||||
|
||||
expect(result.inheritedProps).toEqual([]);
|
||||
|
||||
});
|
||||
|
||||
it("getFinalProps should set supplied props on top of default props", () => {
|
||||
const result = getFinalProps(
|
||||
getComponentInfo(
|
||||
allComponents(),
|
||||
"budibase-components/TextBox"),
|
||||
{size:"small"});
|
||||
|
||||
expect(result).toEqual({
|
||||
_component: "budibase-components/TextBox",
|
||||
size: "small",
|
||||
isPassword: false,
|
||||
placeholder: "",
|
||||
label:""
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("should return correct props for derived component", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"common/SmallTextbox");
|
||||
|
||||
expect(result.errors).toEqual([]);
|
||||
expect(result.fullProps).toEqual({
|
||||
_component: "common/SmallTextbox",
|
||||
size: "small",
|
||||
isPassword: false,
|
||||
placeholder: "",
|
||||
label:""
|
||||
});
|
||||
});
|
||||
|
||||
it("should return correct props for twice derived component", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"common/PasswordBox");
|
||||
|
||||
expect(result.errors).toEqual([]);
|
||||
expect(result.fullProps).toEqual({
|
||||
_component: "common/PasswordBox",
|
||||
size: "small",
|
||||
isPassword: true,
|
||||
placeholder: "",
|
||||
label:""
|
||||
});
|
||||
});
|
||||
|
||||
it("should list inheirted props as those that are defined in ancestor, derived components", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"common/PasswordBox");
|
||||
|
||||
// size is inherited from SmallTextbox
|
||||
expect(result.inheritedProps).toEqual(["size"]);
|
||||
});
|
||||
|
||||
it("should list unset props as those that are only defined in root", () => {
|
||||
const result = getComponentInfo(
|
||||
allComponents(),
|
||||
"common/PasswordBox");
|
||||
|
||||
expect(result.unsetProps).toEqual([
|
||||
"placeholder", "label"]);
|
||||
});
|
||||
|
||||
})
|
|
@ -3,14 +3,14 @@ import {
|
|||
getExactComponent,
|
||||
getAncestorProps
|
||||
} from "../src/userInterface/pagesParsing/searchComponents";
|
||||
|
||||
import { allComponents } from "./testData";
|
||||
|
||||
describe("searchAllComponents", () => {
|
||||
|
||||
it("should match derived component by name", () => {
|
||||
|
||||
const results = searchAllComponents(
|
||||
components(),
|
||||
allComponents(),
|
||||
"password"
|
||||
);
|
||||
|
||||
|
@ -22,7 +22,7 @@ describe("searchAllComponents", () => {
|
|||
it("should match derived component by tag", () => {
|
||||
|
||||
const results = searchAllComponents(
|
||||
components(),
|
||||
allComponents(),
|
||||
"mask"
|
||||
);
|
||||
|
||||
|
@ -34,7 +34,7 @@ describe("searchAllComponents", () => {
|
|||
it("should match component if ancestor matches", () => {
|
||||
|
||||
const results = searchAllComponents(
|
||||
components(),
|
||||
allComponents(),
|
||||
"smalltext"
|
||||
);
|
||||
|
||||
|
@ -47,7 +47,7 @@ describe("searchAllComponents", () => {
|
|||
describe("getExactComponent", () => {
|
||||
it("should get component by name", () => {
|
||||
const result = getExactComponent(
|
||||
components(),
|
||||
allComponents(),
|
||||
"common/SmallTextbox"
|
||||
)
|
||||
|
||||
|
@ -57,7 +57,7 @@ describe("getExactComponent", () => {
|
|||
|
||||
it("should return nothing when no result (should not fail)", () => {
|
||||
const result = getExactComponent(
|
||||
components(),
|
||||
allComponents(),
|
||||
"bla/bla/bla"
|
||||
)
|
||||
|
||||
|
@ -71,75 +71,33 @@ describe("getAncestorProps", () => {
|
|||
it("should return props of root component", () => {
|
||||
|
||||
const result = getAncestorProps(
|
||||
components(),
|
||||
allComponents(),
|
||||
"budibase-components/TextBox"
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
components()[0].props
|
||||
allComponents()[0].props
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
it("should return props of all ancestors and current component, in order", () => {
|
||||
|
||||
const allComponents = components();
|
||||
const components = allComponents();
|
||||
|
||||
const result = getAncestorProps(
|
||||
allComponents,
|
||||
components,
|
||||
"common/PasswordBox"
|
||||
);
|
||||
|
||||
expect(result).toEqual([
|
||||
allComponents[0].props,
|
||||
{_component: "budibase-components/TextBox", ...allComponents[2].props},
|
||||
{_component: "common/SmallTextbox", ...allComponents[3].props}
|
||||
components[0].props,
|
||||
{_component: "budibase-components/TextBox", ...components[2].props},
|
||||
{_component: "common/SmallTextbox", ...components[3].props}
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
const components = () => ([
|
||||
{
|
||||
name: "budibase-components/TextBox",
|
||||
tags: ["Text", "input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
isPassword: "boolean",
|
||||
placeholder: "string",
|
||||
label:"string"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "budibase-components/Button",
|
||||
tags: ["input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
css: "string",
|
||||
content: "component"
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"budibase-components/TextBox",
|
||||
name: "common/SmallTextbox",
|
||||
props: {
|
||||
size: "small"
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"common/SmallTextbox",
|
||||
name: "common/PasswordBox",
|
||||
tags: ["mask"],
|
||||
props: {
|
||||
isPassword: true
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"budibase-components/Button",
|
||||
name:"PrimaryButton",
|
||||
props: {
|
||||
css:"btn-primary"
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
export const allComponents = () => ([
|
||||
{
|
||||
name: "budibase-components/TextBox",
|
||||
tags: ["Text", "input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
isPassword: "bool",
|
||||
placeholder: "string",
|
||||
label:"string"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "budibase-components/Button",
|
||||
tags: ["input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
css: "string",
|
||||
content: "component"
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"budibase-components/TextBox",
|
||||
name: "common/SmallTextbox",
|
||||
props: {
|
||||
size: "small"
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"common/SmallTextbox",
|
||||
name: "common/PasswordBox",
|
||||
tags: ["mask"],
|
||||
props: {
|
||||
isPassword: true
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"budibase-components/Button",
|
||||
name:"PrimaryButton",
|
||||
props: {
|
||||
css:"btn-primary"
|
||||
}
|
||||
}
|
||||
])
|
Loading…
Reference in New Issue