@csszyx/runtime 0.9.10 → 0.10.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/index.d.cts CHANGED
@@ -43,53 +43,6 @@ type SzInput = string | SzObject | SzInput[] | null | undefined | false;
43
43
  * ```
44
44
  */
45
45
  declare function _sz(...classes: SzInput[]): string;
46
- /**
47
- * Conditionally applies className based on a condition.
48
- *
49
- * Supports both pre-compiled strings and SzObjects for dynamic styling.
50
- * This is the recommended helper for conditional class application.
51
- *
52
- * @param {boolean} condition - Whether to apply the truthy value
53
- * @param {SzInput} truthyValue - ClassName or SzObject when condition is true
54
- * @param {SzInput} falsyValue - ClassName or SzObject when condition is false
55
- * @returns {string} The resolved className string
56
- *
57
- * @example
58
- * ```typescript
59
- * // With strings (pre-compiled)
60
- * _szIf(isActive, 'bg-green-500', 'bg-gray-500')
61
- * // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
62
- *
63
- * // With SzObjects (runtime transform)
64
- * _szIf(isActive, { bg: 'green-500' }, { bg: 'gray-500' })
65
- * // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
66
- *
67
- * // Without fallback
68
- * _szIf(isActive, { bg: 'green-500' })
69
- * // Returns: "bg-green-500" if isActive, "" otherwise
70
- * ```
71
- */
72
- declare function _szIf(condition: boolean, truthyValue: SzInput, falsyValue?: SzInput): string;
73
- /**
74
- * Applies className based on multiple conditions (switch-like).
75
- *
76
- * Returns the className for the first truthy condition, or the default.
77
- * Supports both strings and SzObjects.
78
- *
79
- * @param {Array<[boolean, SzInput]>} conditions - Array of [condition, value] tuples
80
- * @param {SzInput} defaultValue - Default value if no conditions match
81
- * @returns {string} The matched className or default
82
- *
83
- * @example
84
- * ```typescript
85
- * _szSwitch([
86
- * [status === 'success', { text: 'green-500' }],
87
- * [status === 'error', { text: 'red-500' }],
88
- * [status === 'warning', { text: 'yellow-500' }]
89
- * ], { text: 'gray-500' })
90
- * ```
91
- */
92
- declare function _szSwitch(conditions: Array<[boolean, SzInput]>, defaultValue?: SzInput): string;
93
46
  /**
94
47
  * Merges className strings, removing duplicates.
95
48
  *
@@ -349,19 +302,19 @@ declare function disableCSRRecovery(): void;
349
302
  */
350
303
  declare function isCSRRecoveryAllowed(): boolean;
351
304
  /**
352
- * Loads the mangle map from the DOM.
353
- *
354
- * Searches for the embedded mangle map script tag and parses it.
305
+ * Validate a parsed mangle map before it is used to rewrite class names. The map
306
+ * is read from the DOM (attacker-writable if the served HTML is compromised), so
307
+ * it must be a plain object of string→string with no prototype-polluting keys.
308
+ * A malformed map is rejected rather than applied.
355
309
  *
356
- * @returns {MangleMap | null} The mangle map or null if not found
310
+ * @param value - the `JSON.parse`d candidate.
311
+ * @returns true when `value` is a safe `MangleMap`.
312
+ */
313
+ declare function isValidMangleMap(value: unknown): value is MangleMap;
314
+ /**
315
+ * Load and validate the mangle map embedded in the DOM by the SSR pipeline.
357
316
  *
358
- * @example
359
- * ```typescript
360
- * const mangleMap = loadMangleMapFromDOM();
361
- * if (mangleMap) {
362
- * console.log('Mangle map loaded');
363
- * }
364
- * ```
317
+ * @returns the validated mangle map, or `null` if absent or invalid.
365
318
  */
366
319
  declare function loadMangleMapFromDOM(): MangleMap | null;
367
320
  /**
@@ -382,20 +335,53 @@ declare function loadMangleMapFromDOM(): MangleMap | null;
382
335
  */
383
336
  declare function verifyMangleChecksum(expectedChecksum: string): boolean;
384
337
  /**
385
- * Verifies mangle map integrity using Rust core verification.
338
+ * Recompute a mangle map's checksum the same way the Rust core does
339
+ * (`compute_checksum_internal`): SHA-256 over the entries sorted by key and
340
+ * formatted `orig:mangle`, joined by `|`, hex-encoded, first 16 chars (64 bits).
386
341
  *
387
- * Loads the mangle map from DOM and verifies its checksum using the
388
- * Rust core's `verify_mangle_checksum()` function for cryptographic-grade verification.
342
+ * Uses the Web Crypto API (`crypto.subtle`), so it works WITHOUT the WASM core —
343
+ * unlike the WASM-only sync path. Async because `crypto.subtle.digest` is async.
389
344
  *
390
- * @returns {boolean} True if mangle map integrity is verified
345
+ * @param map - the mangle map to checksum.
346
+ * @returns the 16-char hex checksum (matches the Rust output byte-for-byte for
347
+ * ASCII class names).
348
+ */
349
+ declare function computeMangleChecksumAsync(map: MangleMap): Promise<string>;
350
+ /**
351
+ * Verify a mangle map's integrity by RECOMPUTING its checksum (via Web Crypto)
352
+ * and comparing it to the expected value — real verification that works without
353
+ * the WASM core. Unlike the sync {@link verifyMangleChecksum} (a plain attribute
354
+ * compare), this recomputes from the map, so it detects a map that was altered
355
+ * without updating the checksum.
391
356
  *
392
- * @example
393
- * ```typescript
394
- * if (!verifyMangleMapIntegrity()) {
395
- * console.error('[csszyx] Mangle map integrity check failed');
396
- * abortHydration();
397
- * }
398
- * ```
357
+ * Still tamper-DETECTION, not authentication: the checksum is unsigned, so an
358
+ * attacker who can rewrite the served HTML can recompute it after editing the
359
+ * map. Use it to catch corruption / accidental drift, not as a trust boundary.
360
+ *
361
+ * @param expectedChecksum - the checksum to match (e.g. from the manifest or the
362
+ * `data-sz-checksum` attribute).
363
+ * @param map - the mangle map; loaded (and schema-validated) from the DOM when omitted.
364
+ * @returns a promise resolving true when the map is present and its recomputed
365
+ * checksum matches.
366
+ */
367
+ declare function verifyMangleChecksumAsync(expectedChecksum: string, map?: MangleMap): Promise<boolean>;
368
+ /**
369
+ * Verifies mangle map integrity using the Rust core checksum verifier.
370
+ *
371
+ * Loads the mangle map from the DOM, validates its shape, and (when the WASM
372
+ * core is present) verifies its checksum via `verify_mangle_checksum()`.
373
+ *
374
+ * IMPORTANT — this is tamper-DETECTION, not authentication. The checksum is an
375
+ * unsigned SHA-256 truncation: it catches accidental server/client drift, but an
376
+ * attacker who can rewrite the served HTML can recompute it after editing the
377
+ * map. Treat it as an integrity (corruption) check, not a trust boundary.
378
+ *
379
+ * When the WASM verifier is absent (the common no-core deployment), the checksum
380
+ * cannot be recomputed in this sync path, so verification degrades to a
381
+ * schema-validated load and emits a dev warning rather than failing closed
382
+ * (failing closed here would break every app not shipping the WASM core).
383
+ *
384
+ * @returns {boolean} True if the map is well-formed and (if verifiable) matches.
399
385
  */
400
386
  declare function verifyMangleMapIntegrity(): boolean;
401
387
  /**
@@ -612,6 +598,133 @@ declare function startHydration(): void;
612
598
  */
613
599
  declare function endHydration(): void;
614
600
 
601
+ /** Which side of the CSS box-model border a property acts on. */
602
+ type BoxRole = 'outer' | 'inner';
603
+
604
+ /**
605
+ * Route a (csszyx-emitted) className string to nested elements by CSS box-model
606
+ * role, plus a category-aware toolkit that exposes csszyx's class knowledge as
607
+ * primitives. Pure string functions — framework-agnostic, cross-platform, no
608
+ * React, no DOM. The class-token → box-role map is GENERATED from the compiler's
609
+ * property tables (see `box-role-map.generated.ts`), so it never drifts.
610
+ *
611
+ * The problem this solves: a caller passes one flat `className` (e.g. from an sz
612
+ * prop) to a component, but the component renders nested elements — the margin
613
+ * belongs on the outer frame while the padding belongs on the inner content. A
614
+ * slot recipe can't re-route a caller's flat string; only a runtime partition
615
+ * can. `splitBox` does that partition at the border line (outer = border-outward,
616
+ * inner = border-inward); the toolkit lets a project express cross-element
617
+ * dependency rules (e.g. "if the frame clips, make the scroller scroll") without
618
+ * hardcoding csszyx's class vocabulary.
619
+ */
620
+
621
+ /** The classification of a single class token. */
622
+ interface Classification {
623
+ /** Which side of the border the property acts on. */
624
+ readonly role: BoxRole;
625
+ /** Semantic group (margin, padding, border, overflow, text, …). */
626
+ readonly category: string;
627
+ }
628
+ /**
629
+ * A way to address a set of classes. One of:
630
+ * - a box-role: `'outer'` | `'inner'`
631
+ * - a box-layer alias: `'content'` (= inner) (`'margin'`/`'border'`/`'padding'`
632
+ * are also categories, so they work directly)
633
+ * - a category: `'overflow'`, `'text'`, `'bg'`, …
634
+ * - a class-prefix: `'px'`, `'bg'`, … (matches `px-2`, `bg-red-500`, …)
635
+ * - a category+value pair: `{ overflow: 'hidden' }`
636
+ */
637
+ type BoxSelector = string | Readonly<Record<string, string>>;
638
+ /** Options controlling how `splitBox` partitions a className. */
639
+ interface SplitBoxOptions {
640
+ /** Force these selectors onto the outer node, overriding the default map. */
641
+ outer?: BoxSelector[];
642
+ /** Force these selectors onto the inner node, overriding the default map. */
643
+ inner?: BoxSelector[];
644
+ /** Where an unrecognized token goes. Defaults to `'outer'`. */
645
+ fallback?: BoxRole;
646
+ }
647
+ /** The two class buckets produced by `splitBox`. */
648
+ interface SplitBoxResult {
649
+ /** Classes for the outer (border-outward) element. */
650
+ outer: string;
651
+ /** Classes for the inner (border-inward) element. */
652
+ inner: string;
653
+ }
654
+ /**
655
+ * Classify a class token by box-model role + semantic category, or `undefined`
656
+ * if it is not a csszyx-owned utility. Variant-, important- and negative-aware.
657
+ *
658
+ * @param token - A single class token to classify.
659
+ * @returns The token's role and category, or `undefined` if unowned.
660
+ */
661
+ declare function classify(token: string): Classification | undefined;
662
+ /**
663
+ * Partition a className string into `{ outer, inner }` at the CSS box-model
664
+ * border line. Every token lands in exactly one bucket (no loss, no duplication)
665
+ * and keeps its variant prefix. Overrides in `options.inner` / `options.outer`
666
+ * win over the default map; `inner` is checked first when a token matches both.
667
+ *
668
+ * @param className - The flat className string to partition.
669
+ * @param options - Overrides for forcing tokens onto a node and the fallback role.
670
+ * @returns The `{ outer, inner }` class buckets.
671
+ * @example splitBox('m-4 px-2 md:flex') // → { outer: 'm-4', inner: 'px-2 md:flex' }
672
+ */
673
+ declare function splitBox(className: string, options?: SplitBoxOptions): SplitBoxResult;
674
+ /**
675
+ * Does any token in `classes` match `selector`? Variant- and mangle-robust.
676
+ *
677
+ * @param classes - A className string to scan.
678
+ * @param selector - The selector to test tokens against.
679
+ * @returns `true` if any token matches the selector.
680
+ */
681
+ declare function has(classes: string, selector: BoxSelector): boolean;
682
+ /**
683
+ * Keep only the tokens in `classes` that match `selector`.
684
+ *
685
+ * @param classes - A className string to filter.
686
+ * @param selector - The selector tokens must match to be kept.
687
+ * @returns The matching tokens joined by spaces.
688
+ */
689
+ declare function pick(classes: string, selector: BoxSelector): string;
690
+ /**
691
+ * Drop the tokens in `classes` that match `selector`, keeping the rest.
692
+ *
693
+ * @param classes - A className string to filter.
694
+ * @param selector - The selector tokens must match to be dropped.
695
+ * @returns The non-matching tokens joined by spaces.
696
+ */
697
+ declare function omit(classes: string, selector: BoxSelector): string;
698
+
699
+ /**
700
+ * Drop the `sz` prop before a component spreads `...rest` onto a host element.
701
+ *
702
+ * The compiler rewrites `sz` to `className` at build time, so a compiled
703
+ * component never carries a leftover `sz` prop. But when a file is NOT compiled
704
+ * — e.g. a workspace package missing from `compilePackages`, or any source the
705
+ * bundler skipped — a hand-forwarded `sz` survives and React spreads it to the
706
+ * DOM as `sz="[object Object]"`. `stripSzProps` removes `sz` from the forwarded
707
+ * props so it never reaches the DOM, and in development warns once when the
708
+ * leaked `sz` is a raw object, pointing at the real cause (an uncompiled file).
709
+ *
710
+ * Pure, framework-agnostic, no React/DOM import.
711
+ *
712
+ * @example
713
+ * function Box({ sz, ...rest }: BoxProps) {
714
+ * return <div {...stripSzProps(rest)} />; // rest may still carry sz when uncompiled
715
+ * }
716
+ */
717
+ /**
718
+ * Return `props` without its `sz` key. When `sz` is absent the original object
719
+ * is returned unchanged (no allocation); otherwise a shallow copy without `sz`
720
+ * is returned. In development, a raw-object `sz` (the uncompiled-leak signature)
721
+ * triggers a one-time warning.
722
+ *
723
+ * @param props - the props a component is about to forward to a host element.
724
+ * @returns the same props without `sz`.
725
+ */
726
+ declare function stripSzProps<T extends Record<string, unknown>>(props: T): Omit<T, 'sz'>;
727
+
615
728
  /**
616
729
  * szv() — variant-based sz object factory.
617
730
  *
@@ -632,9 +745,7 @@ type VariantSchema = Record<string, Record<string, SzObject>>;
632
745
  type VariantSelection<V extends VariantSchema> = {
633
746
  [K in keyof V]?: keyof V[K] | null | undefined;
634
747
  };
635
- /**
636
- *
637
- */
748
+ /** Configuration for a variant component: base styles, variants, and defaults. */
638
749
  interface SzvConfig<V extends VariantSchema> {
639
750
  base?: SzObject;
640
751
  variants: V;
@@ -655,7 +766,7 @@ interface SzvConfig<V extends VariantSchema> {
655
766
  * import { szv } from 'csszyx';
656
767
  *
657
768
  * const buttonSz = szv({
658
- * base: { inlineFlex: true, items: 'center', rounded: 'md', fontWeight: 'medium' },
769
+ * base: { display: 'inline-flex', items: 'center', rounded: 'md', weight: 'medium' },
659
770
  * variants: {
660
771
  * variant: {
661
772
  * default: { bg: 'primary', text: 'primary-foreground' },
@@ -769,5 +880,5 @@ declare function isRuntimeInitialized(): boolean;
769
880
  */
770
881
  declare function resetRuntime(): void;
771
882
 
772
- export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szIf, _szMerge, _szSwitch, abortHydration, attemptCSRRecovery, clearHydrationErrors, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, resetRuntime, startHydration, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleMapIntegrity, verifyRecoveryToken };
773
- export type { HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SzInput, TokenData, VerificationResult };
883
+ export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szMerge, abortHydration, attemptCSRRecovery, classify, clearHydrationErrors, computeMangleChecksumAsync, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, has, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidMangleMap, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, omit, pick, resetRuntime, splitBox, startHydration, stripSzProps, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleChecksumAsync, verifyMangleMapIntegrity, verifyRecoveryToken };
884
+ export type { BoxRole, BoxSelector, Classification, HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SplitBoxOptions, SplitBoxResult, SzInput, TokenData, VerificationResult };
package/dist/index.d.mts CHANGED
@@ -43,53 +43,6 @@ type SzInput = string | SzObject | SzInput[] | null | undefined | false;
43
43
  * ```
