mirror of https://github.com/Budibase/budibase.git
committed by
GitHub
48 changed files with 1403 additions and 256 deletions
@ -0,0 +1,17 @@ |
|||||
|
export const insertCodeMetadata = props => { |
||||
|
if (props._code && props._code.length > 0) { |
||||
|
props._codeMeta = codeMetaData(props._code) |
||||
|
} |
||||
|
|
||||
|
if (!props._children || props._children.length === 0) return |
||||
|
|
||||
|
for (let child of props._children) { |
||||
|
insertCodeMetadata(child) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const codeMetaData = code => { |
||||
|
return { |
||||
|
dependsOnStore: RegExp(/(store.)/g).test(code), |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,55 @@ |
|||||
|
<script> |
||||
|
import Button from "./Button.svelte" |
||||
|
import ButtonGroup from "./ButtonGroup.svelte" |
||||
|
import UIkit from "uikit" |
||||
|
|
||||
|
export let title="" |
||||
|
export let body="" |
||||
|
export let okText = "OK" |
||||
|
export let cancelText = "Cancel" |
||||
|
export let onOk = ()=> {} |
||||
|
export let onCancel = ()=> {} |
||||
|
|
||||
|
export const show = () => { |
||||
|
UIkit.modal(theModal).show() |
||||
|
} |
||||
|
|
||||
|
export const hide = () => { |
||||
|
UIkit.modal(theModal).hide() |
||||
|
} |
||||
|
|
||||
|
let theModal; |
||||
|
|
||||
|
const cancel = () => { |
||||
|
hide() |
||||
|
onCancel() |
||||
|
} |
||||
|
|
||||
|
const ok = () => { |
||||
|
hide() |
||||
|
onOk() |
||||
|
} |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
|
||||
|
<div id="my-id" uk-modal bind:this={theModal}> |
||||
|
<div class="uk-modal-dialog"> |
||||
|
<button class="uk-modal-close-default" type="button" uk-close></button> |
||||
|
<div class="uk-modal-header"> |
||||
|
<h2 class="uk-modal-title">{title}</h2> |
||||
|
</div> |
||||
|
<div class="uk-modal-body">{body}</div> |
||||
|
<div class="uk-modal-footer"> |
||||
|
<ButtonGroup> |
||||
|
<Button grouped color="primary" on:click={ok}> |
||||
|
{okText} |
||||
|
</Button> |
||||
|
<Button grouped color="secondary" on:click={cancel}> |
||||
|
{cancelText} |
||||
|
</Button> |
||||
|
</ButtonGroup> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
After Width: | Height: | Size: 454 B |
@ -0,0 +1,70 @@ |
|||||
|
import { getStateOrValue } from "./getState" |
||||
|
import { setState, setStateFromBinding } from "./setState" |
||||
|
import { trimSlash } from "../common/trimSlash" |
||||
|
import { isBound } from "./isState" |
||||
|
import { attachChildren } from "../render/attachChildren" |
||||
|
|
||||
|
export const bbFactory = ({ |
||||
|
store, |
||||
|
getCurrentState, |
||||
|
frontendDefinition, |
||||
|
componentLibraries, |
||||
|
uiFunctions, |
||||
|
onScreenSlotRendered, |
||||
|
}) => { |
||||
|
const relativeUrl = url => |
||||
|
frontendDefinition.appRootPath |
||||
|
? frontendDefinition.appRootPath + "/" + trimSlash(url) |
||||
|
: url |
||||
|
|
||||
|
const apiCall = method => (url, body) => |
||||
|
fetch(relativeUrl(url), { |
||||
|
method: method, |
||||
|
headers: { |
||||
|
"Content-Type": "application/json", |
||||
|
}, |
||||
|
body: body && JSON.stringify(body), |
||||
|
}) |
||||
|
|
||||
|
const api = { |
||||
|
post: apiCall("POST"), |
||||
|
get: apiCall("GET"), |
||||
|
patch: apiCall("PATCH"), |
||||
|
delete: apiCall("DELETE"), |
||||
|
} |
||||
|
|
||||
|
const safeCallEvent = (event, context) => { |
||||
|
const isFunction = obj => |
||||
|
!!(obj && obj.constructor && obj.call && obj.apply) |
||||
|
|
||||
|
if (isFunction(event)) event(context) |
||||
|
} |
||||
|
|
||||
|
return (treeNode, setupState) => { |
||||
|
const attachParams = { |
||||
|
componentLibraries, |
||||
|
uiFunctions, |
||||
|
treeNode, |
||||
|
onScreenSlotRendered, |
||||
|
setupState, |
||||
|
getCurrentState, |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
attachChildren: attachChildren(attachParams), |
||||
|
context: treeNode.context, |
||||
|
props: treeNode.props, |
||||
|
call: safeCallEvent, |
||||
|
setStateFromBinding: (binding, value) => |
||||
|
setStateFromBinding(store, binding, value), |
||||
|
setState: (path, value) => setState(store, path, value), |
||||
|
getStateOrValue: (prop, currentContext) => |
||||
|
getStateOrValue(getCurrentState(), prop, currentContext), |
||||
|
store: store, |
||||
|
relativeUrl, |
||||
|
api, |
||||
|
isBound, |
||||
|
parent, |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,288 @@ |
|||||
|
import { |
||||
|
isEventType, |
||||
|
eventHandlers, |
||||
|
EVENT_TYPE_MEMBER_NAME, |
||||
|
} from "./eventHandlers" |
||||
|
import { bbFactory } from "./bbComponentApi" |
||||
|
import { getState } from "./getState" |
||||
|
import { attachChildren } from "../render/attachChildren" |
||||
|
|
||||
|
import { |
||||
|
isBound, |
||||
|
takeStateFromStore, |
||||
|
takeStateFromContext, |
||||
|
takeStateFromEventParameters, |
||||
|
BB_STATE_FALLBACK, |
||||
|
BB_STATE_BINDINGPATH, |
||||
|
BB_STATE_BINDINGSOURCE, |
||||
|
} from "./isState" |
||||
|
|
||||
|
const doNothing = () => {} |
||||
|
doNothing.isPlaceholder = true |
||||
|
|
||||
|
const isMetaProp = propName => |
||||
|
propName === "_component" || |
||||
|
propName === "_children" || |
||||
|
propName === "_id" || |
||||
|
propName === "_style" || |
||||
|
propName === "_code" || |
||||
|
propName === "_codeMeta" |
||||
|
|
||||
|
export const createStateManager = ({ |
||||
|
store, |
||||
|
coreApi, |
||||
|
rootPath, |
||||
|
frontendDefinition, |
||||
|
componentLibraries, |
||||
|
uiFunctions, |
||||
|
onScreenSlotRendered, |
||||
|
}) => { |
||||
|
let handlerTypes = eventHandlers(store, coreApi, rootPath) |
||||
|
let currentState |
||||
|
|
||||
|
// any nodes that have props that are bound to the store
|
||||
|
let nodesBoundByProps = [] |
||||
|
|
||||
|
// any node whose children depend on code, that uses the store
|
||||
|
let nodesWithCodeBoundChildren = [] |
||||
|
|
||||
|
const getCurrentState = () => currentState |
||||
|
const registerBindings = _registerBindings( |
||||
|
nodesBoundByProps, |
||||
|
nodesWithCodeBoundChildren |
||||
|
) |
||||
|
const bb = bbFactory({ |
||||
|
store, |
||||
|
getCurrentState, |
||||
|
frontendDefinition, |
||||
|
componentLibraries, |
||||
|
uiFunctions, |
||||
|
onScreenSlotRendered, |
||||
|
}) |
||||
|
|
||||
|
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb) |
||||
|
|
||||
|
const unsubscribe = store.subscribe( |
||||
|
onStoreStateUpdated({ |
||||
|
setCurrentState: s => (currentState = s), |
||||
|
getCurrentState, |
||||
|
nodesWithCodeBoundChildren, |
||||
|
nodesBoundByProps, |
||||
|
uiFunctions, |
||||
|
componentLibraries, |
||||
|
onScreenSlotRendered, |
||||
|
setupState: setup, |
||||
|
}) |
||||
|
) |
||||
|
|
||||
|
return { |
||||
|
setup, |
||||
|
destroy: () => unsubscribe(), |
||||
|
getCurrentState, |
||||
|
store, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const onStoreStateUpdated = ({ |
||||
|
setCurrentState, |
||||
|
getCurrentState, |
||||
|
nodesWithCodeBoundChildren, |
||||
|
nodesBoundByProps, |
||||
|
uiFunctions, |
||||
|
componentLibraries, |
||||
|
onScreenSlotRendered, |
||||
|
setupState, |
||||
|
}) => s => { |
||||
|
setCurrentState(s) |
||||
|
|
||||
|
// the original array gets changed by components' destroy()
|
||||
|
// so we make a clone and check if they are still in the original
|
||||
|
const nodesWithBoundChildren_clone = [...nodesWithCodeBoundChildren] |
||||
|
for (let node of nodesWithBoundChildren_clone) { |
||||
|
if (!nodesWithCodeBoundChildren.includes(node)) continue |
||||
|
attachChildren({ |
||||
|
uiFunctions, |
||||
|
componentLibraries, |
||||
|
treeNode: node, |
||||
|
onScreenSlotRendered, |
||||
|
setupState, |
||||
|
getCurrentState, |
||||
|
})(node.rootElement, { hydrate: true, force: true }) |
||||
|
} |
||||
|
|
||||
|
for (let node of nodesBoundByProps) { |
||||
|
setNodeState(s, node) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => ( |
||||
|
node, |
||||
|
bindings |
||||
|
) => { |
||||
|
if (bindings.length > 0) { |
||||
|
node.bindings = bindings |
||||
|
nodesBoundByProps.push(node) |
||||
|
const onDestroy = () => { |
||||
|
nodesBoundByProps = nodesBoundByProps.filter(n => n === node) |
||||
|
node.onDestroy = node.onDestroy.filter(d => d === onDestroy) |
||||
|
} |
||||
|
node.onDestroy.push(onDestroy) |
||||
|
} |
||||
|
if ( |
||||
|
node.props._children && |
||||
|
node.props._children.filter(c => c._codeMeta && c._codeMeta.dependsOnStore) |
||||
|
.length > 0 |
||||
|
) { |
||||
|
nodesWithCodeBoundChildren.push(node) |
||||
|
const onDestroy = () => { |
||||
|
nodesWithCodeBoundChildren = nodesWithCodeBoundChildren.filter( |
||||
|
n => n === node |
||||
|
) |
||||
|
node.onDestroy = node.onDestroy.filter(d => d === onDestroy) |
||||
|
} |
||||
|
node.onDestroy.push(onDestroy) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const setNodeState = (storeState, node) => { |
||||
|
if (!node.component) return |
||||
|
const newProps = { ...node.bindings.initialProps } |
||||
|
|
||||
|
for (let binding of node.bindings) { |
||||
|
const val = getState(storeState, binding.path, binding.fallback) |
||||
|
|
||||
|
if (val === undefined && newProps[binding.propName] !== undefined) { |
||||
|
delete newProps[binding.propName] |
||||
|
} |
||||
|
|
||||
|
if (val !== undefined) { |
||||
|
newProps[binding.propName] = val |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
node.component.$set(newProps) |
||||
|
} |
||||
|
|
||||
|
const _setup = ( |
||||
|
handlerTypes, |
||||
|
getCurrentState, |
||||
|
registerBindings, |
||||
|
bb |
||||
|
) => node => { |
||||
|
const props = node.props |
||||
|
const context = node.context || {} |
||||
|
const initialProps = { ...props } |
||||
|
const storeBoundProps = [] |
||||
|
const currentStoreState = getCurrentState() |
||||
|
|
||||
|
for (let propName in props) { |
||||
|
if (isMetaProp(propName)) continue |
||||
|
|
||||
|
const val = props[propName] |
||||
|
|
||||
|
if (isBound(val) && takeStateFromStore(val)) { |
||||
|
const path = BindingPath(val) |
||||
|
const source = BindingSource(val) |
||||
|
const fallback = BindingFallback(val) |
||||
|
|
||||
|
storeBoundProps.push({ |
||||
|
path, |
||||
|
fallback, |
||||
|
propName, |
||||
|
source, |
||||
|
}) |
||||
|
|
||||
|
initialProps[propName] = !currentStoreState |
||||
|
? fallback |
||||
|
: getState( |
||||
|
currentStoreState, |
||||
|
BindingPath(val), |
||||
|
BindingFallback(val), |
||||
|
BindingSource(val) |
||||
|
) |
||||
|
} else if (isBound(val) && takeStateFromContext(val)) { |
||||
|
initialProps[propName] = !context |
||||
|
? val |
||||
|
: getState( |
||||
|
context, |
||||
|
BindingPath(val), |
||||
|
BindingFallback(val), |
||||
|
BindingSource(val) |
||||
|
) |
||||
|
} else if (isEventType(val)) { |
||||
|
const handlersInfos = [] |
||||
|
for (let e of val) { |
||||
|
const handlerInfo = { |
||||
|
handlerType: e[EVENT_TYPE_MEMBER_NAME], |
||||
|
parameters: e.parameters, |
||||
|
} |
||||
|
const resolvedParams = {} |
||||
|
for (let paramName in handlerInfo.parameters) { |
||||
|
const paramValue = handlerInfo.parameters[paramName] |
||||
|
if (!isBound(paramValue)) { |
||||
|
resolvedParams[paramName] = () => paramValue |
||||
|
continue |
||||
|
} else if (takeStateFromContext(paramValue)) { |
||||
|
const val = getState( |
||||
|
context, |
||||
|
paramValue[BB_STATE_BINDINGPATH], |
||||
|
paramValue[BB_STATE_FALLBACK] |
||||
|
) |
||||
|
resolvedParams[paramName] = () => val |
||||
|
} else if (takeStateFromStore(paramValue)) { |
||||
|
resolvedParams[paramName] = () => |
||||
|
getState( |
||||
|
getCurrentState(), |
||||
|
paramValue[BB_STATE_BINDINGPATH], |
||||
|
paramValue[BB_STATE_FALLBACK] |
||||
|
) |
||||
|
continue |
||||
|
} else if (takeStateFromEventParameters(paramValue)) { |
||||
|
resolvedParams[paramName] = eventContext => { |
||||
|
getState( |
||||
|
eventContext, |
||||
|
paramValue[BB_STATE_BINDINGPATH], |
||||
|
paramValue[BB_STATE_FALLBACK] |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handlerInfo.parameters = resolvedParams |
||||
|
handlersInfos.push(handlerInfo) |
||||
|
} |
||||
|
|
||||
|
if (handlersInfos.length === 0) initialProps[propName] = doNothing |
||||
|
else { |
||||
|
initialProps[propName] = async context => { |
||||
|
for (let handlerInfo of handlersInfos) { |
||||
|
const handler = makeHandler(handlerTypes, handlerInfo) |
||||
|
await handler(context) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
registerBindings(node, storeBoundProps) |
||||
|
|
||||
|
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb) |
||||
|
initialProps._bb = bb(node, setup) |
||||
|
|
||||
|
return initialProps |
||||
|
} |
||||
|
|
||||
|
const makeHandler = (handlerTypes, handlerInfo) => { |
||||
|
const handlerType = handlerTypes[handlerInfo.handlerType] |
||||
|
return context => { |
||||
|
const parameters = {} |
||||
|
for (let p in handlerInfo.parameters) { |
||||
|
parameters[p] = handlerInfo.parameters[p](context) |
||||
|
} |
||||
|
handlerType.execute(parameters) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const BindingPath = prop => prop[BB_STATE_BINDINGPATH] |
||||
|
const BindingFallback = prop => prop[BB_STATE_FALLBACK] |
||||
|
const BindingSource = prop => prop[BB_STATE_BINDINGSOURCE] |
||||
@ -1,20 +1,189 @@ |
|||||
{ |
{ |
||||
"_lib": "./dist/index.js", |
"_lib": "./dist/index.js", |
||||
"h1": { |
"_generators": {}, |
||||
"name": "H1", |
"Body1": { |
||||
"description": "An HTML H1 tag", |
"name": "Body1", |
||||
|
"description": "Sets the font properties as Roboto Body 1", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Body2": { |
||||
|
"name": "Body2", |
||||
|
"description": "Sets the font properties as Roboto Body 2", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Button": { |
||||
|
"name": "Button", |
||||
|
"description": "A Material Design button with different variations. It renders as an anchor if href is passed to it.", |
||||
"props": { |
"props": { |
||||
|
"onClick": "event", |
||||
|
"variant": "string", |
||||
|
"colour": "string", |
||||
|
"size": "string", |
||||
|
"href": "string", |
||||
|
"icon": "string", |
||||
|
"trailingIcon": "bool", |
||||
|
"fullwidth": "bool", |
||||
"text": "string", |
"text": "string", |
||||
"className": "string" |
"disabled": "bool" |
||||
}, |
}, |
||||
"tags": [] |
"tags": [] |
||||
}, |
}, |
||||
"button": { |
"Caption": { |
||||
"name": "Button", |
"name": "Caption", |
||||
"description": "A button", |
"description": "Sets the font properties as Roboto Caption", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Checkbox": { |
||||
|
"name": "Checkbox", |
||||
|
"description": "A Material Design checkbox. Supports aligning label before or after checkbox.", |
||||
|
"props": { |
||||
|
"onClick": "event", |
||||
|
"id": "string", |
||||
|
"label": "string", |
||||
|
"disabled": "bool", |
||||
|
"alignEnd": "bool", |
||||
|
"indeterminate": "bool", |
||||
|
"checked": "bool" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Datatable": { |
||||
|
"name": "Datatable", |
||||
|
"description": "A Material Design component to represent tabular data.", |
||||
|
"props": {}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H1": { |
||||
|
"name": "H1", |
||||
|
"description": "Sets the font properties as Roboto Headline1", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H2": { |
||||
|
"name": "H2", |
||||
|
"description": "Sets the font properties as Roboto Headline2", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H3": { |
||||
|
"name": "H3", |
||||
|
"description": "Sets the font properties as Roboto Headline3", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H4": { |
||||
|
"name": "H4", |
||||
|
"description": "Sets the font properties as Roboto Headline4", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H5": { |
||||
|
"name": "H5", |
||||
|
"description": "Sets the font properties as Roboto Headline5", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"H6": { |
||||
|
"name": "H6", |
||||
|
"description": "Sets the font properties as Roboto Headline6", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Label": { |
||||
|
"name": "Label", |
||||
|
"description": "A simple label component that displays its text in the standard Roboto Material Design font", |
||||
|
"props": { |
||||
|
"bold": "bool" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Overline": { |
||||
|
"name": "Overline", |
||||
|
"description": "Sets the font properties as Roboto Overline", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Radiobutton": { |
||||
|
"name": "Radiobutton", |
||||
|
"description": "A Material Design radiobutton. Supports aligning label before or after radiobutton.", |
||||
|
"props": { |
||||
|
"onClick": "event", |
||||
|
"id": "string", |
||||
|
"label": "string", |
||||
|
"names": "string", |
||||
|
"name": "string", |
||||
|
"checked": "bool", |
||||
|
"disabled": "bool", |
||||
|
"alignEnd": "bool" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Sub1": { |
||||
|
"name": "Sub1", |
||||
|
"description": "Sets the font properties as Roboto Subtitle1", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Sub2": { |
||||
|
"name": "Sub2", |
||||
|
"description": "Sets the font properties as Roboto Subtitle2", |
||||
|
"props": { |
||||
|
"text": "string" |
||||
|
}, |
||||
|
"tags": [] |
||||
|
}, |
||||
|
"Textfield": { |
||||
|
"name": "Textfield", |
||||
|
"description": "A Material Design textfield with multiple variants. Can also be converted to a text area / multine text field.", |
||||
"props": { |
"props": { |
||||
"raised": "bool" |
"onChange": "event", |
||||
|
"label": "string", |
||||
|
"variant": "string", |
||||
|
"disabled": "bool", |
||||
|
"fullwidth": "bool", |
||||
|
"colour":"string", |
||||
|
"size":"string", |
||||
|
"type": "string", |
||||
|
"required": "bool", |
||||
|
"minLength": "number", |
||||
|
"maxLength": "number", |
||||
|
"helperText": "string", |
||||
|
"errorText": "string", |
||||
|
"placeholder": "string", |
||||
|
"icon": "string", |
||||
|
"trailingIcon": "bool", |
||||
|
"textarea": "bool", |
||||
|
"rows": "number", |
||||
|
"cols": "number", |
||||
|
"validation": "bool", |
||||
|
"persistent": "bool" |
||||
}, |
}, |
||||
"tags": [] |
"tags": [] |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
|
|||||
@ -1,12 +0,0 @@ |
|||||
<script> |
|
||||
import "@material/button/mdc-button.scss" |
|
||||
export let raised = false |
|
||||
|
|
||||
let c = raised ? "mdc-button mdc-button--raised" : "mdc-button" |
|
||||
</script> |
|
||||
|
|
||||
<button class={c}> |
|
||||
<div class="mdc-button__ripple" /> |
|
||||
|
|
||||
<span class="mdc-button__label">Button</span> |
|
||||
</button> |
|
||||
@ -1,2 +1,2 @@ |
|||||
import "./_index.scss" |
import "./_index.scss" |
||||
export { default as button } from "./Button.svelte" |
export { default as Button } from "./Button.svelte" |
||||
|
|||||
@ -1,4 +1,4 @@ |
|||||
import "./_style.scss"; |
import "./_style.scss"; |
||||
export { default as checkbox } from "./Checkbox.svelte"; |
export { default as Checkbox } from "./Checkbox.svelte"; |
||||
export { default as checkboxgroup } from "./CheckboxGroup.svelte"; |
export { default as Checkboxgroup } from "./CheckboxGroup.svelte"; |
||||
|
|
||||
|
|||||
@ -0,0 +1,67 @@ |
|||||
|
<script> |
||||
|
import { onMount, setContext } from "svelte" |
||||
|
import { MDCDataTable } from "@material/data-table" |
||||
|
import Row from "./DatatableRow.svelte" |
||||
|
import Cell from "./DatatableCell.svelte" |
||||
|
import { Button } from "../Button" |
||||
|
import ClassBuilder from "../ClassBuilder.js" |
||||
|
|
||||
|
const cb = new ClassBuilder("data-table") |
||||
|
setContext("BBMD:data-table:cb", cb) |
||||
|
|
||||
|
let datatable = null |
||||
|
let instance = null |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!!datatable) instance = new MDCDataTable(datatable) |
||||
|
return () => { |
||||
|
!!instance && instance.destroy() |
||||
|
instance = null |
||||
|
} |
||||
|
}) |
||||
|
</script> |
||||
|
|
||||
|
<div bind:this={datatable} class={cb.build()}> |
||||
|
<table class={cb.elem`table`} aria-label="Material Design Datatable"> |
||||
|
<thead> |
||||
|
<Row isHeader> |
||||
|
<Cell isHeader>Id</Cell> |
||||
|
<Cell isHeader>First Name</Cell> |
||||
|
<Cell isHeader>Second Name</Cell> |
||||
|
<Cell isHeader>Gender</Cell> |
||||
|
<Cell isHeader>Address</Cell> |
||||
|
<Cell isHeader>Actions</Cell> |
||||
|
</Row> |
||||
|
</thead> |
||||
|
<tbody class={cb.elem`content`}> |
||||
|
<Row> |
||||
|
<Cell>123456</Cell> |
||||
|
<Cell>Conor</Cell> |
||||
|
<Cell>McKeown</Cell> |
||||
|
<Cell>Male</Cell> |
||||
|
<Cell>1 Cool Street</Cell> |
||||
|
<Cell> |
||||
|
<Button |
||||
|
text="Select" |
||||
|
variant="unelevated" |
||||
|
colour="secondary" |
||||
|
size="small" /> |
||||
|
</Cell> |
||||
|
</Row> |
||||
|
<Row> |
||||
|
<Cell>789101</Cell> |
||||
|
<Cell>Joe</Cell> |
||||
|
<Cell>Bloggs</Cell> |
||||
|
<Cell>Male</Cell> |
||||
|
<Cell>2 Cool Street</Cell> |
||||
|
<Cell> |
||||
|
<Button |
||||
|
text="Select" |
||||
|
variant="unelevated" |
||||
|
colour="secondary" |
||||
|
size="small" /> |
||||
|
</Cell> |
||||
|
</Row> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
@ -0,0 +1,23 @@ |
|||||
|
<script> |
||||
|
import { getContext } from "svelte" |
||||
|
|
||||
|
export let isHeader = false |
||||
|
export let numeric = false |
||||
|
|
||||
|
const cb = getContext("BBMD:data-table:cb") |
||||
|
|
||||
|
let elementName = isHeader ? "header-cell" : "cell" |
||||
|
let modifiers = { numeric } |
||||
|
let props = { modifiers } |
||||
|
let cellClass = cb.build({ elementName, props }) |
||||
|
</script> |
||||
|
|
||||
|
{#if isHeader} |
||||
|
<th class={cellClass} role="columnheader" scope="col"> |
||||
|
<slot /> |
||||
|
</th> |
||||
|
{:else} |
||||
|
<td class={cellClass}> |
||||
|
<slot /> |
||||
|
</td> |
||||
|
{/if} |
||||
@ -0,0 +1,26 @@ |
|||||
|
<script> |
||||
|
import { getContext } from "svelte"; |
||||
|
|
||||
|
export let onSelect = () => {}; |
||||
|
export let isHeader = false; |
||||
|
let row = null; |
||||
|
let selected = false; |
||||
|
|
||||
|
const cb = getContext("BBMD:data-table:cb"); |
||||
|
|
||||
|
let elementName = isHeader ? "header-row" : "row"; |
||||
|
let modifiers = {}; |
||||
|
|
||||
|
$: modifiers = { selected }; |
||||
|
$: props = { modifiers }; |
||||
|
$: rowClass = cb.build({ elementName, props }); |
||||
|
|
||||
|
function rowSelected() { |
||||
|
selected = !selected; |
||||
|
onSelect(); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<tr bind:this={row} class={rowClass} on:click={rowSelected}> |
||||
|
<slot /> |
||||
|
</tr> |
||||
@ -0,0 +1 @@ |
|||||
|
@import "@material/data-table/mdc-data-table"; |
||||
@ -0,0 +1,2 @@ |
|||||
|
import "./_style.scss"; |
||||
|
export { default as Datatable } from "./Datatable.svelte"; |
||||
@ -1,8 +0,0 @@ |
|||||
<script> |
|
||||
export let text = "" |
|
||||
export let className = "" |
|
||||
|
|
||||
export let _bb |
|
||||
</script> |
|
||||
|
|
||||
<h1 class={className}>{text}</h1> |
|
||||
@ -1,3 +1,3 @@ |
|||||
import "./_style.scss"; |
import "./_style.scss"; |
||||
export { default as radiobutton } from "./Radiobutton.svelte"; |
export { default as Radiobutton } from "./Radiobutton.svelte"; |
||||
export { default as radiobuttongroup } from "./RadiobuttonGroup.svelte"; |
export { default as Radiobuttongroup } from "./RadiobuttonGroup.svelte"; |
||||
|
|||||
@ -1,23 +1,25 @@ |
|||||
import { |
import { |
||||
H1, |
H1, |
||||
Overline, |
Overline, |
||||
button, |
Button, |
||||
icon, |
Icon, |
||||
textfield, |
Textfield, |
||||
checkbox, |
Checkbox, |
||||
checkboxgroup, |
Checkboxgroup, |
||||
radiobutton, |
Radiobutton, |
||||
radiobuttongroup, |
Radiobuttongroup, |
||||
|
Datatable, |
||||
} from "@BBMD" |
} from "@BBMD" |
||||
|
|
||||
export default { |
export default { |
||||
H1, |
H1, |
||||
Overline, |
Overline, |
||||
button, |
Button, |
||||
icon, |
Icon, |
||||
textfield, |
Textfield, |
||||
checkbox, |
Checkbox, |
||||
checkboxgroup, |
Checkboxgroup, |
||||
radiobutton, |
Radiobutton, |
||||
radiobuttongroup, |
Radiobuttongroup, |
||||
|
Datatable, |
||||
} |
} |
||||
|
|||||
@ -1,2 +1,2 @@ |
|||||
import "./_index.scss" |
import "./_index.scss" |
||||
export { default as textfield } from "./Textfield.svelte" |
export { default as Textfield } from "./Textfield.svelte" |
||||
@ -1,9 +1,11 @@ |
|||||
import "@material/theme/mdc-theme.scss"; |
import "@material/theme/mdc-theme.scss"; |
||||
|
|
||||
export { button } from "./Button" |
export { Button } from "./Button" |
||||
export { default as icon } from "./Icon.svelte" |
export { default as Icon } from "./Common/Icon.svelte" |
||||
export { textfield } from "./Textfield" |
export { Textfield } from "./Textfield" |
||||
export * from "./Typography" |
export * from "./Typography" |
||||
export { checkbox, checkboxgroup } from "./Checkbox" |
export { Checkbox, Checkboxgroup } from "./Checkbox" |
||||
export { radiobutton, radiobuttongroup } from "./Radiobutton" |
export { Radiobutton, Radiobuttongroup } from "./Radiobutton" |
||||
|
export { default as Label } from "./Common/Label.svelte" |
||||
|
export { Datatable } from "./Datatable" |
||||
|
|
||||
|
|||||
@ -0,0 +1,92 @@ |
|||||
|
const { readdir, stat, copyFile } = require("fs-extra") |
||||
|
const { constants } = require("fs") |
||||
|
const { join, basename } = require("path") |
||||
|
const serverConfig = require("../../../server/config")() |
||||
|
|
||||
|
const packagesFolder = ".." |
||||
|
|
||||
|
const jsFile = dir => join(dir, "index.js") |
||||
|
const generatorsFile = dir => join(dir, "generators.js") |
||||
|
const jsMapFile = dir => join(dir, "index.js.map") |
||||
|
const sourceJs = jsFile("dist") |
||||
|
const sourceJsMap = jsMapFile("dist") |
||||
|
const componentsFile = "components.json" |
||||
|
const sourceGenerators = generatorsFile("dist") |
||||
|
|
||||
|
const appPackages = join( |
||||
|
packagesFolder, |
||||
|
"server", |
||||
|
serverConfig.latestPackagesFolder |
||||
|
) |
||||
|
|
||||
|
const publicMain = appName => |
||||
|
join( |
||||
|
appPackages, |
||||
|
appName, |
||||
|
"public", |
||||
|
"main", |
||||
|
"lib", |
||||
|
"node_modules", |
||||
|
"@budibase", |
||||
|
"standard-components" |
||||
|
) |
||||
|
const publicUnauth = appName => |
||||
|
join( |
||||
|
appPackages, |
||||
|
appName, |
||||
|
"public", |
||||
|
"unauthenticated", |
||||
|
"lib", |
||||
|
"node_modules", |
||||
|
"@budibase", |
||||
|
"standard-components" |
||||
|
) |
||||
|
const nodeModulesDist = appName => |
||||
|
join( |
||||
|
appPackages, |
||||
|
appName, |
||||
|
"node_modules", |
||||
|
"@budibase", |
||||
|
"standard-components", |
||||
|
"dist" |
||||
|
) |
||||
|
const nodeModules = appName => |
||||
|
join(appPackages, appName, "node_modules", "@budibase", "standard-components") |
||||
|
|
||||
|
;(async () => { |
||||
|
const apps = await readdir(appPackages) |
||||
|
|
||||
|
const copySource = file => async toDir => { |
||||
|
const dest = join(toDir, basename(file)) |
||||
|
try { |
||||
|
await copyFile(file, dest, constants.COPYFILE_FICLONE) |
||||
|
console.log(`COPIED ${file} to ${dest}`) |
||||
|
} catch (e) { |
||||
|
console.log(`COPY FAILED ${file} to ${dest}: ${e}`) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const copySourceJs = copySource(sourceJs) |
||||
|
const copySourceJsMap = copySource(sourceJsMap) |
||||
|
const copyGenerators = copySource(sourceGenerators) |
||||
|
const copyComponentsJson = copySource(componentsFile) |
||||
|
|
||||
|
for (let app of apps) { |
||||
|
if (app === ".data") continue |
||||
|
if (!(await stat(join(appPackages, app))).isDirectory()) continue |
||||
|
|
||||
|
await copySourceJs(nodeModulesDist(app)) |
||||
|
await copySourceJsMap(nodeModulesDist(app)) |
||||
|
await copyGenerators(nodeModulesDist(app)) |
||||
|
|
||||
|
await copyComponentsJson(nodeModules(app)) |
||||
|
|
||||
|
await copySourceJs(join(publicMain(app), "dist")) |
||||
|
await copySourceJsMap(join(publicMain(app), "dist")) |
||||
|
await copyGenerators(join(publicMain(app), "dist")) |
||||
|
|
||||
|
await copySourceJs(join(publicUnauth(app), "dist")) |
||||
|
await copySourceJsMap(join(publicUnauth(app), "dist")) |
||||
|
await copyGenerators(join(publicUnauth(app), "dist")) |
||||
|
} |
||||
|
})() |
||||
@ -0,0 +1,9 @@ |
|||||
|
module.exports = props => { |
||||
|
if (props._codeMeta) { |
||||
|
delete props._codeMeta |
||||
|
} |
||||
|
|
||||
|
for (let child of props._children || []) { |
||||
|
module.exports(child) |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue