(options: SelectOptions<A> & MultiSelectOptions)
| 252 | } |
| 253 | |
| 254 | function handleProcess<A>(options: SelectOptions<A> & MultiSelectOptions) { |
| 255 | return (input: Terminal.UserInput, state: State) => { |
| 256 | const totalChoices = options.choices.length + metaOptionsCount |
| 257 | switch (input.key.name) { |
| 258 | case "k": |
| 259 | case "up": { |
| 260 | return processCursorUp({ ...state, error: Option.none() }, totalChoices) |
| 261 | } |
| 262 | case "j": |
| 263 | case "down": |
| 264 | case "tab": { |
| 265 | return processCursorDown({ ...state, error: Option.none() }, totalChoices) |
| 266 | } |
| 267 | case "space": { |
| 268 | return processSpace(state, options) |
| 269 | } |
| 270 | case "enter": |
| 271 | case "return": { |
| 272 | const selectedCount = state.selectedIndices.size |
| 273 | if (options.min !== undefined && selectedCount < options.min) { |
| 274 | return Effect.succeed( |
| 275 | Action.NextFrame({ state: { ...state, error: Option.some(`At least ${options.min} are required`) } }) |
| 276 | ) |
| 277 | } |
| 278 | if (options.max !== undefined && selectedCount > options.max) { |
| 279 | return Effect.succeed( |
| 280 | Action.NextFrame({ state: { ...state, error: Option.some(`At most ${options.max} choices are allowed`) } }) |
| 281 | ) |
| 282 | } |
| 283 | const selectedValues = Array.from(state.selectedIndices).sort(Number.Order).map((index) => |
| 284 | options.choices[index].value |
| 285 | ) |
| 286 | return Effect.succeed(Action.Submit({ value: selectedValues })) |
| 287 | } |
| 288 | default: { |
| 289 | return Effect.succeed(Action.Beep()) |
| 290 | } |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | function handleRender<A>(options: SelectOptions<A>) { |
| 296 | return (state: State, action: Prompt.Prompt.Action<State, Array<A>>) => { |
no test coverage detected