@symbiote-native/css-parser 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -19,7 +19,8 @@ CSS Modules all work identically regardless of source language.
|
|
|
19
19
|
Not installed directly by an app — every adapter package (`@symbiote-native/react`,
|
|
20
20
|
`@symbiote-native/vue`, `@symbiote-native/svelte`, `@symbiote-native/solid`,
|
|
21
21
|
`@symbiote-native/angular`) already depends on it and re-exports it via its own
|
|
22
|
-
`./metro-css-parser` subpath
|
|
22
|
+
`./metro-css-parser` subpath, so any app scaffolded by `npx @symbiote-native/cli new` already has
|
|
23
|
+
it wired, no separate flag needed. Writing a Metro transformer for a new adapter yourself:
|
|
23
24
|
|
|
24
25
|
```bash
|
|
25
26
|
npm install @symbiote-native/css-parser
|
|
@@ -52,7 +53,7 @@ import './theme.css'; // plain CSS — registers classes globally, no export
|
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
```tsx
|
|
55
|
-
<
|
|
56
|
+
<view className="card" style={styles.highlight} /> // React
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
```html
|
|
@@ -135,6 +136,10 @@ import {
|
|
|
135
136
|
- It does not implement Tailwind CSS — that needs whole-project class scanning and JIT utility
|
|
136
137
|
generation, a fundamentally different shape than "one source file reduces to CSS text", and is
|
|
137
138
|
being designed as a separate, future package.
|
|
139
|
+
- It drops a `:active`/`:hover`/`:focus` rule the same as any other pseudo-class — there is no
|
|
140
|
+
CSS-class route to a pressed look. `Pressable`'s functional `style={({ pressed }) => ...}` prop
|
|
141
|
+
is the supported way to style a pressed state; the engine resolves it into a separate style slot
|
|
142
|
+
outside this pipeline.
|
|
138
143
|
- It supports `scoped` / `:global()` / CSS Modules and SCSS/Sass/Less/Stylus preprocessing —
|
|
139
144
|
including Svelte's own `<style>` block (its preprocessor calls this package's
|
|
140
145
|
`compileScopedCss`, the same compile every Vue `<style scoped>` block goes through) — and it does
|
|
@@ -756,13 +756,9 @@ function declarationToStyleAt(declaration, context, depth) {
|
|
|
756
756
|
}
|
|
757
757
|
case 'text-shadow':
|
|
758
758
|
return textShadowToStyle(value, context);
|
|
759
|
-
// A CSS-Modules DIRECTIVE, not a style property
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
// first-class `property: 'composes'`, NOT under `custom` where an unknown name goes, so it fell
|
|
763
|
-
// through to the PROPERTY_TABLE miss and every author of a WORKING `.module.*` file was told
|
|
764
|
-
// "unsupported CSS property" on every build. The drop warnings are the only signal that a real
|
|
765
|
-
// rule died; a channel that cries wolf on working code is the one nobody reads when it matters.
|
|
759
|
+
// A CSS-Modules DIRECTIVE, not a style property: the composed names come back through
|
|
760
|
+
// `exports[...].composes`, which `metro-css-module/index.ts` flattens. It arrives as a
|
|
761
|
+
// first-class `property: 'composes'`, NOT under `custom`, so it must be matched here.
|
|
766
762
|
case 'composes':
|
|
767
763
|
return {};
|
|
768
764
|
default:
|
package/build/lightning/rules.js
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
// Class names are emitted AS AUTHORED (`card-title` stays `card-title`, plus whatever the scoping
|
|
13
13
|
// rename appended). No camelCase anywhere in this file: normalization is what the trap was made of.
|
|
14
14
|
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
15
|
+
// The reason this is ONE pass, not two: with `cssModules` on, the visitor still sees the
|
|
16
|
+
// ORIGINAL class names — lightningcss renames AFTER the visitor walk. So the AST
|
|
17
17
|
// gives authored tokens and `exports` gives their renamed spelling, and the renamed CSS text never
|
|
18
18
|
// has to be parsed a second time (which is exactly what `../metro-css-module/index.ts` had to do,
|
|
19
19
|
// and what mangled a scope tail whose base36 hash began with a letter).
|
|
@@ -28,10 +28,9 @@ import { selectorsToMatches } from "./selectors.js";
|
|
|
28
28
|
import { warnOnce } from "../values.js";
|
|
29
29
|
// A conditional at-rule is DROPPED WHOLE, its nested rules with it. There is no media-query engine
|
|
30
30
|
// in React Native, so applying `.responsive` from `@media (min-width: 900px)` would paint it on
|
|
31
|
-
// every phone — worse than not supporting the rule, because it looks supported.
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
// nested style rule never reaches the collector; without it lightningcss hoists it out.
|
|
31
|
+
// every phone — worse than not supporting the rule, because it looks supported. Returning `[]`
|
|
32
|
+
// from the at-rule visitor removes it BEFORE the walk descends, so a nested style rule never
|
|
33
|
+
// reaches the collector; without it lightningcss hoists it out.
|
|
35
34
|
//
|
|
36
35
|
// `@keyframes` and `@font-face` need no entry here — neither emits a style rule to begin with.
|
|
37
36
|
const CONDITIONAL_AT_RULES = ['media', 'supports', 'container'];
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// .card[data-x]{…} -> key `card[dataX]` a key no element can ever carry
|
|
12
12
|
// .a.b / .a .b / .a>.b / .a+.b -> all key `aB` five selectors, one key, merged
|
|
13
13
|
//
|
|
14
|
-
// (Traps six and seven in `.claude/rules/style-registry-collisions.md
|
|
14
|
+
// (Traps six and seven in `.claude/rules/style-registry-collisions.md`.)
|
|
15
15
|
//
|
|
16
16
|
// So this module reports what the selector ACTUALLY says and refuses to guess:
|
|
17
17
|
// - tokens stay AS AUTHORED — `card-title` is `card-title`. Casing is the caller's problem, and
|
|
@@ -32,8 +32,7 @@
|
|
|
32
32
|
// a raw token stream — structurally the same thing `:global(X)` is under that same mode. All three
|
|
33
33
|
// are folded into `deep` here.
|
|
34
34
|
//
|
|
35
|
-
// `:global(X)` arrives in TWO DIFFERENT SHAPES and BOTH are live, so both are handled
|
|
36
|
-
// 2026-08-20, lightningcss 1.32, same CSS through both modes):
|
|
35
|
+
// `:global(X)` arrives in TWO DIFFERENT SHAPES and BOTH are live, so both are handled:
|
|
37
36
|
//
|
|
38
37
|
// cssModules OFF {kind:'custom-function', name:'global', arguments:[…raw token stream…]}
|
|
39
38
|
// cssModules ON {kind:'global', selector:[…parsed SelectorComponent[]…]}
|
|
@@ -60,11 +59,9 @@ const DROP_EXPLANATION = {
|
|
|
60
59
|
// `:active` support is OFF, and the selector machinery below is kept intact so one line turns it
|
|
61
60
|
// back on.
|
|
62
61
|
//
|
|
63
|
-
// WHY. The pressed look has a second, better route
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// machinery, it is what the ecosystem already writes, and it lowers — so the reason `:active`
|
|
67
|
-
// existed, keeping a Pressable lowerable without a state-reading callback, is gone.
|
|
62
|
+
// WHY. The pressed look has a second, better route: a functional `style={({pressed}) => …}`,
|
|
63
|
+
// which the engine resolves into `style` + `activeStyle` (`routeProp`). It reaches the same slot
|
|
64
|
+
// with no pseudo-class machinery and it is what the ecosystem already writes.
|
|
68
65
|
//
|
|
69
66
|
// Keeping BOTH live is what argues against it: they occupy different cascade slots (`activeStyle`
|
|
70
67
|
// replaces the authored style, an `:active` class rule replaces the class style), so an adapter has
|
|
@@ -371,13 +368,9 @@ function consumeComponent(builder, component) {
|
|
|
371
368
|
// depends on for every node at once.
|
|
372
369
|
if (component.kind === STATE_PSEUDO_CLASS) {
|
|
373
370
|
builder.specificity[1]++;
|
|
374
|
-
// ...but NOT through a scope boundary. `:deep(.b:active)`
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
// normally. Two spellings of one relation behaving differently is the bug, and the
|
|
378
|
-
// decision (2026-08-23) is to refuse BOTH: a deep selector reaches into another
|
|
379
|
-
// component's internals, and the state token is only meaningful on the node whose press
|
|
380
|
-
// machine owns it — which is exactly the node a deep rule cannot predict.
|
|
371
|
+
// ...but NOT through a scope boundary. Both `:deep(.b:active)` and `.a >>> .b:active`
|
|
372
|
+
// refuse: a deep selector reaches into another component's internals, and the state
|
|
373
|
+
// token is only meaningful on the node whose press machine owns it.
|
|
381
374
|
if (builder.combinators.includes('deep') ||
|
|
382
375
|
builder.pending === 'deep') {
|
|
383
376
|
drop(builder, 'pseudo-class', 'active through a deep combinator');
|
|
@@ -452,7 +445,7 @@ export function selectorsToMatches(selectors, filename) {
|
|
|
452
445
|
// and that is FALSE here — the pressed look is fully supported, by a different route. A
|
|
453
446
|
// warning that misdescribes the cause is worse than none: it sends the reader to the engine.
|
|
454
447
|
if (problem.reason === 'state-pseudo-class') {
|
|
455
|
-
console.warn(`[@symbiote-native/css-parser] ${filename}: dropped \`:${problem.detail}\` — pseudo-class state is currently disabled in this parser. Use a functional style instead: style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}, which
|
|
448
|
+
console.warn(`[@symbiote-native/css-parser] ${filename}: dropped \`:${problem.detail}\` — pseudo-class state is currently disabled in this parser. Use a functional style instead: style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}, which the engine resolves to style + activeStyle.`);
|
|
456
449
|
continue;
|
|
457
450
|
}
|
|
458
451
|
console.warn(`[@symbiote-native/css-parser] ${filename}: dropped a rule on \`${problem.detail}\` — ${DROP_EXPLANATION[problem.reason]}, so it can never match in React Native.`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/css-parser",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Build-time CSS/SCSS/Less/Stylus compiler for SymbioteNative — compiles stylesheets to React Native style objects, resolved at runtime via a cross-adapter class-name registry.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|