UNPKG

@activecollab/components

Version:

ActiveCollab Components

68 lines 3.58 kB
import { ChangeEvent, FocusEvent, KeyboardEvent } from "react"; /** * useInlineEdit — story-local click-to-edit state machine for StackedCard * (task 4/8). Presentation-only; not exported from the design-system barrel. * * A card in preview/placeholder mode enters an EDITING state on click: a * card-centered text field with confirm/cancel keyboard rules, an optional * validator, and a single-line ↔ multi-line mode switch. The hook owns only the * editing lifecycle (mode, working value, error, keyboard + outside-click); the * card chrome and the async handoff after commit (e.g. the link unfurl ladder * from task 3/8) live in the story that consumes it. * * ── The decided rules (AC task #454744) ── * Single-line Enter confirms · click-outside confirms · Esc cancels + reverts * Multi-line Enter = newline · Cmd/Ctrl+Enter saves · click-outside saves · * Esc cancels + reverts * Validator validate(value) => true | errorMessage, run before every accept * pass → commit + exit editing * fail via a key → STAY editing, surface the message (retry) * fail via outside → REVERT (acts as cancel) — user never trapped * * Keyboard is handled on the field's own keydown (never a global listener) and * every keydown stops propagation, so the card focus model (task 2/8) can't * swallow the Enter/Esc that belong to the editor. */ export type InlineEditValidator = (value: string) => true | string; export interface UseInlineEditConfig { /** Seed value for the first edit; also the revert target until first commit. */ initialValue?: string; /** Multi-line mode: Enter inserts a newline, Cmd/Ctrl+Enter saves. */ multiline?: boolean; /** Optional validator, run before every accept. `true` passes; a string fails. */ validate?: InlineEditValidator; /** Called with the committed value when an accept passes validation. */ onCommit?: (value: string) => void; } /** Props to spread onto the `<input>` or `<textarea>` while editing. */ export interface InlineEditBind { /** Callback ref — assignable to both an input and a textarea. */ ref: (el: HTMLInputElement | HTMLTextAreaElement | null) => void; value: string; onChange: (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void; onKeyDown: (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void; onBlur: (e: FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void; "aria-invalid": boolean; } export interface InlineEditController { /** Whether the field is currently shown. */ editing: boolean; /** The working value (the draft being typed). */ value: string; /** The last committed value — what a revert restores. */ committed: string; /** The current validation message, or null when valid / untouched. */ error: string | null; /** Whether this editor is in multi-line mode. */ multiline: boolean; /** Enter editing, loading the last committed value. */ begin: () => void; /** Cancel + revert to the committed value (the Esc / invalid-outside path). */ cancel: () => void; /** Force a committed value without going through the field (repeat demos). */ reset: (next?: string) => void; /** Spread onto the field element while `editing`. */ bind: InlineEditBind; } export declare const useInlineEdit: ({ initialValue, multiline, validate, onCommit, }?: UseInlineEditConfig) => InlineEditController; //# sourceMappingURL=useInlineEdit.d.ts.map