diff --git a/packages/builder/.vscode/launch.json b/packages/builder/.vscode/launch.json new file mode 100644 index 0000000000..f6b35a0b63 --- /dev/null +++ b/packages/builder/.vscode/launch.json @@ -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}" + } + ] +} \ No newline at end of file diff --git a/packages/builder/rollup.config.js b/packages/builder/rollup.config.js index 834e0b9a9b..c0869fbdba 100644 --- a/packages/builder/rollup.config.js +++ b/packages/builder/rollup.config.js @@ -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", diff --git a/packages/builder/src/common/Button.svelte b/packages/builder/src/common/Button.svelte index 7bd6f8e96e..6254a9f4bf 100644 --- a/packages/builder/src/common/Button.svelte +++ b/packages/builder/src/common/Button.svelte @@ -14,7 +14,7 @@ $: borderClass = grouped diff --git a/packages/builder/src/common/IconButton.svelte b/packages/builder/src/common/IconButton.svelte index 43a4ea8f58..5880cd90bc 100644 --- a/packages/builder/src/common/IconButton.svelte +++ b/packages/builder/src/common/IconButton.svelte @@ -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() {} + } +} + diff --git a/packages/builder/src/common/Textbox.svelte b/packages/builder/src/common/Textbox.svelte index 86e1264542..92eb542743 100644 --- a/packages/builder/src/common/Textbox.svelte +++ b/packages/builder/src/common/Textbox.svelte @@ -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; -
+
- +
+ {#if infoText} +
{infoText}
+ {/if}
+ + diff --git a/packages/builder/src/userInterface/ComponentSearch.svelte b/packages/builder/src/userInterface/ComponentSearch.svelte index 75a9ac25d6..fb182ec722 100644 --- a/packages/builder/src/userInterface/ComponentSearch.svelte +++ b/packages/builder/src/userInterface/ComponentSearch.svelte @@ -16,7 +16,14 @@ $: filteredComponents =
- + +
{#each filteredComponents as component}
onComponentChosen(component)}> diff --git a/packages/builder/src/userInterface/NewComponent.svelte b/packages/builder/src/userInterface/NewComponent.svelte index 655ad0e53a..2d0af23280 100644 --- a/packages/builder/src/userInterface/NewComponent.svelte +++ b/packages/builder/src/userInterface/NewComponent.svelte @@ -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); } - -
-
- {#if basedOnComponent} - - - - - {:else} - - -
+
+
+ +
+

New Component

+
+ +
+ + {#if componentInfo} + + +
+ + +

Properties

+ + + + {:else} + + -
- - {/if} - + onComponentChosen={onBasedOnChosen($store.allComponents)} /> + + + {/if} + +
+ {#if component} + + {/if}
- +
\ No newline at end of file diff --git a/packages/builder/src/userInterface/PropsView.svelte b/packages/builder/src/userInterface/PropsView.svelte index b1973dd21d..6637a9e462 100644 --- a/packages/builder/src/userInterface/PropsView.svelte +++ b/packages/builder/src/userInterface/PropsView.svelte @@ -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);
-
{component.name}
-
{component.description || ""}
- {#each propsDefinition as propDef} -
+ {#if showTitle=true} +
{componentInfo.component.name}
+
{componentInfo.component.description || ""}
+ {/if} + {#each propsDefinitionArray as propDef} + {#if propDef.type === "bool"} - + {:else if propDef.type === "options"} - + {:else} - + {/if} {/each} @@ -65,12 +121,12 @@ let setProp = (name) => (ev) => \ No newline at end of file diff --git a/packages/builder/src/userInterface/UserInterfaceRoot.svelte b/packages/builder/src/userInterface/UserInterfaceRoot.svelte index 5a802130f6..3f082b5510 100644 --- a/packages/builder/src/userInterface/UserInterfaceRoot.svelte +++ b/packages/builder/src/userInterface/UserInterfaceRoot.svelte @@ -27,7 +27,8 @@ const newComponent = () => { COMPONENTS
+ on:click={newComponent} + attributes={{"uk-toggle" : "target: #new-component-modal" }}/>
- +