mirror of https://github.com/Budibase/budibase.git
42 changed files with 393 additions and 341 deletions
@ -1,31 +1,35 @@ |
|||||
<script> |
<script> |
||||
import { componentStore } from "../store" |
import { componentStore } from "../store" |
||||
import { buildStyle, getValidProps } from "../utils" |
import { getValidProps } from "../utils" |
||||
|
|
||||
export let props |
export let definition = {} |
||||
export let children |
|
||||
export let component |
|
||||
export let styles |
|
||||
|
|
||||
$: componentConstructor = componentStore.actions.getComponent(component) |
$: componentProps = getValidProps(definition) |
||||
$: console.log("Rendering: " + component) |
$: children = definition._children |
||||
|
$: componentName = extractComponentName(definition._component) |
||||
|
$: constructor = componentStore.actions.getComponent(componentName) |
||||
|
$: id = `${componentName}-${definition._id}` |
||||
|
$: styles = { ...definition._styles, id } |
||||
|
|
||||
|
// Extracts the actual component name from the library name |
||||
|
function extractComponentName(name) { |
||||
|
console.log(name) |
||||
|
if (name == null) { |
||||
|
console.log(definition) |
||||
|
} |
||||
|
const split = name.split("/") |
||||
|
return split[split.length - 1] |
||||
|
} |
||||
|
|
||||
|
$: console.log("Rendering: " + componentName) |
||||
</script> |
</script> |
||||
|
|
||||
{#if componentConstructor} |
{#if constructor} |
||||
<div |
<svelte:component this={constructor} {...componentProps} {styles}> |
||||
style={buildStyle(styles)} |
{#if children && children.length} |
||||
data-bb-component={component} |
{#each children as child} |
||||
data-bb-name={component._instanceName}> |
<svelte:self definition={child} /> |
||||
<svelte:component this={componentConstructor} {...props}> |
{/each} |
||||
{#if children && children.length} |
{/if} |
||||
{#each children as child} |
</svelte:component> |
||||
<svelte:self |
|
||||
props={getValidProps(child)} |
|
||||
component={child._component} |
|
||||
children={child._children} |
|
||||
styles={child._styles.normal} /> |
|
||||
{/each} |
|
||||
{/if} |
|
||||
</svelte:component> |
|
||||
</div> |
|
||||
{/if} |
{/if} |
||||
|
|||||
@ -1,20 +1,24 @@ |
|||||
<script> |
<script> |
||||
import { screenStore } from "@budibase/component-sdk" |
import { screenStore, routeStore } from "@budibase/component-sdk" |
||||
import { location } from "svelte-spa-router" |
|
||||
import Component from "./Component.svelte" |
import Component from "./Component.svelte" |
||||
import { getValidProps } from "../utils" |
import { getValidProps } from "../utils" |
||||
|
|
||||
export let params |
export let params |
||||
|
|
||||
// Get the screen definition for the current route |
// Get the screen definition for the current route |
||||
$: screenDefinition = screenStore.actions.getScreenByRoute($location) |
$: screenDefinition = $screenStore.activeScreen |
||||
$: screenStore.actions |
|
||||
|
// Update route params |
||||
|
$: routeStore.actions.setRouteParams(params) |
||||
|
|
||||
|
// Redirect to home page if no matching route |
||||
|
$: { |
||||
|
if (screenDefinition == null) { |
||||
|
routeStore.actions.navigate("/") |
||||
|
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
{#if screenDefinition} |
{#if screenDefinition} |
||||
<Component |
<Component definition={screenDefinition.props} /> |
||||
component={screenDefinition.props._component} |
|
||||
props={getValidProps(screenDefinition.props)} |
|
||||
children={screenDefinition.props._children} |
|
||||
styles={screenDefinition.props._styles.normal} /> |
|
||||
{/if} |
{/if} |
||||
|
|||||
@ -1,3 +1 @@ |
|||||
import { createComponentStore } from "./components" |
export { componentStore } from "./components" |
||||
|
|
||||
export const componentStore = createComponentStore() |
|
||||
|
|||||
@ -0,0 +1 @@ |
|||||
|
export const DataProvider = "bb-data-provider" |
||||
@ -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 }, |
||||
|
} |
||||
|
} |
||||
@ -1 +1,2 @@ |
|||||
export const RouterContext = "bb-router" |
export * from "./dataProvider" |
||||
|
export * as ContextTypes from "./contextTypes" |
||||
|
|||||
@ -1,5 +1,5 @@ |
|||||
export * from "./api" |
export * from "./api" |
||||
export * from "./store" |
export * from "./store" |
||||
export * as ContextTypes from "./context" |
export * from "./context" |
||||
export { getAppId } from "./utils" |
export * from "./utils" |
||||
export { link } from "svelte-spa-router" |
export { link as linkable } from "svelte-spa-router" |
||||
|
|||||
@ -1,9 +1,4 @@ |
|||||
import { createConfigStore } from "./config" |
export { configStore } from "./config" |
||||
import { createAuthStore } from "./auth" |
export { authStore } from "./auth" |
||||
import { createRouteStore } from "./routes" |
export { routeStore } from "./routes" |
||||
import { createScreenStore } from "./screens" |
export { screenStore } from "./screens" |
||||
|
|
||||
export const configStore = createConfigStore() |
|
||||
export const authStore = createAuthStore() |
|
||||
export const routeStore = createRouteStore() |
|
||||
export const screenStore = createScreenStore() |
|
||||
|
|||||
@ -1,25 +1,33 @@ |
|||||
import { writable, derived, get } from "svelte/store" |
import { writable, derived } from "svelte/store" |
||||
|
import { routeStore } from "./routes" |
||||
const initialState = [] |
|
||||
|
|
||||
export const createScreenStore = () => { |
export const createScreenStore = () => { |
||||
const store = writable(initialState) |
console.log("CREATE SCREEN STORE") |
||||
const routeLookupMap = derived(store, $screens => { |
|
||||
let map = {} |
const screens = writable([]) |
||||
$screens.forEach(screen => { |
const store = derived([screens, routeStore], ([$screens, $routeStore]) => { |
||||
map[screen.route] = screen |
const activeScreen = $screens.find( |
||||
}) |
screen => screen.route === $routeStore.activeRoute |
||||
return map |
) |
||||
|
return { |
||||
|
screens: $screens, |
||||
|
activeScreen, |
||||
|
} |
||||
}) |
}) |
||||
|
|
||||
const fetchScreens = () => { |
const fetchScreens = () => { |
||||
const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] |
const frontendDefinition = window["##BUDIBASE_FRONTEND_DEFINITION##"] |
||||
store.set(frontendDefinition.screens) |
screens.set(frontendDefinition.screens) |
||||
} |
} |
||||
const getScreenByRoute = path => { |
|
||||
return get(routeLookupMap)[path] |
return { |
||||
|
subscribe: store.subscribe, |
||||
|
actions: { fetchScreens }, |
||||
} |
} |
||||
store.actions = { fetchScreens, getScreenByRoute } |
} |
||||
|
|
||||
return store |
if (!window.bbSDKScreenStore) { |
||||
|
window.bbSDKScreenStore = createScreenStore() |
||||
} |
} |
||||
|
|
||||
|
export const screenStore = window.bbSDKScreenStore |
||||
|
|||||
@ -1 +1,2 @@ |
|||||
export { getAppId } from "./getAppId" |
export { getAppId } from "./getAppId" |
||||
|
export { styleable } from "./styleable" |
||||
|
|||||
@ -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) |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
@ -1,58 +1,61 @@ |
|||||
<script> |
<script> |
||||
|
import { styleable } from "@budibase/component-sdk" |
||||
|
|
||||
export let className = "" |
export let className = "" |
||||
export let type = "div" |
export let type = "div" |
||||
|
export let styles |
||||
$: console.log(type) |
|
||||
</script> |
</script> |
||||
|
|
||||
{#if type === 'div'} |
{#if type === 'div'} |
||||
<div> |
<div use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</div> |
</div> |
||||
{:else if type === 'header'} |
{:else if type === 'header'} |
||||
<header> |
<header use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</header> |
</header> |
||||
{:else if type === 'main'} |
{:else if type === 'main'} |
||||
<main> |
<main use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</main> |
</main> |
||||
{:else if type === 'footer'} |
{:else if type === 'footer'} |
||||
<footer> |
<footer use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</footer> |
</footer> |
||||
{:else if type === 'aside'} |
{:else if type === 'aside'} |
||||
<aside> |
<aside use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</aside> |
</aside> |
||||
{:else if type === 'summary'} |
{:else if type === 'summary'} |
||||
<summary> |
<summary use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</summary> |
</summary> |
||||
{:else if type === 'details'} |
{:else if type === 'details'} |
||||
<details> |
<details use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</details> |
</details> |
||||
{:else if type === 'article'} |
{:else if type === 'article'} |
||||
<article> |
<article use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</article> |
</article> |
||||
{:else if type === 'nav'} |
{:else if type === 'nav'} |
||||
<nav> |
<nav use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</nav> |
</nav> |
||||
{:else if type === 'mark'} |
{:else if type === 'mark'} |
||||
<mark><slot /></mark> |
<mark use:styleable={styles}> |
||||
|
<slot /> |
||||
|
</mark> |
||||
{:else if type === 'figure'} |
{:else if type === 'figure'} |
||||
<figure> |
<figure use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</figure> |
</figure> |
||||
{:else if type === 'figcaption'} |
{:else if type === 'figcaption'} |
||||
<figcaption> |
<figcaption use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</figcaption> |
</figcaption> |
||||
{:else if type === 'paragraph'} |
{:else if type === 'paragraph'} |
||||
<p> |
<p use:styleable={styles}> |
||||
<slot /> |
<slot /> |
||||
</p> |
</p> |
||||
{/if} |
{/if} |
||||
|
|||||
@ -1,10 +1,10 @@ |
|||||
<script> |
<script> |
||||
import Form from "./Form.svelte" |
import Form from "./Form.svelte" |
||||
|
|
||||
export let _bb |
|
||||
export let table |
export let table |
||||
export let title |
export let title |
||||
export let buttonText |
export let buttonText |
||||
|
export let styles |
||||
</script> |
</script> |
||||
|
|
||||
<Form {_bb} {table} {title} {buttonText} wide={true} /> |
<Form {styles} {table} {title} {buttonText} wide /> |
||||
|
|||||
@ -1,5 +1,23 @@ |
|||||
<script> |
<script> |
||||
|
import { styleable } from "@budibase/component-sdk" |
||||
|
|
||||
export let embed |
export let embed |
||||
|
export let styles |
||||
</script> |
</script> |
||||
|
|
||||
{@html embed} |
<div use:styleable={styles}> |
||||
|
{@html embed} |
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
div { |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
justify-content: center; |
||||
|
align-items: stretch; |
||||
|
} |
||||
|
div :global(> *) { |
||||
|
flex: 1 1 auto; |
||||
|
} |
||||
|
</style> |
||||
|
|||||
@ -1,29 +1,22 @@ |
|||||
<script> |
<script> |
||||
|
import { styleable } from "@budibase/component-sdk" |
||||
|
|
||||
export let className = "" |
export let className = "" |
||||
export let type |
export let type |
||||
export let text = "" |
export let text = "" |
||||
|
export let styles |
||||
export let _bb |
|
||||
|
|
||||
let containerElement |
|
||||
|
|
||||
$: containerElement && |
|
||||
!text && |
|
||||
_bb.props.children && |
|
||||
_bb.props.children.length && |
|
||||
_bb.attachChildren(containerElement) |
|
||||
</script> |
</script> |
||||
|
|
||||
{#if type === 'h1'} |
{#if type === 'h1'} |
||||
<h1 class={className} bind:this={containerElement}>{text}</h1> |
<h1 class={className} use:styleable={styles}>{text}</h1> |
||||
{:else if type === 'h2'} |
{:else if type === 'h2'} |
||||
<h2 class={className} bind:this={containerElement}>{text}</h2> |
<h2 class={className} use:styleable={styles}>{text}</h2> |
||||
{:else if type === 'h3'} |
{:else if type === 'h3'} |
||||
<h3 class={className} bind:this={containerElement}>{text}</h3> |
<h3 class={className} use:styleable={styles}>{text}</h3> |
||||
{:else if type === 'h4'} |
{:else if type === 'h4'} |
||||
<h4 class={className} bind:this={containerElement}>{text}</h4> |
<h4 class={className} use:styleable={styles}>{text}</h4> |
||||
{:else if type === 'h5'} |
{:else if type === 'h5'} |
||||
<h5 class={className} bind:this={containerElement}>{text}</h5> |
<h5 class={className} use:styleable={styles}>{text}</h5> |
||||
{:else if type === 'h6'} |
{:else if type === 'h6'} |
||||
<h6 class={className} bind:this={containerElement}>{text}</h6> |
<h6 class={className} use:styleable={styles}>{text}</h6> |
||||
{/if} |
{/if} |
||||
|
|||||
Loading…
Reference in new issue