44
44
  */
45
45
  declare function _sz(...classes: SzInput[]): string;
46
- /**
47
- * Conditionally applies className based on a condition.
48
- *
49
- * Supports both pre-compiled strings and SzObjects for dynamic styling.
50
- * This is the recommended helper for conditional class application.
51
- *
52
- * @param {boolean} condition - Whether to apply the truthy value
53
- * @param {SzInput} truthyValue - ClassName or SzObject when condition is true
54
- * @param {SzInput} falsyValue - ClassName or SzObject when condition is false
55
- * @returns {string} The resolved className string
56
- *
57
- * @example
58
- * ```typescript
59
- * // With strings (pre-compiled)
60
- * _szIf(isActive, 'bg-green-500', 'bg-gray-500')
61
- * // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
62
- *
63
- * // With SzObjects (runtime transform)
64
- * _szIf(isActive, { bg: 'green-500' }, { bg: 'gray-500' })
65
- * // Returns: "bg-green-500" if isActive, "bg-gray-500" otherwise
66
- *
67
- * // Without fallback
68
- * _szIf(isActive, { bg: 'green-500' })
69
- * // Returns: "bg-green-500" if isActive, "" otherwise
70
- * ```
71
- */
72
- declare function _szIf(condition: boolean, truthyValue: SzInput, falsyValue?: SzInput): string;
73
- /**
74
- * Applies className based on multiple conditions (switch-like).
75
- *
76
- * Returns the className for the first truthy condition, or the default.
77
- * Supports both strings and SzObjects.
78
- *
79
- * @param {Array<[boolean, SzInput]>} conditions - Array of [condition, value] tuples
80
- * @param {SzInput} defaultValue - Default value if no conditions match
81
- * @returns {string} The matched className or default
82
- *
83
- * @example
84
- * ```typescript
85
- * _szSwitch([
86
- * [status === 'success', { text: 'green-500' }],
87
- * [status === 'error', { text: 'red-500' }],
88
- * [status === 'warning', { text: 'yellow-500' }]
89
- * ], { text: 'gray-500' })
90
- * ```
91
- */
92
- declare function _szSwitch(conditions: Array<[boolean, SzInput]>, defaultValue?: SzInput): string;
93
46
  /**
94
47
  * Merges className strings, removing duplicates.
95
48
  *
@@ -349,19 +302,19 @@ declare function disableCSRRecovery(): void;
349
302
  */
