@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 CHANGED
@@ -1,11 +1,11 @@
1
1
  # pre.style
2
2
 
3
- [![npm version](https://badge.fury.io/js/pre.style.svg)](https://www.npmjs.com/package/pre.style)
3
+ [![npm version](https://img.shields.io/npm/v/@pre.style/core/next)](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 '@pre.style/core';
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{background-color:#0071ba}
29
- .C{color:#fff}
30
- .E{padding-block-start:.5em}
31
- .D{padding-block-end:.5em}
32
- .A:hover{background-color:#005a94}
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{padding-block-start:1em}
35
- .F{padding-block-end:1em}
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 'vite';
63
- import preStyle from '@pre.style/vite';
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 '@pre.style/core';
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 'virtual:pre.style.css';
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 'astro/config';
110
- import preStyle from '@pre.style/vite';
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 `` 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.
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 '@pre.style/core';
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 `& a` */
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 { opacity: 0; }
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 './button.css';
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 '@pre.style/core';
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 { button, 'primary-button' as primaryButton } from './button.css' with { type: 'pre.style' };
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 { padding-top: 1rem; }
280
- .title { color: black; }
281
- .card:hover .title { color: red; }
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{padding-top:1rem}
286
- .C{color:#000}
287
- .A:hover .B{color:red}
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 { color: gray; padding: 1rem; }
301
- .primary { composes: base; color: blue; }
302
- .wide { composes: card from './card.css'; }
303
- .legacy { composes: old-btn from global; }
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": [{ "package": "@pre.style/core", "extensions": [".css", ".scss"] }]
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 '*.css' {
384
+ declare module "*.css" {
331
385
  const classes: { readonly [name: string]: string };
332
386
  export = classes;
333
387
  }
334
- declare module '*.scss' {
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 './button.css' with { type: 'pre.style' };
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 | Default | Description |
415
- | -------------- | ---------------------------- | ----------- |
416
- | `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. |
417
- | `exclude` | | Globs removed from `include`. |
418
- | `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. |
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`margin: auto;`;
496
+ css`
497
+ margin: auto;
498
+ `;
442
499
  ```
443
500
 
444
501
  ```css
445
- .D{margin-top:auto}
446
- .C{margin-right:auto}
447
- .A{margin-bottom:auto}
448
- .B{margin-left:auto}
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`padding: var(--space); padding-top: 0;`;
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 | Default | Description |
496
- | -------------- | ------------------------------------------------- | ----------- |
497
- | `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. |
498
- | `exclude` | | Globs removed from `include`. |
499
- | `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). |
500
- | `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). |
501
- | `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). |
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": { "$ref": "./node_modules/@pre.style/core/package.schema.json" }
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
- quotes: 'single-quote',
599
+ layer: "pre.style",
600
+ quotes: "single-quote",
529
601
  output: {
530
- file: 'css/pre.style.css',
531
- banner: '/* Generated by pre.style */',
602
+ file: "css/pre.style.css",
603
+ banner: "/* Generated by pre.style */",
532
604
  },
533
605
  });
534
606
  ```
535
607
 
536
- | Option | Default | Description |
537
- | -------------- | ------------------------------------------------- | ----------- |
538
- | `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. |
539
- | `sourceMap` | `false` | Generate a source map for the CSS, mapping each class to the first block it appears in. In dev, it's shown in the browser (the plugin turns on Vite's `css.devSourcemap`). 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. |
540
- | `quotes` | `'double-quote'` | Quotes around the class string that replaces each block in JS: `'single-quote'`, `'double-quote'`, or `'backtick'`. |
541
- | `output.file` | `'pre.style.css'` | Path and name of the CSS file, relative to Vite's `build.outDir`. |
542
- | `output.banner`| | Text added to the start of the CSS file. |
543
- | `output.footer`| | Text added to the end of the CSS file. |
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 | Description |
595
- | ----------------------- | ------------------------------------------------------ |
596
- | `@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. |
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
 
@@ -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;
@@ -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
- return {
86
- atoms: dropOverridden(parsed.atoms),
87
- globals: parsed.globals,
88
- composes: parsed.composes,
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
- return `keyframes ${key(value.name)}`;
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;