You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.2 KiB
Svelte

<script lang="ts">
import { tick, createEventDispatcher } from "svelte";
export let description: string;
export let completed: boolean;
export let editing: boolean;
export let busy: boolean;
const dispatch = createEventDispatcher<{
toggleEdit: void;
saveText: { text: string };
cancelText: void;
}>();
let el: HTMLElement | null = null;
// Mantener el DOM sincronizado cuando se cierra la edición o cambia la descripción
$: if (el && !editing) {
el.textContent = description;
}
// Enfocar al entrar en modo edición
$: if (editing) {
tick().then(() => {
if (el) {
el.focus();
placeCaretAtEnd(el);
}
});
}
function placeCaretAtEnd(node: HTMLElement) {
const range = document.createRange();
range.selectNodeContents(node);
range.collapse(false);
const sel = window.getSelection();
sel?.removeAllRanges();
sel?.addRange(range);
}
function normalizeText(s: string): string {
return s.replace(/\s+/g, " ").trim();
}
export function getCurrentText(): string {
return normalizeText(el?.textContent || "");
}
</script>
<div
tabindex="0"
class="desc"
class:editing={editing}
class:completed
contenteditable={editing && !completed}
role="textbox"
aria-label="Descripción de la tarea"
spellcheck="true"
bind:this={el}
on:dblclick={() => !busy && !completed && dispatch('toggleEdit')}
on:keydown={(e) => {
if (e.key === "Escape") {
e.preventDefault();
dispatch('cancelText');
} else if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
e.preventDefault();
dispatch('saveText', { text: getCurrentText() });
} else if (e.key === "Enter") {
e.preventDefault();
}
}}
>
{description}
</div>
<style>
.desc {
padding: 8px 4px;
grid-column: 1/3;
grid-row: 2/3;
}
.desc.editing {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
background: var(--color-surface);
padding: 2px 4px;
border-radius: 4px;
white-space: normal;
text-overflow: clip;
grid-column: 1/3;
grid-row: 2/3;
margin: 16px 0;
}
.desc.completed {
text-decoration: line-through;
}
</style>