71 lines
1.5 KiB
Svelte
71 lines
1.5 KiB
Svelte
<script lang="ts">
|
|
import { tick } from 'svelte';
|
|
import AppIcon from './AppIcon.svelte';
|
|
|
|
let {
|
|
value = $bindable(),
|
|
form,
|
|
name = 'title',
|
|
label = 'Titel',
|
|
oncommit
|
|
}: {
|
|
value: string;
|
|
form: string;
|
|
name?: string;
|
|
label?: string;
|
|
oncommit?: () => void;
|
|
} = $props();
|
|
|
|
let editing = $state(false);
|
|
let original = $state('');
|
|
let input = $state<HTMLInputElement>();
|
|
let trigger = $state<HTMLButtonElement>();
|
|
|
|
async function edit() {
|
|
original = value;
|
|
editing = true;
|
|
await tick();
|
|
input?.focus();
|
|
input?.select();
|
|
}
|
|
|
|
async function finish(commit: boolean) {
|
|
if (!editing) return;
|
|
if (!commit) value = original;
|
|
editing = false;
|
|
if (commit && value !== original) oncommit?.();
|
|
await tick();
|
|
trigger?.focus();
|
|
}
|
|
</script>
|
|
|
|
<div class="inline-title-editor">
|
|
<input type="hidden" {form} {name} {value} />
|
|
{#if editing}
|
|
<label>
|
|
<span class="sr-only">{label}</span>
|
|
<input
|
|
bind:this={input}
|
|
bind:value
|
|
maxlength="200"
|
|
required
|
|
onkeydown={(event) => {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault();
|
|
void finish(true);
|
|
} else if (event.key === 'Escape') {
|
|
event.preventDefault();
|
|
void finish(false);
|
|
}
|
|
}}
|
|
onblur={() => void finish(true)}
|
|
/>
|
|
</label>
|
|
{:else}
|
|
<button bind:this={trigger} type="button" class="inline-title-trigger" onclick={edit}>
|
|
<span>{value}</span><AppIcon name="pen" size="0.9em" />
|
|
<span class="sr-only">{label} bearbeiten</span>
|
|
</button>
|
|
{/if}
|
|
</div>
|