diff options
Diffstat (limited to 'apps/web-shared/src/components/menu')
| -rw-r--r-- | apps/web-shared/src/components/menu/index.ts | 9 | ||||
| -rw-r--r-- | apps/web-shared/src/components/menu/item.svelte | 8 | ||||
| -rw-r--r-- | apps/web-shared/src/components/menu/menu.svelte | 54 | ||||
| -rw-r--r-- | apps/web-shared/src/components/menu/separator.svelte | 2 |
4 files changed, 73 insertions, 0 deletions
diff --git a/apps/web-shared/src/components/menu/index.ts b/apps/web-shared/src/components/menu/index.ts new file mode 100644 index 0000000..8eb7938 --- /dev/null +++ b/apps/web-shared/src/components/menu/index.ts @@ -0,0 +1,9 @@ +import Menu from "./menu.svelte"; +import MenuItem from "./item.svelte"; +import MenuItemSeparator from "./separator.svelte"; + +export { + Menu, + MenuItem, + MenuItemSeparator +}; diff --git a/apps/web-shared/src/components/menu/item.svelte b/apps/web-shared/src/components/menu/item.svelte new file mode 100644 index 0000000..aeb0f99 --- /dev/null +++ b/apps/web-shared/src/components/menu/item.svelte @@ -0,0 +1,8 @@ +<script lang="ts"> + export let danger = false; +</script> +<li role="menuitem" on:click> + <span class="menu__content {danger ? 'bg-error-lighter@hover color-white@hover' : ''}"> + <slot/> + </span> +</li> diff --git a/apps/web-shared/src/components/menu/menu.svelte b/apps/web-shared/src/components/menu/menu.svelte new file mode 100644 index 0000000..33b1160 --- /dev/null +++ b/apps/web-shared/src/components/menu/menu.svelte @@ -0,0 +1,54 @@ +<script lang="ts"> + import {random_string} from "$shared/lib/helpers"; + + export let id = "__menu_" + random_string(3); + export let trigger: HTMLElement; + export let show = false; + + let windowInnerWidth = 0; + let windowInnerHeight = 0; + let menu: HTMLMenuElement; + + $: if (show && menu && trigger) { + const + selectedTriggerPosition = trigger.getBoundingClientRect(), + menuOnTop = (windowInnerHeight - selectedTriggerPosition.bottom) < selectedTriggerPosition.top, + left = selectedTriggerPosition.left, + right = (windowInnerWidth - selectedTriggerPosition.right), + isRight = (windowInnerWidth < selectedTriggerPosition.left + menu.offsetWidth), + vertical = menuOnTop + ? "bottom: " + (windowInnerHeight - selectedTriggerPosition.top) + "px;" + : "top: " + selectedTriggerPosition.bottom + "px;"; + + let horizontal = isRight ? "right: " + right + "px;" : "left: " + left + "px;"; + + // check right position is correct -> otherwise set left to 0 + if (isRight && (right + menu.offsetWidth) > windowInnerWidth) horizontal = ("left: " + (windowInnerWidth - menu.offsetWidth) / 2 + "px;"); + const maxHeight = menuOnTop ? selectedTriggerPosition.top - 20 : windowInnerHeight - selectedTriggerPosition.bottom - 20; + menu.setAttribute("style", horizontal + vertical + "max-height:" + Math.floor(maxHeight) + "px;"); + } + + function on_window_click(event) { + if (!event.target.closest("#" + id) && !event.target.closest("[aria-controls='" + id + "']")) show = false; + } + + function on_window_touchend(event) { + if (!event.target.closest("#" + id) && !event.target.closest("[aria-controls='" + id + "']")) show = false; + } +</script> + +<svelte:window + on:click={on_window_click} + on:touchend={on_window_touchend} + bind:innerWidth={windowInnerWidth} + bind:innerHeight={windowInnerHeight} +/> + +<menu class="menu" + id="{id}" + bind:this={menu} + class:menu--is-visible={show} + aria-expanded="{show}" + aria-haspopup="true"> + <slot name="options"/> +</menu> diff --git a/apps/web-shared/src/components/menu/separator.svelte b/apps/web-shared/src/components/menu/separator.svelte new file mode 100644 index 0000000..798dce0 --- /dev/null +++ b/apps/web-shared/src/components/menu/separator.svelte @@ -0,0 +1,2 @@ +<li class="menu__separator" + role="separator"></li> |
