diff --git a/packages/builder/package.json b/packages/builder/package.json index 5566e7e036..9595da46f6 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -6,6 +6,7 @@ "build": "rollup -c", "start": "rollup -c -w", "test": "jest", + "test:watch": "jest --watchAll", "dev:builder": "rollup -c -w" }, "jest": { diff --git a/packages/builder/rollup.config.js b/packages/builder/rollup.config.js index b5cc54873d..67507a5cfd 100644 --- a/packages/builder/rollup.config.js +++ b/packages/builder/rollup.config.js @@ -11,34 +11,34 @@ import browsersync from "rollup-plugin-browsersync"; import proxy from "http-proxy-middleware"; const target = 'http://localhost:4001'; -const _builderProxy = proxy('/_builder', { - target:"http://localhost:3000", - pathRewrite: {'^/_builder' : ''} +const _builderProxy = proxy('/_builder', { + target: "http://localhost:3000", + pathRewrite: { '^/_builder': '' } }); -const apiProxy = proxy(['/_builder/api/**', '/_builder/**/componentlibrary', '/_builder/**/componentlibraryGenerators'] , { +const apiProxy = proxy(['/_builder/api/**', '/_builder/**/componentlibrary', '/_builder/**/componentlibraryGenerators'], { target, logLevel: "debug", changeOrigin: true, cookieDomainRewrite: true, onProxyReq(proxyReq) { - if (proxyReq.getHeader("origin")) { - proxyReq.setHeader("origin", target) - } + if (proxyReq.getHeader("origin")) { + proxyReq.setHeader("origin", target) + } } - }); +}); 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", "isInteger", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", "isNaN", -"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", "flattenDeep", "indexOf", "isPlainObject", -"toNumber", "takeRight"]; +const lodash_fp_exports = ["union", "reduce", "isUndefined", "cloneDeep", "split", "some", "map", "filter", "isEmpty", "countBy", "includes", "last", "find", "constant", + "take", "first", "intersection", "mapValues", "isNull", "has", "isInteger", "isNumber", "isString", "isBoolean", "isDate", "isArray", "isObject", "clone", "values", "keyBy", "isNaN", + "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", "flattenDeep", "indexOf", "isPlainObject", + "toNumber", "takeRight", "toPairs"]; -const lodash_exports = ["flow", "join", "replace", "trim", "dropRight", "takeRight", "head", "reduce", -"tail", "startsWith", "findIndex", "merge", -"assign", "each", "find", "orderBy", "union"]; +const lodash_exports = ["flow", "join", "replace", "trim", "dropRight", "takeRight", "head", "reduce", + "tail", "startsWith", "findIndex", "merge", + "assign", "each", "find", "orderBy", "union"]; const outputpath = "../server/builder"; @@ -63,7 +63,7 @@ export default { { src: 'src/favicon.png', dest: outputpath }, { src: 'src/assets', dest: outputpath }, { src: 'node_modules/@budibase/client/dist/budibase-client.esm.mjs', dest: outputpath }, - ] + ] }), svelte({ @@ -80,28 +80,28 @@ export default { resolve({ browser: true, dedupe: importee => { - return importee === 'svelte' - || importee.startsWith('svelte/') - || coreExternal.includes(importee); + return importee === 'svelte' + || importee.startsWith('svelte/') + || coreExternal.includes(importee); } - + }), commonjs({ namedExports: { "lodash/fp": lodash_fp_exports, - "lodash":lodash_exports, + "lodash": lodash_exports, "shortid": ["generate"] } }), url({ - limit: 0, - include: ["**/*.woff2", "**/*.png"], + limit: 0, + include: ["**/*.woff2", "**/*.png"], fileName: "[dirname][name][extname]", emitFiles: true }), url({ - limit: 0, - include: ["**/*.css"], + limit: 0, + include: ["**/*.css"], fileName: "[name][extname]", emitFiles: true }), @@ -113,7 +113,7 @@ export default { !production && livereload(outputpath), !production && browsersync({ server: outputpath, - middleware: [apiProxy,_builderProxy] + middleware: [apiProxy, _builderProxy] }), // If we're building for production (npm run build diff --git a/packages/builder/src/builderStore/generate_css.js b/packages/builder/src/builderStore/generate_css.js new file mode 100644 index 0000000000..29ddb16245 --- /dev/null +++ b/packages/builder/src/builderStore/generate_css.js @@ -0,0 +1,118 @@ +import { filter, map, reduce, toPairs } from "lodash/fp"; +import { pipe } from "../common/core"; + +const self = n => n; +const join_with = delimiter => a => a.join(delimiter); +const empty_string_to_unset = s => s.length ? s : "0"; +const add_suffix = suffix => s => s + suffix; + +export const make_margin = (values) => pipe(values, [ + map(empty_string_to_unset), + map(add_suffix('px')), + join_with(' ') +]); + +const tap = message => x => { + console.log(x); + return x; +} + +const css_map = { + templaterows: { + name: 'grid-template-columns', + generate: self + }, + templatecolumns: { + name: 'grid-template-rows', + generate: self + }, + gridarea: { + name: 'grid-area', + generate: make_margin + }, + gap: { + name: 'grid-gap', + generate: n => `${n}px` + }, + columnstart: { + name: 'grid-column-start', + generate: self + }, + columnend: { + name: 'grid-column-end', + generate: self + }, + rowstart: { + name: 'grid-row-start', + generate: self + }, + rowend: { + name: 'grid-row-end', + generate: self + }, + padding: { + name: 'padding', + generate: make_margin + }, + margin: { + name: 'margin', + generate: make_margin + }, + zindex: { + name: 'z-index', + generate: self + } +} + +export const generate_rule = ([name, values]) => + `${css_map[name].name}: ${css_map[name].generate(values)};` + +const handle_grid = (acc, [name, value]) => { + let tmp = []; + + if (name === 'row' || name === 'column') { + if (value[0]) tmp.push([`${name}start`, value[0]]); + if (value[1]) tmp.push([`${name}end`, value[1]]); + return acc.concat(tmp) + } + + return acc.concat([[name, value]]); +} + +const object_to_css_string = [ + toPairs, + reduce(handle_grid, []), + filter(v => Array.isArray(v[1]) ? v[1].some(s => s.length) : v[1].length), + map(generate_rule), + join_with('\n'), +]; + +export const generate_css = ({ layout, position }) => { + let _layout = pipe(layout, object_to_css_string); + _layout = _layout.length ? _layout + "\ndisplay: grid;" : _layout; + + return { + layout: _layout, + position: pipe(position, object_to_css_string) + } +} + +const apply_class = (id, name, styles) => `.${name}-${id} {\n${styles}\n}`; + +export const generate_screen_css = (component_array) => { + let styles = ""; + + for (let i = 0; i < component_array.length; i += 1) { + const { _styles, _id, _children } = component_array[i]; + const { layout, position } = generate_css(_styles); + + styles += apply_class(_id, 'pos', position) + "\n"; + styles += apply_class(_id, 'lay', layout) + "\n"; + + if (_children && _children.length) { + styles += generate_screen_css(_children) + "\n"; + } + + } + return styles.trim(); +} diff --git a/packages/builder/src/builderStore/store.js b/packages/builder/src/builderStore/store.js index 0975671073..c9dc3da87b 100644 --- a/packages/builder/src/builderStore/store.js +++ b/packages/builder/src/builderStore/store.js @@ -4,7 +4,7 @@ import { import { filter, cloneDeep, sortBy, map, last, keys, concat, keyBy, - find, isEmpty, reduce, values, isEqual + find, isEmpty, values, } from "lodash/fp"; import { pipe, getNode, validate, @@ -17,11 +17,13 @@ import api from "./api"; import { isRootComponent, getExactComponent } from "../userInterface/pagesParsing/searchComponents"; import { rename } from "../userInterface/pagesParsing/renameScreen"; import { - getNewComponentInfo, getScreenInfo, getComponentInfo + getNewComponentInfo, getScreenInfo, } from "../userInterface/pagesParsing/createProps"; import { loadLibs, loadLibUrls, loadGeneratorLibs } from "./loadComponentLibraries"; +import { uuid } from './uuid'; +import { generate_screen_css } from './generate_css'; let appname = ""; @@ -710,7 +712,8 @@ const addChildComponent = store => component => { const component_definition = Object.assign( cloneDeep(newComponent.fullProps), { _component: component, - _layout: {} + _styles: { position: {}, layout: {} }, + _id: uuid() }) if (children) { @@ -729,6 +732,8 @@ const addChildComponent = store => component => { _saveScreen(store, s, s.currentFrontEndItem); + _saveScreen(store, s, s.currentFrontEndItem); + return s; }) } @@ -751,12 +756,13 @@ const setComponentProp = store => (name, value) => { }) } -const setComponentStyle = store => (name, value) => { +const setComponentStyle = store => (type, name, value) => { store.update(s => { - if (!s.currentComponentInfo._layout) { - s.currentComponentInfo._layout = {}; + if (!s.currentComponentInfo._styles) { + s.currentComponentInfo._styles = {}; } - s.currentComponentInfo._layout[name] = value; + s.currentComponentInfo._styles[type][name] = value; + s.currentFrontEndItem._css = generate_screen_css(s.currentFrontEndItem.props._children) // save without messing with the store _save(s.appname, s.currentFrontEndItem, store, s) diff --git a/packages/builder/src/builderStore/uuid.js b/packages/builder/src/builderStore/uuid.js new file mode 100644 index 0000000000..79ad68af94 --- /dev/null +++ b/packages/builder/src/builderStore/uuid.js @@ -0,0 +1,7 @@ +export function uuid() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0, + v = c == 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} diff --git a/packages/builder/src/common/Inputs/InputGroup.svelte b/packages/builder/src/common/Inputs/InputGroup.svelte index 55bede83f2..22a272aec4 100644 --- a/packages/builder/src/common/Inputs/InputGroup.svelte +++ b/packages/builder/src/common/Inputs/InputGroup.svelte @@ -2,6 +2,7 @@ export let meta = []; export let size = ''; export let values = []; + export let type = "number"; export let onStyleChanged = () => {}; let _values = values.map(v => v); @@ -11,7 +12,7 @@