| 1 | /** |
| 2 | * How a composer submission is delivered when the thread already has a turn in |
| 3 | * flight. Shared by web (where the alternate is Mod+Enter) and mobile (where it |
| 4 | * is a long-press on the send button), so both clients agree on what the user's |
| 5 | * configured follow-up behavior means. |
| 6 | */ |
| 7 | export type ComposerDispatchMode = "auto" | "queue" | "steer" | "restart"; |
| 8 | export type ActiveTurnComposerAction = Exclude<ComposerDispatchMode, "auto">; |
| 9 | |
| 10 | /** The alternate switches between queue and steer relative to the configured action. */ |
| 11 | export function resolveComposerDispatchMode(input: { |
| 12 | /** A turn is in flight, so the follow-up has to queue behind it or steer it. */ |
| 13 | readonly running: boolean; |
| 14 | readonly alternateModifier: boolean; |
| 15 | readonly activeTurnDefault?: ActiveTurnComposerAction; |
| 16 | }): ComposerDispatchMode { |
| 17 | if (!input.running) return "auto"; |
| 18 | const defaultAction = input.activeTurnDefault ?? "steer"; |
| 19 | if (input.alternateModifier) return defaultAction === "queue" ? "steer" : "queue"; |
| 20 | return defaultAction; |
| 21 | } |
| 22 | |
| 23 | /** What the alternate would do, for labelling the affordance that triggers it. */ |
| 24 | export function alternateComposerDispatchAction( |
| 25 | activeTurnDefault?: ActiveTurnComposerAction, |
| 26 | ): ActiveTurnComposerAction { |
| 27 | return resolveComposerDispatchMode({ |
| 28 | running: true, |
| 29 | alternateModifier: true, |
| 30 | ...(activeTurnDefault === undefined ? {} : { activeTurnDefault }), |
| 31 | }) as ActiveTurnComposerAction; |
| 32 | } |