Browse Source

state binding working

pull/14/head
Michael Shanks 7 years ago
parent
commit
2e6a34c687
  1. 3
      packages/builder/package.json
  2. 3
      packages/builder/rollup.config.js
  3. 11
      packages/builder/src/builderStore/loadComponentLibraries.js
  4. 28
      packages/builder/src/builderStore/store.js
  5. 1
      packages/builder/src/common/eventHandlers.js
  6. 23
      packages/builder/src/userInterface/ComponentInstanceEditor.svelte
  7. 61
      packages/builder/src/userInterface/CurrentItemPreview.svelte
  8. 23
      packages/builder/src/userInterface/EditComponent.svelte
  9. 5
      packages/builder/src/userInterface/EventListSelector.svelte
  10. 16
      packages/builder/src/userInterface/EventSelector.svelte
  11. 3
      packages/builder/src/userInterface/pagesParsing/buildPropsHierarchy.js
  12. 2
      packages/builder/src/userInterface/pagesParsing/createProps.js
  13. 6
      packages/builder/src/userInterface/pagesParsing/types.js
  14. 1
      packages/builder/src/userInterface/pagesParsing/validateProps.js
  15. 4
      packages/client/rollup.config.js
  16. 10
      packages/client/src/createApp.js
  17. 29
      packages/client/src/index.js
  18. 26
      packages/client/src/state/eventHandlers.js
  19. 34
      packages/client/src/state/getState.js
  20. 33
      packages/client/src/state/setState.js
  21. 118
      packages/client/src/state/stateBinding.js
  22. 59
      packages/client/src/stateBinding.js
  23. 146
      packages/client/tests/stateBinding.spec.js
  24. 2
      packages/server/appPackages/_master/public/main/budibase-client.js
  25. 2
      packages/server/appPackages/_master/public/unauthenticated/budibase-client.js
  26. 2
      packages/server/appPackages/testApp/public/main/budibase-client.js
  27. 2
      packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js
  28. 75
      packages/server/appPackages/testApp2/appDefinition.json
  29. 37
      packages/server/appPackages/testApp2/components/Button in the middle.json
  30. 4
      packages/server/appPackages/testApp2/components/Primary Button.json
  31. 5
      packages/server/appPackages/testApp2/components/containers/two_columns.json
  32. 65
      packages/server/appPackages/testApp2/components/mike.json
  33. 10
      packages/server/appPackages/testApp2/pages.json
  34. 3
      packages/server/appPackages/testApp2/public/main/budibase-client.js
  35. 2
      packages/server/appPackages/testApp2/public/main/budibase-client.js.map
  36. 2
      packages/server/appPackages/testApp2/public/main/clientAppDefinition.js
  37. 18
      packages/server/appPackages/testApp2/public/main/index.html
  38. 3
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js
  39. 2
      packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js.map
  40. 2
      packages/server/appPackages/testApp2/public/unauthenticated/clientAppDefinition.js
  41. 18
      packages/server/appPackages/testApp2/public/unauthenticated/index.html
  42. 2
      packages/server/builder/budibase-client.esm.mjs
  43. 30
      packages/server/builder/bundle.css
  44. 70
      packages/server/builder/bundle.css.map
  45. 638
      packages/server/builder/bundle.js
  46. 2
      packages/server/builder/bundle.js.map
  47. 4
      packages/server/utilities/builder/index.template.html
  48. 1
      packages/standard-components/dist/index.js.map
  49. 7
      packages/standard-components/rollup.config.js
  50. 9
      packages/standard-components/src/button.svelte

3
packages/builder/package.json

@ -33,6 +33,7 @@
]
},
"dependencies": {
"@budibase/client": "*",
"@nx-js/compiler-util": "^2.0.0",
"date-fns": "^1.29.0",
"feather-icons": "^4.21.0",
@ -43,7 +44,7 @@
"shortid": "^2.2.8",
"string_decoder": "^1.2.0",
"uikit": "^3.1.7"
},
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/plugin-transform-runtime": "^7.5.5",

3
packages/builder/rollup.config.js

@ -59,7 +59,8 @@ export default {
copy({
targets: [
{ src: 'src/index.html', dest: outputpath },
{ src: 'src/favicon.png', dest: outputpath }
{ src: 'src/favicon.png', dest: outputpath },
{ src: 'node_modules/@budibase/client/dist/budibase-client.esm.mjs', dest: outputpath }
]
}),

11
packages/builder/src/builderStore/loadComponentLibraries.js

@ -11,6 +11,17 @@ export const loadLibs = async (appName, appPackage) => {
return allLibraries;
}
export const loadLibUrls = (appName, appPackage) => {
const allLibraries = [];
for(let lib of appPackage.pages.componentLibraries) {
const libUrl = makeLibraryUrl(appName, lib);
allLibraries.push({libName:lib, importPath:libUrl});
}
return allLibraries;
}
export const loadLib = async (appName, lib, allLibs) => {
allLibs[lib] = await import(makeLibraryUrl(appName, lib));
return allLibs;

28
packages/builder/src/builderStore/store.js

@ -1,26 +1,14 @@
import {
hierarchy as hierarchyFunctions,
common
} from "../../../core/src";
import {
filter,
cloneDeep,
sortBy,
map,
last,
keys,
concat,
find,
isEmpty,
groupBy,
reduce
filter, cloneDeep, sortBy,
map, last, keys, concat,
find, isEmpty, reduce
} from "lodash/fp";
import {
pipe,
getNode,
validate,
constructHierarchy,
templateApi
pipe, getNode, validate,
constructHierarchy, templateApi
} from "../common/core";
import {writable} from "svelte/store";
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
@ -28,10 +16,9 @@ import { buildPropsHierarchy } from "../userInterface/pagesParsing/buildPropsHie
import api from "./api";
import { isRootComponent } from "../userInterface/pagesParsing/searchComponents";
import {
getComponentInfo,
getNewComponentInfo
getComponentInfo, getNewComponentInfo
} from "../userInterface/pagesParsing/createProps";
import { loadLibs } from "./loadComponentLibraries";
import { loadLibs, loadLibUrls } from "./loadComponentLibraries";
let appname = "";
@ -117,6 +104,7 @@ const initialise = (store, initial) => async () => {
.then(r => r.json());
initial.libraries = await loadLibs(appname, pkg);
initial.loadLibraryUrls = () => loadLibUrls(appname, pkg);
initial.appname = appname;
initial.pages = pkg.pages;
initial.hasAppPackage = true;

1
packages/builder/src/common/eventHandlers.js

@ -0,0 +1 @@
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";

23
packages/builder/src/userInterface/ComponentInstanceEditor.svelte

@ -10,7 +10,7 @@ import {
} from "lodash/fp";
import { fade, slide } from 'svelte/transition';
export let propertyName = "";
export let title = "";
export let onGoBack = () => {};
export let instanceProps = {};
export let onPropsChanged = () => {};
@ -18,6 +18,9 @@ export let onPropsChanged = () => {};
let editingSubComponentName;
let editingSubComponentProps;
let editingSubComponentArrayIndex;
let editingSubComponentArrayPropName;
let editingSubComponentTitle;
let allComponents;
store.subscribe(s => {
@ -33,18 +36,28 @@ const onSubComponentGoBack = () => {
}
const onEditComponentProp = (propName, arrayIndex, arrayPropName) => {
editingSubComponentName = isUndefined(arrayIndex)
editingSubComponentName = propName;
editingSubComponentTitle = isUndefined(arrayIndex)
? propName
: `${propName}[${arrayIndex}].${arrayPropName}`;
editingSubComponentProps = isUndefined(arrayIndex)
? instanceProps[propName]
: instanceProps[propName][arrayIndex][arrayPropName];
editingSubComponentArrayIndex = arrayIndex;
editingSubComponentArrayPropName = arrayPropName;
};
const onSubComponentPropsChanged = (subProps) => {
const newProps = cloneDeep(instanceProps);
newProps[editingSubComponentName] = subProps;
if(isUndefined(editingSubComponentArrayIndex)) {
newProps[editingSubComponentName] = subProps;
} else {
newProps[editingSubComponentName]
[editingSubComponentArrayIndex]
[editingSubComponentArrayPropName] = subProps;
}
instanceProps = newProps;
onPropsChanged(newProps);
}
@ -62,7 +75,7 @@ const propsChanged = newProps => {
<div class="title">
<IconButton icon="chevron-left"
on:click={onGoBack}/>
<span>{propertyName}</span>
<span>{title}</span>
</div>
{#if editingSubComponentName}
@ -71,7 +84,7 @@ const propsChanged = newProps => {
<svelte:self onPropsChanged={onSubComponentPropsChanged}
onGoBack={onSubComponentGoBack}
instanceProps={editingSubComponentProps}
propertyName={editingSubComponentName} />
title={editingSubComponentTitle} />
</div>
{:else}
<PropsView {instanceProps}

61
packages/builder/src/userInterface/CurrentItemPreview.svelte

@ -2,79 +2,47 @@
import { store } from "../builderStore";
import { makeLibraryUrl } from "../builderStore/loadComponentLibraries";
import {
last,
split,
map,
join
last, split, map, join
} from "lodash/fp";
import { pipe } from "../common/core";
import { splitName } from "./pagesParsing/splitRootComponentName"
import { afterUpdate } from 'svelte';
import { getRootComponent } from "./pagesParsing/getRootComponent";
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy";
if(!window.budibaseIframeConnector) {
window.budibaseIframeConnector = {
initialiseComponent(props, htmlElement) {
const rootComponent = getRootComponent(
props._component, allComponents);
const {componentName, libName} = splitName(
rootComponent.name);
new (libraries[libName][componentName])({
target: htmlElement,
props: {...props, _app: window.budibaseIframeConnector}
});
}
}
}
let component;
let stylesheetLinks = "";
let componentHtml = "";
let props;
let componentLibraryUrl = "";
let rootComponentName = "";
let iframe;
let libraries;
let allComponents;
let appDefinition = {};
store.subscribe(s => {
const {componentName, libName} = splitName(
s.currentComponentInfo.rootComponent.name);
rootComponentName = componentName;
props = s.currentComponentInfo.fullProps;
component = s.libraries[libName][componentName];
stylesheetLinks = pipe(s.pages.stylesheets, [
map(s => `<link rel="stylesheet" href="${s}"/>`),
join("\n")
]);
componentLibraryUrl = makeLibraryUrl(s.appname, libName);
appDefinition = {
componentLibraries: s.loadLibraryUrls(),
props: buildPropsHierarchy(s.allComponents, s.currentFrontEndItem)
};
libraries = s.libraries;
allComponents = s.allComponents;
});
/*
afterUpdate(() => {
if(iframe) iframeLoaded();
});
*/
const iframeLoaded = () => {
setTimeout(() => {
iframe.style.height = (iframe.contentWindow.document.body.scrollHeight + 1).toString() + "px";
iframe.style.width = (iframe.contentWindow.document.body.scrollWidth + 1).toString() + "px";
}, 100);
}
</script>
<div class="component-preview" >
<div class="component-container">
<iframe bind:this={iframe}
on:load={iframeLoaded}
<iframe style="height: 100%; width: 100%"
title="componentPreview"
srcdoc={
`<html>
@ -82,16 +50,11 @@ const iframeLoaded = () => {
<head>
${stylesheetLinks}
<script>
import('${componentLibraryUrl}')
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)};
import('./budibase-client.esm.mjs')
.then(module => {
const componentClass = module['${rootComponentName}'];
const instance = new componentClass({
target: document.body,
props: {...${JSON.stringify(props)}, _app: window.parent.budibaseIframeConnector}
}) ;
})
module.loadBudibase();
})
</script>
</head>
<body>

23
packages/builder/src/userInterface/EditComponent.svelte

@ -36,6 +36,10 @@ let modalElement
let propsValidationErrors = [];
let editingComponentInstance;
let editingComponentInstancePropName="";
let editingComponentArrayIndex;
let editingComponentArrayPropName;
let editingComponentInstanceTitle;
let allComponents;
$: shortName = last(name.split("/"));
@ -116,9 +120,13 @@ const onEditComponentProp = (propName, arrayIndex, arrayPropName) => {
editingComponentInstance = isUndefined(arrayIndex)
? component.props[propName]
: component.props[propName][arrayIndex][arrayPropName];
editingComponentInstancePropName = isUndefined(arrayIndex)
editingComponentInstancePropName = propName;
editingComponentInstanceTitle = isUndefined(arrayIndex)
? propName
: `${propName}[${arrayIndex}].${arrayPropName}`;
editingComponentArrayIndex = arrayIndex;
editingComponentArrayPropName = arrayPropName;
}
const componentInstanceCancelEdit = () => {
@ -127,8 +135,15 @@ const componentInstanceCancelEdit = () => {
}
const componentInstancePropsChanged = (instanceProps) => {
updateComponent(newComponent =>
newComponent.props[editingComponentInstancePropName] = instanceProps);
updateComponent(newComponent => {
if(isUndefined(editingComponentArrayIndex)) {
newComponent.props[editingComponentInstancePropName] = instanceProps;
} else {
newComponent.props[editingComponentInstancePropName]
[editingComponentArrayIndex]
[editingComponentArrayPropName] = instanceProps;
}
});
}
</script>
@ -151,7 +166,7 @@ const componentInstancePropsChanged = (instanceProps) => {
{#if editingComponentInstance}
<ComponentInstanceEditor onGoBack={componentInstanceCancelEdit}
propertyName={editingComponentInstancePropName}
title={editingComponentInstanceTitle}
instanceProps={editingComponentInstance}
onPropsChanged={componentInstancePropsChanged}/>
{:else}

5
packages/builder/src/userInterface/EventListSelector.svelte

@ -4,7 +4,7 @@ import EventSelector from "./EventSelector.svelte";
import {
filter
} from "lodash/fp";
import {EVENT_TYPE_MEMBER_NAME} from "../common/eventHandlers";
export let parentProps;
export let propDef;
export let onValueChanged;
@ -18,7 +18,8 @@ $: {
}
const addHandler = () => {
const newHandler = {handlerType:"", parameters:{}};
const newHandler = {parameters:{}};
newHandler[EVENT_TYPE_MEMBER_NAME] = "";
events = [...events, newHandler];
onValueChanged(events);
}

16
packages/builder/src/userInterface/EventSelector.svelte

@ -5,6 +5,7 @@ import {
find, map, keys, reduce
} from "lodash/fp";
import { pipe } from "../common/core";
import { EVENT_TYPE_MEMBER_NAME } from "../common/eventHandlers";
export let event;
export let onChanged;
@ -21,7 +22,7 @@ let parameters = [];
$: {
if(event) {
eventType = event.handlerType;
eventType = event[EVENT_TYPE_MEMBER_NAME];
parameters = pipe(event.parameters, [
keys,
map(k => ({name:k, value:event.parameters[k]}))
@ -41,10 +42,11 @@ const eventChanged = (type, parameters) => {
, {}
)(parameters)
onChanged({
handlerType:type,
parameters: paramsAsObject
});
const ev = {};
ev[EVENT_TYPE_MEMBER_NAME]=type;
ev.parameters = paramsAsObject;
onChanged(ev);
}
const eventTypeChanged = (ev) => {
@ -53,9 +55,9 @@ const eventTypeChanged = (ev) => {
eventChanged(eType.name, emptyParameters);
}
const onParameterChanged = index => ev => {
const onParameterChanged = index => val => {
const newparameters = [...parameters];
newparameters[index].value = ev.target.value;
newparameters[index].value = val;
eventChanged(eventType, newparameters);
}

3
packages/builder/src/userInterface/pagesParsing/buildPropsHierarchy.js

@ -1,7 +1,6 @@
import {
getComponentInfo, createProps, getInstanceProps
} from "./createProps";
import { cloneDeep } from "lodash/fp";
export const buildPropsHierarchy = (allComponents, baseComponent) => {
@ -39,7 +38,7 @@ export const buildPropsHierarchy = (allComponents, baseComponent) => {
for(let element of propsArray) {
newPropsArray.push(
buildProps(
`${propName}[${index}]`,
`${propName}#array_element#`,
propDef.elementDefinition,
element));
index++;

2
packages/builder/src/userInterface/pagesParsing/createProps.js

@ -150,7 +150,7 @@ export const createProps = (componentName, propsDefinition, derivedFromProps) =>
export const createArrayElementProps = (arrayPropName, elementDefinition) =>
createProps(
`#element#${arrayPropName}`,
`#${arrayPropName}#array_element`,
elementDefinition);
const parsePropDef = propDef => {

6
packages/builder/src/userInterface/pagesParsing/types.js

@ -8,6 +8,10 @@ import {
every
} from "lodash/fp";
import {
EVENT_TYPE_MEMBER_NAME
} from "../../common/eventHandlers";
const defaultDef = typeName => () => ({
type: typeName,
required:false,
@ -51,7 +55,7 @@ export const expandPropsDefinition = propsDefinition => {
const isComponent = isObjectLike;
const isEvent = e =>
isPlainObject(e)
&& isString(e.handlerType)
&& isString(e[EVENT_TYPE_MEMBER_NAME])
&& isPlainObject(e.parameters);
const isEventList = e =>

1
packages/builder/src/userInterface/pagesParsing/validateProps.js

@ -145,7 +145,6 @@ export const validateProps = (propsDefinition, props, stack=[], isFinal=true) =>
if(propDef.type === "array") {
let index = 0;
for(let arrayItem of propValue) {
arrayItem._component = arrayElementComponentName(props._component, propDefName);
const arrayErrs = validateProps(
propDef.elementDefinition,
arrayItem,

4
packages/client/rollup.config.js

@ -6,8 +6,8 @@ import { terser } from 'rollup-plugin-terser';
const lodash_fp_exports = [
"find", "isUndefined", "split",
"last", "union", "reduce",
"cloneDeep", "some"];
"last", "union", "reduce", "isObject",
"cloneDeep", "some", "isArray"];
const lodash_exports = [
"flow","reduce", "constant", "head", "isEmpty",

10
packages/client/src/createApp.js

@ -4,7 +4,7 @@ import {
} from "lodash/fp";
import {writable} from "svelte/store";
import { $ } from "./core/common";
import { bindComponent } from "./stateBinding";
import { setupBinding } from "./state/stateBinding";
export const createApp = componentLibraries => {
@ -12,12 +12,16 @@ export const createApp = componentLibraries => {
const {componentName, libName} = splitName(props._component);
if(!componentName || !libName) return;
const {initialProps, bind} = setupBinding(store, props);
const component = new (componentLibraries[libName][componentName])({
target: htmlElement,
props: {...props, _app}
props: {...initialProps, _app}
});
bindComponent(store, component);
bind(component);
}

29
packages/client/src/index.js

@ -1,25 +1,32 @@
import { createApp } from "./createApp";
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
export const loadBudibase = async (componentLibraries, props) => {
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
(async () => {
const componentLibraries = {};
if(!componentLibraries) {
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');
componentLibraries = {};
for(let lib of appDefinition.componentLibraries) {
componentLibraries[lib.libName] = await import(
componentLibraryUrl(lib.importPath));
}
for(let lib of appDefinition.componentLibraries) {
componentLibraries[lib.libName] = await import(
componentLibraryUrl(lib.importPath));
}
if(!props) {
props = appDefinition.props;
}
const _app = createApp(componentLibraries);
_app.initialiseComponent(
props,
document.body);
})();
};
window.loadBudibase = loadBudibase;

26
packages/client/src/state/eventHandlers.js

@ -0,0 +1,26 @@
import {
setState
} from "./setState";
import {
isArray, isUndefined
} from "lodash/fp";
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";
export const eventHandlers = store => {
const handler = (parameters, execute) => ({
execute, parameters
});
const setStateHandler = ({path, value}) => setState(store, path, value);
return {
"Set State": handler(["path", "value"], setStateHandler)
};
};
export const isEventType = prop =>
isArray(prop)
&& prop.length > 0
&& !isUndefined(prop[0][EVENT_TYPE_MEMBER_NAME]);

34
packages/client/src/state/getState.js

@ -0,0 +1,34 @@
import {
isUndefined,
isObject
} from "lodash/fp";
export const getState = (s, path, fallback) => {
const pathParts = path.split(".");
const safeGetPath = (obj, currentPartIndex=0) => {
const currentKey = pathParts[currentPartIndex];
if(pathParts.length - 1 == currentPartIndex) {
const value = obj[currentKey];
if(isUndefined(value))
return fallback;
else
return value;
}
if(obj[currentKey] === null
|| obj[currentKey] === undefined
|| !isObject(obj[currentKey])) {
return fallback;
}
return safeGetPath(obj[currentKey], currentPartIndex + 1);
}
return safeGetPath(s);
}

33
packages/client/src/state/setState.js

@ -0,0 +1,33 @@
import {
isObject
} from "lodash/fp";
export const setState = (store, path, value) => {
const pathParts = path.split(".");
const safeSetPath = (obj, currentPartIndex=0) => {
const currentKey = pathParts[currentPartIndex];
if(pathParts.length - 1 == currentPartIndex) {
obj[currentKey] = value;
return;
}
if(obj[currentKey] === null
|| obj[currentKey] === undefined
|| !isObject(obj.currentKey)) {
obj[currentKey] = {};
}
safeSetPath(obj[currentKey], currentPartIndex + 1);
}
store.update(s => {
safeSetPath(s);
return s;
});
}

118
packages/client/src/state/stateBinding.js

@ -0,0 +1,118 @@
import {
isEventType, eventHandlers, EVENT_TYPE_MEMBER_NAME
} from "./eventHandlers";
import {
getState
} from "./getState";
export const BB_STATE_BINDINGPATH = "##bbstate";
export const BB_STATE_FALLBACK = "##bbstatefallback";
const doNothing = () => {};
export const setupBinding = (store, props) => {
const initialProps = {...props};
const boundProps = [];
const componentEventHandlers = [];
for(let propName in props) {
const val = initialProps[propName];
if(isState(val)) {
const binding = stateBinding(val);
const fallback = stateFallback(val);
boundProps.push({
stateBinding:binding,
fallback, propName
});
initialProps[propName] = fallback;
} else if(isEventType(val)) {
const handlers = { propName, handlers:[] };
componentEventHandlers.push(handlers);
for(let e of val) {
handlers.handlers.push({
handlerType: e[EVENT_TYPE_MEMBER_NAME],
parameters: e.parameters
})
}
initialProps[propName] = doNothing;
}
}
const bind = (component) => {
if(boundProps.length === 0 && componentEventHandlers.length === 0) return;
const handlerTypes = eventHandlers(store);
const unsubscribe = store.subscribe(s => {
const newProps = {};
for(let boundProp of boundProps) {
const val = getState(
s,
boundProp.stateBinding,
boundProp.fallback);
if(val === undefined && newProps[boundProp.propName] !== undefined) {
delete newProps[boundProp.propName];
}
if(val !== undefined) {
newProps[boundProp.propName] = val;
}
}
for(let boundHandler of componentEventHandlers) {
const closuredHandlers = [];
for(let h of boundHandler.handlers) {
const parameters = {};
for(let pname in h.parameters) {
const p = h.parameters[pname];
parameters[pname] = isState(p)
? getState(
s, p[BB_STATE_BINDINGPATH], p[BB_STATE_FALLBACK])
: p;
}
const handlerType = handlerTypes[h.handlerType];
closuredHandlers.push(() => handlerType.execute(parameters));
}
newProps[boundHandler.propName] = () => {
for(let runHandler of closuredHandlers) {
runHandler();
}
}
}
component.$set(newProps);
});
return unsubscribe;
}
return {
initialProps, bind
};
}
const isState = (prop) => prop[BB_STATE_BINDINGPATH] !== undefined;
const stateBinding = (prop) => prop[BB_STATE_BINDINGPATH];
const stateFallback = (prop) => prop[BB_STATE_FALLBACK];

59
packages/client/src/stateBinding.js

@ -1,59 +0,0 @@
export const BB_STATE_BINDINGPATH = "##bbstate";
export const BB_STATE_FALLBACK = "##bbstatefallback";
export const bindComponent = (store, component) => {
const newProps = {...component.props};
const boundProps = [];
for(let propName in component.props) {
const val = newProps[propName];
if(!isState(val)) continue;
const binding = stateBinding(val);
const fallback = stateFallback(val);
boundProps.push({
stateBinding:binding,
fallback, propName
});
}
if(boundProps.length === 0) return;
const unsubscribe = store.subscribe(s => {
const newProps = {...component.props};
for(let boundProp of boundProps) {
const val = boundValueFromStore(
s,
boundProp.stateBinding,
boundProp.fallback);
if(val === undefined && newProps[boundProp.propName] !== undefined) {
delete newProps[boundProp.propName];
}
if(val !== undefined) {
newProps[boundProp.propName] = val;
}
}
component.$set(newProps);
});
return unsubscribe;
}
const isState = (prop) => prop[BB_STATE_BINDINGPATH] !== undefined;
const stateBinding = (prop) => prop[BB_STATE_BINDINGPATH];
const stateFallback = (prop) => prop[BB_STATE_FALLBACK];
const boundValueFromStore = (s, binding, fallback) => {
const value = s[binding];
if(value === undefined) return fallback;
return value;
}

146
packages/client/tests/stateBinding.spec.js

@ -0,0 +1,146 @@
import {
setupBinding,
BB_STATE_BINDINGPATH,
BB_STATE_FALLBACK
} from "../src/state/stateBinding";
import { EVENT_TYPE_MEMBER_NAME } from "../src/state/eventHandlers";
import {writable} from "svelte/store";
import { isFunction } from "lodash/fp";
describe("setupBinding", () => {
it("should correctly create initials props, including fallback values", () => {
const {store, props, component} = testSetup();
const {initialProps} = testSetupBinding(store, props, component);
expect(initialProps.boundWithFallback).toBe("Bob");
expect(initialProps.boundNoFallback).toBeUndefined();
expect(initialProps.unbound).toBe("hello");
expect(isFunction(initialProps.eventBound)).toBeTruthy();
initialProps.eventBound();
});
it("should update component bound props when store is updated", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
store.update(s => {
s.FirstName = "Bobby";
s.LastName = "Thedog";
s.Customer = {
Name: "ACME inc",
Address: ""
};
s.addressToSet = "123 Main Street"
return s;
});
expect(component.props.boundWithFallback).toBe("Bobby");
expect(component.props.boundNoFallback).toBe("Thedog");
expect(component.props.multiPartBound).toBe("ACME inc");
});
it("should not update unbound props when store is updated", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
store.update(s => {
s.FirstName = "Bobby";
s.LastName = "Thedog";
s.Customer = {
Name: "ACME inc",
Address: ""
};
s.addressToSet = "123 Main Street"
return s;
});
expect(component.props.unbound).toBe("hello");
});
it("should update event handlers on state change", () => {
const {component, store, props} = testSetup();
const {bind} = testSetupBinding(store, props, component);
bind(component);
expect(component.props.boundToEventOutput).toBe("initial address");
component.props.eventBound();
expect(component.props.boundToEventOutput).toBe("event fallback address");
store.update(s => {
s.addressToSet = "123 Main Street"
return s;
});
component.props.eventBound();
expect(component.props.boundToEventOutput).toBe("123 Main Street");
});
});
const testSetupBinding = (store, props, component) => {
const setup = setupBinding(store, props);
component.props = setup.initialProps; // svelte does this for us in real life
return setup;
}
const testSetup = () => {
const c = {};
c.props = {};
c.$set = propsToSet => {
for(let pname in propsToSet)
c.props[pname] = propsToSet[pname];
}
const binding = (path, fallback) => {
const b = {};
b[BB_STATE_BINDINGPATH] = path;
b[BB_STATE_FALLBACK] = fallback;
return b;
};
const event = (handlerType, parameters) => {
const e = {};
e[EVENT_TYPE_MEMBER_NAME] = handlerType;
e.parameters = parameters;
return e;
}
const props = {
boundWithFallback : binding("FirstName", "Bob"),
boundNoFallback : binding("LastName"),
unbound: "hello",
multiPartBound: binding("Customer.Name", "ACME"),
boundToEventOutput: binding("Customer.Address", "initial address"),
eventBound: [
event("Set State", {
path: "Customer.Address",
value: binding("addressToSet", "event fallback address")
})
]
}
return {
component:c,
store:writable({}),
props
};
}

2
packages/server/appPackages/_master/public/main/budibase-client.js

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/_master/public/unauthenticated/budibase-client.js

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp/public/main/budibase-client.js

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp/public/unauthenticated/budibase-client.js

File diff suppressed because one or more lines are too long

75
packages/server/appPackages/testApp2/appDefinition.json

@ -156,14 +156,75 @@
]
},
"props": {
"main": {},
"main": {
"_component": "@budibase/standard-components/grid",
"gridTemplateRows": "",
"gridTemplateColumns": "[left] 1fr [right] 1fr",
"children": [
{
"_component": "children#array_element#",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": "Click Me",
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": [
{
"##eventHandlerType": "Set State",
"parameters": {
"path": "SomeText",
"value": "hello !"
}
}
]
},
"gridColumn": "left",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
},
{
"_component": "children#array_element#",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": {
"##bbstate": "SomeText",
"##bbstatefallback": "(none)"
},
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": []
},
"gridColumn": "",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
}
],
"width": "auto",
"height": "auto",
"containerClass": "",
"itemContainerClass": ""
},
"unauthenticated": {
"_component": "budibase-standard-components/login",
"logo": "/_shared/budibase-logo.png",
"loginRedirect": "",
"usernameLabel": "Username",
"passwordLabel": "Password",
"loginButtonLabel": "Login"
"_component": "@budibase/standard-components/grid",
"gridTemplateRows": "",
"gridTemplateColumns": "[left] 1fr [right] 1fr",
"children": [],
"width": "auto",
"height": "auto",
"containerClass": "",
"itemContainerClass": ""
}
}
}

37
packages/server/appPackages/testApp2/components/Button in the middle.json

@ -1,37 +0,0 @@
{
"name": "Button in the middle",
"description": "",
"inherits": "Centered Panel",
"props": {
"children": [
{
"_component": "undefined:children",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": "Button",
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": []
},
"gridColumn": "center",
"gridRow": "middle",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
}
],
"height": "200px",
"width": "200px"
},
"tags": [
"div",
"container",
"layout",
"panel",
"grid"
]
}

4
packages/server/appPackages/testApp2/components/Primary Button.json

@ -5,14 +5,14 @@
"props": {
"onClick": [
{
"handlerType": "Load Record",
"##eventHandlerType": "Load Record",
"parameters": {
"recordKey": "waa",
"statePath": "yea"
}
},
{
"handlerType": "Load Record",
"##eventHandlerType": "Load Record",
"parameters": {
"recordKey": "ttt",
"statePath": "eee"

5
packages/server/appPackages/testApp2/components/Centered Panel.json → packages/server/appPackages/testApp2/components/containers/two_columns.json

@ -1,10 +1,9 @@
{
"name": "Centered Panel",
"name": "/containers/two_columns",
"description": "",
"inherits": "@budibase/standard-components/grid",
"props": {
"gridTemplateColumns": "[left] 30px [center] 1fr [right] 30px",
"gridTemplateRows": "[top] 30px [middle] 1fr [bottom] 30px"
"gridTemplateColumns": "[left] 1fr [right] 1fr"
},
"tags": [
"div",

65
packages/server/appPackages/testApp2/components/mike.json

@ -0,0 +1,65 @@
{
"name": "mike",
"description": "",
"inherits": "containers/two_columns",
"props": {
"children": [
{
"_component": "#children#array_element",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": "Click Me",
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": [
{
"##eventHandlerType": "Set State",
"parameters": {
"path": "SomeText",
"value": "hello !"
}
}
]
},
"gridColumn": "left",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
},
{
"_component": "#children#array_element",
"control": {
"_component": "@budibase/standard-components/button",
"contentText": {
"##bbstate": "SomeText",
"##bbstatefallback": "(none)"
},
"contentComponent": {
"_component": ""
},
"className": "default",
"disabled": false,
"onClick": []
},
"gridColumn": "",
"gridRow": "",
"gridColumnStart": "",
"gridColumnEnd": "",
"gridRowStart": "",
"gridRowEnd": ""
}
]
},
"tags": [
"div",
"container",
"layout",
"panel",
"grid"
]
}

10
packages/server/appPackages/testApp2/pages.json

@ -1,13 +1,15 @@
{
"main": {
"index": {},
"appBody": ""
"index": {
"title": "main yeo"
},
"appBody": "mike"
},
"unauthenticated": {
"index": {
"title": "Test App Two"
"title": "main"
},
"appBody": "login"
"appBody": "containers/two_columns"
},
"componentLibraries": [
"@budibase/standard-components"

3
packages/server/appPackages/testApp2/public/main/budibase-client.js

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/main/budibase-client.js.map

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/main/clientAppDefinition.js

@ -1 +1 @@
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":["budibase-standard-components"],"appRootPath":"/testApp2","props":{}}
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":[{"importPath":"/lib/node_modules/@budibase/standard-components/dist/index.js","libName":"@budibase/standard-components"}],"appRootPath":"/testApp2","props":{"_component":"@budibase/standard-components/grid","gridTemplateRows":"","gridTemplateColumns":"[left] 1fr [right] 1fr","children":[{"_component":"children#array_element#","control":{"_component":"@budibase/standard-components/button","contentText":"Click Me","contentComponent":{"_component":""},"className":"default","disabled":false,"onClick":[{"##eventHandlerType":"Set State","parameters":{"path":"SomeText","value":"hello !"}}]},"gridColumn":"left","gridRow":"","gridColumnStart":"","gridColumnEnd":"","gridRowStart":"","gridRowEnd":""},{"_component":"children#array_element#","control":{"_component":"@budibase/standard-components/button","contentText":{"##bbstate":"SomeText","##bbstatefallback":"(none)"},"contentComponent":{"_component":""},"className":"default","disabled":false,"onClick":[]},"gridColumn":"","gridRow":"","gridColumnStart":"","gridColumnEnd":"","gridRowStart":"","gridRowEnd":""}],"width":"auto","height":"auto","containerClass":"","itemContainerClass":""}}

18
packages/server/appPackages/testApp2/public/main/index.html

@ -4,16 +4,26 @@
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Budibase App</title>
<link rel='icon' type='image/png' href='/testApp2/_shared/favicon.png'>
<title>main yeo</title>
<link rel='icon' type='image/png' href='/testApp2//_shared/favicon.png'>
<style>
html, body {
height: 100%;
width: 100%;
}
</style>
<script src='/testApp2/clientAppDefinition.js'></script>
<script src='/testApp2/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>
<body id="app">
<script src='/testApp2/clientAppDefinition.js'></script>
</body>
</html>

3
packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/unauthenticated/budibase-client.js.map

File diff suppressed because one or more lines are too long

2
packages/server/appPackages/testApp2/public/unauthenticated/clientAppDefinition.js

@ -1 +1 @@
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":["budibase-standard-components"],"appRootPath":"/testApp2","props":{"_component":"budibase-standard-components/login","logo":"/_shared/budibase-logo.png","loginRedirect":"","usernameLabel":"Username","passwordLabel":"Password","loginButtonLabel":"Login"}}
window['##BUDIBASE_APPDEFINITION##'] = {"hierarchy":{"name":"root","type":"root","children":[{"name":"customer","type":"record","fields":[{"name":"name","type":"string","typeOptions":{"maxLength":1000,"values":null,"allowDeclaredValuesOnly":false},"label":"name","getInitialValue":"default","getUndefinedValue":"default"}],"children":[{"name":"invoiceyooo","type":"record","fields":[{"name":"amount","type":"number","typeOptions":{"minValue":99999999999,"maxValue":99999999999,"decimalPlaces":2},"label":"amount","getInitialValue":"default","getUndefinedValue":"default"}],"children":[],"validationRules":[],"nodeId":2,"indexes":[],"allidsShardFactor":1,"collectionName":"invoices","isSingle":false}],"validationRules":[],"nodeId":1,"indexes":[{"name":"customer_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":5}],"allidsShardFactor":64,"collectionName":"customers","isSingle":false}],"pathMaps":[],"indexes":[{"name":"Yeo index","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[1],"nodeId":4},{"name":"everyones_invoices","type":"index","map":"return {...record};","filter":"","indexType":"ancestor","getShardName":"","getSortKey":"record.id","aggregateGroups":[],"allowedRecordNodeIds":[2],"nodeId":6}],"nodeId":0},"componentLibraries":[{"importPath":"/lib/node_modules/@budibase/standard-components/dist/index.js","libName":"@budibase/standard-components"}],"appRootPath":"/testApp2","props":{"_component":"@budibase/standard-components/grid","gridTemplateRows":"","gridTemplateColumns":"[left] 1fr [right] 1fr","children":[],"width":"auto","height":"auto","containerClass":"","itemContainerClass":""}}

18
packages/server/appPackages/testApp2/public/unauthenticated/index.html

@ -4,16 +4,26 @@
<meta charset='utf8'>
<meta name='viewport' content='width=device-width'>
<title>Test App Two</title>
<link rel='icon' type='image/png' href='/testApp2/_shared/favicon.png'>
<title>main</title>
<link rel='icon' type='image/png' href='/testApp2//_shared/favicon.png'>
<style>
html, body {
height: 100%;
width: 100%;
}
</style>
<script src='/testApp2/clientAppDefinition.js'></script>
<script src='/testApp2/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>
<body id="app">
<script src='/testApp2/clientAppDefinition.js'></script>
</body>
</html>

2
packages/server/builder/budibase-client.esm.mjs

File diff suppressed because one or more lines are too long

30
packages/server/builder/bundle.css

@ -3,45 +3,45 @@ main.svelte-1ui0j3s{height:100%;width:100%;font-family:"Roboto", Helvetica, Aria
.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-q8uz1n{height:100%;display:flex}.content.svelte-q8uz1n{flex:1 1 auto;height:100%;background-color:var(--white);margin:0}.nav.svelte-q8uz1n{flex:0 1 auto;width:300px;height:100%}
button.svelte-bxuckr{border-style:none;background-color:rgba(0,0,0,0);cursor:pointer;outline:none}button.svelte-bxuckr:hover{color:var(--hovercolor)}button.svelte-bxuckr:active{outline:none}
.root.svelte-1dih19s{display:grid;grid-template-columns:[uiNav] 250px [preview] auto [properties] 300px;height:100%;width:100%}.ui-nav.svelte-1dih19s{grid-column-start:uiNav;background-color:var(--primary10);height:100%}.properties-pane.svelte-1dih19s{grid-column-start:properties;background-color:var(--primary10);height:100%}.pages-list-container.svelte-1dih19s{padding-top:20px}.nav-group-header.svelte-1dih19s{font-size:10pt;padding-left:10px}.nav-items-container.svelte-1dih19s{padding-top:10px}.nav-group-header.svelte-1dih19s{display:grid;grid-template-columns:[icon] auto [title] 1fr [button] auto;padding:10px 2px 0px 7px}.nav-group-header.svelte-1dih19s>div.svelte-1dih19s:nth-child(1){padding:0px 7px 0px 0px;vertical-align:bottom;grid-column-start:icon;margin-right:5px}.nav-group-header.svelte-1dih19s>span.svelte-1dih19s:nth-child(2){margin-left:5px;vertical-align:bottom;grid-column-start:title;margin-top:auto}.nav-group-header.svelte-1dih19s>div.svelte-1dih19s:nth-child(3){vertical-align:bottom;grid-column-start:button;cursor:pointer;color:var(--slate)}.nav-group-header.svelte-1dih19s>div.svelte-1dih19s:nth-child(3):hover{color:var(--primary75)}
.border-normal.svelte-vnon4v{border-radius:var(--borderradiusall)}.border-left.svelte-vnon4v{border-radius:var(--borderradius) 0 0 var(--borderradius)}.border-right.svelte-vnon4v{border-radius:0 var(--borderradius) var(--borderradius) 0}.border-middle.svelte-vnon4v{border-radius:0}button.svelte-vnon4v{border-style:solid;padding:7.5px 15px;cursor:pointer;margin:5px;border-radius:5px}.primary.svelte-vnon4v{background-color:var(--primary100);border-color:var(--primary100);color:var(--white)}.primary.svelte-vnon4v:hover{background-color:var(--primary75);border-color:var(--primary75)}.primary.svelte-vnon4v:active{background-color:var(--primarydark);border-color:var(--primarydark)}.primary-outline.svelte-vnon4v{background-color:var(--white);border-color:var(--primary100);color:var(--primary100)}.primary-outline.svelte-vnon4v:hover{background-color:var(--primary10)}.primary-outline.svelte-vnon4v:pressed{background-color:var(--primary25)}.secondary.svelte-vnon4v{background-color:var(--secondary100);border-color:var(--secondary100);color:var(--white)}.secondary.svelte-vnon4v:hover{background-color:var(--secondary75);border-color:var(--secondary75)}.secondary.svelte-vnon4v:pressed{background-color:var(--secondarydark);border-color:var(--secondarydark)}.secondary-outline.svelte-vnon4v{background-color:var(--white);border-color:var(--secondary100);color:var(--secondary100)}.secondary-outline.svelte-vnon4v:hover{background-color:var(--secondary10)}.secondary-outline.svelte-vnon4v:pressed{background-color:var(--secondary25)}.success.svelte-vnon4v{background-color:var(--success100);border-color:var(--success100);color:var(--white)}.success.svelte-vnon4v:hover{background-color:var(--success75);border-color:var(--success75)}.success.svelte-vnon4v:pressed{background-color:var(--successdark);border-color:var(--successdark)}.success-outline.svelte-vnon4v{background-color:var(--white);border-color:var(--success100);color:var(--success100)}.success-outline.svelte-vnon4v:hover{background-color:var(--success10)}.success-outline.svelte-vnon4v:pressed{background-color:var(--success25)}.deletion.svelte-vnon4v{background-color:var(--deletion100);border-color:var(--deletion100);color:var(--white)}.deletion.svelte-vnon4v:hover{background-color:var(--deletion75);border-color:var(--deletion75)}.deletion.svelte-vnon4v:pressed{background-color:var(--deletiondark);border-color:var(--deletiondark)}.deletion-outline.svelte-vnon4v{background-color:var(--white);border-color:var(--deletion100);color:var(--deletion100)}.deletion-outline.svelte-vnon4v:hover{background-color:var(--deletion10)}.deletion-outline.svelte-vnon4v:pressed{background-color:var(--deletion25)}
.root.svelte-1p3g2nf{display:grid;grid-template-columns:[uiNav] 250px [preview] auto [properties] 300px;height:100%;width:100%;overflow-y:auto}.ui-nav.svelte-1p3g2nf{grid-column-start:uiNav;background-color:var(--primary10);height:100%}.properties-pane.svelte-1p3g2nf{grid-column-start:properties;background-color:var(--primary10);height:100%;overflow-y:hidden}.pages-list-container.svelte-1p3g2nf{padding-top:20px}.nav-group-header.svelte-1p3g2nf{font-size:10pt;padding-left:10px}.nav-items-container.svelte-1p3g2nf{padding-top:10px}.nav-group-header.svelte-1p3g2nf{display:grid;grid-template-columns:[icon] auto [title] 1fr [button] auto;padding:10px 2px 0px 7px}.nav-group-header.svelte-1p3g2nf>div.svelte-1p3g2nf:nth-child(1){padding:0px 7px 0px 0px;vertical-align:bottom;grid-column-start:icon;margin-right:5px}.nav-group-header.svelte-1p3g2nf>span.svelte-1p3g2nf:nth-child(2){margin-left:5px;vertical-align:bottom;grid-column-start:title;margin-top:auto}.nav-group-header.svelte-1p3g2nf>div.svelte-1p3g2nf:nth-child(3){vertical-align:bottom;grid-column-start:button;cursor:pointer;color:var(--slate)}.nav-group-header.svelte-1p3g2nf>div.svelte-1p3g2nf:nth-child(3):hover{color:var(--primary75)}
h4.svelte-sqtlby{margin-top:20px}
.root.svelte-wfv60d{height:100%;position:relative;padding:1.5rem}.actions-header.svelte-wfv60d{flex:0 1 auto}.node-view.svelte-wfv60d{overflow-y:auto;flex:1 1 auto}
.root.svelte-nd1yft{height:100%;position:relative;padding:1.5rem}
.root.svelte-apja7r{height:100%;position:relative}.actions-header.svelte-apja7r{flex:0 1 auto}.node-view.svelte-apja7r{overflow-y:auto;flex:1 1 auto}
.root.svelte-1ywqvdl{height:100%;background-color:var(--secondary5)}.items-root.svelte-1ywqvdl{display:flex;flex-direction:column;max-height:100%;height:10px}.hierarchy.svelte-1ywqvdl{flex:1 1 auto}.hierarchy-title-row.svelte-1ywqvdl{padding:2rem 1rem 0rem 1rem;font-size:10pt;display:flex;font-weight:bold}.hierarchy-title.svelte-1ywqvdl{flex:auto 1 1}.space-filler.svelte-1ywqvdl{flex:1 1 auto}
.root.svelte-zzs4qg{padding:10px}
.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-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}
.root.svelte-183dehm{height:100%;border-style:solid;border-color:var(--lightslate);border-width:0px 0px 0px 1px}.padding.svelte-183dehm{padding:0px 5px 0px 10px}.title.svelte-183dehm{background-color:white;padding:3px;display:grid;grid-template-columns:[name] 1fr [actions] auto}.title.svelte-183dehm>div.svelte-183dehm:nth-child(1){grid-column-start:name;color:var(--secondary100)}.title.svelte-183dehm>div.svelte-183dehm:nth-child(2){grid-column-start:actions}.section-header.svelte-183dehm{font-style:italic;color:var(--slate);border-style:solid;border-color:var(--lightslate);border-width:0px 0px 1px 0px}.section-header.svelte-183dehm{vertical-align:middle;margin-top:20px}
.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}
h1.svelte-16jkjx9{font-size:1.2em}
.uk-modal-dialog.svelte-vwwrf9{border-radius:.3rem}
.component-preview.svelte-1jir83x{display:grid;grid-template-rows:[top] 1fr [middle] auto [bottom] 1fr;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-column-start:preview;height:100%}.component-container.svelte-1jir83x{grid-row-start:middle;grid-column-start:middle}
.root.svelte-k32wsr{height:100%;border-style:solid;border-color:var(--lightslate);border-width:0px 0px 0px 1px;display:flex;flex-direction:column}.padding.svelte-k32wsr{padding:0px 5px 0px 10px}.title.svelte-k32wsr{background-color:white;padding:3px;display:grid;grid-template-columns:[name] 1fr [actions] auto}.title.svelte-k32wsr>div.svelte-k32wsr:nth-child(1){grid-column-start:name;color:var(--secondary100)}.title.svelte-k32wsr>div.svelte-k32wsr:nth-child(2){grid-column-start:actions}.section-header.svelte-k32wsr{font-style:italic;color:var(--slate);border-style:solid;border-color:var(--lightslate);border-width:0px 0px 1px 0px}.section-header.svelte-k32wsr{vertical-align:middle;margin-top:20px}.component-props-container.svelte-k32wsr{flex:1 1 auto;overflow-y:auto}
h1.svelte-16jkjx9{font-size:1.2em}
.root.svelte-1ersoxu{padding:15px}.help-text.svelte-1ersoxu{color:var(--slate);font-size:10pt}
.section-container.svelte-yk1mmr{padding:15px;border-style:dotted;border-width:1px;border-color:var(--lightslate);border-radius:2px}.section-container.svelte-yk1mmr:nth-child(1){margin-bottom:15px}.row-text.svelte-yk1mmr{margin-right:15px;color:var(--primary100)}input.svelte-yk1mmr{margin-right:15px}p.svelte-yk1mmr>span.svelte-yk1mmr{margin-left:30px}.header.svelte-yk1mmr{display:grid;grid-template-columns:[title] 1fr [icon] auto}.header.svelte-yk1mmr>div.svelte-yk1mmr:nth-child(1){grid-column-start:title}.header.svelte-yk1mmr>div.svelte-yk1mmr:nth-child(2){grid-column-start:icon}
.root.svelte-16m6n12{height:100%;padding:2rem}.settings-title.svelte-16m6n12{font-weight:600}.title.svelte-16m6n12{margin:3rem 0rem 0rem 0rem;font-weight:600}.recordkey.svelte-16m6n12{font-size:14px;font-weight:600;color:var(--primary100)}.fields-table.svelte-16m6n12{margin:1rem 1rem 0rem 0rem;border-collapse:collapse}.add-field-button.svelte-16m6n12{cursor:pointer}.edit-button.svelte-16m6n12{cursor:pointer;color:var(--white)}.edit-button.svelte-16m6n12:hover{color:var(--secondary75)}th.svelte-16m6n12{text-align:left}td.svelte-16m6n12{padding:1rem 5rem 1rem 0rem;margin:0}thead.svelte-16m6n12>tr.svelte-16m6n12{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--secondary75);margin-bottom:20px}tbody.svelte-16m6n12>tr.svelte-16m6n12{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--primary10)}tbody.svelte-16m6n12>tr.svelte-16m6n12:hover{background-color:var(--primary10)}tbody.svelte-16m6n12>tr:hover .edit-button.svelte-16m6n12{color:var(--secondary75)}.index-container.svelte-16m6n12{border-style:solid;border-width:0 0 1px 0;border-color:var(--secondary25);padding:10px;margin-bottom:5px}.index-label.svelte-16m6n12{color:var(--slate)}.index-name.svelte-16m6n12{font-weight:bold;color:var(--primary100)}.index-container.svelte-16m6n12 code.svelte-16m6n12{margin:0;display:inline;background-color:var(--primary10);color:var(--secondary100);padding:3px}.index-field-row.svelte-16m6n12{margin:1rem 0rem 0rem 0rem}.no-indexes.svelte-16m6n12{margin:1rem 0rem 0rem 0rem;font-family:var(--fontnormal);font-size:14px}
.edit-button.svelte-lhfdtn{cursor:pointer;color:var(--secondary25)}tr.svelte-lhfdtn:hover .edit-button.svelte-lhfdtn{color:var(--secondary75)}.title.svelte-lhfdtn{margin:3rem 0rem 0rem 0rem;font-weight:700}.table-content.svelte-lhfdtn{font-weight:500;font-size:.9rem}
.root.svelte-x3bf9z{display:flex}.root.svelte-x3bf9z:last-child{border-radius:0 var(--borderradius) var(--borderradius) 0}.root.svelte-x3bf9z:first-child{border-radius:var(--borderradius) 0 0 var(--borderradius)}.root.svelte-x3bf9z:not(:first-child):not(:last-child){border-radius:0}
.edit-button.svelte-zm41av{cursor:pointer;color:var(--secondary25)}.title.svelte-zm41av{margin:3rem 0rem 0rem 0rem;font-weight:700}.table-content.svelte-zm41av{font-weight:500;font-size:.9rem}tr.svelte-zm41av:hover .edit-button.svelte-zm41av{color:var(--secondary75)}
.root.svelte-b3063u{display:block;font-size:1rem;width:100%;cursor:pointer}.title.svelte-b3063u{font:var(--fontblack);padding-top:10px;padding-right:5px;padding-bottom:10px;color:var(--secondary100)}.title.svelte-b3063u:hover{background-color:var(--secondary10)}
.root.svelte-wgyofl{padding:1.5rem;width:100%;align-items:right}
.root.svelte-pq2tmv{height:100%;padding:15px}.allowed-records.svelte-pq2tmv{margin:20px 0px}.allowed-records.svelte-pq2tmv>span.svelte-pq2tmv{margin-right:30px}
.dropdown-background.svelte-11ifkop{position:fixed;top:0;left:0;width:100vw;height:100vh}.root.svelte-11ifkop{cursor:pointer;z-index:1}.dropdown-content.svelte-11ifkop{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-11ifkop:not(:focus){display:none}.action-row.svelte-11ifkop{padding:7px 10px;cursor:pointer}.action-row.svelte-11ifkop:hover{background-color:var(--primary100);color:var(--white)}
.root.svelte-qdxuha{height:100%;padding:2rem}.settings-title.svelte-qdxuha{font-weight:700}.title.svelte-qdxuha{margin:3rem 0rem 0rem 0rem;font-weight:700}.recordkey.svelte-qdxuha{font-size:14px;font-weight:600;color:var(--primary100)}.fields-table.svelte-qdxuha{margin:1rem 1rem 0rem 0rem;border-collapse:collapse}.add-field-button.svelte-qdxuha{cursor:pointer}.edit-button.svelte-qdxuha{cursor:pointer;color:var(--secondary25)}.edit-button.svelte-qdxuha:hover{cursor:pointer;color:var(--secondary75)}th.svelte-qdxuha{text-align:left}td.svelte-qdxuha{padding:1rem 5rem 1rem 0rem;margin:0}thead.svelte-qdxuha>tr.svelte-qdxuha{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--secondary75);margin-bottom:20px}tbody.svelte-qdxuha>tr.svelte-qdxuha{border-width:0px 0px 1px 0px;border-style:solid;border-color:var(--primary10)}tbody.svelte-qdxuha>tr.svelte-qdxuha:hover{background-color:var(--primary10)}tbody.svelte-qdxuha>tr:hover .edit-button.svelte-qdxuha{color:var(--secondary75)}.index-container.svelte-qdxuha{border-style:solid;border-width:0 0 1px 0;border-color:var(--secondary25);padding:10px;margin-bottom:5px}.index-label.svelte-qdxuha{color:var(--slate)}.index-name.svelte-qdxuha{font-weight:bold;color:var(--primary100)}.index-container.svelte-qdxuha code.svelte-qdxuha{margin:0;display:inline;background-color:var(--primary10);color:var(--secondary100);padding:3px}.index-field-row.svelte-qdxuha{margin:1rem 0rem 0rem 0rem}.no-indexes.svelte-qdxuha{margin:1rem 0rem 0rem 0rem;font-family:var(--fontnormal);font-size:14px}
.root.svelte-3fdbwl{display:block;font-size:10pt;width:100%;cursor:pointer}.title.svelte-3fdbwl{padding-top:.5rem;padding-right:.5rem;color:var(--secondary100)}.title.svelte-3fdbwl:hover{background-color:var(--secondary10)}.active.svelte-3fdbwl{background-color:var(--primary10)}
.nav-item.svelte-1ld5h6g{padding:1rem 1rem 0rem 1rem;font-size:10pt;font-weight:bold;cursor:pointer;flex:0 0 auto}.nav-item.svelte-1ld5h6g:hover{background-color:var(--primary10)}.active.svelte-1ld5h6g{background-color:var(--primary10)}
.root.svelte-x3bf9z{display:flex}.root.svelte-x3bf9z:last-child{border-radius:0 var(--borderradius) var(--borderradius) 0}.root.svelte-x3bf9z:first-child{border-radius:var(--borderradius) 0 0 var(--borderradius)}.root.svelte-x3bf9z:not(:first-child):not(:last-child){border-radius:0}
.edit-button.svelte-9z4fqi{cursor:pointer;color:var(--white)}tr.svelte-9z4fqi:hover .edit-button.svelte-9z4fqi{color:var(--secondary75)}
.edit-button.svelte-neetem{cursor:pointer;color:var(--white)}tr.svelte-neetem:hover .edit-button.svelte-neetem{color:var(--secondary75)}
.dropdown-background.svelte-11ifkop{position:fixed;top:0;left:0;width:100vw;height:100vh}.root.svelte-11ifkop{cursor:pointer;z-index:1}.dropdown-content.svelte-11ifkop{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-11ifkop:not(:focus){display:none}.action-row.svelte-11ifkop{padding:7px 10px;cursor:pointer}.action-row.svelte-11ifkop:hover{background-color:var(--primary100);color:var(--white)}
.root.svelte-1sxai5n{font-size:10pt}.padding.svelte-1sxai5n{padding:0 10px}.inherited-title.svelte-1sxai5n{margin-top:40px;display:grid;grid-template-columns:[name] 1fr [actions] auto;border-style:solid;border-width:0px 0px 1px 0px;border-color:var(--lightslate);font-style:italic}.inherited-title.svelte-1sxai5n>div.svelte-1sxai5n:nth-child(1){grid-column-start:name;color:var(--slate)}.inherited-title.svelte-1sxai5n>div.svelte-1sxai5n:nth-child(2){grid-column-start:actions;color:var(--secondary100)}
.info-text.svelte-y0b7l0{font-size:0.8em;color:var(--slate)}
.title.svelte-dhe1ge{padding:3px;background-color:white;color:var(--secondary100);border-style:solid;border-width:1px 0 0 0;border-color:var(--lightslate)}.title.svelte-dhe1ge>span.svelte-dhe1ge{margin-left:10px}
.component.svelte-qxar5p{padding:5px;border-style:solid;border-width:0 0 1px 0;border-color:var(--lightslate);cursor:pointer}.component.svelte-qxar5p:hover{background-color:var(--primary10)}.component.svelte-qxar5p>.title.svelte-qxar5p{font-size:13pt;color:var(--secondary100)}.component.svelte-qxar5p>.description.svelte-qxar5p{font-size:10pt;color:var(--primary75);font-style:italic}
.root.svelte-16sjty9{padding:2rem;border-radius:2rem}.uk-grid-small.svelte-16sjty9{padding:1rem}.option-container.svelte-16sjty9{border-style:dotted;border-width:1px;border-color:var(--primary75);padding:3px;margin-right:5px}
input.svelte-9fre0g{margin-right:7px}
.error-container.svelte-ole1mk{padding:10px;border-style:solid;border-color:var(--deletion100);border-radius:var(--borderradiusall);background:var(--deletion75)}.error-row.svelte-ole1mk{padding:5px 0px}
textarea.svelte-di7k4b{padding:3px;margin-top:5px;margin-bottom:10px;background:var(--lightslate);color:var(--white);font-family:'Courier New', Courier, monospace;width:95%;height:100px;border-radius:5px}
.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-9fre0g{margin-right:7px}
.root.svelte-1el8vet{padding:3px 5px 7px 10px;border-style:dotted;border-width:0 0 1px 0;border-color:var(--primary25)}.prop-label.svelte-1el8vet{font-size:0.9em;color:var(--primary100);font-weight:bold}
.root.svelte-ogh8o0{display:grid;grid-template-columns:[name] 1fr [actions] auto}.root.svelte-ogh8o0>div.svelte-ogh8o0:nth-child(1){grid-column-start:name;color:var(--secondary50)}.root.svelte-ogh8o0>div.svelte-ogh8o0:nth-child(2){grid-column-start:actions}.selectedname.svelte-ogh8o0{font-weight:bold;color:var(--secondary)}
.root.svelte-1el8vet{padding:3px 5px 7px 10px;border-style:dotted;border-width:0 0 1px 0;border-color:var(--primary25)}.prop-label.svelte-1el8vet{font-size:0.9em;color:var(--primary100);font-weight:bold}
textarea.svelte-1kv2xk7{width:300px;height:200px}
.unbound-container.svelte-18ig4tf{display:flex}.unbound-container.svelte-18ig4tf>.svelte-18ig4tf:nth-child(1){width:auto;flex:1 0 auto}.bound-header.svelte-18ig4tf{display:flex}.bound-header.svelte-18ig4tf>div.svelte-18ig4tf:nth-child(1){flex:1 0 auto;width:30px;color:var(--darkslate);padding-left:5px;font-style:italic}.binding-prop-label.svelte-18ig4tf{color:var(--darkslate)}
.addelement-container.svelte-199q8jr{cursor:pointer;padding:3px 0px;text-align:center}.addelement-container.svelte-199q8jr:hover{background-color:var(--primary25)}.item-container.svelte-199q8jr{padding-left:3px;background:var(--secondary10)}
.addelement-container.svelte-r1ft9p{cursor:pointer;padding:3px 0px;text-align:center}.addelement-container.svelte-r1ft9p:hover{background-color:var(--primary25);margin-top:5px}.control-container.svelte-r1ft9p{padding-left:3px;background:var(--secondary10)}.separator.svelte-r1ft9p{width:60%;margin:10px auto;border-style:solid;border-width:1px 0 0 0;border-color:var(--primary25)}
.type-selector-container.svelte-1b6pj9u{display:flex}.type-selector.svelte-1b6pj9u{border-color:var(--primary50);border-radius:2px;width:50px;flex:1 0 auto}
.unbound-container.svelte-1fe5d1g{display:flex}.unbound-container.svelte-1fe5d1g>input.svelte-1fe5d1g{width:auto}.bound-header.svelte-1fe5d1g{display:flex}.bound-header.svelte-1fe5d1g>div.svelte-1fe5d1g:nth-child(1){flex:1 0 auto;width:30px;color:var(--darkslate);padding-left:5px}.binding-prop-label.svelte-1fe5d1g{color:var(--darkslate)}
.unbound-container.svelte-18ig4tf{display:flex}.unbound-container.svelte-18ig4tf>.svelte-18ig4tf:nth-child(1){width:auto;flex:1 0 auto}.bound-header.svelte-18ig4tf{display:flex}.bound-header.svelte-18ig4tf>div.svelte-18ig4tf:nth-child(1){flex:1 0 auto;width:30px;color:var(--darkslate);padding-left:5px;font-style:italic}.binding-prop-label.svelte-18ig4tf{color:var(--darkslate)}
/*# sourceMappingURL=bundle.css.map */

70
packages/server/builder/bundle.css.map

File diff suppressed because one or more lines are too long

638
packages/server/builder/bundle.js

File diff suppressed because it is too large

2
packages/server/builder/bundle.js.map

File diff suppressed because one or more lines are too long

4
packages/server/utilities/builder/index.template.html

@ -20,7 +20,9 @@
<script src='{{ appRootPath }}/clientAppDefinition.js'></script>
<script src='{{ appRootPath }}/budibase-client.js'></script>
<script>
loadBudibase();
</script>
</head>

1
packages/standard-components/dist/index.js.map

File diff suppressed because one or more lines are too long

7
packages/standard-components/rollup.config.js

@ -4,7 +4,12 @@ import resolve from 'rollup-plugin-node-resolve';
export default {
input: 'src/index.js',
output: [
{ file: "dist/index.js", 'format': 'esm', name:"budibaseStandardComponents" }
{
file: "dist/index.js",
format: 'esm',
name:"budibaseStandardComponents",
sourcemap: "inline"
}
],
plugins: [
svelte(),

9
packages/standard-components/src/button.svelte

@ -9,14 +9,19 @@ export let _app;
let contentComponentContainer;
$:{
if(_app && contentComponentContainer)
if(_app && contentComponentContainer && contentComponent._component)
_app.initialiseComponent(contentComponent, contentComponentContainer);
}
const clickHandler = () => {
if(onClick) onClick();
}
</script>
<button class={className} {disabled} on:click={onClick}>
<button class={className} {disabled} on:click={clickHandler}>
{#if contentComponent && contentComponent._component}
<div bind:this={contentComponentContainer}>
</div>

Loading…
Cancel
Save