97 lines
1.9 KiB
Svelte
97 lines
1.9 KiB
Svelte
<script lang="ts">
|
|
import Selector, {
|
|
type SELECTOR_TYPE,
|
|
type SelectorValue,
|
|
} from "./Selector.svelte";
|
|
import { createEventDispatcher } from "svelte";
|
|
import type { IValue } from "@upnd/upend/types";
|
|
import IconButton from "./IconButton.svelte";
|
|
|
|
const dispatch = createEventDispatcher();
|
|
|
|
export let value: IValue | undefined = undefined;
|
|
export let types: SELECTOR_TYPE[] | undefined = undefined;
|
|
let newValue: SelectorValue = value;
|
|
|
|
let editing = false;
|
|
|
|
let selector: Selector;
|
|
let hover = false;
|
|
let focus = false;
|
|
|
|
$: if (editing && selector) selector.focus();
|
|
$: if (!focus && !hover) editing = false;
|
|
|
|
function onInput(ev: CustomEvent<SelectorValue>) {
|
|
newValue = ev.detail;
|
|
selector.focus();
|
|
}
|
|
</script>
|
|
|
|
<div
|
|
class="editable"
|
|
class:editing
|
|
on:mouseenter={() => (hover = true)}
|
|
on:mouseleave={() => (hover = false)}
|
|
>
|
|
<div class="inner">
|
|
{#if editing}
|
|
<div
|
|
class="selector"
|
|
on:keydown={(ev) => {
|
|
if (ev.key === "Escape") {
|
|
editing = false;
|
|
}
|
|
}}
|
|
>
|
|
<Selector
|
|
{types}
|
|
bind:this={selector}
|
|
on:focus={(ev) => (focus = ev.detail)}
|
|
on:input={onInput}
|
|
/>
|
|
</div>
|
|
<IconButton
|
|
name="save"
|
|
on:click={() => {
|
|
dispatch("edit", newValue);
|
|
editing = false;
|
|
}}
|
|
/>
|
|
{:else}
|
|
<div class="content">
|
|
<slot />
|
|
</div>
|
|
<div class="edit-icon">
|
|
<IconButton name="edit" on:click={() => (editing = true)} />
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.edit-icon {
|
|
opacity: 0;
|
|
transition: opacity 0.2s ease-in-out;
|
|
}
|
|
|
|
.editable:hover .edit-icon {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.inner {
|
|
display: flex;
|
|
gap: 0.25em;
|
|
align-items: center;
|
|
}
|
|
|
|
.content {
|
|
min-width: 0;
|
|
}
|
|
|
|
.selector {
|
|
flex-grow: 1;
|
|
min-width: 0;
|
|
}
|
|
</style>
|