cssints 0.3.0 → 0.4.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 (152) hide show
  1. package/README.md +1 -1
  2. package/dist/check.mjs +2 -2
  3. package/dist/clay-types.d.mts +207 -0
  4. package/dist/clay.d.mts +40 -0
  5. package/dist/clay.mjs +550 -0
  6. package/dist/{contrast-B49XCnVX.mjs → contrast-DLi4pp25.mjs} +2 -2
  7. package/dist/group-common-3PAVTxpd.d.mts +1 -0
  8. package/dist/{group-types-9ttphdku.d.mts → group-types-Dn9CIR8J.d.mts} +1 -1
  9. package/dist/groups/baseline-2015/with-downstream.d.mts +3 -3
  10. package/dist/groups/baseline-2015.d.mts +3 -3
  11. package/dist/groups/baseline-2016/with-downstream.d.mts +3 -3
  12. package/dist/groups/baseline-2016.d.mts +3 -3
  13. package/dist/groups/baseline-2017/with-downstream.d.mts +3 -3
  14. package/dist/groups/baseline-2017.d.mts +3 -3
  15. package/dist/groups/baseline-2018/with-downstream.d.mts +3 -3
  16. package/dist/groups/baseline-2018.d.mts +3 -3
  17. package/dist/groups/baseline-2019/with-downstream.d.mts +3 -3
  18. package/dist/groups/baseline-2019.d.mts +3 -3
  19. package/dist/groups/baseline-2020/with-downstream.d.mts +3 -3
  20. package/dist/groups/baseline-2020.d.mts +3 -3
  21. package/dist/groups/baseline-2021/with-downstream.d.mts +3 -3
  22. package/dist/groups/baseline-2021.d.mts +3 -3
  23. package/dist/groups/baseline-2022/with-downstream.d.mts +3 -3
  24. package/dist/groups/baseline-2022.d.mts +3 -3
  25. package/dist/groups/baseline-2023/with-downstream.d.mts +3 -3
  26. package/dist/groups/baseline-2023.d.mts +3 -3
  27. package/dist/groups/baseline-2024/with-downstream.d.mts +3 -3
  28. package/dist/groups/baseline-2024.d.mts +3 -3
  29. package/dist/groups/baseline-2025/with-downstream.d.mts +3 -3
  30. package/dist/groups/baseline-2025.d.mts +3 -3
  31. package/dist/groups/baseline-2026/with-downstream.d.mts +1 -1
  32. package/dist/groups/baseline-2026.d.mts +1 -1
  33. package/dist/groups/compositing-2.d.mts +3 -3
  34. package/dist/groups/css-align-3.d.mts +3 -3
  35. package/dist/groups/css-anchor-position-1.d.mts +3 -3
  36. package/dist/groups/css-anchor-position-2.d.mts +3 -3
  37. package/dist/groups/css-animations-1.d.mts +3 -3
  38. package/dist/groups/css-animations-2.d.mts +3 -3
  39. package/dist/groups/css-backgrounds-3.d.mts +3 -3
  40. package/dist/groups/css-backgrounds-4.d.mts +3 -3
  41. package/dist/groups/css-borders-4.d.mts +3 -3
  42. package/dist/groups/css-box-4.d.mts +3 -3
  43. package/dist/groups/css-break-4.d.mts +3 -3
  44. package/dist/groups/css-cascade-5.d.mts +3 -3
  45. package/dist/groups/css-cascade-6.d.mts +3 -3
  46. package/dist/groups/css-color-4.d.mts +3 -3
  47. package/dist/groups/css-color-5.d.mts +3 -3
  48. package/dist/groups/css-color-6.d.mts +3 -3
  49. package/dist/groups/css-color-adjust-1.d.mts +3 -3
  50. package/dist/groups/css-color-hdr-1.d.mts +3 -3
  51. package/dist/groups/css-conditional-3.d.mts +3 -3
  52. package/dist/groups/css-conditional-4.d.mts +3 -3
  53. package/dist/groups/css-conditional-5.d.mts +3 -3
  54. package/dist/groups/css-contain-2.d.mts +3 -3
  55. package/dist/groups/css-content-3.d.mts +3 -3
  56. package/dist/groups/css-counter-styles-3.d.mts +3 -3
  57. package/dist/groups/css-display-4.d.mts +3 -3
  58. package/dist/groups/css-easing-2.d.mts +3 -3
  59. package/dist/groups/css-env-1.d.mts +3 -3
  60. package/dist/groups/css-flexbox-1.d.mts +3 -3
  61. package/dist/groups/css-fonts-4.d.mts +3 -3
  62. package/dist/groups/css-fonts-5.d.mts +3 -3
  63. package/dist/groups/css-forms-1.d.mts +3 -3
  64. package/dist/groups/css-gaps-1.d.mts +3 -3
  65. package/dist/groups/css-gcpm-3.d.mts +3 -3
  66. package/dist/groups/css-gcpm-4.d.mts +3 -3
  67. package/dist/groups/css-grid-2.d.mts +3 -3
  68. package/dist/groups/css-grid-3.d.mts +3 -3
  69. package/dist/groups/css-images-3.d.mts +3 -3
  70. package/dist/groups/css-images-4.d.mts +3 -3
  71. package/dist/groups/css-images-5.d.mts +3 -3
  72. package/dist/groups/css-inline-3.d.mts +3 -3
  73. package/dist/groups/css-lists-3.d.mts +3 -3
  74. package/dist/groups/css-logical-1.d.mts +3 -3
  75. package/dist/groups/css-masking-1.d.mts +3 -3
  76. package/dist/groups/css-multicol-2.d.mts +3 -3
  77. package/dist/groups/css-overflow-3.d.mts +3 -3
  78. package/dist/groups/css-overflow-4.d.mts +3 -3
  79. package/dist/groups/css-overflow-5.d.mts +3 -3
  80. package/dist/groups/css-overscroll-1.d.mts +3 -3
  81. package/dist/groups/css-page-3.d.mts +3 -3
  82. package/dist/groups/css-page-floats-3.d.mts +3 -3
  83. package/dist/groups/css-position-3.d.mts +3 -3
  84. package/dist/groups/css-position-4.d.mts +3 -3
  85. package/dist/groups/css-rhythm-1.d.mts +3 -3
  86. package/dist/groups/css-round-display-1.d.mts +3 -3
  87. package/dist/groups/css-ruby-1.d.mts +3 -3
  88. package/dist/groups/css-scroll-anchoring-1.d.mts +3 -3
  89. package/dist/groups/css-scroll-snap-1.d.mts +3 -3
  90. package/dist/groups/css-scroll-snap-2.d.mts +3 -3
  91. package/dist/groups/css-scrollbars-1.d.mts +3 -3
  92. package/dist/groups/css-shapes-1.d.mts +3 -3
  93. package/dist/groups/css-shapes-2.d.mts +3 -3
  94. package/dist/groups/css-size-adjust-1.d.mts +3 -3
  95. package/dist/groups/css-sizing-3.d.mts +3 -3
  96. package/dist/groups/css-sizing-4.d.mts +3 -3
  97. package/dist/groups/css-speech-1.d.mts +3 -3
  98. package/dist/groups/css-tables-3.d.mts +3 -3
  99. package/dist/groups/css-text-3.d.mts +3 -3
  100. package/dist/groups/css-text-4.d.mts +3 -3
  101. package/dist/groups/css-text-decor-3.d.mts +3 -3
  102. package/dist/groups/css-text-decor-4.d.mts +3 -3
  103. package/dist/groups/css-transforms-1.d.mts +3 -3
  104. package/dist/groups/css-transforms-2.d.mts +3 -3
  105. package/dist/groups/css-transitions-1.d.mts +3 -3
  106. package/dist/groups/css-transitions-2.d.mts +3 -3
  107. package/dist/groups/css-ui-4.d.mts +3 -3
  108. package/dist/groups/css-values-4.d.mts +3 -3
  109. package/dist/groups/css-values-5.d.mts +3 -3
  110. package/dist/groups/css-variables-2.d.mts +2 -2
  111. package/dist/groups/css-view-transitions-2.d.mts +3 -3
  112. package/dist/groups/css-viewport.d.mts +3 -3
  113. package/dist/groups/css-will-change-1.d.mts +3 -3
  114. package/dist/groups/css-writing-modes-4.d.mts +3 -3
  115. package/dist/groups/css2.d.mts +3 -3
  116. package/dist/groups/fill-stroke-3.d.mts +3 -3
  117. package/dist/groups/filter-effects-1.d.mts +3 -3
  118. package/dist/groups/filter-effects-2.d.mts +3 -3
  119. package/dist/groups/limited-availability.d.mts +1 -1
  120. package/dist/groups/mediaqueries-4.d.mts +3 -3
  121. package/dist/groups/mediaqueries-5.d.mts +3 -3
  122. package/dist/groups/motion-1.d.mts +3 -3
  123. package/dist/groups/newly-available/with-downstream.d.mts +3 -3
  124. package/dist/groups/newly-available.d.mts +3 -3
  125. package/dist/groups/not-discouraged.d.mts +3 -3
  126. package/dist/groups/scroll-animations-1.d.mts +3 -3
  127. package/dist/groups/selectors-4.d.mts +2 -2
  128. package/dist/groups/selectors-5.d.mts +2 -2
  129. package/dist/groups/widely-available/with-downstream.d.mts +3 -3
  130. package/dist/groups/widely-available.d.mts +3 -3
  131. package/dist/index.d.mts +1 -1
  132. package/dist/index.mjs +12 -5
  133. package/dist/{instrument-BqIZpbIU.mjs → instrument-C7Am_dJ3.mjs} +1 -1
  134. package/dist/{lowered-aJVapQT6.mjs → lowered-CKSYUc0i.mjs} +1 -1
  135. package/dist/{node-OJ_w_Usj.d.mts → node-BABEZ2oF.d.mts} +6 -0
  136. package/dist/plugin-types.d.mts +1 -1
  137. package/dist/plugin.d.mts +1 -1
  138. package/dist/{registry-BUSEO32-.mjs → registry-ByrYF2v5.mjs} +5 -1
  139. package/dist/{scope-INuJD4RT.d.mts → scope-1R_Np2Mj.d.mts} +5 -6
  140. package/dist/{sheet-BeHdq4xt.mjs → sheet-BT2R1wk_.mjs} +2 -2
  141. package/dist/surface.d.mts +1 -1
  142. package/dist/{theme-SlQ73rFL.mjs → theme-WGcgMD4V.mjs} +7 -5
  143. package/dist/{theme-types-Bqv0Ggz_.d.mts → theme-types-BY0mRf3K.d.mts} +5 -6
  144. package/dist/tui-types.d.mts +1 -1
  145. package/dist/tui.mjs +4 -4
  146. package/dist/types.d.mts +1 -1
  147. package/dist/vite.d.mts +1 -1
  148. package/dist/vite.mjs +10 -9
  149. package/docs/API.md +105 -2
  150. package/package.json +6 -2
  151. package/skills/cssints/references/plugins.md +12 -0
  152. package/dist/group-common-9zpBxfUF.d.mts +0 -1
