summaryrefslogtreecommitdiffhomepage
path: root/src/features/surface-host/logic/plan.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/surface-host/logic/plan.ts')
-rw-r--r--src/features/surface-host/logic/plan.ts210
1 files changed, 105 insertions, 105 deletions
diff --git a/src/features/surface-host/logic/plan.ts b/src/features/surface-host/logic/plan.ts
index 89088c3..c8f82b9 100644
--- a/src/features/surface-host/logic/plan.ts
+++ b/src/features/surface-host/logic/plan.ts
@@ -1,20 +1,20 @@
import type { InvokeMessage, SurfaceSpec } from "@dispatch/ui-contract";
import type {
- FieldView,
- NumberFieldView,
- RenderGroup,
- StatFieldView,
- SurfaceRenderPlan,
+ FieldView,
+ NumberFieldView,
+ RenderGroup,
+ StatFieldView,
+ SurfaceRenderPlan,
} from "./types";
const KNOWN_KINDS = new Set([
- "toggle",
- "progress",
- "selector",
- "stat",
- "number",
- "button",
- "custom",
+ "toggle",
+ "progress",
+ "selector",
+ "stat",
+ "number",
+ "button",
+ "custom",
]);
/**
@@ -25,73 +25,73 @@ const KNOWN_KINDS = new Set([
* decision (unknown `rendererId` → skipped there), not a planning one.
*/
export function planSurface(spec: SurfaceSpec): SurfaceRenderPlan {
- const fields: FieldView[] = [];
- for (const field of spec.fields) {
- if (!KNOWN_KINDS.has(field.kind)) continue;
- switch (field.kind) {
- case "toggle":
- fields.push({
- kind: "toggle",
- label: field.label,
- value: field.value,
- action: field.action,
- });
- break;
- case "progress":
- fields.push({
- kind: "progress",
- label: field.label,
- value: field.value,
- });
- break;
- case "selector":
- fields.push({
- kind: "selector",
- label: field.label,
- value: field.value,
- options: field.options,
- action: field.action,
- });
- break;
- case "stat":
- fields.push({
- kind: "stat",
- label: field.label,
- value: field.value,
- });
- break;
- case "number": {
- // Carry optional hints only when present (exactOptionalPropertyTypes).
- const view: NumberFieldView = {
- kind: "number",
- label: field.label,
- value: field.value,
- action: field.action,
- ...(field.min !== undefined ? { min: field.min } : {}),
- ...(field.max !== undefined ? { max: field.max } : {}),
- ...(field.step !== undefined ? { step: field.step } : {}),
- ...(field.unit !== undefined ? { unit: field.unit } : {}),
- };
- fields.push(view);
- break;
- }
- case "button":
- fields.push({
- kind: "button",
- label: field.label,
- action: field.action,
- });
- break;
- case "custom":
- fields.push({
- kind: "custom",
- rendererId: field.rendererId,
- payload: field.payload,
- });
- break;
- }
- }
- return { fields };
+ const fields: FieldView[] = [];
+ for (const field of spec.fields) {
+ if (!KNOWN_KINDS.has(field.kind)) continue;
+ switch (field.kind) {
+ case "toggle":
+ fields.push({
+ kind: "toggle",
+ label: field.label,
+ value: field.value,
+ action: field.action,
+ });
+ break;
+ case "progress":
+ fields.push({
+ kind: "progress",
+ label: field.label,
+ value: field.value,
+ });
+ break;
+ case "selector":
+ fields.push({
+ kind: "selector",
+ label: field.label,
+ value: field.value,
+ options: field.options,
+ action: field.action,
+ });
+ break;
+ case "stat":
+ fields.push({
+ kind: "stat",
+ label: field.label,
+ value: field.value,
+ });
+ break;
+ case "number": {
+ // Carry optional hints only when present (exactOptionalPropertyTypes).
+ const view: NumberFieldView = {
+ kind: "number",
+ label: field.label,
+ value: field.value,
+ action: field.action,
+ ...(field.min !== undefined ? { min: field.min } : {}),
+ ...(field.max !== undefined ? { max: field.max } : {}),
+ ...(field.step !== undefined ? { step: field.step } : {}),
+ ...(field.unit !== undefined ? { unit: field.unit } : {}),
+ };
+ fields.push(view);
+ break;
+ }
+ case "button":
+ fields.push({
+ kind: "button",
+ label: field.label,
+ action: field.action,
+ });
+ break;
+ case "custom":
+ fields.push({
+ kind: "custom",
+ rendererId: field.rendererId,
+ payload: field.payload,
+ });
+ break;
+ }
+ }
+ return { fields };
}
/**
@@ -100,24 +100,24 @@ export function planSurface(spec: SurfaceSpec): SurfaceRenderPlan {
* other field stays a standalone `field` group. Order is preserved. Pure.
*/
export function groupRenderFields(fields: readonly FieldView[]): RenderGroup[] {
- const groups: RenderGroup[] = [];
- let run: StatFieldView[] = [];
- const flush = (): void => {
- if (run.length > 0) {
- groups.push({ type: "stats", stats: run });
- run = [];
- }
- };
- for (const field of fields) {
- if (field.kind === "stat") {
- run.push(field);
- } else {
- flush();
- groups.push({ type: "field", field });
- }
- }
- flush();
- return groups;
+ const groups: RenderGroup[] = [];
+ let run: StatFieldView[] = [];
+ const flush = (): void => {
+ if (run.length > 0) {
+ groups.push({ type: "stats", stats: run });
+ run = [];
+ }
+ };
+ for (const field of fields) {
+ if (field.kind === "stat") {
+ run.push(field);
+ } else {
+ flush();
+ groups.push({ type: "field", field });
+ }
+ }
+ flush();
+ return groups;
}
/**
@@ -126,13 +126,13 @@ export function groupRenderFields(fields: readonly FieldView[]): RenderGroup[] {
* for button the payload is omitted.
*/
export function buildInvoke(
- surfaceId: string,
- field: Extract<FieldView, { action: unknown }>,
- value?: unknown,
+ surfaceId: string,
+ field: Extract<FieldView, { action: unknown }>,
+ value?: unknown,
): InvokeMessage {
- const base = { type: "invoke" as const, surfaceId, actionId: field.action.actionId };
- if (value !== undefined) {
- return { ...base, payload: value };
- }
- return base;
+ const base = { type: "invoke" as const, surfaceId, actionId: field.action.actionId };
+ if (value !== undefined) {
+ return { ...base, payload: value };
+ }
+ return base;
}