feat: add popper to droplist

This commit is contained in:
Torsten Dittmann
2022-10-21 16:49:08 +02:00
parent 1e2d691eb4
commit 421c1ded64
13 changed files with 96 additions and 76 deletions
+79 -19
View File
@@ -1,21 +1,81 @@
<script lang="ts">
import { createPopper, type Instance } from '@popperjs/core';
import { afterUpdate, onDestroy, onMount } from 'svelte';
import { slide } from 'svelte/transition';
export let show = false;
export let position: 'top' | 'bottom' = 'top';
export let horizontal: 'left' | 'right' = 'right';
export let arrowPosition: 'start' | 'center' | 'end' = 'start';
export let arrow = true;
export let noArrow = false;
export let placement: Placement = 'bottom-start';
export let scrollable = false;
export let childStart = false;
let parentElement: HTMLDivElement;
type Placement = 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';
let element: HTMLDivElement;
let tooltip: HTMLDivElement;
let instance: Instance;
let currentArrow: Placement;
$: [arrowHorizontal, arrowPosition] = applyArrow(currentArrow);
function applyArrow(value: Placement): [string: 'start' | 'end', string: 'top' | 'bottom'] {
switch (value) {
case 'bottom-start':
return ['start', 'bottom'];
case 'bottom-end':
return ['end', 'bottom'];
case 'top-start':
return ['start', 'top'];
case 'top-end':
return ['end', 'top'];
default:
return ['start', 'bottom'];
}
}
onMount(() => {
instance = createPopper(element, tooltip, {
placement,
modifiers: [
{
name: 'offset',
options: {
offset: [0, noArrow ? 0 : 12]
}
},
{
name: 'flip',
options: {
fallbackPlacements: ['top-start', 'top-end', 'bottom-start', 'bottom-end']
}
},
{
name: 'placementLogger',
enabled: true,
phase: 'main',
fn({ state }) {
if (currentArrow !== state.placement) {
currentArrow = state.placement as Placement;
}
}
}
]
});
});
$: if (show) {
instance?.update();
}
afterUpdate(() => {
instance?.update();
});
onDestroy(() => {
instance?.destroy();
});
const onBlur = (event: MouseEvent) => {
if (
show &&
!(event.target === parentElement || parentElement.contains(event.target as Node))
) {
if (show && !(event.target === element || element.contains(event.target as Node))) {
show = false;
}
};
@@ -23,20 +83,20 @@
<svelte:window on:click={onBlur} />
<div
class="drop-wrapper"
class:is-open={show}
class:u-cross-child-start={childStart}
bind:this={parentElement}>
<div class="drop-wrapper" class:u-cross-child-start={childStart} bind:this={element}>
<slot />
</div>
<div bind:this={tooltip} style="z-index: 10">
{#if show}
<div
class="drop"
class:is-arrow-center={arrowPosition === 'center'}
class:is-arrow-end={arrowPosition === 'end'}
class:is-no-arrow={!arrow}
class:is-block-end={position === 'bottom'}
class:is-inline-end={horizontal === 'left'}
style="position: revert"
class:is-no-arrow={noArrow}
class:is-arrow-start={arrowHorizontal === 'start'}
class:is-arrow-end={arrowHorizontal === 'end'}
class:is-block-start={arrowPosition === 'top'}
class:is-block-end={arrowPosition === 'bottom'}
transition:slide={{ duration: 100 }}>
<section
class:u-overflow-y-auto={scrollable}
@@ -21,12 +21,7 @@
}
</script>
<DropList
bind:show={showDropdown}
position="bottom"
horizontal="right"
arrow={true}
arrowPosition="start">
<DropList bind:show={showDropdown} placement="bottom-end">
<Button text noMargin on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Add role</span>
+1 -6
View File
@@ -42,12 +42,7 @@
</nav>
<nav class="user-profile">
{#if $user}
<DropList
bind:show={showDropdown}
position="bottom"
horizontal="left"
arrow={false}
scrollable={true}>
<DropList bind:show={showDropdown} placement="bottom-start" scrollable={true} noArrow>
<button class="user-profile-button" on:click={() => (showDropdown = !showDropdown)}>
<AvatarInitials size={40} name={$user.name} />
<span class="user-profile-info is-only-desktop">
+1 -5
View File
@@ -94,11 +94,7 @@
</a>
{/if}
{#if $titleDropdown?.length && $organization}
<DropList
bind:show={showDropdown}
position="bottom"
arrow={false}
scrollable={true}>
<DropList bind:show={showDropdown} scrollable={true} noArrow>
<button
class="button is-text u-padding-inline-0"
on:click={() => (showDropdown = !showDropdown)}>
@@ -254,12 +254,7 @@
</Button>
{#if $user.status}
{#if $user.phone && $user.email}
<DropList
bind:show={showVerifcationDropdown}
position="top"
horizontal="left"
arrow={true}
arrowPosition="end">
<DropList bind:show={showVerifcationDropdown} placement="top-start">
<Button
secondary
on:click={() => (showVerifcationDropdown = !showVerifcationDropdown)}>
@@ -75,9 +75,8 @@
<TableCell showOverflow>
<DropList
bind:show={showDropdown[index]}
position="bottom"
horizontal="left"
arrow={false}>
placement="bottom-start"
noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"
@@ -108,11 +108,7 @@
{index.orders}
</TableCellText>
<TableCell showOverflow>
<DropList
bind:show={showDropdown[i]}
position="bottom"
horizontal="left"
arrow={false}>
<DropList bind:show={showDropdown[i]} placement="bottom-start" noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"
@@ -192,9 +192,8 @@
<TableCell showOverflow>
<DropList
bind:show={showDropdown[index]}
position="bottom"
horizontal="left"
arrow={false}>
placement="bottom-start"
noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"
@@ -501,9 +501,8 @@
<td class="table-col u-overflow-visible" data-title="options">
<DropList
bind:show={showVariablesDropdown[i]}
position="bottom"
horizontal="left"
arrow={false}>
placement="bottom-start"
noArrow>
<button
class="button is-text is-only-icon"
aria-label="more options"
@@ -57,11 +57,7 @@
<Secret value={variable.value} />
</TableCell>
<TableCell showOverflow title="options">
<DropList
bind:show={showDropdown[i]}
position="bottom"
horizontal="left"
arrow={false}>
<DropList bind:show={showDropdown[i]} placement="bottom-start" noArrow>
<button
class="button is-text is-only-icon"
aria-label="more options"
@@ -107,9 +107,7 @@
</div>
<DropList
bind:show={showPeriodBandwidth}
position="bottom"
horizontal="left"
arrowPosition="end"
placement="bottom-start"
childStart>
<button
class="transparent-button"
@@ -150,9 +148,7 @@
</div>
<DropList
bind:show={showPeriodRequests}
position="bottom"
horizontal="left"
arrowPosition="end"
placement="bottom-start"
childStart>
<button
class="transparent-button"
@@ -37,12 +37,7 @@
<div class="common-section u-flex u-gap-12">
<Heading tag="h3" size="7">Platforms</Heading>
<span class="u-margin-inline-start-auto">
<DropList
bind:show={showDropdown}
position="bottom"
horizontal="right"
arrow={true}
arrowPosition="start">
<DropList bind:show={showDropdown} placement="bottom-start">
<Button on:click={() => (showDropdown = !showDropdown)}>
<span class="icon-plus" aria-hidden="true" />
<span class="text">Add platform</span>
@@ -154,9 +154,8 @@
<TableCell showOverflow>
<DropList
bind:show={showDropdown[index]}
position="bottom"
horizontal="left"
arrow={false}>
placement="bottom-start"
noArrow>
<button
class="button is-only-icon is-text"
aria-label="More options"