@pre.style/core 3.1.0-alpha.0 → 3.1.0-alpha.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 +154 -72
- package/dist/compiler/block.d.ts +2 -0
- package/dist/compiler/block.js +9 -7
- package/dist/compiler/compiler.d.ts +22 -0
- package/dist/compiler/compiler.js +213 -43
- package/dist/compiler/config.d.ts +1 -0
- package/dist/compiler/config.js +10 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/keyframes.d.ts +6 -0
- package/dist/compiler/keyframes.js +120 -0
- package/dist/compiler/libraries.d.ts +2 -0
- package/dist/compiler/libraries.js +3 -2
- package/dist/compiler/mapper.js +6 -1
- package/dist/compiler/selectors.d.ts +3 -0
- package/dist/compiler/selectors.js +38 -0
- package/dist/compiler/stylesheet.js +8 -0
- package/package.json +1 -1
- package/package.schema.json +8 -0
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# pre.style
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@pre.style/core)
|
|
4
4
|
|
|
5
5
|
Zero-runtime CSS-in-JS. Write plain CSS or SCSS next to your markup, and pre.style compiles it at build time into atomic CSS classes: one small class per declaration, shared across your whole project.
|
|
6
6
|
|
|
7
7
|
```js
|
|
8
|
-
import { css } from
|
|
8
|
+
import { css } from "@pre.style/core";
|
|
9
9
|
|
|
10
10
|
const button = css`
|
|
11
11
|
background-color: #0071ba;
|
|
@@ -25,14 +25,28 @@ const button = css`
|
|
|
25
25
|
After the build, `button` is a plain string, `"B C E D A G F"`. The block is replaced, and these classes are added to a single CSS file:
|
|
26
26
|
|
|
27
27
|
```css
|
|
28
|
-
.B{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
|
|
28
|
+
.B {
|
|
29
|
+
background-color: #0071ba;
|
|
30
|
+
}
|
|
31
|
+
.C {
|
|
32
|
+
color: #fff;
|
|
33
|
+
}
|
|
34
|
+
.E {
|
|
35
|
+
padding-block-start: 0.5em;
|
|
36
|
+
}
|
|
37
|
+
.D {
|
|
38
|
+
padding-block-end: 0.5em;
|
|
39
|
+
}
|
|
40
|
+
.A:hover {
|
|
41
|
+
background-color: #005a94;
|
|
42
|
+
}
|
|
33
43
|
@media (width>=768px) {
|
|
34
|
-
.G{
|
|
35
|
-
|
|
44
|
+
.G {
|
|
45
|
+
padding-block-start: 1em;
|
|
46
|
+
}
|
|
47
|
+
.F {
|
|
48
|
+
padding-block-end: 1em;
|
|
49
|
+
}
|
|
36
50
|
}
|
|
37
51
|
```
|
|
38
52
|
|
|
@@ -59,8 +73,8 @@ npm install --save-dev sass
|
|
|
59
73
|
Add the plugin to `vite.config.ts`:
|
|
60
74
|
|
|
61
75
|
```ts
|
|
62
|
-
import { defineConfig } from
|
|
63
|
-
import preStyle from
|
|
76
|
+
import { defineConfig } from "vite";
|
|
77
|
+
import preStyle from "@pre.style/vite";
|
|
64
78
|
|
|
65
79
|
export default defineConfig({
|
|
66
80
|
plugins: [preStyle()],
|
|
@@ -70,7 +84,7 @@ export default defineConfig({
|
|
|
70
84
|
Then import `css` (or `scss`) from `@pre.style/core` and use the class strings:
|
|
71
85
|
|
|
72
86
|
```jsx
|
|
73
|
-
import { css } from
|
|
87
|
+
import { css } from "@pre.style/core";
|
|
74
88
|
|
|
75
89
|
export function Card({ children }) {
|
|
76
90
|
return (
|
|
@@ -95,7 +109,7 @@ You can also write styles in `.css` and `.scss` files and import their classes,
|
|
|
95
109
|
Frameworks that render on the server, such as React Router's framework mode, don't use `index.html`. Import pre.style's CSS in your root module instead:
|
|
96
110
|
|
|
97
111
|
```ts
|
|
98
|
-
import
|
|
112
|
+
import "virtual:pre.style.css";
|
|
99
113
|
```
|
|
100
114
|
|
|
101
115
|
Vite then bundles the CSS with your app's other CSS, and the framework links it when rendering on the server, both in builds and in dev. The plugin doesn't write `output.file` when the CSS is imported this way.
|
|
@@ -106,8 +120,8 @@ Add the plugin to Astro's Vite config, and import the CSS in your layout's front
|
|
|
106
120
|
|
|
107
121
|
```js
|
|
108
122
|
// astro.config.mjs
|
|
109
|
-
import { defineConfig } from
|
|
110
|
-
import preStyle from
|
|
123
|
+
import { defineConfig } from "astro/config";
|
|
124
|
+
import preStyle from "@pre.style/vite";
|
|
111
125
|
|
|
112
126
|
export default defineConfig({
|
|
113
127
|
vite: { plugins: [preStyle()] },
|
|
@@ -127,7 +141,7 @@ const title = css`
|
|
|
127
141
|
<h1 class={title}>Hello</h1>
|
|
128
142
|
```
|
|
129
143
|
|
|
130
|
-
Blocks work in frontmatter, in template expressions such as ``
|
|
144
|
+
Blocks work in frontmatter, in template expressions such as ``class={css`…`}``, in `<script>` tags, and in the islands of any framework. Astro links the CSS on every page that uses the layout, prerendered or rendered on demand. Astro compiles components before the plugin sees them, but errors and source maps still point to the component.
|
|
131
145
|
|
|
132
146
|
## Writing blocks
|
|
133
147
|
|
|
@@ -138,7 +152,7 @@ A block styles one element. Each block is treated as its own small stylesheet, w
|
|
|
138
152
|
`css` blocks are plain CSS. `scss` blocks are compiled with Sass first, so you can use variables, mixins, functions, and everything else Sass supports:
|
|
139
153
|
|
|
140
154
|
```js
|
|
141
|
-
import { scss } from
|
|
155
|
+
import { scss } from "@pre.style/core";
|
|
142
156
|
|
|
143
157
|
const title = scss`
|
|
144
158
|
$size: 2rem;
|
|
@@ -161,7 +175,8 @@ css`
|
|
|
161
175
|
&::before { content: '→'; }
|
|
162
176
|
& > * + * { margin-top: 1rem; }
|
|
163
177
|
.dark & { color: white; }
|
|
164
|
-
a { text-decoration: underline; } /* the same as
|
|
178
|
+
a { text-decoration: underline; } /* the same as ` &
|
|
179
|
+
a` */
|
|
165
180
|
`;
|
|
166
181
|
```
|
|
167
182
|
|
|
@@ -174,20 +189,32 @@ Other at-rules, such as `@keyframes`, `@font-face`, and `@property`, are copied
|
|
|
174
189
|
```js
|
|
175
190
|
css`
|
|
176
191
|
@keyframes fade-in {
|
|
177
|
-
from {
|
|
192
|
+
from {
|
|
193
|
+
opacity: 0;
|
|
194
|
+
}
|
|
178
195
|
}
|
|
179
196
|
|
|
180
197
|
animation: fade-in 200ms ease-out;
|
|
181
198
|
`;
|
|
182
199
|
```
|
|
183
200
|
|
|
201
|
+
#### Local keyframes
|
|
202
|
+
|
|
203
|
+
By default, keyframes names are global, so two blocks that each define a different `@keyframes spin` collide, and the last one wins everywhere. Set `"keyframeLocalization": true` in your `package.json`'s `pre.style` field to give each `@keyframes` a generated name, as styled-components' `keyframes` helper does:
|
|
204
|
+
|
|
205
|
+
- A block's or stylesheet file's `@keyframes` get a short generated name, and its `animation` and `animation-name` declarations use it. In a stylesheet file, every class in the file shares the file's keyframes, as in CSS Modules.
|
|
206
|
+
- Keyframes with the same contents get the same name wherever they're defined, so they're written once.
|
|
207
|
+
- Keyframes from [prepended files](#sharing-values-with-prepended-files) are localized too. Every block gets the same copy, so prepended files are the way to share keyframes between blocks.
|
|
208
|
+
- Names a block or file doesn't define are left as they are, so `animation-name: spin` still refers to a global `@keyframes spin`, for example one in a CSS file that pre.style doesn't process. That also means a block can't use keyframes another block defines.
|
|
209
|
+
- Names in custom properties (`--anim: spin`) aren't renamed, because pre.style can't tell they name keyframes.
|
|
210
|
+
|
|
184
211
|
### `composes` in blocks
|
|
185
212
|
|
|
186
213
|
A block can build on classes from a [stylesheet file](#stylesheet-files), or on global class names, with `composes`, as in CSS Modules:
|
|
187
214
|
|
|
188
215
|
```js
|
|
189
216
|
css`
|
|
190
|
-
composes: button from
|
|
217
|
+
composes: button from "./button.css";
|
|
191
218
|
composes: legacy-btn from global;
|
|
192
219
|
color: white;
|
|
193
220
|
`;
|
|
@@ -208,7 +235,7 @@ HTML can't import anything, so blocks in HTML files that Vite processes, such as
|
|
|
208
235
|
Atomic classes all have the same specificity, so when two classes on one element set the same property, the order of the CSS file decides which wins, not the order in your `class` attribute. Use `cn` to combine class strings: when two classes conflict, it keeps the later one.
|
|
209
236
|
|
|
210
237
|
```js
|
|
211
|
-
import { css, cn } from
|
|
238
|
+
import { css, cn } from "@pre.style/core";
|
|
212
239
|
|
|
213
240
|
const button = css`
|
|
214
241
|
background-color: #0071ba;
|
|
@@ -225,7 +252,7 @@ const className = cn(button, isDanger && danger);
|
|
|
225
252
|
|
|
226
253
|
Two classes conflict when they set the same property under the same at-rules and selector. A later shorthand also removes earlier longhands it covers.
|
|
227
254
|
|
|
228
|
-
When every argument is a block or a string literal, the plugin resolves the call during the build, so it costs nothing at runtime. Other calls use a small lookup table the plugin generates for your project.
|
|
255
|
+
When every argument is a block or a string literal, the plugin resolves the call during the build, so it costs nothing at runtime. Arguments can also name a top-level `const` holding one of these, or holding another call that's resolved this way (`const base = css`…`;` then `cn(base, …)`). Other calls use a small lookup table the plugin generates for your project.
|
|
229
256
|
|
|
230
257
|
> **Note:** `cn` removes `!important` declarations too. A later class that sets the same property wins, even when the earlier one is `!important`.
|
|
231
258
|
|
|
@@ -251,7 +278,10 @@ Styles can also live in `.css` and `.scss` files, imported with the `pre.style`
|
|
|
251
278
|
```
|
|
252
279
|
|
|
253
280
|
```jsx
|
|
254
|
-
import {
|
|
281
|
+
import {
|
|
282
|
+
button,
|
|
283
|
+
"primary-button" as primaryButton,
|
|
284
|
+
} from "./button.css" with { type: "pre.style" };
|
|
255
285
|
|
|
256
286
|
<button className={primaryButton}>Save</button>;
|
|
257
287
|
```
|
|
@@ -276,15 +306,27 @@ In `.scss` files, relative `@use`, `@forward`, and `@import` resolve from the fi
|
|
|
276
306
|
Atomic classes are shared, so no single class in a class string identifies one export. When an exported class is used as context for another, as `card` is in `.card:hover .title`, pre.style gives it a **marker**: one extra class, added to `card`'s class string, that the selector uses.
|
|
277
307
|
|
|
278
308
|
```css
|
|
279
|
-
.card {
|
|
280
|
-
|
|
281
|
-
|
|
309
|
+
.card {
|
|
310
|
+
padding-top: 1rem;
|
|
311
|
+
}
|
|
312
|
+
.title {
|
|
313
|
+
color: black;
|
|
314
|
+
}
|
|
315
|
+
.card:hover .title {
|
|
316
|
+
color: red;
|
|
317
|
+
}
|
|
282
318
|
```
|
|
283
319
|
|
|
284
320
|
```css
|
|
285
|
-
.D{
|
|
286
|
-
|
|
287
|
-
|
|
321
|
+
.D {
|
|
322
|
+
padding-top: 1rem;
|
|
323
|
+
}
|
|
324
|
+
.C {
|
|
325
|
+
color: #000;
|
|
326
|
+
}
|
|
327
|
+
.A:hover .B {
|
|
328
|
+
color: red;
|
|
329
|
+
}
|
|
288
330
|
```
|
|
289
331
|
|
|
290
332
|
`card` is `"D A"`, where `A` is its marker, and `title` is `"C B"`.
|
|
@@ -297,10 +339,20 @@ Atomic classes are shared, so no single class in a class string identifies one e
|
|
|
297
339
|
`composes` works as in CSS Modules:
|
|
298
340
|
|
|
299
341
|
```css
|
|
300
|
-
.base {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
342
|
+
.base {
|
|
343
|
+
color: gray;
|
|
344
|
+
padding: 1rem;
|
|
345
|
+
}
|
|
346
|
+
.primary {
|
|
347
|
+
composes: base;
|
|
348
|
+
color: blue;
|
|
349
|
+
}
|
|
350
|
+
.wide {
|
|
351
|
+
composes: card from "./card.css";
|
|
352
|
+
}
|
|
353
|
+
.legacy {
|
|
354
|
+
composes: old-btn from global;
|
|
355
|
+
}
|
|
304
356
|
```
|
|
305
357
|
|
|
306
358
|
> [!IMPORTANT]
|
|
@@ -318,7 +370,9 @@ TypeScript 7.1 adds [content mappers](https://devblogs.microsoft.com/typescript/
|
|
|
318
370
|
|
|
319
371
|
```json
|
|
320
372
|
{
|
|
321
|
-
"contentMappers": [
|
|
373
|
+
"contentMappers": [
|
|
374
|
+
{ "package": "@pre.style/core", "extensions": [".css", ".scss"] }
|
|
375
|
+
]
|
|
322
376
|
}
|
|
323
377
|
```
|
|
324
378
|
|
|
@@ -327,11 +381,11 @@ Content mappers run code from a package, so `tsc` needs the `--runExternalCode`
|
|
|
327
381
|
Before TypeScript 7.1, add this declaration to your project instead (for example as `src/stylesheets.d.ts`):
|
|
328
382
|
|
|
329
383
|
```ts
|
|
330
|
-
declare module
|
|
384
|
+
declare module "*.css" {
|
|
331
385
|
const classes: { readonly [name: string]: string };
|
|
332
386
|
export = classes;
|
|
333
387
|
}
|
|
334
|
-
declare module
|
|
388
|
+
declare module "*.scss" {
|
|
335
389
|
const classes: { readonly [name: string]: string };
|
|
336
390
|
export = classes;
|
|
337
391
|
}
|
|
@@ -340,7 +394,7 @@ declare module '*.scss' {
|
|
|
340
394
|
TypeScript can't type named imports from it, so use a namespace import:
|
|
341
395
|
|
|
342
396
|
```ts
|
|
343
|
-
import * as styles from
|
|
397
|
+
import * as styles from "./button.css" with { type: "pre.style" };
|
|
344
398
|
|
|
345
399
|
styles.button;
|
|
346
400
|
```
|
|
@@ -411,11 +465,12 @@ A library's class names depend on the whole app, so they differ between apps. Do
|
|
|
411
465
|
}
|
|
412
466
|
```
|
|
413
467
|
|
|
414
|
-
| Field
|
|
415
|
-
|
|
|
416
|
-
| `include`
|
|
417
|
-
| `exclude`
|
|
418
|
-
| `prependFiles`
|
|
468
|
+
| Field | Default | Description |
|
|
469
|
+
| ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
470
|
+
| `include` | Every JS, TS, and Astro file | Globs of the files with blocks, relative to the package. A glob or an array of them. Stylesheet files the library imports are found from its imports. |
|
|
471
|
+
| `exclude` | | Globs removed from `include`. |
|
|
472
|
+
| `prependFiles` | | Files added to the start of the library's blocks and stylesheet files, relative to the package. They apply only to the library's, not the app's, so the library's tokens and mixins are always available to it and never leak into the app. |
|
|
473
|
+
| `keyframeLocalization` | `false` | Give each `@keyframes` in the library's blocks and stylesheet files a generated name. See [Local keyframes](#local-keyframes). The library's setting applies to its blocks, whatever the app sets, since the library's styles are written for it. |
|
|
419
474
|
|
|
420
475
|
`"pre.style": true` uses the defaults. A library's field uses the same name and shape as an app's (see [Configuration](#configuration)). `libraries` and `quirksMode` only apply to the app, so in a library's field they're ignored, with a warning. A package that is both, such as a library with its own demo app, is read as the app when it's the Vite root, and as a library when it's a dependency.
|
|
421
476
|
|
|
@@ -438,20 +493,33 @@ Production builds scan your files first, so names are stable between builds. In
|
|
|
438
493
|
Shorthand properties are expanded into their longhands, so `cn` can resolve conflicts between them:
|
|
439
494
|
|
|
440
495
|
```js
|
|
441
|
-
css`
|
|
496
|
+
css`
|
|
497
|
+
margin: auto;
|
|
498
|
+
`;
|
|
442
499
|
```
|
|
443
500
|
|
|
444
501
|
```css
|
|
445
|
-
.D{
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
.
|
|
502
|
+
.D {
|
|
503
|
+
margin-top: auto;
|
|
504
|
+
}
|
|
505
|
+
.C {
|
|
506
|
+
margin-right: auto;
|
|
507
|
+
}
|
|
508
|
+
.A {
|
|
509
|
+
margin-bottom: auto;
|
|
510
|
+
}
|
|
511
|
+
.B {
|
|
512
|
+
margin-left: auto;
|
|
513
|
+
}
|
|
449
514
|
```
|
|
450
515
|
|
|
451
516
|
`border` (which sets 12 longhands), shorthands whose values aren't known until runtime (values with `var()`, `env()`, or `attr()`), and shorthands set to a CSS-wide keyword (`font: inherit`, `margin: initial`) are kept as one class. They're written before longhands, so a longhand still wins:
|
|
452
517
|
|
|
453
518
|
```js
|
|
454
|
-
css`
|
|
519
|
+
css`
|
|
520
|
+
padding: var(--space);
|
|
521
|
+
padding-top: 0;
|
|
522
|
+
`;
|
|
455
523
|
```
|
|
456
524
|
|
|
457
525
|
Expanding means some shorthands produce many classes. For example, `font` also resets the `font-variant-*` properties, among others, so it becomes about 20 classes. The CSS file barely grows, because the classes are shared across your project, but class strings get longer.
|
|
@@ -460,7 +528,7 @@ Expanding means some shorthands produce many classes. For example, `font` also r
|
|
|
460
528
|
|
|
461
529
|
Within one block, a later declaration overrides an earlier one, as in plain CSS. Across blocks, the CSS file is ordered so the usual rules hold:
|
|
462
530
|
|
|
463
|
-
1. Hoisted at-rules (`@layer` statements, `@import`, `@namespace`), then other copied at-rules.
|
|
531
|
+
1. Hoisted at-rules (`@layer` statements, `@import`, `@namespace`), then other copied at-rules. With the `layer` option, everything but `@import` and `@namespace` is inside the layer.
|
|
464
532
|
2. Classes on the element.
|
|
465
533
|
3. Selector variants, with pseudo-classes in LVHFA order (`:link`, `:visited`, `:hover`, `:focus`, `:active`).
|
|
466
534
|
4. At-rule groups. `@media` queries with only a `min-width` come last, smallest first (mobile-first).
|
|
@@ -492,13 +560,14 @@ Options every tool that reads your styles has to agree on (the bundler plugin, a
|
|
|
492
560
|
}
|
|
493
561
|
```
|
|
494
562
|
|
|
495
|
-
| Option
|
|
496
|
-
|
|
|
497
|
-
| `include`
|
|
498
|
-
| `exclude`
|
|
499
|
-
| `prependFiles`
|
|
500
|
-
| `libraries`
|
|
501
|
-
| `quirksMode`
|
|
563
|
+
| Option | Default | Description |
|
|
564
|
+
| ---------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
565
|
+
| `include` | `**/*.{js,jsx,ts,tsx,mjs,cjs,mts,cts,html,astro}` | Globs of the files with blocks, relative to the `package.json`. A glob or an array of them. Scanned before a build to assign names; stylesheet files are found from the scanned files' imports. `node_modules` and the output directory are always skipped. |
|
|
566
|
+
| `exclude` | | Globs removed from `include`. |
|
|
567
|
+
| `prependFiles` | | Files added to the start of the app's blocks and stylesheet files. See [Sharing values with prepended files](#sharing-values-with-prepended-files). |
|
|
568
|
+
| `libraries` | | Component libraries to compile, by package name, in addition to dependencies with a `pre.style` field. A config replaces the package's field, `true` uses the defaults, and `false` leaves the package out. See [Component libraries](#component-libraries). |
|
|
569
|
+
| `quirksMode` | `false` | **You probably don't want this.** Use lowercase class names only, for pages in quirks mode. Names get longer. See [Quirks mode](#quirks-mode). |
|
|
570
|
+
| `keyframeLocalization` | `false` | Give each `@keyframes` in the app's blocks and stylesheet files a generated name, used only in the block or file that defines it. See [Local keyframes](#local-keyframes). Libraries use their own setting. |
|
|
502
571
|
|
|
503
572
|
The plugin warns about keys it doesn't know, and fails the build on values of the wrong type. For completion and validation in your editor, `@pre.style/core` includes a JSON Schema for the field, at `node_modules/@pre.style/core/package.schema.json`. In VS Code, add it to your settings:
|
|
504
573
|
|
|
@@ -509,7 +578,9 @@ The plugin warns about keys it doesn't know, and fails the build on values of th
|
|
|
509
578
|
"fileMatch": ["package.json"],
|
|
510
579
|
"schema": {
|
|
511
580
|
"properties": {
|
|
512
|
-
"pre.style": {
|
|
581
|
+
"pre.style": {
|
|
582
|
+
"$ref": "./node_modules/@pre.style/core/package.schema.json"
|
|
583
|
+
}
|
|
513
584
|
}
|
|
514
585
|
}
|
|
515
586
|
}
|
|
@@ -525,27 +596,37 @@ Options about how a build writes its output go to the plugin. All options are op
|
|
|
525
596
|
preStyle({
|
|
526
597
|
lightningcss: { minify: true, targets: { safari: 16 << 16 } },
|
|
527
598
|
sourceMap: true,
|
|
528
|
-
|
|
599
|
+
layer: "pre.style",
|
|
600
|
+
quotes: "single-quote",
|
|
529
601
|
output: {
|
|
530
|
-
file:
|
|
531
|
-
banner:
|
|
602
|
+
file: "css/pre.style.css",
|
|
603
|
+
banner: "/* Generated by pre.style */",
|
|
532
604
|
},
|
|
533
605
|
});
|
|
534
606
|
```
|
|
535
607
|
|
|
536
|
-
| Option
|
|
537
|
-
|
|
|
538
|
-
| `lightningcss`
|
|
539
|
-
| `sourceMap`
|
|
540
|
-
| `
|
|
541
|
-
| `
|
|
542
|
-
| `output.
|
|
543
|
-
| `output.
|
|
608
|
+
| Option | Default | Description |
|
|
609
|
+
| --------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
610
|
+
| `lightningcss` | | [Lightning CSS options](https://lightningcss.dev/transforms.html), such as `minify`, `targets`, `drafts`, and `visitor`. A `visitor` runs before pre.style processes each block. `filename`, `code`, `sourceMap`, `projectRoot`, `inputSourceMap`, and `cssModules` are ignored. |
|
|
611
|
+
| `sourceMap` | `true` in dev, `false` in builds | Generate a source map for the CSS, mapping each class to the first block it appears in (a source map can only point to one place; the [DevTools extension](#tracing-classes-with-the-devtools-extension) lists them all). In dev, it's shown in the browser (the plugin turns on Vite's `css.devSourcemap`, unless you set it). In builds, it's written next to `output.file`. When you import `virtual:pre.style.css`, builds have no CSS source map, because Vite doesn't write them for bundled CSS. |
|
|
612
|
+
| `layer` | `false` | Wrap the CSS in a [cascade layer](https://developer.mozilla.org/docs/Web/CSS/@layer): `false` for none, `""` for an unnamed layer, or the layer's name, such as `"pre.style"` or `"vendor.pre-style"`. `@import` and `@namespace` rules stay before the layer, since they can't be inside one. `@layer` rules from blocks become layers nested in it. Browsers without cascade layers (Chrome before 99, Safari before 15.4, Firefox before 97) ignore everything inside it. |
|
|
613
|
+
| `quotes` | `'double-quote'` | Quotes around the class string that replaces each block in JS: `'single-quote'`, `'double-quote'`, or `'backtick'`. |
|
|
614
|
+
| `output.file` | `'pre.style.css'` | Path and name of the CSS file, relative to Vite's `build.outDir`. |
|
|
615
|
+
| `output.banner` | | Text added to the start of the CSS file. |
|
|
616
|
+
| `output.footer` | | Text added to the end of the CSS file. |
|
|
544
617
|
|
|
545
618
|
The CSS isn't minified unless you set `lightningcss: { minify: true }`.
|
|
546
619
|
|
|
547
620
|
Before 3.1, `include`, `exclude`, `prependFiles`, `libraries`, and `quirksMode` were plugin options. Passing them to the plugin now fails with a message pointing to `package.json`.
|
|
548
621
|
|
|
622
|
+
### Tracing classes with the DevTools extension
|
|
623
|
+
|
|
624
|
+
Classes are shared, so one class can come from many blocks, and a source map can only point to one of them. The [pre.style DevTools extension](packages/devtools) adds a **pre.style** tab to the Elements panel in Chrome and Firefox. For the selected element, it lists each pre.style rule like the Styles pane does, with a link to every block that uses it.
|
|
625
|
+
|
|
626
|
+
It works with the Vite dev server while `sourceMap` is on, which is the default in dev. Setting `sourceMap: false` turns it off. It only runs on `localhost`, `*.localhost`, loopback addresses, and hostnames you add in its settings, and sends other sites no requests.
|
|
627
|
+
|
|
628
|
+
Its links open your editor through Vite, which guesses which one you use. When the dev server runs in VS Code's terminal, the plugin sets the `LAUNCH_EDITOR` environment variable to `code` if it isn't set, which also applies to Vite's error overlay. To choose an editor yourself, set `LAUNCH_EDITOR`.
|
|
629
|
+
|
|
549
630
|
### Quirks mode
|
|
550
631
|
|
|
551
632
|
> [!WARNING]
|
|
@@ -591,10 +672,11 @@ The build fails, with the file, line, and column, when:
|
|
|
591
672
|
|
|
592
673
|
## Packages
|
|
593
674
|
|
|
594
|
-
| Package
|
|
595
|
-
|
|
|
596
|
-
| `@pre.style/core`
|
|
597
|
-
| `@pre.style/vite` | The Vite plugin.
|
|
675
|
+
| Package | Description |
|
|
676
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
677
|
+
| `@pre.style/core` | `css`, `scss`, and `cn`, the compiler at `@pre.style/core/compiler` for bundler plugins, TypeScript's content mapper for stylesheet files, and the JSON Schema for the `package.json` field. |
|
|
678
|
+
| `@pre.style/vite` | The Vite plugin. |
|
|
679
|
+
| [pre.style DevTools](packages/devtools) | A side pane for the Elements panel in Chrome and Firefox that lists every block using each class. Not published to the extension stores yet. |
|
|
598
680
|
|
|
599
681
|
## Development
|
|
600
682
|
|
package/dist/compiler/block.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export interface ParseOptions {
|
|
|
69
69
|
prepend: Record<Lang, string>;
|
|
70
70
|
sass: SassCompiler | null;
|
|
71
71
|
warn: (message: string) => void;
|
|
72
|
+
keyframeLocalization: boolean;
|
|
72
73
|
}
|
|
73
74
|
export declare const key: (value: unknown) => string;
|
|
74
75
|
export declare function parseBlock(code: string, lang: Lang, options: ParseOptions): ParsedBlock;
|
|
@@ -85,6 +86,7 @@ export declare function addDeclarations(block: {
|
|
|
85
86
|
importantDeclarations?: Declaration[];
|
|
86
87
|
} | undefined, atRules: AtRuleSegment[], selectors: SelectorList, atoms: Atom[], composes: Compose[] | null, position: Position | null): void;
|
|
87
88
|
export declare function addGlobal(rule: Rule, atRules: AtRuleSegment[], globals: GlobalRule[], position: ToPosition): void;
|
|
89
|
+
export declare function overrideKey(rule: Rule): string;
|
|
88
90
|
export declare function propertyOf(declaration: Declaration): {
|
|
89
91
|
property: string;
|
|
90
92
|
shorthand: boolean;
|
package/dist/compiler/block.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { composeVisitors, transform } from 'lightningcss';
|
|
2
2
|
import { atRuleInfo } from './at-rules.js';
|
|
3
3
|
import { expand } from './expand.js';
|
|
4
|
+
import { localizeKeyframes } from './keyframes.js';
|
|
4
5
|
import { compose, fromPlaceholder, isElement, PLACEHOLDER, repair } from './selectors.js';
|
|
5
6
|
import { splitBlock } from './split.js';
|
|
6
7
|
import { SHORTHANDS } from '../shorthands.js';
|
|
@@ -82,11 +83,11 @@ export function parseBlock(code, lang, options) {
|
|
|
82
83
|
// Sass output positions don't match the block, so scss atoms have none.
|
|
83
84
|
const position = (loc) => lang === 'css' && loc ? toBlock(loc.line, loc.column) : null;
|
|
84
85
|
parseRules(css, options.lightningcss, position, (rules) => walk(rules, [], null, parsed, position));
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
globals: parsed.globals,
|
|
88
|
-
|
|
89
|
-
};
|
|
86
|
+
const atoms = dropOverridden(parsed.atoms);
|
|
87
|
+
if (!options.keyframeLocalization)
|
|
88
|
+
return { atoms, globals: parsed.globals, composes: parsed.composes };
|
|
89
|
+
const local = localizeKeyframes(parsed.globals);
|
|
90
|
+
return { atoms: local.atoms(atoms), globals: local.globals, composes: parsed.composes };
|
|
90
91
|
}
|
|
91
92
|
// Parses CSS with Lightning CSS, and passes its rules to `collect` once the
|
|
92
93
|
// user's visitor has changed them. `position` converts error locations.
|
|
@@ -276,11 +277,12 @@ export function addGlobal(rule, atRules, globals, position) {
|
|
|
276
277
|
});
|
|
277
278
|
}
|
|
278
279
|
// The identity of an overridable at-rule: its type and name.
|
|
279
|
-
function overrideKey(rule) {
|
|
280
|
+
export function overrideKey(rule) {
|
|
280
281
|
const value = valueOf(rule);
|
|
281
282
|
switch (rule.type) {
|
|
282
283
|
case 'keyframes':
|
|
283
|
-
|
|
284
|
+
// `@-webkit-keyframes x` doesn't replace `@keyframes x`.
|
|
285
|
+
return `keyframes ${key(value.vendorPrefix ?? [])} ${key(value.name)}`;
|
|
284
286
|
case 'font-face': {
|
|
285
287
|
// A font face is identified by its family, style, weight, and stretch.
|
|
286
288
|
const descriptors = Object.fromEntries(value.properties
|
|
@@ -8,6 +8,7 @@ export type PrependFiles = string[] | {
|
|
|
8
8
|
export interface Library {
|
|
9
9
|
dir: string;
|
|
10
10
|
prependFiles?: PrependFiles;
|
|
11
|
+
keyframeLocalization?: boolean;
|
|
11
12
|
}
|
|
12
13
|
export interface CompilerOptions {
|
|
13
14
|
prependFiles?: PrependFiles;
|
|
@@ -17,6 +18,8 @@ export interface CompilerOptions {
|
|
|
17
18
|
root?: string;
|
|
18
19
|
warn?: (message: string) => void;
|
|
19
20
|
quirksMode?: boolean;
|
|
21
|
+
keyframeLocalization?: boolean;
|
|
22
|
+
layer?: false | string;
|
|
20
23
|
}
|
|
21
24
|
export interface Block {
|
|
22
25
|
code: string;
|
|
@@ -34,6 +37,23 @@ export interface CompiledStylesheet {
|
|
|
34
37
|
exports: [name: string, classString: string][];
|
|
35
38
|
dependencies: string[];
|
|
36
39
|
}
|
|
40
|
+
export interface Source {
|
|
41
|
+
file: string;
|
|
42
|
+
line: number;
|
|
43
|
+
column: number;
|
|
44
|
+
}
|
|
45
|
+
export interface ClassUsage {
|
|
46
|
+
className: string;
|
|
47
|
+
selector: string;
|
|
48
|
+
atRules: string[];
|
|
49
|
+
declaration: string;
|
|
50
|
+
property: string;
|
|
51
|
+
covers: string[];
|
|
52
|
+
important: boolean;
|
|
53
|
+
specificity: [ids: number, classes: number, types: number];
|
|
54
|
+
order: number;
|
|
55
|
+
sources: Source[];
|
|
56
|
+
}
|
|
37
57
|
export declare function createCompiler(options?: CompilerOptions): Promise<Compiler>;
|
|
38
58
|
export declare class Compiler {
|
|
39
59
|
#private;
|
|
@@ -45,6 +65,8 @@ export declare class Compiler {
|
|
|
45
65
|
classString(block: Block): string;
|
|
46
66
|
dependencies(block: Block): string[];
|
|
47
67
|
classNames(sheet: Stylesheet): string[];
|
|
68
|
+
usages(classNames: Iterable<string>): ClassUsage[];
|
|
69
|
+
forgetSources(file: string): void;
|
|
48
70
|
stylesheet(sheet: Stylesheet): CompiledStylesheet;
|
|
49
71
|
css(): Printed;
|
|
50
72
|
cnTable(): CnTable;
|