350
303
  declare function isCSRRecoveryAllowed(): boolean;
351
304
  /**
352
- * Loads the mangle map from the DOM.
353
- *
354
- * Searches for the embedded mangle map script tag and parses it.
305
+ * Validate a parsed mangle map before it is used to rewrite class names. The map
306
+ * is read from the DOM (attacker-writable if the served HTML is compromised), so
307
+ * it must be a plain object of string→string with no prototype-polluting keys.
308
+ * A malformed map is rejected rather than applied.
355
309
  *
356
- * @returns {MangleMap | null} The mangle map or null if not found
310
+ * @param value - the `JSON.parse`d candidate.
311
+ * @returns true when `value` is a safe `MangleMap`.
312
+ */
313
+ declare function isValidMangleMap(value: unknown): value is MangleMap;
314
+ /**
315
+ * Load and validate the mangle map embedded in the DOM by the SSR pipeline.
357
316
  *
358
- * @example
359
- * ```typescript
360
- * const mangleMap = loadMangleMapFromDOM();
361
- * if (mangleMap) {
362
- * console.log('Mangle map loaded');
363
- * }
364
- * ```
317
+ * @returns the validated mangle map, or `null` if absent or invalid.
365
318
  */
366
319
  declare function loadMangleMapFromDOM(): MangleMap | null;