package/docs/API.md CHANGED
@@ -1084,8 +1084,10 @@ More plugins on `scope()`, each a package of its own with its rules and limits i
1084
1084
  | [`@cssints/layout`](../packages/layout/README.md) | `stack()`, `cluster()`, `sidebar()`, `switcher()`, `cover()`, `autoGrid()` | Every Layout primitives as chain members |
1085
1085
  | [`@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 |
1086
1086
  | [`@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 |
1087
- | [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors` | DTCG data for `createTokens` |
1087
+ | [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors`, `/madoromi` | DTCG data for `createTokens` |
1088
1088
  | [`@cssints/gradient`](../packages/gradient/README.md) | `gradient(kind, direction, from, to, easing?, stops?)` | Eased colour stops mixed in oklab at build time |
1089
+ | [`@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) |
1090
+ | [`@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 |
1089
1091
  | [`@cssints/motion`](../packages/motion/README.md) | `motion().preset().duration().delay().easing()` | Animation presets over `keyframes()`, with reduced motion |
1090
1092
  | [`@cssints/squircle`](../packages/squircle/README.md) | `squircle().radius()` | `corner-shape: squircle`, else a CSS `mask` of the same shape |
1091
1093
  | [`@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) |
@@ -1248,6 +1250,10 @@ The process must end the exporter or Node stays alive: `vite build` and `server.
1248
1250
 
1249
1251
  `packages/cssints/test/trace.mjs` (in `bun run test`) checks the spans, the file attribute and the error's trace id against an in-process collector. `node packages/cssints/test/trace-live.mjs` builds apps/csssky and runs its HMR test traced, then reads both traces back through Jaeger's API (`GET /api/traces?service=cssints`) and prints span counts and the slowest hooks; it skips when no backend answers. Effect's DevTools (the VS Code extension, `effect/devtools`) is not wired: it needs the editor's extension listening, so neither a script nor an agent can read it.
1250
1252
 
1253
+ ### Debugging: the limit of an evaluation (`CSSINTS_EVAL_TIMEOUT`, cssints-joex)
1254
+
1255
+ A module is evaluated with all it imports in at most 30 seconds, else the build fails with `cssints: evaluating <file> took more than 30 seconds`. The engine cannot stop the code, so it closes the Module Runner: the evaluation ends at the next module it would load, and the next evaluation starts on a new runner. `CSSINTS_EVAL_TIMEOUT=<milliseconds>` changes the limit (read once, when the plugin loads); it is for tests that run on a busy machine, and the default is the one for your code.
1256
+
1251
1257
  ### Checks for tools: `cssints/check` (2026-10-09, cssints-p3d2)
1252
1258
 
1253
1259
  The engine's own checks, as functions, for a tool that answers as a build would (`@cssints/mcp`). Node only (culori, LightningCSS): nothing here reaches a browser, and user code has no reason to import it. Each returns an Effect.
@@ -1370,6 +1376,103 @@ process.stdin.on("data", (bytes) => dispatch(input.scan(follow.feed(bytes)).even
1370
1376
  - **Live in the browser** (cssints-ey13, 2026-10-11). [The TUI page](https://cssints.dev/tui) of this site runs apps/csssky-tui's styles on `@cssints/tui/bomb` in a real terminal: Ghostty's emulator compiled to WebAssembly (ghostty-web) draws csssky's feed and thread from its recorded fixtures, with keys and the mouse. The page is the terminal: it answers the system theme's queries (OSC 10, 11, 4, `CSI ? 996 n`) from the site's display settings and reports a change of them (mode 2031), so the theme is solved again as the palette or the mode changes. OpenTUI is not shown: its renderer is native Zig over `bun:ffi`. On a change notification, `followSystemTheme` of `@cssints/tui/bomb` asks the colours again (`COLOURS` of `@cssints/tui/system`), not the scheme report: its reply is the same sequence as a notification, and asking it looped with a terminal that answers it.
1371
1377
  - **Cost.** A colour member costs what the same web member costs in the types (the `color` grammar); `bench/tui.ts` is 184k instantiations (tsc) for 16 calls and a token set. No terminal HMR in this version. The system theme brings culori's rgb, oklab, oklch and okhsl modes to the app (45 kB unminified in csssky-tui's bundle).
1372
1378
 
1379
+ ### Clay: `cssints/clay` (2026-10-19, cssints-iwey)
1380
+
1381
+ A native UI laid out by [Clay](https://github.com/nicbarker/clay), with no browser and no JS where it runs (an ESP32's firmware), writes its styles with `cssints/clay`. The same Vite plugin compiles each site to an object literal shaped as Clay's own structs, and `header()` prints a module of them as C initializers:
1382
+
1383
+ ```ts
1384
+ import * as css from "cssints/clay" with { type: "cssints" };
1385
+
1386
+ export const pill = css.cn(
1387
+ css.width(200),
1388
+ css.height(38),
1389
+ css.justifyContent("center"),
1390
+ css.alignItems("center"),
1391
+ css.bg("rgb(36 40 52)"),
1392
+ css.borderRadius(19),
1393
+ css.border(1, "#969baa"),
1394
+ );
1395
+ export const label = css.cn(css.color("#ebebf0"), css.fontSize(14));
1396
+ css.width("10rem"); // error: Clay counts pixels
1397
+ css.boxShadow("0 0 1px red"); // error: no such member in Clay
1398
+ ```
1399
+
1400
+ ```c
1401
+ static const Clay_ElementDeclaration pill = { .layout = { .sizing = { .width = { .size = { .minMax = { 200, 200 } }, .type = CLAY__SIZING_TYPE_FIXED }, ... }, .backgroundColor = { .r = 36, .g = 40, .b = 52, .a = 255 }, ... };
1402
+ static const Clay_TextElementConfig label_text = { .textColor = { .r = 235, .g = 235, .b = 240, .a = 255 }, .fontSize = 14 };
1403
+ ```
1404
+
1405
+ ```c
1406
+ CLAY(CLAY_ID("Units"), pill) { CLAY_TEXT(CLAY_STRING("switch to g"), label_text); }
1407
+ ```
1408
+
1409
+ - **Members**: `width`, `height` (pixels, `N%`, `auto` for Clay's FIT, `stretch` for GROW), `padding`/`p` and the sides, `gap` (`childGap`), `flexDirection` (`row`, `column`), `justifyContent` and `alignItems` (start, center, end: Clay's `childAlignment`, the axis from `flexDirection`), `backgroundColor`/`bg`, `borderRadius`, `border(width, colour)`, `borderWidth`, `borderColor`, `overflow("hidden")` (`clip`), `float()` (`floating`, below), and for text `color`, `fontSize`, `letterSpacing`, `lineHeight`, `textAlign`, `whiteSpace` (`wrapMode`); `cn` merges, a later prop wins. Any other property is not a member.
1410
+ - **Pixels.** A number or `"Npx"`; padding, gap and border widths are whole numbers (`uint16_t` in Clay). Another unit is a type error and a build error.
1411
+ - **Colours** are checked by the web's `color` grammar, or are colour tokens of cssints/clay's `createTokens`, and are written as 0-255 `r g b a`.
1412
+ - **`header(exports)`** prints a `Clay_ElementDeclaration` per export and, for one with text props, a `Clay_TextElementConfig` named `<name>_text`. A field it does not set is zero, which is Clay's default.
1413
+ - **States**: `hover`, `focus`, `active` wrap styles. Clay has no states, so the literal has an overlay per state (`":active": { backgroundColor }`, the fields the state sets, at their values over the base), and `header()` prints the whole declaration again, `<name>_active` (`<name>_hover_text` for text): the page asks Clay and picks one, nothing is merged in C. States do not nest.
1414
+ - **Tokens and themes**: `createTokens` and `createGlobalTheme(tokens, name, overrides)` of cssints/clay, on tables of their own (a web or terminal token is not a Clay one, and a theme of one is a build error). Resolved at build time: a site has its colours at the tokens' values and, under `themes`, what each theme changes. `header()` prints every style of a module with a theme again, the theme's name last (`units_light`, `units_active_light`, `title_text_light`), so a page switches at run time by a suffix. A style sees the themes evaluated before it: declare them first, or in a module it imports.
1415
+ - **Fonts**: `fonts("Roboto", "Mono")` is the order of the app's font array; `.Mono` is a style that sets Clay's `fontId` to 1, and `header()` prints the order as an enum, `font_Roboto = 0, font_Mono = 1` (the export's name, then the font's).
1416
+
1417
+ ```ts
1418
+ import * as css from "cssints/clay" with { type: "cssints" };
1419
+
1420
+ export const t = css.createTokens({
1421
+ color: { $type: "color", surface: { $value: "rgb(36 40 52)" }, pressed: { $value: "#ffc878" } },
1422
+ });
1423
+ css.createGlobalTheme(t, "light", { color: { surface: "white" } });
1424
+ export const font = css.fonts("Roboto", "Mono");
1425
+
1426
+ export const units = css.cn(
1427
+ css.width(200),
1428
+ css.bg(t.color.surface),
1429
+ css.active(css.bg(t.color.pressed)),
1430
+ );
1431
+ export const label = css.cn(font.Mono, css.fontSize(14));
1432
+ css.cn(font.Serif); // error: not one of the fonts
1433
+ ```
1434
+
1435
+ ```c
1436
+ #define T(name) (light ? name##_light : name)
1437
+ CLAY(CLAY_ID("Units"), pressed ? T(units_active) : T(units)) { CLAY_TEXT(CLAY_STRING("switch to g"), label_text); }
1438
+ ```
1439
+
1440
+ - **Floating elements**: `float({ ... })` fills Clay's `floating`, the foundation of menus, popovers and dialogs. Every option is optional, and what it leaves out is Clay's own default, so `header()` prints only what is set (`float()` alone is `{ .attachTo = CLAY_ATTACH_TO_PARENT }`). The name is `float` as in CSS: it is a valid binding, and no other Clay member shares it.
1441
+
1442
+ | Option | Clay field | Default |
1443
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
1444
+ | `attach: { element, parent }` | `attachPoints`: which point of the float sits on which point of its parent, each `"left top"`, `"center center"`, `"right bottom"`, ... (x, then y) | `left top` on `left top` |
1445
+ | `parent: "Units"` | `parentId` and `attachTo = ELEMENT_WITH_ID`: the string of the parent's `CLAY_ID("Units")` (ASCII; a `CLAY_IDI` or local id is not one) | the element the float is a child of (`attachTo = PARENT`) |
1446
+ | `root: true` | `attachTo = ROOT`: absolute positioning, a dialog on the screen (not with `parent`) | off |
1447
+ | `offset: { x, y }` | `offset`: pixels from where `attach` puts it; a negative number goes left or up | 0, 0 |
1448
+ | `expand: { width, height }` | `expand`: pixels the float's own box grows by, its children's not; not negative | 0, 0 |
1449
+ | `zIndex` | `zIndex`: a whole number, `int16_t`; floats draw in ascending order, with their children | 0 |
1450
+ | `capture: false` | `pointerCaptureMode = PASSTHROUGH`: the pointer reaches what lies under the float (`true` is `CAPTURE`) | `true` |
1451
+ | `clip: "parent"` | `clipTo = ATTACHED_PARENT`: clipped to the box its parent is clipped to (`"none"` is `CLIP_TO_NONE`; with `root` it has nothing to clip to, a build error) | `"none"` |
1452
+
1453
+ `parentId` is printed as a number, the hash of the id (`Clay__HashString(id, 0)` computed at build time), because `CLAY_ID()` is a call and a `static const` initializer takes constants. A misspelt id is Clay's own `FLOATING_CONTAINER_PARENT_NOT_FOUND` error at run time. A bad value, an option that does not exist, a negative `expand`, a non-ASCII id are build errors (the types catch what a type can: a point such as `"top left"`, an unknown option). Two floats merge in a `cn()` as the other members do: the later one's options win and the rest stay; a state (`hover(float(...))`) is a declaration of its own.
1454
+
1455
+ ```ts
1456
+ import * as css from "cssints/clay" with { type: "cssints" };
1457
+
1458
+ export const menu = css.cn(
1459
+ css.width(160),
1460
+ css.bg("#242834"),
1461
+ css.float({ parent: "Units", attach: { parent: "left bottom" }, offset: { y: 4 }, zIndex: 10 }),
1462
+ );
1463
+ export const dialog = css.float({
1464
+ root: true,
1465
+ attach: { element: "center center", parent: "center center" },
1466
+ });
1467
+ css.float({ attach: { element: "top left" } }); // error: a point is x, then y
1468
+ ```
1469
+
1470
+ ```c
1471
+ static const Clay_ElementDeclaration menu = { .layout = { ... }, .backgroundColor = { ... }, .floating = { .offset = { .x = 0, .y = 4 }, .parentId = 3516868942u, .zIndex = 10, .attachPoints = { .element = CLAY_ATTACH_POINT_LEFT_TOP, .parent = CLAY_ATTACH_POINT_LEFT_BOTTOM }, .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID } };
1472
+ ```
1473
+
1474
+ - **Not yet**: min and max sizes, derived colour tokens (`color-mix()` of tokens: a colour Clay is given must parse as one), a theme under a condition (a theme is a name; `media()` has no meaning on a board).
1475
+
1373
1476
  ### Export groups: `cssints/widely-available`, `cssints/css-grid-2`, … (decided 2026-10-11, cssints-n7z3)
1374
1477
 
1375
1478
  A group is a subpath of `cssints` that exports the members of `cssints` which a set of CSS features has, and refuses a value that holds a feature outside the set. It is the same import (`with { type: "cssints" }`), the same members, the same classes:
@@ -1399,7 +1502,7 @@ color("color-mix(in oklab, red, blue)"); // error: color: "color-mix()" is not i
1399
1502
  ```
1400
1503
 
1401
1504
  - **Baseline groups** (web-features 3.42, the status of each BCD key): `widely-available` is Baseline high, `newly-available` is high and low, `limited-availability` is everything (it is `cssints` itself, under its Baseline name) and `not-discouraged` is everything web-features does not mark `discouraged` (`clip`, the `page-break-*` aliases, `ime-mode`, `word-break: break-word`, `text-decoration-line: blink`, device media features). A feature web-features does not know is limited availability.
1402
- - **Downstream groups** (cssints-n12x, 2026-10-11): `widely-available/with-downstream` and `newly-available/with-downstream` are the Baseline group also checked against Opera, Opera Mobile, Samsung Internet, Android WebView, UC and QQ, as `browserslist-config-baseline/with-downstream` is. A feature is in one when the Baseline group has it and every one of those browsers has it, by BCD, at the minimum version that [baseline-browser-mapping](https://www.npmjs.com/package/baseline-browser-mapping) 2.11.28 gives for the target (the rule of the support warnings: no prefix, no flag; UC and QQ are Blink, checked as Chrome at the Blink version of that build). `widely-available/with-downstream` has 520 of the 521 members (not `maskImage`: Opera has `-webkit-mask-image` only) and refuses `inline-size: fit-content` (Samsung Internet), `shape-outside: xywh()` and `prefers-contrast`; `newly-available/with-downstream` has 533 of 567 (UC and QQ are on Blink 123 and 121).
1505
+ - **Downstream groups** (cssints-n12x, 2026-10-11): `widely-available/with-downstream` and `newly-available/with-downstream` are the Baseline group also checked against Opera, Opera Mobile, Samsung Internet, Android WebView, UC and QQ, as `browserslist-config-baseline/with-downstream` is. A feature is in one when the Baseline group has it and every one of those browsers has it, by BCD, at the minimum version that [baseline-browser-mapping](https://npmx.dev/package/baseline-browser-mapping) 2.11.28 gives for the target (the rule of the support warnings: no prefix, no flag; UC and QQ are Blink, checked as Chrome at the Blink version of that build). `widely-available/with-downstream` has 520 of the 521 members (not `maskImage`: Opera has `-webkit-mask-image` only) and refuses `inline-size: fit-content` (Samsung Internet), `shape-outside: xywh()` and `prefers-contrast`; `newly-available/with-downstream` has 533 of 567 (UC and QQ are on Blink 123 and 121).
1403
1506
  - **Baseline years:** `baseline-2015` to `baseline-2026` (the first year web-features has to the current one) and `baseline-YYYY/with-downstream`, as `browserslist-config-baseline/YYYY` has them. `baseline-YYYY` is **cumulative**: what was Baseline (newly available, `baseline_low_date`) by the end of YYYY, so `baseline-2022` refuses `color-mix()` (2023) and `baseline-2023` refuses `light-dark()` (2024). 220 members in `baseline-2015`, 387 in `baseline-2020`, 537 in `baseline-2024`. `baseline-2026` is `newly-available` today.
1404
1507
  - **Spec groups** are named by the W3C shortname that @webref/css uses: `cssints/css-grid-2`, `cssints/css-color-4`, `cssints/mediaqueries-4`, `cssints/selectors-4`, … (92 of them). A group holds what the spec defines, and **a level includes the levels of its series before it**: `css-color-5` has what Color 3, 4 and 5 define, `css-color-4` has Color 3 and 4. A level is a delta (Color 5 over Color 4) or a rewrite (Media Queries 4 over 3), and "I write for Color 5" means both. What only a later level defines is refused: `css-color-4` has no `colorMix` and refuses `color-mix()`, `mediaqueries-4` refuses `prefers-color-scheme`. A group has the properties, functions, pseudo-class wrappers and conditions its spec defines, so `display` is in `css-display-4` and `gridTemplateColumns` in `css-grid-2`: import from several groups in one file.
1405
1508
  - **What is a member:** the properties (and their short names), the functions, the pseudo-class wrappers, `media`, `container`, `supports`, `keyframes` and `positionTry`. Everything else (`cn`, `cv`, `firstThatWorks`, `token`, `createTokens`, `createGlobalTheme`, `check`, `style`, `global`, `layers`, `attr`, `within`, `group`, the Typed OM values) is in every group. A group has no `css` object: write `import * as css from "cssints/widely-available"`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cssints",
3
- "version": "0.3.0",
3
+ "version": "0.4.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": {
@@ -54,6 +54,10 @@
54
54
  "types": "./dist/tui-types.d.mts",
55
55
  "default": "./dist/tui.mjs"
56
56
  },
57
+ "./clay": {
58
+ "types": "./dist/clay-types.d.mts",
59
+ "default": "./dist/clay.mjs"
60
+ },
57
61
  "./devtools-link": {
58
62
  "types": "./dist/devtools-link.d.mts",
59
63
  "default": "./dist/devtools-link.mjs"
@@ -64,7 +68,7 @@
64
68
  }
65
69
  },
66
70
  "dependencies": {
67
- "@cssints/css-grammar": "^0.3.0",
71
+ "@cssints/css-grammar": "^0.4.0",
68
72
  "culori": "^4.0.2",
69
73
  "effect": "4.0.0",
70
74
  "happy-dom": "^20.14.5",
@@ -62,6 +62,18 @@ a suggestion.
62
62
  **`@cssints/gradient`**: `backgroundImage(gradient("linear", "to bottom", "#000", "transparent", "ease-in-out", 5))`:
63
63
  eased stops mixed in oklab. Each argument its own string; the direction is one string (`"to bottom"`).
64
64
 
65
+ **`@cssints/gradient-2d`**: `meshGradient("red, blue; green, yellow")` (rows from the top of the box down, separated by
66
+ `;`, stops by `,`) and `freeformGradient("red top left, gold 4 60% 40%, yellow bottom right")` (points, an optional
67
+ weight before the position). One string per call. Where the browser has `mesh-gradient()`, the declaration is native;
68
+ elsewhere a runtime the build adds draws the same points on a canvas, so it needs a script.
69
+
70
+ **`@cssints/color-names`**: `color(named("tangerine"))` is `#ff9300`. `colorNames.<sector>(name)` is the same name
71
+ restricted to one sector (`red`, `orange`, `yellow`, `green`, `cyan`, `blue`, `purple`, `pink`, `brown`, `neutral`), so
72
+ completion stays short; the colour word in the name picks the sector. An unknown name is a build error with the nearest
73
+ one, and a name outside the sector is one that names the sectors it is in. The list's hex wins over the CSS keyword's
74
+ (`named("green")` is `#00ff00`; `color("green")` is the CSS one). `@cssints/color-names/nearest` maps a hex to the
75
+ closest name at build time.
76
+
65
77
  **`@cssints/placeholder`**: `backgroundImage(placeholder("src/hero.jpg"))` (a gradient of the image's colours) or
66
78
  `{ mode: "thumbhash" }` (a tiny PNG; pair it with `backgroundSize("cover")`). JPEG and PNG only; the path is relative
67
79
  to the working directory.
@@ -1 +0,0 @@
1
- import "./theme-types-Bqv0Ggz_.mjs";