Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
144
planned
1,365
shipped

Motir · Roadmap

MOTIR-3947Done

Scoped design previews are not ISOLATED — 69 `[data-style='X'] <descendant>` material rules cross the nesting boundary, so 10 of 11 style previews wear the ancestor's style

Opened by Zhu Yue ·

Carved out of MOTIR-3933 by the re-plan its own run submitted. That card frames the style half as a base-entry token leak with a one-block remedy; measured, it is an isolation problem across 69 rules and it needs a mechanism DECIDED before any of them is touched.

The measurement

packages/design-system/theme.css carries 69 descendant rules of the form [data-style='X'] [data-surface='…'] (and [data-style='X'] body, [data-style='X'] .border, …). A descendant combinator does not stop at a nested data-style, so every one of them matches inside a scoped StyleVignette.

Rendered in headless chromium — eleven <div data-style="ID"><div data-surface="card"> tiles under one <html data-style="ACTIVE">, each compared against what that same style renders when it is the ACTIVE one:

<html> data-styletiles wearing their OWN material
warm-editorial (the base — no block, so nothing to leak)11 / 11
aurora3 / 11
glassmorphism1 / 11

Under glassmorphism, a tile labelled Neo-Brutalism computes backdrop-filter: blur(18px) saturate(1.8) and a translucent fill. The tokens are right and the rendering is the ancestor's.

This is why a base token block is the wrong remedy. It would make MOTIR-3933's criterion 3 pass — the resolved --radius-card would be correct — on a tile that still paints as glass. The assertion would be green over a wrong page, which is the failure mode the whole card exists to close.

The decision to make

StyleVignette's own header already names it, as an unowned follow-up: "Full nested-base isolation (a reset block or an iframe) is a noted follow-up if a future consumer needs it." That future consumer arrived (motir.co/design, and the onboarding Style gallery has the same shape). The candidates, to be weighed against the 69 rules rather than in the abstract:

  1. Scope every material rule so it cannot cross a boundary — e.g. [data-style='X'] :not([data-style]) [data-surface='…'], or a :where()-based barrier. Cheap per rule, 69 of them, and it changes the meaning of every existing selector.
  2. Render each scoped preview in an isolated tree — an iframe or a shadow root carrying its own copy of the token layer. One change, no selector churn, but it costs a document per tile and changes how the component is consumed.
  3. Emit the material rules from a scope-anchored selector rather than a descendant one, so scoping is structural instead of a per-rule opt-out.

Acceptance criteria

  • An ADR under motir-core/docs/decisions/ naming the chosen mechanism, the two it rejected, and the measured table above as the evidence. It states explicitly what a nested preview is and is not isolated from, so the next reader does not re-derive it.
  • The ADR is checked against BOTH known consumers — the onboarding Style gallery and TokensSpecimen's galleries — and says what each has to change.
  • The build cards are AUTHORED in this pass, not deferred to prose: one per unit of work the chosen mechanism implies, each sized, each blocked_by this card. A sentence saying "the implementation is a later card" with no key is what this criterion exists to forbid.
  • No behaviour change ships from this card. It decides and it plans; the selectors are touched by the cards it authors.

Boundary

Does not touch the PALETTE or TYPE axes — those are MOTIR-3933, which is bounded, measured, and independently shippable. Does not touch motir-marketing. Does not publish the package.

Discussion

No comments yet.

Adding to this discussion signs you in on app.motir.co and brings you back to this request.

Add a comment