Architecture
How Flow-UI turns a JSON page into native SwiftUI: decode through an open registry, contain failures, render widgets, and dispatch actions as data.
Flow-UI is a rendering engine, not a networking stack. The host supplies bytes. The framework decodes a page, looks up each widget in a registry the app owns, and paints native SwiftUI. Unknown types and malformed payloads are contained so one bad widget never blanks a screen.
The pipeline#
- Load.
PageStorecalls the hostPageLoaderfor a page id. The store owns fetch, refresh, pagination and in-flight cancellation. A slower response does not overwrite a newer one. - Decode.
FlowCorereads the envelope:PageModel, thenSectionModel, thenAnyWidget. Layout, actions and tracking ride alongside the payload. Decoding is handwrittenDecodablewithdecodeIfPresentdefaults. - Resolve. Each widget
typestring is looked up inWidgetRegistry. The registry is the onlyAnyViewerasure point. Registering a widget is one generic call in the host app; there is no framework enum to extend. - Render.
FlowPageViewdraws nav, sticky header and footer bars, sections (vertical, carousel, grid), sheets and toasts. Chrome fromWidgetLayoutis applied in one fixed order: padding, background or gradient, corner clip, border, margin. - Act. Taps carry
ActionData.ActionDispatcheris a chain of responsibility. Built-ins cover toast, dismiss, refresh, bottom sheet and api mutations. Deeplinks are host handlers.
What the engine does not own#
Flow-UI ships no HTTP client, no image library and no design system. PageLoader and FlowImageLoader are host types. ThemeProvider maps tokens the backend already uses. That is why the package plugs into an existing app instead of replacing it.
Resilience is the default#
LossyArray keeps a section alive when one child fails. DecodeDiagnostics records the type and key path. Debug builds show a labelled placeholder; release builds skip the widget. Stable ids are derived from the coding path so a refresh diffs instead of rebuilding.