367
320
  /**
@@ -382,20 +335,53 @@ declare function loadMangleMapFromDOM(): MangleMap | null;
382
335
  */
383
336
  declare function verifyMangleChecksum(expectedChecksum: string): boolean;
384
337
  /**
385
- * Verifies mangle map integrity using Rust core verification.
338
+ * Recompute a mangle map's checksum the same way the Rust core does
339
+ * (`compute_checksum_internal`): SHA-256 over the entries sorted by key and
340
+ * formatted `orig:mangle`, joined by `|`, hex-encoded, first 16 chars (64 bits).
386
341
  *
387
- * Loads the mangle map from DOM and verifies its checksum using the
388
- * Rust core's `verify_mangle_checksum()` function for cryptographic-grade verification.
342
+ * Uses the Web Crypto API (`crypto.subtle`), so it works WITHOUT the WASM core —
343
+ * unlike the WASM-only sync path. Async because `crypto.subtle.digest` is async.
389
344
  *
390
- * @returns {boolean} True if mangle map integrity is verified
345
+ * @param map - the mangle map to checksum.
346
+ * @returns the 16-char hex checksum (matches the Rust output byte-for-byte for
347
+ * ASCII class names).
348
+ */
349
+ declare function computeMangleChecksumAsync(map: MangleMap): Promise<string>;
350
+ /**
351
+ * Verify a mangle map's integrity by RECOMPUTING its checksum (via Web Crypto)
352
+ * and comparing it to the expected value — real verification that works without
353
+ * the WASM core. Unlike the sync {@link verifyMangleChecksum} (a plain attribute
354
+ * compare), this recomputes from the map, so it detects a map that was altered
355
+ * without updating the checksum.
391
356
  *
392
- * @example
393
- * ```typescript
394
- * if (!verifyMangleMapIntegrity()) {
395
- * console.error('[csszyx] Mangle map integrity check failed');
396
- * abortHydration();
397
- * }
398
- * ```
357
+ * Still tamper-DETECTION, not authentication: the checksum is unsigned, so an
358
+ * attacker who can rewrite the served HTML can recompute it after editing the
359
+ * map. Use it to catch corruption / accidental drift, not as a trust boundary.
360
+ *
361
+ * @param expectedChecksum - the checksum to match (e.g. from the manifest or the
362
+ * `data-sz-checksum` attribute).
363
+ * @param map - the mangle map; loaded (and schema-validated) from the DOM when omitted.
364
+ * @returns a promise resolving true when the map is present and its recomputed
365
+ * checksum matches.
366
+ */
367
+ declare function verifyMangleChecksumAsync(expectedChecksum: string, map?: MangleMap): Promise<boolean>;
368
+ /**
369
+ * Verifies mangle map integrity using the Rust core checksum verifier.
370
+ *
371
+ * Loads the mangle map from the DOM, validates its shape, and (when the WASM
372
+ * core is present) verifies its checksum via `verify_mangle_checksum()`.
373
+ *
374
+ * IMPORTANT — this is tamper-DETECTION, not authentication. The checksum is an
375
+ * unsigned SHA-256 truncation: it catches accidental server/client drift, but an
376
+ * attacker who can rewrite the served HTML can recompute it after editing the
377
+ * map. Treat it as an integrity (corruption) check, not a trust boundary.
378
+ *
379
+ * When the WASM verifier is absent (the common no-core deployment), the checksum
380
+ * cannot be recomputed in this sync path, so verification degrades to a
381
+ * schema-validated load and emits a dev warning rather than failing closed
382
+ * (failing closed here would break every app not shipping the WASM core).
383
+ *
384
+ * @returns {boolean} True if the map is well-formed and (if verifiable) matches.
399
385
  */
