# Build the "Regenerate with instruction" pattern: `RegeneratePanel`

## Stack (edit this block to match your project)
- React 18+ with TypeScript: one function component, typed props, no `any`.
- Tailwind CSS, using your design system's tokens if you have them.
- Presentational only: data comes in through props, decisions go out through callbacks. No fetching or global state inside.
- If your codebase already has conventions (naming, shared components, tokens), follow them over this spec.

## What the pattern is for
Re-run scoped to a correction — shorter, more formal, drop the third point — instead of a blind retry.

Use it when: When the miss is directional and the user can name it in a few words.

## What to build
A control for re-running an AI output with a named correction (quick chips like "Shorter" or "More formal", point-level actions like keep or drop, and a free-text instruction) instead of a blind retry. Each result is kept as a numbered version for comparison. It renders under or beside a generated response or draft.

### Props
- `presets`: Array<{ id: string; label: string }>, quick instructions, e.g. Shorter, More formal, Friendlier.
- `parts?`: Array<{ id: string; text: string; mark: "keep" | "drop" | "neutral" }>, the output's points or paragraphs, which the person can pin or drop.
- `instruction`: string and `selectedPresetIds`: string[], controlled.
- `versions`: Array<{ id: string; label: string; instruction?: string; createdAt: Date }> with `currentVersionId`.
- `status`: "idle" | "regenerating" | "error".
- `onInstructionChange(text)`, `onPresetsChange(ids)`, `onPartMark(id, mark)`: callbacks.
- `onRegenerate({ instruction, presetIds, keep: string[], drop: string[], baseVersionId })`, `onSelectVersion(id)` and `onCancel()`: callbacks. The component never generates text itself.

### States it must render
- Idle: preset chips, an instruction field ("Tell it what to change"), and parts with keep or drop toggles; the button reads "Rewrite" only when an instruction, preset or mark is set.
- Regenerating: the current version stays visible with "Rewriting v1: more formal, drop point 3" and Cancel.
- New version: tabs or a switcher "v1 | v2" with each version's instruction shown under its tab; kept parts are marked as unchanged.
- Error: the previous version remains current with "Couldn't rewrite" and Retry, the instruction preserved.

### Interactions
- Chips toggle and combine with free text; the composed instruction is shown as one line before submitting.
- Marking a part "keep" pins it so it must return word for word; "drop" removes it; both go into `onRegenerate`.
- Enter in the instruction field submits; Escape clears it.
- Switching versions calls `onSelectVersion` without discarding any version.

### Edge cases
- No instruction at all: the plain retry is available but secondary and labelled "Try again (no changes)".
- Contradicting presets (Shorter and Expand): selecting one deselects the other.
- A kept part that came back changed: the parent can flag it and the version shows "Kept part was altered".
- Many versions: show the latest five tabs with a "More versions" menu.

## Must avoid
A bare regenerate button that rolls the dice and loses the parts the user already liked.

## Engineering constraint
Carry the prior output into context as the base; keep both versions addressable for comparison.

## Accessibility
- Presets and keep/drop toggles use `aria-pressed`; version tabs follow the tabs pattern.
- Announce "v2 ready" when a regeneration completes, without moving focus from the control.

## House rules
- Real `<button>`/`<input>` elements, full keyboard use, visible focus; announce status changes with `aria-live="polite"`; respect `prefers-reduced-motion`.
- All user-facing text comes from props (or a `labels` prop) so it can be translated.
- One consistent accent marks anything the AI made or is doing; amber means "needs a person", red means risky, green means done. Never rely on colour alone.
- Fits a 360 px wide container without horizontal scrolling.

## Acceptance checks
- [ ] Every state above can be rendered by passing props, with no internal fake data.
- [ ] Every interaction and edge case above behaves as described.
- [ ] Nothing in "Must avoid" can happen with this component.

## Deliver
1. The component file with its exported prop types.
2. A short usage example that renders each state.
