You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The rules, compressed: declarations are aspirational (each surface renders what it understands, the rest is inert — never an error); item properties are inherited within a page, never across resolution (a handle's block styles the handle); container properties resolve by scope override (page declares for its scope, a section overrides for its own children); display is positional; style is presentation-only — no style property affects queue scope, playback, or navigation; degradation drops decorations before layout.
Breaking
String styles, 'rail', and Track.childrenStyle are deleted — no string shorthand, no dialect normalization. Nothing has shipped, so there is no migration; the wire is flat nested structs.
Checklist (design doc §7)
Spec: TrackStyle / SectionStyle extends TrackStyle as Nitro structs (named exported unions — inline string unions don't codegen); ResolvedTrack.style widens to SectionStyle; codegen + web-stub mirrors. Ship with the flip: display, gridWrap; other properties land with their features (no dead fields).
Resolution: one resolver per platform — item properties track ?? section ?? page ?? default; container properties section ?? page ?? default; display on an explicit positional deny-list.
Spec-level tests: inheritance-completeness (every TrackStyle key read by every resolver, in precedence order; positional keys provably excluded — Nitro erases extends, so types can't enforce it).
Dev-mode inert-declaration diagnostic (warn when a declaration can never render — gridWrap on a list section, cardTint with no card treatment): InertStyleDiagnostic on both platforms, called from each resolveUncached — structural inertness only, judged per declaring level; the narrower promise-less all-grid page warning (Android) stays as its own check.
iOS: section presentation keys off display + gridWrap (+ gridTile when it lands); pre-26 degradation — treatment drops, layout survives (gridWrap: false → legacy image row; wrapping grid → list).
Android: tile detection from resolved display; delete childrenStyle and re-source the parent-level content-style hint from the browsable handle's declared display (the page-layout promise: declared or it doesn't exist, plus a targeted dev warning when a served grid page sits under a promise-less parent). Per-item hints derive from the section resolution.
Tolerant decoding in both native decoders (decode-to-nil on mismatch — a stale payload must never kill a page or persisted playback state); persisted queues keep style and disabled.
Summary
Presentation stops accreting as flat fields in two competing shapes — core style strings (
Section.style: 'list' | 'grid' | 'rail',Track.style/Track.childrenStyle) and platform-prefixed hints (carPlay*) — and becomes one CSS-adjacent declaration block:Full specification:
docs/section-styling-design.html(schema with JSDocs, resolution rules, property ledger, rendering matrix, rejected-shapes log). Decision record: ADR 0011. SDK evidence:docs/carplay-sdk-audit.html.The rules, compressed: declarations are aspirational (each surface renders what it understands, the rest is inert — never an error); item properties are inherited within a page, never across resolution (a handle's block styles the handle); container properties resolve by scope override (page declares for its scope, a section overrides for its own children);
displayis positional; style is presentation-only — no style property affects queue scope, playback, or navigation; degradation drops decorations before layout.Breaking
String styles,
'rail', andTrack.childrenStyleare deleted — no string shorthand, no dialect normalization. Nothing has shipped, so there is no migration; the wire is flat nested structs.Checklist (design doc §7)
TrackStyle/SectionStyle extends TrackStyleas Nitro structs (named exported unions — inline string unions don't codegen);ResolvedTrack.stylewidens toSectionStyle; codegen + web-stub mirrors. Ship with the flip:display,gridWrap; other properties land with their features (no dead fields).track ?? section ?? page ?? default; container propertiessection ?? page ?? default;displayon an explicit positional deny-list.TrackStylekey read by every resolver, in precedence order; positional keys provably excluded — Nitro erasesextends, so types can't enforce it).gridWrapon a list section,cardTintwith no card treatment):InertStyleDiagnosticon both platforms, called from eachresolveUncached— structural inertness only, judged per declaring level; the narrower promise-less all-grid page warning (Android) stays as its own check.display+gridWrap(+gridTilewhen it lands); pre-26 degradation — treatment drops, layout survives (gridWrap: false→ legacy image row; wrapping grid → list).display; deletechildrenStyleand re-source the parent-level content-style hint from the browsable handle's declareddisplay(the page-layout promise: declared or it doesn't exist, plus a targeted dev warning when a served grid page sits under a promise-less parent). Per-item hints derive from the section resolution.styleanddisabled.Track.disabledcontent fact (see Track.disabled — unavailable items (grayed where drawable, hidden elsewhere) #126): never plays anywhere; grayed where the surface can draw it, hidden where it can't.ResolvedTrack → Trackprojection drops container properties explicitly.gridWrap: falseas a horizontal scroller (intended usage).Follow-ups that land with their features (not this issue)
style.accessorySymbolstyle.imageShapegridTile: 'card' | 'condensed',cardTint,cardImage— designed in the audit/design doc; no issues until their features land (no dead fields).