Establishes citation-work as the standalone home of the review workspace, migrated out of the citation-evidence umbrella app. - Package/tooling scaffold: package.json, tsconfig, vite/vitest/eslint configs with eslint-plugin-boundaries enforcing engine/anchor/source-only imports - Providers/hooks: EngineProvider, SessionProvider + use* hooks (T02) - Panes: CollectionList, ViewerShell, EvidenceSidebar (T03/T04/T05) - Capture/edit: InlineCaptureForm, EvidenceFormBody; UploadDropzone owned here - ReviewShell: repo-owned three-pane layout with an upload slot seam - Tests: CollectionList, InlineCaptureForm capture flow, EvidenceSidebar export/edit/activation (11 tests, all green) - Anchor consumed as @citation-evidence/evidence-anchor package; @source kept on the umbrella facade for its local viewer-url policy - Docs (README/SCOPE) refreshed; deferred gaps recorded Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
/**
|
|
* EvidenceFormBody — the shared "citation + commentary" editor.
|
|
*
|
|
* One form drives both:
|
|
* - the *capture* flow (creating evidence from a fresh selection
|
|
* inside `InlineCaptureForm`), and
|
|
* - the *edit* flow (modifying an existing evidence card inside
|
|
* `EvidenceSidebar`).
|
|
*
|
|
* Keeping a single component means changes to the field layout, hint
|
|
* placement, or save-button copy land in one file and apply to both
|
|
* surfaces. Callers control the labels and any badge/helper text.
|
|
*/
|
|
|
|
import type { CSSProperties, ReactNode } from "react";
|
|
|
|
export interface EvidenceFormBodyProps {
|
|
readonly quote: string;
|
|
readonly commentary: string;
|
|
onChangeQuote(next: string): void;
|
|
onChangeCommentary(next: string): void;
|
|
onSave(): void;
|
|
onCancel(): void;
|
|
/** Save-button label, defaults to "Save". */
|
|
readonly saveLabel?: string;
|
|
/** Cancel-button label, defaults to "Cancel". */
|
|
readonly cancelLabel?: string;
|
|
/** Short caption rendered at the top of the form, e.g. a selector
|
|
* count badge or "Editing". */
|
|
readonly badge?: ReactNode;
|
|
/** Inline note shown under the buttons (e.g. "won't move the
|
|
* marked passage" when editing an existing item). */
|
|
readonly helper?: ReactNode;
|
|
/** data-testid prefix for the input + button hooks. */
|
|
readonly testidPrefix: string;
|
|
}
|
|
|
|
export function EvidenceFormBody(p: EvidenceFormBodyProps) {
|
|
const saveLabel = p.saveLabel ?? "Save";
|
|
const cancelLabel = p.cancelLabel ?? "Cancel";
|
|
return (
|
|
<div style={{ padding: 8, fontSize: 12 }}>
|
|
{p.badge && (
|
|
<div style={{ marginBottom: 6, fontWeight: 600 }}>{p.badge}</div>
|
|
)}
|
|
<label style={labelStyle}>Citation text</label>
|
|
<textarea
|
|
value={p.quote}
|
|
onChange={(e) => p.onChangeQuote(e.target.value)}
|
|
data-testid={`${p.testidPrefix}-quote`}
|
|
rows={3}
|
|
style={{
|
|
...textareaStyle,
|
|
fontStyle: "italic",
|
|
}}
|
|
/>
|
|
<label style={labelStyle}>Commentary</label>
|
|
<textarea
|
|
value={p.commentary}
|
|
onChange={(e) => p.onChangeCommentary(e.target.value)}
|
|
data-testid={`${p.testidPrefix}-commentary`}
|
|
rows={2}
|
|
placeholder="(optional)"
|
|
style={textareaStyle}
|
|
/>
|
|
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
|
|
<button
|
|
type="button"
|
|
onClick={p.onSave}
|
|
data-testid={`${p.testidPrefix}-save`}
|
|
style={{ fontSize: 12, padding: "4px 10px" }}
|
|
>
|
|
{saveLabel}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={p.onCancel}
|
|
data-testid={`${p.testidPrefix}-cancel`}
|
|
style={{ fontSize: 12, padding: "4px 10px" }}
|
|
>
|
|
{cancelLabel}
|
|
</button>
|
|
{p.helper && (
|
|
<span style={{ fontSize: 11, color: "#888" }}>{p.helper}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const labelStyle: CSSProperties = {
|
|
display: "block",
|
|
color: "#666",
|
|
fontSize: 11,
|
|
marginBottom: 2,
|
|
};
|
|
|
|
const textareaStyle: CSSProperties = {
|
|
width: "100%",
|
|
boxSizing: "border-box",
|
|
fontSize: 12,
|
|
padding: 4,
|
|
marginBottom: 6,
|
|
};
|