400
386
  declare function verifyMangleMapIntegrity(): boolean;
401
387
  /**
@@ -612,6 +598,133 @@ declare function startHydration(): void;
612
598
  */
613
599
  declare function endHydration(): void;
614
600
 
601
+ /** Which side of the CSS box-model border a property acts on. */
602
+ type BoxRole = 'outer' | 'inner';
603
+
604
+ /**
605
+ * Route a (csszyx-emitted) className string to nested elements by CSS box-model
606
+ * role, plus a category-aware toolkit that exposes csszyx's class knowledge as
607
+ * primitives. Pure string functions — framework-agnostic, cross-platform, no
608
+ * React, no DOM. The class-token → box-role map is GENERATED from the compiler's
609
+ * property tables (see `box-role-map.generated.ts`), so it never drifts.
610
+ *
611
+ * The problem this solves: a caller passes one flat `className` (e.g. from an sz
612
+ * prop) to a component, but the component renders nested elements — the margin
613
+ * belongs on the outer frame while the padding belongs on the inner content. A
614
+ * slot recipe can't re-route a caller's flat string; only a runtime partition
615
+ * can. `splitBox` does that partition at the border line (outer = border-outward,
616
+ * inner = border-inward); the toolkit lets a project express cross-element
617
+ * dependency rules (e.g. "if the frame clips, make the scroller scroll") without
618
+ * hardcoding csszyx's class vocabulary.
619
+ */
620
+
621
+ /** The classification of a single class token. */
622
+ interface Classification {
623
+ /** Which side of the border the property acts on. */
624
+ readonly role: BoxRole;
625
+ /** Semantic group (margin, padding, border, overflow, text, …). */
626
+ readonly category: string;
627
+ }
628
+ /**
629
+ * A way to address a set of classes. One of:
630
+ * - a box-role: `'outer'` | `'inner'`
631
+ * - a box-layer alias: `'content'` (= inner) (`'margin'`/`'border'`/`'padding'`
632
+ * are also categories, so they work directly)
633
+ * - a category: `'overflow'`, `'text'`, `'bg'`, …
634
+ * - a class-prefix: `'px'`, `'bg'`, … (matches `px-2`, `bg-red-500`, …)
635
+ * - a category+value pair: `{ overflow: 'hidden' }`
636
+ */
637
+ type BoxSelector = string | Readonly<Record<string, string>>;
638
+ /** Options controlling how `splitBox` partitions a className. */
639
+ interface SplitBoxOptions {
640
+ /** Force these selectors onto the outer node, overriding the default map. */
641
+ outer?: BoxSelector[];
642
+ /** Force these selectors onto the inner node, overriding the default map. */
643
+ inner?: BoxSelector[];
644
+ /** Where an unrecognized token goes. Defaults to `'outer'`. */
645
+ fallback?: BoxRole;
646
+ }
647
+ /** The two class buckets produced by `splitBox`. */
648
+ interface SplitBoxResult {
649
+ /** Classes for the outer (border-outward) element. */
650
+ outer: string;
651
+ /** Classes for the inner (border-inward) element. */
652
+ inner: string;
653
+ }
654
+ /**
655
+ * Classify a class token by box-model role + semantic category, or `undefined`
656
+ * if it is not a csszyx-owned utility. Variant-, important- and negative-aware.
657
+ *
658
+ * @param token - A single class token to classify.
659
+ * @returns The token's role and category, or `undefined` if unowned.
660
+ */
661
+ declare function classify(token: string): Classification | undefined;
662
+ /**
663
+ * Partition a className string into `{ outer, inner }` at the CSS box-model
664
+ * border line. Every token lands in exactly one bucket (no loss, no duplication)
665
+ * and keeps its variant prefix. Overrides in `options.inner` / `options.outer`
666
+ * win over the default map; `inner` is checked first when a token matches both.
667
+ *
668
+ * @param className - The flat className string to partition.
669
+ * @param options - Overrides for forcing tokens onto a node and the fallback role.
670
+ * @returns The `{ outer, inner }` class buckets.
671
+ * @example splitBox('m-4 px-2 md:flex') // → { outer: 'm-4', inner: 'px-2 md:flex' }
672
+ */
673
+ declare function splitBox(className: string, options?: SplitBoxOptions): SplitBoxResult;
674
+ /**
675
+ * Does any token in `classes` match `selector`? Variant- and mangle-robust.
676
+ *
677
+ * @param classes - A className string to scan.
678
+ * @param selector - The selector to test tokens against.
679
+ * @returns `true` if any token matches the selector.
680
+ */
681
+ declare function has(classes: string, selector: BoxSelector): boolean;
682
+ /**
683
+ * Keep only the tokens in `classes` that match `selector`.
684
+ *
685
+ * @param classes - A className string to filter.
686
+ * @param selector - The selector tokens must match to be kept.
687
+ * @returns The matching tokens joined by spaces.
688
+ */
689
+ declare function pick(classes: string, selector: BoxSelector): string;
690
+ /**
691
+ * Drop the tokens in `classes` that match `selector`, keeping the rest.
692
+ *
693
+ * @param classes - A className string to filter.
694
+ * @param selector - The selector tokens must match to be dropped.
695
+ * @returns The non-matching tokens joined by spaces.
696
+ */
697
+ declare function omit(classes: string, selector: BoxSelector): string;
698
+
699
+ /**
700
+ * Drop the `sz` prop before a component spreads `...rest` onto a host element.
701
+ *
702
+ * The compiler rewrites `sz` to `className` at build time, so a compiled
703
+ * component never carries a leftover `sz` prop. But when a file is NOT compiled
704
+ * — e.g. a workspace package missing from `compilePackages`, or any source the
705
+ * bundler skipped — a hand-forwarded `sz` survives and React spreads it to the
706
+ * DOM as `sz="[object Object]"`. `stripSzProps` removes `sz` from the forwarded
707
+ * props so it never reaches the DOM, and in development warns once when the
708
+ * leaked `sz` is a raw object, pointing at the real cause (an uncompiled file).
709
+ *
710
+ * Pure, framework-agnostic, no React/DOM import.
711
+ *
712
+ * @example
713
+ * function Box({ sz, ...rest }: BoxProps) {
714
+ * return <div {...stripSzProps(rest)} />; // rest may still carry sz when uncompiled
715
+ * }
716
+ */
717
+ /**
718
+ * Return `props` without its `sz` key. When `sz` is absent the original object
719
+ * is returned unchanged (no allocation); otherwise a shallow copy without `sz`
720
+ * is returned. In development, a raw-object `sz` (the uncompiled-leak signature)
721
+ * triggers a one-time warning.
722
+ *
723
+ * @param props - the props a component is about to forward to a host element.
724
+ * @returns the same props without `sz`.
725
+ */
726
+ declare function stripSzProps<T extends Record<string, unknown>>(props: T): Omit<T, 'sz'>;
727
+
615
728
  /**
616
729
  * szv() — variant-based sz object factory.
617
730
  *
@@ -632,9 +745,7 @@ type VariantSchema = Record<string, Record<string, SzObject>>;
632
745
  type VariantSelection<V extends VariantSchema> = {
633
746
  [K in keyof V]?: keyof V[K] | null | undefined;
634
747
  };
635
- /**
636
- *
637
- */
748
+ /** Configuration for a variant component: base styles, variants, and defaults. */
638
749
  interface SzvConfig<V extends VariantSchema> {
639
750
  base?: SzObject;
640
751
  variants: V;
@@ -655,7 +766,7 @@ interface SzvConfig<V extends VariantSchema> {
655
766
  * import { szv } from 'csszyx';
656
767
  *
657
768
  * const buttonSz = szv({
658
- * base: { inlineFlex: true, items: 'center', rounded: 'md', fontWeight: 'medium' },
769
+ * base: { display: 'inline-flex', items: 'center', rounded: 'md', weight: 'medium' },
659
770
  * variants: {
660
771
  * variant: {
661
772
  * default: { bg: 'primary', text: 'primary-foreground' },
@@ -769,5 +880,5 @@ declare function isRuntimeInitialized(): boolean;
769
880
  */
770
881
  declare function resetRuntime(): void;
771
882
 
772
- export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szIf, _szMerge, _szSwitch, abortHydration, attemptCSRRecovery, clearHydrationErrors, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, resetRuntime, startHydration, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleMapIntegrity, verifyRecoveryToken };
773
- export type { HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SzInput, TokenData, VerificationResult };
883
+ export { DEFAULT_RUNTIME_CONFIG, VERSION, _sz, _sz2, _sz3, _szMerge, abortHydration, attemptCSRRecovery, classify, clearHydrationErrors, computeMangleChecksumAsync, disableCSRRecovery, enableCSRRecovery, endHydration, getAbortedSubtreeCount, getHydrationErrors, getRecoveryMode, getRuntimeConfig, getSSRContext, guardHydration, has, hasRecoveryToken, initRuntime, isCSRRecoveryAllowed, isHydrating, isHydrationAborted, isRuntimeInitialized, isSSREnvironment, isValidMangleMap, isValidManifest, loadMangleMapFromDOM, loadManifestFromDOM, omit, pick, resetRuntime, splitBox, startHydration, stripSzProps, szv, validateHydrationClass, verifyAllTokens, verifyMangleChecksum, verifyMangleChecksumAsync, verifyMangleMapIntegrity, verifyRecoveryToken };
884
+ export type { BoxRole, BoxSelector, Classification, HydrationError, HydrationErrorType, MangleMap, RecoveryManifest, RecoveryMode, RuntimeConfig, SSRContext, SplitBoxOptions, SplitBoxResult, SzInput, TokenData, VerificationResult };