refactor(editor): untrack() fuer form-lokale Snapshots (Item I)
Some checks failed
Build & Publish Docker Image / build-and-push (push) Has been cancelled
Some checks failed
Build & Publish Docker Image / build-and-push (push) Has been cancelled
Alle 10 pre-existing svelte-check WARNINGs ("state_referenced_locally")
in RecipeEditor.svelte und recipes/[id]/+page.svelte addressiert.
Die betroffenen `let foo = $state(recipe.bar)`-Pattern sind
intentional Snapshots: der Editor soll User-Edits behalten und nicht
von prop-Updates ueberschrieben werden. untrack() macht die Intent
explizit und silenced die Warnung sauber statt sie unter den Teppich
zu kehren.
Scope: imagePath, title, description, servings, prepMin, cookMin,
totalMin, ingredients, steps (RecipeEditor) + recipeState
(recipes/[id]/+page).
Gate: svelte-check 0 Warnings (war 10), Tests 184/184.
Refs docs/superpowers/plans/2026-04-19-post-review-roadmap.md Item I.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { untrack } from 'svelte';
|
||||||
import { Plus, Trash2, ChevronUp, ChevronDown, ImagePlus, ImageOff } from 'lucide-svelte';
|
import { Plus, Trash2, ChevronUp, ChevronDown, ImagePlus, ImageOff } from 'lucide-svelte';
|
||||||
import type { Recipe, Ingredient, Step } from '$lib/types';
|
import type { Recipe, Ingredient, Step } from '$lib/types';
|
||||||
import { alertAction, confirmAction } from '$lib/client/confirm.svelte';
|
import { alertAction, confirmAction } from '$lib/client/confirm.svelte';
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
|
|
||||||
let { recipe, saving = false, onsave, oncancel, onimagechange }: Props = $props();
|
let { recipe, saving = false, onsave, oncancel, onimagechange }: Props = $props();
|
||||||
|
|
||||||
let imagePath = $state<string | null>(recipe.image_path);
|
let imagePath = $state<string | null>(untrack(() => recipe.image_path));
|
||||||
let uploading = $state(false);
|
let uploading = $state(false);
|
||||||
let fileInput: HTMLInputElement | null = $state(null);
|
let fileInput: HTMLInputElement | null = $state(null);
|
||||||
|
|
||||||
@@ -94,12 +95,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = $state(recipe.title);
|
// Form-lokaler Zustand: Initialwerte aus dem Prop snapshotten (untrack),
|
||||||
let description = $state(recipe.description ?? '');
|
// damit User-Edits nicht von prop-Updates ueberschrieben werden.
|
||||||
let servings = $state<number | ''>(recipe.servings_default ?? '');
|
let title = $state(untrack(() => recipe.title));
|
||||||
let prepMin = $state<number | ''>(recipe.prep_time_min ?? '');
|
let description = $state(untrack(() => recipe.description ?? ''));
|
||||||
let cookMin = $state<number | ''>(recipe.cook_time_min ?? '');
|
let servings = $state<number | ''>(untrack(() => recipe.servings_default ?? ''));
|
||||||
let totalMin = $state<number | ''>(recipe.total_time_min ?? '');
|
let prepMin = $state<number | ''>(untrack(() => recipe.prep_time_min ?? ''));
|
||||||
|
let cookMin = $state<number | ''>(untrack(() => recipe.cook_time_min ?? ''));
|
||||||
|
let totalMin = $state<number | ''>(untrack(() => recipe.total_time_min ?? ''));
|
||||||
|
|
||||||
type DraftIng = {
|
type DraftIng = {
|
||||||
qty: string;
|
qty: string;
|
||||||
@@ -110,15 +113,17 @@
|
|||||||
type DraftStep = { text: string };
|
type DraftStep = { text: string };
|
||||||
|
|
||||||
let ingredients = $state<DraftIng[]>(
|
let ingredients = $state<DraftIng[]>(
|
||||||
recipe.ingredients.map((i) => ({
|
untrack(() =>
|
||||||
qty: i.quantity !== null ? String(i.quantity).replace('.', ',') : '',
|
recipe.ingredients.map((i) => ({
|
||||||
unit: i.unit ?? '',
|
qty: i.quantity !== null ? String(i.quantity).replace('.', ',') : '',
|
||||||
name: i.name,
|
unit: i.unit ?? '',
|
||||||
note: i.note ?? ''
|
name: i.name,
|
||||||
}))
|
note: i.note ?? ''
|
||||||
|
}))
|
||||||
|
)
|
||||||
);
|
);
|
||||||
let steps = $state<DraftStep[]>(
|
let steps = $state<DraftStep[]>(
|
||||||
recipe.steps.map((s) => ({ text: s.text }))
|
untrack(() => recipe.steps.map((s) => ({ text: s.text })))
|
||||||
);
|
);
|
||||||
|
|
||||||
function addIngredient() {
|
function addIngredient() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, onDestroy, tick } from 'svelte';
|
import { onMount, onDestroy, tick, untrack } from 'svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import {
|
import {
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
let editMode = $state(false);
|
let editMode = $state(false);
|
||||||
let saving = $state(false);
|
let saving = $state(false);
|
||||||
let recipeState = $state(data.recipe);
|
let recipeState = $state(untrack(() => data.recipe));
|
||||||
|
|
||||||
// Einmalige Pulse-Animation beim Aktivieren (nicht beim Wieder-Abwählen).
|
// Einmalige Pulse-Animation beim Aktivieren (nicht beim Wieder-Abwählen).
|
||||||
// Per tick()-Zwischenschritt "aus → an" erzwingen, damit die Animation
|
// Per tick()-Zwischenschritt "aus → an" erzwingen, damit die Animation
|
||||||
|
|||||||
Reference in New Issue
Block a user