New feature and refactor of Classbuilder along with some bug fixes (#85)
This commit is contained in:
parent
7fe09780a4
commit
52c0e3b066
|
@ -1,40 +1,50 @@
|
||||||
<script>
|
<script>
|
||||||
import { setContext, getContext } from "svelte"
|
import { setContext, getContext } from "svelte";
|
||||||
import Icon from "../Icon.svelte"
|
import Icon from "../Icon.svelte";
|
||||||
import ripple from "../Ripple.js"
|
import ripple from "../Ripple.js";
|
||||||
import ClassBuilder from "../ClassBuilder.js"
|
import ClassBuilder from "../ClassBuilder.js";
|
||||||
|
|
||||||
const cb = new ClassBuilder("button", ["primary", "medium"])
|
const cb = new ClassBuilder("button", ["primary", "medium"]);
|
||||||
|
|
||||||
export let variant = "raised"
|
export let variant = "raised";
|
||||||
export let colour = "primary"
|
export let colour = "primary";
|
||||||
export let size = "medium"
|
export let size = "medium";
|
||||||
|
|
||||||
export let href = ""
|
export let href = "";
|
||||||
export let icon = ""
|
export let icon = "";
|
||||||
export let trailingIcon = false
|
export let trailingIcon = false;
|
||||||
export let fullwidth = false
|
export let fullwidth = false;
|
||||||
|
|
||||||
export let text = ""
|
export let text = "";
|
||||||
export let disabled = false
|
export let disabled = false;
|
||||||
|
|
||||||
|
let modifiers = {};
|
||||||
|
let customs = { size, colour };
|
||||||
|
|
||||||
|
if (!href) modifiers = { variant };
|
||||||
|
|
||||||
|
let props = { modifiers, customs };
|
||||||
|
|
||||||
|
let blockClasses = cb.build({ props });
|
||||||
|
const labelClass = cb.elem("label");
|
||||||
|
|
||||||
$: if (icon) {
|
$: if (icon) {
|
||||||
setContext("BBMD:icon:context", "button")
|
setContext("BBMD:icon:context", "button");
|
||||||
}
|
}
|
||||||
|
|
||||||
$: renderLeadingIcon = !!icon && !trailingIcon
|
$: renderLeadingIcon = !!icon && !trailingIcon;
|
||||||
$: renderTrailingIcon = !!icon && trailingIcon
|
$: renderTrailingIcon = !!icon && trailingIcon;
|
||||||
|
|
||||||
let blockClasses = cb.blocks({
|
|
||||||
modifiers: !href ? [variant] : null,
|
|
||||||
customs: { size, colour },
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- TODO: Activated colour on primary elevated buttons seems to be rendering weird -->
|
<style>
|
||||||
|
.fullwidth {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
{#if href}
|
{#if href}
|
||||||
<a class={blockClasses} {href} on:click>
|
<a class={blockClasses} {href} on:click>
|
||||||
<span class={cb.elements('label')}>{text}</span>
|
<span class={labelClass}>{text}</span>
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
<button
|
<button
|
||||||
|
@ -46,15 +56,9 @@
|
||||||
{#if renderLeadingIcon}
|
{#if renderLeadingIcon}
|
||||||
<Icon {icon} />
|
<Icon {icon} />
|
||||||
{/if}
|
{/if}
|
||||||
<span class={cb.elements('label')}>{text}</span>
|
<span class={labelClass}>{text}</span>
|
||||||
{#if renderTrailingIcon}
|
{#if renderTrailingIcon}
|
||||||
<Icon {icon} />
|
<Icon {icon} />
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
|
||||||
.fullwidth {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,43 +1,70 @@
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Classparams modifier and custom could take an object. Booleans or numbers use key value for classes, strings use property value for classes. Extras to stay as is
|
//use if a different base is needed than whats defined by this.block
|
||||||
buildClass(base, classParams) {
|
debase(base, elementProps) {
|
||||||
|
if (!elementProps) return base;
|
||||||
|
return this._handleProps(base, elementProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
//proxies bindProps and checks for which elementProps exist before binding
|
||||||
|
_handleProps(base, elementProps) {
|
||||||
let cls = base;
|
let cls = base;
|
||||||
const { modifiers, customs, extras } = classParams;
|
const { modifiers, customs, extras } = elementProps;
|
||||||
if (!!modifiers)
|
if (!!modifiers) cls += this._bindProps(modifiers, base);
|
||||||
cls += modifiers.map(m => (!!m ? ` ${base}--${m}` : "")).join(" ");
|
if (!!customs) cls += this._bindProps(customs, base, true);
|
||||||
if (!!customs)
|
|
||||||
cls += Object.entries(customs)
|
|
||||||
.map(([property, value]) => {
|
|
||||||
//disregard falsy and values set by customDefaults constructor param
|
|
||||||
if (
|
|
||||||
!!value &&
|
|
||||||
(!this.customDefaults || !this.customDefaults.includes(value))
|
|
||||||
) {
|
|
||||||
//custom scss name convention = bbmd-[block | element]--[property]-[value]
|
|
||||||
return ` bbmd-${base}--${property}-${value}`;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.join("");
|
|
||||||
if (!!extras) cls += ` ${extras.join(" ")}`;
|
if (!!extras) cls += ` ${extras.join(" ")}`;
|
||||||
return cls.trim();
|
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}--${property}-${value}`
|
||||||
|
: ` ${classBase}--${value}`;
|
||||||
|
} else if (valueType == "boolean") {
|
||||||
|
return ` ${classBase}--${property}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
const getComponent = comp => `@budibase//materialdesign-components/${comp}`;
|
const getComponent = comp => `@budibase//materialdesign-components/${comp}`;
|
||||||
|
|
||||||
|
|
||||||
export const props = {
|
export const props = {
|
||||||
justAnH1: {
|
justAnH1: {
|
||||||
_component: "@budibase/materialdesign-components/h1",
|
_component: "@budibase/materialdesign-components/h1",
|
||||||
|
@ -27,11 +28,11 @@ export const props = {
|
||||||
textfield: {
|
textfield: {
|
||||||
_component: "@budibase/materialdesign-components/textfield",
|
_component: "@budibase/materialdesign-components/textfield",
|
||||||
_children: [],
|
_children: [],
|
||||||
label: "Surname",
|
label: "First",
|
||||||
icon: "alarm_on",
|
colour: "secondary",
|
||||||
variant: "outlined",
|
|
||||||
helperText: "Add Surname",
|
|
||||||
textarea: true,
|
textarea: true,
|
||||||
|
fullwidth:true,
|
||||||
|
helperText: "Add Surname",
|
||||||
useCharCounter: true
|
useCharCounter: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,15 +44,14 @@
|
||||||
export let persistent = false
|
export let persistent = false
|
||||||
|
|
||||||
let id = `${label}-${variant}`
|
let id = `${label}-${variant}`
|
||||||
let helperClasses = `${cb.block}-helper-text`
|
|
||||||
|
|
||||||
let modifiers = []
|
let modifiers = { fullwidth, disabled, textarea }
|
||||||
let customs = { colour }
|
let customs = { colour }
|
||||||
|
|
||||||
if (variant == "standard" || fullwidth) {
|
if (variant == "standard" || fullwidth) {
|
||||||
customs = { ...customs, variant }
|
customs = { ...customs, variant }
|
||||||
} else {
|
} else {
|
||||||
modifiers.push(variant)
|
modifiers = { ...modifiers, variant }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!textarea && size !== "medium") {
|
if (!textarea && size !== "medium") {
|
||||||
|
@ -60,15 +59,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!label || fullwidth) {
|
if (!label || fullwidth) {
|
||||||
modifiers.push("no-label")
|
modifiers = { ...modifiers, noLabel: "no-label" }
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Refactor - this could be handled better using an object as modifier instead of an array
|
let helperClasses = cb.debase(`${cb.block}-helper-text`, {
|
||||||
if (fullwidth) modifiers.push("fullwidth")
|
modifiers: { persistent, validation },
|
||||||
if (disabled) modifiers.push("disabled")
|
})
|
||||||
if (textarea) modifiers.push("textarea")
|
|
||||||
if (persistent) helperClasses += ` ${cb.block}-helper-text--persistent`
|
|
||||||
if (validation) helperClasses += ` ${cb.block}-helper-text--validation`
|
|
||||||
|
|
||||||
let useLabel = !!label && (!fullwidth || (fullwidth && textarea))
|
let useLabel = !!label && (!fullwidth || (fullwidth && textarea))
|
||||||
let useIcon = !!icon && (!textarea && !fullwidth)
|
let useIcon = !!icon && (!textarea && !fullwidth)
|
||||||
|
@ -77,16 +73,16 @@
|
||||||
|
|
||||||
if (useIcon) {
|
if (useIcon) {
|
||||||
setContext("BBMD:icon:context", "text-field")
|
setContext("BBMD:icon:context", "text-field")
|
||||||
trailingIcon
|
let iconClass = trailingIcon ? "with-trailing-icon" : "with-leading-icon"
|
||||||
? modifiers.push("with-trailing-icon")
|
modifiers = { ...modifiers, iconClass }
|
||||||
: modifiers.push("with-leading-icon")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$: renderLeadingIcon = useIcon && !trailingIcon
|
$: renderLeadingIcon = useIcon && !trailingIcon
|
||||||
$: renderTrailingIcon = useIcon && trailingIcon
|
$: renderTrailingIcon = useIcon && trailingIcon
|
||||||
|
|
||||||
const blockClasses = cb.blocks({ modifiers, customs })
|
let props = { modifiers, customs }
|
||||||
const inputClasses = cb.elements("input")
|
const blockClasses = cb.build({ props })
|
||||||
|
const inputClasses = cb.elem("input")
|
||||||
|
|
||||||
let renderMaxLength = !!maxLength ? `0 / ${maxLength}` : "0"
|
let renderMaxLength = !!maxLength ? `0 / ${maxLength}` : "0"
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,12 @@
|
||||||
&.bbmd-mdc-text-field--colour-secondary {
|
&.bbmd-mdc-text-field--colour-secondary {
|
||||||
&.mdc-text-field--focused {
|
&.mdc-text-field--focused {
|
||||||
.mdc-floating-label--float-above {
|
.mdc-floating-label--float-above {
|
||||||
color: var(--mdc-theme-secondary);
|
@include mdc-floating-label-ink-color(secondary)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mdc-line-ripple--active {
|
.mdc-line-ripple--active {
|
||||||
background-color: var(--mdc-theme-secondary);
|
@include mdc-line-ripple-color(secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mdc-text-field--outlined,
|
&.mdc-text-field--outlined,
|
||||||
|
|
Loading…
Reference in New Issue