Compatibility
MacroDeck.Ui, MacroDeck.Ui.Model, and MacroDeck.Ui.Testing are public NuGet contracts. Existing
keys, component meanings, patch semantics, and public API members must follow the normal
compatibility policy.
Why the floor is 3 and the ceiling is 4
Section titled “Why the floor is 3 and the ceiling is 4”The UI model’s Minimum is 3 and its Current is 4, and the gap between them is the difference between
a rename and a widening.
The floor moved to 3 because the component vocabulary was renamed outright rather than extended: every
widget.* node type became either ui.* or macrodeck.*, with no alias kept for the old spelling. A
tree built against the old vocabulary is not representable under the new one, so a package that no longer
understands a single widget.* type must not advertise the majors in which those were the only spelling.
The ceiling moved to 4 because an icon property may now carry a typed {"type":…,"reference":…}
provider reference where it previously always carried a bare icon-pack reference string - the same shape
as the move to 2, where a text property gained the option of carrying a localization reference. A producer
built against 3 emits only the string form and one built against 4 may emit either, so the two are not
interchangeable and the version has to say which a session speaks. The floor stayed where it was because
nothing was renamed: a reader at 4 accepts both readings, so it still reads every tree a producer at 3
emits, and UiIconInput is unchanged.
Either way a client and a provider negotiate the model version as they always have - before a session is opened - and a mismatch produces the same graceful decline, never a tree the reader cannot parse.
Additions that moved no version
Section titled “Additions that moved no version”New component types and new properties are additive and leave the model version alone; the component profile’s rule decides which of the two a new feature is. Modifiers add both:
| Addition | Shape | An older reader |
|---|---|---|
modifiers (background, radius, border, accessibility text, disabled) |
A property on any node | Ignores it and draws the node plainer. A disabled subtree still offers none of its own events, because the DSL stopped it declaring them, but the reader does not know the region absorbs the tile’s press, so a deck tile’s own flows still run there. |
drag, drag-end, swipe, pinch, pinch-end |
Event names | Never sends a name it does not implement. |
ui.modifier (padding, opacity, clip, mask, frame), component version 1 |
A type | Draws the node’s explicit fallback; without one, none of the wrapped content (Macro Deck’s renderer shows a faint placeholder box). No fallback is invented for you. |
See ADR 0064
for why the vocabulary is organized as a registry over the ui.*/macrodeck.* namespaces rather than one
flat list, and The UI model for where negotiation
sits in a session’s lifecycle.