Skip to content

fix(core): support media queries and nested selectors inside templates - #163

Open
richard-grosjean wants to merge 1 commit into
margarita-form:mainfrom
richard-grosjean:fix/template-media-queries
Open

fix(core): support media queries and nested selectors inside templates#163
richard-grosjean wants to merge 1 commit into
margarita-form:mainfrom
richard-grosjean:fix/template-media-queries

Conversation

@richard-grosjean

Copy link
Copy Markdown
Collaborator

Problem

Media queries (and nested selectors / pseudos) declared inside a defineTemplates node never work. Given:

defineTemplates({
  textStyle: {
    heading: {
      large: {
        fontSize: '110px',
        '@largeMobileDown': { fontSize: '60px' },
      },
    },
  },
});

the generated _templates.css contains:

.text-style-heading-large-@large-mobile-down, .t_wIUD { font-size: 60px; }

— no @media wrapper, and the bogus class is never composed onto any element, so the responsive override is silently dead.

Root cause

parseTemplates (libs/core/src/parsers/parse-templates.ts) re-implements template→CSS rendering and diverges from the normal style parser in two ways:

  1. It treats every object-valued key as a nested template path segment. A media query like '@largeMobileDown': { … } is an object, so it gets recursed as a path and dash-cased into the class name, with no @media wrapping. getTemplateClasses() only walks the declared path (heading.large), so that class is never applied either.
  2. It never forwards the config to parseAndJoinStyles. So even when a query lives in a rich node's base (where the object is passed to the parser), the named query isn't resolved — it's emitted as a literal @largeMobileDown { … } instead of @media (max-width: 960px).

By contrast, normal component styles go through parseStyles with the config, which handles @media/named queries/modifiers correctly.

Fix

  • Add isStyleKey — keys starting with @, & or : are CSS constructs for the current node, not template paths. Route them to the style parser instead of recursing:
    • in non-rich leaves (collected into the rendered style object),
    • in rich nodes (node-level constructs render with base),
    • and in isChildEntry / the token & variant-map walkers, so they no longer leak into generated template token types.
  • Forward the resolved config from SaltyCompiler.generateCss through parseTemplates into parseAndJoinStyles, with omitTemplates enabled (template definitions are literal styles and shouldn't recursively expand other templates). Named media queries, modifiers and tokens now resolve in templates exactly as in component styles.

Tests

Added three cases to parse-templates.spec.ts:

  • media query in a leaf → wrapped in @media, kept on the leaf class, not leaked into the class name;
  • named media query → resolved via the forwarded config;
  • media query in a rich node base → wrapped correctly.

nx run core:test (vitest, libs/core/src): 23 files / 449 tests pass (4 existing template tests + 3 new). Typecheck of libs/core is clean.

No behavior change for templates without @/&/: keys.

`parseTemplates` re-implements template→CSS rendering and diverged from the
normal style parser in two ways, so media queries inside a `defineTemplates`
node never worked:

1. It treated *every* object-valued key as a nested template path segment. A
   media query such as `'@largeMobileDown': { … }` in a leaf was therefore
   dash-cased into the class name (`.text-style-…-large-@large-mobile-down`)
   with no `@media` wrapper, and was never composed onto any element.
2. It never forwarded the config to `parseAndJoinStyles`, so even a media query
   inside a rich node's `base` was emitted with its *named* query unresolved
   (literal `@largeMobileDown { … }` instead of `@media (max-width: 960px)`).

Fix:
- Add `isStyleKey` (keys starting with `@`, `&` or `:`) and route those objects
  to the style parser instead of recursing them as template paths — in leaves,
  in rich-node bodies, and in the token/variant-map walkers (so they no longer
  leak into generated template token types).
- Forward the resolved config from `SaltyCompiler` through `parseTemplates` to
  `parseAndJoinStyles`, with template-token expansion disabled, so named media
  queries / modifiers / tokens resolve in templates exactly as in component
  styles.

Adds tests covering a media query in a leaf, named-query resolution via config,
and a media query in a rich node base.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@richard-grosjean

richard-grosjean commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

Just noticed that I could just have used the base/'at-mediaQuery' setup instead of relying on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant