mirror of https://github.com/Budibase/budibase.git
Browse Source
* Completed checkbox and form field component with changes around how test app renders components * Tidyuppull/4023/head
committed by
GitHub
13 changed files with 243 additions and 60 deletions
@ -0,0 +1,49 @@ |
|||||
|
<script> |
||||
|
import { onMount, onDestroy, getContext } from "svelte"; |
||||
|
import Formfield from "../Common/Formfield.svelte"; |
||||
|
import { fieldStore } from "../Common/FormfieldStore.js"; |
||||
|
import ClassBuilder from "../ClassBuilder.js"; |
||||
|
import { MDCCheckbox } from "@material/checkbox"; |
||||
|
|
||||
|
export let id = ""; |
||||
|
export let label = ""; |
||||
|
export let disabled = false; |
||||
|
export let alignEnd = false; |
||||
|
export let indeterminate = false; |
||||
|
|
||||
|
let instance = null; |
||||
|
let checkbox = null; |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!!checkbox) { |
||||
|
instance = new MDCCheckbox(checkbox); |
||||
|
let fieldStore = getContext("BBMD:field-element"); |
||||
|
fieldStore.setInput(instance); |
||||
|
instance.indeterminate = indeterminate; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
const cb = new ClassBuilder("checkbox"); |
||||
|
let modifiers = { disabled }; |
||||
|
let props = { modifiers }; |
||||
|
|
||||
|
const blockClass = cb.build({ props }); |
||||
|
</script> |
||||
|
|
||||
|
<!-- TODO: Customizing Colour and Density - What level of customization for these things does Budibase need here? --> |
||||
|
|
||||
|
<Formfield {label} {id} {alignEnd}> |
||||
|
<div bind:this={checkbox} class={blockClass}> |
||||
|
<input type="checkbox" class={cb.elem`native-control`} {id} {disabled} /> |
||||
|
<div class={cb.elem`background`}> |
||||
|
<svg class={cb.elem`checkmark`} viewBox="0 0 24 24"> |
||||
|
<path |
||||
|
class={cb.elem`checkmark-path`} |
||||
|
fill="none" |
||||
|
d="M1.73,12.91 8.1,19.28 22.79,4.59" /> |
||||
|
</svg> |
||||
|
<div class={cb.elem`mixedmark`} /> |
||||
|
</div> |
||||
|
<div class={cb.elem`ripple`} /> |
||||
|
</div> |
||||
|
</Formfield> |
||||
@ -0,0 +1,2 @@ |
|||||
|
@import "@material/form-field/mdc-form-field"; |
||||
|
@import "@material/checkbox/mdc-checkbox.scss"; |
||||
@ -0,0 +1,2 @@ |
|||||
|
import "./_style.scss"; |
||||
|
export { default as checkbox } from "./Checkbox.svelte"; |
||||
@ -1,38 +1,74 @@ |
|||||
export default class ClassBuilder { |
export default class ClassBuilder { |
||||
constructor(block, customDefaults) { |
constructor(block, defaultIgnoreList) { |
||||
this.block = `mdc-${block}` |
this.block = `mdc-${block}`; |
||||
this.customDefaults = customDefaults //will be ignored when building custom classes
|
this.defaultIgnoreList = defaultIgnoreList; //will be ignored when building custom classes
|
||||
} |
} |
||||
|
|
||||
// classParams: {modifiers:[] (mdc), custom:[] (bbmd), extra:[] (any)}
|
/* |
||||
blocks(classParams) { |
handles both blocks and elementss (BEM MD Notation) |
||||
let base = this.block |
params = {elementName: string, props: {modifiers{}, customs:{}, extras: []}} |
||||
if (classParams == undefined) return base |
All are optional |
||||
return this.buildClass(base, classParams) |
*/ |
||||
|
build(params) { |
||||
|
if (!params) return this.block; //return block if nothing passed
|
||||
|
const { props, elementName } = params; |
||||
|
let base = !!elementName ? `${this.block}__${elementName}` : this.block; |
||||
|
if (!props) return base; |
||||
|
return this._handleProps(base, props); |
||||
} |
} |
||||
|
|
||||
//elementName: string, classParams: {}
|
//Easily grab a simple element class
|
||||
elements(elementName, classParams) { |
elem(elementName) { |
||||
let base = `${this.block}__${elementName}` |
return this.build({ elementName }); |
||||
if (classParams == undefined) return base |
|
||||
return this.buildClass(base, classParams) |
|
||||
} |
} |
||||
|
|
||||
buildClass(base, classParams) { |
//use if a different base is needed than whats defined by this.block
|
||||
let cls = base |
debase(base, elementProps) { |
||||
const { modifiers, customs, extras } = classParams |
if (!elementProps) return base; |
||||
if (modifiers) cls += modifiers.map(m => ` ${base}--${m}`).join(" ") |
return this._handleProps(base, elementProps); |
||||
if (customs) |
} |
||||
cls += Object.entries(customs) |
|
||||
.map(([property, value]) => { |
//proxies bindProps and checks for which elementProps exist before binding
|
||||
//disregard falsy and values set by customDefaults constructor param
|
_handleProps(base, elementProps) { |
||||
if (!!value && !this.customDefaults.includes(value)) { |
let cls = base; |
||||
//custom scss name convention = bbmd-[block | element]--[property]-[value]
|
const { modifiers, customs, extras } = elementProps; |
||||
return ` bbmd-${base}--${property}-${value}` |
if (!!modifiers) cls += this._bindProps(modifiers, base); |
||||
|
if (!!customs) cls += this._bindProps(customs, base, true); |
||||
|
if (!!extras) cls += ` ${extras.join(" ")}`; |
||||
|
return cls.trim(); |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
Handles both modifiers and customs. Use property, value or both depending |
||||
|
on whether it is passsed props for custom or modifiers |
||||
|
if custom uses the following convention for scss mixins: |
||||
|
bbmd-{this.block}--{property}-{value} |
||||
|
bbmd-mdc-button--size-large |
||||
|
*/ |
||||
|
_bindProps(elementProps, base, isCustom = false) { |
||||
|
return Object.entries(elementProps) |
||||
|
.map(([property, value]) => { |
||||
|
//disregard falsy and values set by defaultIgnoreList constructor param
|
||||
|
if ( |
||||
|
!!value && |
||||
|
(!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value)) |
||||
|
) { |
||||
|
let classBase = isCustom ? `bbmd-${base}` : `${base}`; |
||||
|
let valueType = typeof value; |
||||
|
|
||||
|
if (valueType == "string" || valueType == "number") { |
||||
|
return isCustom |
||||
|
? ` ${classBase}--${this._convertCamel(property)}-${value}` |
||||
|
: ` ${classBase}--${value}`; |
||||
|
} else if (valueType == "boolean") { |
||||
|
return ` ${classBase}--${this._convertCamel(property)}`; |
||||
} |
} |
||||
}) |
} |
||||
.join("") |
}) |
||||
if (extras) cls += ` ${extras.join(" ")}` |
.join(""); |
||||
return cls.trim() |
} |
||||
|
|
||||
|
_convertCamel(str) { |
||||
|
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,35 @@ |
|||||
|
<script> |
||||
|
import "@material/form-field/mdc-form-field.scss"; |
||||
|
import ClassBuilder from "../ClassBuilder.js"; |
||||
|
import { fieldStore } from "./FormfieldStore.js"; |
||||
|
import { MDCFormField } from "@material/form-field"; |
||||
|
import { onMount, onDestroy, setContext } from "svelte"; |
||||
|
|
||||
|
const cb = new ClassBuilder("form-field"); |
||||
|
|
||||
|
let store; |
||||
|
const unsubscribe = fieldStore.subscribe(s => (store = s)); |
||||
|
|
||||
|
export let id = ""; |
||||
|
export let label = ""; |
||||
|
export let alignEnd = false; |
||||
|
|
||||
|
let formField = null; |
||||
|
|
||||
|
let modifiers = { alignEnd }; |
||||
|
let props = { modifiers }; |
||||
|
|
||||
|
let blockClasses = cb.build({ props }); |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!!formField) fieldStore.set(new MDCFormField(formField)); |
||||
|
setContext("BBMD:field-element", fieldStore); |
||||
|
}); |
||||
|
|
||||
|
onDestroy(unsubscribe); |
||||
|
</script> |
||||
|
|
||||
|
<div bind:this={formField} class={blockClasses}> |
||||
|
<slot /> |
||||
|
<label for={id}>{label}</label> |
||||
|
</div> |
||||
@ -0,0 +1,19 @@ |
|||||
|
import { writable } from "svelte/store"; |
||||
|
|
||||
|
function store() { |
||||
|
const { set, update, subscribe } = writable({}); |
||||
|
|
||||
|
function setInput(inp) { |
||||
|
update(n => { |
||||
|
n.input = inp; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
subscribe, |
||||
|
set, |
||||
|
setInput |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export const fieldStore = store(); |
||||
@ -1,17 +1,24 @@ |
|||||
import { createApp } from "@budibase/client/src/createApp" |
import { createApp } from "@budibase/client/src/createApp" |
||||
import components from "./testComponents" |
import components from "./testComponents" |
||||
import packageJson from "../../package.json" |
import packageJson from "../../package.json" |
||||
|
import { rootComponent } from "./rootComponent" |
||||
export default async () => { |
export default async props => { |
||||
delete components._lib |
delete components._lib |
||||
|
|
||||
const componentLibraries = {} |
const componentLibraries = {} |
||||
componentLibraries[packageJson.name] = components |
componentLibraries[packageJson.name] = components |
||||
|
componentLibraries["testcomponents"] = { |
||||
|
rootComponent: rootComponent(window) |
||||
|
} |
||||
const appDef = { hierarchy: {}, actions: {} } |
const appDef = { hierarchy: {}, actions: {} } |
||||
const user = { name: "yeo", permissions: [] } |
const user = { name: "yeo", permissions: [] } |
||||
|
const { initialisePage } = createApp( |
||||
var app = createApp(window.document, componentLibraries, appDef, user, {}) |
window.document, |
||||
|
componentLibraries, |
||||
return app |
{ appRootPath: "" }, |
||||
} |
appDef, |
||||
|
user, |
||||
|
{}, |
||||
|
[] |
||||
|
) |
||||
|
return initialisePage |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
export const rootComponent = window => { |
||||
|
return function(opts) { |
||||
|
const node = window.document.createElement("DIV") |
||||
|
const $set = props => { |
||||
|
props._bb.hydrateChildren(props._children, node) |
||||
|
} |
||||
|
const $destroy = () => { |
||||
|
if (opts.target && node) opts.target.removeChild(node) |
||||
|
} |
||||
|
this.$set = $set |
||||
|
this.$set(opts.props) |
||||
|
this.$destroy = $destroy |
||||
|
opts.target.appendChild(node) |
||||
|
} |
||||
|
} |
||||
@ -1,4 +1,3 @@ |
|||||
import h1 from "../H1.svelte" |
import { H1, Overline, button, icon, checkbox, textfield } from "@BBMD" |
||||
import { button, icon } from "@BBMD" |
|
||||
|
|
||||
export default { h1, button, icon } |
export default {H1, Overline, button, icon, checkbox, textfield } |
||||
|
|||||
@ -1,3 +1,14 @@ |
|||||
export { default as h1 } from "./H1.svelte" |
import "@material/theme/mdc-theme.scss"; |
||||
export { default as icon } from "./Icon.svelte" |
|
||||
export { button } from "./Button" |
export { button } from "./Button" |
||||
|
export { default as icon } from "./Icon.svelte" |
||||
|
export { textfield } from "./Textfield" |
||||
|
export * from "./Typography" |
||||
|
export { checkbox } from "./Checkbox" |
||||
|
|
||||
|
// import { Button } from "./Button";
|
||||
|
// import Icon from "./Icon.svelte";
|
||||
|
// import { Textfield } from "./Textfield";
|
||||
|
// export { Button, Icon, Textfield };
|
||||
|
// export * from "./Typography";
|
||||
|
// export { Checkbox } from "./Checkbox";
|
||||
|
|||||
Loading…
Reference in new issue