data binding and stndard componets work
This commit is contained in:
parent
346ec5c4da
commit
70ddecfab0
|
@ -1,5 +1,3 @@
|
|||
import { isUndefined } from "lodash/fp";
|
||||
|
||||
const apiCall = (method) => (url, body) =>
|
||||
fetch(url, {
|
||||
method: method,
|
||||
|
|
|
@ -3,7 +3,8 @@ import {
|
|||
isBoolean,
|
||||
isNumber,
|
||||
isArray,
|
||||
isObjectLike
|
||||
isObjectLike,
|
||||
some
|
||||
} from "lodash/fp";
|
||||
|
||||
const defaultDef = typeName => () => ({
|
||||
|
@ -47,6 +48,14 @@ export const expandPropsDefinition = propsDefinition => {
|
|||
}
|
||||
|
||||
const isComponent = isObjectLike;
|
||||
const isEvent = e =>
|
||||
isObjectLike(e)
|
||||
&& e.handlerType && isString(e.handlerType)
|
||||
&& e.parameters && isArray(e.parameters);
|
||||
|
||||
const isEventList = e =>
|
||||
isArray(e) && !some(ev => !isEvent(ev));
|
||||
|
||||
|
||||
export const types = {
|
||||
string: propType(() => "", isString, defaultDef("string")),
|
||||
|
@ -56,4 +65,5 @@ export const types = {
|
|||
options: propType(() => "", isString, defaultDef("options")),
|
||||
component: propType(() => ({_component:""}), isComponent, defaultDef("component")),
|
||||
asset: propType(() => "", isString, defaultDef("asset")),
|
||||
event: propType(() => [], isEventList, defaultDef("event"))
|
||||
};
|
|
@ -103,6 +103,18 @@ describe("createDefaultProps", () => {
|
|||
expect(props.columns).toEqual([]);
|
||||
});
|
||||
|
||||
it("should create a object with single empty array, when prop definition is 'event' ", () => {
|
||||
const propDef = {
|
||||
onClick: "event"
|
||||
};
|
||||
|
||||
const { props, errors } = createProps("some_component",propDef);
|
||||
|
||||
expect(errors).toEqual([]);
|
||||
expect(props.onClick).toBeDefined();
|
||||
expect(props.onClick).toEqual([]);
|
||||
});
|
||||
|
||||
it("should create a object with single empty component props, when prop definition is 'component' ", () => {
|
||||
const propDef = {
|
||||
content: "component"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"version": "0.0.3",
|
||||
"license": "MPL-2.0",
|
||||
"main": "dist/budibase-client.js",
|
||||
"module": "dist/budibase-client.js",
|
||||
"module": "dist/budibase-client.esm.mjs",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"test": "jest",
|
||||
|
|
|
@ -26,12 +26,19 @@ const coreExternal = [
|
|||
|
||||
export default {
|
||||
input: 'src/index.js',
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: `./dist/budibase-client.js`
|
||||
},
|
||||
output: [
|
||||
{
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: `./dist/budibase-client.js`
|
||||
},
|
||||
{
|
||||
file: 'dist/budibase-client.esm.mjs',
|
||||
format: 'esm',
|
||||
sourcemap: 'inline'
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
|
||||
resolve({
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
split,
|
||||
last
|
||||
} from "lodash/fp";
|
||||
import {writable} from "svelte/store";
|
||||
import { $ } from "./core/common";
|
||||
import { bindComponent } from "./stateBinding";
|
||||
|
||||
export const createApp = componentLibraries => {
|
||||
|
||||
const initialiseComponent = (props, htmlElement) => {
|
||||
|
||||
const {componentName, libName} = splitName(props._component);
|
||||
|
||||
const component = new (componentLibraries[libName][componentName])({
|
||||
target: htmlElement,
|
||||
props: {...props, _app}
|
||||
});
|
||||
|
||||
bindComponent(store, component);
|
||||
|
||||
}
|
||||
|
||||
const store = writable({});
|
||||
|
||||
const _app = {
|
||||
initialiseComponent,
|
||||
store
|
||||
};
|
||||
|
||||
return _app;
|
||||
|
||||
}
|
||||
|
||||
|
||||
const splitName = fullname => {
|
||||
const componentName = $(fullname, [
|
||||
split("/"),
|
||||
last
|
||||
]);
|
||||
|
||||
const libName =fullname.substring(
|
||||
0, fullname.length - componentName.length - 1);
|
||||
|
||||
return {libName, componentName};
|
||||
}
|
|
@ -1,5 +1,25 @@
|
|||
import { initialise } from "./initialise";
|
||||
import { createApp } from "./createApp";
|
||||
|
||||
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
|
||||
|
||||
initialise(window.document, appDefinition);
|
||||
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
|
||||
|
||||
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');
|
||||
|
||||
(async () => {
|
||||
|
||||
const componentLibraries = {};
|
||||
|
||||
for(let lib of appDefinition.componentLibraries) {
|
||||
componentLibraries[lib.libName] = await import(
|
||||
componentLibraryUrl(lib.importPath));
|
||||
}
|
||||
|
||||
|
||||
const _app = createApp(componentLibraries);
|
||||
|
||||
_app.initialiseComponent(
|
||||
props,
|
||||
document.body);
|
||||
|
||||
})();
|
|
@ -1,22 +0,0 @@
|
|||
import { writable } from "svelte/store";
|
||||
import { initialiseComponent } from "./initialiseComponent";
|
||||
|
||||
export const initialise = async (document, appDefinition) => {
|
||||
|
||||
const componentLibraries = {};
|
||||
|
||||
for(let lib of appDefinition.componentLibraries) {
|
||||
componentLibraries[lib.libName] = await import(
|
||||
componentLibraryUrl(lib.importPath));
|
||||
}
|
||||
|
||||
const store = writable({});
|
||||
|
||||
initialiseComponent(componentLibraries, store)(
|
||||
appDefinition.props,
|
||||
document.body);
|
||||
}
|
||||
const componentLibraryUrl = (lib) => "./" + trimSlash(lib)
|
||||
|
||||
const trimSlash = (str) => str.replace(/^\/+|\/+$/g, '');
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
import {
|
||||
find,
|
||||
isUndefined,
|
||||
split,
|
||||
last
|
||||
} from "lodash/fp";
|
||||
|
||||
import { $ } from "./core/common";
|
||||
|
||||
export const initialiseComponent = (componentLibraries, store) => (props, htmlElement) => {
|
||||
|
||||
const _app = {
|
||||
initialiseComponent: initialiseComponent(componentLibraries, store),
|
||||
store
|
||||
};
|
||||
|
||||
const {componentName, libName} = splitName(props._component);
|
||||
|
||||
new (componentLibraries[libName][componentName])({
|
||||
target: htmlElement,
|
||||
props: {...props, _app}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const splitName = fullname => {
|
||||
const componentName = $(fullname, [
|
||||
split("/"),
|
||||
last
|
||||
]);
|
||||
|
||||
const libName =fullname.substring(
|
||||
0, fullname.length - componentName.length - 1);
|
||||
|
||||
return {libName, componentName};
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
export const BB_STATE_INDICATOR = "##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_INDICATOR] !== undefined;
|
||||
const stateBinding = (prop) => prop[BB_STATE_INDICATOR];
|
||||
const stateFallback = (prop) => prop[BB_STATE_FALLBACK];
|
||||
const boundValueFromStore = (s, binding, fallback) => {
|
||||
const value = s[binding];
|
||||
if(value === undefined) return fallback;
|
||||
return value;
|
||||
}
|
|
@ -7,6 +7,13 @@
|
|||
<title>{{ title }}</title>
|
||||
<link rel='icon' type='image/png' href='{{ favicon }}'>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ each(options.stylesheets) }}
|
||||
<link rel='stylesheet' href='{{ @this }}'>
|
||||
{{ /each }}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"tags": ["button"]
|
||||
},
|
||||
"login" : {
|
||||
"importPath": "login",
|
||||
"importPath": "Login",
|
||||
"name": "Login Control",
|
||||
"desciption": "A control that accepts username, password an also handles password resets",
|
||||
"props" : {
|
||||
|
@ -21,33 +21,21 @@
|
|||
"loginRedirect": "string",
|
||||
"usernameLabel": {"type":"string", "default": "Username"},
|
||||
"passwordLabel": {"type":"string", "default": "Password"},
|
||||
"loginButtonLabel": {"type":"string", "default": "Login"}
|
||||
"loginButtonLabel": {"type":"string", "default": "Login"},
|
||||
"buttonClass": "string"
|
||||
},
|
||||
"tags": ["login", "credentials", "password", "logon"]
|
||||
},
|
||||
"formControl" : {
|
||||
"importPath": "formControl",
|
||||
"name": "Form Control",
|
||||
"desciption": "A wrapper for a control, used inside a form. Allows a label, and properly alligns the control inside the parent form",
|
||||
"props" : {
|
||||
"containerClass": "string",
|
||||
"labelContainerClass": "string",
|
||||
"controlContainerClass": "string",
|
||||
"label": "string",
|
||||
"control": "component",
|
||||
"fullWidth": "bool"
|
||||
},
|
||||
"tags": ["login"]
|
||||
},
|
||||
"form" : {
|
||||
"importPath": "form",
|
||||
"importPath": "Form",
|
||||
"name": "Form",
|
||||
"desciption": "A form - you should usually add FormControls as children to get nice allignment",
|
||||
"desciption": "A form - allgned fields with labels",
|
||||
"props" : {
|
||||
"containerClass": "string",
|
||||
"formControls": {
|
||||
"type":"array",
|
||||
"elementDefinition": {
|
||||
"label": "string",
|
||||
"control":"component"
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +43,7 @@
|
|||
"tags": ["form"]
|
||||
},
|
||||
"textbox" : {
|
||||
"importPath": "textbox",
|
||||
"importPath": "Textbox",
|
||||
"name": "Textbox",
|
||||
"desciption": "An input type=text or password",
|
||||
"props" : {
|
||||
|
@ -66,7 +54,7 @@
|
|||
"tags": ["form"]
|
||||
},
|
||||
"stackpanel": {
|
||||
"importPath": "stackpanel",
|
||||
"importPath": "StackPanel",
|
||||
"name": "StackPanel",
|
||||
"desciption": "Layout elements in a stack, either horizontally or vertically",
|
||||
"props" : {
|
||||
|
@ -87,5 +75,53 @@
|
|||
"itemContainerClass":"string"
|
||||
},
|
||||
"tags": ["div", "container", "layout", "panel"]
|
||||
},
|
||||
"grid": {
|
||||
"importPath": "Grid",
|
||||
"name": "Grid",
|
||||
"desciption": "CSS Grid layout ",
|
||||
"props" : {
|
||||
"gridTemplateRows": "string",
|
||||
"gridTemplateColumns": "string",
|
||||
"children": {
|
||||
"type":"array",
|
||||
"elementDefinition": {
|
||||
"control":"component",
|
||||
"gridColumn":"string",
|
||||
"gridRow":"string",
|
||||
"gridColumnStart":"string",
|
||||
"gridColumnEnd":"string",
|
||||
"gridRowStart":"string",
|
||||
"gridRowEnd":"string"
|
||||
}
|
||||
},
|
||||
"width": {"type":"string","default":"auto"},
|
||||
"height": {"type":"string","default":"auto"},
|
||||
"containerClass":"string",
|
||||
"itemContainerClass":"string"
|
||||
},
|
||||
"tags": ["div", "container", "layout", "panel", "grid"]
|
||||
},
|
||||
"text": {
|
||||
"importPath": "Text",
|
||||
"name": "Text",
|
||||
"desciption": "A div with text inside ",
|
||||
"props" : {
|
||||
"value": "string",
|
||||
"containerClass": "string",
|
||||
"background": "string",
|
||||
"border": "string",
|
||||
"font": "string",
|
||||
"color": "string",
|
||||
"padding": "string",
|
||||
"display": {
|
||||
"type": "options",
|
||||
"default":"inline",
|
||||
"options": [
|
||||
"inline", "block", "inline-block"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": ["div", "container"]
|
||||
}
|
||||
}
|
|
@ -11,15 +11,19 @@
|
|||
"start:dev": "sirv public --single --dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@budibase/client": "*",
|
||||
"lodash": "^4.17.15",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"rollup": "^1.11.0",
|
||||
"rollup-plugin-commonjs": "^10.0.2",
|
||||
"rollup-plugin-json": "^4.0.0",
|
||||
"rollup-plugin-livereload": "^1.0.1",
|
||||
"rollup-plugin-node-resolve": "^5.0.0",
|
||||
"rollup-plugin-svelte": "^5.0.0",
|
||||
"rollup-plugin-terser": "^5.1.1",
|
||||
"shortid": "^2.2.15",
|
||||
"sirv-cli": "^0.4.4",
|
||||
"svelte": "^3.0.0"
|
||||
"svelte": "^3.12.1"
|
||||
},
|
||||
"keywords": [
|
||||
"svelte"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
.root.svelte-1s3350l{height:100%;display:grid;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-template-rows:[top] 1fr [center] auto [bottom] 1fr}.content.svelte-1s3350l{grid-column-start:middle;grid-row-start:center;width:400px}.logo-container.svelte-1s3350l{margin-bottom:20px
|
||||
}.logo-container.svelte-1s3350l>img.svelte-1s3350l{max-width:100%}.login-button-container.svelte-1s3350l{text-align:right;margin-top:20px}
|
||||
.label.svelte-98bu7e{grid-column-start:label;padding:5px 10px;vertical-align:middle}.control.svelte-98bu7e{grid-column-start:control;padding:5px 10px}.overflow.svelte-98bu7e{grid-column-start:overflow}.full-width.svelte-98bu7e{width:100%}
|
||||
.form-root.svelte-h706oz{display:grid;grid-template-columns:[label] auto [control] auto}
|
||||
.current.svelte-cgpppc{height:100%;width:100%}
|
||||
input.svelte-bmvn6x{width:100%}input.svelte-bmvn6x{font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px;width:100%}input.svelte-bmvn6x:disabled{color:#ccc}
|
||||
button.svelte-19ku4ig{font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px}button.svelte-19ku4ig{color:#333;background-color:#f4f4f4;outline:none}button.svelte-19ku4ig:active{background-color:#ddd}button.svelte-19ku4ig:focus{border-color:#666}
|
||||
#current_component.svelte-1xqz9vm{height:100%;width:100%}
|
||||
.root.svelte-1oto99m{height:100%;display:grid;grid-template-columns:[left] 1fr [middle] auto [right] 1fr;grid-template-rows:[top] 1fr [center] auto [bottom] 1fr}.content.svelte-1oto99m{grid-column-start:middle;grid-row-start:center;width:400px}.logo-container.svelte-1oto99m{margin-bottom:20px
|
||||
}.logo-container.svelte-1oto99m>img.svelte-1oto99m{max-width:100%}.login-button-container.svelte-1oto99m{text-align:right;margin-top:20px}.incorrect-details-panel.svelte-1oto99m{margin-top:30px;padding:10px;border-style:solid;border-width:1px;border-color:maroon;border-radius:1px;text-align:center;color:maroon;background-color:mistyrose}.form-root.svelte-1oto99m{display:grid;grid-template-columns:[label] auto [control] 1fr}.label.svelte-1oto99m{grid-column-start:label;padding:5px 10px;vertical-align:middle}.control.svelte-1oto99m{grid-column-start:control;padding:5px 10px}
|
||||
.root.svelte-10kw8to{display:grid}
|
||||
.default.svelte-1ec4wqj{width:100%;font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px;width:100%}.default.svelte-1ec4wqj:disabled{color:#ccc}
|
||||
.form-root.svelte-m9d6ue{display:grid;grid-template-columns:[label] auto [control] 1fr}.label.svelte-m9d6ue{grid-column-start:label;padding:5px 10px;vertical-align:middle}.control.svelte-m9d6ue{grid-column-start:control;padding:5px 10px}.overflow.svelte-m9d6ue{grid-column-start:overflow}.full-width.svelte-m9d6ue{width:100%}
|
||||
.default.svelte-1q8lga0{font-family:inherit;font-size:inherit;padding:0.4em;margin:0 0 0.5em 0;box-sizing:border-box;border:1px solid #ccc;border-radius:2px;color:#333;background-color:#f4f4f4;outline:none}.default.svelte-1q8lga0:active{background-color:#ddd}.default.svelte-1q8lga0:focus{border-color:#666}
|
||||
|
||||
/*# sourceMappingURL=bundle.css.map */
|
|
@ -2,21 +2,21 @@
|
|||
"version": 3,
|
||||
"file": "bundle.css",
|
||||
"sources": [
|
||||
"..\\src\\Login.svelte",
|
||||
"..\\src\\FormControl.svelte",
|
||||
"..\\src\\Form.svelte",
|
||||
"..\\src\\Test\\TestApp.svelte",
|
||||
"..\\src\\Login.svelte",
|
||||
"..\\src\\Grid.svelte",
|
||||
"..\\src\\Textbox.svelte",
|
||||
"..\\src\\Form.svelte",
|
||||
"..\\src\\Button.svelte"
|
||||
],
|
||||
"sourcesContent": [
|
||||
"<script>\r\n\r\nimport Textbox from \"./Textbox.svelte\";\r\nimport FormControl from \"./FormControl.svelte\";\r\nimport Form from \"./Form.svelte\";\r\nimport Button from \"./Button.svelte\";\r\n\r\nexport let usernameLabel = \"Username\";\r\nexport let passwordLabel = \"Password\";\r\nexport let loginRedirect = \"\";\r\nexport let logo = \"/budibase-logo.png\";\r\n\r\nlet username = \"\";\r\nlet password = \"\";\r\n\r\n</script>\r\n\r\n<div class=\"root\">\r\n\r\n <div class=\"content\">\r\n\r\n <div class=\"logo-container\">\r\n <img src={logo} alt=\"logo\"/>\r\n </div>\r\n\r\n <Form>\r\n <FormControl label={usernameLabel}>\r\n <Textbox bind:value={username} />\r\n </FormControl>\r\n <FormControl label={passwordLabel}>\r\n <Textbox bind:value={password} hideValue=true />\r\n </FormControl>\r\n </Form>\r\n\r\n <div class=\"login-button-container\">\r\n <Button>Login</Button>\r\n </div>\r\n\r\n </div>\r\n\r\n</div>\r\n\r\n<style>\r\n\r\n.root {\r\n height: 100%;\r\n display:grid;\r\n grid-template-columns: [left] 1fr [middle] auto [right] 1fr;\r\n grid-template-rows: [top] 1fr [center] auto [bottom] 1fr;\r\n}\r\n\r\n.content {\r\n grid-column-start: middle;\r\n grid-row-start: center;\r\n width: 400px;\r\n}\r\n\r\n.logo-container {\r\n margin-bottom: 20px\r\n}\r\n\r\n.logo-container > img {\r\n max-width: 100%;\r\n}\r\n\r\n.login-button-container {\r\n text-align: right;\r\n margin-top: 20px;\r\n}\r\n\r\n</style>",
|
||||
"<script>\r\n\r\nexport let containerClass = \"\";\r\nexport let labelContainerClass = \"\";\r\nexport let controlContainerClass = \"\";\r\nexport let label = \"\";\r\nexport let control;\r\nexport let overflowControl;\r\nexport let fullWidth = false;\r\n\r\n</script>\r\n\r\n<div class=\"label {labelContainerClass}\">{label}</div>\r\n<div class=\"control {controlContainerClass}\" class:full-width={fullWidth}>\r\n {#if control}\r\n <control />\r\n {:else}\r\n <slot />\r\n {/if}\r\n \r\n</div>\r\n<!--div class=\"overflow\">\r\n {#if overflowControl}\r\n <overflowControl />\r\n {:else}\r\n <slot name=\"overflow\" />\r\n {/if}\r\n</div>-->\r\n\r\n<style>\r\n\r\n.label {\r\n grid-column-start: label;\r\n padding: 5px 10px;\r\n vertical-align: middle;\r\n}\r\n.control {\r\n grid-column-start: control;\r\n padding: 5px 10px;\r\n}\r\n.overflow {\r\n grid-column-start: overflow;\r\n}\r\n.full-width {\r\n width: 100%;\r\n}\r\n</style>",
|
||||
"<script>\r\n\r\nexport let containerClass = \"\";\r\nexport let formControls = [];\r\n\r\n</script>\r\n\r\n<div class=\"form-root {containerClass}\">\r\n {#each formControls as formControl}\r\n <formControl />\r\n {:else}\r\n <slot/>\r\n {/each}\r\n</div>\r\n\r\n<style>\r\n.form-root {\r\n display: grid;\r\n grid-template-columns: [label] auto [control] auto; /* [overflow] auto;*/\r\n}\r\n</style>",
|
||||
"<script>\r\nimport Login from \"../Login.svelte\";\r\n</script>\r\n\r\n\r\n<div class=\"current\">\r\n <Login />\r\n</div>\r\n\r\n<style>\r\n.current {\r\n height: 100%;\r\n width: 100%;\r\n}\r\n</style>\r\n\r\n",
|
||||
"<script>\r\n\r\nexport let value=\"\";\r\nexport let hideValue = false;\r\n\r\n</script>\r\n\r\n{#if hideValue}\r\n<input type=\"password\" bind:value={value}/>\r\n{:else}\r\n<input type=\"text\" bind:value={value}/>\r\n{/if}\r\n\r\n<style>\r\ninput {\r\n width: 100%;\r\n}\r\n\r\ninput {\r\n\tfont-family: inherit;\r\n\tfont-size: inherit;\r\n\tpadding: 0.4em;\r\n\tmargin: 0 0 0.5em 0;\r\n\tbox-sizing: border-box;\r\n\tborder: 1px solid #ccc;\r\n border-radius: 2px;\r\n width: 100%;\r\n}\r\n\r\ninput:disabled {\r\n\tcolor: #ccc;\r\n}\r\n\r\n</style>",
|
||||
"<script>\r\nexport let className = \"\";\r\nexport let disabled = false;\r\nexport let contentText;\r\nexport let contentComponent;\r\n</script>\r\n\r\n\r\n<button class={className} {disabled} on:click>\r\n {#if contentComponent}\r\n {contentComponent}\r\n {:else if contentText}\r\n {contentText}\r\n {:else}\r\n <slot />\r\n {/if}\r\n</button>\r\n\r\n\r\n<style>\r\n\r\nbutton {\r\n\tfont-family: inherit;\r\n\tfont-size: inherit;\r\n\tpadding: 0.4em;\r\n\tmargin: 0 0 0.5em 0;\r\n\tbox-sizing: border-box;\r\n\tborder: 1px solid #ccc;\r\n\tborder-radius: 2px;\r\n}\r\n\r\n\r\nbutton {\r\n\tcolor: #333;\r\n\tbackground-color: #f4f4f4;\r\n\toutline: none;\r\n}\r\n\r\nbutton:active {\r\n\tbackground-color: #ddd;\r\n}\r\n\r\nbutton:focus {\r\n\tborder-color: #666;\r\n}\r\n\r\n</style>"
|
||||
"<script>\nimport createApp from \"./createApp\";\nimport { props } from \"./props\";\n\nlet _app;\n\nconst _appPromise = createApp();\n_appPromise.then(a => _app = a);\n\nconst testProps = props.grid;\n\nlet currentComponent;\n\n$: {\n if(_app && currentComponent) {\n _app.initialiseComponent(testProps, currentComponent);\n }\n}\n\n\n\n</script>\n\n{#await _appPromise}\nloading\n{:then _app}\n\n<div id=\"current_component\" bind:this={currentComponent}>\n</div>\n\n{/await}\n\n\n<style>\n#current_component {\n height: 100%;\n width: 100%;\n}\n</style>\n\n",
|
||||
"<script>\n\nimport Textbox from \"./Textbox.svelte\";\nimport Form from \"./Form.svelte\";\nimport Button from \"./Button.svelte\";\nimport { authenticate } from \"./api\";\n\nexport let usernameLabel = \"Username\";\nexport let passwordLabel = \"Password\";\nexport let loginButtonLabel = \"Login\";\nexport let loginRedirect = \"\";\nexport let logo = \"\";\nexport let buttonClass = \"\";\n\nlet username = \"\";\nlet password = \"\";\nlet busy = false;\nlet incorrect = false;\n\nconst login = () => {\n busy = true;\n authenticate(username, password)\n .then(r => {\n busy = false;\n if(r.status === 200) {\n // reload page\n } else {\n incorrect = true;\n }\n })\n}\n\n</script>\n\n<div class=\"root\">\n\n <div class=\"content\">\n\n {#if logo}\n <div class=\"logo-container\">\n <img src={logo} alt=\"logo\"/>\n </div>\n {/if}\n\n <div class=\"form-root\">\n <div class=\"label\">\n {usernameLabel}\n </div>\n <div class=\"control\">\n <Textbox bind:value={username} />\n </div>\n <div class=\"label\">\n {passwordLabel}\n </div>\n <div class=\"control\">\n <Textbox bind:value={password} hideValue=true />\n </div>\n </div>\n\n <div class=\"login-button-container\">\n <Button disabled={busy} \n on:click={login}\n class={buttonClass}>\n {loginButtonLabel}\n </Button>\n </div>\n\n {#if incorrect}\n <div class=\"incorrect-details-panel\">\n Incorrect username or password\n </div>\n {/if}\n\n </div>\n\n</div>\n\n<style>\n\n.root {\n height: 100%;\n display:grid;\n grid-template-columns: [left] 1fr [middle] auto [right] 1fr;\n grid-template-rows: [top] 1fr [center] auto [bottom] 1fr;\n}\n\n.content {\n grid-column-start: middle;\n grid-row-start: center;\n width: 400px;\n}\n\n.logo-container {\n margin-bottom: 20px\n}\n\n.logo-container > img {\n max-width: 100%;\n}\n\n.login-button-container {\n text-align: right;\n margin-top: 20px;\n}\n\n.incorrect-details-panel {\n margin-top: 30px;\n padding: 10px;\n border-style: solid;\n border-width: 1px;\n border-color: maroon;\n border-radius: 1px;\n text-align: center;\n color: maroon;\n background-color: mistyrose;\n}\n\n.form-root {\n display: grid;\n grid-template-columns: [label] auto [control] 1fr; /* [overflow] auto;*/\n}\n\n.label {\n grid-column-start: label;\n padding: 5px 10px;\n vertical-align: middle;\n}\n.control {\n grid-column-start: control;\n padding: 5px 10px;\n}\n\n</style>",
|
||||
"<script>\r\nimport { onMount } from 'svelte'\r\nimport {buildStyle} from \"./buildStyle\";\r\n\r\nexport let gridTemplateRows =\"\";\r\nexport let gridTemplateColumns =\"\";\r\nexport let children = [];\r\nexport let width = \"auto\";\r\nexport let height = \"auto\";\r\nexport let containerClass=\"\";\r\nexport let itemContainerClass=\"\";\r\n\r\n/*\"gridColumnStart\":\"string\",\r\n\"gridColumnEnd\":\"string\",\r\n\"gridRowStart\":\"string\",\r\n\"gridRowEnd\":\"string\"*/\r\n\r\n\r\nexport let _app;\r\n\r\nlet style=\"\";\r\nlet htmlElements = {};\r\n\r\n$ : {\r\n if(_app && htmlElements) {\r\n for(let el in htmlElements) {\r\n _app.initialiseComponent(\r\n children[el].control,\r\n htmlElements[el]\r\n );\r\n }\r\n }\r\n}\r\n\r\nconst childStyle = child => \r\n buildStyle({\r\n \"grid-column-start\": child.gridColumnStart,\r\n \"grid-column-end\": child.gridColumnEnd,\r\n \"grid-column\": child.gridColumn,\r\n \"grid-row-start\": child.gridRowStart,\r\n \"grid-row-end\": child.gridRowStart,\r\n \"grid-row\": child.gridRow,\r\n });\r\n\r\n</script>\r\n\r\n<div class=\"root {containerClass}\"\r\n style=\"width: {width}; height: {height}; grid-template-columns: {gridTemplateColumns}; grid-template-rows: {gridTemplateRows};\">\r\n {#each children as child, index}\r\n <div class=\"{itemContainerClass}\"\r\n style={childStyle(child)}\r\n bind:this={htmlElements[index]}>\r\n </div>\r\n {/each}\r\n</div>\r\n\r\n<style>\r\n\r\n.root {\r\n display: grid;\r\n}\r\n\r\n</style>",
|
||||
"<script>\n\nexport let value=\"\";\nexport let hideValue = false;\nexport let className = \"default\";\n\nexport let _app;\n\nlet actualValue = \"\";\n$: {\n\tif(_app && value._isstate) {\n\t\t_app.store.subscribe(s => {\n\t\t\tactualValue = _app.store.getValue(s, value);\n\t\t});\n\t}\n}\n\nconst onchange = (ev) => {\n\tif(_app && value._isstate) {\n\t\t_app.store.setValue(value, ev.target.value);\n\t} else if(!value._isstate) {\n\t\tactualValue = ev.target.value;\n\t}\n}\n\n</script>\n\n{#if hideValue}\n<input class={className} \n\t type=\"password\" \n\t value={actualValue} on:change/>\n{:else}\n<input class={className} type=\"text\" value={actualValue}/>\n{/if}\n\n<style>\n.default {\n width: 100%;\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tpadding: 0.4em;\n\tmargin: 0 0 0.5em 0;\n\tbox-sizing: border-box;\n\tborder: 1px solid #ccc;\n border-radius: 2px;\n width: 100%;\n}\n\n.default:disabled {\n\tcolor: #ccc;\n}\n\n</style>",
|
||||
"<script>\nexport let containerClass = \"\";\nexport let formControls = [];\n\nexport let _app;\n\nlet htmlElements = {};\nlet labels = {};\n\n$ : {\n let cIndex = 0;\n for(let c of formControls) {\n labels[cIndex] = c.label;\n cIndex++;\n }\n\n if(_app && htmlElements) {\n for(let el in htmlElements) {\n _app.initialiseComponent(\n formControls[el].control,\n htmlElements[el]\n );\n }\n }\n}\n\n</script>\n\n<div class=\"form-root {containerClass}\">\n {#each formControls as child, index}\n <div class=\"label\">{labels[index]}</div>\n <div class=\"control\"\n bind:this={htmlElements[index]}>\n </div>\n {/each}\n</div>\n\n<style>\n.form-root {\n display: grid;\n grid-template-columns: [label] auto [control] 1fr; /* [overflow] auto;*/\n}\n\n.label {\n grid-column-start: label;\n padding: 5px 10px;\n vertical-align: middle;\n}\n.control {\n grid-column-start: control;\n padding: 5px 10px;\n}\n.overflow {\n grid-column-start: overflow;\n}\n.full-width {\n width: 100%;\n}\n</style>",
|
||||
"<script>\nexport let className = \"default\";\nexport let disabled = false;\nexport let contentText;\nexport let contentComponent;\n\nexport let _app;\nlet contentComponentContainer;\n\n$:{\n\tif(_app && contentComponentContainer)\n\t\t_app.initialiseComponent(contentComponent, contentComponentContainer);\n}\n\n</script>\n\n\n<button class={className} {disabled} on:click>\n {#if contentComponent && contentComponent._component}\n\t<div bind:this={contentComponentContainer}>\n\t</div>\n {:else if contentText}\n {contentText}\n {:else}\n <slot />\n {/if}\n</button>\n\n\n<style>\n\n.default {\n\tfont-family: inherit;\n\tfont-size: inherit;\n\tpadding: 0.4em;\n\tmargin: 0 0 0.5em 0;\n\tbox-sizing: border-box;\n\tborder: 1px solid #ccc;\n\tborder-radius: 2px;\n\tcolor: #333;\n\tbackground-color: #f4f4f4;\n\toutline: none;\n}\n\n.default:active {\n\tbackground-color: #ddd;\n}\n\n.default:focus {\n\tborder-color: #666;\n}\n\n</style>"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "AA4CA,KAAK,eAAC,CAAC,AACH,MAAM,CAAE,IAAI,CACZ,QAAQ,IAAI,CACZ,qBAAqB,CAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAC3D,kBAAkB,CAAE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,AAC5D,CAAC,AAED,QAAQ,eAAC,CAAC,AACN,iBAAiB,CAAE,MAAM,CACzB,cAAc,CAAE,MAAM,CACtB,KAAK,CAAE,KAAK,AAChB,CAAC,AAED,eAAe,eAAC,CAAC,AACb,aAAa,CAAE,IAAI;AACvB,CAAC,AAED,8BAAe,CAAG,GAAG,eAAC,CAAC,AACnB,SAAS,CAAE,IAAI,AACnB,CAAC,AAED,uBAAuB,eAAC,CAAC,AACrB,UAAU,CAAE,KAAK,CACjB,UAAU,CAAE,IAAI,AACpB,CAAC;ACrCD,MAAM,cAAC,CAAC,AACJ,iBAAiB,CAAE,KAAK,CACxB,OAAO,CAAE,GAAG,CAAC,IAAI,CACjB,cAAc,CAAE,MAAM,AAC1B,CAAC,AACD,QAAQ,cAAC,CAAC,AACN,iBAAiB,CAAE,OAAO,CAC1B,OAAO,CAAE,GAAG,CAAC,IAAI,AACrB,CAAC,AACD,SAAS,cAAC,CAAC,AACP,iBAAiB,CAAE,QAAQ,AAC/B,CAAC,AACD,WAAW,cAAC,CAAC,AACT,KAAK,CAAE,IAAI,AACf,CAAC;AC7BD,UAAU,cAAC,CAAC,AACR,OAAO,CAAE,IAAI,CACb,qBAAqB,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,AACtD,CAAC;ACTD,QAAQ,cAAC,CAAC,AACN,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,AACf,CAAC;ACCD,KAAK,cAAC,CAAC,AACH,KAAK,CAAE,IAAI,AACf,CAAC,AAED,KAAK,cAAC,CAAC,AACN,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CACnB,UAAU,CAAE,UAAU,CACtB,MAAM,CAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CACnB,aAAa,CAAE,GAAG,CAClB,KAAK,CAAE,IAAI,AACf,CAAC,AAED,mBAAK,SAAS,AAAC,CAAC,AACf,KAAK,CAAE,IAAI,AACZ,CAAC;ACVD,MAAM,eAAC,CAAC,AACP,WAAW,CAAE,OAAO,CACpB,SAAS,CAAE,OAAO,CAClB,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CACnB,UAAU,CAAE,UAAU,CACtB,MAAM,CAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CACtB,aAAa,CAAE,GAAG,AACnB,CAAC,AAGD,MAAM,eAAC,CAAC,AACP,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,OAAO,CACzB,OAAO,CAAE,IAAI,AACd,CAAC,AAED,qBAAM,OAAO,AAAC,CAAC,AACd,gBAAgB,CAAE,IAAI,AACvB,CAAC,AAED,qBAAM,MAAM,AAAC,CAAC,AACb,YAAY,CAAE,IAAI,AACnB,CAAC"
|
||||
"mappings": "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"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +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":{}}
|
|
@ -9,6 +9,7 @@
|
|||
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||
<link rel='stylesheet' href='/global.css'>
|
||||
<link rel='stylesheet' href='/bundle.css'>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -3,9 +3,25 @@ import resolve from 'rollup-plugin-node-resolve';
|
|||
import commonjs from 'rollup-plugin-commonjs';
|
||||
import livereload from 'rollup-plugin-livereload';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import json from 'rollup-plugin-json';
|
||||
|
||||
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", "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",
|
||||
"isObjectLike", "assign", "some", "each", "find", "orderBy", "union", "cloneDeep"];
|
||||
|
||||
const coreExternal = [
|
||||
"lodash", "lodash/fp", "date-fns",
|
||||
"lunr", "safe-buffer", "shortid",
|
||||
"@nx-js/compiler-util"
|
||||
];
|
||||
|
||||
export default {
|
||||
input: 'src/Test/testMain.js',
|
||||
output: {
|
||||
|
@ -32,9 +48,20 @@ export default {
|
|||
// https://github.com/rollup/rollup-plugin-commonjs
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
|
||||
dedupe: importee => {
|
||||
return importee === 'svelte'
|
||||
|| importee.startsWith('svelte/')
|
||||
|| coreExternal.includes(importee);
|
||||
}
|
||||
}),
|
||||
commonjs(),
|
||||
commonjs({
|
||||
namedExports: {
|
||||
"lodash/fp": lodash_fp_exports,
|
||||
"lodash":lodash_exports,
|
||||
"shortid": ["generate"]
|
||||
}
|
||||
}),
|
||||
json(),
|
||||
|
||||
// Watch the `public` directory and refresh the
|
||||
// browser on changes when not in production
|
||||
|
|
|
@ -1,21 +1,59 @@
|
|||
<script>
|
||||
|
||||
export let containerClass = "";
|
||||
export let formControls = [];
|
||||
|
||||
export let _app;
|
||||
|
||||
let htmlElements = {};
|
||||
let labels = {};
|
||||
|
||||
$ : {
|
||||
let cIndex = 0;
|
||||
for(let c of formControls) {
|
||||
labels[cIndex] = c.label;
|
||||
cIndex++;
|
||||
}
|
||||
|
||||
if(_app && htmlElements) {
|
||||
for(let el in htmlElements) {
|
||||
_app.initialiseComponent(
|
||||
formControls[el].control,
|
||||
htmlElements[el]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="form-root {containerClass}">
|
||||
{#each formControls as formControl}
|
||||
<formControl />
|
||||
{:else}
|
||||
<slot/>
|
||||
{#each formControls as child, index}
|
||||
<div class="label">{labels[index]}</div>
|
||||
<div class="control"
|
||||
bind:this={htmlElements[index]}>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.form-root {
|
||||
display: grid;
|
||||
grid-template-columns: [label] auto [control] auto; /* [overflow] auto;*/
|
||||
grid-template-columns: [label] auto [control] 1fr; /* [overflow] auto;*/
|
||||
}
|
||||
|
||||
.label {
|
||||
grid-column-start: label;
|
||||
padding: 5px 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.control {
|
||||
grid-column-start: control;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.overflow {
|
||||
grid-column-start: overflow;
|
||||
}
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,47 +0,0 @@
|
|||
<script>
|
||||
|
||||
export let containerClass = "";
|
||||
export let labelContainerClass = "";
|
||||
export let controlContainerClass = "";
|
||||
export let label = "";
|
||||
export let control;
|
||||
export let overflowControl;
|
||||
export let fullWidth = false;
|
||||
|
||||
</script>
|
||||
|
||||
<div class="label {labelContainerClass}">{label}</div>
|
||||
<div class="control {controlContainerClass}" class:full-width={fullWidth}>
|
||||
{#if control}
|
||||
<control />
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
<!--div class="overflow">
|
||||
{#if overflowControl}
|
||||
<overflowControl />
|
||||
{:else}
|
||||
<slot name="overflow" />
|
||||
{/if}
|
||||
</div>-->
|
||||
|
||||
<style>
|
||||
|
||||
.label {
|
||||
grid-column-start: label;
|
||||
padding: 5px 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.control {
|
||||
grid-column-start: control;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.overflow {
|
||||
grid-column-start: overflow;
|
||||
}
|
||||
.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,63 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte'
|
||||
import {buildStyle} from "./buildStyle";
|
||||
|
||||
export let gridTemplateRows ="";
|
||||
export let gridTemplateColumns ="";
|
||||
export let children = [];
|
||||
export let width = "auto";
|
||||
export let height = "auto";
|
||||
export let containerClass="";
|
||||
export let itemContainerClass="";
|
||||
|
||||
/*"gridColumnStart":"string",
|
||||
"gridColumnEnd":"string",
|
||||
"gridRowStart":"string",
|
||||
"gridRowEnd":"string"*/
|
||||
|
||||
|
||||
export let _app;
|
||||
|
||||
let style="";
|
||||
let htmlElements = {};
|
||||
|
||||
$ : {
|
||||
if(_app && htmlElements) {
|
||||
for(let el in htmlElements) {
|
||||
_app.initialiseComponent(
|
||||
children[el].control,
|
||||
htmlElements[el]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const childStyle = child =>
|
||||
buildStyle({
|
||||
"grid-column-start": child.gridColumnStart,
|
||||
"grid-column-end": child.gridColumnEnd,
|
||||
"grid-column": child.gridColumn,
|
||||
"grid-row-start": child.gridRowStart,
|
||||
"grid-row-end": child.gridRowStart,
|
||||
"grid-row": child.gridRow,
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<div class="root {containerClass}"
|
||||
style="width: {width}; height: {height}; grid-template-columns: {gridTemplateColumns}; grid-template-rows: {gridTemplateRows};">
|
||||
{#each children as child, index}
|
||||
<div class="{itemContainerClass}"
|
||||
style={childStyle(child)}
|
||||
bind:this={htmlElements[index]}>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.root {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,18 +1,34 @@
|
|||
<script>
|
||||
|
||||
import Textbox from "./Textbox.svelte";
|
||||
import FormControl from "./FormControl.svelte";
|
||||
import Form from "./Form.svelte";
|
||||
import Button from "./Button.svelte";
|
||||
import { authenticate } from "./api";
|
||||
|
||||
export let usernameLabel = "Username";
|
||||
export let passwordLabel = "Password";
|
||||
export let loginButtonLabel = "Login";
|
||||
export let loginRedirect = "";
|
||||
export let logo = "/budibase-logo.png";
|
||||
export let logo = "";
|
||||
export let buttonClass = "";
|
||||
|
||||
let username = "";
|
||||
let password = "";
|
||||
let busy = false;
|
||||
let incorrect = false;
|
||||
|
||||
const login = () => {
|
||||
busy = true;
|
||||
authenticate(username, password)
|
||||
.then(r => {
|
||||
busy = false;
|
||||
if(r.status === 200) {
|
||||
// reload page
|
||||
} else {
|
||||
incorrect = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -20,23 +36,41 @@ let password = "";
|
|||
|
||||
<div class="content">
|
||||
|
||||
{#if logo}
|
||||
<div class="logo-container">
|
||||
<img src={logo} alt="logo"/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Form>
|
||||
<FormControl label={usernameLabel}>
|
||||
<div class="form-root">
|
||||
<div class="label">
|
||||
{usernameLabel}
|
||||
</div>
|
||||
<div class="control">
|
||||
<Textbox bind:value={username} />
|
||||
</FormControl>
|
||||
<FormControl label={passwordLabel}>
|
||||
</div>
|
||||
<div class="label">
|
||||
{passwordLabel}
|
||||
</div>
|
||||
<div class="control">
|
||||
<Textbox bind:value={password} hideValue=true />
|
||||
</FormControl>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="login-button-container">
|
||||
<Button>{loginButtonLabel}</Button>
|
||||
<Button disabled={busy}
|
||||
on:click={login}
|
||||
class={buttonClass}>
|
||||
{loginButtonLabel}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{#if incorrect}
|
||||
<div class="incorrect-details-panel">
|
||||
Incorrect username or password
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -69,4 +103,31 @@ let password = "";
|
|||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.incorrect-details-panel {
|
||||
margin-top: 30px;
|
||||
padding: 10px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: maroon;
|
||||
border-radius: 1px;
|
||||
text-align: center;
|
||||
color: maroon;
|
||||
background-color: mistyrose;
|
||||
}
|
||||
|
||||
.form-root {
|
||||
display: grid;
|
||||
grid-template-columns: [label] auto [control] 1fr; /* [overflow] auto;*/
|
||||
}
|
||||
|
||||
.label {
|
||||
grid-column-start: label;
|
||||
padding: 5px 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.control {
|
||||
grid-column-start: control;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -1,14 +1,38 @@
|
|||
<script>
|
||||
import Login from "../Login.svelte";
|
||||
import createApp from "./createApp";
|
||||
import { props } from "./props";
|
||||
|
||||
let _app;
|
||||
|
||||
const _appPromise = createApp();
|
||||
_appPromise.then(a => _app = a);
|
||||
|
||||
const testProps = props.grid;
|
||||
|
||||
let currentComponent;
|
||||
|
||||
$: {
|
||||
if(_app && currentComponent) {
|
||||
_app.initialiseComponent(testProps, currentComponent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
{#await _appPromise}
|
||||
loading
|
||||
{:then _app}
|
||||
|
||||
<div class="current">
|
||||
<Login />
|
||||
<div id="current_component" bind:this={currentComponent}>
|
||||
</div>
|
||||
|
||||
{/await}
|
||||
|
||||
|
||||
<style>
|
||||
.current {
|
||||
#current_component {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { writable } from "svelte/store";
|
||||
import Login from "../Login.svelte";
|
||||
import Grid from "../Grid.svelte";
|
||||
import Form from "../Form.svelte";
|
||||
import Textbox from "../Textbox.svelte";
|
||||
import Text from "../Text.svelte";
|
||||
import { createApp } from "@budibase/client/src/createApp";
|
||||
|
||||
export default async () => {
|
||||
|
||||
const componentLibraries = {
|
||||
components : {
|
||||
login : Login,
|
||||
grid : Grid,
|
||||
form : Form,
|
||||
textbox : Textbox,
|
||||
text: Text
|
||||
}
|
||||
}
|
||||
|
||||
return createApp(componentLibraries);
|
||||
|
||||
const initialiseComponent = (props, htmlElement) => {
|
||||
|
||||
new (components[props._component])({
|
||||
target: htmlElement,
|
||||
props: {...props, _app}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const store = writable({});
|
||||
|
||||
const _app = {
|
||||
initialiseComponent,
|
||||
store
|
||||
};
|
||||
|
||||
return _app;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
export const props = {
|
||||
|
||||
login: { _component:"components/login" },
|
||||
|
||||
form: {
|
||||
_component: "components/form",
|
||||
formControls: [
|
||||
{
|
||||
control: {
|
||||
_component: "components/textbox"
|
||||
},
|
||||
label:"First Name"
|
||||
},
|
||||
{
|
||||
control: {
|
||||
_component: "components/textbox"
|
||||
},
|
||||
label:"Last Name"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
grid: {
|
||||
_component: "components/grid",
|
||||
gridTemplateColumns: "[left] auto [center] auto [right] auto",
|
||||
gridTemplateRows: "[top] auto [middle] auto [bottom] auto",
|
||||
children : [
|
||||
{
|
||||
control: {
|
||||
_component: "components/text",
|
||||
value: "1",
|
||||
background: "blue",
|
||||
textAlign:"center",
|
||||
color: "white"
|
||||
},
|
||||
gridColumn: "left",
|
||||
gridRow: "top"
|
||||
},
|
||||
{
|
||||
control: {
|
||||
_component: "components/text",
|
||||
value: "2",
|
||||
background: "red",
|
||||
textAlign:"center",
|
||||
color: "white",
|
||||
padding: "10px"
|
||||
},
|
||||
gridColumn: "center",
|
||||
gridRow: "middle"
|
||||
},
|
||||
{
|
||||
control: {
|
||||
_component: "components/text",
|
||||
value: "3",
|
||||
background: "yellow",
|
||||
textAlign:"center",
|
||||
color: "black"
|
||||
},
|
||||
gridColumn: "right",
|
||||
gridRow: "bottom"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<script>
|
||||
import {buildStyle} from "./buildStyle";
|
||||
|
||||
export let value="";
|
||||
export let containerClass="";
|
||||
|
||||
export let background="";
|
||||
export let border="";
|
||||
export let font="";
|
||||
export let display="";
|
||||
export let textAlign="";
|
||||
export let color="";
|
||||
export let padding="";
|
||||
|
||||
export let _app;
|
||||
|
||||
let style="";
|
||||
|
||||
|
||||
$: {
|
||||
style=buildStyle({
|
||||
border, background, font,
|
||||
padding, display, color,
|
||||
"text-align": textAlign
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class={containerClass}
|
||||
style={style}>
|
||||
{value}
|
||||
</div>
|
|
@ -4,12 +4,33 @@ export let value="";
|
|||
export let hideValue = false;
|
||||
export let className = "default";
|
||||
|
||||
export let _app;
|
||||
|
||||
let actualValue = "";
|
||||
$: {
|
||||
if(_app && value._isstate) {
|
||||
_app.store.subscribe(s => {
|
||||
actualValue = _app.store.getValue(s, value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const onchange = (ev) => {
|
||||
if(_app && value._isstate) {
|
||||
_app.store.setValue(value, ev.target.value);
|
||||
} else if(!value._isstate) {
|
||||
actualValue = ev.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
{#if hideValue}
|
||||
<input class={className} type="password" bind:value={value}/>
|
||||
<input class={className}
|
||||
type="password"
|
||||
value={actualValue} on:change/>
|
||||
{:else}
|
||||
<input class={className} type="text" bind:value={value}/>
|
||||
<input class={className} type="text" value={actualValue}/>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
const apiCall = (method) => (url, body) =>
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: body && JSON.stringify(body),
|
||||
});
|
||||
|
||||
export const post = apiCall("POST");
|
||||
export const get = apiCall("GET");
|
||||
export const patch = apiCall("PATCH");
|
||||
export const del = apiCall("DELETE");
|
||||
|
||||
export const authenticate = (username, password) => post("./api/authenticate", {
|
||||
username, password
|
||||
});
|
||||
|
||||
export default {
|
||||
post, get, patch, delete:del
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
export const buildStyle = (styles) => {
|
||||
let str = "";
|
||||
for(let s in styles) {
|
||||
if(styles[s]) {
|
||||
str += `${s}: ${styles[s]}; `
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
|
@ -3,6 +3,7 @@ export let className = "default";
|
|||
export let disabled = false;
|
||||
export let contentText;
|
||||
export let contentComponent;
|
||||
export let onClick = () => {};
|
||||
|
||||
export let _app;
|
||||
let contentComponentContainer;
|
||||
|
|
Loading…
Reference in New Issue