cssints 0.10.0 → 0.12.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.
Files changed (144) hide show
  1. package/dist/clay-types.d.mts +1 -1
  2. package/dist/clay.mjs +2 -2
  3. package/dist/{contrast-Dw6gXoO3.mjs → contrast-B1QrUfME.mjs} +1 -1
  4. package/dist/group-common-DeOjPus2.d.mts +1 -0
  5. package/dist/{group-types-D1m9Whs0.d.mts → group-types-e0K9k9bI.d.mts} +1 -1
  6. package/dist/groups/baseline-2015/with-downstream.d.mts +3 -3
  7. package/dist/groups/baseline-2015.d.mts +3 -3
  8. package/dist/groups/baseline-2016/with-downstream.d.mts +3 -3
  9. package/dist/groups/baseline-2016.d.mts +3 -3
  10. package/dist/groups/baseline-2017/with-downstream.d.mts +3 -3
  11. package/dist/groups/baseline-2017.d.mts +3 -3
  12. package/dist/groups/baseline-2018/with-downstream.d.mts +3 -3
  13. package/dist/groups/baseline-2018.d.mts +3 -3
  14. package/dist/groups/baseline-2019/with-downstream.d.mts +3 -3
  15. package/dist/groups/baseline-2019.d.mts +3 -3
  16. package/dist/groups/baseline-2020/with-downstream.d.mts +3 -3
  17. package/dist/groups/baseline-2020.d.mts +3 -3
  18. package/dist/groups/baseline-2021/with-downstream.d.mts +3 -3
  19. package/dist/groups/baseline-2021.d.mts +3 -3
  20. package/dist/groups/baseline-2022/with-downstream.d.mts +3 -3
  21. package/dist/groups/baseline-2022.d.mts +3 -3
  22. package/dist/groups/baseline-2023/with-downstream.d.mts +3 -3
  23. package/dist/groups/baseline-2023.d.mts +3 -3
  24. package/dist/groups/baseline-2024/with-downstream.d.mts +3 -3
  25. package/dist/groups/baseline-2024.d.mts +3 -3
  26. package/dist/groups/baseline-2025/with-downstream.d.mts +3 -3
  27. package/dist/groups/baseline-2025.d.mts +3 -3
  28. package/dist/groups/baseline-2026/with-downstream.d.mts +1 -1
  29. package/dist/groups/baseline-2026.d.mts +1 -1
  30. package/dist/groups/compositing-2.d.mts +3 -3
  31. package/dist/groups/css-align-3.d.mts +3 -3
  32. package/dist/groups/css-anchor-position-1.d.mts +3 -3
  33. package/dist/groups/css-anchor-position-2.d.mts +3 -3
  34. package/dist/groups/css-animations-1.d.mts +3 -3
  35. package/dist/groups/css-animations-2.d.mts +3 -3
  36. package/dist/groups/css-backgrounds-3.d.mts +3 -3
  37. package/dist/groups/css-backgrounds-4.d.mts +3 -3
  38. package/dist/groups/css-borders-4.d.mts +3 -3
  39. package/dist/groups/css-box-4.d.mts +3 -3
  40. package/dist/groups/css-break-4.d.mts +3 -3
  41. package/dist/groups/css-cascade-5.d.mts +3 -3
  42. package/dist/groups/css-cascade-6.d.mts +3 -3
  43. package/dist/groups/css-color-4.d.mts +3 -3
  44. package/dist/groups/css-color-5.d.mts +3 -3
  45. package/dist/groups/css-color-6.d.mts +3 -3
  46. package/dist/groups/css-color-adjust-1.d.mts +3 -3
  47. package/dist/groups/css-color-hdr-1.d.mts +3 -3
  48. package/dist/groups/css-conditional-3.d.mts +3 -3
  49. package/dist/groups/css-conditional-4.d.mts +3 -3
  50. package/dist/groups/css-conditional-5.d.mts +3 -3
  51. package/dist/groups/css-contain-2.d.mts +3 -3
  52. package/dist/groups/css-content-3.d.mts +3 -3
  53. package/dist/groups/css-counter-styles-3.d.mts +3 -3
  54. package/dist/groups/css-display-4.d.mts +3 -3
  55. package/dist/groups/css-easing-2.d.mts +3 -3
  56. package/dist/groups/css-env-1.d.mts +3 -3
  57. package/dist/groups/css-flexbox-1.d.mts +3 -3
  58. package/dist/groups/css-fonts-4.d.mts +3 -3
  59. package/dist/groups/css-fonts-5.d.mts +3 -3
  60. package/dist/groups/css-forms-1.d.mts +3 -3
  61. package/dist/groups/css-gaps-1.d.mts +3 -3
  62. package/dist/groups/css-gcpm-3.d.mts +3 -3
  63. package/dist/groups/css-gcpm-4.d.mts +3 -3
  64. package/dist/groups/css-grid-2.d.mts +3 -3
  65. package/dist/groups/css-grid-3.d.mts +3 -3
  66. package/dist/groups/css-images-3.d.mts +3 -3
  67. package/dist/groups/css-images-4.d.mts +3 -3
  68. package/dist/groups/css-images-5.d.mts +3 -3
  69. package/dist/groups/css-inline-3.d.mts +3 -3
  70. package/dist/groups/css-lists-3.d.mts +3 -3
  71. package/dist/groups/css-logical-1.d.mts +3 -3
  72. package/dist/groups/css-masking-1.d.mts +3 -3
  73. package/dist/groups/css-multicol-2.d.mts +3 -3
  74. package/dist/groups/css-overflow-3.d.mts +3 -3
  75. package/dist/groups/css-overflow-4.d.mts +3 -3
  76. package/dist/groups/css-overflow-5.d.mts +3 -3
  77. package/dist/groups/css-overscroll-1.d.mts +3 -3
  78. package/dist/groups/css-page-3.d.mts +3 -3
  79. package/dist/groups/css-page-floats-3.d.mts +3 -3
  80. package/dist/groups/css-position-3.d.mts +3 -3
  81. package/dist/groups/css-position-4.d.mts +3 -3
  82. package/dist/groups/css-rhythm-1.d.mts +3 -3
  83. package/dist/groups/css-round-display-1.d.mts +3 -3
  84. package/dist/groups/css-ruby-1.d.mts +3 -3
  85. package/dist/groups/css-scroll-anchoring-1.d.mts +3 -3
  86. package/dist/groups/css-scroll-snap-1.d.mts +3 -3
  87. package/dist/groups/css-scroll-snap-2.d.mts +3 -3
  88. package/dist/groups/css-scrollbars-1.d.mts +3 -3
  89. package/dist/groups/css-shapes-1.d.mts +3 -3
  90. package/dist/groups/css-shapes-2.d.mts +3 -3
  91. package/dist/groups/css-size-adjust-1.d.mts +3 -3
  92. package/dist/groups/css-sizing-3.d.mts +3 -3
  93. package/dist/groups/css-sizing-4.d.mts +3 -3
  94. package/dist/groups/css-speech-1.d.mts +3 -3
  95. package/dist/groups/css-tables-3.d.mts +3 -3
  96. package/dist/groups/css-text-3.d.mts +3 -3
  97. package/dist/groups/css-text-4.d.mts +3 -3
  98. package/dist/groups/css-text-decor-3.d.mts +3 -3
  99. package/dist/groups/css-text-decor-4.d.mts +3 -3
  100. package/dist/groups/css-transforms-1.d.mts +3 -3
  101. package/dist/groups/css-transforms-2.d.mts +3 -3
  102. package/dist/groups/css-transitions-1.d.mts +3 -3
  103. package/dist/groups/css-transitions-2.d.mts +3 -3
  104. package/dist/groups/css-ui-4.d.mts +3 -3
  105. package/dist/groups/css-values-4.d.mts +3 -3
  106. package/dist/groups/css-values-5.d.mts +3 -3
  107. package/dist/groups/css-variables-2.d.mts +2 -2
  108. package/dist/groups/css-view-transitions-2.d.mts +3 -3
  109. package/dist/groups/css-viewport.d.mts +3 -3
  110. package/dist/groups/css-will-change-1.d.mts +3 -3
  111. package/dist/groups/css-writing-modes-4.d.mts +3 -3
  112. package/dist/groups/css2.d.mts +3 -3
  113. package/dist/groups/fill-stroke-3.d.mts +3 -3
  114. package/dist/groups/filter-effects-1.d.mts +3 -3
  115. package/dist/groups/filter-effects-2.d.mts +3 -3
  116. package/dist/groups/limited-availability.d.mts +1 -1
  117. package/dist/groups/mediaqueries-4.d.mts +3 -3
  118. package/dist/groups/mediaqueries-5.d.mts +3 -3
  119. package/dist/groups/motion-1.d.mts +3 -3
  120. package/dist/groups/newly-available/with-downstream.d.mts +3 -3
  121. package/dist/groups/newly-available.d.mts +3 -3
  122. package/dist/groups/not-discouraged.d.mts +3 -3
  123. package/dist/groups/scroll-animations-1.d.mts +3 -3
  124. package/dist/groups/selectors-4.d.mts +2 -2
  125. package/dist/groups/selectors-5.d.mts +2 -2
  126. package/dist/groups/widely-available/with-downstream.d.mts +3 -3
  127. package/dist/groups/widely-available.d.mts +3 -3
  128. package/dist/index.mjs +3 -3
  129. package/dist/{instrument-D68RkfDU.mjs → instrument-QGVM1E1B.mjs} +3 -2
  130. package/dist/plugin-types.d.mts +1 -1
  131. package/dist/plugin.d.mts +1 -1
  132. package/dist/{scope-xUS8MykU.d.mts → scope-CYtpn6RD.d.mts} +10 -8
  133. package/dist/{sheet-qCuMvyUo.mjs → sheet-BVksF2ST.mjs} +8 -3
  134. package/dist/surface.d.mts +1 -1
  135. package/dist/{theme-C5cmxs1-.mjs → theme-Le0IAI8N.mjs} +12 -2
  136. package/dist/{theme-types-C5OAtybo.d.mts → theme-types-D8PVAr7H.d.mts} +10 -8
  137. package/dist/tui-types.d.mts +1 -1
  138. package/dist/tui.mjs +3 -3
  139. package/dist/types.d.mts +1 -1
  140. package/dist/vite.d.mts +11 -1
  141. package/dist/vite.mjs +30 -15
  142. package/docs/API.md +45 -21
  143. package/package.json +2 -2
  144. package/dist/group-common-ClVCSlR6.d.mts +0 -1
