2022-09-27 04:16:45 +02:00
|
|
|
<!--
|
|
|
|
Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
-->
|
|
|
|
<script lang="ts">
|
2022-12-01 10:24:26 +01:00
|
|
|
import { createEventDispatcher, setContext } from "svelte";
|
2022-12-07 06:31:37 +01:00
|
|
|
import { writable } from "svelte/store";
|
2022-12-01 10:24:26 +01:00
|
|
|
|
|
|
|
import { selectKey } from "./context-keys";
|
2022-09-27 04:16:45 +02:00
|
|
|
import IconConstrain from "./IconConstrain.svelte";
|
|
|
|
import { chevronDown } from "./icons";
|
|
|
|
import Popover from "./Popover.svelte";
|
|
|
|
import WithFloating from "./WithFloating.svelte";
|
|
|
|
|
|
|
|
export let id: string | undefined = undefined;
|
2022-12-01 10:24:26 +01:00
|
|
|
|
2022-09-27 04:16:45 +02:00
|
|
|
let className = "";
|
|
|
|
export { className as class };
|
2022-12-01 10:24:26 +01:00
|
|
|
|
2022-09-27 04:16:45 +02:00
|
|
|
export let disabled = false;
|
2022-12-01 10:24:26 +01:00
|
|
|
export let label = "<br>";
|
|
|
|
export let value = 0;
|
|
|
|
|
|
|
|
const dispatch = createEventDispatcher();
|
|
|
|
|
|
|
|
function setValue(v: number) {
|
|
|
|
value = v;
|
2022-12-07 06:31:37 +01:00
|
|
|
dispatch("change", { value });
|
2022-12-01 10:24:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export let element: HTMLElement | undefined = undefined;
|
2022-09-27 04:16:45 +02:00
|
|
|
|
|
|
|
export let tooltip: string | undefined = undefined;
|
|
|
|
|
|
|
|
const rtl: boolean = window.getComputedStyle(document.body).direction == "rtl";
|
|
|
|
let hover = false;
|
|
|
|
|
|
|
|
let showFloating = false;
|
|
|
|
let clientWidth: number;
|
2022-12-01 10:24:26 +01:00
|
|
|
|
|
|
|
async function handleKey(e: KeyboardEvent) {
|
|
|
|
if (e.code === "Enter") {
|
|
|
|
e.preventDefault();
|
|
|
|
showFloating = !showFloating;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-07 06:31:37 +01:00
|
|
|
const selectStore = writable({ value, setValue });
|
|
|
|
$: $selectStore.value = value;
|
|
|
|
setContext(selectKey, selectStore);
|
2022-09-27 04:16:45 +02:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<WithFloating
|
|
|
|
show={showFloating}
|
|
|
|
offset={0}
|
2022-10-10 05:53:13 +02:00
|
|
|
shift={0}
|
2022-09-27 04:16:45 +02:00
|
|
|
hideArrow
|
|
|
|
inline
|
|
|
|
closeOnInsideClick
|
2022-12-01 10:24:26 +01:00
|
|
|
keepOnKeyup
|
2022-09-27 04:16:45 +02:00
|
|
|
on:close={() => (showFloating = false)}
|
|
|
|
let:asReference
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
{id}
|
|
|
|
class="{className} select-container"
|
|
|
|
class:rtl
|
|
|
|
class:hover
|
|
|
|
{disabled}
|
|
|
|
title={tooltip}
|
2022-12-01 10:24:26 +01:00
|
|
|
tabindex="0"
|
|
|
|
on:keypress={handleKey}
|
2022-09-27 04:16:45 +02:00
|
|
|
on:mouseenter={() => (hover = true)}
|
|
|
|
on:mouseleave={() => (hover = false)}
|
|
|
|
on:click={() => (showFloating = !showFloating)}
|
|
|
|
bind:this={element}
|
|
|
|
use:asReference
|
|
|
|
bind:clientWidth
|
|
|
|
>
|
2022-12-01 10:24:26 +01:00
|
|
|
<div class="inner">
|
|
|
|
<div class="label">{@html label}</div>
|
|
|
|
</div>
|
2022-09-27 04:16:45 +02:00
|
|
|
<div class="chevron">
|
|
|
|
<IconConstrain iconSize={80}>
|
|
|
|
{@html chevronDown}
|
|
|
|
</IconConstrain>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<Popover slot="floating" scrollable --popover-width="{clientWidth}px">
|
|
|
|
<slot />
|
|
|
|
</Popover>
|
|
|
|
</WithFloating>
|
|
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
@use "sass/button-mixins" as button;
|
2022-12-01 10:24:26 +01:00
|
|
|
|
|
|
|
$padding-inline: 0.5rem;
|
|
|
|
|
2022-09-27 04:16:45 +02:00
|
|
|
.select-container {
|
|
|
|
@include button.select($with-disabled: false);
|
|
|
|
line-height: 1.5;
|
2022-12-01 10:24:26 +01:00
|
|
|
height: 100%;
|
2022-09-27 04:16:45 +02:00
|
|
|
position: relative;
|
2022-12-01 10:24:26 +01:00
|
|
|
display: flex;
|
|
|
|
flex-flow: row;
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
.inner {
|
|
|
|
flex-grow: 1;
|
|
|
|
position: relative;
|
|
|
|
.label {
|
|
|
|
position: absolute;
|
|
|
|
top: 0;
|
|
|
|
right: $padding-inline;
|
|
|
|
bottom: 0;
|
|
|
|
left: $padding-inline;
|
|
|
|
white-space: nowrap;
|
|
|
|
overflow: hidden;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
}
|
|
|
|
}
|
2022-09-27 04:16:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.chevron {
|
2022-12-01 10:24:26 +01:00
|
|
|
height: 100%;
|
|
|
|
align-self: flex-end;
|
2022-10-29 02:48:53 +02:00
|
|
|
border-left: 1px solid var(--border-subtle);
|
2022-09-27 04:16:45 +02:00
|
|
|
}
|
2022-12-01 10:24:26 +01:00
|
|
|
|
2022-09-27 04:16:45 +02:00
|
|
|
:global([dir="rtl"]) {
|
|
|
|
.chevron {
|
|
|
|
border-left: none;
|
2022-10-29 02:48:53 +02:00
|
|
|
border-right: 1px solid var(--border-subtle);
|
2022-09-27 04:16:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|