nuclo 0.2.19 → 0.2.21

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.
@@ -2,14 +2,21 @@ import type { ClassInput, CssInstance, FlatStyle, KeyframeFrames, Style, StyleRe
2
2
  export type { ClassInput, CssInstance, CSSProperties, FlatStyle, KeyframeFrames, KeyframeStop, Pseudo, Size, Style, StyleResult, ThemeConfig, VariantDefinitions, VariantProps, VariantsConfig, VariantsFn, } from "../../types/style";
3
3
  /**
4
4
  * Compose class lists with exact conflict resolution: when two inputs style
5
- * the same (query, selector, property), the last one wins. Works because the
6
- * engine knows what every class it generated means. Nested arrays are flattened,
7
- * so `cx([a, cond && b], c)` composes the same as `cx(a, cond && b, c)`.
5
+ * the same (query, selector-suffix) context, their declaration blocks merge
6
+ * with the later input winning per property — the merged block gets its own
7
+ * content-addressed class, so `cx(base, active)` keeps every base property
8
+ * the active style doesn't override. Works because the engine remembers what
9
+ * every class it minted means. Unknown external classes pass through as-is.
10
+ * Nested arrays are flattened, so `cx([a, cond && b], c)` composes the same
11
+ * as `cx(a, cond && b, c)`.
8
12
  */
9
13
  export declare function cx(...inputs: ClassInput[]): StyleResult;
10
14
  export declare function createCss<const T extends ThemeConfig>(theme?: T): CssInstance<T>;
11
15
  /** Themeless css() — full property/variant typing, no tokens or screens. */
12
- export declare const css: (style: Style<object>) => StyleResult;
16
+ export declare const css: {
17
+ (style: Style<object>): StyleResult;
18
+ (name: string, style: Style<object>): StyleResult;
19
+ };
13
20
  /** Themeless variants() recipe helper. */
14
21
  export declare const variants: <const V extends VariantDefinitions<object>>(config: VariantsConfig<object, V>) => VariantsFn<V>;
15
22
  /** Themeless keyframes() helper. */
@@ -1 +1 @@
1
- {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../src/style/css.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,cAAc,EAEd,KAAK,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAElB,cAAc,EACd,UAAU,EACV,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,cAAc,EACd,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,KAAK,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,UAAU,GACV,MAAM,mBAAmB,CAAC;AAiJ3B;;;;;GAKG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,WAAW,CAMvD;AAKD,wBAAgB,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,GAAE,CAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CA2NzF;AAgBD,4EAA4E;AAC5E,eAAO,MAAM,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,WAAwD,CAAC;AACrG,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EACjE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAC7B,UAAU,CAAC,CAAC,CAAqD,CAAC;AACvE,oCAAoC;AACpC,eAAO,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,MAA2D,CAAC;AACxH,sCAAsC;AACtC,eAAO,MAAM,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK,IACxB,CAAC"}
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../../src/style/css.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACX,UAAU,EACV,WAAW,EACX,SAAS,EACT,cAAc,EAEd,KAAK,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAElB,cAAc,EACd,UAAU,EACV,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,SAAS,EACT,cAAc,EACd,YAAY,EACZ,MAAM,EACN,IAAI,EACJ,KAAK,EACL,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,UAAU,GACV,MAAM,mBAAmB,CAAC;AA+L3B;;;;;;;;;GASG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,WAAW,CAMvD;AAKD,wBAAgB,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,GAAE,CAAW,GAAG,WAAW,CAAC,CAAC,CAAC,CA8QzF;AAgBD,4EAA4E;AAC5E,eAAO,MAAM,GAAG,EAAE;IACjB,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC;IACpC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC;CAIV,CAAC;AAC1C,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,kBAAkB,CAAC,MAAM,CAAC,EACjE,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,KAC7B,UAAU,CAAC,CAAC,CAAqD,CAAC;AACvE,oCAAoC;AACpC,eAAO,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,MAA2D,CAAC;AACxH,sCAAsC;AACtC,eAAO,MAAM,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK,IACxB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Shared atomic-CSS engine state.
2
+ * Shared generated-CSS engine state.
3
3
  *
4
4
  * One stylesheet, one rule registry, shared by every `createCss` instance so
5
5
  * identical declarations dedupe globally and cascade order stays deterministic:
@@ -11,19 +11,44 @@
11
11
  */
12
12
  type SSRCollector = (rule: string) => void;
13
13
  export declare function setSSRCollector(fn: SSRCollector | null): void;
14
+ export interface BlockMeta {
15
+ readonly query: string | undefined;
16
+ readonly suffix: string;
17
+ readonly decls: ReadonlyArray<readonly [string, string]>;
18
+ /** Author-supplied identity from `css(name, …)`; inherited by cx() merges. */
19
+ readonly name: string | undefined;
20
+ }
14
21
  /** Pre-register at-rule queries so their cascade order follows theme order. */
15
22
  export declare function registerQueries(queries: Iterable<string>): void;
16
23
  /**
17
- * Order-independent 53-bit content hash (two interleaved FNV-1a style passes).
18
- * Class names must match between server and client for SSR hydration, so a
19
- * counter is not an option; 53 bits keeps collision odds negligible (~1e-5 at
20
- * 10k unique declarations).
24
+ * Content-addressed ~42-bit hash (two interleaved FNV-1a style passes). Class
25
+ * names must match between server and client for SSR hydration, so a counter
26
+ * is not an option; 42 bits keeps collision odds low (~1e-5 at 10k
27
+ * unique declaration blocks).
21
28
  */
22
29
  export declare function hash(input: string): string;
23
- /** One class per (query, selector-suffix, declaration) — the atomic core. */
24
- export declare function atom(query: string | undefined, suffix: string, property: string, value: string): string;
25
- /** Conflict key for a generated class — lets cx() resolve overrides exactly. */
30
+ export declare function expandAmpersands(input: string, replacement: string): string;
31
+ /**
32
+ * One class per (query, selector-suffix) — every declaration that shares that
33
+ * context compiles into a single rule under a single generated class name,
34
+ * rather than one class per individual property. Pass `name` to give the
35
+ * style a stable, readable identity (see mintBlock).
36
+ */
37
+ export declare function atomBlock(query: string | undefined, suffix: string, decls: ReadonlyArray<readonly [string, string]>, name?: string, exactName?: boolean): string;
38
+ /**
39
+ * Merge two same-context generated classes into one: `second`'s declarations
40
+ * override `first`'s per exact property (shorthand/longhand interplay is left
41
+ * to CSS order), and the combined block mints its own content-addressed class
42
+ * — so cx(base, override) keeps base's untouched properties instead of
43
+ * dropping the whole base class. Deterministic: the same pair always yields
44
+ * the same class name, on server and client alike. A named base passes its
45
+ * name down as a prefix, so `cx(appRoot, active)` reads as `app-root-1a2b3c`.
46
+ */
47
+ export declare function mergeBlocks(first: string, second: string): string;
48
+ /** Conflict key (query|suffix) for a generated class — lets cx() group classes by selector context. */
26
49
  export declare function conflictKeyOf(className: string): string | undefined;
50
+ /** Current registry generation, used to invalidate per-instance WeakMap hits after resetStyles(). */
51
+ export declare function getStyleEpoch(): number;
27
52
  /** Register a non-atomic rule (keyframes, global styles) once per dedupe key. */
28
53
  export declare function addRawRule(dedupeKey: string, rule: string): void;
29
54
  /** All generated CSS — base rules first, then at-rule groups in registration order. */
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/style/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAG3C,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAE7D;AAwBD,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAI/D;AA0FD;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS1C;AAED,6EAA6E;AAC7E,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAavG;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAOhE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED,gFAAgF;AAChF,wBAAgB,WAAW,IAAI,IAAI,CAclC"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/style/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAG3C,wBAAgB,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAE7D;AAQD,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACzD,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AA4BD,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAI/D;AAsND;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS1C;AAWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAsB3E;AA+FD;;;;;GAKG;AACH,wBAAgB,SAAS,CACxB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC/C,IAAI,CAAC,EAAE,MAAM,EACb,SAAS,UAAQ,GACf,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAWjE;AAED,uGAAuG;AACvG,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGnE;AAED,qGAAqG;AACrG,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAOhE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED,gFAAgF;AAChF,wBAAgB,WAAW,IAAI,IAAI,CAiBlC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "nuclo",
3
3
  "private": false,
4
- "version": "0.2.19",
5
- "description": "Lightweight, type-safe DOM library with plain mutable state and explicit updates — global tag builders, SSR, hydration, and atomic CSS, no virtual DOM, no compiler.",
4
+ "version": "0.2.21",
5
+ "description": "Lightweight, type-safe DOM library with plain mutable state and explicit updates — global tag builders, SSR, hydration, and typed CSS, no virtual DOM, no compiler.",
6
6
  "license": "MIT",
7
7
  "author": "Danilo Celestino de Castro (https://github.com/dan2dev)",
8
8
  "keywords": [
@@ -56,6 +56,7 @@
56
56
  "test": "npm run typecheck && vitest run --coverage",
57
57
  "test:watch": "vitest --watch --coverage",
58
58
  "bench": "bun bench/ssr.bench.ts && bun bench/hydrate.bench.ts",
59
+ "bench:style": "bun bench/style.bench.ts",
59
60
  "bench:jfb": "bun bench/js-framework.bench.ts",
60
61
  "lint": "eslint . --ext .ts,.js,.json,.jsonc,.json5,.md,.css",
61
62
  "lint:fix": "eslint . --ext .ts,.js,.json,.jsonc,.json5,.md,.css --fix"
@@ -62,6 +62,8 @@ declare global {
62
62
 
63
63
  /** Themeless css() — full property/variant typing, no tokens or screens. */
64
64
  function css(style: Style<object>): StyleResult;
65
+ /** Themeless css() under a readable, stable class name: `css("app-root", { … })` → `.app-root`. */
66
+ function css(name: string, style: Style<object>): StyleResult;
65
67
  /** Compose class lists with last-wins conflict resolution. */
66
68
  function cx(...inputs: ClassInput[]): StyleResult;
67
69
  /** Themeless variants() recipe helper. */
package/types/index.d.ts CHANGED
@@ -107,6 +107,7 @@ export const isBrowser: boolean;
107
107
  // Styling (themeless default instance + themed factory)
108
108
  export function createCss<const T extends ThemeConfig>(theme?: T): CssInstance<T>;
109
109
  export function css(style: Style<object>): StyleResult;
110
+ export function css(name: string, style: Style<object>): StyleResult;
110
111
  export function cx(...inputs: ClassInput[]): StyleResult;
111
112
  export function variants<const V extends VariantDefinitions<object>>(
112
113
  config: VariantsConfig<object, V>,
package/types/ssr.d.ts CHANGED
@@ -41,5 +41,5 @@ export function renderToStringWithContainer(
41
41
  */
42
42
  export function setSSRCollector(fn: ((rule: string) => void) | null): void;
43
43
 
44
- /** Serialize every registered atomic CSS rule (for a <style> tag in SSR output). */
44
+ /** Serialize every registered generated CSS rule (for a <style> tag in SSR output). */
45
45
  export function getCssText(): string;
package/types/style.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * nuclo styling type definitions — atomic, theme-aware, typed CSS-in-TS.
2
+ * nuclo styling type definitions — block-based, theme-aware, typed CSS-in-TS.
3
3
  *
4
4
  * This module is the single source of truth for the styling types. It lives in
5
5
  * `types/` (shipped in the npm package alongside `dist/`) so that both the
@@ -334,7 +334,7 @@ export type StyleResult = {
334
334
  };
335
335
 
336
336
  // ---------------------------------------------------------------------------
337
- // Variants — typed, atomic style recipes (base + named variant groups +
337
+ // Variants — typed style recipes (base + named variant groups +
338
338
  // defaults + compound variants). One recipe in, a call-with-props function out.
339
339
  // ---------------------------------------------------------------------------
340
340
 
@@ -379,10 +379,19 @@ export type ClassInput = StyleResult | string | false | null | undefined | reado
379
379
  /** A themed styling instance returned by createCss(). */
380
380
  export interface CssInstance<T extends ThemeConfig = ThemeConfig> {
381
381
  /**
382
- * Compile a style object into atomic CSS classes.
382
+ * Compile a style object into CSS classes — one per selector context
383
+ * (base, each pseudo-selector, each media query) it touches.
383
384
  * Returns `{ className }` — usable directly as a nuclo attributes object.
384
385
  */
385
386
  css(style: Style<T>): StyleResult;
387
+ /**
388
+ * Compile a style object under a readable, stable class name:
389
+ * `css("app-root", { minHeight: "100vh" })` → `.app-root`.
390
+ * The base context takes the name verbatim; the style's other contexts
391
+ * take it as a prefix (`app-root-1a2b3c`). Named styles are keyed by name
392
+ * as well as content, so they never share a class with an unrelated style.
393
+ */
394
+ css(name: string, style: Style<T>): StyleResult;
386
395
  /**
387
396
  * Compose class lists with exact conflict resolution: when two inputs
388
397
  * style the same (query, selector, property), the last one wins.