Completed MD Menu component

This commit is contained in:
Conor_Mack 2020-02-25 10:09:32 +00:00
parent f11853a790
commit 395bee750c
6 changed files with 118 additions and 47 deletions

View File

@ -45,6 +45,7 @@
"@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/list": "4.0.0",
"@material/menu": "4.0.0",
"@material/radio": "^4.0.0", "@material/radio": "^4.0.0",
"@material/textfield": "^4.0.0" "@material/textfield": "^4.0.0"
} }

View File

@ -1,64 +1,71 @@
<script> <script>
import { onMount } from "svelte" import { onMount, getContext } from "svelte";
import { MDCList } from "@material/list" import { MDCList } from "@material/list";
import { MDCRipple } from "@material/ripple" import { MDCRipple } from "@material/ripple";
import ListItem from "./ListItem.svelte" import ListItem from "./ListItem.svelte";
import ClassBuilder from "../ClassBuilder.js" import ClassBuilder from "../ClassBuilder.js";
const cb = new ClassBuilder("list") const cb = new ClassBuilder("list", ["one-line"]);
let list = null let list = null;
let instance = null let instance = null;
export let onSelect = selectedItems => {} export let onSelect = selectedItems => {};
export let variant = "" export let variant = "one-line";
//items: [{text: string | {primary: string, secondary: string}, value: any, selected: bool}...n] //items: [{text: string | {primary: string, secondary: string}, value: any, selected: bool}...n]
export let items = [] export let items = [];
export let singleSelection = false export let singleSelection = false;
export let inputElement = null export let inputElement = null;
let role = "listbox";
onMount(() => { onMount(() => {
if (!!list) { if (!!list) {
instance = new MDCList(list) instance = new MDCList(list);
instance.singleSelection = singleSelection instance.singleSelection = singleSelection;
instance.listElements.map(element => new MDCRipple(element)) instance.listElements.map(element => new MDCRipple(element));
}
let context = getContext("BBMD:list:context");
if (context === "menu") {
role = "menu";
} }
return () => { return () => {
instance && instance.destroy() instance && instance.destroy();
instance = null instance = null;
} };
}) });
function handleSelectedItem(item) { function handleSelectedItem(item) {
if (!item.disabled) { if (!item.disabled) {
if (singleSelection || inputElement === "radiobutton") { if (singleSelection || inputElement === "radiobutton") {
items.forEach(i => { items.forEach(i => {
if (i.selected) i.selected = false if (i.selected) i.selected = false;
}) });
} }
let idx = items.indexOf(item) let idx = items.indexOf(item);
if (!!item.selected) { if (!!item.selected) {
items[idx].selected = !item.selected items[idx].selected = !item.selected;
} else { } else {
items[idx].selected = true items[idx].selected = true;
} }
onSelect(items.filter(item => item.selected)) onSelect(items.filter(item => item.selected));
} }
} }
$: useDoubleLine = $: useDoubleLine =
variant == "two-line" && variant == "two-line" &&
items.every(i => typeof i.text == "object" && "primary" in i.text) items.every(i => typeof i.text == "object" && "primary" in i.text);
$: modifiers = { variant } $: modifiers = { variant };
$: props = { modifiers } $: props = { modifiers };
$: listClass = cb.build({ props }) $: listClass = cb.build({ props });
</script> </script>
<div class={listClass} role="listbox"> <ul class={listClass} {role}>
{#each items as item, i} {#each items as item, i}
<ListItem <ListItem
{item} {item}
@ -69,4 +76,4 @@
<li role="separator" class="mdc-list-divider" /> <li role="separator" class="mdc-list-divider" />
{/if} {/if}
{/each} {/each}
</div> </ul>

View File

@ -1,30 +1,39 @@
<script> <script>
import { setContext } from "svelte" import { onMount, getContext } from "svelte";
import { Radiobutton } from "../Radiobutton" import { Radiobutton } from "../Radiobutton";
import { Checkbox } from "../Checkbox" import { Checkbox } from "../Checkbox";
import ClassBuilder from "../ClassBuilder.js" import ClassBuilder from "../ClassBuilder.js";
const cb = new ClassBuilder("list-item") const cb = new ClassBuilder("list-item");
export let onClick = item => {} export let onClick = item => {};
export let item = null export let item = null;
export let useDoubleLine = false export let useDoubleLine = false;
export let inputElement = null //radiobutton or checkbox export let inputElement = null; //radiobutton or checkbox
let role = "option";
onMount(() => {
let context = getContext("BBMD:list:context");
if (context === "menu") {
role = "menuitem";
}
});
$: if (!!inputElement) { $: if (!!inputElement) {
setContext("BBMD:input:context", "list-item") setContext("BBMD:input:context", "list-item");
} }
$: modifiers = { $: modifiers = {
selected: !inputElement ? item.selected : null, selected: !inputElement ? item.selected : null,
disabled: item.disabled, disabled: item.disabled
} };
$: props = { modifiers } $: props = { modifiers };
$: listItemClass = cb.build({ props }) $: listItemClass = cb.build({ props });
$: useSecondaryText = $: useSecondaryText =
typeof item.text === "object" && "secondary" in item.text typeof item.text === "object" && "secondary" in item.text;
</script> </script>
<li <li

View File

@ -0,0 +1,50 @@
<script>
import { List } from "../List";
import { MDCMenu } from "@material/menu";
import { onMount, setContext } from "svelte";
export let items = [];
export let singleSelection = true;
export let width = "400px";
export let open = true;
export let useFixedPosition = false;
export let useAbsolutePosition = false;
//{x: number, y: number}
export let absolutePositionCoords = null;
let menu = null;
let instance = null;
onMount(() => {
if (!!menu) {
instance = new MDCMenu(menu);
instance.open = open;
if (useFixedPosition) {
instance.setFixedPosition(true);
} else if (useAbsolutePosition) {
let { x, y } = absolutePositionCoords;
instance.setAbsolutePosition(x | 0, y | 0);
}
}
setContext("BBMD:list:context", "menu");
});
</script>
{#if useFixedPosition || useAbsolutePosition}
<div
bind:this={menu}
class="mdc-menu mdc-menu-surface"
style={`width: ${width}`}>
<List {items} {singleSelection} />
</div>
{:else}
<div class="mdc-menu-surface--anchor">
<!-- Will automatically anchor to slotted element -->
<slot />
<div
bind:this={menu}
class="mdc-menu mdc-menu-surface"
style={`width: ${width}`}>
<List {items} {singleSelection} />
</div>
</div>
{/if}

View File

@ -0,0 +1,2 @@
@import "@material/menu-surface/mdc-menu-surface.scss";
@import "@material/menu/mdc-menu.scss";

View File

@ -0,0 +1,2 @@
import "./_styles.scss";
export { default as Menu } from "./Menu.svelte";