cssints 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{node-CWwn8PaX.d.mts → author-types-CTeNrh2c.d.mts} +94 -6
- package/dist/clay.mjs +1 -1
- package/dist/index.d.mts +1 -2
- package/dist/index.mjs +11 -4
- package/dist/plugin-types.d.mts +247 -2
- package/dist/plugin.d.mts +3 -3
- package/dist/plugin.mjs +18 -1
- package/dist/{scope-Oxd_stwQ.d.mts → scope-9RiDANgb.d.mts} +13 -2
- package/dist/surface.d.mts +1 -1
- package/dist/{theme-ClgusumY.mjs → theme-B7ttL9B5.mjs} +18 -3
- package/dist/tui.mjs +1 -1
- package/dist/vite.d.mts +1 -2
- package/docs/API.md +83 -29
- package/package.json +2 -2
- package/dist/author-types-X4zGpNpU.d.mts +0 -88
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { a as Kernel, c as ThemeRule, i as GlobalRule, n as Conflict, o as Runtime } from "./author-types-X4zGpNpU.mjs";
|
|
2
1
|
import { Warning } from "@cssints/css-grammar/support";
|
|
3
2
|
import { Context } from "effect";
|
|
4
3
|
import { TokenType } from "@cssints/css-grammar/token";
|
|
@@ -124,7 +123,7 @@ interface RegistryState {
|
|
|
124
123
|
/** file -> site index -> replacement expression */
|
|
125
124
|
sites: Map<string, Map<number, string>>;
|
|
126
125
|
/** file -> site index -> the declarations of the style it produced: what a cn() with runtime arguments settles (macro.ts `groupOf`) */
|
|
127
|
-
nodes: Map<string, Map<number, Decl[]>>;
|
|
126
|
+
nodes: Map<string, Map<number, Decl$1[]>>;
|
|
128
127
|
/** class -> rule; one entry per class across all modules */
|
|
129
128
|
rules: Map<string, Rule>;
|
|
130
129
|
/** `layer<TAB>css` -> a global rule: in the sheet of the modules that carry it, in layer _.k unless it names a layer (sheet.ts `addGlobal`) */
|
|
@@ -213,9 +212,11 @@ interface Cond {
|
|
|
213
212
|
}
|
|
214
213
|
/**
|
|
215
214
|
* One declaration: property and value, under the conditions that wrap it (outermost first). `fallbacks` are the other
|
|
216
|
-
* values of a `firstThatWorks(...)`, best first: the rule prints them before `value`, which is the one wanted.
|
|
215
|
+
* values of a `firstThatWorks(...)`, best first: the rule prints them before `value`, which is the one wanted. `join`
|
|
216
|
+
* makes it a list: when two declarations of this property meet in one `cn()` under the same conditions, their values
|
|
217
|
+
* join with this separator instead of the later one replacing the earlier.
|
|
217
218
|
*/
|
|
218
|
-
type Decl = [prop: string, value: string, conds?: Cond[], fallbacks?: string[]];
|
|
219
|
+
type Decl$1 = [prop: string, value: string, conds?: Cond[], fallbacks?: string[], join?: ","];
|
|
219
220
|
/**
|
|
220
221
|
* What a css.* builder returns: its declarations, and next to them the fixed classes it prints (`markers`, each with
|
|
221
222
|
* the key of the kernel it belongs to), the kernels it needs, and the plugin members whose runtime and conflicts apply
|
|
@@ -223,7 +224,7 @@ type Decl = [prop: string, value: string, conds?: Cond[], fallbacks?: string[]];
|
|
|
223
224
|
* own (`pretty()`, `frame()`): a condition around it would wrap nothing of theirs, so it is an error.
|
|
224
225
|
*/
|
|
225
226
|
interface CssNode {
|
|
226
|
-
__cssints: Decl[];
|
|
227
|
+
__cssints: Decl$1[];
|
|
227
228
|
markers?: [marker: string, kernel: string][];
|
|
228
229
|
kernels?: Kernel[];
|
|
229
230
|
globals?: GlobalRule[];
|
|
@@ -232,4 +233,91 @@ interface CssNode {
|
|
|
232
233
|
plugs?: Plug[];
|
|
233
234
|
bare?: [marker: string, kernel: string][];
|
|
234
235
|
}
|
|
235
|
-
|
|
236
|
+
/** A declaration a member emits: property and value (a custom property, `--_r`, is allowed); `append()` makes a list. */
|
|
237
|
+
type Decl = readonly [prop: string, value: string, conds?: readonly Cond[], fallbacks?: readonly string[], join?: ","];
|
|
238
|
+
/** A feature of `@mdn/browser-compat-data`: `css.at-rules.container.style_queries_for_custom_properties`. */
|
|
239
|
+
type BcdKey = `css.${string}`;
|
|
240
|
+
/**
|
|
241
|
+
* Global rules, registered once by `key` (`name@version`) in layer `_.k`; `atProperty` (the `@property` rules of its
|
|
242
|
+
* custom properties) goes at the top of the sheet. A target lacking a `requires` feature gets a support warning, never an
|
|
243
|
+
* error; `{ key, exact: true }` also counts a partial implementation as lacking (relative colour, whose channel scales
|
|
244
|
+
* differ in Chrome 119-121 and Safari 16.4-17.6). Two members share a kernel by pointing at the same object; the same key with other CSS is a build error, as is
|
|
245
|
+
* a custom property or a marker that two keys share.
|
|
246
|
+
*/
|
|
247
|
+
interface Kernel {
|
|
248
|
+
key: string;
|
|
249
|
+
css: string;
|
|
250
|
+
atProperty?: string;
|
|
251
|
+
requires?: (BcdKey | {
|
|
252
|
+
key: BcdKey;
|
|
253
|
+
exact: true;
|
|
254
|
+
})[];
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* A global rule a member contributes. It is identified by its content (`layer` and `css`): the same rule from two
|
|
258
|
+
* styles is one, an edit of it replaces the old one, and it is in the sheet of the modules whose styles carry it, until
|
|
259
|
+
* they stop. It goes to layer `_.k` with the kernels. Unlike a kernel, two globals **may** declare the same custom
|
|
260
|
+
* property: a look sets the same `--color-*` in several source layers, which is the point of fill-through. Use it for a
|
|
261
|
+
* rule that is not a class.
|
|
262
|
+
*/
|
|
263
|
+
interface GlobalRule {
|
|
264
|
+
css: string;
|
|
265
|
+
/**
|
|
266
|
+
* A top-level `@layer` of this name to put the rule in (a rule that must beat the engine's `:root` fallbacks). The
|
|
267
|
+
* layer must be declared: by `layers` of the same `Made`, or by `layers()` in a module this one imports. Omitted:
|
|
268
|
+
* layer `_.k`.
|
|
269
|
+
*/
|
|
270
|
+
layer?: string;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* A theme a member contributes, as `createGlobalTheme(tokens, selector, overrides, { layer, scope })` makes one: the
|
|
274
|
+
* same checks (the paths and values of `overrides` against the types of `tokens`, a layer that is declared), the
|
|
275
|
+
* aliases that depend on an override declared again, and `check.contrast` reads it. `tokens` is a token set of
|
|
276
|
+
* `createTokens()` that the member got from its caller (a closure: the arguments of a member are joined into one string).
|
|
277
|
+
*/
|
|
278
|
+
interface ThemeRule {
|
|
279
|
+
tokens: object;
|
|
280
|
+
overrides: object;
|
|
281
|
+
selector: string;
|
|
282
|
+
layer?: string;
|
|
283
|
+
/** A selector: the rule goes inside `@scope (<scope>) { ... }`. */
|
|
284
|
+
scope?: string;
|
|
285
|
+
}
|
|
286
|
+
/** One element family of a runtime: the nearest `marker` ancestor's computed `read` is copied into `write`. */
|
|
287
|
+
interface ParentVar {
|
|
288
|
+
marker: string;
|
|
289
|
+
read: `--${string}`;
|
|
290
|
+
write: `--${string}`;
|
|
291
|
+
/** A property that changes when a CSS condition (`:hover`, a media query) changes `read`: its transition re-runs the copy. */
|
|
292
|
+
watch?: `--${string}`;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The runtime half of a member. The client module that holds a site with the member imports
|
|
296
|
+
* `virtual:cssints/runtime/<name>`, which is empty unless a browserslist target lacks a feature in `polyfills` (and, with
|
|
297
|
+
* `parentVars`, has `@property`, which the script stands on); then it imports `script`, configures `cssints/parent-vars`,
|
|
298
|
+
* and `css` (the fallback rules) is added to the sheet in layer `_.k`. A `requires` of the member's kernel that is in
|
|
299
|
+
* `polyfills` warns only for the targets the runtime does not reach.
|
|
300
|
+
*/
|
|
301
|
+
interface Runtime {
|
|
302
|
+
polyfills: BcdKey[];
|
|
303
|
+
parentVars?: ParentVar[];
|
|
304
|
+
css?: string;
|
|
305
|
+
/** The plugin's browser script, a module specifier the app resolves (`"@cssints/balance/runtime"`): imported, never evaluated at build time. */
|
|
306
|
+
script?: string;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* A value a site ships as a JavaScript object of its own: `ship({ owner, open })` (`@cssints/reactive`'s `state()`, whose
|
|
310
|
+
* owner is a style and whose sources are data). Each `Style` becomes its class string, an array or an object keeps its
|
|
311
|
+
* shape, and anything else is its JSON.
|
|
312
|
+
*/
|
|
313
|
+
interface Ship {
|
|
314
|
+
readonly "~ship": {
|
|
315
|
+
readonly [key: string]: unknown;
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/** A build error when one `cn()` holds the member's marker and a property listed here (a name, or a pattern). */
|
|
319
|
+
interface Conflict {
|
|
320
|
+
props: (string | RegExp)[];
|
|
321
|
+
message: string;
|
|
322
|
+
}
|
|
323
|
+
export { Kernel as a, ThemeRule as c, LayersDecl as d, RegistryState as f, GlobalRule as i, CssNode as l, Conflict as n, Runtime as o, Decl as r, Ship as s, BcdKey as t, At as u };
|
package/dist/clay.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as registry } from "./registry-8sYvlzyn.mjs";
|
|
2
|
-
import { a as createTokens$1, i as createGlobalTheme$1, j as fail, s as sets } from "./theme-
|
|
2
|
+
import { a as createTokens$1, i as createGlobalTheme$1, j as fail, s as sets } from "./theme-B7ttL9B5.mjs";
|
|
3
3
|
import { n as valueOf, t as together } from "./contrast-BB0wimFI.mjs";
|
|
4
4
|
import { n as parseColor } from "./color-BB8ipynT.mjs";
|
|
5
5
|
import { Formatter, Predicate } from "effect";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { a as Kernel } from "./author-types-
|
|
1
|
+
import { a as Kernel, l as CssNode, u as At } from "./author-types-CTeNrh2c.mjs";
|
|
2
2
|
import { n as _cv, r as _cx } from "./runtime-Cv7hGrWf.mjs";
|
|
3
|
-
import { n as At, t as CssNode } from "./node-CWwn8PaX.mjs";
|
|
4
3
|
import { CSS, CSSColorValue, CSSImageValue, CSSStyleValue, CSSUnitValue } from "@cssints/css-grammar/values";
|
|
5
4
|
import { Effect } from "effect";
|
|
6
5
|
/** What firstThatWorks() builds: its values as text, the wanted one first. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as registry, d as MacroError, f as MemberError, o as warn, r as forgetKernels, t as Registry } from "./registry-8sYvlzyn.mjs";
|
|
2
|
-
import { A as camel, C as hashClass, D as settled, E as minWidth, F as probed, M as failIn, N as isNode, O as toDecls, P as node, S as edge, T as merged, _ as PSEUDOS, a as createTokens, b as checkVars, c as tokensOf, d as style, f as token, g as PROPS, h as LAYER, i as createGlobalTheme, j as fail, k as VAR, l as CSSTokenValue, m as FUNCTIONS, n as addTheme, o as isDone, p as CONTEXTS, r as check$1, t as DONE, u as isStyle, v as carried, w as isFallback, x as dropsOf, y as chainDecl } from "./theme-
|
|
2
|
+
import { A as camel, C as hashClass, D as settled, E as minWidth, F as probed, M as failIn, N as isNode, O as toDecls, P as node, S as edge, T as merged, _ as PSEUDOS, a as createTokens, b as checkVars, c as tokensOf, d as style, f as token, g as PROPS, h as LAYER, i as createGlobalTheme, j as fail, k as VAR, l as CSSTokenValue, m as FUNCTIONS, n as addTheme, o as isDone, p as CONTEXTS, r as check$1, t as DONE, u as isStyle, v as carried, w as isFallback, x as dropsOf, y as chainDecl } from "./theme-B7ttL9B5.mjs";
|
|
3
3
|
import { D as relation, S as addRuntime, _ as addKernel, i as byOrder, n as addGlobal, r as addLayers, y as kernelWarnings } from "./sheet-rwl57DmD.mjs";
|
|
4
4
|
import { n as loweredOf } from "./lowered-DOJEDRFM.mjs";
|
|
5
5
|
import { i as SCV_CALL, l as groups$1, n as CX_CALL, t as CV_CALL } from "./instrument-QGVM1E1B.mjs";
|
|
@@ -524,7 +524,13 @@ const grouped = (c, def, carry) => def.group ? {
|
|
|
524
524
|
...carry,
|
|
525
525
|
markers: [...carry.markers ?? [], [`_g-${c.name}`, "group"]]
|
|
526
526
|
} : carry;
|
|
527
|
-
const ownDecls = (c, emitted) => emitted.map(([p, v]) => [
|
|
527
|
+
const ownDecls = (c, emitted) => emitted.map(([p, v, , fallbacks, join]) => fallbacks || join ? [
|
|
528
|
+
c.own(p),
|
|
529
|
+
c.own(v),
|
|
530
|
+
void 0,
|
|
531
|
+
fallbacks && [...fallbacks],
|
|
532
|
+
join
|
|
533
|
+
] : [c.own(p), c.own(v)]);
|
|
528
534
|
const argOf = (c, label, def, v, tokens) => {
|
|
529
535
|
const { name } = c;
|
|
530
536
|
if (def === "$tokens") {
|
|
@@ -767,13 +773,14 @@ const wrapper = (cond) => Object.assign((...styles) => {
|
|
|
767
773
|
const carry = carried(styles);
|
|
768
774
|
const [bare] = carry.bare ?? [];
|
|
769
775
|
if (bare) throw fail(`cssints: ${cond.text} wraps ${bare[0]}, the marker of kernel ${bare[1]}, with no declaration of its own: a kernel is global CSS keyed to its marker class and cannot be conditional, so the marker would apply everywhere. Put the member outside the condition; a condition can wrap the declarations a member sets (its methods)`);
|
|
770
|
-
return node(merged(styles.flatMap((n) => n.__cssints.map(([p, v, inner = [], fallbacks]) => {
|
|
776
|
+
return node(merged(styles.flatMap((n) => n.__cssints.map(([p, v, inner = [], fallbacks, join]) => {
|
|
771
777
|
if (inner.length >= 4) throw fail(`cssints: a style takes at most 4 conditions (layers ${LAYER[0]} to ${LAYER[4]}); this one has ${inner.length + 1}: ${[cond, ...inner].map((c) => c.text).join(" > ")}`);
|
|
772
778
|
return [
|
|
773
779
|
p,
|
|
774
780
|
v,
|
|
775
781
|
[cond, ...inner],
|
|
776
|
-
fallbacks
|
|
782
|
+
fallbacks,
|
|
783
|
+
join
|
|
777
784
|
];
|
|
778
785
|
}))), carry);
|
|
779
786
|
}, {
|
package/dist/plugin-types.d.mts
CHANGED
|
@@ -2,8 +2,242 @@ import { N as Wrap, X as types_d_exports, dm as Part, fm as Style, lm as CheckIn
|
|
|
2
2
|
import { CSSStyleValue } from "@cssints/css-grammar/values";
|
|
3
3
|
import { Grammar, TokenType } from "@cssints/css-grammar/token";
|
|
4
4
|
import { ValidSelector } from "@cssints/css-grammar/query";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { Warning } from "@cssints/css-grammar/support";
|
|
6
|
+
import "effect";
|
|
7
|
+
interface Rule {
|
|
8
|
+
layer: string;
|
|
9
|
+
/** Sort key within the layer: the min-width of its conditions, then the places of its pseudo-classes. */
|
|
10
|
+
cond: number[];
|
|
11
|
+
/** The at-rule preludes around `css`, outermost first (`@media (width >= 40rem)`). */
|
|
12
|
+
wrap: string[];
|
|
13
|
+
prop: string;
|
|
14
|
+
/** The style rule: `.cls:hover{color:red}`. */
|
|
15
|
+
css: string;
|
|
16
|
+
/** The tokens (`--name`) its value reads. */
|
|
17
|
+
tokens?: string[];
|
|
18
|
+
}
|
|
19
|
+
/** What a plugin member leaves on a style node besides declarations: its name, and the runtime and conflicts it has. */
|
|
20
|
+
interface Plug {
|
|
21
|
+
name: string;
|
|
22
|
+
/** What errors call it (the scope that owns `name`), when that is not `name`. */
|
|
23
|
+
label?: string;
|
|
24
|
+
marker: string;
|
|
25
|
+
conflicts?: Conflict;
|
|
26
|
+
runtime?: Runtime;
|
|
27
|
+
}
|
|
28
|
+
/** A registered runtime, by plugin name: the files whose styles use it. */
|
|
29
|
+
interface RuntimeEntry {
|
|
30
|
+
runtime: Runtime;
|
|
31
|
+
users: Set<string>;
|
|
32
|
+
}
|
|
33
|
+
/** A registered kernel: the custom properties it declares, the markers printed for it, the files that use it. */
|
|
34
|
+
interface KernelEntry {
|
|
35
|
+
kernel: Kernel;
|
|
36
|
+
vars: string[];
|
|
37
|
+
markers: Set<string>;
|
|
38
|
+
users: Set<string>;
|
|
39
|
+
}
|
|
40
|
+
/** A support warning of a declaration in a kernel written as styles, weighed against the runtimes of a style (kernel.ts `addKernel`). */
|
|
41
|
+
interface KernelWarning {
|
|
42
|
+
prop: string;
|
|
43
|
+
/** the value as the sheet prints it: `--_x` is `--<scope>-x` */
|
|
44
|
+
value: string;
|
|
45
|
+
warning: Warning;
|
|
46
|
+
}
|
|
47
|
+
/** The call site being evaluated, set by `__at` before its expression runs. */
|
|
48
|
+
interface At {
|
|
49
|
+
file: string;
|
|
50
|
+
site: number;
|
|
51
|
+
offset: number;
|
|
52
|
+
}
|
|
53
|
+
/** A token's `@property` rule, by variable name (`--color-primary`). One entry per name across all modules. */
|
|
54
|
+
interface Property {
|
|
55
|
+
css: string;
|
|
56
|
+
/** Literals of its type, put in place of `var(--name)` when a value that uses it is checked (TOKEN_TYPES). */
|
|
57
|
+
probes: readonly string[];
|
|
58
|
+
/** Where it was declared: `file#site.n`, `file`, and the evaluation (`gen`) that declared it. */
|
|
59
|
+
by: string;
|
|
60
|
+
file: string;
|
|
61
|
+
gen: number;
|
|
62
|
+
}
|
|
63
|
+
/** What a token is worth, by variable name: its literal (an alias or a derived token: the flattened one), and what it stays live as. */
|
|
64
|
+
interface TokenDef {
|
|
65
|
+
kind: TokenType;
|
|
66
|
+
/** Whether the custom property inherits: only a token that does can be written on <html> by the runtime of derived tokens. */
|
|
67
|
+
inherit: boolean;
|
|
68
|
+
/** `color.bg` for a token of createTokens, else the variable. */
|
|
69
|
+
path: string;
|
|
70
|
+
value: string;
|
|
71
|
+
/** An alias or a derived token: its value with `var(--target)` for each reference, and the variables it refers to. */
|
|
72
|
+
template?: string;
|
|
73
|
+
refs?: string[];
|
|
74
|
+
/** `value` as LightningCSS lowers it for the targets that lack it: the initial value, and the default of a derived token. */
|
|
75
|
+
fallback?: string;
|
|
76
|
+
/** A derived token the runtime computes (derived-data.ts): its flattened literal, which a browser that parses it needs no runtime for. */
|
|
77
|
+
poly?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* A rule of a token set or a theme, in layer _.k after the globals (sheet.ts). `key` orders them: the kind (0 the
|
|
81
|
+
* `:root` declarations of aliases, 1 themes under a condition, 2 themes under a selector), then the place in the source.
|
|
82
|
+
* `names` are the variables it sets or reads: a module that uses one of them has the rule in its sheet too (plugin.ts).
|
|
83
|
+
* `layer`, when set, sends the rule to a **top-level** declared layer of that name instead of `_.k`: a look must rank
|
|
84
|
+
* above the engine's `:root` fallbacks, and a nested layer ranks below the rules of its parent.
|
|
85
|
+
* `theme` is what a contrast check reads: the values the theme sets, by variable name, for the selector `label` (inside
|
|
86
|
+
* `@scope (scope)`, if it has one); `poly` those of them that the runtime of derived tokens computes, with their flattened literals.
|
|
87
|
+
*/
|
|
88
|
+
interface Themed {
|
|
89
|
+
file: string;
|
|
90
|
+
key: string;
|
|
91
|
+
css: string;
|
|
92
|
+
names: string[];
|
|
93
|
+
layer?: string;
|
|
94
|
+
theme?: {
|
|
95
|
+
label: string;
|
|
96
|
+
scope?: string;
|
|
97
|
+
values: Map<string, string>;
|
|
98
|
+
poly?: Map<string, string>;
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** A global rule of a plugin member (`addGlobal`), by its content, with the files whose styles carry it. */
|
|
102
|
+
interface GlobalEntry {
|
|
103
|
+
global: GlobalRule;
|
|
104
|
+
users: Set<string>;
|
|
105
|
+
}
|
|
106
|
+
/** A statement `@layer a, b;` to declare: `before` prints it before the engine's `@layer _.k, …;`, so its layers rank below. */
|
|
107
|
+
interface LayersDecl {
|
|
108
|
+
names: readonly string[];
|
|
109
|
+
before?: boolean;
|
|
110
|
+
}
|
|
111
|
+
/** A declared statement `@layer a, b;` (`layers()`), by its names joined with `,`, with the files that declared it. */
|
|
112
|
+
interface LayerEntry {
|
|
113
|
+
names: string[];
|
|
114
|
+
before: boolean;
|
|
115
|
+
users: Set<string>;
|
|
116
|
+
}
|
|
117
|
+
/** A `css.check.contrast` call, checked once the module that made it has run, and again at the end of a build. */
|
|
118
|
+
interface Check {
|
|
119
|
+
at: At;
|
|
120
|
+
fg: string;
|
|
121
|
+
bg: string;
|
|
122
|
+
min: number;
|
|
123
|
+
gen: number;
|
|
124
|
+
}
|
|
125
|
+
interface RegistryState {
|
|
126
|
+
/** file -> site index -> replacement expression */
|
|
127
|
+
sites: Map<string, Map<number, string>>;
|
|
128
|
+
/** file -> site index -> the declarations of the style it produced: what a cn() with runtime arguments settles (macro.ts `groupOf`) */
|
|
129
|
+
nodes: Map<string, Map<number, Decl$1[]>>;
|
|
130
|
+
/** class -> rule; one entry per class across all modules */
|
|
131
|
+
rules: Map<string, Rule>;
|
|
132
|
+
/** `layer<TAB>css` -> a global rule: in the sheet of the modules that carry it, in layer _.k unless it names a layer (sheet.ts `addGlobal`) */
|
|
133
|
+
globals: Map<string, GlobalEntry>;
|
|
134
|
+
/** the declared top-level layers (sheet.ts `addLayers`) */
|
|
135
|
+
layers: Map<string, LayerEntry>;
|
|
136
|
+
/** key -> the kernels of the styles evaluated so far (sheet.ts `addKernel`): for collisions; the sheet reads the entries of a module */
|
|
137
|
+
kernels: Map<string, KernelEntry>;
|
|
138
|
+
/** plugin name -> its runtime and the files that use it (delivery.ts) */
|
|
139
|
+
runtimes: Map<string, RuntimeEntry>;
|
|
140
|
+
/** scope name -> the hash of its content (scope.ts `register`): a name is unique per process */
|
|
141
|
+
scopes: Map<string, string>;
|
|
142
|
+
/** what scope.ts needs of the eval-time library, set by macro.ts: `css` for a kernel written as styles (with `nest` and `vars`), `kernelOf` to check and print it under its class */
|
|
143
|
+
lib?: {
|
|
144
|
+
css: object;
|
|
145
|
+
kernelOf: (what: string, style: CssNode, cls: string) => {
|
|
146
|
+
css: string;
|
|
147
|
+
props: string[];
|
|
148
|
+
kernels?: Kernel[];
|
|
149
|
+
warnings: KernelWarning[];
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
/** the replacement of a site that holds a node of cssints/tui (tui.ts), set when that module loads */
|
|
153
|
+
tui?: (value: {
|
|
154
|
+
readonly __tui: unknown;
|
|
155
|
+
}) => string | undefined;
|
|
156
|
+
/** the replacement of a site that holds a node of cssints/clay (clay.ts), set when that module loads */
|
|
157
|
+
clay?: (value: {
|
|
158
|
+
readonly __clay: unknown;
|
|
159
|
+
}) => string | undefined;
|
|
160
|
+
/** the tokens and themes of cssints/tui (tui.ts): a namespace of their own, never in a sheet (cssints-0s1z) */
|
|
161
|
+
terminal?: Pick<RegistryState, "properties" | "defs" | "themed">;
|
|
162
|
+
/** the tokens and themes of cssints/clay (clay.ts): a namespace of their own too, never in a sheet */
|
|
163
|
+
clayTokens?: Pick<RegistryState, "properties" | "defs" | "themed">;
|
|
164
|
+
/** what the front of "cssints/plugin" calls (scope-engine.ts `engine`), set by macro.ts */
|
|
165
|
+
engine?: object;
|
|
166
|
+
/** the typed properties of scopes: checked by their own grammar when called, not by the engine */
|
|
167
|
+
userProps: Set<string>;
|
|
168
|
+
/** file -> the evaluation (`gen`) in which its first site ran: its kernels of older ones are forgotten (`__at`) */
|
|
169
|
+
seen: Map<string, number>;
|
|
170
|
+
/** name -> the `@property` rule of every token declared so far (token.ts) */
|
|
171
|
+
properties: Map<string, Property>;
|
|
172
|
+
/** name -> what each token is worth (token.ts, theme.ts): the contrast check and the theme rules read it */
|
|
173
|
+
defs: Map<string, TokenDef>;
|
|
174
|
+
/** `file#site.n` -> the rules of createTokens and createGlobalTheme calls */
|
|
175
|
+
themed: Map<string, Themed>;
|
|
176
|
+
/** `file#site` -> the contrast checks */
|
|
177
|
+
checks: Map<string, Check>;
|
|
178
|
+
/** the evaluation in progress; tokens of an older one that its file no longer declares are stale */
|
|
179
|
+
gen: number;
|
|
180
|
+
/** tokens created at the site being evaluated: two in one site get different private names */
|
|
181
|
+
tokens: number;
|
|
182
|
+
/** warnings not yet handed to Vite, each at the site that made it (`warn`) */
|
|
183
|
+
warnings: Warned[];
|
|
184
|
+
/** `file of the site \0 key` of the warnings said in this build; in dev, until that file is edited (`forgetWarnings`) */
|
|
185
|
+
warned: Set<string>;
|
|
186
|
+
/** `property value feature targets` -> what LightningCSS lowers it to, or false (lowered.ts) */
|
|
187
|
+
lowered: Map<string, string | false>;
|
|
188
|
+
/** the files the evaluation in progress read (`dependsOn`): dependencies of the module being evaluated (plugin.ts `depsOf`) */
|
|
189
|
+
files: Set<string>;
|
|
190
|
+
at?: At;
|
|
191
|
+
/** the site `tokens` is counting for: a call in a loop is one site that registers several tokens */
|
|
192
|
+
site?: string;
|
|
193
|
+
}
|
|
194
|
+
declare global {
|
|
195
|
+
var __cssints: RegistryState | undefined;
|
|
196
|
+
}
|
|
197
|
+
/** A warning and the site that made it, when there is one. */
|
|
198
|
+
interface Warned {
|
|
199
|
+
message: string;
|
|
200
|
+
at?: At | undefined;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* One condition of a style: an at-rule prelude (`@media (width >= 40rem)`), a pseudo-class (`:hover`), an attribute
|
|
204
|
+
* (`[aria-current="page"]`) or, with `ancestor`, a selector of a marked ancestor (`:where(._g:hover)`), or, with
|
|
205
|
+
* `nest` (kernels only), a selector around the class (`& > *`, `:root:has(&)`: `&` is the class); with `own`, its subject
|
|
206
|
+
* is still the element (`.x &`).
|
|
207
|
+
* `rank` orders the rules of a layer: the min-width of a media or container query in px, the place of a pseudo-class.
|
|
208
|
+
*/
|
|
209
|
+
interface Cond {
|
|
210
|
+
text: string;
|
|
211
|
+
rank: number;
|
|
212
|
+
ancestor?: true;
|
|
213
|
+
nest?: true;
|
|
214
|
+
own?: true;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* One declaration: property and value, under the conditions that wrap it (outermost first). `fallbacks` are the other
|
|
218
|
+
* values of a `firstThatWorks(...)`, best first: the rule prints them before `value`, which is the one wanted. `join`
|
|
219
|
+
* makes it a list: when two declarations of this property meet in one `cn()` under the same conditions, their values
|
|
220
|
+
* join with this separator instead of the later one replacing the earlier.
|
|
221
|
+
*/
|
|
222
|
+
type Decl$1 = [prop: string, value: string, conds?: Cond[], fallbacks?: string[], join?: ","];
|
|
223
|
+
/**
|
|
224
|
+
* What a css.* builder returns: its declarations, and next to them the fixed classes it prints (`markers`, each with
|
|
225
|
+
* the key of the kernel it belongs to), the kernels it needs, and the plugin members whose runtime and conflicts apply
|
|
226
|
+
* (`plugs`). `cn()` merges all three. `bare` are the markers of a merged style that came with no declaration of their
|
|
227
|
+
* own (`pretty()`, `frame()`): a condition around it would wrap nothing of theirs, so it is an error.
|
|
228
|
+
*/
|
|
229
|
+
interface CssNode {
|
|
230
|
+
__cssints: Decl$1[];
|
|
231
|
+
markers?: [marker: string, kernel: string][];
|
|
232
|
+
kernels?: Kernel[];
|
|
233
|
+
globals?: GlobalRule[];
|
|
234
|
+
themes?: ThemeRule[];
|
|
235
|
+
layers?: LayersDecl[];
|
|
236
|
+
plugs?: Plug[];
|
|
237
|
+
bare?: [marker: string, kernel: string][];
|
|
238
|
+
}
|
|
239
|
+
/** A declaration a member emits: property and value (a custom property, `--_r`, is allowed); `append()` makes a list. */
|
|
240
|
+
type Decl = readonly [prop: string, value: string, conds?: readonly Cond[], fallbacks?: readonly string[], join?: ","];
|
|
7
241
|
/** A feature of `@mdn/browser-compat-data`: `css.at-rules.container.style_queries_for_custom_properties`. */
|
|
8
242
|
type BcdKey = `css.${string}`;
|
|
9
243
|
/**
|
|
@@ -177,6 +411,17 @@ interface Typed<T> {
|
|
|
177
411
|
}
|
|
178
412
|
/** `arg<T>()`: one value of the TypeScript type `T`. */
|
|
179
413
|
export declare const arg: <T>() => Typed<T>;
|
|
414
|
+
/**
|
|
415
|
+
* `append("--_x", "a")`: a declaration that is a list. Two declarations of the property that meet in one `cn()` under the
|
|
416
|
+
* same conditions join their values with `,` instead of the later replacing the earlier (`@cssints/reactive`'s protocol
|
|
417
|
+
* properties: two `on()`s on one element are one program list). A list beside a plain value of the property is a build
|
|
418
|
+
* error, and so is a list with `firstThatWorks()`: a list has no alternatives.
|
|
419
|
+
*
|
|
420
|
+
* @param {string} prop the property, a custom property for a plugin's own (`--_x` is `--<scope>-x`)
|
|
421
|
+
* @param {string} value the value of this declaration alone
|
|
422
|
+
* @returns {Decl} the declaration, its values joined with `,` when another list of the property follows
|
|
423
|
+
*/
|
|
424
|
+
export declare const append: (prop: string, value: string) => Decl;
|
|
180
425
|
/** One argument: a grammar (aliases of the table allowed), `"$tokens"` (a token set), `"$overrides"` (values for the paths of the `$tokens` before it), `"$selector"` (a CSS selector list) or `arg<T>()`. */
|
|
181
426
|
type Leaf = string | Typed<unknown>;
|
|
182
427
|
/** An object argument of named leaves (`"key?"` is optional). */
|
package/dist/plugin.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as Kernel, c as ThemeRule, i as GlobalRule, n as Conflict, o as Runtime, r as Decl, s as Ship } from "./author-types-
|
|
3
|
-
export { type ArgsDef, type Chain, type Conflict, type Css, type Decl, type Entry, type GlobalRule, type Impl, type Kernel, type KernelDef, type Made, type Members, type Part, type Pending, type Runtime, type Scope, type Ship, type Style, type Table, type ThemeRule, type Typed, arg, dependsOn, fn, inGroup, lacking, scope, ship };
|
|
1
|
+
import { C as Style, S as Part, _ as fn, a as Entry, b as scope, c as Made, d as Scope, f as Table, g as dependsOn, h as arg, i as Css, l as Members, m as append, n as ArgsDef, o as Impl, p as Typed, r as Chain, s as KernelDef, u as Pending, v as inGroup, x as ship, y as lacking } from "./scope-9RiDANgb.mjs";
|
|
2
|
+
import { a as Kernel, c as ThemeRule, i as GlobalRule, n as Conflict, o as Runtime, r as Decl, s as Ship } from "./author-types-CTeNrh2c.mjs";
|
|
3
|
+
export { type ArgsDef, type Chain, type Conflict, type Css, type Decl, type Entry, type GlobalRule, type Impl, type Kernel, type KernelDef, type Made, type Members, type Part, type Pending, type Runtime, type Scope, type Ship, type Style, type Table, type ThemeRule, type Typed, append, arg, dependsOn, fn, inGroup, lacking, scope, ship };
|
package/dist/plugin.mjs
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
/** `arg<T>()`: one value of the TypeScript type `T`. */
|
|
3
3
|
const arg = () => ({ "~arg": 1 });
|
|
4
4
|
/**
|
|
5
|
+
* `append("--_x", "a")`: a declaration that is a list. Two declarations of the property that meet in one `cn()` under the
|
|
6
|
+
* same conditions join their values with `,` instead of the later replacing the earlier (`@cssints/reactive`'s protocol
|
|
7
|
+
* properties: two `on()`s on one element are one program list). A list beside a plain value of the property is a build
|
|
8
|
+
* error, and so is a list with `firstThatWorks()`: a list has no alternatives.
|
|
9
|
+
*
|
|
10
|
+
* @param {string} prop the property, a custom property for a plugin's own (`--_x` is `--<scope>-x`)
|
|
11
|
+
* @param {string} value the value of this declaration alone
|
|
12
|
+
* @returns {Decl} the declaration, its values joined with `,` when another list of the property follows
|
|
13
|
+
*/
|
|
14
|
+
const append = (prop, value) => [
|
|
15
|
+
prop,
|
|
16
|
+
value,
|
|
17
|
+
void 0,
|
|
18
|
+
void 0,
|
|
19
|
+
","
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
5
22
|
* A value member whose `args` is a tuple or `arg<T>()`: `value` gets the arguments as a call member's `build` does. A
|
|
6
23
|
* table cannot type `value` from the `args` beside it (as `build()` does for call members); this call can.
|
|
7
24
|
*/
|
|
@@ -46,4 +63,4 @@ const ship = (entries) => {
|
|
|
46
63
|
});
|
|
47
64
|
return entries;
|
|
48
65
|
};
|
|
49
|
-
export { arg, dependsOn, fn, inGroup, lacking, scope, ship };
|
|
66
|
+
export { append, arg, dependsOn, fn, inGroup, lacking, scope, ship };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Decl, s as Ship, t as BcdKey } from "./author-types-
|
|
1
|
+
import { r as Decl, s as Ship, t as BcdKey } from "./author-types-CTeNrh2c.mjs";
|
|
2
2
|
import { t as ClassValue } from "./runtime-Cv7hGrWf.mjs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { CSS, CSS as CSS$1, CSSColorValue, CSSColorValue as CSSColorValue$1, CSSImageValue, CSSImageValue as CSSImageValue$1, CSSStyleValue, CSSStyleValue as CSSStyleValue$1, CSSUnitValue, CSSUnitValue as CSSUnitValue$1 } from "@cssints/css-grammar/values";
|
|
@@ -3584,6 +3584,17 @@ interface Typed<T> {
|
|
|
3584
3584
|
}
|
|
3585
3585
|
/** `arg<T>()`: one value of the TypeScript type `T`. */
|
|
3586
3586
|
declare const arg: <T>() => Typed<T>;
|
|
3587
|
+
/**
|
|
3588
|
+
* `append("--_x", "a")`: a declaration that is a list. Two declarations of the property that meet in one `cn()` under the
|
|
3589
|
+
* same conditions join their values with `,` instead of the later replacing the earlier (`@cssints/reactive`'s protocol
|
|
3590
|
+
* properties: two `on()`s on one element are one program list). A list beside a plain value of the property is a build
|
|
3591
|
+
* error, and so is a list with `firstThatWorks()`: a list has no alternatives.
|
|
3592
|
+
*
|
|
3593
|
+
* @param {string} prop the property, a custom property for a plugin's own (`--_x` is `--<scope>-x`)
|
|
3594
|
+
* @param {string} value the value of this declaration alone
|
|
3595
|
+
* @returns {Decl} the declaration, its values joined with `,` when another list of the property follows
|
|
3596
|
+
*/
|
|
3597
|
+
declare const append: (prop: string, value: string) => Decl;
|
|
3587
3598
|
/** One argument: a grammar (aliases of the table allowed), `"$tokens"` (a token set), `"$overrides"` (values for the paths of the `$tokens` before it), `"$selector"` (a CSS selector list) or `arg<T>()`. */
|
|
3588
3599
|
type Leaf = string | Typed<unknown>;
|
|
3589
3600
|
/** An object argument of named leaves (`"key?"` is optional). */
|
|
@@ -3810,4 +3821,4 @@ declare const inGroup: (group: string, property: string, value: string) => boole
|
|
|
3810
3821
|
declare const ship: (entries: {
|
|
3811
3822
|
readonly [key: string]: unknown;
|
|
3812
3823
|
}) => Ship;
|
|
3813
|
-
export { Style as S,
|
|
3824
|
+
export { Style as C, Part as S, fn as _, Entry as a, scope as b, Made as c, Scope as d, Table as f, dependsOn as g, arg as h, Css as i, Members as l, append as m, ArgsDef as n, Impl as o, Typed as p, Chain as r, KernelDef as s, AliasesOf as t, Pending as u, inGroup as v, ship as x, lacking as y };
|
package/dist/surface.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as AliasesOf } from "./scope-
|
|
1
|
+
import { t as AliasesOf } from "./scope-9RiDANgb.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* `surface().color(t.color.canvas).lighten(0.06).ink()`: a background that follows from the surface around it, however
|
|
4
4
|
* many plain wrappers sit between. `color(<color>)` is an absolute base (default: the parent surface); `lighten(step)`,
|
|
@@ -221,15 +221,30 @@ function merged(decls) {
|
|
|
221
221
|
const out = [];
|
|
222
222
|
const at = (d) => (d[2] ?? []).map((c) => c.text).join(" > ");
|
|
223
223
|
for (const d of decls) {
|
|
224
|
+
if (d[4] && d[3]) throw fail(`cssints: ${d[0]} is a list (${JSON.stringify(d[1])}) with firstThatWorks(): a list has no alternatives`);
|
|
224
225
|
const where = at(d);
|
|
226
|
+
let decl = d;
|
|
225
227
|
for (let i = out.length - 1; i >= 0; i--) {
|
|
226
228
|
const o = out[i];
|
|
227
229
|
if (at(o) !== where) continue;
|
|
228
230
|
const r = relation(o[0], d[0]);
|
|
229
|
-
if (r === "same")
|
|
230
|
-
|
|
231
|
+
if (r === "same") {
|
|
232
|
+
if (o[4] || d[4]) {
|
|
233
|
+
if (o[4] !== d[4]) throw fail(`cssints: ${d[0]} is a list ${JSON.stringify(o[4] ? o[1] : d[1])} and a value ${JSON.stringify(o[4] ? d[1] : o[1])}: they cannot be merged${where ? ` (under ${where})` : ""}`);
|
|
234
|
+
out.splice(i, 1);
|
|
235
|
+
decl = [
|
|
236
|
+
d[0],
|
|
237
|
+
`${o[1]}${o[4]}${decl[1]}`,
|
|
238
|
+
d[2],
|
|
239
|
+
void 0,
|
|
240
|
+
o[4]
|
|
241
|
+
];
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
out.splice(i, 1);
|
|
245
|
+
} else if (r === "overlap") throw fail(`cssints: ${o[0]} and ${d[0]} overlap without one containing the other${where ? ` (under ${where})` : ""}, so the sheet cannot order them by the arguments: set one of them, or the longhands`);
|
|
231
246
|
}
|
|
232
|
-
out.push(
|
|
247
|
+
out.push(decl);
|
|
233
248
|
}
|
|
234
249
|
return out;
|
|
235
250
|
}
|
package/dist/tui.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as registry } from "./registry-8sYvlzyn.mjs";
|
|
2
|
-
import { a as createTokens$1, i as createGlobalTheme$1, j as fail, s as sets } from "./theme-
|
|
2
|
+
import { a as createTokens$1, i as createGlobalTheme$1, j as fail, s as sets } from "./theme-B7ttL9B5.mjs";
|
|
3
3
|
import { g as evaluate, h as css } from "./sheet-rwl57DmD.mjs";
|
|
4
4
|
import { n as valueOf, t as together } from "./contrast-BB0wimFI.mjs";
|
|
5
5
|
import { n as parseColor } from "./color-BB8ipynT.mjs";
|
package/dist/vite.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { i as GlobalRule } from "./author-types-X4zGpNpU.mjs";
|
|
2
1
|
import { n as ImportError, r as MacroError } from "./errors-jNEiB3ye.mjs";
|
|
3
|
-
import {
|
|
2
|
+
import { d as LayersDecl, f as RegistryState, i as GlobalRule, u as At } from "./author-types-CTeNrh2c.mjs";
|
|
4
3
|
import { Effect } from "effect";
|
|
5
4
|
import { ImportDeclaration } from "oxc-parser";
|
|
6
5
|
import MagicString from "magic-string";
|
package/docs/API.md
CHANGED
|
@@ -85,7 +85,7 @@ The static arguments of `cn` are one class string; `prop && p(4)` depends on a r
|
|
|
85
85
|
|
|
86
86
|
- **The class names** are a hash of the declaration (and its conditions), so the same declaration gives the same class in every file.
|
|
87
87
|
- **One sheet.** All rules are in `virtual:cssints.css`, each once, sorted by layer, then condition, then shorthand before longhand (`border` before `border-top`, counted from Chrome's own expansion of each shorthand), then class name. So a longhand wins over a shorthand that contains it, whatever the order of the arguments: `cn(pl(2), p(4))` keeps `padding-left: 0.5rem`.
|
|
88
|
-
- **`cn()` keeps the later of the same property.** `cn(p(4), p(2))` is `p(2)`: the earlier declaration is dropped at build time (also for an alias: `wordWrap` is `overflowWrap`). Under different conditions both stay, because they are in different layers: `cn(md(p(6)), p(2))`. Two properties that overlap without one containing the other are a build error, because the sheet cannot order them by the arguments: `cn(borderTop("1px solid red"), borderColor("blue"))` both set `border-top-color`; so do a physical and a logical side (`marginLeft` and `marginInline`, `width` and `inlineSize`), since which physical side a logical one is depends on the writing mode. A logical property inside a physical shorthand that sets every side is contained, not overlapping: `cn(border(...), borderInline(...))` is fine, and `borderInline` wins. A style in a runtime argument is compared with the static arguments at build time, and replaces the classes it overrides while it is active (see "Runtime: `cn`, `cv`").
|
|
88
|
+
- **`cn()` keeps the later of the same property.** `cn(p(4), p(2))` is `p(2)`: the earlier declaration is dropped at build time (also for an alias: `wordWrap` is `overflowWrap`). Under different conditions both stay, because they are in different layers: `cn(md(p(6)), p(2))`. Two properties that overlap without one containing the other are a build error, because the sheet cannot order them by the arguments: `cn(borderTop("1px solid red"), borderColor("blue"))` both set `border-top-color`; so do a physical and a logical side (`marginLeft` and `marginInline`, `width` and `inlineSize`), since which physical side a logical one is depends on the writing mode. A logical property inside a physical shorthand that sets every side is contained, not overlapping: `cn(border(...), borderInline(...))` is fine, and `borderInline` wins. A style in a runtime argument is compared with the static arguments at build time, and replaces the classes it overrides while it is active (see "Runtime: `cn`, `cv`"). A declaration can be a list (`append()` in `cssints/plugin`): two of them of one property under the same conditions join their values instead of the later replacing the earlier, one beside a plain value of the property is a build error, and a list has no `firstThatWorks()` fallbacks (2026-10-31, cssints-674d).
|
|
89
89
|
- **A layout context** gives one string: `flex().alignItems("center")` is `"_1s47490 _1ob5z5m"`.
|
|
90
90
|
- **Also exported:** `css` (the namespace as a value) and `chain`, `cn`, `cv`, `firstThatWorks`, `media`, `container`, `supports`, `attr`, `within`, `group`, `global`, `token`, `style`, `createTokens`, `createGlobalTheme`, `check`. Nothing is exported for the browser: the runtime is the plugin's.
|
|
91
91
|
|
|
@@ -886,6 +886,7 @@ export const hidden = ring().core; // error: no such method
|
|
|
886
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? }`.
|
|
887
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.
|
|
888
888
|
- **`themes`** — `themes: { tokens, overrides, selector, layer?, scope? }[]` from `build` is `createGlobalTheme(tokens, selector, overrides, { layer, scope })` made by a member, through the same path: the paths and values of `overrides` are checked against the types of `tokens` at build time, the aliases that depend on an override are declared again, and `check.contrast` reads the theme with the others. With `args: ["$tokens", "$overrides", ...]` the member takes the token set from its caller and the overrides are checked in the types as well.
|
|
889
|
+
- **`append(prop, value)`** (decided 2026-10-31, cssints-674d) makes a declaration a list: two declarations of that property in one `cn()` under the same conditions join their values with `,` instead of the later replacing the earlier, and a third still appends. It is how a plugin puts several programs on one element: `@cssints/reactive`'s two `on()` calls are `--reactive-on: click toggle open,keydown set tab two`. A list beside a plain value of the property is a build error (appending would be wrong, replacing would drop a program: `cssints: --x is a list "a" and a value "b": they cannot be merged`), and a list has no `firstThatWorks()` alternatives. The separator belongs to the declaration and nothing else reads it: the sheet prints the joined value, the class hash, clay, tui and the devtools see it as one declaration. A `cv()` variant is an alternative, not a list: a list declared in a variant replaces the base's as any declaration does.
|
|
889
890
|
|
|
890
891
|
```ts
|
|
891
892
|
import { scope } from "cssints/plugin";
|
|
@@ -1222,27 +1223,27 @@ export const typo = mdi("clos"); // error: not an icon of mdi
|
|
|
1222
1223
|
|
|
1223
1224
|
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`.
|
|
1224
1225
|
|
|
1225
|
-
| Package | Members
|
|
1226
|
-
| ----------------------------------------------------------- |
|
|
1227
|
-
| [`@cssints/fluid`](../packages/fluid/README.md) | `fluid(min, max, { from?, to?, zoom? })`, `fluid.container(...)`
|
|
1228
|
-
| [`@cssints/layout`](../packages/layout/README.md) | `stack()`, `cluster()`, `sidebar()`, `switcher()`, `cover()`, `autoGrid()`
|
|
1229
|
-
| [`@cssints/fonts`](../packages/fonts/README.md) | `font(family, { provider, ... })` → `.family()`, `.trim()`
|
|
1230
|
-
| [`@cssints/reset`](../packages/reset/README.md) | `reset({ media?, prose? })`
|
|
1231
|
-
| [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors`, `/madoromi`
|
|
1232
|
-
| [`@cssints/gradient`](../packages/gradient/README.md) | `gradient(kind, direction, from, to, easing?, stops?)`
|
|
1233
|
-
| [`@cssints/gradient-2d`](../packages/gradient-2d/README.md) | `meshGradient(mesh)`, `freeformGradient(points)`
|
|
1234
|
-
| [`@cssints/color-names`](../packages/color-names/README.md) | `named(name)`, `colorNames.<sector>(name)`, `/nearest`
|
|
1235
|
-
| [`@cssints/motion`](../packages/motion/README.md) | `motion().preset().duration().delay().easing()`
|
|
1236
|
-
| [`@cssints/squircle`](../packages/squircle/README.md) | `squircle().radius()`
|
|
1237
|
-
| [`@cssints/reveal`](../packages/reveal/README.md) | `reveal().preset().range().duration().easing()`, `appear().preset().range().duration().easing().inOut()`
|
|
1238
|
-
| [`@cssints/stuck`](../packages/stuck/README.md) | `sticky().top()`, `stuck(styles)`, `stuck("bottom")(styles)`
|
|
1239
|
-
| [`@cssints/balance`](../packages/balance/README.md) | `balance()`, `pretty()`
|
|
1240
|
-
| [`@cssints/masonry`](../packages/masonry/README.md) | `masonry().columns().gap()`
|
|
1241
|
-
| [`@cssints/placeholder`](../packages/placeholder/README.md) | `placeholder(path, { mode? })`
|
|
1242
|
-
| [`@cssints/ramp`](../packages/ramp/README.md) | `ramp(base, { mode, steps \| ratios, background })`, `overrides(ramp)`
|
|
1243
|
-
| [`@cssints/rybitten`](../packages/rybitten/README.md) | `color(hue, { cube })`, `wheel(steps, { cube })`, `shades(hue, lightness)`, `overrides(group)`
|
|
1244
|
-
| [`@cssints/skeleton`](../packages/skeleton/README.md) | `skeleton().radius().color().highlight()`
|
|
1245
|
-
| [`@cssints/reactive`](../packages/reactive/README.md) | `state()`, `toggle()`, `set()`, `on()`, `bind()`, `when()`, `inside()`
|
|
1226
|
+
| Package | Members | What it does |
|
|
1227
|
+
| ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1228
|
+
| [`@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 |
|
|
1229
|
+
| [`@cssints/layout`](../packages/layout/README.md) | `stack()`, `cluster()`, `sidebar()`, `switcher()`, `cover()`, `autoGrid()` | Every Layout primitives as chain members |
|
|
1230
|
+
| [`@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 |
|
|
1231
|
+
| [`@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 |
|
|
1232
|
+
| [`@cssints/tokens`](../packages/tokens/README.md) | `/open-props`, `/radix`, `/flexoki`, `/reasonable-colors`, `/madoromi` | DTCG data for `createTokens` |
|
|
1233
|
+
| [`@cssints/gradient`](../packages/gradient/README.md) | `gradient(kind, direction, from, to, easing?, stops?)` | Eased colour stops mixed in oklab at build time |
|
|
1234
|
+
| [`@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) |
|
|
1235
|
+
| [`@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 |
|
|
1236
|
+
| [`@cssints/motion`](../packages/motion/README.md) | `motion().preset().duration().delay().easing()` | Animation presets over `keyframes()`, with reduced motion |
|
|
1237
|
+
| [`@cssints/squircle`](../packages/squircle/README.md) | `squircle().radius()` | `corner-shape: squircle`, else a CSS `mask` of the same shape |
|
|
1238
|
+
| [`@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) |
|
|
1239
|
+
| [`@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) |
|
|
1240
|
+
| [`@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) |
|
|
1241
|
+
| [`@cssints/masonry`](../packages/masonry/README.md) | `masonry().columns().gap()` | `display: grid-lanes`, else CSS `columns` (top to bottom per column) |
|
|
1242
|
+
| [`@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 |
|
|
1243
|
+
| [`@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 |
|
|
1244
|
+
| [`@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 |
|
|
1245
|
+
| [`@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 |
|
|
1246
|
+
| [`@cssints/reactive`](../packages/reactive/README.md) | `state()`, `toggle()`, `set()`, `value()`, `checked()`, `persist()`, `on()`, `bind()`, `when()`, `inside()` | State as custom properties, events as data on the element: writes only in events, conditions and DOM output in plain CSS, wired by a 1.2 kB runtime shipped to every target; `value()`/`checked()` take the field's value, calls of `on()`, `bind()` or `state()` in one `cn()` append, and `persist(value, key)` keeps a state across a reload (2026-10-31, cssints-674d) |
|
|
1246
1247
|
|
|
1247
1248
|
### Headless: `createField` and `createConfirm` (`@cssints/headless`)
|
|
1248
1249
|
|
|
@@ -1768,7 +1769,7 @@ createSlider(options?: {
|
|
|
1768
1769
|
focus(): void;
|
|
1769
1770
|
blur(): void;
|
|
1770
1771
|
keyDown(key: string): boolean; // true when the key was consumed (preventDefault it)
|
|
1771
|
-
pointerDown(position: number): void; // a rail press at a 0..1 fraction of the
|
|
1772
|
+
pointerDown(position: number): void; // a rail press or a drag move at a 0..1 fraction of the rail
|
|
1772
1773
|
thumbProps: {
|
|
1773
1774
|
id;
|
|
1774
1775
|
role: "slider";
|
|
@@ -1782,8 +1783,9 @@ createSlider(options?: {
|
|
|
1782
1783
|
onFocus;
|
|
1783
1784
|
onBlur;
|
|
1784
1785
|
onKeyDown;
|
|
1786
|
+
onPointerDown;
|
|
1785
1787
|
};
|
|
1786
|
-
trackProps: { onPointerDown };
|
|
1788
|
+
trackProps: { onPointerDown; onPointerMove; onPointerUp; onPointerCancel; onLostPointerCapture };
|
|
1787
1789
|
};
|
|
1788
1790
|
```
|
|
1789
1791
|
|
|
@@ -1839,13 +1841,17 @@ createSpinbutton(options?: {
|
|
|
1839
1841
|
|
|
1840
1842
|
`disabled` is **a widget-level extension of the APG patterns**, and the specs say so: `slider.qnt` lists it under its deliberate omissions, and `spinbutton.qnt` models the steppers' at-bound state only (`DisabledOnlyAtBound`). Neither machine has a `disabled` var, so the DOM tests, not the model, hold the primitive to these rules:
|
|
1841
1843
|
|
|
1842
|
-
- a disabled slider **keeps the thumb as its tab stop** (`tabindex="0"`, the same choice `createButton` makes with `aria-disabled`) and announces `aria-disabled="true"` on the thumb; every key
|
|
1844
|
+
- a disabled slider **keeps the thumb as its tab stop** (`tabindex="0"`, the same choice `createButton` makes with `aria-disabled`) and announces `aria-disabled="true"` on the thumb; every key, rail press and drag is dropped before it becomes a request, so `onValueChange` never fires and `keyDown` returns `false` (nothing to preventDefault);
|
|
1843
1845
|
- a disabled spinbutton's field announces `aria-disabled` **and carries the native `disabled`** (the field is an `<input>`, so the platform's own form-control rule applies); the spin keys, the typed draft (Enter and blur included) and both steppers change nothing, and **both** steppers announce `aria-disabled="true"` — the at-bound rule of the spec stays, and a disabled widget adds the other side;
|
|
1844
1846
|
- both read the option on every attribute read, so a host may flip `disabled` on a mounted widget and the attributes and the guards follow in the same tick.
|
|
1845
1847
|
|
|
1848
|
+
**Dragging** is the rail press repeated: `pointerdown` on the rail jumps the value to where it landed and starts a drag, and a press on the thumb starts the drag where the value already is (no jump, the thumb is there). While the pointer is held, every `pointermove` asks for the value of the pointer's position on the rail, rounded to `step` and clamped to `min`/`max`, in all four combinations of `orientation` and `direction`: up is more on a vertical rail, and a horizontal rail under `rtl` counts from its right edge, the same reflection the arrow keys use. `pointerup`, `pointercancel` or a lost capture ends the drag. The rail owns the gesture whichever element took the press, so the moves sit on `trackProps` and pointer capture keeps the drag alive off the rail: no document listener, and nothing to clean up on disposal. The thumb must be rendered inside the rail, because that is how its press reaches it. A drag is still a request: it fires `onValueChange` once per distinct value, and a controlled host that ignores the request keeps its value. `trackProps` carries no CSS, so a host that wants a drag instead of a text selection or a page scroll sets `touch-action: none` and `user-select: none` on the rail.
|
|
1849
|
+
|
|
1850
|
+
`specs/apg/slider.qnt` fixes a discrete rail press only, so the drag is a second deliberate extension and `slider.browser.test.tsx` is its oracle. The invariant the machine does not carry is **DragFollowsPointer**: while the pointer is held, `aria-valuenow` is the value of the pointer's current position (not an accumulation of moves, so returning the pointer to the press position returns the value), and no move after the release changes anything. The step grid and the clamp the drag shares with the press are the model's; the geometry is the DOM's, and the bridge hands the model a 0..1 fraction.
|
|
1851
|
+
|
|
1846
1852
|
### Headless: `createSliderMultiThumb` (`@cssints/headless`)
|
|
1847
1853
|
|
|
1848
|
-
The APG Slider (Multi-Thumb) pattern: two `role="slider"` thumbs on one rail, each bounded by its neighbour, so they cannot pass one another; equal values are allowed. Its behaviour is `packages/apg-specs/specs/apg/slider-multithumb.qnt`, checked against the real DOM by the differential walk in `packages/headless/test/slider-multithumb.browser.test.tsx`. The spec fixes two thumbs and one linked pair: the independent-thumbs variant, N thumbs
|
|
1854
|
+
The APG Slider (Multi-Thumb) pattern: two `role="slider"` thumbs on one rail, each bounded by its neighbour, so they cannot pass one another; equal values are allowed. Its behaviour is `packages/apg-specs/specs/apg/slider-multithumb.qnt`, checked against the real DOM by the differential walk in `packages/headless/test/slider-multithumb.browser.test.tsx`. The spec fixes two thumbs and one linked pair: the independent-thumbs variant, N thumbs and per-thumb dragging are not modelled, and the primitive's nearest-thumb rail press, its drag and `disabled` are deliberate extensions of the pattern, with that DOM test as their oracle. Options are plain and read lazily; `value` + `onValueChange` make the widget controlled.
|
|
1849
1855
|
|
|
1850
1856
|
```ts skip
|
|
1851
1857
|
createSliderMultiThumb(options?: {
|
|
@@ -1856,14 +1862,15 @@ createSliderMultiThumb(options?: {
|
|
|
1856
1862
|
value?: readonly [number, number] | undefined; // controlled; undefined = uncontrolled
|
|
1857
1863
|
defaultValue?: readonly [number, number]; // [3, 7], clamped into the range and ordered
|
|
1858
1864
|
orientation?: "horizontal" | "vertical"; // "horizontal"
|
|
1859
|
-
direction?: "ltr" | "rtl"; // "ltr": under rtl the horizontal arrows flip
|
|
1865
|
+
direction?: "ltr" | "rtl"; // "ltr": under rtl the horizontal arrows and the rail flip
|
|
1866
|
+
disabled?: boolean; // aria-disabled on both thumbs; no key, press or drag changes anything
|
|
1860
1867
|
id?: string; // base of the thumb ids
|
|
1861
1868
|
onValueChange?(values: readonly [number, number]): void; // a request the host may ignore
|
|
1862
1869
|
}): {
|
|
1863
1870
|
values(): readonly [number, number];
|
|
1864
1871
|
focused(): 0 | 1 | null;
|
|
1865
1872
|
setValues(values: readonly [number, number]): void;
|
|
1866
|
-
pointerDown(index: 0 | 1, position: number): void; // a press at a 0..1 fraction of the
|
|
1873
|
+
pointerDown(index: 0 | 1, position: number): void; // a press or a drag move at a 0..1 fraction of the value axis
|
|
1867
1874
|
focusThumb(index: 0 | 1): void;
|
|
1868
1875
|
blur(): void;
|
|
1869
1876
|
keyDown(key: string): boolean; // true when the key was consumed (preventDefault it)
|
|
@@ -1875,15 +1882,28 @@ createSliderMultiThumb(options?: {
|
|
|
1875
1882
|
"aria-valuemax"; // the lower thumb: the upper value; the upper thumb: the range's maximum
|
|
1876
1883
|
"aria-valuetext";
|
|
1877
1884
|
"aria-orientation";
|
|
1885
|
+
"aria-disabled"; // "true" while disabled, else undefined
|
|
1878
1886
|
tabindex: 0;
|
|
1879
1887
|
onFocus;
|
|
1880
1888
|
onBlur;
|
|
1881
1889
|
onKeyDown;
|
|
1890
|
+
onPointerDown;
|
|
1891
|
+
};
|
|
1892
|
+
trackProps: {
|
|
1893
|
+
onPointerDown;
|
|
1894
|
+
onPointerMove;
|
|
1895
|
+
onPointerUp;
|
|
1896
|
+
onPointerCancel;
|
|
1897
|
+
onLostPointerCapture;
|
|
1882
1898
|
};
|
|
1883
1899
|
};
|
|
1884
1900
|
```
|
|
1885
1901
|
|
|
1886
|
-
Both thumbs are tab stops in a fixed order (lower, then upper), whatever the values are.
|
|
1902
|
+
Both thumbs are tab stops in a fixed order (lower, then upper), whatever the values are.
|
|
1903
|
+
|
|
1904
|
+
`trackProps` is a rail press and a drag, like the single slider's: `pointerdown` beside the thumbs names the thumb nearest the pointer (a tie goes to the lower, the pair's floor and first tab stop) and moves it to the pointer's position; a press that starts on a thumb drags that thumb from the value it already has, without a jump. While the pointer is held, every `pointermove` asks for that thumb's value at the pointer's position on the rail, rounded to `step` and clamped to the neighbour, in all four combinations of `orientation` and `direction` (up is more on a vertical rail, and a horizontal rail under `rtl` counts from its right edge, as the arrows do). `pointerup`, `pointercancel` or a lost capture ends the drag. The rail owns the gesture whichever element took the press, so the moves sit on `trackProps`; the thumb must be rendered inside the rail, and pointer capture keeps the drag alive off it. A drag is still a request: it fires `onValueChange` once per distinct pair, a controlled host that ignores it keeps its pair, and a thumb clamps at its neighbour so the two can never cross. `focused()` names the thumb the press took and reads synchronously, so a host can move the DOM focus with it. `trackProps` carries no CSS, so a host that wants a drag instead of a page scroll or a text selection sets `touch-action: none` and `user-select: none` on the rail.
|
|
1905
|
+
|
|
1906
|
+
`disabled` follows the single slider: both thumbs keep their tab stops and announce `aria-disabled="true"`, and every key, rail press and drag is dropped before it becomes a request. The spec has no `disabled` var, so `slider-multithumb.browser.test.tsx` is its oracle, as it is for the press's nearest thumb (`NearestThumbTakesPress`) and the drag (`DragFollowsPointer`).
|
|
1887
1907
|
|
|
1888
1908
|
### Headless: `createKnob` (`@cssints/headless`)
|
|
1889
1909
|
|
|
@@ -2014,6 +2034,40 @@ createTimeline(options: {
|
|
|
2014
2034
|
- **Selection.** A click selects and moves the tab stop; ArrowUp / ArrowDown / Home / End move a roving tab stop; Enter or Space selects the focused row. The host moves real DOM focus after an arrow key, as the demo fixture does; `selected` + `onSelect` make it controlled, `select(id)` is the programmatic request.
|
|
2015
2035
|
- **`status` is `data-status`** on the row, a styling hook for the host's colour. The primitive never invents the label: the host's data holds it.
|
|
2016
2036
|
|
|
2037
|
+
### Headless: `createDiagramFocus` (`@cssints/headless`)
|
|
2038
|
+
|
|
2039
|
+
The readable twin of a canvas: the same nodes and edges, positioned by the host (absolute `div`s, an SVG layer for the edges), as one roving tab stop plus a keyboard cursor over the outgoing edges, with a polite live region saying where the user is. **The APG has no pattern for a diagram** — a graph is not one of the 44 — so there is no Quint spec and no ported scenarios: `packages/headless/test/diagram.browser.test.tsx` is its oracle. It borrows the grid's roving tabindex (exactly one node in the tab order, so Tab leaves the composite), WAI-ARIA's `aria-roledescription="node"` on each `role="button"`, and `createStatus`'s `role="status"` / `aria-live="polite"` region.
|
|
2040
|
+
|
|
2041
|
+
```ts skip
|
|
2042
|
+
createDiagramFocus(options: {
|
|
2043
|
+
nodes: ReadonlyArray<{ id: string; label: string; x: number; y: number; width?: number; height?: number }> | (() => ...); // x/y: the node's top-left in diagram space; width/height only size its centre (0)
|
|
2044
|
+
edges: ReadonlyArray<{ id: string; from: string; to: string; label?: string }> | (() => ...); // in option order; an edge with a missing endpoint is ignored
|
|
2045
|
+
onActivate?(nodeId: string): void; // Enter or Space on the active node
|
|
2046
|
+
onEdgeActivate?(edgeId: string): void; // Enter on the edge cursor, or a click on an edge
|
|
2047
|
+
labels?: { diagram?: string; edges?: string } | undefined; // the diagram's name in the announcement; the edge noun ("transitions", default "edges")
|
|
2048
|
+
id?: string | undefined; // base for the nodes' element ids (<id>-node-<node id>), which is how a move focuses the node; generated when absent
|
|
2049
|
+
}): {
|
|
2050
|
+
active(): string | undefined; // the node holding the tab stop; undefined when the diagram is empty
|
|
2051
|
+
focus(id: string): string | undefined; // programmatic move; a node that is not in `nodes` is a no-op; returns where it landed
|
|
2052
|
+
nodeProps(id: string): { id: string; role: "button"; "aria-roledescription": "node"; "aria-label": string; tabindex: 0 | -1; onFocus; onClick; onKeyDown };
|
|
2053
|
+
edgeProps(id: string): { role: "button"; "aria-label": string; tabindex: -1; onClick }; // "From → To"
|
|
2054
|
+
edgesOf(id: string): ReadonlyArray<{ id: string; from: string; to: string; label?: string }>; // outgoing, in option order
|
|
2055
|
+
edgeCursor(): number; // an index into edgesOf(active()), or -1 while off
|
|
2056
|
+
setEdgeCursor(index: number): void; // the programmatic version; a negative index clears
|
|
2057
|
+
status(): string; // "Payment. 2 edges: to Pending, to Failed" / "Edge Payment → Pending. Enter to activate"; empty when the diagram is empty
|
|
2058
|
+
statusProps: { role: "status"; "aria-live": "polite" }; // render once, always
|
|
2059
|
+
};
|
|
2060
|
+
```
|
|
2061
|
+
|
|
2062
|
+
- **The layout is the navigation.** An arrow moves to the nearest node whose centre is in that direction's half-plane (right is `dx > 0`, up is `dy < 0`), by smallest squared distance, ties by id; when nothing lies that way it wraps to the opposite end of that axis (right to the leftmost node, down to the topmost, ties by id), so every arrow does something. Home / End are the first and last node in option order. The arrows compare **centres**, which is why `width`/`height` exist at all.
|
|
2063
|
+
- **A diagram is never drag-only.** The pointer path is the host's drawing; the keyboard path is the arrows plus Enter / Space (`onActivate`) and `e`, so a graph that was drawn with a mouse is still readable and operable from the keyboard.
|
|
2064
|
+
- **`e` opens the outgoing edges.** The cursor starts on the first edge of `edgesOf(active)` and the region says "Edge Payment → Pending. Enter to activate". Arrows move the cursor and wrap, Enter (or Space) fires `onEdgeActivate`, Escape — or any other navigation key — leaves the cursor. Edges are `role="button"` with `tabindex="-1"`: the keyboard path to an edge is the cursor, not a Tab stop, so 40 transitions do not add 40 stops.
|
|
2065
|
+
- **The live region is the announcement.** `status()` is derived from the active node and the cursor, so it changes with every move (that is what makes a screen reader read it). Render `statusProps` once and always; a region that mounts with its text announces nothing.
|
|
2066
|
+
- **Exactly one node is in the tab order.** `nodeProps` sets `tabindex="0"` on the active node and `-1` on the rest, and `onFocus` moves the tab stop to whatever node took focus, so a host that focuses the node it selects keeps the two in step. Tab then leaves the diagram (there is no `Tab` handling and no sentinels).
|
|
2067
|
+
- **Focus follows the tab stop by itself.** `nodeProps` also carries an element `id` (`<base>-node-<node id>`, the base from `options.id` or generated), so an arrow, Home / End or `focus(id)` focuses the node it landed on: the host spreads the props and needs no effect, and the tab stop and `document.activeElement` cannot disagree. A host that renders a node outside the document (a portal on another document) moves focus itself.
|
|
2068
|
+
- **The lists are getters.** Pass `() => nodes()` and the arrays are read at attribute-read time: an async model arrives without rebuilding the primitive, and the tab stop keeps its node while that node exists (else it falls back to the first). A node id that is not in `nodes` is a no-op in `nodeProps` and `focus`; an edge whose endpoint is missing is ignored everywhere.
|
|
2069
|
+
- **The host owns the DOM.** Nothing is measured, nothing is positioned and nothing is focused by the primitive; the host renders the nodes where its layout put them, the edges on its SVG layer, and the `role="status"` paragraph.
|
|
2070
|
+
|
|
2017
2071
|
### Publishing a library (decided 2026-10-02, cssints-0l3f)
|
|
2018
2072
|
|
|
2019
2073
|
A package written on cssints ships JavaScript that still has the attribute, and its `.d.ts`. The app that installs it evaluates the package with its own engine: one sheet, the app's browserslist and themes, and a token, a kernel or an `@property` of the package is made once however many modules use it. Nothing is declared: the engine recognises a file by `with { type: "cssints" }`, the same marker as in app code.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cssints",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.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": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@cssints/css-grammar": "^0.
|
|
75
|
+
"@cssints/css-grammar": "^0.24.0",
|
|
76
76
|
"culori": "^4.0.2",
|
|
77
77
|
"effect": "4.0.6",
|
|
78
78
|
"happy-dom": "^20.14.5",
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/** A declaration a member emits: property and value (a custom property, `--_r`, is allowed). */
|
|
2
|
-
type Decl = readonly [prop: string, value: string];
|
|
3
|
-
/** A feature of `@mdn/browser-compat-data`: `css.at-rules.container.style_queries_for_custom_properties`. */
|
|
4
|
-
type BcdKey = `css.${string}`;
|
|
5
|
-
/**
|
|
6
|
-
* Global rules, registered once by `key` (`name@version`) in layer `_.k`; `atProperty` (the `@property` rules of its
|
|
7
|
-
* custom properties) goes at the top of the sheet. A target lacking a `requires` feature gets a support warning, never an
|
|
8
|
-
* error; `{ key, exact: true }` also counts a partial implementation as lacking (relative colour, whose channel scales
|
|
9
|
-
* differ in Chrome 119-121 and Safari 16.4-17.6). Two members share a kernel by pointing at the same object; the same key with other CSS is a build error, as is
|
|
10
|
-
* a custom property or a marker that two keys share.
|
|
11
|
-
*/
|
|
12
|
-
interface Kernel {
|
|
13
|
-
key: string;
|
|
14
|
-
css: string;
|
|
15
|
-
atProperty?: string;
|
|
16
|
-
requires?: (BcdKey | {
|
|
17
|
-
key: BcdKey;
|
|
18
|
-
exact: true;
|
|
19
|
-
})[];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* A global rule a member contributes. It is identified by its content (`layer` and `css`): the same rule from two
|
|
23
|
-
* styles is one, an edit of it replaces the old one, and it is in the sheet of the modules whose styles carry it, until
|
|
24
|
-
* they stop. It goes to layer `_.k` with the kernels. Unlike a kernel, two globals **may** declare the same custom
|
|
25
|
-
* property: a look sets the same `--color-*` in several source layers, which is the point of fill-through. Use it for a
|
|
26
|
-
* rule that is not a class.
|
|
27
|
-
*/
|
|
28
|
-
interface GlobalRule {
|
|
29
|
-
css: string;
|
|
30
|
-
/**
|
|
31
|
-
* A top-level `@layer` of this name to put the rule in (a rule that must beat the engine's `:root` fallbacks). The
|
|
32
|
-
* layer must be declared: by `layers` of the same `Made`, or by `layers()` in a module this one imports. Omitted:
|
|
33
|
-
* layer `_.k`.
|
|
34
|
-
*/
|
|
35
|
-
layer?: string;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* A theme a member contributes, as `createGlobalTheme(tokens, selector, overrides, { layer, scope })` makes one: the
|
|
39
|
-
* same checks (the paths and values of `overrides` against the types of `tokens`, a layer that is declared), the
|
|
40
|
-
* aliases that depend on an override declared again, and `check.contrast` reads it. `tokens` is a token set of
|
|
41
|
-
* `createTokens()` that the member got from its caller (a closure: the arguments of a member are joined into one string).
|
|
42
|
-
*/
|
|
43
|
-
interface ThemeRule {
|
|
44
|
-
tokens: object;
|
|
45
|
-
overrides: object;
|
|
46
|
-
selector: string;
|
|
47
|
-
layer?: string;
|
|
48
|
-
/** A selector: the rule goes inside `@scope (<scope>) { ... }`. */
|
|
49
|
-
scope?: string;
|
|
50
|
-
}
|
|
51
|
-
/** One element family of a runtime: the nearest `marker` ancestor's computed `read` is copied into `write`. */
|
|
52
|
-
interface ParentVar {
|
|
53
|
-
marker: string;
|
|
54
|
-
read: `--${string}`;
|
|
55
|
-
write: `--${string}`;
|
|
56
|
-
/** A property that changes when a CSS condition (`:hover`, a media query) changes `read`: its transition re-runs the copy. */
|
|
57
|
-
watch?: `--${string}`;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* The runtime half of a member. The client module that holds a site with the member imports
|
|
61
|
-
* `virtual:cssints/runtime/<name>`, which is empty unless a browserslist target lacks a feature in `polyfills` (and, with
|
|
62
|
-
* `parentVars`, has `@property`, which the script stands on); then it imports `script`, configures `cssints/parent-vars`,
|
|
63
|
-
* and `css` (the fallback rules) is added to the sheet in layer `_.k`. A `requires` of the member's kernel that is in
|
|
64
|
-
* `polyfills` warns only for the targets the runtime does not reach.
|
|
65
|
-
*/
|
|
66
|
-
interface Runtime {
|
|
67
|
-
polyfills: BcdKey[];
|
|
68
|
-
parentVars?: ParentVar[];
|
|
69
|
-
css?: string;
|
|
70
|
-
/** The plugin's browser script, a module specifier the app resolves (`"@cssints/balance/runtime"`): imported, never evaluated at build time. */
|
|
71
|
-
script?: string;
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* A value a site ships as a JavaScript object of its own: `ship({ owner, open })` (`@cssints/reactive`'s `state()`, whose
|
|
75
|
-
* owner is a style and whose sources are data). Each `Style` becomes its class string, an array or an object keeps its
|
|
76
|
-
* shape, and anything else is its JSON.
|
|
77
|
-
*/
|
|
78
|
-
interface Ship {
|
|
79
|
-
readonly "~ship": {
|
|
80
|
-
readonly [key: string]: unknown;
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/** A build error when one `cn()` holds the member's marker and a property listed here (a name, or a pattern). */
|
|
84
|
-
interface Conflict {
|
|
85
|
-
props: (string | RegExp)[];
|
|
86
|
-
message: string;
|
|
87
|
-
}
|
|
88
|
-
export { Kernel as a, ThemeRule as c, GlobalRule as i, Conflict as n, Runtime as o, Decl as r, Ship as s, BcdKey as t };
|