Skip to content
Merged
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,29 @@ API surface).

### Added

- **`morph::ui`: the view tree, its mount and the frontend seam.** Header-only, in the base `morph`
target.
- An immutable view tree of the UI document's base palette (`view.hpp`): every property a constant
or a slot, a reactive value with an optional stable id (`ui::slot`), and every event a command
sink; keyed `forEach` and `table` over any row type.
- The backend contract (`backend.hpp`): one widget interface per kind and an `IViewBackend` with a
typed factory each. No setter calls a handler, a setter with the value a widget shows changes
nothing, and a widget the user cannot reach takes no input.
- `Mounted` (`mount.hpp`) builds a tree's widgets once and keeps them current through
equality-gated bindings. Switch cases, Tabs pages, Dialog content and ForEach/Table rows mount
all or nothing into child scopes, torn down child-first, with owners' bindings running first;
rows keep their identity per key and reorder with the fewest moves. Input widgets are
controlled by their slots: a refused edit snaps back, an accepted one costs no setter call.
- The frontend seam (`frontend.hpp`): `AppContext`, `AppSource` (`open`, `switchBackend`,
`close`), `Bundle`, `ConnectError`, `Backend`, `Frontend`, and `selectFrontend`, which picks a
frontend from `--ui`, `MORPH_UI` or the first usable one and returns a `FrontendError` naming the
built ones; `runApp` fixes the order a frontend opens a source, mounts its shell and tears both
down.
- `testing::RecordingBackend`, a headless reference backend with an operation log, a golden dump
and user-interaction helpers, and the conformance cases every renderer runs through its own
`ConformanceProbe`.

See `docs/spec/ui/view_tree.md`, `backend_contract.md` and `frontend.md`.
- **Model-free dispatch.** `RawHandler` binds a model by its registered type
id and dispatches actions by id with a JSON body, for a client compiled
without the model's type. Calls carry the default session, the execute
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ target_sources(morph
include/morph/reactive/scheduler.hpp
include/morph/reactive/testing/manual_scheduler.hpp
include/morph/reactive/control.hpp
include/morph/ui/view.hpp
include/morph/ui/backend.hpp
include/morph/ui/mount.hpp
include/morph/ui/frontend.hpp
include/morph/ui/testing/recording_backend.hpp
include/morph/ui/testing/backend_conformance.hpp
include/morph/render/i18n.hpp
include/morph/render/locale_format.hpp
include/morph/core/file_io_ops.hpp
Expand Down
12 changes: 12 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ The public surface is split per topic so callers always know whether a name is p
| `morph::time` | UTC timestamps for actions | `DateTime`, `Timestamp` |
| `morph::forms` | JSON-Schema generation for auto-built GUIs | `schemaJson<A>()`, `allRequiredEngaged()`, `Choice<T, ...>`, `FixedString`, `isChoice`, `EmptyCapableField` |
| `morph::reactive` | Signal graph, view state and declarative control (see `docs/spec/reactive/`) | `Runtime`, `RuntimeOptions`, `Signal<T>`, `Computed<T>`, `Effect`, `Scope`, `EqualityPolicy`, `kEqualityUsable`, `Store<ViewState, Msg>`, `ExhaustiveUpdate`, `request()`, `Query<A, R>`, `QueryOptions`, `InvalidationLink`, `Mutation<A, R>`, `MutationOptions<A>`, `Concurrency`, `Subscription<R>`, `Refetchable`, `errorMessage`, `Scheduler`, `TimerHandle`; `testing::ManualScheduler` |
| `morph::ui` | View tree, mount and the frontend seam (see `docs/spec/ui/`) | `Node`, `Prop<T>`, `SlotId`, `slot()`, `Key`, the node kinds and their builders, `forEach`, `table`, `switchOn`; `Widget`, `ContainerWidget`, the widget interfaces, `IViewBackend`; `Mounted`; `AppContext`, `AppSource`, `Bundle`, `ConnectError`, `Backend`, `Frontend`, `FrontendOption`, `FrontendError`, `EnvironmentReader`, `processEnvironment`, `selectFrontend`, `MountedShell`, `ShellFactory`, `runApp`; `testing::RecordingBackend`, `testing::ConformanceProbe`, `testing::conformanceCases` |
| `morph::testing` | The installed owner test kit | `StepExecutor`, `OwnerProbeRecorder` |
| `morph::qt` | Qt integration (built only when `MORPH_BUILD_QT=ON`) | `QtExecutor`, `QtWebSocketBackend`, `QtWebSocketServer` |

Expand Down Expand Up @@ -707,6 +708,17 @@ folder.
| `reactive/testing/manual_scheduler.hpp` | `testing::ManualScheduler` — a `Scheduler` whose clock moves only when a test advances it |
| `reactive/detail/graph.hpp` | `RuntimeCore`, `Node`, `TrackingFrame`, `Colour`, `FlushBounds`, the misuse site names, `kDefaultMaxEffectRunsPerFlush`, `kDefaultMaxThrowReposts` (`morph::reactive::detail::`) |

#### `ui/` — view tree, mount, frontend seam

| Header | Responsibility |
|---|---|
| `ui/view.hpp` | `Node`, `NodeData`, `Prop<T>`, `SlotId`, `SlotBinding`, `slot()`, `Key`, `Common`, `Sizing`, `LayoutHints`, every node kind and its builder, `switchOn`, `forEach`, `table` (`morph::ui::`) — the immutable view tree whose properties are constants or slots. See `docs/spec/ui/view_tree.md`. |
| `ui/backend.hpp` | `Widget`, `ContainerWidget`, one widget interface per kind, `IViewBackend` — the retained widgets a renderer implements. See `docs/spec/ui/backend_contract.md`. |
| `ui/mount.hpp` | `Mounted` — builds a tree's widgets once, keeps them current through bindings, mounts content in child scopes, keeps keyed rows, controls inputs by their slots |
| `ui/frontend.hpp` | `AppContext`, `AppSource`, `Bundle`, `ConnectError`, `Backend`, `Frontend`, `FrontendOption`, `FrontendError`, `selectFrontend`, `MountedShell`, `ShellFactory`, `runApp` — the seam `main` picks a frontend through. See `docs/spec/ui/frontend.md`. |
| `ui/testing/recording_backend.hpp` | `testing::RecordingBackend` — the headless reference backend: operation log, golden dump, interaction helpers |
| `ui/testing/backend_conformance.hpp` | `testing::ConformanceProbe`, `testing::ConformanceCase`, `testing::conformanceCases()` — the scripted cases every backend passes |

#### `testing/` — the installed owner test kit

| Header | Responsibility |
Expand Down
7 changes: 7 additions & 0 deletions docs/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ server
[`reactive/control.md`](reactive/control.md) — signals, view state, and server
interaction a controller declares instead of sequencing

**Declarative UI**
[`ui/view_tree.md`](ui/view_tree.md) ·
[`ui/backend_contract.md`](ui/backend_contract.md) ·
[`ui/frontend.md`](ui/frontend.md) — the view tree a screen mounts into,
the widgets every renderer implements, and the seam that picks a renderer
at runtime

**Exact values on the wire**
[`util/rational.md`](util/rational.md) ·
[`util/quantity_type.md`](util/quantity_type.md) ·
Expand Down
Loading
Loading