diff --git a/packages/client/package.json b/packages/client/package.json index d7fea8dd64..71fb4b6e87 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -15,17 +15,17 @@ "svelte-spa-router": "^3.0.5" }, "devDependencies": { + "@budibase/standard-components": "^0.3.8", + "@rollup/plugin-alias": "^3.1.1", + "@rollup/plugin-commonjs": "^16.0.0", + "@rollup/plugin-node-resolve": "^10.0.0", "fs-extra": "^8.1.0", "jsdom": "^16.0.1", - "rollup": "^2.11.2", - "rollup-plugin-alias": "^2.2.0", - "rollup-plugin-commonjs": "^10.0.0", + "rollup": "^2.33.2", "rollup-plugin-node-builtins": "^2.1.2", "rollup-plugin-node-globals": "^1.4.0", - "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-svelte": "^6.1.1", - "svelte": "3.29.0", - "svelte-jester": "^1.0.6" + "svelte": "^3.29.0" }, "gitHead": "e4e053cb6ff9a0ddc7115b44ccaa24b8ec41fb9a" } diff --git a/packages/client/rollup.config.js b/packages/client/rollup.config.js index c4b2e51a8f..413372416b 100644 --- a/packages/client/rollup.config.js +++ b/packages/client/rollup.config.js @@ -1,9 +1,8 @@ -import resolve from "rollup-plugin-node-resolve" -import commonjs from "rollup-plugin-commonjs" +import alias from "@rollup/plugin-alias" +import commonjs from "@rollup/plugin-commonjs" +import resolve from "@rollup/plugin-node-resolve" import builtins from "rollup-plugin-node-builtins" -import nodeglobals from "rollup-plugin-node-globals" import svelte from "rollup-plugin-svelte" -import alias from "rollup-plugin-alias" import path from "path" const production = !process.env.ROLLUP_WATCH @@ -13,13 +12,7 @@ export default { input: "src/index.js", output: [ { - sourcemap: true, - format: "iife", - name: "app", - file: `./dist/budibase-client.js`, - }, - { - file: "dist/budibase-client.esm.mjs", + file: "dist/budibase-client.js", format: "esm", sourcemap: "inline", }, @@ -45,7 +38,6 @@ export default { }), commonjs(), builtins(), - nodeglobals(), ], watch: { clearScreen: false, diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index dbf19e0865..a3adef6e34 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -2,11 +2,10 @@ import { onMount } from "svelte" import { componentStore } from "../store" import Component from "./Component.svelte" - import { getValidProps } from "../utils" let frontendDefinition let loaded = false - $: pageProps = frontendDefinition?.page?.props + $: pageDefinition = frontendDefinition?.page?.props onMount(async () => { frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] @@ -17,9 +16,5 @@ {#if loaded} - + {/if} diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 5b0565eb94..4e4df7664c 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -1,31 +1,35 @@ -{#if componentConstructor} -
- - {#if children && children.length} - {#each children as child} - - {/each} - {/if} - -
+{#if constructor} + + {#if children && children.length} + {#each children as child} + + {/each} + {/if} + {/if} diff --git a/packages/client/src/components/Router.svelte b/packages/client/src/components/Router.svelte index b08dc4d5a4..3b5cd675c6 100644 --- a/packages/client/src/components/Router.svelte +++ b/packages/client/src/components/Router.svelte @@ -1,9 +1,10 @@ {#if routes} - +
+ +
{/if} diff --git a/packages/client/src/components/Screen.svelte b/packages/client/src/components/Screen.svelte index 35c4fbfc14..894e1b0ea2 100644 --- a/packages/client/src/components/Screen.svelte +++ b/packages/client/src/components/Screen.svelte @@ -1,20 +1,24 @@ {#if screenDefinition} - + {/if} diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 68f5d2d701..cb00d4b708 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -2,6 +2,7 @@ import ClientApp from "./components/ClientApp.svelte" // Initialise client app const loadBudibase = () => { + window.document.body.innerHTML = "" new ClientApp({ target: window.document.body, }) diff --git a/packages/client/src/store/components.js b/packages/client/src/store/components.js index eed1c87325..4ab0a85b3f 100644 --- a/packages/client/src/store/components.js +++ b/packages/client/src/store/components.js @@ -2,10 +2,8 @@ import { writable, get } from "svelte/store" import { getAppId } from "@budibase/component-sdk" import Router from "../components/Router.svelte" -const initialState = {} - -export const createComponentStore = () => { - const store = writable(initialState) +const createComponentStore = () => { + const store = writable({}) /** * Loads the component library from the server @@ -25,14 +23,13 @@ export const createComponentStore = () => { if (!componentName) { return null } - const split = componentName.split("/") - const strippedName = split[split.length - 1] // Edge case for screen slot - if (strippedName === "screenslot") { + if (componentName === "screenslot") { return Router } - return get(store)[strippedName] + + return get(store)[componentName] } // Attach actions to the store @@ -40,3 +37,5 @@ export const createComponentStore = () => { return store } + +export const componentStore = createComponentStore() diff --git a/packages/client/src/store/index.js b/packages/client/src/store/index.js index ea0a3b5709..08a4ea7e95 100644 --- a/packages/client/src/store/index.js +++ b/packages/client/src/store/index.js @@ -1,3 +1 @@ -import { createComponentStore } from "./components" - -export const componentStore = createComponentStore() +export { componentStore } from "./components" diff --git a/packages/client/src/utils.js b/packages/client/src/utils.js index 6df8fd6d40..0a08ce8386 100644 --- a/packages/client/src/utils.js +++ b/packages/client/src/utils.js @@ -1,16 +1,3 @@ -/** - * Builds a style string from a style object. - */ -export const buildStyle = styles => { - let str = "" - Object.entries(styles).forEach(([style, value]) => { - if (style && value) { - str += `${style}: ${value}; ` - } - }) - return str -} - /** * Extracts all valid props from a component definition that should be passed to * its actual component instance. diff --git a/packages/component-sdk/package.json b/packages/component-sdk/package.json index 2087d6e52d..9681576e11 100644 --- a/packages/component-sdk/package.json +++ b/packages/component-sdk/package.json @@ -21,6 +21,7 @@ "rollup-plugin-svelte": "^6.1.1" }, "dependencies": { + "svelte": "^3.29.0", "svelte-spa-router": "^3.0.5" } } diff --git a/packages/component-sdk/src/api/rows.js b/packages/component-sdk/src/api/rows.js index 5875300546..a8b16a1c06 100644 --- a/packages/component-sdk/src/api/rows.js +++ b/packages/component-sdk/src/api/rows.js @@ -14,21 +14,19 @@ export const fetchRow = async ({ tableId, rowId }) => { /** * Creates a row in a table. */ -export const saveRow = async (params, state) => { +export const saveRow = async row => { return await api.post({ - url: `/api/${params.tableId}/rows`, - body: makeRowRequestBody(params, state), + url: `/api/${row.tableId}/rows`, + body: row, }) } /** * Updates a row in a table. */ -export const updateRow = async (params, state) => { - const row = makeRowRequestBody(params, state) - row._id = params._id +export const updateRow = async row => { return await api.patch({ - url: `/api/${params.tableId}/rows/${params._id}`, + url: `/api/${row.tableId}/rows/${row._id}`, body: row, }) } @@ -55,44 +53,6 @@ export const deleteRows = async ({ tableId, rows }) => { }) } -/** - * Sanitises and parses column types when saving and updating rows. - */ -const makeRowRequestBody = (parameters, state) => { - // start with the row thats currently in context - const body = { ...(state.data || {}) } - - // dont send the table - if (body._table) delete body._table - - // then override with supplied parameters - if (parameters.fields) { - for (let fieldName of Object.keys(parameters.fields)) { - const field = parameters.fields[fieldName] - - // ensure fields sent are of the correct type - if (field.type === "boolean") { - if (field.value === "true") body[fieldName] = true - if (field.value === "false") body[fieldName] = false - } else if (field.type === "number") { - const val = parseFloat(field.value) - if (!isNaN(val)) { - body[fieldName] = val - } - } else if (field.type === "datetime") { - const date = new Date(field.value) - if (!isNaN(date.getTime())) { - body[fieldName] = date.toISOString() - } - } else { - body[fieldName] = field.value - } - } - } - - return body -} - /** * Enriches rows which contain certain field types so that they can * be properly displayed. diff --git a/packages/component-sdk/src/context/contextTypes.js b/packages/component-sdk/src/context/contextTypes.js new file mode 100644 index 0000000000..3092147d30 --- /dev/null +++ b/packages/component-sdk/src/context/contextTypes.js @@ -0,0 +1 @@ +export const DataProvider = "bb-data-provider" diff --git a/packages/component-sdk/src/context/dataProvider.js b/packages/component-sdk/src/context/dataProvider.js new file mode 100644 index 0000000000..10d1b88cfb --- /dev/null +++ b/packages/component-sdk/src/context/dataProvider.js @@ -0,0 +1,24 @@ +import { writable } from "svelte/store" + +export const createDataProviderContext = () => { + const store = writable({ + rows: [], + table: null, + }) + const setRows = rows => { + store.update(state => { + state.rows = rows + return state + }) + } + const setTable = table => { + store.update(state => { + state.table = table + return state + }) + } + return { + subscribe: store.subscribe, + actions: { setRows, setTable }, + } +} diff --git a/packages/component-sdk/src/context/index.js b/packages/component-sdk/src/context/index.js index ba5c1047ce..45c7f54d88 100644 --- a/packages/component-sdk/src/context/index.js +++ b/packages/component-sdk/src/context/index.js @@ -1 +1,2 @@ -export const RouterContext = "bb-router" +export * from "./dataProvider" +export * as ContextTypes from "./contextTypes" diff --git a/packages/component-sdk/src/index.js b/packages/component-sdk/src/index.js index 64af7c9cb5..81228a5503 100644 --- a/packages/component-sdk/src/index.js +++ b/packages/component-sdk/src/index.js @@ -1,5 +1,5 @@ export * from "./api" export * from "./store" -export * as ContextTypes from "./context" -export { getAppId } from "./utils" -export { link } from "svelte-spa-router" +export * from "./context" +export * from "./utils" +export { link as linkable } from "svelte-spa-router" diff --git a/packages/component-sdk/src/store/auth.js b/packages/component-sdk/src/store/auth.js index 287dab767d..bca9e4935e 100644 --- a/packages/component-sdk/src/store/auth.js +++ b/packages/component-sdk/src/store/auth.js @@ -1,11 +1,9 @@ -import { localStorageStore } from "../../../builder/src/builderStore/store/localStorage" import * as api from "../api" import { getAppId } from "../utils" - -const initialState = "" +import { writable } from "svelte/store" export const createAuthStore = () => { - const store = localStorageStore("budibase:token", initialState) + const store = writable("") /** * Logs a user in. @@ -22,7 +20,7 @@ export const createAuthStore = () => { * Logs a user out. */ const logOut = () => { - store.set(initialState) + store.set("") // Expire any cookies const appId = getAppId() @@ -33,10 +31,14 @@ export const createAuthStore = () => { } } - store.actions = { - logIn, - logOut, + return { + subscribe: store.subscribe, + actions: { logIn, logOut }, } - - return store } + +if (!window.bbSDKAuthStore) { + window.bbSDKAuthStore = createAuthStore() +} + +export const authStore = window.bbSDKAuthStore diff --git a/packages/component-sdk/src/store/config.js b/packages/component-sdk/src/store/config.js index b6978d6f77..934a62d939 100644 --- a/packages/component-sdk/src/store/config.js +++ b/packages/component-sdk/src/store/config.js @@ -37,11 +37,14 @@ export const createConfigStore = () => { handler && handler(error) } - store.actions = { - initialise, - reset, - handleError, + return { + subscribe: store.subscribe, + actions: { initialise, reset, handleError }, } - - return store } + +if (!window.bbSDKConfigStore) { + window.bbSDKConfigStore = createConfigStore() +} + +export const configStore = window.bbSDKConfigStore diff --git a/packages/component-sdk/src/store/index.js b/packages/component-sdk/src/store/index.js index 91baa595b3..75777e10ed 100644 --- a/packages/component-sdk/src/store/index.js +++ b/packages/component-sdk/src/store/index.js @@ -1,9 +1,4 @@ -import { createConfigStore } from "./config" -import { createAuthStore } from "./auth" -import { createRouteStore } from "./routes" -import { createScreenStore } from "./screens" - -export const configStore = createConfigStore() -export const authStore = createAuthStore() -export const routeStore = createRouteStore() -export const screenStore = createScreenStore() +export { configStore } from "./config" +export { authStore } from "./auth" +export { routeStore } from "./routes" +export { screenStore } from "./screens" diff --git a/packages/component-sdk/src/store/routes.js b/packages/component-sdk/src/store/routes.js index 50eb072938..7520a4345b 100644 --- a/packages/component-sdk/src/store/routes.js +++ b/packages/component-sdk/src/store/routes.js @@ -1,9 +1,12 @@ import { writable } from "svelte/store" import { push } from "svelte-spa-router" -const initialState = [] - export const createRouteStore = () => { + const initialState = { + routes: [], + routeParams: {}, + activeRoute: null, + } const store = writable(initialState) const fetchRoutes = () => { @@ -12,10 +15,35 @@ export const createRouteStore = () => { path: screen.route, screenId: screen._id, })) - store.set(routes) + store.update(state => { + state.routes = routes + return state + }) + } + const setRouteParams = routeParams => { + console.log("new route params: ") + console.log(routeParams) + store.update(state => { + state.routeParams = routeParams + return state + }) + } + const setActiveRoute = route => { + store.update(state => { + state.activeRoute = route + return state + }) } const navigate = push - store.actions = { fetchRoutes, navigate } - return store + return { + subscribe: store.subscribe, + actions: { fetchRoutes, navigate, setRouteParams, setActiveRoute }, + } } + +if (!window.bbSDKRouteStore) { + window.bbSDKRouteStore = createRouteStore() +} + +export const routeStore = window.bbSDKRouteStore diff --git a/packages/component-sdk/src/store/screens.js b/packages/component-sdk/src/store/screens.js index c29535d34e..f59e8aa9a7 100644 --- a/packages/component-sdk/src/store/screens.js +++ b/packages/component-sdk/src/store/screens.js @@ -1,25 +1,33 @@ -import { writable, derived, get } from "svelte/store" - -const initialState = [] +import { writable, derived } from "svelte/store" +import { routeStore } from "./routes" export const createScreenStore = () => { - const store = writable(initialState) - const routeLookupMap = derived(store, $screens => { - let map = {} - $screens.forEach(screen => { - map[screen.route] = screen - }) - return map + console.log("CREATE SCREEN STORE") + + const screens = writable([]) + const store = derived([screens, routeStore], ([$screens, $routeStore]) => { + const activeScreen = $screens.find( + screen => screen.route === $routeStore.activeRoute + ) + return { + screens: $screens, + activeScreen, + } }) const fetchScreens = () => { const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] - store.set(frontendDefinition.screens) + screens.set(frontendDefinition.screens) } - const getScreenByRoute = path => { - return get(routeLookupMap)[path] - } - store.actions = { fetchScreens, getScreenByRoute } - return store + return { + subscribe: store.subscribe, + actions: { fetchScreens }, + } } + +if (!window.bbSDKScreenStore) { + window.bbSDKScreenStore = createScreenStore() +} + +export const screenStore = window.bbSDKScreenStore diff --git a/packages/component-sdk/src/utils/index.js b/packages/component-sdk/src/utils/index.js index 1eb0ca2cfe..63da748cf6 100644 --- a/packages/component-sdk/src/utils/index.js +++ b/packages/component-sdk/src/utils/index.js @@ -1 +1,2 @@ export { getAppId } from "./getAppId" +export { styleable } from "./styleable" diff --git a/packages/component-sdk/src/utils/styleable.js b/packages/component-sdk/src/utils/styleable.js new file mode 100644 index 0000000000..8f1d7ac3e1 --- /dev/null +++ b/packages/component-sdk/src/utils/styleable.js @@ -0,0 +1,46 @@ +const buildStyleString = styles => { + let str = "" + Object.entries(styles).forEach(([style, value]) => { + if (style && value) { + str += `${style}: ${value}; ` + } + }) + return str +} + +/** + * Svelte action to apply correct component styles. + */ +export const styleable = (node, styles = {}) => { + const normalStyles = styles.normal || {} + const hoverStyles = { + ...normalStyles, + ...styles.hover, + } + + function applyNormalStyles() { + node.style = buildStyleString(normalStyles) + } + + function applyHoverStyles() { + node.style = buildStyleString(hoverStyles) + } + + // Add listeners to toggle hover styles + node.addEventListener("mouseover", applyHoverStyles) + node.addEventListener("mouseout", applyNormalStyles) + + // Apply normal styles initially + applyNormalStyles() + + // Also apply data tags so we know how to reference each component + node.setAttribute("data-bb-id", styles.id) + + return { + // Clean up event listeners when component is destroyed + destroy: () => { + node.removeEventListener("mouseover", applyHoverStyles) + node.removeEventListener("mouseout", applyNormalStyles) + }, + } +} diff --git a/packages/component-sdk/yarn.lock b/packages/component-sdk/yarn.lock index 5266d3e283..821ffe191f 100644 --- a/packages/component-sdk/yarn.lock +++ b/packages/component-sdk/yarn.lock @@ -828,6 +828,11 @@ svelte-spa-router@^3.0.5: dependencies: regexparam "1.3.0" +svelte@^3.29.0: + version "3.29.7" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.29.7.tgz#e254eb2d0d609ce0fd60f052d444ac4a66d90f7d" + integrity sha512-rx0g311kBODvEWUU01DFBUl3MJuJven04bvTVFUG/w0On/wuj0PajQY/QlXcJndFxG+W1s8iXKaB418tdHWc3A== + typedarray-to-buffer@~1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-1.0.4.tgz#9bb8ba0e841fb3f4cf1fe7c245e9f3fa8a5fe99c" diff --git a/packages/standard-components/package.json b/packages/standard-components/package.json index 64d41ae5f8..71ca8815a8 100644 --- a/packages/standard-components/package.json +++ b/packages/standard-components/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/standard-components", - "svelte": "src/index.svelte", + "svelte": "src/index.js", "main": "dist/index.js", "module": "dist/index.js", "scripts": { @@ -15,13 +15,13 @@ "devDependencies": { "@budibase/client": "^0.3.6", "@rollup/plugin-alias": "^3.1.1", - "@rollup/plugin-commonjs": "^11.1.0", + "@rollup/plugin-commonjs": "^16.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^10.0.0", + "@rollup/plugin-replace": "^2.3.4", "lodash": "^4.17.15", "rollup": "^2.11.2", - "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-postcss": "^3.1.5", "rollup-plugin-svelte": "^6.1.1", "rollup-plugin-terser": "^7.0.2", diff --git a/packages/standard-components/rollup.config.js b/packages/standard-components/rollup.config.js index ae191bfc16..7e49654b66 100644 --- a/packages/standard-components/rollup.config.js +++ b/packages/standard-components/rollup.config.js @@ -1,13 +1,13 @@ -import svelte from "rollup-plugin-svelte" -import resolve from "rollup-plugin-node-resolve" -import commonjs from "@rollup/plugin-commonjs" -import postcss from "rollup-plugin-postcss" import alias from "@rollup/plugin-alias" +import commonjs from "@rollup/plugin-commonjs" +import resolve from "@rollup/plugin-node-resolve" +import replace from "@rollup/plugin-replace" +import svelte from "rollup-plugin-svelte" +import postcss from "rollup-plugin-postcss" import { terser } from "rollup-plugin-terser" import path from "path" const production = !process.env.ROLLUP_WATCH -const lodash_fp_exports = ["isEmpty"] const projectRootDir = path.resolve(__dirname) export default { @@ -17,7 +17,7 @@ export default { file: "dist/index.js", format: "esm", name: "budibaseStandardComponents", - sourcemap: true, + sourcemap: false, }, ], plugins: [ @@ -33,19 +33,18 @@ export default { ], }), production && terser(), - postcss({ - plugins: [], - }), + postcss(), svelte({ - hydratable: true, + dev: !production, }), resolve({ browser: true, }), - commonjs({ - namedExports: { - "lodash/fp": lodash_fp_exports, - }, + commonjs(), + // Fix for https://github.com/sveltejs/svelte/issues/3165 + replace({ + "outros.c.push": + "if (outros === undefined) { block.o(local); return }\noutros.c.push", }), ], } diff --git a/packages/standard-components/src/Button.svelte b/packages/standard-components/src/Button.svelte index 54f7812dc2..89fa1ad273 100644 --- a/packages/standard-components/src/Button.svelte +++ b/packages/standard-components/src/Button.svelte @@ -1,25 +1,20 @@ diff --git a/packages/standard-components/src/Container.svelte b/packages/standard-components/src/Container.svelte index c850e44a5c..4259bf9cef 100644 --- a/packages/standard-components/src/Container.svelte +++ b/packages/standard-components/src/Container.svelte @@ -1,58 +1,61 @@ {#if type === 'div'} -
+
{:else if type === 'header'} -
+
{:else if type === 'main'} -
+
{:else if type === 'footer'} -