package/dist/vite.d.mts CHANGED
@@ -105,7 +105,7 @@ export declare const renderSheet: (entries: Iterable<string>) => Effect.Effect<s
105
105
  export declare const targets: import("lightningcss").Targets;
106
106
  /** `build: { cssTarget }`, the browserslist query of `targets`, so a minified build keeps `firstThatWorks` fallbacks. */
107
107
  export declare const cssTarget: string[];
108
- export default function cssints({ inner, exclude, devtools, opencode }?: {
108
+ export default function cssints({ inner, exclude, devtools, opencode, evaluation }?: {
109
109
  inner?: boolean;
110
110
  /**
111
111
  * Files the plugin leaves alone, in Vite's filter style (`createFilter`: a picomatch glob, a RegExp or an array of them;
@@ -124,5 +124,15 @@ export default function cssints({ inner, exclude, devtools, opencode }?: {
124
124
  * and tokens plus the instruction. Needs `@opencode/client` installed. Off by default; a build has none of it.
125
125
  */
126
126
  opencode?: boolean | OpenCodeOptions;
127
+ /**
128
+ * The server that evaluates sites, when the app's own ssr environment cannot: a runner that sets `browser` for it (vitest's
129
+ * browser mode) serves every dependency as ESM — its CJS ones fail — and resolves the library to the browser entry. The plugin
130
+ * then starts its own server with the app's aliases, conditions and `noExternal`. When that environment inlines everything
131
+ * (`ssr.noExternal: true`), the list cannot be copied (CJS would break), so `inline` names what a framework needs inlined to
132
+ * resolve its own builds: `["solid-js", "@solidjs/web"]` for Solid.
133
+ */
134
+ evaluation?: {
135
+ readonly inline?: ReadonlyArray<string | RegExp>;
136
+ };
127
137
  }): Plugin[];
128
138
  export type { DevTable, OpenCodeOptions };
package/dist/vite.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { c as EvalError, d as MacroError, f as MemberError, i as forgetWarnings, l as HookError, n as forget, p as SiteMissingError, t as Registry } from "./registry-8sYvlzyn.mjs";
2
- import { C as fallbackEntries, T as runtimeNames, a as closeNames, b as DERIVED, c as layerEntries, f as themedEntries, l as layerStatements, m as usesDerived, n as addGlobal, o as globalEntries, r as addLayers, s as globalNames, t as LAYERS, u as renderSheet, v as kernelEntries, w as runtimeModule, x as RUNTIME_ID } from "./sheet-qCuMvyUo.mjs";
3
- import { a as instrument, c as writeSite, o as runtimeImport, s as tagged } from "./instrument-D68RkfDU.mjs";
4
- import { r as verifyChecks } from "./contrast-Dw6gXoO3.mjs";
2
+ import { C as fallbackEntries, T as runtimeNames, a as closeNames, b as DERIVED, c as layerEntries, f as themedEntries, l as layerStatements, m as usesDerived, n as addGlobal, o as globalEntries, r as addLayers, s as globalNames, t as LAYERS, u as renderSheet, v as kernelEntries, w as runtimeModule, x as RUNTIME_ID } from "./sheet-BVksF2ST.mjs";
3
+ import { a as instrument, c as writeSite, o as runtimeImport, s as tagged } from "./instrument-QGVM1E1B.mjs";
4
+ import { r as verifyChecks } from "./contrast-B1QrUfME.mjs";
5
5
  import { i as serverId, n as gitRoot, o as sessionOf, r as register } from "./devtools-link-DN91p7g5.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import { targets as targets$1, useTargets } from "@cssints/css-grammar/support";
@@ -652,16 +652,20 @@ const locate = Effect.fn("cssints.locate")(function* (e, code, id) {
652
652
  }
653
653
  return yield* e;
654
654
  });
655
- function cssints({ inner = false, exclude, devtools = false, opencode = false } = {}) {
655
+ function cssints({ inner = false, exclude, devtools = false, opencode = false, evaluation } = {}) {
656
656
  const excluded = [exclude ?? []].flat().length ? createFilter(exclude) : () => false;
657
657
  let server;
658
- let ownServer = false;
659
658
  let runner;
660
659
  let build = false;
661
660
  let root = process.cwd();
662
661
  let rootTargets;
663
662
  let cssPlugins = [];
664
663
  let resolveOf = {};
664
+ const evaluator = {
665
+ server: void 0,
666
+ own: false,
667
+ needed: false
668
+ };
665
669
  const usedBy = /* @__PURE__ */ new Map();
666
670
  const depsOf = /* @__PURE__ */ new Map();
667
671
  const inflight = /* @__PURE__ */ new Set();
@@ -809,7 +813,7 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
809
813
  if (inner) return void 0;
810
814
  const parsed = yield* instrument(code, id, true, !!devtools && !build);
811
815
  if (!parsed) return void 0;
812
- const env = server.environments.ssr;
816
+ const env = evaluator.server.environments.ssr;
813
817
  if (!runner || runner.isClosed()) runner = createServerModuleRunner(env, {
814
818
  hmr: false,
815
819
  sourcemapInterceptor: "prepareStackTrace",
@@ -820,7 +824,7 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
820
824
  return yield* clientTransform(code, id, parsed, env, (w) => ctx.warn(w), watch).pipe(Effect.ensuring(Effect.sync(() => inflight.delete(id))));
821
825
  });
822
826
  const startServer = Effect.fn("cssints.buildStart")(function* () {
823
- server = yield* Effect.tryPromise({
827
+ const started = yield* Effect.tryPromise({
824
828
  try: () => createServer({
825
829
  configFile: false,
826
830
  root,
@@ -843,11 +847,13 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
843
847
  cause
844
848
  })
845
849
  });
846
- ownServer = true;
850
+ evaluator.own = true;
851
+ evaluator.server = started;
852
+ server ??= started;
847
853
  });
848
854
  const stopServer = Effect.fn("cssints.closeBundle")(function* () {
849
- if (!ownServer || !server) return;
850
- const s = server;
855
+ if (!evaluator.own || !evaluator.server) return;
856
+ const s = evaluator.server;
851
857
  yield* Effect.tryPromise({
852
858
  try: () => s.close(),
853
859
  catch: (cause) => new HookError({
@@ -856,8 +862,10 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
856
862
  cause
857
863
  })
858
864
  });
859
- server = runner = void 0;
860
- ownServer = false;
865
+ if (server === s) server = void 0;
866
+ evaluator.server = void 0;
867
+ evaluator.own = false;
868
+ runner = void 0;
861
869
  });
862
870
  const renderChunk = Effect.fn("cssints.renderChunk")(function* (ctx, chunk) {
863
871
  if (inner || !Object.hasOwn(chunk.modules, SHEET)) return null;
@@ -931,12 +939,18 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
931
939
  buildMap = build && !inner && config.build.sourcemap;
932
940
  root = config.root;
933
941
  if (!inner) rootTargets = Effect.runSync(targets$1(void 0, root));
942
+ evaluator.needed = config.environments.ssr?.resolve?.conditions?.includes("browser") === true;
934
943
  const ssr = config.environments.ssr?.resolve;
935
944
  resolveOf = {
936
- resolve: { alias: config.resolve.alias },
945
+ resolve: {
946
+ alias: config.resolve.alias,
947
+ dedupe: config.resolve.dedupe
948
+ },
937
949
  ...ssr && { environments: { ssr: { resolve: {
938
950
  conditions: ssr.conditions,
939
- externalConditions: ssr.externalConditions
951
+ externalConditions: ssr.externalConditions,
952
+ noExternal: [...Array.isArray(ssr.noExternal) ? ssr.noExternal : [], ...evaluation?.inline ?? []],
953
+ ...ssr.external !== void 0 && { external: ssr.external }
940
954
  } } } }
941
955
  };
942
956
  cssPlugins = ["vite:css", "vite:css-post"].map((n) => config.plugins.find((p) => p.name === n));
@@ -944,6 +958,7 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
944
958
  configureServer(s) {
945
959
  server = s;
946
960
  if (inner) return;
961
+ evaluator.server = evaluator.needed ? void 0 : s;
947
962
  s.environments.client.hot.on("cssints:sheet", (v) => {
948
963
  if (!s.environments.client.moduleGraph.getModuleById(SHEET)?.transformResult?.code.includes(v)) Effect.runSync(reloadSheet());
949
964
  });
@@ -951,7 +966,7 @@ function cssints({ inner = false, exclude, devtools = false, opencode = false }
951
966
  buildStart() {
952
967
  if (inner) return;
953
968
  if (build) forgetWarnings();
954
- if (server) return;
969
+ if (evaluator.server) return;
955
970
  return run(hook("vite.buildStart", root, startServer()));
956
971
  },
957
972
  buildEnd() {
package/docs/API.md CHANGED
@@ -327,7 +327,31 @@ css.createGlobalTheme(t, css.hover, { color: { bg: "red" } }); // error: a pseud
327
327
  ```
328
328
 
329
329
  - **Types:** `$type` is inherited through groups, and a token needs one (it is not guessed from the value). It maps to a token type: `color` to `color`, `dimension` to `length`, `number` to `number`, `duration` to `time`, `fontWeight` to `number` (keywords such as `bold` become 700), `cubicBezier` to `easingFunction`, `shadow` to `shadow`. `fontFamily`, `strokeStyle` and the other composite types (`border`, `transition`, `gradient`, `typography`) are an error. A value is a CSS string of the type's grammar, or the DTCG form: `{ colorSpace, components, alpha? }`, `{ value, unit }` (`px` or `rem`, `ms` or `s`), a number, `[x1, y1, x2, y2]` (`cubic-bezier(x1, y1, x2, y2)`), `{ color, offsetX, offsetY, blur, spread, inset? }` or an array of them (the parts are DTCG values or CSS strings, without references). The initial value follows the rule of "Tokens": `{ value: 1, unit: "rem" }` is `initial-value:16px` and `:root{--space-md:1rem}`.
330
+ - **A leaf may be its value:** when the group's `$type` is in scope, a token is the value itself, as a theme's overrides take it — `color: { $type: "color", bg: "#fff", link: "{color.accent}" }`. A string is a value of the group's type, an alias `{path}` included, and a number is one for `number` and `fontWeight`; anything else stays `{ $value }` as in DTCG: a DTCG object (`{ colorSpace, components }`, `{ value, unit }`, a shadow), and a token with its own `$type`, `$description` or `$extensions`. A value with no `$type` in its group is an error, in the types and at build time (a type is not guessed from the value). The same tokens, spelled both ways:
331
+
332
+ ```ts
333
+ import * as css from "cssints" with { type: "cssints" };
334
+
335
+ const short = css.createTokens({
336
+ color: { $type: "color", bg: "#fff", edge: "oklch(80% 0.02 259)" },
337
+ space: { $type: "dimension", sm: "4px", md: "8px" },
338
+ hue: { $type: "number", accent: 345 },
339
+ });
340
+ const long = css.createTokens({
341
+ color: {
342
+ $type: "color",
343
+ bg: { $value: "#fff" },
344
+ edge: { $value: "oklch(80% 0.02 259)" },
345
+ },
346
+ space: { $type: "dimension", sm: { $value: "4px" }, md: { $value: { value: 8, unit: "px" } } },
347
+ hue: { $type: "number", accent: { $value: 345 } },
348
+ });
349
+ css.padding(short.space.md, long.space.md);
350
+ css.createTokens({ color: { bg: "#fff" } }); // error: no $type in scope
351
+ ```
352
+
330
353
  - **Names:** the variable name is the kebab-case path (`--color-bg`). A second argument to `createTokens` maps a path (an array of names) to a name, or to `{ var, inherit }`.
354
+
331
355
  - **Support warnings** (cssints-tuyw): a token value goes through the same support check as a property value, since it reaches the same browsers: the initial value of `token.<type>()` and of a `createTokens()` leaf, an override of `createGlobalTheme()` (its references replaced by their literals) and a `token.set()` value. It is checked as a value of a property that takes its type (`color` for a colour, `width` for a length, `transform` for a transform list; `custom-ident` and `resolution` have none), so `oklch()` warns for a target without it, like `color: oklch(...)`. A warning is given once per token (or theme value) and BCD feature per build, and a dev server gives it again after each edit, as for properties. It names the token path and, for a theme, the theme: `createTokens(): color.accent value: "oklch()" in "oklch(0.62 0.19 259)" is not supported by chrome 109 (css.types.color.oklch)`, `createGlobalTheme(): color.accent value in .light: "oklch()" in ...`, `token.color() initial value of --name: ...`, `token.set() value of --name: ...`. An alias has the same warning for its own token, since its `@property` rule holds the same literal. A value that goes into the sheet gets no warning when a fallback below handles it for the targets (the bullet "No warning for what LightningCSS lowers" below says what LightningCSS lowers); an inline `token.set()` value never goes through LightningCSS and keeps the warning, as does a value LightningCSS cannot lower (`color-mix()` over a token in a class).
332
356
  - **Fallbacks for older targets** (cssints-33pa): a browser that cannot parse the initial value of an `@property` rule (`oklch()` in Chrome 109) drops the rule, and the token has no value at all. When some target lacks a value, the engine writes it for that target (transforming `--x:value` through LightningCSS with the lacking targets and taking the first declaration, `#db4aa7` for `oklch(0.637 0.203 345)`) and nothing changes for a target set that has it, byte for byte:
333
357
  - **A plain token** (`token.color("oklch(0.637 0.203 345)", "accent")`, a `createTokens()` leaf): `@property --accent{…initial-value:#db4aa7}` and `:root{--accent:oklch(0.637 0.203 345)}`, which LightningCSS lowers like any custom property (`--accent:#db4aa7`, then the wide-gamut `lab()` under `@supports (color: lab(0% 0 0))`). A browser that parses the value gets the wide one, so a modern browser reads the same colour as before, written as `lab()` (`:where(*)` stands for `:root` when the token does not inherit).
@@ -857,7 +881,7 @@ export const hidden = ring().core; // error: no such method
857
881
  - **Namespaces.** Everything a scope declares is the scope's own. In the CSS of a kernel, a runtime or a global, and in what `emit` and `build` return, `--_x` is the custom property `--<scope>-x`; in a kernel or a runtime `&` is the class the engine mints for the kernel (`_<scope>-<entry>`, `_ring-core`) and `&(mod.key)` that of the kernel `key` of an embedded scope. A runtime or conflicts entry takes the class of the first kernel in the `uses` of the member. Scope names are lowercase letters, digits and `-`; `cssints` and `derived` are the engine's.
858
882
  - **`uses`** lists what a member needs, by key: kernels, globals, layers, runtimes and conflicts of the scope, or `mod.key` of an embedded one (the types reject a name that is none of these, or a private one). A call member may add more in what `build` returns.
859
883
  - **`group: true`** on a chain or call member makes every style of the member carry the group marker `_g-<scope>`, after the markers of its kernels: `sticky: { uses: ["core"], group: true, chain: {...} }` in scope `stuck` gives `_stuck-core _g-stuck _x`, and `within(attr("data-stuck", "top", "~="), "stuck")(...)` reads that ancestor (2026-10-08, cssints-sbs8). The group's name is the scope's, unique in the process, so two plugins never share one; a user's `group("stuck")` is the same group, so do not name your own groups after a scope you use. It is a marker like a kernel's: a condition around the member with no declaration of its own is a build error (see "Conditions and layers").
860
- - **Kernels** are global CSS, registered once per scope entry (key `<scope>.<entry>`) on first use: the CSS goes into layer `_.k`, below every class layer, and `atProperty` (the `@property` rules) at the top of the sheet. So a kernel cannot be conditional per site: a condition around a member that has only its marker is a build error (see "Conditions and layers"); give the member a method or arguments that set custom properties, which a condition can wrap. A kernel can also be written as styles, `css: (css) => [css.outline("var(--_w)", "solid", "var(--_c)"), css.outlineOffset("2px")]`, which prints the declarations under the kernel's class: they are checked like a user's (grammar, prose rules), conditions, `nest()`, `vars()` and `keyframes()` names are allowed (see below), `firstThatWorks()` and a member's marker are not. Build errors, at the call site: two keys that declare one custom property, two keys that print one marker, and two kernels written as styles in one member's `uses` that set properties of the element that meet (the same property, a shorthand and its longhand, a logical and a physical side, as in `cn()`): `cssints: x: kernels run and view both set animation, animation-timeline (they are one element's styles and print in no set order): write those in one kernel`. Kernels are printed in `_.k` sorted by key (`<scope>.<entry>`), whatever the order of `uses` or of the modules, so two of one member never decide between themselves; in one kernel the sheet's order holds (a shorthand before its longhands). A raw kernel derives no properties and is not compared (2026-10-08, cssints-life). A kernel's `requires` (BCD keys) is a build warning for a target that lacks one, never an error. A key that is also in the `polyfills` of a runtime in the member's `uses` is covered: it warns only for the targets that runtime does not reach (a `parentVars` runtime below `@property`, see below), and a fallback of CSS or a `script` covers it everywhere. The support warning of a declaration in a kernel written as styles is covered by the same rule, by its BCD key (the one in parentheses at the end of the warning): `core: { css: (css) => [css.borderRadius("var(--_r)"), css.cornerShape("squircle")] }` beside `mask: { polyfills: ["css.properties.corner-shape"], css: "..." }` in `uses` warns for nobody, so a plugin keeps derived conflicts without a raw kernel (2026-10-08, cssints-rp0e); a warning or an error of such a declaration prints its value as the sheet does, `var(--squircle-r)`, not `var(--_r)`. As in every support warning, a BCD `partial_implementation` counts as support, because most partial entries are edge cases; an entry `{ key, exact: true }` counts it as lacking, for a feature whose partial form gives other results (`surface()` asks for `{ key: "css.types.color.oklch.relative_syntax", exact: true }`), and the warning says so: `(a partial implementation counts as lacking)`.
884
+ - **Kernels** are global CSS, registered once per scope entry (key `<scope>.<entry>`) on first use: the CSS goes into layer `_.k`, below every class layer, and `atProperty` (the `@property` rules) at the top of the sheet. So a kernel cannot be conditional per site: a condition around a member that has only its marker is a build error (see "Conditions and layers"); give the member a method or arguments that set custom properties, which a condition can wrap. A kernel can also be written as styles, `css: (css) => [css.outline("var(--_w)", "solid", "var(--_c)"), css.outlineOffset("2px")]`, which prints the declarations under the kernel's class: they are checked like a user's (grammar, prose rules), conditions, `nest()`, `vars()` and `keyframes()` names are allowed (see below), `firstThatWorks()` and a member's marker are not. Build errors, at the call site: two kernels of one scope that declare one of its own custom properties (`--reveal-k`), two kernels of different scopes that declare a custom property neither of them owns (`--bx-w`), two keys that print one marker, and two kernels written as styles in one member's `uses` that set properties of the element that meet (the same property, a shorthand and its longhand, a logical and a physical side, as in `cn()`): `cssints: x: kernels run and view both set animation, animation-timeline (they are one element's styles and print in no set order): write those in one kernel`. Kernels are printed in `_.k` sorted by key (`<scope>.<entry>`), whatever the order of `uses` or of the modules, so two of one member never decide between themselves; in one kernel the sheet's order holds (a shorthand before its longhands). A scope **may** declare a custom property another scope owns (`reveal()`'s kernel sets motion's `--motion-*`): that is reuse, and the two can sit on one page, while two of one scope may not share a short name of their own. A raw kernel derives no properties and is not compared (2026-10-08, cssints-life). A kernel's `requires` (BCD keys) is a build warning for a target that lacks one, never an error. A key that is also in the `polyfills` of a runtime in the member's `uses` is covered: it warns only for the targets that runtime does not reach (a `parentVars` runtime below `@property`, see below), and a fallback of CSS or a `script` covers it everywhere. The support warning of a declaration in a kernel written as styles is covered by the same rule, by its BCD key (the one in parentheses at the end of the warning): `core: { css: (css) => [css.borderRadius("var(--_r)"), css.cornerShape("squircle")] }` beside `mask: { polyfills: ["css.properties.corner-shape"], css: "..." }` in `uses` warns for nobody, so a plugin keeps derived conflicts without a raw kernel (2026-10-08, cssints-rp0e); a warning or an error of such a declaration prints its value as the sheet does, `var(--squircle-r)`, not `var(--_r)`. As in every support warning, a BCD `partial_implementation` counts as support, because most partial entries are edge cases; an entry `{ key, exact: true }` counts it as lacking, for a feature whose partial form gives other results (`surface()` asks for `{ key: "css.types.color.oklch.relative_syntax", exact: true }`), and the warning says so: `(a partial implementation counts as lacking)`.
861
885
  - **Chain members** (`chain: { method: { args, spacing?, excludes?, emit } }`) give `() => chain`. `args` is the grammar of the method's parts, checked in the types (the error is on the bad argument and says `ring.width: unexpected "red" ...`) and again at build time. `spacing` makes a lone number a step of the spacing scale (0.25rem), as in `padding`. `emit` returns declarations; a custom property is allowed and its value is not checked, any other property is checked like a `css.*` one. A method is used once: the chain leaves it out. `excludes: ["darken"]` leaves other methods out after this one too, and `args: ""` makes a method that takes no value (`ink()`). A grammar must be a literal type (a `const` variable is fine; if TypeScript has widened it to `string`, the method says so: write `as const`).
862
886
  - **Call members** (`{ args, uses? }` and a function in `build()`) take their arguments by `args`: a grammar (the parts, joined by a space, as a property takes them: `args: "small | large"`), `arg<T>()` (one value of a TypeScript type, which TypeScript checks and `build` gets as it is: `arg<"home" | "star">()`), or a **tuple of positional arguments**, each a grammar (one part), `"$tokens"` (a token set from `createTokens`), `"$overrides"` (values by path for the tokens of the `$tokens` before it, checked in the types against that token set), `"$selector"` (a CSS selector list, checked in the types for brackets and quotes and at build time as a whole), `arg<T>()`, or at the end one object of named leaves (`{ "size?": "<width>", on: "<color>" }`, a key ending in `?` is optional). `build` gets them as written, grammar parts as checked text. The positional form type-checks within the per-call budget; its cost is that an error lands on the call, with the position and the reason in the message, not on the argument. `build` returns `{ decls?, uses?, globals?, themes?, layers? }`.
863
887
  - **`globals`** are global rules that are not classes (`{ rule, layer? }` in the table, or `{ css, layer? }[]` from `build`). A global is identified by its content, not by a name: the same rule from two styles is one, and editing a value replaces it. It is in the sheet of the modules whose styles carry it (as kernels are), and leaves it with them. `layer` sends a rule to a top-level layer of that name (`@layer app`); it must be declared by a `layers` entry (or `layers` from `build`: a list, or `{ layers: [...], before: true }` for layers below the engine's), or by `layers()` in a module imported before. No layer puts it in `_.k`. Unlike a kernel, two globals **may** declare the same custom property; that is what lets a look set the same `--color-*` in several source layers.
@@ -1197,26 +1221,26 @@ export const typo = mdi("clos"); // error: not an icon of mdi
1197
1221
 
1198
1222
  More plugins on `scope()`, each a package of its own with its rules and limits in its README. Import them with the attribute, like `cssints`.
1199
1223
 
1200
- | Package | Members | What it does |
1201
- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1202
- | [`@cssints/fluid`](../packages/fluid/README.md) | `fluid(min, max, { from?, to?, zoom? })`, `fluid.container(...)` | A `clamp()` that grows between two widths, computed at build time; a range that fails WCAG 1.4.4 is a build error |
1203
- | [`@cssints/layout`](../packages/layout/README.md) | `stack()`, `cluster()`, `sidebar()`, `switcher()`, `cover()`, `autoGrid()` | Every Layout primitives as chain members |
1204
- | [`@cssints/fonts`](../packages/fonts/README.md) | `font(family, { provider, ... })` → `.family()`, `.trim()` | `@font-face` and a metric-matched fallback face; cap-height trimming by `text-box`, else capsize's margins |
1205
- | [`@cssints/reset`](../packages/reset/README.md) | `reset({ media?, prose? })` | A modern reset in a top-level `@layer reset` declared before the engine's, below every style; `@cssints/reset/<baseline group>` keeps only the declarations of that group |
1206
- | [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors`, `/madoromi` | DTCG data for `createTokens` |
1207
- | [`@cssints/gradient`](../packages/gradient/README.md) | `gradient(kind, direction, from, to, easing?, stops?)` | Eased colour stops mixed in oklab at build time |
1208
- | [`@cssints/gradient-2d`](../packages/gradient-2d/README.md) | `meshGradient(mesh)`, `freeformGradient(points)` | `mesh-gradient()` / `freeform-gradient()` where the browser has them, else a runtime's canvas (this package's algorithms; lines and shapes not yet) |
1209
- | [`@cssints/color-names`](../packages/color-names/README.md) | `named(name)`, `colorNames.<sector>(name)`, `/nearest` | The Color Name List (31,939 names) as hex colours; the ten sector members keep an editor's completion short, `nearest()` is the build-time reverse lookup |
1210
- | [`@cssints/motion`](../packages/motion/README.md) | `motion().preset().duration().delay().easing()` | Animation presets over `keyframes()`, with reduced motion |
1211
- | [`@cssints/squircle`](../packages/squircle/README.md) | `squircle().radius()` | `corner-shape: squircle`, else a CSS `mask` of the same shape |
1212
- | [`@cssints/reveal`](../packages/reveal/README.md) | `reveal().preset().range().duration().easing()` | motion's entrance presets on `animation-timeline: view()`; for other targets a script plays it once on entry (delivered by the runtime) |
1213
- | [`@cssints/stuck`](../packages/stuck/README.md) | `sticky().top()`, `stuck(styles)`, `stuck("bottom")(styles)` | Styles inside a sticky element while it is stuck, by `@container scroll-state()`; for other targets an `IntersectionObserver` (delivered by the runtime) |
1214
- | [`@cssints/balance`](../packages/balance/README.md) | `balance()`, `pretty()` | `text-wrap: balance` / `pretty`; for targets without balance a script balances the lines (delivered by the runtime) |
1215
- | [`@cssints/masonry`](../packages/masonry/README.md) | `masonry().columns().gap()` | `display: grid-lanes`, else CSS `columns` (top to bottom per column) |
1216
- | [`@cssints/placeholder`](../packages/placeholder/README.md) | `placeholder(path, { mode? })` | An `<image>` from a JPEG or PNG read at build time: a gradient of its colours laid out as the image, or a tiny thumbhash PNG |
1217
- | [`@cssints/ramp`](../packages/ramp/README.md) | `ramp(base, { mode, steps \| ratios, background })`, `overrides(ramp)` | An OKLCH palette as DTCG data for `createTokens`; the contrast mode meets each ratio against its background |
1218
- | [`@cssints/rybitten`](../packages/rybitten/README.md) | `color(hue, { cube })`, `wheel(steps, { cube })`, `shades(hue, lightness)`, `overrides(group)` | RYBitten's red-yellow-blue colours (36 historical cubes) as DTCG data for `createTokens`: a hue, a wheel of hues, a hue at several lightnesses |
1219
- | [`@cssints/skeleton`](../packages/skeleton/README.md) | `skeleton().radius().color().highlight()` | Loading placeholders whose shimmer is in phase across the page (one clock on `:root`), static under reduced motion |
1224
+ | Package | Members | What it does |
1225
+ | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1226
+ | [`@cssints/fluid`](../packages/fluid/README.md) | `fluid(min, max, { from?, to?, zoom? })`, `fluid.container(...)` | A `clamp()` that grows between two widths, computed at build time; a range that fails WCAG 1.4.4 is a build error |
1227
+ | [`@cssints/layout`](../packages/layout/README.md) | `stack()`, `cluster()`, `sidebar()`, `switcher()`, `cover()`, `autoGrid()` | Every Layout primitives as chain members |
1228
+ | [`@cssints/fonts`](../packages/fonts/README.md) | `font(family, { provider, ... })` → `.family()`, `.trim()` | `@font-face` and a metric-matched fallback face; cap-height trimming by `text-box`, else capsize's margins |
1229
+ | [`@cssints/reset`](../packages/reset/README.md) | `reset({ media?, prose? })` | A modern reset in a top-level `@layer reset` declared before the engine's, below every style; `@cssints/reset/<baseline group>` keeps only the declarations of that group |
1230
+ | [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors`, `/madoromi` | DTCG data for `createTokens` |
1231
+ | [`@cssints/gradient`](../packages/gradient/README.md) | `gradient(kind, direction, from, to, easing?, stops?)` | Eased colour stops mixed in oklab at build time |
1232
+ | [`@cssints/gradient-2d`](../packages/gradient-2d/README.md) | `meshGradient(mesh)`, `freeformGradient(points)` | `mesh-gradient()` / `freeform-gradient()` where the browser has them, else a runtime's canvas (this package's algorithms; lines and shapes not yet) |
1233
+ | [`@cssints/color-names`](../packages/color-names/README.md) | `named(name)`, `colorNames.<sector>(name)`, `/nearest` | The Color Name List (31,939 names) as hex colours; the ten sector members keep an editor's completion short, `nearest()` is the build-time reverse lookup |
1234
+ | [`@cssints/motion`](../packages/motion/README.md) | `motion().preset().duration().delay().easing()` | Animation presets over `keyframes()`, with reduced motion |
1235
+ | [`@cssints/squircle`](../packages/squircle/README.md) | `squircle().radius()` | `corner-shape: squircle`, else a CSS `mask` of the same shape |
1236
+ | [`@cssints/reveal`](../packages/reveal/README.md) | `reveal().preset().range().duration().easing()`, `appear().preset().range().duration().easing().inOut()` | motion's entrance presets on `animation-timeline: view()` (reveal) or on `timeline-trigger` + `animation-trigger` (appear); for other targets a script plays it once on entry (delivered by the runtime) |
1237
+ | [`@cssints/stuck`](../packages/stuck/README.md) | `sticky().top()`, `stuck(styles)`, `stuck("bottom")(styles)` | Styles inside a sticky element while it is stuck, by `@container scroll-state()`; for other targets an `IntersectionObserver` (delivered by the runtime) |
1238
+ | [`@cssints/balance`](../packages/balance/README.md) | `balance()`, `pretty()` | `text-wrap: balance` / `pretty`; for targets without balance a script balances the lines (delivered by the runtime) |
1239
+ | [`@cssints/masonry`](../packages/masonry/README.md) | `masonry().columns().gap()` | `display: grid-lanes`, else CSS `columns` (top to bottom per column) |
1240
+ | [`@cssints/placeholder`](../packages/placeholder/README.md) | `placeholder(path, { mode? })` | An `<image>` from a JPEG or PNG read at build time: a gradient of its colours laid out as the image, or a tiny thumbhash PNG |
1241
+ | [`@cssints/ramp`](../packages/ramp/README.md) | `ramp(base, { mode, steps \| ratios, background })`, `overrides(ramp)` | An OKLCH palette as DTCG data for `createTokens`; the contrast mode meets each ratio against its background |
1242
+ | [`@cssints/rybitten`](../packages/rybitten/README.md) | `color(hue, { cube })`, `wheel(steps, { cube })`, `shades(hue, lightness)`, `overrides(group)` | RYBitten's red-yellow-blue colours (36 historical cubes) as DTCG data for `createTokens`: a hue, a wheel of hues, a hue at several lightnesses |
1243
+ | [`@cssints/skeleton`](../packages/skeleton/README.md) | `skeleton().radius().color().highlight()` | Loading placeholders whose shimmer is in phase across the page (one clock on `:root`), static under reduced motion |
1220
1244
 
1221
1245
  ### Headless: `createField` and `createConfirm` (`@cssints/headless`)
1222
1246
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cssints",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "CSS in TypeScript: typed css.* calls compiled to atomic CSS at build time (a Vite plugin)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -68,7 +68,7 @@
68
68
  }
69
69
  },
70
70
  "dependencies": {
71
- "@cssints/css-grammar": "^0.10.0",
71
+ "@cssints/css-grammar": "^0.12.0",
72
72
  "culori": "^4.0.2",
73
73
  "effect": "4.0.6",
74
74
  "happy-dom": "^20.14.5",
@@ -1 +0,0 @@
1
- import "./theme-types-C5OAtybo.mjs";