import type { StepTechStepView, SubmitTechStepCorrectionResult } from "@batch-cooking/shared"; import { Fragment, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Tooltip } from "../../../components/ui/Tooltip"; import { splitDescriptionSegments } from "./highlight-tech-steps"; import { TechStepCorrectionPopover } from "./TechStepCorrectionPopover"; import { temperatureLabel } from "./temperature-label"; import { type TextSelectionRange, useTextSelection } from "./use-text-selection"; /** * A recipe step's description, with every detected technique's exact * matched words highlighted and given a {@link Tooltip} naming the * technique (e.g. hovering/focusing "hacher" in "Hacher les oignons" shows * "Hacher") — `RecipeDetailPanel`'s replacement for a bare `
{description}
`. * * A match's wider `contextStart`/`contextEnd` clause (see * `StepTechStepView`) is deliberately *not* visualized here — only the * tight keyword span is highlighted. The backend still computes and * persists it (`tech-step-matcher.ts`/`StepTechStep`), and * `splitDescriptionByTechSteps` still splits the description around it * (`isKeyword: false` context segments), but this component now renders * those non-keyword segments as plain text, same as a segment with no * technique at all — the visual "wider clause, subtler highlight" * treatment (`.step-tech-step-context`) turned out to be more visual noise * than useful signal in practice and was turned back off. * * `techStep.key` resolves its tooltip label through `catalog.techSteps.
{segments.map((segment, index) => {
const start = offset;
offset += segment.text.length;
// Captured now, not read as `offset` later inside a click
// handler below — `offset` keeps mutating for every subsequent
// segment this same `.map()` pass renders, so a closure
// referencing it directly would see its *final* value (the end
// of the whole description) whenever it actually fires, long
// after render — found via a real correction submitted with
// `end` far past this segment's own text.
const end = offset;
// A segment's own text/techStep don't uniquely identify it (the
// same word can appear twice in one description) — index is the
// only thing that does, but this list is fully regenerated from
// `description`/`liveTechSteps` on every render (never reordered
// or spliced in place), so using it as part of the key is safe
// here.
const key = `${index}-${segment.text}`;
if (segment.temperature) {
// A detected temperature mention ("180°C", "feu doux") — its
// own subtle highlight + a Tooltip with the normalized value.
// Not correctable (no popover), same as utensils; still gets a
// `data-offset` in editable mode so a text selection spanning
// it resolves correctly.
const label = temperatureLabel(segment.temperature, t);
const modifier = segment.temperature.qualitative ?? "value";
return (