@navecss/core 0.4.0 → 0.6.0
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/CONSUMER-ATOMS.md +15 -11
- package/LICENSE +22 -0
- package/README.md +300 -33
- package/dist/{atom-names-2OreuBx9.d.ts → atom-names-B8Ud-7zD.d.ts} +2 -1
- package/dist/atoms.d.ts +3 -2
- package/dist/bin.js +98 -15
- package/dist/check.d.ts +2 -1
- package/dist/check.js +4 -3
- package/dist/{chunk-NFS2REPQ.js → chunk-2K5EBBF2.js} +1 -191
- package/dist/chunk-2TNTYI4L.js +7 -0
- package/dist/{chunk-LQSGQ2OA.js → chunk-B5CWZIBK.js} +3 -2
- package/dist/{chunk-XQQCDUV6.js → chunk-CTFEYJBE.js} +1 -1
- package/dist/{chunk-E5F6YF7A.js → chunk-EYMFWE3A.js} +2273 -126
- package/dist/chunk-KDLLTOAM.js +4031 -0
- package/dist/{chunk-2A7IUZBH.js → chunk-R6R5DSTT.js} +8 -8
- package/dist/chunk-UVHGEVMV.js +204 -0
- package/dist/{chunk-UANF3FGO.js → chunk-ZNTNLGEC.js} +2 -1
- package/dist/collect.d.ts +340 -6
- package/dist/collect.js +38 -1
- package/dist/css.d.ts +1 -0
- package/dist/cx.d.ts +1 -1
- package/dist/lightningcss.d.ts +3 -2
- package/dist/lightningcss.js +7 -4
- package/dist/postcss.d.ts +29 -3
- package/dist/postcss.js +331 -81
- package/dist/standalone.css +2 -0
- package/dist/{vite-options-D1-hGA9L.d.ts → vite-options-sOCeGn9B.d.ts} +3 -2
- package/dist/vite.d.ts +24 -3
- package/dist/vite.js +1541 -2284
- package/package.json +53 -24
- package/skills/navecss/SKILL.md +15 -1
- package/dist/chunk-LADFXRWQ.js +0 -1089
package/CONSUMER-ATOMS.md
CHANGED
|
@@ -122,20 +122,22 @@ Compiles to:
|
|
|
122
122
|
user-select: none;
|
|
123
123
|
-webkit-tap-highlight-color: transparent;
|
|
124
124
|
outline: none;
|
|
125
|
-
transition-property: color, background-color, border-color, opacity, box-shadow;
|
|
126
|
-
transition-duration: var(--nave-motion-duration-base);
|
|
127
|
-
transition-timing-function: var(--nave-motion-easing-standard);
|
|
128
|
-
background: var(--nave-color-action-primary);
|
|
129
|
-
color: var(--nave-color-on-action-primary);
|
|
130
|
-
padding: var(--nave-spacing-control-md) var(--nave-spacing-control-lg);
|
|
131
|
-
border-radius: var(--nave-radius-control);
|
|
132
|
-
font-weight: var(--nave-font-weight-medium);
|
|
133
125
|
&:focus-visible {
|
|
134
126
|
outline-style: solid;
|
|
135
127
|
outline-width: var(--nave-border-width-focus, 2px);
|
|
136
128
|
outline-color: var(--nave-color-border-focus, currentColor);
|
|
137
129
|
outline-offset: 2px;
|
|
138
130
|
}
|
|
131
|
+
& {
|
|
132
|
+
transition-property: color, background-color, border-color, opacity, box-shadow;
|
|
133
|
+
transition-duration: var(--nave-motion-duration-base);
|
|
134
|
+
transition-timing-function: var(--nave-motion-easing-standard);
|
|
135
|
+
background: var(--nave-color-action-primary);
|
|
136
|
+
color: var(--nave-color-on-action-primary);
|
|
137
|
+
padding: var(--nave-spacing-control-md) var(--nave-spacing-control-lg);
|
|
138
|
+
border-radius: var(--nave-radius-control);
|
|
139
|
+
font-weight: var(--nave-font-weight-medium);
|
|
140
|
+
}
|
|
139
141
|
&:hover {
|
|
140
142
|
background: var(--nave-color-action-primary-hover);
|
|
141
143
|
}
|
|
@@ -293,15 +295,17 @@ Compiles to:
|
|
|
293
295
|
display: flex;
|
|
294
296
|
flex-direction: column;
|
|
295
297
|
gap: var(--nave-spacing-content-md);
|
|
296
|
-
background: var(--nave-color-surface-raised);
|
|
297
|
-
border-radius: var(--nave-radius-card);
|
|
298
|
-
padding: var(--nave-spacing-content-md);
|
|
299
298
|
@container (width >= 28rem) {
|
|
300
299
|
& {
|
|
301
300
|
flex-direction: row;
|
|
302
301
|
align-items: center;
|
|
303
302
|
}
|
|
304
303
|
}
|
|
304
|
+
& {
|
|
305
|
+
background: var(--nave-color-surface-raised);
|
|
306
|
+
border-radius: var(--nave-radius-card);
|
|
307
|
+
padding: var(--nave-spacing-content-md);
|
|
308
|
+
}
|
|
305
309
|
}
|
|
306
310
|
}
|
|
307
311
|
```
|
package/LICENSE
CHANGED
|
@@ -55,3 +55,25 @@ JavaScript under dist/: the member names of a version 3 source map, the
|
|
|
55
55
|
layout of its mappings string, the base64 VLQ encoding of each field in it,
|
|
56
56
|
and the base64 alphabet. The code implementing them is this package's own, and
|
|
57
57
|
everything in this package is offered under the MIT licence above.
|
|
58
|
+
|
|
59
|
+
This package also includes material copied from or derived from mdn-data
|
|
60
|
+
(css/properties.json in the mdn/data repository, version 2.37.2,
|
|
61
|
+
https://github.com/mdn/data), which its authors dedicated to the public domain
|
|
62
|
+
under CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/),
|
|
63
|
+
and from CSS Logical Properties and Values Module Level 1, CSS Overflow Module
|
|
64
|
+
Level 3, CSS Overscroll Behavior Module Level 1, CSS Scroll Snap Module Level 1,
|
|
65
|
+
CSS Box Sizing Module Level 4, CSS Fonts Module Level 4, CSS Text Module Level
|
|
66
|
+
4, CSS Gaps Module Level 1, CSS Fragmentation Module Level 4, CSS Backgrounds
|
|
67
|
+
and Borders Module Level 3, and CSS Cascading and Inheritance Module Level 5 (in
|
|
68
|
+
the w3c/csswg-drafts repository, at commit
|
|
69
|
+
40527902c4d0840cdb7a808c8cd42302be1c3bc8). Copyright (c) 2026 World Wide Web
|
|
70
|
+
Consortium. Those specifications, and the repository carrying them, are
|
|
71
|
+
published under the W3C Software and Document License
|
|
72
|
+
(https://www.w3.org/copyright/software-license-2023/).
|
|
73
|
+
|
|
74
|
+
What is copied or derived is implemented in
|
|
75
|
+
src/directive/property-table.generated.ts, built into the JavaScript under
|
|
76
|
+
dist/: the names of CSS properties, the properties each shorthand sets, which
|
|
77
|
+
names are legacy name aliases of another property, and which logical and
|
|
78
|
+
physical properties belong to one group. The code using them is this package's
|
|
79
|
+
own, and everything in this package is offered under the MIT licence above.
|
package/README.md
CHANGED
|
@@ -107,10 +107,140 @@ Requires the Vite plugin or the PostCSS plugin. Everything stays in CSS files.
|
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Declarations are inlined at build time, and nothing of `@nave` is left at run time.
|
|
110
|
-
Pseudo-class rules (`:focus-visible` from `focusRing`), `@media` and
|
|
111
|
-
|
|
112
|
-
apply to every selector in a selector list. Native nesting is inside the browser
|
|
113
|
-
|
|
110
|
+
Pseudo-class rules (`:focus-visible` from `focusRing`), `@media` and `@container` blocks are
|
|
111
|
+
emitted as native CSS nesting inside your rule, each right after its own atom's declarations, so
|
|
112
|
+
they apply to every selector in a selector list. Native nesting is inside the browser floor under
|
|
113
|
+
[Requirements](#requirements), and [Order inside a rule](#order-inside-a-rule) says what wins when
|
|
114
|
+
your rule sets the same property.
|
|
115
|
+
|
|
116
|
+
#### Order inside a rule
|
|
117
|
+
|
|
118
|
+
`@nave a b;` expands where you write it, in the order CSS mixins will apply
|
|
119
|
+
`@apply --a; @apply --b;`: the declarations of `a`, then the pseudo-class,
|
|
120
|
+
`@media` and `@container` blocks of `a`, then the same for `b`. Whatever your rule
|
|
121
|
+
says after the directive comes after all of it. So of two declarations of one
|
|
122
|
+
property that both apply, the later one wins, unless the earlier one has the more
|
|
123
|
+
specific selector (an atom's pseudo-class block, such as the `:focus-visible` of
|
|
124
|
+
`focusRing`, does), as anywhere else in CSS.
|
|
125
|
+
|
|
126
|
+
```css
|
|
127
|
+
.panel {
|
|
128
|
+
@nave flex hideDesktopUp;
|
|
129
|
+
gap: var(--nave-spacing-content-md);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
expands to:
|
|
134
|
+
|
|
135
|
+
```css
|
|
136
|
+
.panel {
|
|
137
|
+
display: flex;
|
|
138
|
+
@media (width >= 75em) {
|
|
139
|
+
& {
|
|
140
|
+
display: none;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
& {
|
|
144
|
+
gap: var(--nave-spacing-content-md);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
A declaration that follows a nested block is written inside `& { }`, the wrapper
|
|
150
|
+
Nave already uses for a directive written after a nested rule. Under a selector
|
|
151
|
+
list, `&` matches with the specificity of the list's most specific selector, so a
|
|
152
|
+
wrapped declaration can win over a rule elsewhere that a bare one would lose to;
|
|
153
|
+
write it above the directive if that matters.
|
|
154
|
+
|
|
155
|
+
The order you write is the order that wins:
|
|
156
|
+
|
|
157
|
+
| You write | From 75em up |
|
|
158
|
+
| ------------------------------------- | ---------------- |
|
|
159
|
+
| `@nave flex hideDesktopUp;` | hidden |
|
|
160
|
+
| `@nave hideDesktopUp flex;` | shown, as flex |
|
|
161
|
+
| `display: grid; @nave hideDesktopUp;` | hidden |
|
|
162
|
+
| `@nave hideDesktopUp; display: grid;` | shown, as a grid |
|
|
163
|
+
|
|
164
|
+
Name a responsive or state atom after the atoms it adjusts, and write a declaration
|
|
165
|
+
that should give way to an atom's variants above the directive. A declaration or a
|
|
166
|
+
nested block below the directive is how you customize an atom inside your own rule.
|
|
167
|
+
|
|
168
|
+
The same order applies to the focus atoms. After `@nave focusRing;`, a later
|
|
169
|
+
`&:focus-visible { outline-color: var(--brand) }` recolours the ring, and a later
|
|
170
|
+
`&:focus { outline: none }` or `&:focus-visible { outline: none }` removes it,
|
|
171
|
+
which leaves the element with no focus indicator from `focusRing` under keyboard
|
|
172
|
+
focus. After `@nave srOnlyFocusable;`, a later `&:focus-visible { position: fixed }`
|
|
173
|
+
places the revealed element, and a later `clip-path: inset(50%)` in the same state
|
|
174
|
+
hides it again, so a skip link stays hidden when it has focus. To keep the atom's
|
|
175
|
+
result, write the block above the directive. The order warning below reports each
|
|
176
|
+
of these, and says so when the ring or the reveal is lost.
|
|
177
|
+
|
|
178
|
+
**The order warning.** Where something later in the rule overrides one of an atom's
|
|
179
|
+
pseudo-class, `@media` or `@container` blocks with a different value, the build
|
|
180
|
+
prints a warning at the later content. Where moving something lets the atom win
|
|
181
|
+
without a new warning, it says what to move, and it always shows how to mark the
|
|
182
|
+
directive if the later value is meant to win:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
src/panel.css:3:3: @nave: display: grid comes after "hideDesktopUp", so under @media (width >= 75em) display is grid, not none. To let "hideDesktopUp" win, move display: grid above the directive. If it is meant to win, mark the directive that names "hideDesktopUp": `@nave /* nave-allow-override: display */ hideDesktopUp;`
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Where no move clears the warning, as when the later value comes from another atom's
|
|
189
|
+
block and moving either only turns the pair round, it prints only the marker. Write
|
|
190
|
+
the atom that should win last, and mark the directive the warning then names.
|
|
191
|
+
|
|
192
|
+
It never fails the build, and `onUnknown` does not change it. The Vite plugin prints
|
|
193
|
+
it through Vite's logger, the PostCSS plugin as a PostCSS warning (and with `console.warn` on
|
|
194
|
+
Next.js under Turbopack, which does not print PostCSS warnings), the Lightning CSS
|
|
195
|
+
adapter with `console.warn`, and `navecss-core expand` on standard error, without
|
|
196
|
+
changing its exit code. No option turns it off for the whole project.
|
|
197
|
+
|
|
198
|
+
A directive written inside a nested rule that applies to the same element, such as
|
|
199
|
+
`.card { & { @nave hideDesktopUp } display: flex; }`, is checked the same way: its atoms' blocks
|
|
200
|
+
are compared with what follows the directive inside that nested rule, and with what each
|
|
201
|
+
enclosing rule holds after the nested rule.
|
|
202
|
+
|
|
203
|
+
**Marking an override you mean.** Name the property in a comment inside the
|
|
204
|
+
directive:
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
.panel {
|
|
208
|
+
@nave /* nave-allow-override: display */ hideDesktopUp;
|
|
209
|
+
display: grid;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The comment says that what comes after this directive's atoms (a later atom in it,
|
|
214
|
+
or your rule's own content) is meant to win for the properties it names. It
|
|
215
|
+
silences the warning for those properties on this directive and nothing else: an
|
|
216
|
+
override of another property, or of another directive's atoms, still warns. A
|
|
217
|
+
shorthand covers its longhands (`outline` covers `outline-color`). You can add a
|
|
218
|
+
reason after `--`: `/* nave-allow-override: display -- a grid on wide screens */`.
|
|
219
|
+
The head `nave-allow-override:` is matched in lower case only, as `eslint-disable`
|
|
220
|
+
is, so a comment that writes it in another case is not a marker: it allows nothing,
|
|
221
|
+
and the warning it was meant to silence still prints.
|
|
222
|
+
The comment never reaches your CSS. Only a comment inside the directive is read,
|
|
223
|
+
because some build steps remove the others before Nave sees the stylesheet (Vite
|
|
224
|
+
under `css.transformer: 'lightningcss'`, for one). A marker naming a property that
|
|
225
|
+
nothing overrides any more is reported, so remove it when you reorder. The Vite plugin under
|
|
226
|
+
`css.transformer: 'lightningcss'` does not report one, at any targets, because it cannot tell
|
|
227
|
+
whether Lightning CSS has already moved what follows the directive.
|
|
228
|
+
|
|
229
|
+
#### Output size
|
|
230
|
+
|
|
231
|
+
`@nave` copies an atom's declarations into every rule that uses it. That is the design: the directive is a build-time stand-in for native CSS mixins, whose `@apply` puts a mixin's declarations into the rule that applies it ([why](https://github.com/navecss/navecss/blob/main/docs/04-adr/0006-nave-directive-stands-in-for-css-mixins.md)). A browser that supports native mixins does that expansion itself, so such a stylesheet carries each mixin's body once, plus a short `@apply` where it is used; a build step has to write the copies out.
|
|
232
|
+
|
|
233
|
+
What the copies cost, in a model of a large app (10,000 component rules using a 25-atom design system and class names of about 20 characters, minified): about 70 percent of the raw CSS, 40 percent after gzip and 30 percent after brotli at level 11. Your app will differ, so measure your own bundle. What reduces it:
|
|
234
|
+
|
|
235
|
+
- **Compress CSS ahead of time with brotli at its highest level (11)**, instead of compressing on the fly at a lower one. In the model, level 11 sent 260 KB where level 5 sent 330 KB, which saves more than any way of removing the copies that was tried (below).
|
|
236
|
+
- **Split CSS by route**, so a page loads a shared part and its own rules rather than the whole app's. Split into one shared part and 40 routes, a page in the model loaded 65 KB at level 11, about a quarter, though all the parts together came to 348 KB, a third more than the single bundle.
|
|
237
|
+
|
|
238
|
+
What Nave does not do, and why:
|
|
239
|
+
|
|
240
|
+
- **It does not merge the copies into shared rules with combined selector lists.** In the model that saved 0.3 percent under brotli at level 11 and made gzip output 19 percent larger, because each selector then repeats once per atom, far apart. With 7-character class names the same merge saved 2 percent under gzip, 4 under brotli at level 11 and 12 under brotli at level 5, still less than level 11 saves over level 5. It also changed the computed style of 4 to 6 percent of the elements sampled: two atoms that set the same property stop resolving in the order you wrote them, and an atom's `@media` blocks move relative to your own declarations.
|
|
241
|
+
- **It does not turn your `@nave` atoms into shared classes for your markup to carry** (`cx()` does that for Nave's built-in atoms, where you choose it). That would move them into the `atomic` layer, below your component CSS, so your other rules and Nave's own component styles start beating them, and the class names it would add to your JavaScript and HTML cost about as much as the CSS it would remove under brotli, and about half as much under gzip.
|
|
242
|
+
|
|
243
|
+
The lasting fix is native CSS mixins. Once they ship in a browser and the specification settles, Nave adds a flag that writes `@mixin` and `@apply`, and once all three engines support them that becomes the default.
|
|
114
244
|
|
|
115
245
|
### Escape hatch — cx() utility
|
|
116
246
|
|
|
@@ -193,8 +323,11 @@ Every custom property Nave declares is in the stylesheet you already installed,
|
|
|
193
323
|
|
|
194
324
|
## Setting up `@nave`
|
|
195
325
|
|
|
196
|
-
On Vite, use the Vite plugin: it is the one route this package teaches for Vite
|
|
197
|
-
|
|
326
|
+
On Vite, use the Vite plugin: it is the one route this package teaches for Vite, and for Astro,
|
|
327
|
+
which builds with Vite ([Astro](#astro) has its config). On
|
|
328
|
+
Next.js, use [`@navecss/prune`](https://github.com/navecss/navecss/tree/main/packages/prune#readme)
|
|
329
|
+
to ship only the atoms the build can read a use for, or the PostCSS plugin to keep every atom. On
|
|
330
|
+
webpack, or any other pipeline that runs PostCSS plugins, use the PostCSS plugin. A host
|
|
198
331
|
that runs Lightning CSS directly uses [the Lightning CSS adapter](#lightning-css-adapter-setup),
|
|
199
332
|
and a project with no bundler uses [`navecss-core expand`](#navecss-core-expand).
|
|
200
333
|
|
|
@@ -218,8 +351,8 @@ It has no dependency and no peer. It expands `@nave` after Vite's own CSS step h
|
|
|
218
351
|
through `@import`, a Sass file (including a `@mixin` that holds a directive), a CSS Module, an
|
|
219
352
|
`?inline` or `?url` import, a Vue or Svelte style block and a `.css` inside `node_modules` are all
|
|
220
353
|
read as the CSS they compile to, in `vite build` and in the dev server, under either
|
|
221
|
-
`css.transformer`. A `?raw` import returns the file's text as it is. Astro
|
|
222
|
-
|
|
354
|
+
`css.transformer`. A `?raw` import returns the file's text as it is. Astro has its own setup and
|
|
355
|
+
its own measured list: [Astro](#astro).
|
|
223
356
|
|
|
224
357
|
**It also chooses which atoms ship.** A `cx()` call in your code whose atoms the build cannot read,
|
|
225
358
|
such as `cx(variant)` with a prop, is an error in the dev server and fails `vite build`.
|
|
@@ -242,10 +375,15 @@ Nave class it cannot see has no rule unless its atom is listed in `keep`.
|
|
|
242
375
|
|
|
243
376
|
**Under `css.transformer: 'lightningcss'`** the plugin expands exactly as it does under the default
|
|
244
377
|
transformer once both floor keys below are set. At Vite's default targets, which sit below the
|
|
245
|
-
floor, Lightning CSS lowers CSS nesting before any plugin runs, and
|
|
378
|
+
floor, Lightning CSS lowers CSS nesting before any plugin runs, and three things change.
|
|
246
379
|
A directive written after a declaration that follows a nested rule can be moved ahead of that
|
|
247
380
|
declaration: in `.a { &:hover { color: red; } display: grid; @nave block; }`, `grid` wins with no
|
|
248
|
-
message, where the default transformer makes `block` win.
|
|
381
|
+
message, where the default transformer makes `block` win.
|
|
382
|
+
What a rule says after a directive becomes a rule of its own, after the directive's, so it
|
|
383
|
+
already resolves in the order [Order inside a rule](#order-inside-a-rule) describes, but no order
|
|
384
|
+
warning is printed for it: a later `&:focus { outline: none }` after `focusRing`, for one, removes
|
|
385
|
+
the ring there with no message.
|
|
386
|
+
A directive in a group rule nested in a
|
|
249
387
|
style rule (`.a { @media (...) { @nave flex; } }`) still fails the build, but the message no longer
|
|
250
388
|
names the `& { @nave ...; }` workaround, and its position is in the CSS as Lightning CSS rewrote
|
|
251
389
|
it, not in your file. The plugin also drops one message and only that one: Lightning CSS's
|
|
@@ -310,8 +448,9 @@ newest 8.x at the time of each release.
|
|
|
310
448
|
The Vite plugin also chooses which of Nave's atoms reach your stylesheet. It reads the `cx()` calls
|
|
311
449
|
in the code the build compiles, dependencies included, and ships the rules for the atoms those calls
|
|
312
450
|
name, for the atom of each Nave class written as text (`nave-grid` in `index.html` or in a string in
|
|
313
|
-
your code, say)
|
|
314
|
-
|
|
451
|
+
your code, say) and each Nave class a CSS Module composes from global (`composes: nave-flex from global`),
|
|
452
|
+
and for the atoms you list in `keep` and `keepFor`; `srOnlyFocusable` also ships whenever `srOnly`
|
|
453
|
+
does. The dev server serves the same atoms, from the code it has read. This is
|
|
315
454
|
what `navePlugin()` does with no options. On the CSS-first path, where `@nave` copies an atom's
|
|
316
455
|
declarations into your own rule, a project that never calls `cx()` and writes no Nave class ships no
|
|
317
456
|
rule from the atom layer.
|
|
@@ -456,16 +595,27 @@ list: with an empty list, or none, it fails the build. Each client build records
|
|
|
456
595
|
`nave-used-atoms.json` file described below, the atoms it read from each listed package's calls,
|
|
457
596
|
where the calls it could not read are, and any `keepFor` key that names no package the build read.
|
|
458
597
|
|
|
459
|
-
`keepFor` stands in for the package's own calls, never for a call your code makes, so
|
|
598
|
+
`keepFor` stands in for the package's own calls, never for a call your code makes, so four problems
|
|
460
599
|
in a listed package still fail the build. A module of the package that re-exports `cx` under the
|
|
461
600
|
name `cx` still fails when a file of yours imports `cx` from that module itself, in an `import` or
|
|
462
601
|
`export ... from` statement, or a dependency that does more than re-export it imports it from there,
|
|
463
602
|
and the report gives the `cxModules` entry that lets the build read those calls. Through a module
|
|
464
603
|
that only re-exports it, such as the package's own entry file or another package, a listed module
|
|
465
604
|
would be two steps away, so there the report names each file of yours that takes it: import `cx`
|
|
466
|
-
from `@navecss/core/cx` there instead. A module that
|
|
467
|
-
|
|
468
|
-
|
|
605
|
+
from `@navecss/core/cx` there instead. A CommonJS module that forwards it with
|
|
606
|
+
`module.exports = require(...)` or `exports.cn = require(...).cn`, or with what TypeScript emits for
|
|
607
|
+
`export { cn } from` and `export * from` when it compiles to CommonJS, counts as one that only
|
|
608
|
+
re-exports it. A module that gives `cx` out under another name, as a default
|
|
609
|
+
or inside a namespace, or by assigning it first (`export const cn = cx`), still fails when your code
|
|
610
|
+
takes that export, and the report names each file of yours that does: import `cx` from
|
|
611
|
+
`@navecss/core/cx` there instead. A module of the package that uses `cx` where the build cannot
|
|
612
|
+
follow it to an export, such as `obj.cn = cx`, `memo(cx)` or `{ cn: cx }`, or that takes a module
|
|
613
|
+
holding a `cx` export in a way the build reads neither as calls only nor as a forward,
|
|
614
|
+
such as the CommonJS that Babel, esbuild or Rollup write for `export * from`, fails whenever it is
|
|
615
|
+
part of the build, whatever your code takes from the package, because the build cannot tell whether
|
|
616
|
+
a call of yours goes through it. The report names the file and the form. The fix is the package's,
|
|
617
|
+
in a release of it or a patched copy: export `cx` by name from an ES module. Until then, ship every
|
|
618
|
+
atom (below). And a module of the package
|
|
469
619
|
that you list in `cxModules` but that does not re-export Nave's `cx` under that name still fails:
|
|
470
620
|
remove it from `cxModules`.
|
|
471
621
|
|
|
@@ -481,6 +631,11 @@ A class your code takes at run time from `@navecss/core/atoms` (`atomClassMap[va
|
|
|
481
631
|
`toClassName('grid')`) is one the build does not read: it neither reads nor refuses it, so list its
|
|
482
632
|
atom in `keep`.
|
|
483
633
|
|
|
634
|
+
A package listed in `keepFor` can give `cx` to your code without the build failing if it redefines
|
|
635
|
+
or adds a method on `Function.prototype` or `Object.prototype`, or declares its own function under
|
|
636
|
+
one of the names compilers reserve for their interop helpers, such as `__importStar`: the build
|
|
637
|
+
cannot see either.
|
|
638
|
+
|
|
484
639
|
If your pages are rendered outside the build, by a backend that serves its own templates and uses
|
|
485
640
|
Vite for its assets only, the build reads none of their classes. While `keep` is empty, the plugin
|
|
486
641
|
warns when it has read no HTML page, no server render and no use of Nave at all: no `cx()` call, no
|
|
@@ -490,7 +645,9 @@ templates use in `keep`, or, if they are many, ship every atom (below).
|
|
|
490
645
|
|
|
491
646
|
The PostCSS plugin and the Lightning CSS adapter read no `cx()` call and leave every atom in the
|
|
492
647
|
layer, on Next.js and webpack alike; so does a page with no bundler, which links the standalone
|
|
493
|
-
stylesheet.
|
|
648
|
+
stylesheet. On Next.js,
|
|
649
|
+
[`@navecss/prune`](https://github.com/navecss/navecss/tree/main/packages/prune#readme) ships only
|
|
650
|
+
the atoms its build can read a use for.
|
|
494
651
|
|
|
495
652
|
A server build leaves packages in `node_modules` external by default, so it does not read their
|
|
496
653
|
code. For such a package that depends on `@navecss/core`, the build warns, naming it, unless it is
|
|
@@ -562,6 +719,82 @@ their own code, and `keepFor` does not reach it.
|
|
|
562
719
|
|
|
563
720
|
List every atom your components can apply at run time, `focusRing`, `srOnly`, `srOnlyFocusable`, `hidden` and the `hide*` atoms included where you use them: a consumer passes them to `keepFor` under your package's name, and one left out renders as if the class were absent in their production build.
|
|
564
721
|
|
|
722
|
+
#### Astro
|
|
723
|
+
|
|
724
|
+
Astro builds with Vite, so the Vite plugin is the route there too. Add it under `vite` in your
|
|
725
|
+
Astro config, which is where Astro takes Vite plugins, and put the floor key under `vite` as well:
|
|
726
|
+
Astro's own `build` has no `cssTarget`, and drops one written there without an error.
|
|
727
|
+
|
|
728
|
+
```js
|
|
729
|
+
// astro.config.mjs
|
|
730
|
+
import { defineConfig } from 'astro/config'
|
|
731
|
+
import { navePlugin } from '@navecss/core/vite'
|
|
732
|
+
|
|
733
|
+
export default defineConfig({
|
|
734
|
+
vite: {
|
|
735
|
+
plugins: [navePlugin()],
|
|
736
|
+
build: { cssTarget: ['chrome125', 'edge125', 'firefox128', 'safari18', 'ios18'] },
|
|
737
|
+
},
|
|
738
|
+
})
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
The build chooses which atoms ship, so run your checks, keyboard, screen-reader and automated
|
|
742
|
+
accessibility checks included, against a production build as well as in dev: `astro build`, then
|
|
743
|
+
`astro preview` or however you serve production.
|
|
744
|
+
|
|
745
|
+
Put Nave's order statement first in the `<head>` of every layout, as an inline style, ahead of
|
|
746
|
+
anything that can bring a style, `<ClientRouter />` included:
|
|
747
|
+
|
|
748
|
+
```astro
|
|
749
|
+
---
|
|
750
|
+
// src/layouts/Layout.astro
|
|
751
|
+
import '../styles/app.css'
|
|
752
|
+
---
|
|
753
|
+
<html lang="en">
|
|
754
|
+
<head>
|
|
755
|
+
<style is:inline>@layer tokens.defaults, tokens.presets, reset, atomic, components.nave, components.consumer, overrides;</style>
|
|
756
|
+
<meta charset="utf-8" />
|
|
757
|
+
<!-- the rest of your head, <ClientRouter /> included -->
|
|
758
|
+
</head>
|
|
759
|
+
<body><slot /></body>
|
|
760
|
+
</html>
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Astro can place a page's or a component's own style ahead of your layout's stylesheet, and with
|
|
764
|
+
`<ClientRouter />` it does so whatever the page imports first. A `@layer` in that style then fixes
|
|
765
|
+
its layer's place before Nave's order statement does, and the order inverts with no error. Astro
|
|
766
|
+
leaves an `is:inline` style where you write it, so this one is the first `@layer` the page sees.
|
|
767
|
+
`astro dev` does not show the inversion a build makes, so check the order in a build. The statement
|
|
768
|
+
is the one `@navecss/core/layers` holds, and the two must stay identical. Write the rules of a
|
|
769
|
+
`<style>` block inside `@layer components.consumer`, as for any CSS of yours: Astro leaves them
|
|
770
|
+
outside every layer otherwise, where they beat all of them.
|
|
771
|
+
|
|
772
|
+
The build chooses atoms as [Which atoms the build ships](#which-atoms-the-build-ships) says, with
|
|
773
|
+
three things particular to Astro. Astro writes its CSS in its server build, before the browser's
|
|
774
|
+
build runs, so an atom named only by code the browser runs, such as a `client:only` component or a
|
|
775
|
+
`<script>` in an `.astro` file, fails the build: list it in `keep`. A dependency the server build
|
|
776
|
+
leaves external is read just as late: add it to `resolve.noExternal` under `vite`, which reaches
|
|
777
|
+
every environment Astro builds, where `ssr.noExternal` does not. And in `output: 'server'` with
|
|
778
|
+
prerendered pages, the stylesheet the on-demand pages share ships every atom.
|
|
779
|
+
|
|
780
|
+
Both end-of-build checks, the `@nave` scan and the check that the atom layer holds exactly the atoms
|
|
781
|
+
the build chose, also read the stylesheets Astro writes into the page instead of as files (those
|
|
782
|
+
under 4 kB, by default). The file a message names for one of those is the name the stylesheet had
|
|
783
|
+
before Astro inlined it, so no file of that name is in `dist`. In an `.astro` file, the line of a
|
|
784
|
+
`@nave` error counts from the start of the `<style>` block that holds it, not from the top of the
|
|
785
|
+
file, and its column can differ from your file's, because Astro rewrites the block's whitespace.
|
|
786
|
+
|
|
787
|
+
In `astro dev`, the first paint holds the stylesheet as Vite's own CSS step left it, every atom and
|
|
788
|
+
every `@nave` unexpanded, until the page's scripts load; after that the dev server serves what the
|
|
789
|
+
build would, as far as it has read. The build is unaffected. As on any Vite project, run your
|
|
790
|
+
checks, keyboard, screen-reader and automated accessibility checks included, against a production
|
|
791
|
+
build as well as in dev: `astro build`, then `astro preview` or however you serve production.
|
|
792
|
+
|
|
793
|
+
A fixture measures this on Astro 7.4.0, with Vite 8.3.5 underneath: `@nave` expanded in `.css`
|
|
794
|
+
files and in `<style>` and `<style is:global>` blocks, and `cx()` read in frontmatter, in templates
|
|
795
|
+
and in React islands, in `astro build` for a static site and for `output: 'server'`, and in
|
|
796
|
+
`astro dev`. Islands in Vue, Svelte or Solid were not measured.
|
|
797
|
+
|
|
565
798
|
### PostCSS plugin setup
|
|
566
799
|
|
|
567
800
|
For Next.js, webpack under `postcss-loader`, and any other pipeline that runs PostCSS plugins.
|
|
@@ -592,6 +825,10 @@ If you are using only `cx()` or tokens, you do not need to install it.
|
|
|
592
825
|
|
|
593
826
|
#### Next.js
|
|
594
827
|
|
|
828
|
+
To ship only the atoms the build can read a use for, use
|
|
829
|
+
[`@navecss/prune`](https://github.com/navecss/navecss/tree/main/packages/prune#readme) in place of
|
|
830
|
+
this plugin. The setup below keeps every atom.
|
|
831
|
+
|
|
595
832
|
Next.js reads a PostCSS plugin by its package name, so give it the name as a key and do not
|
|
596
833
|
call `navePlugin()`:
|
|
597
834
|
|
|
@@ -618,6 +855,11 @@ Without it, Turbopack compiles for older browsers and rewrites every `light-dark
|
|
|
618
855
|
Nave's colours included, into `--lightningcss-light` and `--lightningcss-dark` variables. Spell
|
|
619
856
|
the floor out as above: Next 15 rejects the shorter `baseline 2024` with `Unknown browser baseline`.
|
|
620
857
|
|
|
858
|
+
**Where Nave's warnings show.** With webpack (`next build --webpack`), `next build` prints them under `Compiled with warnings`, once for each compilation that reads the stylesheet, so a CSS Module imported from a Server Component can show the same warning twice; `next dev --webpack` may not print a global stylesheet's, so read them from `next build`. Turbopack does not print PostCSS warnings, so under Turbopack the plugin prints them itself on standard error, with the file, line and column, in `next build` and `next dev` alike. Neither bundler shows them in the browser console or Next's error overlay.
|
|
859
|
+
A problem that [`onUnknown`](#options) covers is a warning only under `'warn'`; under the
|
|
860
|
+
default, `'error'`, it fails the build on either bundler. Where the warnings show was measured
|
|
861
|
+
on Next 16.4.1, not on Next 15.
|
|
862
|
+
|
|
621
863
|
**If your Vite config sets `css.transformer: 'lightningcss'`, this plugin never
|
|
622
864
|
runs.** That option replaces Vite's CSS pipeline with Lightning CSS, which does
|
|
623
865
|
not run PostCSS plugins at all: the build stays green, `@nave` reaches the
|
|
@@ -667,7 +909,8 @@ Nave's own messages, with the file's path and the line and column of each proble
|
|
|
667
909
|
and the map as a string, ready for `transform()`'s `code` and `inputSourceMap`. `resolver.read` reads each file
|
|
668
910
|
`bundleAsync()` asks for and returns its expanded text, so a file reached through `@import` is
|
|
669
911
|
covered too. It takes `extend` (an object of your own atoms) and `onUnknown` as the other plugins
|
|
670
|
-
do ([Options](#options)); under `'warn'` it prints each problem with `console.warn
|
|
912
|
+
do ([Options](#options)); under `'warn'` it prints each problem with `console.warn`, and prints
|
|
913
|
+
the [order warning](#order-inside-a-rule) the same way under every `onUnknown`.
|
|
671
914
|
|
|
672
915
|
The adapter imports nothing from `lightningcss`, types included, and declares no peer: you bring
|
|
673
916
|
your own copy. The supported range is documented, not declared: `lightningcss` 1.24.1 and later.
|
|
@@ -696,6 +939,21 @@ in one error, positioned at the first: its message, then
|
|
|
696
939
|
others. The report covers one stylesheet, so a bundler that stops at the first
|
|
697
940
|
failing file reports one file per build. Under `'warn'`, each problem is a
|
|
698
941
|
warning of its own.
|
|
942
|
+
The [order warning](#order-inside-a-rule) is not one of these problems: it is printed as a
|
|
943
|
+
warning whatever `onUnknown` says. On Turbopack, Next 16's default bundler, which shows no
|
|
944
|
+
PostCSS warning, the PostCSS plugin prints each problem under `'warn'` and each order warning
|
|
945
|
+
to the terminal instead, as `file:line:column:` and the message
|
|
946
|
+
([where Next.js shows them](#nextjs)). It knows Turbopack by the `TURBOPACK` environment
|
|
947
|
+
variable, which Next.js sets for it, so wherever that variable is set and not empty, under Vite
|
|
948
|
+
or the PostCSS CLI as well, it does the same and raises no PostCSS warning. The Vite plugin and
|
|
949
|
+
the Lightning CSS adapter do not read the variable. The PostCSS plugin also takes
|
|
950
|
+
`printWarnings` (default `true`): with `printWarnings: false` it raises each problem under
|
|
951
|
+
`'warn'` and each order warning as a PostCSS warning and prints none of them, whatever
|
|
952
|
+
`TURBOPACK` holds, for a tool that runs the plugin itself and reports the warnings it raises.
|
|
953
|
+
Such a tool can import `isOrderWarning(warning)` from `@navecss/core/postcss` to tell them
|
|
954
|
+
apart: it is `true` for an order warning and `false` for each of these problems, so the tool
|
|
955
|
+
can report an order warning as the plugin does, whatever `onUnknown` says, and never fail a
|
|
956
|
+
build on one.
|
|
699
957
|
|
|
700
958
|
To add atoms of your own to `@nave`, pass them as `extend`: see
|
|
701
959
|
[CONSUMER-ATOMS.md](./CONSUMER-ATOMS.md). An `extend` object written inline in
|
|
@@ -795,6 +1053,9 @@ across every file is printed in one run, one report per stylesheet. Exit codes:
|
|
|
795
1053
|
`--watch`, a directory that could not be watched. Nothing is written, except that files written
|
|
796
1054
|
before an `--out` that failed stay written.
|
|
797
1055
|
|
|
1056
|
+
An order warning is printed and is not a problem here: it changes neither the exit code nor what is
|
|
1057
|
+
written.
|
|
1058
|
+
|
|
798
1059
|
It does not resolve or inline `@import`; that would make it a CSS bundler. It
|
|
799
1060
|
expands only the files you name with `--source`, so a stylesheet you import that
|
|
800
1061
|
holds `@nave` needs a pair of its own. An `@import` of a relative or absolute URL
|
|
@@ -881,18 +1142,24 @@ Consumers of `@navecss/tokens` alone get no guide: it ships only in this package
|
|
|
881
1142
|
|
|
882
1143
|
## Exports
|
|
883
1144
|
|
|
884
|
-
| Export | Description
|
|
885
|
-
| ---------------------------- |
|
|
886
|
-
| `@navecss/core` | CSS entry point — `@import url('@navecss/core')`
|
|
887
|
-
| `@navecss/core/layers` | The `@layer` order statement alone. Import it first, before any other stylesheet
|
|
888
|
-
| `@navecss/core/no-tokens` | Entry point for projects that generate their own Nave token layer; see the header comment in the file
|
|
889
|
-
| `@navecss/core/reset` | Reset stylesheet only. It reads Nave's custom properties, so it needs a token layer beside it
|
|
890
|
-
| `@navecss/core/atomic` | Generated atomic CSS (global `nave-` classes)
|
|
891
|
-
| `@navecss/core/cx` | `cx()` / `cx.raw()` utilities + `AtomName` type
|
|
892
|
-
| `@navecss/core/atoms` | Atom definitions + `atomClassMap`
|
|
893
|
-
| `@navecss/core/vite` | Vite plugin — `navePlugin()`
|
|
894
|
-
| `@navecss/core/lightningcss` | Lightning CSS adapter — `navePlugin()`, returning `expand` and `resolver`
|
|
895
|
-
| `@navecss/core/standalone` | The whole stylesheet in one file, with no `@import`, for projects with no bundler
|
|
896
|
-
| `@navecss/core/postcss` | PostCSS plugin — `navePlugin()`
|
|
897
|
-
| `@navecss/core/check` | The survival check as a function — `check({ source })`
|
|
898
|
-
| `@navecss/core/collect` | Reads which atoms a module uses, for build tools; not meant for application code
|
|
1145
|
+
| Export | Description |
|
|
1146
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
1147
|
+
| `@navecss/core` | CSS entry point — `@import url('@navecss/core')` |
|
|
1148
|
+
| `@navecss/core/layers` | The `@layer` order statement alone. Import it first, before any other stylesheet |
|
|
1149
|
+
| `@navecss/core/no-tokens` | Entry point for projects that generate their own Nave token layer; see the header comment in the file |
|
|
1150
|
+
| `@navecss/core/reset` | Reset stylesheet only. It reads Nave's custom properties, so it needs a token layer beside it |
|
|
1151
|
+
| `@navecss/core/atomic` | Generated atomic CSS (global `nave-` classes) |
|
|
1152
|
+
| `@navecss/core/cx` | `cx()` / `cx.raw()` utilities + `AtomName` type |
|
|
1153
|
+
| `@navecss/core/atoms` | Atom definitions + `atomClassMap` |
|
|
1154
|
+
| `@navecss/core/vite` | Vite plugin — `navePlugin()` |
|
|
1155
|
+
| `@navecss/core/lightningcss` | Lightning CSS adapter — `navePlugin()`, returning `expand` and `resolver` |
|
|
1156
|
+
| `@navecss/core/standalone` | The whole stylesheet in one file, with no `@import`, for projects with no bundler |
|
|
1157
|
+
| `@navecss/core/postcss` | PostCSS plugin — `navePlugin()` |
|
|
1158
|
+
| `@navecss/core/check` | The survival check as a function — `check({ source })` |
|
|
1159
|
+
| `@navecss/core/collect` | Reads which atoms a module uses and trims the atom layer to them, for build tools; not meant for application code |
|
|
1160
|
+
|
|
1161
|
+
## Trademark
|
|
1162
|
+
|
|
1163
|
+
This package is not affiliated with, endorsed by or sponsored by Vercel or the Next.js project.
|
|
1164
|
+
|
|
1165
|
+
Vercel, the Vercel design, Next.js and related marks, designs and logos are trademarks or registered trademarks of Vercel, Inc. or its affiliates in the US and other countries.
|
|
@@ -24,4 +24,5 @@ declare const toClassName: (name: AtomName) => string;
|
|
|
24
24
|
*/
|
|
25
25
|
declare const atomClassMap: Record<AtomName, string>;
|
|
26
26
|
|
|
27
|
-
export {
|
|
27
|
+
export { atomClassMap as a, toClassName as t };
|
|
28
|
+
export type { AtomName as A };
|
package/dist/atoms.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AtomName, a as atomClassMap, t as toClassName } from './atom-names-
|
|
1
|
+
export { A as AtomName, a as atomClassMap, t as toClassName } from './atom-names-B8Ud-7zD.js';
|
|
2
2
|
|
|
3
3
|
type CSSDeclarations = Record<string, string>;
|
|
4
4
|
type PseudoMap = Record<string, CSSDeclarations>;
|
|
@@ -406,4 +406,5 @@ declare const atoms: {
|
|
|
406
406
|
};
|
|
407
407
|
};
|
|
408
408
|
|
|
409
|
-
export {
|
|
409
|
+
export { atoms };
|
|
410
|
+
export type { AtomDefinition };
|