1
0
Fork 0
mirror of synced 2024-07-11 17:26:01 +12:00

Remove validation, use references rather than clones where possible, prioritise side-panel working with components for now.

This commit is contained in:
pngwn 2020-01-24 14:30:17 +00:00
parent 2a4cfa278b
commit 86c42a44ab
9 changed files with 73 additions and 385 deletions

View file

@ -93,7 +93,8 @@ export const getStore = () => {
store.createGeneratedComponents = createGeneratedComponents(store); store.createGeneratedComponents = createGeneratedComponents(store);
store.addChildComponent = addChildComponent(store); store.addChildComponent = addChildComponent(store);
store.selectComponent = selectComponent(store); store.selectComponent = selectComponent(store);
store.saveComponent = saveComponent(store); store.updateComponentProp = updateComponentProp(store);
return store; return store;
} }
@ -137,6 +138,7 @@ const initialise = (store, initial) => async () => {
shadowHierarchy, initial.currentNode.nodeId shadowHierarchy, initial.currentNode.nodeId
); );
} }
console.log(initial)
store.set(initial); store.set(initial);
return initial; return initial;
} }
@ -701,19 +703,16 @@ const addChildComponent = store => component => {
const children = s.currentFrontEndItem.props._children; const children = s.currentFrontEndItem.props._children;
const component_definition = { const component_definition = Object.assign(
...newComponent.fullProps, cloneDeep(newComponent.fullProps), {
_component: component, _component: component,
name: component, })
description: '',
location: (s.currentFrontEndItem.location ? s.currentFrontEndItem.location : [])
.concat(children && children.length || 0)
}
s.currentFrontEndItem.props._children = s.currentFrontEndItem.props._children =
children ? children ?
children.concat(component_definition) : children.concat(component_definition) :
[component_definition]; [component_definition];
console.log(component_definition)
return s; return s;
}) })
@ -721,15 +720,20 @@ const addChildComponent = store => component => {
const selectComponent = store => component => { const selectComponent = store => component => {
store.update(s => { store.update(s => {
s.currentComponentInfo = getComponentInfo(s.components, component); s.currentComponentInfo = component;
console.log(s)
return s; return s;
}) })
} }
const saveComponent = store => component => { const updateComponentProp = store => (name, value) => {
store.update(s => { store.update(s => {
s.currentComponentInfo = getComponentInfo(s.components, component); const current_component = s.currentComponentInfo;
console.log(s.currentFrontEndItem, s.screens) s.currentComponentInfo[name] = value;
return _saveScreen(store, s, s.currentFrontEndItem); _saveScreen(store, s, s.currentFrontEndItem);
s.currentComponentInfo = current_component;
return s;
}) })
} }

View file

@ -5,13 +5,10 @@ import { store } from "../builderStore";
import { isRootComponent } from "./pagesParsing/searchComponents"; import { isRootComponent } from "./pagesParsing/searchComponents";
import IconButton from "../common/IconButton.svelte"; import IconButton from "../common/IconButton.svelte";
import Textbox from "../common/Textbox.svelte"; import Textbox from "../common/Textbox.svelte";
// import UIkit from "uikit";
import { pipe } from "../common/core"; import { pipe } from "../common/core";
import { import {
getScreenInfo getScreenInfo
} from "./pagesParsing/createProps"; } from "./pagesParsing/createProps";
// import Button from "../common/Button.svelte";
// import ButtonGroup from "../common/ButtonGroup.svelte";
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/'; import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/';
import CodeEditor from './CodeEditor.svelte'; import CodeEditor from './CodeEditor.svelte';
import LayoutEditor from './LayoutEditor.svelte'; import LayoutEditor from './LayoutEditor.svelte';
@ -32,18 +29,18 @@ let name = "";
let description = ""; let description = "";
let tagsString = ""; let tagsString = "";
let nameInvalid = ""; let nameInvalid = "";
let componentInfo; let componentInfo = {};
let modalElement let modalElement
let propsValidationErrors = []; let propsValidationErrors = [];
let originalName=""; let originalName="";
let components; let components;
let ignoreStore = false; let ignoreStore = false;
$: shortName = last(name.split("/")); // $: shortName = last(name.split("/"));
store.subscribe(s => { store.subscribe(s => {
if(ignoreStore) return; if(ignoreStore) return;
component = s.currentComponentInfo.component; component = s.currentComponentInfo;
if(!component) return; if(!component) return;
originalName = component.name; originalName = component.name;
name = component.name; name = component.name;
@ -53,100 +50,12 @@ store.subscribe(s => {
components = s.components; components = s.components;
}); });
const save = () => { const onPropsChanged = store.updateComponentProp;
ignoreStore = true;
if(!validate()) {
ignoreStore = false;
return;
}
component.name = originalName || name;
component.description = description;
component.tags = pipe(tagsString, [
split(","),
map(s => s.trim())
]);
store.saveComponent(component);
ignoreStore = false;
// now do the rename
if(name !== originalName) {
store.renameScreen(originalName, name);
}
}
const deleteComponent = () => {
showDialog();
}
const confirmDeleteComponent = () => {
store.deleteScreen(component.name);
hideDialog();
}
const onPropsValidate = result => {
propsValidationErrors = result;
}
const updateComponent = doChange => {
const newComponent = cloneDeep(component);
component = doChange(newComponent);
console.log(component, $store.screens[0].props._children[1])
componentInfo = getScreenInfo(components, newComponent);
}
const onPropsChanged = newProps => {
updateComponent(newComponent =>
assign(newComponent, newProps))
save();
}
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();
// }
let current_view = 'props'; let current_view = 'props';
</script> </script>
<div class="root"> <div class="root">
<!-- <div class="title">
<div>{shortName}</div>
<div>
<IconButton icon="save"
on:click={save}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
<IconButton icon="trash"
on:click={deleteComponent}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
</div>
</div> -->
<ul> <ul>
<li> <li>
<button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}> <button class:selected={current_view === 'props'} on:click={() => current_view = 'props'}>
@ -165,12 +74,11 @@ let current_view = 'props';
</li> </li>
</ul> </ul>
{#if !componentInfo.component}
<div class="component-props-container"> <div class="component-props-container">
{#if current_view === 'props'} {#if current_view === 'props'}
<PropsView onValidate={onPropsValidate} <PropsView {componentInfo} {components} {onPropsChanged} />
{componentInfo}
{onPropsChanged} />
{:else if current_view === 'layout'} {:else if current_view === 'layout'}
<LayoutEditor /> <LayoutEditor />
{:else} {:else}
@ -178,39 +86,13 @@ let current_view = 'props';
{/if} {/if}
</div> </div>
{:else}
<h1> This is a screen, this will be dealt with later</h1>
{/if}
</div> </div>
<!-- <div bind:this={modalElement} uk-modal>
<div class="uk-modal-dialog">
<div class="uk-modal-header">
Delete {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> <style>
.root { .root {

View file

@ -1,5 +1,5 @@
<script> <script>
import ComponentHierarchyChildren from './ComponentHierarchyChildren.svelte'; import ComponentsHierarchyChildren from './ComponentsHierarchyChildren.svelte';
import { import {
last, last,
@ -19,14 +19,8 @@ import getIcon from "../common/icon";
import { store } from "../builderStore"; import { store } from "../builderStore";
export let components = [] export let components = []
export let thisLevel = "";
let pathPartsThisLevel;
let componentsThisLevel;
let _components; let _components;
let subfolders;
let expandedFolders = [];
const joinPath = join("/"); const joinPath = join("/");
@ -37,40 +31,9 @@ const normalizedName = name => pipe(name, [
trimChars(" ") trimChars(" ")
]); ]);
const isOnThisLevel = (c) =>
normalizedName(c.name).split("/").length === pathPartsThisLevel
&&
(!thisLevel || normalizedName(c.name).startsWith(normalizedName(thisLevel)));
const notOnThisLevel = (c) => !isOnThisLevel(c);
const isInSubfolder = (subfolder, c) =>
normalizedName(c.name).startsWith(
trimCharsStart("/")(
joinPath([thisLevel, subfolder])));
const isOnNextLevel = (c) =>
normalizedName(c.name).split("/").length === pathPartsThisLevel + 1
const lastPartOfName = (c) => const lastPartOfName = (c) =>
last(c.name ? c.name.split("/") : c._component.split("/")) last(c.name ? c.name.split("/") : c._component.split("/"))
const subFolder = (c) => {
const cname = normalizedName(c.name);
const folderName = cname.substring(thisLevel.length, cname.length).split("/")[0];
return ({
name: folderName,
isExpanded: includes(folderName)(expandedFolders),
path: thisLevel + "/" + folderName
});
}
const subComponents = (subfolder) => pipe(components, [
filter(c => isInSubfolder(subfolder, c))
]);
const expandFolder = folder => { const expandFolder = folder => {
const expandedFolder = {...folder}; const expandedFolder = {...folder};
if(expandedFolder.isExpanded) { if(expandedFolder.isExpanded) {
@ -99,42 +62,21 @@ const isFolderSelected = (current, folder) =>
$: { $: _components =
pathPartsThisLevel = !thisLevel
? 1
: normalizedName(thisLevel).split("/").length + 1;
_components =
pipe(components, [ pipe(components, [
// filter(isOnThisLevel),
map(c => ({component: c, title:lastPartOfName(c)})), map(c => ({component: c, title:lastPartOfName(c)})),
sortBy("title") sortBy("title")
]); ]);
// subfolders = function select_component(screen, component) {
// pipe(components, [ store.setCurrentScreen(screen);
// filter(notOnThisLevel), store.selectComponent(component);
// sortBy("name"),
// map(subFolder),
// uniqWith((f1,f2) => f1.path === f2.path)
// ]);
} }
</script> </script>
<div class="root"> <div class="root">
<!-- {#each subfolders as folder}
<div class="hierarchy-item folder"
on:click|stopPropagation={() => expandFolder(folder)}>
<span>{@html getIcon(folder.isExpanded ? "chevron-down" : "chevron-right", "16")}</span>
<span class="title" class:currentfolder={$store.currentFrontEndItem && isInSubfolder(folder.name, $store.currentFrontEndItem)}>{folder.name}</span>
{#if folder.isExpanded}
<svelte:self components={subComponents(folder.name)}
thisLevel={folder.path} />
{/if}
</div>
{/each} -->
{#each _components as component} {#each _components as component}
<div class="hierarchy-item component" <div class="hierarchy-item component"
@ -144,7 +86,8 @@ $: {
<span class="title">{component.title}</span> <span class="title">{component.title}</span>
</div> </div>
{#if component.component.props && component.component.props._children} {#if component.component.props && component.component.props._children}
<ComponentHierarchyChildren components={component.component.props._children} onSelect={store.selectComponent}/> <ComponentsHierarchyChildren components={component.component.props._children}
onSelect={component =>select_component(component.component.name, component)} />
{/if} {/if}
{/each} {/each}

View file

@ -13,7 +13,7 @@
{#each components as component} {#each components as component}
<ul> <ul>
<li on:click|stopPropagation={() => onSelect(component)}> <li on:click|stopPropagation={() => onSelect(component)}>
{get_capitalised_name(component.name)} {get_capitalised_name(component._component)}
{#if component._children} {#if component._children}
<svelte:self components={component._children}/> <svelte:self components={component._children}/>

View file

@ -81,9 +81,6 @@ let current_view = 'text';
<div class="name"> <div class="name">
{splitName(component.name).componentName} {splitName(component.name).componentName}
</div> </div>
<!-- <div class="description">
{component.description}
</div> -->
</div> </div>
{/each} {/each}

View file

@ -51,43 +51,6 @@ store.subscribe(s => {
components = s.components; components = s.components;
}); });
const save = () => {
ignoreStore = true;
if(!validate()) {
ignoreStore = false;
return;
}
component.name = originalName || name;
component.description = description;
component.tags = pipe(tagsString, [
split(","),
map(s => s.trim())
]);
store.saveScreen(component);
ignoreStore = false;
// now do the rename
if(name !== originalName) {
store.renameScreen(originalName, name);
}
}
const deleteComponent = () => {
showDialog();
}
const confirmDeleteComponent = () => {
store.deleteScreen(component.name);
hideDialog();
}
const onPropsValidate = result => {
propsValidationErrors = result;
}
const updateComponent = doChange => { const updateComponent = doChange => {
const newComponent = cloneDeep(component); const newComponent = cloneDeep(component);
doChange(newComponent); doChange(newComponent);
@ -98,47 +61,12 @@ const updateComponent = doChange => {
const onPropsChanged = newProps => { const onPropsChanged = newProps => {
updateComponent(newComponent => updateComponent(newComponent =>
assign(newComponent.props, newProps)); assign(newComponent.props, newProps));
}
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> </script>
<div class="root"> <div class="root">
<!-- <div class="title">
<div>{shortName}</div>
<div>
<IconButton icon="save"
on:click={save}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
<IconButton icon="trash"
on:click={deleteComponent}
color="var(--secondary100)"
hoverColor="var(--primary100)"/>
</div>
</div> -->
<ul> <ul>
<li><button><PaintIcon /></button></li> <li><button><PaintIcon /></button></li>
<li><button><LayoutIcon /></button></li> <li><button><LayoutIcon /></button></li>
@ -148,7 +76,7 @@ const showDialog = () => {
<div class="component-props-container"> <div class="component-props-container">
<PropsView onValidate={onPropsValidate} <PropsView
{componentInfo} {componentInfo}
{onPropsChanged} /> {onPropsChanged} />
@ -157,36 +85,6 @@ const showDialog = () => {
</div> </div>
<div bind:this={modalElement} uk-modal>
<div class="uk-modal-dialog">
<div class="uk-modal-header">
Delete {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> <style>
.root { .root {

View file

@ -5,6 +5,7 @@ import {
filter filter
} from "lodash/fp"; } from "lodash/fp";
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers"; import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
export let parentProps; export let parentProps;
export let propDef; export let propDef;
export let onValueChanged; export let onValueChanged;

View file

@ -6,13 +6,12 @@ import Dropdown from "../common/Dropdown.svelte";
import EventListSelector from "./EventListSelector.svelte"; import EventListSelector from "./EventListSelector.svelte";
import StateBindingControl from "./StateBindingControl.svelte"; import StateBindingControl from "./StateBindingControl.svelte";
export let errors = [];
export let setProp = () => {}; export let setProp = () => {};
export let fieldHasError =() => {};
export let propDef = {};
export let props = {};
export let disabled; export let disabled;
export let index; export let index;
export let prop_name;
export let prop_value;
export let prop_type = {};
$: isOdd = (index % 2 !== 0); $: isOdd = (index % 2 !== 0);
@ -25,20 +24,20 @@ const setComponentProp = (props) => {
<div class="root" > <div class="root" >
{#if propDef.type === "event"} {#if prop_type === "event"}
<h5>{propDef.____name}</h5> <!-- <h5>{prop_name}</h5>
<EventListSelector parentProps={props} <EventListSelector parentProps={props}
{propDef} {propDef}
onValueChanged={setComponentProp} /> onValueChanged={setComponentProp} /> -->
{:else } {:else }
<h5>{propDef.____name}</h5> <h5>{prop_name}</h5>
<StateBindingControl value={props[propDef.____name]} <StateBindingControl value={prop_value}
type={propDef.type} type={prop_type}
options={propDef.options} options={prop_type.options}
onChanged={v => setProp(propDef.____name, v)}/> onChanged={v => setProp(prop_name, v)}/>
{/if} {/if}

View file

@ -10,66 +10,30 @@ import { getInstanceProps } from "./pagesParsing/createProps";
import Checkbox from "../common/Checkbox.svelte"; import Checkbox from "../common/Checkbox.svelte";
import Textbox from "../common/Textbox.svelte"; import Textbox from "../common/Textbox.svelte";
import Dropdown from "../common/Dropdown.svelte"; import Dropdown from "../common/Dropdown.svelte";
import { validateProps } from "./pagesParsing/validateProps";
import PropControl from "./PropControl.svelte"; import PropControl from "./PropControl.svelte";
import IconButton from "../common/IconButton.svelte"; import IconButton from "../common/IconButton.svelte";
export let shouldValidate = true;
export let onValidate = () => {};
export let componentInfo; export let componentInfo;
export let instanceProps = null; export let instanceProps = null;
export let onPropsChanged = () => {}; export let onPropsChanged = () => {};
export let components;
let errors = []; let errors = [];
let props = {}; let props = {};
let propsDefinitions = []; let propsDefinitions = [];
let isInstance = false; let isInstance = false;
$: { const props_to_ignore = ['_component','_children', '_layout'];
if(componentInfo)
{
isInstance = !!instanceProps;
props = isInstance
? getInstanceProps(componentInfo, instanceProps)
: cloneDeep(componentInfo.fullProps);
propsDefinitions = pipe(componentInfo.propsDefinition.props, [ $: propDefs = componentInfo && Object.entries(componentInfo).filter(([name])=> !props_to_ignore.includes(name));
keys,
map(k => ({...componentInfo.propsDefinition[k], ____name:k})),
sortBy("____name")
]);
}
}
function find_type(prop_name) {
if(!componentInfo._component) return;
return components.find(({name}) => name === componentInfo._component).props[prop_name];
}
let setProp = (name, value) => { let setProp = (name, value) => {
const newProps = cloneDeep(props); onPropsChanged(name, value);
let finalProps = isInstance ? newProps : cloneDeep(componentInfo.component.props ? componentInfo.component.props : componentInfo.component);
if(!isInstance) {
const nowSet = [];
for(let p of componentInfo.unsetProps) {
if(!isEqual(newProps[p])(componentInfo.rootDefaultProps[p])) {
finalProps[p] = newProps[p];
nowSet.push(p);
}
}
componentInfo.unsetProps = difference(nowSet)(componentInfo.unsetProps);
}
newProps[name] = value;
finalProps[name] = value;
props = newProps;
if(validate(finalProps))
onPropsChanged(finalProps);
}
const validate = (finalProps) => {
errors = validateProps(componentInfo.rootComponent, finalProps, [], false);
onValidate(errors);
return errors.length === 0;
} }
const fieldHasError = (propName) => const fieldHasError = (propName) =>
@ -80,14 +44,14 @@ const fieldHasError = (propName) =>
<div class="root"> <div class="root">
<form class="uk-form-stacked form-root"> <form class="uk-form-stacked form-root">
{#each propsDefinitions as propDef, index} {#each propDefs as [prop_name, prop_value], index}
<div class="prop-container"> <div class="prop-container">
<PropControl {setProp} <PropControl {setProp}
{fieldHasError} {prop_name}
{propDef} {prop_value}
{props} prop_type={find_type(prop_name)}
{index} {index}
disabled={false} /> disabled={false} />