Merge pull request #117 from Conor-Mack/feature/mdc-list
Completed List Component and related changes to Radio and Check Compo…
This commit is contained in:
commit
6e9200808b
|
@ -44,6 +44,7 @@
|
||||||
"@material/checkbox": "^4.0.0",
|
"@material/checkbox": "^4.0.0",
|
||||||
"@material/data-table": "4.0.0",
|
"@material/data-table": "4.0.0",
|
||||||
"@material/form-field": "^4.0.0",
|
"@material/form-field": "^4.0.0",
|
||||||
|
"@material/list": "4.0.0",
|
||||||
"@material/radio": "^4.0.0",
|
"@material/radio": "^4.0.0",
|
||||||
"@material/textfield": "^4.0.0"
|
"@material/textfield": "^4.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,51 @@
|
||||||
<script>
|
<script>
|
||||||
import { onMount, onDestroy, getContext } from "svelte";
|
import { onMount, onDestroy, getContext } from "svelte"
|
||||||
import Formfield from "../Common/Formfield.svelte";
|
import Formfield from "../Common/Formfield.svelte"
|
||||||
import { fieldStore } from "../Common/FormfieldStore.js";
|
import { fieldStore } from "../Common/FormfieldStore.js"
|
||||||
import ClassBuilder from "../ClassBuilder.js";
|
import ClassBuilder from "../ClassBuilder.js"
|
||||||
import { MDCCheckbox } from "@material/checkbox";
|
import { MDCCheckbox } from "@material/checkbox"
|
||||||
|
|
||||||
export let onClick = item => {};
|
export let onClick = item => {}
|
||||||
|
|
||||||
export let id = "";
|
export let id = ""
|
||||||
export let label = "";
|
export let label = ""
|
||||||
export let disabled = false;
|
export let disabled = false
|
||||||
export let alignEnd = false;
|
export let alignEnd = false
|
||||||
export let indeterminate = false;
|
export let indeterminate = false
|
||||||
export let checked = false;
|
export let checked = false
|
||||||
|
|
||||||
let instance = null;
|
let instance = null
|
||||||
let checkbox = null;
|
let checkbox = null
|
||||||
|
|
||||||
|
let context = getContext("BBMD:input:context")
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!!checkbox) {
|
if (!!checkbox) {
|
||||||
instance = new MDCCheckbox(checkbox);
|
instance = new MDCCheckbox(checkbox)
|
||||||
let fieldStore = getContext("BBMD:field-element");
|
instance.indeterminate = indeterminate
|
||||||
fieldStore.setInput(instance);
|
if (context !== "list-item") {
|
||||||
instance.indeterminate = indeterminate;
|
let fieldStore = getContext("BBMD:field-element")
|
||||||
|
fieldStore.setInput(instance)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const cb = new ClassBuilder("checkbox");
|
let extras = null
|
||||||
let modifiers = { disabled };
|
|
||||||
let props = { modifiers };
|
|
||||||
|
|
||||||
const blockClass = cb.build({ props });
|
if (context === "list-item") {
|
||||||
|
extras = ["mdc-list-item__meta"]
|
||||||
|
}
|
||||||
|
|
||||||
|
const cb = new ClassBuilder("checkbox")
|
||||||
|
let modifiers = { disabled }
|
||||||
|
let props = { modifiers, extras }
|
||||||
|
|
||||||
|
const blockClass = cb.build({ props })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- TODO: Customizing Colour and Density - What level of customization for these things does Budibase need here? -->
|
<!-- TODO: Customizing Colour and Density - What level of customization for these things does Budibase need here? -->
|
||||||
|
|
||||||
|
{#if context !== 'list-item'}
|
||||||
<Formfield {label} {id} {alignEnd}>
|
<Formfield {label} {id} {alignEnd}>
|
||||||
<div bind:this={checkbox} class={blockClass}>
|
<div bind:this={checkbox} class={blockClass}>
|
||||||
<input
|
<input
|
||||||
|
@ -56,3 +67,24 @@
|
||||||
<div class={cb.elem`ripple`} />
|
<div class={cb.elem`ripple`} />
|
||||||
</div>
|
</div>
|
||||||
</Formfield>
|
</Formfield>
|
||||||
|
{:else}
|
||||||
|
<div bind:this={checkbox} class={blockClass}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class={cb.elem`native-control`}
|
||||||
|
{id}
|
||||||
|
{disabled}
|
||||||
|
{checked}
|
||||||
|
on:click={onClick} />
|
||||||
|
<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>
|
||||||
|
{/if}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { MDCList } from "@material/list";
|
||||||
|
import { MDCRipple } from "@material/ripple";
|
||||||
|
import ListItem from "./ListItem.svelte";
|
||||||
|
import ClassBuilder from "../ClassBuilder.js";
|
||||||
|
|
||||||
|
const cb = new ClassBuilder("list");
|
||||||
|
|
||||||
|
let list = null;
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
export let onSelect = selectedItems => {};
|
||||||
|
|
||||||
|
export let variant = "";
|
||||||
|
//items: [{text: string | {primary: string, secondary: string}, value: any, selected: bool}...n]
|
||||||
|
export let items = [];
|
||||||
|
export let singleSelection = false;
|
||||||
|
export let inputElement = null;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!!list) {
|
||||||
|
instance = new MDCList(list);
|
||||||
|
instance.singleSelection = singleSelection;
|
||||||
|
instance.listElements.map(element => new MDCRipple(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
instance && instance.destroy();
|
||||||
|
instance = null;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSelectedItem(item) {
|
||||||
|
if (singleSelection || inputElement === "radiobutton") {
|
||||||
|
items.forEach(i => {
|
||||||
|
if (i.selected) i.selected = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = items.indexOf(item);
|
||||||
|
if (!!item.selected) {
|
||||||
|
items[idx].selected = !item.selected;
|
||||||
|
} else {
|
||||||
|
items[idx].selected = true;
|
||||||
|
}
|
||||||
|
onSelect(items.filter(item => item.selected));
|
||||||
|
}
|
||||||
|
|
||||||
|
$: useDoubleLine =
|
||||||
|
variant == "two-line" &&
|
||||||
|
items.every(i => typeof i.text == "object" && "primary" in i.text);
|
||||||
|
|
||||||
|
$: modifiers = { variant };
|
||||||
|
$: props = { modifiers };
|
||||||
|
$: listClass = cb.build({ props });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class={listClass} role="listbox">
|
||||||
|
{#each items as item, i}
|
||||||
|
<ListItem
|
||||||
|
{item}
|
||||||
|
{useDoubleLine}
|
||||||
|
{inputElement}
|
||||||
|
onClick={() => handleSelectedItem(item)} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<script>
|
||||||
|
import { setContext } from "svelte";
|
||||||
|
import { Radiobutton } from "../Radiobutton";
|
||||||
|
import { Checkbox } from "../Checkbox";
|
||||||
|
import ClassBuilder from "../ClassBuilder.js";
|
||||||
|
|
||||||
|
const cb = new ClassBuilder("list-item");
|
||||||
|
|
||||||
|
export let onClick = item => {};
|
||||||
|
|
||||||
|
export let item = null;
|
||||||
|
export let useDoubleLine = false;
|
||||||
|
export let inputElement = null; //radiobutton or checkbox
|
||||||
|
|
||||||
|
$: if (!!inputElement) {
|
||||||
|
setContext("BBMD:input:context", "list-item");
|
||||||
|
}
|
||||||
|
|
||||||
|
$: modifiers = { selected: !inputElement ? item.selected : null };
|
||||||
|
$: props = { modifiers };
|
||||||
|
$: listItemClass = cb.build({ props });
|
||||||
|
|
||||||
|
$: useSecondaryText =
|
||||||
|
typeof item.text === "object" && "secondary" in item.text;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<li
|
||||||
|
class={listItemClass}
|
||||||
|
role="option"
|
||||||
|
aria-selected={item.selected}
|
||||||
|
tabindex="0"
|
||||||
|
on:click={onClick}>
|
||||||
|
{#if item.leadingIcon}
|
||||||
|
<span class="mdc-list-item__graphic material-icons" aria-hidden="true">
|
||||||
|
{item.leadingIcon}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
<span class={cb.elem`text`}>
|
||||||
|
{#if useDoubleLine}
|
||||||
|
<span class={cb.elem`primary-text`}>{item.text.primary}</span>
|
||||||
|
{#if useSecondaryText}
|
||||||
|
<span class={cb.elem`secondary-text`}>{item.text.secondary}</span>
|
||||||
|
{/if}
|
||||||
|
{:else}{item.text}{/if}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{#if inputElement}
|
||||||
|
{#if inputElement === 'radiobutton'}
|
||||||
|
<Radiobutton checked={item.selected} />
|
||||||
|
{:else if inputElement === 'checkbox'}
|
||||||
|
<Checkbox checked={item.selected} />
|
||||||
|
{/if}
|
||||||
|
{:else if item.trailingIcon}
|
||||||
|
<!-- TODO: Adapt label to accept class prop to handle this. Context is insufficient -->
|
||||||
|
<span class="mdc-list-item__meta material-icons" aria-hidden="true">
|
||||||
|
{item.trailingIcon}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</li>
|
|
@ -0,0 +1 @@
|
||||||
|
@import "@material/list/mdc-list.scss";
|
|
@ -0,0 +1,2 @@
|
||||||
|
import "./_style.scss";
|
||||||
|
export { default as List } from "./List.svelte";
|
|
@ -16,21 +16,32 @@
|
||||||
let instance = null
|
let instance = null
|
||||||
let radiobtn = null
|
let radiobtn = null
|
||||||
|
|
||||||
|
let context = getContext("BBMD:input:context")
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
if (!!radiobtn) {
|
if (!!radiobtn) {
|
||||||
instance = new MDCRadio(radiobtn)
|
instance = new MDCRadio(radiobtn)
|
||||||
|
if (context !== "list-item") {
|
||||||
let fieldStore = getContext("BBMD:field-element")
|
let fieldStore = getContext("BBMD:field-element")
|
||||||
fieldStore.setInput(instance)
|
fieldStore.setInput(instance)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let extras = null
|
||||||
|
|
||||||
|
if (context === "list-item") {
|
||||||
|
extras = ["mdc-list-item__meta"]
|
||||||
|
}
|
||||||
|
|
||||||
const cb = new ClassBuilder("radio")
|
const cb = new ClassBuilder("radio")
|
||||||
let modifiers = { disabled }
|
let modifiers = { disabled }
|
||||||
let props = { modifiers }
|
let props = { modifiers, extras }
|
||||||
|
|
||||||
const blockClass = cb.build({ props })
|
const blockClass = cb.build({ props })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if context !== 'list-item'}
|
||||||
<Formfield {id} {label} {alignEnd}>
|
<Formfield {id} {label} {alignEnd}>
|
||||||
<div class={blockClass}>
|
<div class={blockClass}>
|
||||||
<input
|
<input
|
||||||
|
@ -48,3 +59,20 @@
|
||||||
<div class={cb.elem`ripple`} />
|
<div class={cb.elem`ripple`} />
|
||||||
</div>
|
</div>
|
||||||
</Formfield>
|
</Formfield>
|
||||||
|
{:else}
|
||||||
|
<div class={blockClass}>
|
||||||
|
<input
|
||||||
|
{id}
|
||||||
|
class={cb.elem`native-control`}
|
||||||
|
type="radio"
|
||||||
|
{name}
|
||||||
|
{checked}
|
||||||
|
{disabled}
|
||||||
|
on:click={onClick} />
|
||||||
|
<div class={cb.elem`background`}>
|
||||||
|
<div class={cb.elem`outer-circle`} />
|
||||||
|
<div class={cb.elem`inner-circle`} />
|
||||||
|
</div>
|
||||||
|
<div class={cb.elem`ripple`} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
{name}
|
{name}
|
||||||
{alignEnd}
|
{alignEnd}
|
||||||
label={item.label}
|
label={item.label}
|
||||||
checked={item.checked}
|
checked={item.checked || false}
|
||||||
onClick={() => handleOnClick(item)} />
|
onClick={() => handleOnClick(item)} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
Radiobuttongroup,
|
Radiobuttongroup,
|
||||||
Datatable,
|
Datatable,
|
||||||
CustomersIndexTable,
|
CustomersIndexTable,
|
||||||
|
List,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
let currentComponent
|
let currentComponent
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
Radiobutton,
|
Radiobutton,
|
||||||
Radiobuttongroup,
|
Radiobuttongroup,
|
||||||
Datatable,
|
Datatable,
|
||||||
CustomersIndexTable
|
CustomersIndexTable,
|
||||||
|
List,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,4 +103,23 @@ export const props = {
|
||||||
},
|
},
|
||||||
|
|
||||||
CustomersIndexTable: indexDatatable(templateOptions)[0].props,
|
CustomersIndexTable: indexDatatable(templateOptions)[0].props,
|
||||||
|
List: {
|
||||||
|
_component: "@budibase/materialdesign-components/List",
|
||||||
|
_children: [],
|
||||||
|
variant: "two-line",
|
||||||
|
singleSelection: true,
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
text: { primary: "Curry", secondary: "Chicken or Beef" },
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: { primary: "Pastie", secondary: "Bap with Mayo" },
|
||||||
|
value: 1,
|
||||||
|
selected: true,
|
||||||
|
},
|
||||||
|
{ text: { primary: "Fish", secondary: "Salmon or Cod" }, value: 2 },
|
||||||
|
],
|
||||||
|
onSelect: selected => console.log(selected),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,3 +15,4 @@ export {
|
||||||
DatatableRow,
|
DatatableRow,
|
||||||
} from "./Datatable"
|
} from "./Datatable"
|
||||||
export { default as indexDatatable } from "./Templates/indexDatatable"
|
export { default as indexDatatable } from "./Templates/indexDatatable"
|
||||||
|
export { List } from "./List"
|
||||||
|
|
Loading…
Reference in New Issue