@morgs32/ink-steps
v0.0.12
Published
Ink components for step-by-step CLI flows. The public API is exported from `src/index.ts`. The sub-entry `src/MyMultiSelect/index.ts` re-exports the multi-select and its types.
Readme
ink-steps
Ink components for step-by-step CLI flows. The public API is exported from src/index.ts. The sub-entry src/MyMultiSelect/index.ts re-exports the multi-select and its types.
ProcedureStep
ProcedureStep and its helpers model a procedural step with a status-driven display. It provides a context that children read to decide what to render.
Status values (ProcedureStepStatus): error, loading, prompt, saving, success.
Exports:
ProcedureStep- wraps a step, renders a vertical guide line, and provides the status context.ProcedureStepContext/useProcedureStepContext- context + hook; the hook throws if used outside aProcedureStep.ProcedureStepPrompt- renders a yellow diamond and children when status isprompt.ProcedureStepLoading- renders a spinner (and optional message) when status isloading.ProcedureStepSuccess- renders a green diamond and children when status issuccess.ProcedureStepError- renders a red error line when status iserrorand an error is provided.ProcedureNextStep- renders children only when status issuccess(for chaining steps).useProgram/UseProgramResult- runs aneffectprogram once on mount and maps it to{ status, data, error }.
How it shows up in the ska add flow:
../ska/src/commands/add.tsxcomposes a sequence of add steps (for exampleFindSkills,GetLocks,UpdateLock). Those steps useProcedureStepto show loading/success/error while still returning render-prop children to continue the chain.../ska/src/add/FindSkills.tsxusesuseProgram+ProcedureStepto report the status of reading skills.../ska/src/add/SelectTargetLock.tsxusesProcedureStepPromptfor an interactive choice andProcedureStepSuccessonce chosen.
Example (trimmed from ../ska/src/add/FindSkills.tsx):
const { data, error, status } = useProgram({
fetcher: () => readSkillsFromCache(cachePath),
});
return (
<ProcedureStep status={status}>
<ProcedureStepError error={error} />
{data && (
<ProcedureStepSuccess>
<Text>Skills found ({data.length})</Text>
</ProcedureStepSuccess>
)}
<ProcedureStepLoading message="Reading skills..." />
<ProcedureNextStep>{data ? children(data) : null}</ProcedureNextStep>
</ProcedureStep>
);PromptStep
PromptStep models an interactive step that the user must submit. It uses a render prop to expose a submit callback and a context to coordinate the prompt/success views.
Status values (PromptStatus): inputting, submitted.
Exports:
PromptStep- wraps a step and provides{ submit }to its children.PromptStepContext/usePromptStepContext- context + hook; the hook throws if used outside aPromptStep.PromptStepPrompt- renders a yellow diamond and children while inputting.PromptStepSuccess- renders a green diamond and children once submitted.PromptNextStep- renders children only once submitted.
How it shows up in the ska add flow:
../ska/src/add/SelectSkills.tsxusesPromptStepwithMyMultiSelect. Once the user submits their selection, it callssubmit()to switch the UI into the success state and lets the next step render.
Example (trimmed from ../ska/src/add/SelectSkills.tsx):
<PromptStep>
{({ submit }) => (
<>
<PromptStepPrompt>
<MyMultiSelect
options={filteredOptions}
onSubmit={(values) => {
setSelectedValues(values);
submit();
}}
/>
</PromptStepPrompt>
<PromptStepSuccess>
<Text>{selectionSummary}</Text>
</PromptStepSuccess>
<PromptNextStep>{children(selectedSkills)}</PromptNextStep>
</>
)}
</PromptStep>Miscellaneous
MyMultiSelect
A keyboard-driven multi-select list with scrollable options and optional highlight text.
Exports:
MyMultiSelect- renders options, handles focus/selection, and callsonSubmiton Enter.MyMultiSelectProps- props for the component.MyMultiSelectStateChange-{ focusedValue, value }emitted viaonStateChange.Option-{ label, value }option shape.
Behavior notes:
- Up/Down arrows move focus, Space toggles the focused option, Tab selects all or none, Enter triggers
onSubmit. highlightTextis rendered in a different style inside matching labels.visibleOptionCountcontrols the scroll window size.
ConditionalStep / renderConditionalStep
Utility to optionally wrap children. If if is true, then(children) is returned; otherwise the children render as-is. renderConditionalStep is the same logic as a function.
Exit
Ink component that exits the app after 5 seconds (useApp().exit()). Returns null and is useful at the end of flows.
ErrorBoundary
Class-based error boundary for Ink. It logs the error and component stack to stderr and renders a user-facing error message when a child throws.
