tailwind-to-style 4.0.2 → 5.1.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v4.0.2
2
+ * tailwind-to-style v5.1.0
3
3
  * Zero-build runtime Tailwind CSS engine
4
4
  *
5
5
  * @author Bigetion
@@ -2149,6 +2149,182 @@ function getActiveCollector() {
2149
2149
  return _activeCollector;
2150
2150
  }
2151
2151
 
2152
+ /**
2153
+ * Shared Constants
2154
+ *
2155
+ * All constant values used across the library.
2156
+ * Extracted from monolithic index.js for better maintainability.
2157
+ *
2158
+ * @module shared/constants
2159
+ */
2160
+
2161
+ // ============================================================================
2162
+ // Environment Detection
2163
+ // ============================================================================
2164
+
2165
+ /**
2166
+ * True when running in a browser environment (window & document available)
2167
+ */
2168
+ const IS_BROWSER$1 = typeof window !== "undefined" && typeof document !== "undefined";
2169
+
2170
+ /**
2171
+ * Maximum number of entries in Set-based caches
2172
+ */
2173
+ const MAX_SET_SIZE$1 = 10000;
2174
+
2175
+ // ============================================================================
2176
+ // Built-in Animation Keyframes
2177
+ // ============================================================================
2178
+
2179
+ /**
2180
+ * Mapping of animation names to their keyframe definitions
2181
+ */
2182
+ const BUILTIN_KEYFRAMES = {
2183
+ spin: {
2184
+ "0%": {
2185
+ transform: "rotate(0deg)"
2186
+ },
2187
+ "100%": {
2188
+ transform: "rotate(360deg)"
2189
+ }
2190
+ },
2191
+ ping: {
2192
+ "75%, 100%": {
2193
+ transform: "scale(2)",
2194
+ opacity: "0"
2195
+ }
2196
+ },
2197
+ pulse: {
2198
+ "50%": {
2199
+ opacity: ".5"
2200
+ }
2201
+ },
2202
+ bounce: {
2203
+ "0%, 100%": {
2204
+ transform: "translateY(-25%)",
2205
+ animationTimingFunction: "cubic-bezier(0.8,0,1,1)"
2206
+ },
2207
+ "50%": {
2208
+ transform: "none",
2209
+ animationTimingFunction: "cubic-bezier(0,0,0.2,1)"
2210
+ }
2211
+ },
2212
+ fadeIn: {
2213
+ "0%": {
2214
+ opacity: "0"
2215
+ },
2216
+ "50%": {
2217
+ opacity: "1"
2218
+ },
2219
+ "100%": {
2220
+ opacity: "0"
2221
+ }
2222
+ },
2223
+ slideUp: {
2224
+ "0%": {
2225
+ transform: "translateY(20px)",
2226
+ opacity: "0"
2227
+ },
2228
+ "50%": {
2229
+ transform: "translateY(0)",
2230
+ opacity: "1"
2231
+ },
2232
+ "100%": {
2233
+ transform: "translateY(-20px)",
2234
+ opacity: "0"
2235
+ }
2236
+ }
2237
+ };
2238
+
2239
+ /**
2240
+ * Opacity modifiers
2241
+ */
2242
+ const OPACITY_MODIFIER_REGEX = /\/(\d+)$/;
2243
+
2244
+ /**
2245
+ * Opacity property patterns for substitution
2246
+ */
2247
+ const OPACITY_PROP_REGEXES = {
2248
+ "--text-opacity": /--text-opacity\s*:\s*[\d.]+/gi,
2249
+ "--bg-opacity": /--bg-opacity\s*:\s*[\d.]+/gi,
2250
+ "--border-opacity": /--border-opacity\s*:\s*[\d.]+/gi,
2251
+ "--ring-opacity": /--ring-opacity\s*:\s*[\d.]+/gi,
2252
+ "--placeholder-opacity": /--placeholder-opacity\s*:\s*[\d.]+/gi,
2253
+ "--divide-opacity": /--divide-opacity\s*:\s*[\d.]+/gi
2254
+ };
2255
+
2256
+ /**
2257
+ * Bracket encoding/decoding
2258
+ */
2259
+ const BRACKET_CONTENT_REGEX = /\[([^\]]+)\]/g;
2260
+ const OPENING_PAREN_REGEX = /\(/g;
2261
+ const CLOSING_PAREN_REGEX = /\)/g;
2262
+ const ENCODED_PAREN_OPEN_REGEX = /__P__/g;
2263
+ const ENCODED_PAREN_CLOSE_REGEX = /__C__/g;
2264
+
2265
+ /**
2266
+ * Animation detection
2267
+ */
2268
+ const ANIMATION_NAME_REGEX = /animation(?:-name)?:\s*([a-zA-Z0-9-]+)/gi;
2269
+
2270
+ /**
2271
+ * Color property regex patterns (pre-compiled for each color property)
2272
+ * Used in processOpacityModifier for 50-100x performance improvement
2273
+ */
2274
+ const COLOR_PROPERTIES$1 = ["color", "background-color", "border-color", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color"];
2275
+
2276
+ /**
2277
+ * CSS property name conversion
2278
+ */
2279
+ const UPPERCASE_LETTER_REGEX = /([A-Z])/g;
2280
+
2281
+ /**
2282
+ * Hash Utilities
2283
+ *
2284
+ * Fast hashing functions for string and object caching.
2285
+ * Extracted from monolithic index.js for reusability.
2286
+ *
2287
+ * @module shared/hash
2288
+ */
2289
+
2290
+ /**
2291
+ * Fast string hash using FNV-1a algorithm.
2292
+ * Produces 32-bit hash values for cache keys.
2293
+ *
2294
+ * @param {string} str - String to hash
2295
+ * @returns {number} 32-bit hash
2296
+ *
2297
+ * @example
2298
+ * hashString('bg-blue-500') // → 2845719273
2299
+ * hashString('hover:bg-red-600') // → 3927461034
2300
+ */
2301
+ function hashString$2(str) {
2302
+ let hash = 2166136261; // FNV offset basis
2303
+ for (let i = 0; i < str.length; i++) {
2304
+ hash ^= str.charCodeAt(i);
2305
+ // FNV prime: 16777619
2306
+ hash = hash * 16777619 >>> 0; // >>> 0 keeps it a 32-bit unsigned integer
2307
+ }
2308
+ return hash;
2309
+ }
2310
+
2311
+ /**
2312
+ * Generate a short hash for CSS class names.
2313
+ * Uses base36 encoding for compact, URL-safe identifiers.
2314
+ *
2315
+ * @param {string} str - Input string
2316
+ * @param {number} length - Desired hash length (default: 8)
2317
+ * @returns {string} Short hash string
2318
+ *
2319
+ * @example
2320
+ * getCssHash('bg-blue-500 p-4 rounded') // → 'x7k2m9n1'
2321
+ */
2322
+ function getCssHash(str) {
2323
+ let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 8;
2324
+ const hash = hashString$2(str);
2325
+ return hash.toString(36).substring(0, length);
2326
+ }
2327
+
2152
2328
  /**
2153
2329
  * Proper LRU (Least Recently Used) Cache implementation
2154
2330
  * Efficiently manages memory by removing least recently used items
@@ -2175,49 +2351,496 @@ class LRUCache {
2175
2351
  return value;
2176
2352
  }
2177
2353
 
2178
- /**
2179
- * Set value in cache
2180
- * Removes least recently used item if cache is full
2181
- */
2182
- set(key, value) {
2183
- // If key exists, delete it first to update position
2184
- if (this.cache.has(key)) {
2185
- this.cache.delete(key);
2186
- } else if (this.cache.size >= this.maxSize) {
2187
- // Remove least recently used (first item)
2188
- const firstKey = this.cache.keys().next().value;
2189
- this.cache.delete(firstKey);
2354
+ /**
2355
+ * Set value in cache
2356
+ * Removes least recently used item if cache is full
2357
+ */
2358
+ set(key, value) {
2359
+ // If key exists, delete it first to update position
2360
+ if (this.cache.has(key)) {
2361
+ this.cache.delete(key);
2362
+ } else if (this.cache.size >= this.maxSize) {
2363
+ // Remove least recently used (first item)
2364
+ const firstKey = this.cache.keys().next().value;
2365
+ this.cache.delete(firstKey);
2366
+ }
2367
+ this.cache.set(key, value);
2368
+ }
2369
+
2370
+ /**
2371
+ * Check if key exists in cache
2372
+ */
2373
+ has(key) {
2374
+ return this.cache.has(key);
2375
+ }
2376
+
2377
+ /**
2378
+ * Clear all cache entries
2379
+ */
2380
+ clear() {
2381
+ this.cache.clear();
2382
+ }
2383
+
2384
+ /**
2385
+ * Get current cache size
2386
+ */
2387
+ get size() {
2388
+ return this.cache.size;
2389
+ }
2390
+
2391
+ /**
2392
+ * Delete specific key
2393
+ */
2394
+ delete(key) {
2395
+ return this.cache.delete(key);
2396
+ }
2397
+ }
2398
+
2399
+ /**
2400
+ * Cache Management
2401
+ *
2402
+ * Global caches and cache utilities for performance optimization.
2403
+ * Uses LRU (Least Recently Used) strategy to prevent memory leaks.
2404
+ *
2405
+ * @module shared/cache
2406
+ */
2407
+
2408
+
2409
+ /**
2410
+ * Cache for bracket value encoding
2411
+ * @type {LRUCache}
2412
+ */
2413
+ const encodeBracketCache = new LRUCache(1000);
2414
+
2415
+ /**
2416
+ * Cache for bracket value decoding
2417
+ * @type {LRUCache}
2418
+ */
2419
+ const decodeBracketCache = new LRUCache(1000);
2420
+
2421
+ /**
2422
+ * Set of injected CSS hashes (prevents duplicate injection)
2423
+ * @type {Set<string>}
2424
+ */
2425
+ const injectedCssHashSet = new Set();
2426
+
2427
+ /**
2428
+ * Registry of sourceKey → cssBlock for smart slot-based replacement
2429
+ * Prevents stale CSS chunks from accumulating across HMR cycles
2430
+ * @type {Map<string, string>}
2431
+ */
2432
+ const cssBlockRegistry = new Map();
2433
+
2434
+ /**
2435
+ * Evict old entries from a Set when size exceeds maxSize.
2436
+ *
2437
+ * @deprecated Use LRUCache instead - kept for backward compatibility
2438
+ * @param {Set|LRUCache} set - Set to evict from
2439
+ * @param {number} maxSize - Maximum size
2440
+ */
2441
+ function evictSet(set) {
2442
+ let maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : MAX_SET_SIZE$1;
2443
+ if (set instanceof LRUCache) return; // LRUCache handles its own eviction
2444
+ if (set.size <= maxSize) return;
2445
+ const excess = set.size - maxSize;
2446
+ const iter = set.values();
2447
+ for (let i = 0; i < excess; i++) {
2448
+ set.delete(iter.next().value);
2449
+ }
2450
+ }
2451
+
2452
+ /**
2453
+ * Generate minified CSS keyframes for animations.
2454
+ * Converts camelCase property names to kebab-case.
2455
+ *
2456
+ * @param {string[]} animationNames - Array of animation names to generate
2457
+ * @returns {string} Minified CSS @keyframes rules
2458
+ *
2459
+ * @example
2460
+ * generateMinifiedKeyframes(['spin', 'pulse'])
2461
+ * // → '@keyframes spin{0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}}
2462
+ * // @keyframes pulse{50%{opacity:.5;}}'
2463
+ *
2464
+ * @example
2465
+ * generateMinifiedKeyframes(['fadeIn'])
2466
+ * // → '@keyframes fadeIn{0%{opacity:0;}50%{opacity:1;}100%{opacity:0;}}'
2467
+ */
2468
+ function generateMinifiedKeyframes(animationNames) {
2469
+ let css = "";
2470
+ for (const name of animationNames) {
2471
+ const keyframe = BUILTIN_KEYFRAMES[name];
2472
+ if (!keyframe) continue;
2473
+ css += "@keyframes ".concat(name, "{");
2474
+ for (const _ref of Object.entries(keyframe)) {
2475
+ var _ref2 = _slicedToArray(_ref, 2);
2476
+ const percentage = _ref2[0];
2477
+ const styles = _ref2[1];
2478
+ css += "".concat(percentage, "{");
2479
+ for (const _ref3 of Object.entries(styles)) {
2480
+ var _ref4 = _slicedToArray(_ref3, 2);
2481
+ const prop = _ref4[0];
2482
+ const value = _ref4[1];
2483
+ const cssProp = prop.replace(UPPERCASE_LETTER_REGEX, "-$1").toLowerCase();
2484
+ css += "".concat(cssProp, ":").concat(value, ";");
2485
+ }
2486
+ css += "}";
2487
+ }
2488
+ css += "}";
2489
+ }
2490
+ return css;
2491
+ }
2492
+
2493
+ /**
2494
+ * Opacity Modifier Processing
2495
+ *
2496
+ * Handles Tailwind opacity modifiers (e.g., bg-blue-500/50).
2497
+ * Converts color values to rgba/hsla with specified opacity.
2498
+ *
2499
+ * @module generator/opacity
2500
+ */
2501
+
2502
+
2503
+ // Pre-compile regex patterns for each color property
2504
+ const COLOR_REGEX_PATTERNS$1 = new Map();
2505
+ for (const prop of COLOR_PROPERTIES$1) {
2506
+ const escapedProp = prop.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2507
+ COLOR_REGEX_PATTERNS$1.set(prop, {
2508
+ rgb: new RegExp("(".concat(escapedProp, "\\s*:\\s*)rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)"), "gi"),
2509
+ rgba: new RegExp("(".concat(escapedProp, "\\s*:\\s*)rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)"), "gi"),
2510
+ hsl: new RegExp("(".concat(escapedProp, "\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)"), "gi"),
2511
+ hsla: new RegExp("(".concat(escapedProp, "\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)"), "gi"),
2512
+ hex: new RegExp("(".concat(escapedProp, "\\s*:\\s*)(#[0-9a-fA-F]{3,6})"), "gi")
2513
+ });
2514
+ }
2515
+
2516
+ /**
2517
+ * Process opacity modifiers in Tailwind classes.
2518
+ *
2519
+ * Handles:
2520
+ * - Tailwind CSS custom properties (--text-opacity, --bg-opacity, etc.)
2521
+ * - Direct color values (rgb, rgba, hsl, hsla, hex)
2522
+ * - Converts colors to rgba/hsla with specified opacity
2523
+ *
2524
+ * @param {string} className - Tailwind class name (e.g., 'bg-blue-500/50')
2525
+ * @param {string} cssDeclaration - CSS declaration to modify
2526
+ * @returns {string} Modified CSS declaration with opacity applied
2527
+ *
2528
+ * @example
2529
+ * processOpacityModifier('bg-blue-500/50', 'background-color: rgb(59, 130, 246);')
2530
+ * // → 'background-color: rgba(59, 130, 246, 0.5);'
2531
+ *
2532
+ * @example
2533
+ * processOpacityModifier('text-red-600/75', 'color: #dc2626;')
2534
+ * // → 'color: rgba(220, 38, 38, 0.75);'
2535
+ *
2536
+ * @example
2537
+ * processOpacityModifier('bg-blue-500', 'background-color: rgb(59, 130, 246);')
2538
+ * // → 'background-color: rgb(59, 130, 246);' (no change - no opacity modifier)
2539
+ */
2540
+ function processOpacityModifier(className, cssDeclaration) {
2541
+ const opacityMatch = OPACITY_MODIFIER_REGEX.exec(className);
2542
+ if (!opacityMatch) return cssDeclaration;
2543
+ const opacityValue = parseInt(opacityMatch[1], 10);
2544
+ if (opacityValue < 0 || opacityValue > 100) return cssDeclaration;
2545
+ const alphaValue = (opacityValue / 100).toString();
2546
+
2547
+ // Handle Tailwind's CSS custom property pattern
2548
+ let modifiedDeclaration = cssDeclaration;
2549
+
2550
+ // Replace opacity custom properties using pre-compiled regexes
2551
+ for (const prop in OPACITY_PROP_REGEXES) {
2552
+ const regex = OPACITY_PROP_REGEXES[prop];
2553
+ regex.lastIndex = 0; // Reset global regex
2554
+ modifiedDeclaration = modifiedDeclaration.replace(regex, "".concat(prop, ": ").concat(alphaValue));
2555
+ }
2556
+
2557
+ // Also handle direct color values using pre-compiled regex patterns
2558
+ for (const prop of COLOR_PROPERTIES$1) {
2559
+ const patterns = COLOR_REGEX_PATTERNS$1.get(prop);
2560
+ if (!patterns) continue;
2561
+
2562
+ // Reset all regex lastIndex for reuse
2563
+ patterns.rgb.lastIndex = 0;
2564
+ patterns.rgba.lastIndex = 0;
2565
+ patterns.hsl.lastIndex = 0;
2566
+ patterns.hsla.lastIndex = 0;
2567
+ patterns.hex.lastIndex = 0;
2568
+
2569
+ // Convert rgb to rgba with opacity
2570
+ modifiedDeclaration = modifiedDeclaration.replace(patterns.rgb, "$1rgba($2, $3, $4, ".concat(alphaValue, ")"));
2571
+
2572
+ // Update existing rgba opacity
2573
+ modifiedDeclaration = modifiedDeclaration.replace(patterns.rgba, "$1rgba($2, $3, $4, ".concat(alphaValue, ")"));
2574
+
2575
+ // Convert hsl to hsla with opacity
2576
+ modifiedDeclaration = modifiedDeclaration.replace(patterns.hsl, "$1hsla($2, $3, $4, ".concat(alphaValue, ")"));
2577
+
2578
+ // Update existing hsla opacity
2579
+ modifiedDeclaration = modifiedDeclaration.replace(patterns.hsla, "$1hsla($2, $3, $4, ".concat(alphaValue, ")"));
2580
+
2581
+ // Handle hex colors - convert to rgba
2582
+ modifiedDeclaration = modifiedDeclaration.replace(patterns.hex, (match, propPart, hexColor) => {
2583
+ // Convert hex to rgba
2584
+ const hex = hexColor.replace("#", "");
2585
+ let r, g, b;
2586
+ if (hex.length === 3) {
2587
+ r = parseInt(hex[0] + hex[0], 16);
2588
+ g = parseInt(hex[1] + hex[1], 16);
2589
+ b = parseInt(hex[2] + hex[2], 16);
2590
+ } else {
2591
+ r = parseInt(hex.substring(0, 2), 16);
2592
+ g = parseInt(hex.substring(2, 4), 16);
2593
+ b = parseInt(hex.substring(4, 6), 16);
2594
+ }
2595
+ return "".concat(propPart, "rgba(").concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alphaValue, ")");
2596
+ });
2597
+ }
2598
+ return modifiedDeclaration;
2599
+ }
2600
+
2601
+ /**
2602
+ * Performance Monitoring Utilities
2603
+ *
2604
+ * Tracks and logs performance metrics for optimization analysis.
2605
+ *
2606
+ * @module utils/performanceMonitor
2607
+ */
2608
+
2609
+
2610
+ /**
2611
+ * Performance monitoring system
2612
+ *
2613
+ * Provides start/end timing and automatic slow operation logging.
2614
+ */
2615
+ const performanceMonitor$1 = {
2616
+ enabled: typeof performance !== "undefined",
2617
+ /**
2618
+ * Start performance measurement
2619
+ *
2620
+ * @param {string} label - Label for the measurement
2621
+ * @returns {Object|null} Marker object with label and start time
2622
+ */
2623
+ start(label) {
2624
+ if (!this.enabled) return null;
2625
+ return {
2626
+ label,
2627
+ startTime: performance.now()
2628
+ };
2629
+ },
2630
+ /**
2631
+ * End performance measurement and log if slow
2632
+ *
2633
+ * @param {Object} marker - Marker from start()
2634
+ */
2635
+ end(marker) {
2636
+ if (!this.enabled || !marker) return;
2637
+ const duration = performance.now() - marker.startTime;
2638
+ if (duration > 5) {
2639
+ // Only log if > 5ms
2640
+ logger.warn("Slow ".concat(marker.label, ": ").concat(duration.toFixed(2), "ms"));
2641
+ }
2642
+ },
2643
+ /**
2644
+ * Measure function execution time
2645
+ *
2646
+ * @param {Function} fn - Function to measure
2647
+ * @param {string} label - Label for measurement
2648
+ * @returns {*} Function result
2649
+ */
2650
+ measure(fn, label) {
2651
+ const marker = this.start(label);
2652
+ try {
2653
+ const result = fn();
2654
+ this.end(marker);
2655
+ return result;
2656
+ } catch (error) {
2657
+ this.end(marker);
2658
+ throw error;
2659
+ }
2660
+ }
2661
+ };
2662
+
2663
+ /**
2664
+ * DOM CSS Injector
2665
+ *
2666
+ * Handles automatic CSS injection into the DOM.
2667
+ * Supports SSR mode, HMR-friendly block registry, and hash-based deduplication.
2668
+ *
2669
+ * @module injector/dom
2670
+ */
2671
+
2672
+
2673
+ /**
2674
+ * Rebuild the style tag from the CSS block registry.
2675
+ *
2676
+ * Used for slot-based updates where each twsx() call owns its own CSS block.
2677
+ * Rebuilds the entire style tag to avoid stale CSS from previous HMR cycles.
2678
+ *
2679
+ * @private
2680
+ */
2681
+ function rebuildStyleTag$1() {
2682
+ let styleTag = document.getElementById("twsx-auto-style");
2683
+ if (!styleTag) {
2684
+ styleTag = document.createElement("style");
2685
+ styleTag.id = "twsx-auto-style";
2686
+ styleTag.setAttribute("data-twsx", "");
2687
+ document.head.appendChild(styleTag);
2688
+ }
2689
+ styleTag.textContent = [...cssBlockRegistry.values()].join("\n");
2690
+ }
2691
+
2692
+ /**
2693
+ * Automatically inject CSS into the DOM or collect for SSR.
2694
+ *
2695
+ * Supports three modes:
2696
+ * 1. SSR mode: Delegates to utils/ssr.js collector
2697
+ * 2. Slot-based mode (with sourceKey): HMR-friendly block registry
2698
+ * 3. Hash-based mode (no sourceKey): Legacy deduplication
2699
+ *
2700
+ * @param {string} cssString - CSS to inject
2701
+ * @param {string|null} sourceKey - Optional unique key for slot-based updates
2702
+ *
2703
+ * @example
2704
+ * // Slot-based (HMR-friendly)
2705
+ * autoInjectCss('.btn { color: blue; }', 'twsx-call-123');
2706
+ *
2707
+ * @example
2708
+ * // Hash-based (legacy)
2709
+ * autoInjectCss('.btn { color: blue; }');
2710
+ *
2711
+ * @example
2712
+ * // SSR mode (delegates to ssr.js)
2713
+ * startSSR();
2714
+ * autoInjectCss('.btn { color: blue; }');
2715
+ * const css = stopSSR();
2716
+ */
2717
+ function autoInjectCss(cssString) {
2718
+ let sourceKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
2719
+ const marker = performanceMonitor$1.start("css:inject");
2720
+ try {
2721
+ // SSR mode: collect CSS strings instead of DOM injection. Delegates to
2722
+ // the shared collector in ./utils/ssr.js so both the legacy
2723
+ // startSSR()/stopSSR() pair and the modern createSSRCollector() actually
2724
+ // receive the CSS generated by tw()/twsx().
2725
+ if (isSSRCollecting()) {
2726
+ collectSSRCSS(cssString);
2727
+ performanceMonitor$1.end(marker);
2728
+ return;
2190
2729
  }
2191
- this.cache.set(key, value);
2192
- }
2730
+ if (IS_BROWSER$1) {
2731
+ if (sourceKey) {
2732
+ // Slot-based update: each unique twsx(obj) call owns its own CSS block.
2733
+ // When styles change (new content, same logical call site via cacheKey)
2734
+ // the old slot is replaced and the style tag is fully rebuilt, so no
2735
+ // stale rules from previous HMR cycles can pile up.
2736
+ const existing = cssBlockRegistry.get(sourceKey);
2737
+ if (existing === cssString) {
2738
+ // Identical content – nothing to do.
2739
+ performanceMonitor$1.end(marker);
2740
+ return;
2741
+ }
2742
+ cssBlockRegistry.set(sourceKey, cssString);
2743
+ rebuildStyleTag$1();
2744
+ if (cssBlockRegistry.size % 10 === 0) {
2745
+ logger.debug("CSS registry stats: ".concat(cssBlockRegistry.size, " blocks registered"));
2746
+ }
2747
+ performanceMonitor$1.end(marker);
2748
+ return;
2749
+ }
2193
2750
 
2194
- /**
2195
- * Check if key exists in cache
2196
- */
2197
- has(key) {
2198
- return this.cache.has(key);
2199
- }
2751
+ // Fallback path (e.g. direct autoInjectCss calls without a sourceKey):
2752
+ // keep the original hash-based dedup + append behaviour.
2753
+ const cssHash = getCssHash(cssString);
2754
+ if (injectedCssHashSet.has(cssHash)) {
2755
+ performanceMonitor$1.end(marker);
2756
+ return;
2757
+ }
2758
+ injectedCssHashSet.add(cssHash);
2759
+ evictSet(injectedCssHashSet);
2760
+ let styleTag = document.getElementById("twsx-auto-style");
2761
+ if (!styleTag) {
2762
+ styleTag = document.createElement("style");
2763
+ styleTag.id = "twsx-auto-style";
2764
+ styleTag.setAttribute("data-twsx", "");
2765
+ document.head.appendChild(styleTag);
2766
+ }
2200
2767
 
2201
- /**
2202
- * Clear all cache entries
2203
- */
2204
- clear() {
2205
- this.cache.clear();
2206
- }
2768
+ // Append CSS to style tag using textContent for reliability
2769
+ // Note: insertRule + textContent mixing destroys CSSOM rules,
2770
+ // so we use textContent exclusively for consistent behavior
2771
+ // with @keyframes, @media, and other nested CSS blocks.
2772
+ styleTag.textContent += "\n".concat(cssString);
2207
2773
 
2208
- /**
2209
- * Get current cache size
2210
- */
2211
- get size() {
2212
- return this.cache.size;
2774
+ // Log injection stats periodically
2775
+ if (injectedCssHashSet.size % 10 === 0) {
2776
+ logger.debug("CSS injection stats: ".concat(injectedCssHashSet.size, " unique stylesheets injected"));
2777
+ }
2778
+ }
2779
+ performanceMonitor$1.end(marker);
2780
+ } catch (error) {
2781
+ performanceMonitor$1.end(marker);
2782
+ logger.error("Error injecting CSS:", error);
2213
2783
  }
2784
+ }
2214
2785
 
2215
- /**
2216
- * Delete specific key
2217
- */
2218
- delete(key) {
2219
- return this.cache.delete(key);
2220
- }
2786
+ /**
2787
+ * Bracket Value Encoding/Decoding
2788
+ *
2789
+ * Handles encoding and decoding of bracket values in Tailwind classes.
2790
+ * Example: bg-[rgb(255,0,0)] → bg-[rgb__P__255%2C0%2C0__C__]
2791
+ *
2792
+ * @module parser/bracket
2793
+ */
2794
+
2795
+
2796
+ /**
2797
+ * Encode bracket values to prevent parsing issues.
2798
+ * Encodes parentheses within brackets to special markers.
2799
+ *
2800
+ * @param {string} input - Class string with brackets
2801
+ * @returns {string} Encoded string
2802
+ *
2803
+ * @example
2804
+ * encodeBracketValues('bg-[rgb(255,0,0)]')
2805
+ * // → 'bg-[rgb__P__255%2C0%2C0__C__]'
2806
+ *
2807
+ * @example
2808
+ * encodeBracketValues('w-[calc(100%-20px)]')
2809
+ * // → 'w-[calc__P__100%25-20px__C__]'
2810
+ */
2811
+ function encodeBracketValues(input) {
2812
+ if (!input) return input;
2813
+ if (encodeBracketCache.has(input)) return encodeBracketCache.get(input);
2814
+ BRACKET_CONTENT_REGEX.lastIndex = 0; // Reset global regex
2815
+ const result = input.replace(BRACKET_CONTENT_REGEX, (_, content) => {
2816
+ const encoded = encodeURIComponent(content).replace(OPENING_PAREN_REGEX, "__P__").replace(CLOSING_PAREN_REGEX, "__C__");
2817
+ return "[".concat(encoded, "]");
2818
+ });
2819
+ encodeBracketCache.set(input, result);
2820
+ return result;
2821
+ }
2822
+
2823
+ /**
2824
+ * Decode previously encoded bracket values.
2825
+ * Reverses the encoding done by encodeBracketValues().
2826
+ *
2827
+ * @param {string} input - Encoded class string
2828
+ * @returns {string} Decoded string
2829
+ *
2830
+ * @example
2831
+ * decodeBracketValues('bg-[rgb__P__255%2C0%2C0__C__]')
2832
+ * // → 'bg-[rgb(255,0,0)]'
2833
+ *
2834
+ * @example
2835
+ * decodeBracketValues('w-[calc__P__100%25-20px__C__]')
2836
+ * // → 'w-[calc(100%-20px)]'
2837
+ */
2838
+ function decodeBracketValues(input) {
2839
+ if (!input) return input;
2840
+ if (decodeBracketCache.has(input)) return decodeBracketCache.get(input);
2841
+ const result = decodeURIComponent(input).replace(ENCODED_PAREN_OPEN_REGEX, "(").replace(ENCODED_PAREN_CLOSE_REGEX, ")");
2842
+ decodeBracketCache.set(input, result);
2843
+ return result;
2221
2844
  }
2222
2845
 
2223
2846
  function generator$2S() {
@@ -6021,11 +6644,6 @@ cx.with = function () {
6021
6644
  };
6022
6645
  };
6023
6646
 
6024
- // ============================================================================
6025
- // SSR (Server-Side Rendering) Support
6026
- // Detect environment once at module load for zero-cost runtime checks
6027
- // ============================================================================
6028
- const IS_BROWSER$1 = typeof window !== "undefined" && typeof document !== "undefined";
6029
6647
  const MAX_CACHE_SIZE$1 = 5000;
6030
6648
  const MAX_SET_SIZE = 10000;
6031
6649
 
@@ -6038,138 +6656,17 @@ const _twsxInputCache = new LRUCache(MAX_CACHE_SIZE$1);
6038
6656
  // WeakMap for object identity-based caching (fast lookup for repeated objects)
6039
6657
  const _objectIdentityCache = new WeakMap();
6040
6658
 
6041
- /** @deprecated Use LRUCache instead - kept for backward compatibility */
6042
- function evictSet(set) {
6043
- let maxSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : MAX_SET_SIZE;
6044
- if (set instanceof LRUCache) return; // LRUCache handles its own eviction
6045
- if (set.size <= maxSize) return;
6046
- const excess = set.size - maxSize;
6047
- const iter = set.values();
6048
- for (let i = 0; i < excess; i++) {
6049
- set.delete(iter.next().value);
6050
- }
6051
- }
6052
-
6053
- // Mapping of animation names to their keyframe definitions
6054
- const BUILTIN_KEYFRAMES = {
6055
- spin: {
6056
- "0%": {
6057
- transform: "rotate(0deg)"
6058
- },
6059
- "100%": {
6060
- transform: "rotate(360deg)"
6061
- }
6062
- },
6063
- ping: {
6064
- "75%, 100%": {
6065
- transform: "scale(2)",
6066
- opacity: "0"
6067
- }
6068
- },
6069
- pulse: {
6070
- "50%": {
6071
- opacity: ".5"
6072
- }
6073
- },
6074
- bounce: {
6075
- "0%, 100%": {
6076
- transform: "translateY(-25%)",
6077
- animationTimingFunction: "cubic-bezier(0.8,0,1,1)"
6078
- },
6079
- "50%": {
6080
- transform: "none",
6081
- animationTimingFunction: "cubic-bezier(0,0,0.2,1)"
6082
- }
6083
- },
6084
- fadeIn: {
6085
- "0%": {
6086
- opacity: "0"
6087
- },
6088
- "50%": {
6089
- opacity: "1"
6090
- },
6091
- "100%": {
6092
- opacity: "0"
6093
- }
6094
- },
6095
- slideUp: {
6096
- "0%": {
6097
- transform: "translateY(20px)",
6098
- opacity: "0"
6099
- },
6100
- "50%": {
6101
- transform: "translateY(0)",
6102
- opacity: "1"
6103
- },
6104
- "100%": {
6105
- transform: "translateY(-20px)",
6106
- opacity: "0"
6107
- }
6108
- }
6109
- };
6110
-
6111
- // Generate minified keyframes CSS
6112
- function generateMinifiedKeyframes(animationNames) {
6113
- let css = "";
6114
- for (const name of animationNames) {
6115
- const keyframe = BUILTIN_KEYFRAMES[name];
6116
- if (!keyframe) continue;
6117
- css += "@keyframes ".concat(name, "{");
6118
- for (const _ref of Object.entries(keyframe)) {
6119
- var _ref2 = _slicedToArray(_ref, 2);
6120
- const percentage = _ref2[0];
6121
- const styles = _ref2[1];
6122
- css += "".concat(percentage, "{");
6123
- for (const _ref3 of Object.entries(styles)) {
6124
- var _ref4 = _slicedToArray(_ref3, 2);
6125
- const prop = _ref4[0];
6126
- const value = _ref4[1];
6127
- const cssProp = prop.replace(UPPERCASE_LETTER_REGEX, "-$1").toLowerCase();
6128
- css += "".concat(cssProp, ":").concat(value, ";");
6129
- }
6130
- css += "}";
6131
- }
6132
- css += "}";
6133
- }
6134
- return css;
6135
- }
6136
-
6137
- // Opacity modifiers
6138
- const OPACITY_MODIFIER_REGEX = /\/(\d+)$/;
6139
- const OPACITY_PROP_REGEXES = {
6140
- "--text-opacity": /--text-opacity\s*:\s*[\d.]+/gi,
6141
- "--bg-opacity": /--bg-opacity\s*:\s*[\d.]+/gi,
6142
- "--border-opacity": /--border-opacity\s*:\s*[\d.]+/gi,
6143
- "--ring-opacity": /--ring-opacity\s*:\s*[\d.]+/gi,
6144
- "--divide-opacity": /--divide-opacity\s*:\s*[\d.]+/gi,
6145
- "--placeholder-opacity": /--placeholder-opacity\s*:\s*[\d.]+/gi,
6146
- "--text-decoration-opacity": /--text-decoration-opacity\s*:\s*[\d.]+/gi,
6147
- "--outline-opacity": /--outline-opacity\s*:\s*[\d.]+/gi,
6148
- "--accent-opacity": /--accent-opacity\s*:\s*[\d.]+/gi,
6149
- "--caret-opacity": /--caret-opacity\s*:\s*[\d.]+/gi
6150
- };
6151
-
6152
6659
  // CSS parsing
6153
- const CSS_CLASS_REGEX = /([a-zA-Z0-9\-_\\/.]+)\s*{\s*([^}]+)\s*}/g;
6154
- const DOUBLE_BACKSLASH_REGEX = /\\\\/g;
6155
- const LEADING_UNDERSCORE_REGEX = /^_/;
6156
- const MULTIPLE_SPACES_REGEX = /\s+/g;
6157
-
6158
- // Bracket encoding/decoding
6159
- const BRACKET_CONTENT_REGEX = /\[([^\]]+)\]/g;
6160
- const OPENING_PAREN_REGEX = /\(/g;
6161
- const CLOSING_PAREN_REGEX = /\)/g;
6162
- const ENCODED_PAREN_OPEN_REGEX = /__P__/g;
6163
- const ENCODED_PAREN_CLOSE_REGEX = /__C__/g;
6660
+ const CSS_CLASS_REGEX = /([a-zA-Z0-9\-_\\/.]+)\s*{\s*([^}]+)\s*}/g;
6661
+ const DOUBLE_BACKSLASH_REGEX = /\\\\/g;
6662
+ const LEADING_UNDERSCORE_REGEX = /^_/;
6663
+ const MULTIPLE_SPACES_REGEX = /\s+/g;
6164
6664
 
6165
6665
  // Variant expansion
6166
6666
  const DIRECTIVE_GROUP_REGEX = /(\w+)\(([^()]+)\)/g;
6167
6667
  const VARIANT_GROUP_REGEX = /(\w+):\(([^()]+(?:\((?:[^()]+)\))?[^()]*)\)/g;
6168
6668
  const WHITESPACE_SPLIT_REGEX = /\s+/;
6169
6669
  const VARIANT_COLON_SPLIT_REGEX = /:/;
6170
-
6171
- // Animation detection
6172
- const ANIMATION_NAME_REGEX = /animation(?:-name)?:\s*([a-zA-Z0-9-]+)/gi;
6173
6670
  const CUSTOM_VALUE_FULL_REGEX = /^(.+?)\[(.+)\]$/;
6174
6671
 
6175
6672
  // Selector variants
@@ -6194,9 +6691,6 @@ for (const prop of COLOR_PROPERTIES) {
6194
6691
  });
6195
6692
  }
6196
6693
 
6197
- // CSS property name conversion
6198
- const UPPERCASE_LETTER_REGEX = /([A-Z])/g;
6199
-
6200
6694
  // Escape characters
6201
6695
  const ESCAPE_SLASH_REGEX = /\//g;
6202
6696
  const ESCAPE_DOT_REGEX = /\./g;
@@ -6400,6 +6894,14 @@ function parseCustomClassWithPatterns(className) {
6400
6894
  return null;
6401
6895
  }
6402
6896
 
6897
+ /**
6898
+ * Resolve all CSS custom properties (var) in a CSS string and output only clear CSS (no custom property)
6899
+ * Optimized with for loops and indexOf for 2-3x better performance
6900
+ * @param {string} cssString
6901
+ * @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
6902
+ */
6903
+ // NOTE: resolveCssToClearCss now imported from ./generator/css-string.js
6904
+
6403
6905
  // Cache for getConfigOptions - use LRU cache
6404
6906
  const configOptionsCache = new LRUCache(500);
6405
6907
  function generateTailwindCssString() {
@@ -6489,27 +6991,9 @@ const selectorVariants = {
6489
6991
  number: arg => "> :nth-child(".concat(arg, ")")
6490
6992
  };
6491
6993
 
6492
- // Optimize encoding/decoding bracket values with memoization
6493
- const encodeBracketCache = new LRUCache(1000);
6494
- function encodeBracketValues(input) {
6495
- if (!input) return input;
6496
- if (encodeBracketCache.has(input)) return encodeBracketCache.get(input);
6497
- BRACKET_CONTENT_REGEX.lastIndex = 0; // Reset global regex
6498
- const result = input.replace(BRACKET_CONTENT_REGEX, (_, content) => {
6499
- const encoded = encodeURIComponent(content).replace(OPENING_PAREN_REGEX, "__P__").replace(CLOSING_PAREN_REGEX, "__C__");
6500
- return "[".concat(encoded, "]");
6501
- });
6502
- encodeBracketCache.set(input, result);
6503
- return result;
6504
- }
6505
- const decodeBracketCache = new LRUCache(1000);
6506
- function decodeBracketValues(input) {
6507
- if (!input) return input;
6508
- if (decodeBracketCache.has(input)) return decodeBracketCache.get(input);
6509
- const result = decodeURIComponent(input).replace(ENCODED_PAREN_OPEN_REGEX, "(").replace(ENCODED_PAREN_CLOSE_REGEX, ")");
6510
- decodeBracketCache.set(input, result);
6511
- return result;
6512
- }
6994
+ // NOTE: encodeBracketValues and decodeBracketValues now imported from ./parser/bracket.js
6995
+ // NOTE: encodeBracketCache and decodeBracketCache are in ./parser/bracket.js
6996
+
6513
6997
  function replaceSelector(selector) {
6514
6998
  SELECTOR_VARIANT_REGEX.lastIndex = 0; // Reset global regex
6515
6999
  return selector.replace(SELECTOR_VARIANT_REGEX, (_, raw) => {
@@ -6547,73 +7031,6 @@ function resolveVariants(selector, variants) {
6547
7031
  };
6548
7032
  }
6549
7033
 
6550
- /**
6551
- * Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
6552
- * @param {string} className - Class name with potential opacity modifier
6553
- * @param {string} cssDeclaration - CSS declaration to modify
6554
- * @returns {string} Modified CSS declaration with opacity applied
6555
- */
6556
- function processOpacityModifier(className, cssDeclaration) {
6557
- const opacityMatch = OPACITY_MODIFIER_REGEX.exec(className);
6558
- if (!opacityMatch) return cssDeclaration;
6559
- const opacityValue = parseInt(opacityMatch[1], 10);
6560
- if (opacityValue < 0 || opacityValue > 100) return cssDeclaration;
6561
- const alphaValue = (opacityValue / 100).toString();
6562
-
6563
- // Handle Tailwind's CSS custom property pattern
6564
- let modifiedDeclaration = cssDeclaration;
6565
-
6566
- // Replace opacity custom properties using pre-compiled regexes
6567
- for (const prop in OPACITY_PROP_REGEXES) {
6568
- const regex = OPACITY_PROP_REGEXES[prop];
6569
- regex.lastIndex = 0; // Reset global regex
6570
- modifiedDeclaration = modifiedDeclaration.replace(regex, "".concat(prop, ": ").concat(alphaValue));
6571
- }
6572
-
6573
- // Also handle direct color values using pre-compiled regex patterns
6574
- for (const prop of COLOR_PROPERTIES) {
6575
- const patterns = COLOR_REGEX_PATTERNS.get(prop);
6576
- if (!patterns) continue;
6577
-
6578
- // Reset all regex lastIndex for reuse
6579
- patterns.rgb.lastIndex = 0;
6580
- patterns.rgba.lastIndex = 0;
6581
- patterns.hsl.lastIndex = 0;
6582
- patterns.hsla.lastIndex = 0;
6583
- patterns.hex.lastIndex = 0;
6584
-
6585
- // Convert rgb to rgba with opacity
6586
- modifiedDeclaration = modifiedDeclaration.replace(patterns.rgb, "$1rgba($2, $3, $4, ".concat(alphaValue, ")"));
6587
-
6588
- // Update existing rgba opacity
6589
- modifiedDeclaration = modifiedDeclaration.replace(patterns.rgba, "$1rgba($2, $3, $4, ".concat(alphaValue, ")"));
6590
-
6591
- // Convert hsl to hsla with opacity
6592
- modifiedDeclaration = modifiedDeclaration.replace(patterns.hsl, "$1hsla($2, $3, $4, ".concat(alphaValue, ")"));
6593
-
6594
- // Update existing hsla opacity
6595
- modifiedDeclaration = modifiedDeclaration.replace(patterns.hsla, "$1hsla($2, $3, $4, ".concat(alphaValue, ")"));
6596
-
6597
- // Handle hex colors - convert to rgba
6598
- modifiedDeclaration = modifiedDeclaration.replace(patterns.hex, (match, propPart, hexColor) => {
6599
- // Convert hex to rgba
6600
- const hex = hexColor.replace("#", "");
6601
- let r, g, b;
6602
- if (hex.length === 3) {
6603
- r = parseInt(hex[0] + hex[0], 16);
6604
- g = parseInt(hex[1] + hex[1], 16);
6605
- b = parseInt(hex[2] + hex[2], 16);
6606
- } else {
6607
- r = parseInt(hex.substring(0, 2), 16);
6608
- g = parseInt(hex.substring(2, 4), 16);
6609
- b = parseInt(hex.substring(4, 6), 16);
6610
- }
6611
- return "".concat(propPart, "rgba(").concat(r, ", ").concat(g, ", ").concat(b, ", ").concat(alphaValue, ")");
6612
- });
6613
- }
6614
- return modifiedDeclaration;
6615
- }
6616
-
6617
7034
  // Performance monitoring utilities
6618
7035
  const performanceMonitor = {
6619
7036
  enabled: typeof performance !== "undefined",
@@ -6690,9 +7107,11 @@ function expandGroupedClass(input) {
6690
7107
  } while (result !== prev);
6691
7108
  return result;
6692
7109
  }
6693
- // CSS Processing utilities
7110
+ // CSS Processing utilities
6694
7111
  const parseSelectorCache = new LRUCache(500);
6695
- function parseSelector(selector) {
7112
+
7113
+ // Parse selector with @css property support (different from parser/selector.js)
7114
+ function parseSelectorWithCssProperty(selector) {
6696
7115
  if (parseSelectorCache.has(selector)) {
6697
7116
  return parseSelectorCache.get(selector);
6698
7117
  }
@@ -6717,10 +7136,10 @@ function parseSelector(selector) {
6717
7136
  }
6718
7137
  function processClass(cls, selector, styles) {
6719
7138
  if (cls.trim() === "") return;
6720
- const _ref5 = cls.includes(":") ? [cls.split(":").slice(0, -1), cls.split(":").slice(-1)[0]] : [[], cls],
6721
- _ref6 = _slicedToArray(_ref5, 2),
6722
- rawVariants = _ref6[0],
6723
- className = _ref6[1];
7139
+ const _ref = cls.includes(":") ? [cls.split(":").slice(0, -1), cls.split(":").slice(-1)[0]] : [[], cls],
7140
+ _ref2 = _slicedToArray(_ref, 2),
7141
+ rawVariants = _ref2[0],
7142
+ className = _ref2[1];
6724
7143
  let isImportant = false;
6725
7144
  let pureClassName = className;
6726
7145
  if (className.startsWith("!")) {
@@ -6798,10 +7217,10 @@ function processNestedSelectors(nested, selector, styles, walk) {
6798
7217
  const nestedVal = nested[nestedSel];
6799
7218
  if (nestedSel === "@css" && typeof nestedVal === "object") {
6800
7219
  // For @css directive, use raw CSS values without any processing
6801
- const cssDeclarations = Object.entries(nestedVal).map(_ref7 => {
6802
- let _ref8 = _slicedToArray(_ref7, 2),
6803
- key = _ref8[0],
6804
- value = _ref8[1];
7220
+ const cssDeclarations = Object.entries(nestedVal).map(_ref3 => {
7221
+ let _ref4 = _slicedToArray(_ref3, 2),
7222
+ key = _ref4[0],
7223
+ value = _ref4[1];
6805
7224
  // Convert camelCase to kebab-case (e.g., borderTopColor -> border-top-color)
6806
7225
  const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
6807
7226
  // Ensure CSS values are properly formatted and not processed through Tailwind conversion
@@ -6824,9 +7243,9 @@ function walkStyleTree(selector, val, styles, walk) {
6824
7243
  logger.warn("Invalid selector in walk function:", selector);
6825
7244
  return;
6826
7245
  }
6827
- const _parseSelector = parseSelector(selector),
6828
- baseSelector = _parseSelector.baseSelector,
6829
- cssProperty = _parseSelector.cssProperty;
7246
+ const _parseSelectorWithCss = parseSelectorWithCssProperty(selector),
7247
+ baseSelector = _parseSelectorWithCss.baseSelector,
7248
+ cssProperty = _parseSelectorWithCss.cssProperty;
6830
7249
  if (cssProperty && typeof val === "object" && Array.isArray(val) && val.length > 0) {
6831
7250
  const cssValue = val[0];
6832
7251
  if (typeof cssValue === "string") {
@@ -6865,9 +7284,9 @@ function walkStyleTree(selector, val, styles, walk) {
6865
7284
  }
6866
7285
  walk(selector, [expandGroupedClass(val)]);
6867
7286
  } else if (typeof val === "object" && val !== null) {
6868
- const _parseSelector2 = parseSelector(selector),
6869
- baseSelector = _parseSelector2.baseSelector,
6870
- cssProperty = _parseSelector2.cssProperty;
7287
+ const _parseSelectorWithCss2 = parseSelectorWithCssProperty(selector),
7288
+ baseSelector = _parseSelectorWithCss2.baseSelector,
7289
+ cssProperty = _parseSelectorWithCss2.cssProperty;
6871
7290
  if (cssProperty) {
6872
7291
  const cssValue = Object.values(val).join(" ");
6873
7292
  styles[baseSelector] = styles[baseSelector] || "";
@@ -6878,10 +7297,10 @@ function walkStyleTree(selector, val, styles, walk) {
6878
7297
  // Check if this is a @css object within the current object
6879
7298
  if (val["@css"] && typeof val["@css"] === "object") {
6880
7299
  // Handle object with @css directive - process the @css part specially
6881
- const cssDeclarations = Object.entries(val["@css"]).map(_ref9 => {
6882
- let _ref0 = _slicedToArray(_ref9, 2),
6883
- key = _ref0[0],
6884
- value = _ref0[1];
7300
+ const cssDeclarations = Object.entries(val["@css"]).map(_ref5 => {
7301
+ let _ref6 = _slicedToArray(_ref5, 2),
7302
+ key = _ref6[0],
7303
+ value = _ref6[1];
6885
7304
  // Convert camelCase to kebab-case (e.g., borderTopColor -> border-top-color)
6886
7305
  const cssKey = key.replace(/([A-Z])/g, "-$1").toLowerCase();
6887
7306
  // Keep CSS values intact without any processing
@@ -7027,9 +7446,9 @@ function generateCssString(styles) {
7027
7446
  let cssString = "";
7028
7447
 
7029
7448
  // Add base styles
7030
- for (const _ref1 of baseStyles) {
7031
- const sel = _ref1.sel;
7032
- const css = _ref1.css;
7449
+ for (const _ref7 of baseStyles) {
7450
+ const sel = _ref7.sel;
7451
+ const css = _ref7.css;
7033
7452
  cssString += "".concat(sel, "{").concat(css.trim().replace(/\n/g, ""), "}");
7034
7453
  }
7035
7454
 
@@ -7039,9 +7458,9 @@ function generateCssString(styles) {
7039
7458
  return match ? parseInt(match[1], 10) : 99999;
7040
7459
  }
7041
7460
  mediaStyles.sort((a, b) => mediaPriority(a.sel) - mediaPriority(b.sel));
7042
- for (const _ref10 of mediaStyles) {
7043
- const sel = _ref10.sel;
7044
- const content = _ref10.content;
7461
+ for (const _ref8 of mediaStyles) {
7462
+ const sel = _ref8.sel;
7463
+ const content = _ref8.content;
7045
7464
  cssString += "".concat(sel, "{");
7046
7465
  for (const subSel in content) {
7047
7466
  cssString += "".concat(subSel, "{").concat(content[subSel].trim().replace(/\n/g, ""), "}");
@@ -7238,14 +7657,14 @@ function twsxNoCache(obj) {
7238
7657
  })
7239
7658
  });
7240
7659
  const configOptions = getConfigOptions(mergedOptions, Object.keys(plugins));
7241
- const _ref11 = configOptions.theme || {},
7242
- _ref11$keyframes = _ref11.keyframes,
7243
- keyframes = _ref11$keyframes === void 0 ? {} : _ref11$keyframes;
7660
+ const _ref9 = configOptions.theme || {},
7661
+ _ref9$keyframes = _ref9.keyframes,
7662
+ keyframes = _ref9$keyframes === void 0 ? {} : _ref9$keyframes;
7244
7663
  let customKeyframesCSS = "";
7245
- for (const _ref12 of Object.entries(keyframes)) {
7246
- var _ref13 = _slicedToArray(_ref12, 2);
7247
- const name = _ref13[0];
7248
- const keyframe = _ref13[1];
7664
+ for (const _ref0 of Object.entries(keyframes)) {
7665
+ var _ref1 = _slicedToArray(_ref0, 2);
7666
+ const name = _ref1[0];
7667
+ const keyframe = _ref1[1];
7249
7668
  // Skip if already in built-in keyframes or already injected
7250
7669
  if (BUILTIN_KEYFRAMES[name] || _injectedKeyframes.has(name)) continue;
7251
7670
 
@@ -7256,15 +7675,15 @@ function twsxNoCache(obj) {
7256
7675
 
7257
7676
  // Generate minified custom keyframe
7258
7677
  customKeyframesCSS += "@keyframes ".concat(name, "{");
7259
- for (const _ref14 of Object.entries(keyframe)) {
7260
- var _ref15 = _slicedToArray(_ref14, 2);
7261
- const percentage = _ref15[0];
7262
- const styles = _ref15[1];
7678
+ for (const _ref10 of Object.entries(keyframe)) {
7679
+ var _ref11 = _slicedToArray(_ref10, 2);
7680
+ const percentage = _ref11[0];
7681
+ const styles = _ref11[1];
7263
7682
  customKeyframesCSS += "".concat(percentage, "{");
7264
- for (const _ref16 of Object.entries(styles)) {
7265
- var _ref17 = _slicedToArray(_ref16, 2);
7266
- const prop = _ref17[0];
7267
- const value = _ref17[1];
7683
+ for (const _ref12 of Object.entries(styles)) {
7684
+ var _ref13 = _slicedToArray(_ref12, 2);
7685
+ const prop = _ref13[0];
7686
+ const value = _ref13[1];
7268
7687
  const cssProp = prop.replace(UPPERCASE_LETTER_REGEX, "-$1").toLowerCase();
7269
7688
  customKeyframesCSS += "".concat(cssProp, ":").concat(value, ";");
7270
7689
  }
@@ -7420,111 +7839,16 @@ function twsx(obj) {
7420
7839
  return result;
7421
7840
  }
7422
7841
 
7423
- // Simple hashCode function for CSS deduplication
7424
- function getCssHash(str) {
7425
- let hash = 0,
7426
- i,
7427
- chr;
7428
- if (str.length === 0) return hash;
7429
- for (i = 0; i < str.length; i++) {
7430
- chr = str.charCodeAt(i);
7431
- hash = (hash << 5) - hash + chr;
7432
- hash |= 0; // Convert to 32bit integer
7433
- }
7434
- return hash;
7435
- }
7436
-
7437
- // Enhanced auto-inject CSS with performance monitoring & SSR support
7438
- const injectedCssHashSet = new Set();
7439
-
7440
- // Registry of sourceKey → cssBlock for smart slot-based replacement.
7441
- // Prevents stale CSS chunks from accumulating across HMR cycles.
7442
- const _cssBlockRegistry = new Map();
7443
-
7444
- /**
7445
- * Rebuild the single twsx style tag from the full CSS block registry.
7446
- * Called whenever a block is added or updated.
7447
- */
7448
- function rebuildStyleTag$1() {
7449
- let styleTag = document.getElementById("twsx-auto-style");
7450
- if (!styleTag) {
7451
- styleTag = document.createElement("style");
7452
- styleTag.id = "twsx-auto-style";
7453
- styleTag.setAttribute("data-twsx", "");
7454
- document.head.appendChild(styleTag);
7455
- }
7456
- styleTag.textContent = [..._cssBlockRegistry.values()].join("\n");
7457
- }
7458
- function autoInjectCss(cssString) {
7459
- let sourceKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
7460
- const marker = performanceMonitor.start("css:inject");
7461
- try {
7462
- // SSR mode: collect CSS strings instead of DOM injection. Delegates to
7463
- // the shared collector in ./utils/ssr.js so both the legacy
7464
- // startSSR()/stopSSR() pair and the modern createSSRCollector() actually
7465
- // receive the CSS generated by tw()/twsx().
7466
- if (isSSRCollecting()) {
7467
- collectSSRCSS(cssString);
7468
- performanceMonitor.end(marker);
7469
- return;
7470
- }
7471
- if (IS_BROWSER$1) {
7472
- if (sourceKey) {
7473
- // Slot-based update: each unique twsx(obj) call owns its own CSS block.
7474
- // When styles change (new content, same logical call site via cacheKey)
7475
- // the old slot is replaced and the style tag is fully rebuilt, so no
7476
- // stale rules from previous HMR cycles can pile up.
7477
- const existing = _cssBlockRegistry.get(sourceKey);
7478
- if (existing === cssString) {
7479
- // Identical content – nothing to do.
7480
- performanceMonitor.end(marker);
7481
- return;
7482
- }
7483
- _cssBlockRegistry.set(sourceKey, cssString);
7484
- rebuildStyleTag$1();
7485
- if (_cssBlockRegistry.size % 10 === 0) {
7486
- logger.debug("CSS registry stats: ".concat(_cssBlockRegistry.size, " blocks registered"));
7487
- }
7488
- performanceMonitor.end(marker);
7489
- return;
7490
- }
7491
-
7492
- // Fallback path (e.g. direct autoInjectCss calls without a sourceKey):
7493
- // keep the original hash-based dedup + append behaviour.
7494
- const cssHash = getCssHash(cssString);
7495
- if (injectedCssHashSet.has(cssHash)) {
7496
- performanceMonitor.end(marker);
7497
- return;
7498
- }
7499
- injectedCssHashSet.add(cssHash);
7500
- evictSet(injectedCssHashSet);
7501
- let styleTag = document.getElementById("twsx-auto-style");
7502
- if (!styleTag) {
7503
- styleTag = document.createElement("style");
7504
- styleTag.id = "twsx-auto-style";
7505
- styleTag.setAttribute("data-twsx", "");
7506
- document.head.appendChild(styleTag);
7507
- }
7508
-
7509
- // Append CSS to style tag using textContent for reliability
7510
- // Note: insertRule + textContent mixing destroys CSSOM rules,
7511
- // so we use textContent exclusively for consistent behavior
7512
- // with @keyframes, @media, and other nested CSS blocks.
7513
- styleTag.textContent += "\n".concat(cssString);
7514
-
7515
- // Log injection stats periodically
7516
- if (injectedCssHashSet.size % 10 === 0) {
7517
- logger.debug("CSS injection stats: ".concat(injectedCssHashSet.size, " unique stylesheets injected"));
7518
- }
7519
- }
7520
- performanceMonitor.end(marker);
7521
- } catch (error) {
7522
- performanceMonitor.end(marker);
7523
- logger.error("Error injecting CSS:", error);
7524
- }
7525
- }
7842
+ // ============================================================================
7843
+ // Main API Exports
7844
+ // ============================================================================
7845
+ // twsxClassName - Unified CSS-in-JS API with variants and slots
7846
+ // tw - Atomic CSS class generator with pseudo-class support
7847
+ // REMOVED: Re-export removed to break circular dependency
7848
+ // Import directly from './className/index.js' if needed
7849
+ // export { twsxClassName, tw } from "./className/index.js";
7526
7850
 
7527
- const _excluded = ["name", "prefix", "hash", "hashLength", "inject", "_"],
7851
+ const _excluded = ["name", "prefix", "hash", "hashLength", "inject"],
7528
7852
  _excluded2 = ["class", "className"],
7529
7853
  _excluded3 = ["class", "className"];
7530
7854
 
@@ -8023,14 +8347,115 @@ function processTokens(classString) {
8023
8347
  // Style Processing Utilities
8024
8348
  // ============================================================================
8025
8349
 
8026
- function expandShorthands(config, baseSelector) {
8027
- const expanded = {};
8028
- const specialKeys = new Set(["name", "prefix", "hash", "hashLength", "inject", "base", "variants", "compoundVariants", "defaultVariants", "slots", "responsiveVariants", "extend", "animation", "enter", "exit", "enterFrom", "enterTo", "leaveFrom", "leaveTo", "_"]);
8350
+ /**
8351
+ * Known CSS property names (camelCase and kebab-case).
8352
+ * Used to differentiate raw CSS properties from Tailwind shorthand keys.
8353
+ * Covers the full set of standard CSS properties.
8354
+ */
8355
+ const CSS_PROPERTIES = new Set([
8356
+ // Box model
8357
+ "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "min-width", "min-height", "max-width", "max-height", "margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "margin-top", "margin-right", "margin-bottom", "margin-left", "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft", "padding-top", "padding-right", "padding-bottom", "padding-left", "boxSizing", "box-sizing",
8358
+ // Display & layout
8359
+ "display", "overflow", "overflowX", "overflowY", "overflow-x", "overflow-y", "visibility", "opacity", "position", "top", "right", "bottom", "left", "zIndex", "z-index", "float", "clear",
8360
+ // Flexbox
8361
+ "flex", "flexGrow", "flexShrink", "flexBasis", "flexFlow", "flexDirection", "flexWrap", "flex-grow", "flex-shrink", "flex-basis", "flex-flow", "flex-direction", "flex-wrap", "alignItems", "alignContent", "alignSelf", "justifyContent", "justifyItems", "justifySelf", "align-items", "align-content", "align-self", "justify-content", "justify-items", "justify-self", "gap", "rowGap", "columnGap", "row-gap", "column-gap", "order", "placeItems", "placeContent", "placeSelf", "place-items", "place-content", "place-self",
8362
+ // Grid
8363
+ "grid", "gridTemplate", "gridTemplateColumns", "gridTemplateRows", "gridTemplateAreas", "gridColumn", "gridRow", "gridArea", "gridAutoFlow", "gridAutoColumns", "gridAutoRows", "grid-template", "grid-template-columns", "grid-template-rows", "grid-template-areas", "grid-column", "grid-row", "grid-area", "grid-auto-flow", "grid-auto-columns", "grid-auto-rows",
8364
+ // Typography
8365
+ "color", "fontSize", "fontWeight", "fontFamily", "fontStyle", "fontVariant", "fontStretch", "font-size", "font-weight", "font-family", "font-style", "font-variant", "font-stretch", "lineHeight", "letterSpacing", "wordSpacing", "textAlign", "textDecoration", "textTransform", "line-height", "letter-spacing", "word-spacing", "text-align", "text-decoration", "text-transform", "textOverflow", "whiteSpace", "wordBreak", "overflowWrap", "hyphens", "textIndent", "text-overflow", "white-space", "word-break", "overflow-wrap", "text-indent", "verticalAlign", "vertical-align", "fontFeatureSettings", "font-feature-settings",
8366
+ // Backgrounds
8367
+ "background", "backgroundColor", "backgroundImage", "backgroundSize", "backgroundPosition", "backgroundRepeat", "backgroundAttachment", "backgroundOrigin", "backgroundClip", "background-color", "background-image", "background-size", "background-position", "background-repeat", "background-attachment", "background-origin", "background-clip",
8368
+ // Borders
8369
+ "border", "borderTop", "borderRight", "borderBottom", "borderLeft", "border-top", "border-right", "border-bottom", "border-left", "borderWidth", "borderStyle", "borderColor", "borderRadius", "border-width", "border-style", "border-color", "border-radius", "borderTopWidth", "borderTopStyle", "borderTopColor", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomWidth", "borderBottomStyle", "borderBottomColor", "borderBottomLeftRadius", "borderBottomRightRadius", "borderLeftWidth", "borderLeftStyle", "borderLeftColor", "borderRightWidth", "borderRightStyle", "borderRightColor", "outline", "outlineWidth", "outlineStyle", "outlineColor", "outlineOffset", "outline-width", "outline-style", "outline-color", "outline-offset",
8370
+ // Transforms & transitions
8371
+ "transform", "transformOrigin", "transformStyle", "perspective", "perspectiveOrigin", "transform-origin", "transform-style", "perspective-origin", "transition", "transitionProperty", "transitionDuration", "transitionTimingFunction", "transitionDelay", "transition-property", "transition-duration", "transition-timing-function", "transition-delay", "animation", "animationName", "animationDuration", "animationTimingFunction", "animationDelay", "animationIterationCount", "animationDirection", "animationFillMode", "animationPlayState", "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-iteration-count", "animation-direction", "animation-fill-mode", "animation-play-state",
8372
+ // Effects
8373
+ "boxShadow", "textShadow", "filter", "backdropFilter", "opacity", "box-shadow", "text-shadow", "backdrop-filter", "mix-blend-mode", "mixBlendMode", "isolation", "objectFit", "objectPosition", "object-fit", "object-position",
8374
+ // Lists & tables
8375
+ "listStyle", "listStyleType", "listStylePosition", "listStyleImage", "list-style", "list-style-type", "list-style-position", "list-style-image", "tableLayout", "borderCollapse", "borderSpacing", "captionSide", "emptyCells", "table-layout", "border-collapse", "border-spacing", "caption-side", "empty-cells",
8376
+ // SVG
8377
+ "fill", "stroke", "strokeWidth", "strokeDasharray", "strokeDashoffset", "strokeLinecap", "strokeLinejoin", "stroke-width", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
8378
+ // Misc
8379
+ "content", "cursor", "pointerEvents", "userSelect", "resize", "appearance", "caretColor", "pointer-events", "user-select", "caret-color", "willChange", "will-change", "scrollBehavior", "scroll-behavior", "clipPath", "clip-path", "mask", "maskImage", "mask-image", "columns", "columnCount", "columnGap", "columnRule", "columnWidth", "columnSpan", "column-count", "column-rule", "column-width", "column-span", "pageBreakBefore", "pageBreakAfter", "pageBreakInside", "breakBefore", "breakAfter", "breakInside", "page-break-before", "page-break-after", "page-break-inside", "break-before", "break-after", "break-inside",
8380
+ // CSS variables & custom
8381
+ "all", "direction", "unicodeBidi", "unicode-bidi", "writingMode", "writing-mode", "overscrollBehavior", "overscroll-behavior", "touchAction", "touch-action", "scrollSnapType", "scrollSnapAlign", "scroll-snap-type", "scroll-snap-align"]);
8382
+
8383
+ /**
8384
+ * Detect if a key is a raw CSS property (camelCase or kebab-case).
8385
+ * Also accepts CSS custom properties (--var-name) and any key containing a hyphen
8386
+ * that doesn't match known Tailwind-ish patterns.
8387
+ *
8388
+ * @param {string} key
8389
+ * @returns {boolean}
8390
+ */
8391
+ function isCssProperty(key) {
8392
+ // Explicit set match (fast path)
8393
+ if (CSS_PROPERTIES.has(key)) return true;
8394
+ // CSS custom properties
8395
+ if (key.startsWith("--")) return true;
8396
+ // kebab-case that isn't a Tailwind modifier pattern (no colons)
8397
+ if (key.includes("-") && !key.includes(":") && !key.startsWith("@")) {
8398
+ // Exclude known Tailwind-ish hyphenated shorthands already in PSEUDO_SHORTHANDS or BREAKPOINTS
8399
+ if (PSEUDO_SHORTHANDS[key] || GROUP_PEER_STATES[key] || BREAKPOINTS[key]) return false;
8400
+ return true;
8401
+ }
8402
+ return false;
8403
+ }
8404
+
8405
+ /**
8406
+ * Convert a camelCase or kebab-case key to a kebab-case CSS property.
8407
+ * @param {string} key
8408
+ * @returns {string}
8409
+ */
8410
+ function toCssPropertyName(key) {
8411
+ // Already kebab-case
8412
+ if (key.includes("-")) return key;
8413
+ // camelCase → kebab-case
8414
+ return key.replace(/([A-Z])/g, "-$1").toLowerCase();
8415
+ }
8416
+
8417
+ /**
8418
+ * Extract all raw CSS property key/value pairs from a config object.
8419
+ * Returns an object suitable for the @css directive (kebab-case keys, string values).
8420
+ *
8421
+ * @param {Object} config
8422
+ * @returns {Object|null} - null if nothing found
8423
+ */
8424
+ function extractRawCssProps(config) {
8425
+ let result = null;
8029
8426
  for (const _ref3 of Object.entries(config)) {
8030
8427
  var _ref4 = _slicedToArray(_ref3, 2);
8031
8428
  const key = _ref4[0];
8032
8429
  const value = _ref4[1];
8430
+ if (!isCssProperty(key)) continue;
8431
+ if (typeof value !== "string" && typeof value !== "number") continue;
8432
+ if (!result) result = {};
8433
+ result[toCssPropertyName(key)] = String(value);
8434
+ }
8435
+ return result;
8436
+ }
8437
+ function expandShorthands(config, baseSelector) {
8438
+ const expanded = {};
8439
+ const specialKeys = new Set(["name", "prefix", "hash", "hashLength", "inject", "base", "variants", "compoundVariants", "defaultVariants", "slots", "responsiveVariants", "extend", "animation", "enter", "exit", "enterFrom", "enterTo", "leaveFrom", "leaveTo", "_", "tw"]);
8440
+
8441
+ // Collect raw CSS properties into the @css directive for this selector
8442
+ const rawCss = extractRawCssProps(config);
8443
+ if (rawCss) {
8444
+ // twsx supports { [selector]: { "@css": { prop: value } } }
8445
+ // We expand that here so it lands in the style object correctly
8446
+ if (!expanded[baseSelector]) expanded[baseSelector] = {};
8447
+ // expanded[baseSelector] may already be a string (Tailwind classes) — keep both
8448
+ // by using a special marker object that the caller (generateBasicClassName) will merge
8449
+ expanded["__rawCss__"] = expanded["__rawCss__"] || {};
8450
+ Object.assign(expanded["__rawCss__"], rawCss);
8451
+ }
8452
+ for (const _ref5 of Object.entries(config)) {
8453
+ var _ref6 = _slicedToArray(_ref5, 2);
8454
+ const key = _ref6[0];
8455
+ const value = _ref6[1];
8033
8456
  if (specialKeys.has(key)) continue;
8457
+ // Skip raw CSS properties — already handled above
8458
+ if (isCssProperty(key) && (typeof value === "string" || typeof value === "number")) continue;
8034
8459
 
8035
8460
  // Process tokens in value
8036
8461
  const processedValue = typeof value === "string" ? processTokens(value) : value;
@@ -8082,22 +8507,40 @@ function expandShorthands(config, baseSelector) {
8082
8507
  }
8083
8508
  function processNestedStyles(config, baseSelector) {
8084
8509
  const result = {};
8085
- for (const _ref5 of Object.entries(config)) {
8086
- var _ref6 = _slicedToArray(_ref5, 2);
8087
- const key = _ref6[0];
8088
- const value = _ref6[1];
8510
+ for (const _ref7 of Object.entries(config)) {
8511
+ var _ref8 = _slicedToArray(_ref7, 2);
8512
+ const key = _ref8[0];
8513
+ const value = _ref8[1];
8089
8514
  if (typeof value === "object" && !Array.isArray(value)) {
8090
8515
  const nestedSelector = key.replace(/^&/, baseSelector);
8091
8516
  const nested = processNestedStyles(value, nestedSelector);
8092
8517
  Object.assign(result, nested);
8093
- if (value._) {
8094
- result[nestedSelector] = processTokens(value._);
8518
+
8519
+ // Support both `_` and `tw` as the Tailwind class key inside nested objects
8520
+ const nestedTwClasses = [value._, value.tw].filter(Boolean).join(" ");
8521
+ if (nestedTwClasses) {
8522
+ result[nestedSelector] = processTokens(nestedTwClasses);
8095
8523
  const nestedShorthands = expandShorthands(value, nestedSelector);
8524
+ // Wire raw CSS from nested object
8525
+ if (nestedShorthands.__rawCss__) {
8526
+ const existingNested = result[nestedSelector] || "";
8527
+ if (typeof existingNested === "string") {
8528
+ result[nestedSelector] = [existingNested, {
8529
+ "@css": nestedShorthands.__rawCss__
8530
+ }];
8531
+ }
8532
+ delete nestedShorthands.__rawCss__;
8533
+ }
8096
8534
  Object.assign(result, nestedShorthands);
8097
8535
  }
8098
8536
  } else if (typeof value === "string") {
8099
- if (key === "_") {
8100
- result[baseSelector] = processTokens(value);
8537
+ if (key === "_" || key === "tw") {
8538
+ // Both _ and tw are Tailwind class shorthands for the current selector
8539
+ if (result[baseSelector]) {
8540
+ result[baseSelector] = result[baseSelector] + " " + processTokens(value);
8541
+ } else {
8542
+ result[baseSelector] = processTokens(value);
8543
+ }
8101
8544
  } else {
8102
8545
  const selector = PSEUDO_SHORTHANDS[key] ? PSEUDO_SHORTHANDS[key].replace("&", baseSelector) : GROUP_PEER_STATES[key] ? GROUP_PEER_STATES[key].replace("&", baseSelector) : key.replace(/^&/, baseSelector);
8103
8546
  result[selector] = processTokens(value);
@@ -8162,10 +8605,10 @@ function processAnimations(config, baseSelector, className) {
8162
8605
  }
8163
8606
  function generateKeyframes(name, frames) {
8164
8607
  let css = "@keyframes ".concat(name, " {\n");
8165
- for (const _ref7 of Object.entries(frames)) {
8166
- var _ref8 = _slicedToArray(_ref7, 2);
8167
- const key = _ref8[0];
8168
- const value = _ref8[1];
8608
+ for (const _ref9 of Object.entries(frames)) {
8609
+ var _ref0 = _slicedToArray(_ref9, 2);
8610
+ const key = _ref0[0];
8611
+ const value = _ref0[1];
8169
8612
  // Convert Tailwind classes to approximate CSS (simplified)
8170
8613
  const cssValue = value.replace(/([a-z]+)-([a-z0-9-]+)/g, (match, prop, val) => {
8171
8614
  // This is a simplified conversion - real implementation would use twsx
@@ -8214,8 +8657,6 @@ function generateBasicClassName(config) {
8214
8657
  hashLength = _config$hashLength === void 0 ? globalConfig.hashLength : _config$hashLength,
8215
8658
  _config$inject = config.inject,
8216
8659
  inject = _config$inject === void 0 ? globalConfig.inject : _config$inject,
8217
- _config$_ = config._,
8218
- baseStyles = _config$_ === void 0 ? "" : _config$_,
8219
8660
  rest = _objectWithoutProperties(config, _excluded);
8220
8661
  const configHash = getConfigHash(config);
8221
8662
  let className;
@@ -8233,22 +8674,11 @@ function generateBasicClassName(config) {
8233
8674
  return cached;
8234
8675
  }
8235
8676
  const baseSelector = ".".concat(className);
8236
- const styleObj = {};
8237
-
8238
- // Add base styles with token processing
8239
- if (baseStyles) {
8240
- styleObj[baseSelector] = processTokens(baseStyles);
8241
- }
8242
-
8243
- // Process shorthands (hover, focus, dark, group-hover, etc.)
8244
- const expanded = expandShorthands(rest, baseSelector);
8245
- Object.assign(styleObj, expanded);
8246
8677
 
8247
- // Process nested objects
8248
- const nested = processNestedStyles(rest, baseSelector);
8249
- Object.assign(styleObj, nested);
8678
+ // buildStyleObj handles `_`, `tw`, raw CSS props, pseudo shorthands, nested — all in one place
8679
+ const styleObj = buildStyleObj(rest, baseSelector);
8250
8680
 
8251
- // Process animations
8681
+ // Process animations (has its own dedicated fields)
8252
8682
  const _processAnimations = processAnimations(rest, baseSelector, className),
8253
8683
  animStyles = _processAnimations.styles,
8254
8684
  keyframes = _processAnimations.keyframes;
@@ -8273,6 +8703,60 @@ function generateBasicClassName(config) {
8273
8703
  return className;
8274
8704
  }
8275
8705
 
8706
+ // ============================================================================
8707
+ // Shared: Build a twsx-compatible style object from a style config object
8708
+ // Handles `_`, `tw` (Tailwind classes), raw CSS properties, pseudo shorthands,
8709
+ // breakpoints, and nested selectors — centralised so variants & slots reuse it.
8710
+ // ============================================================================
8711
+
8712
+ /**
8713
+ * Build a styleObj ready for twsx() from a style config value.
8714
+ *
8715
+ * @param {string|Object} styleValue - A Tailwind class string OR a mixed config object
8716
+ * @param {string} selector - The CSS selector to target (e.g. ".btn--color-primary")
8717
+ * @returns {Object} - styleObj for twsx()
8718
+ */
8719
+ function buildStyleObj(styleValue, selector) {
8720
+ const styleObj = {};
8721
+ if (typeof styleValue === "string") {
8722
+ // Plain Tailwind class string
8723
+ styleObj[selector] = processTokens(styleValue);
8724
+ return styleObj;
8725
+ }
8726
+ if (typeof styleValue !== "object" || styleValue === null) return styleObj;
8727
+
8728
+ // Merge `_` and `tw` as Tailwind classes for this selector
8729
+ const twClasses = [styleValue._, styleValue.tw].filter(Boolean).join(" ");
8730
+
8731
+ // Extract raw CSS properties
8732
+ const rawCss = extractRawCssProps(styleValue);
8733
+ if (twClasses && rawCss) {
8734
+ // Both Tailwind classes AND raw CSS — use array form: [twClasses, { "@css": {...} }]
8735
+ styleObj[selector] = [processTokens(twClasses), {
8736
+ "@css": rawCss
8737
+ }];
8738
+ } else if (twClasses) {
8739
+ styleObj[selector] = processTokens(twClasses);
8740
+ } else if (rawCss) {
8741
+ styleObj[selector] = [{
8742
+ "@css": rawCss
8743
+ }];
8744
+ }
8745
+
8746
+ // Expand pseudo shorthands, breakpoints, nested selectors
8747
+ const expanded = expandShorthands(styleValue, selector);
8748
+ if (expanded.__rawCss__) {
8749
+ // top-level rawCss already handled above; drop the marker
8750
+ delete expanded.__rawCss__;
8751
+ }
8752
+ Object.assign(styleObj, expanded);
8753
+
8754
+ // Process nested style objects
8755
+ const nested = processNestedStyles(styleValue, selector);
8756
+ Object.assign(styleObj, nested);
8757
+ return styleObj;
8758
+ }
8759
+
8276
8760
  // ============================================================================
8277
8761
  // Core: Variants Mode
8278
8762
  // ============================================================================
@@ -8312,18 +8796,7 @@ function createVariants(config) {
8312
8796
  // Generate base styles
8313
8797
  if (base) {
8314
8798
  const baseSelector = ".".concat(baseClassName);
8315
- let styleObj = {};
8316
- if (typeof base === "string") {
8317
- styleObj[baseSelector] = processTokens(base);
8318
- } else if (typeof base === "object") {
8319
- if (base._) {
8320
- styleObj[baseSelector] = processTokens(base._);
8321
- }
8322
- const expanded = expandShorthands(base, baseSelector);
8323
- Object.assign(styleObj, expanded);
8324
- const nested = processNestedStyles(base, baseSelector);
8325
- Object.assign(styleObj, nested);
8326
- }
8799
+ const styleObj = buildStyleObj(base, baseSelector);
8327
8800
  const baseCss = twsx(styleObj, {
8328
8801
  inject: false
8329
8802
  });
@@ -8331,28 +8804,17 @@ function createVariants(config) {
8331
8804
  }
8332
8805
 
8333
8806
  // Generate styles for each variant value
8334
- for (const _ref9 of Object.entries(variants)) {
8335
- var _ref0 = _slicedToArray(_ref9, 2);
8336
- const variantKey = _ref0[0];
8337
- const variantOptions = _ref0[1];
8338
- for (const _ref1 of Object.entries(variantOptions)) {
8339
- var _ref10 = _slicedToArray(_ref1, 2);
8340
- const optionKey = _ref10[0];
8341
- const optionValue = _ref10[1];
8807
+ for (const _ref1 of Object.entries(variants)) {
8808
+ var _ref10 = _slicedToArray(_ref1, 2);
8809
+ const variantKey = _ref10[0];
8810
+ const variantOptions = _ref10[1];
8811
+ for (const _ref11 of Object.entries(variantOptions)) {
8812
+ var _ref12 = _slicedToArray(_ref11, 2);
8813
+ const optionKey = _ref12[0];
8814
+ const optionValue = _ref12[1];
8342
8815
  const variantClassName = "".concat(baseClassName, "--").concat(variantKey, "-").concat(optionKey);
8343
8816
  const selector = ".".concat(variantClassName);
8344
- let styleObj = {};
8345
- if (typeof optionValue === "string") {
8346
- styleObj[selector] = processTokens(optionValue);
8347
- } else if (typeof optionValue === "object") {
8348
- if (optionValue._) {
8349
- styleObj[selector] = processTokens(optionValue._);
8350
- }
8351
- const expanded = expandShorthands(optionValue, selector);
8352
- Object.assign(styleObj, expanded);
8353
- const nested = processNestedStyles(optionValue, selector);
8354
- Object.assign(styleObj, nested);
8355
- }
8817
+ const styleObj = buildStyleObj(optionValue, selector);
8356
8818
  const css = twsx(styleObj, {
8357
8819
  inject: false
8358
8820
  });
@@ -8363,10 +8825,10 @@ function createVariants(config) {
8363
8825
 
8364
8826
  // Generate responsive variant styles if enabled
8365
8827
  if (responsiveVariants.includes(variantKey)) {
8366
- for (const _ref11 of Object.entries(BREAKPOINTS)) {
8367
- var _ref12 = _slicedToArray(_ref11, 2);
8368
- const bp = _ref12[0];
8369
- const bpValue = _ref12[1];
8828
+ for (const _ref13 of Object.entries(BREAKPOINTS)) {
8829
+ var _ref14 = _slicedToArray(_ref13, 2);
8830
+ const bp = _ref14[0];
8831
+ const bpValue = _ref14[1];
8370
8832
  const respClassName = "".concat(baseClassName, "--").concat(bp, "-").concat(variantKey, "-").concat(optionKey);
8371
8833
  const respSelector = ".".concat(respClassName);
8372
8834
  const respStyleObj = {
@@ -8412,10 +8874,10 @@ function createVariants(config) {
8412
8874
  // Inject all CSS upfront
8413
8875
  if (inject) {
8414
8876
  let allCss = "";
8415
- for (const _ref13 of variantStyles.entries()) {
8416
- var _ref14 = _slicedToArray(_ref13, 2);
8417
- const key = _ref14[0];
8418
- const value = _ref14[1];
8877
+ for (const _ref15 of variantStyles.entries()) {
8878
+ var _ref16 = _slicedToArray(_ref15, 2);
8879
+ const key = _ref16[0];
8880
+ const value = _ref16[1];
8419
8881
  if (key === "__base__") {
8420
8882
  allCss += value + "\n";
8421
8883
  } else if (typeof value === "object" && value.css) {
@@ -8436,10 +8898,10 @@ function createVariants(config) {
8436
8898
  const classes = [baseClassName];
8437
8899
 
8438
8900
  // Add variant classes
8439
- for (const _ref15 of Object.entries(mergedProps)) {
8440
- var _ref16 = _slicedToArray(_ref15, 2);
8441
- const variantKey = _ref16[0];
8442
- const variantValue = _ref16[1];
8901
+ for (const _ref17 of Object.entries(mergedProps)) {
8902
+ var _ref18 = _slicedToArray(_ref17, 2);
8903
+ const variantKey = _ref18[0];
8904
+ const variantValue = _ref18[1];
8443
8905
  if (variantValue === undefined || variantValue === null) continue;
8444
8906
 
8445
8907
  // Handle boolean variants
@@ -8447,10 +8909,10 @@ function createVariants(config) {
8447
8909
 
8448
8910
  // Handle responsive variants: { size: { initial: 'sm', md: 'lg' } }
8449
8911
  if (typeof variantValue === "object" && !Array.isArray(variantValue)) {
8450
- for (const _ref17 of Object.entries(variantValue)) {
8451
- var _ref18 = _slicedToArray(_ref17, 2);
8452
- const bp = _ref18[0];
8453
- const bpVariantValue = _ref18[1];
8912
+ for (const _ref19 of Object.entries(variantValue)) {
8913
+ var _ref20 = _slicedToArray(_ref19, 2);
8914
+ const bp = _ref20[0];
8915
+ const bpVariantValue = _ref20[1];
8454
8916
  if (bp === "initial") {
8455
8917
  const variantData = variantStyles.get("".concat(variantKey, ":").concat(bpVariantValue));
8456
8918
  if (variantData) classes.push(variantData.className);
@@ -8468,18 +8930,18 @@ function createVariants(config) {
8468
8930
  }
8469
8931
 
8470
8932
  // Check compound variants
8471
- for (const _ref19 of variantStyles.entries()) {
8472
- var _ref20 = _slicedToArray(_ref19, 2);
8473
- const key = _ref20[0];
8474
- const data = _ref20[1];
8933
+ for (const _ref21 of variantStyles.entries()) {
8934
+ var _ref22 = _slicedToArray(_ref21, 2);
8935
+ const key = _ref22[0];
8936
+ const data = _ref22[1];
8475
8937
  if (!key.startsWith("__compound__:")) continue;
8476
8938
  const conditions = data.conditions,
8477
8939
  className = data.className;
8478
8940
  let matches = true;
8479
- for (const _ref21 of Object.entries(conditions)) {
8480
- var _ref22 = _slicedToArray(_ref21, 2);
8481
- const condKey = _ref22[0];
8482
- const condValue = _ref22[1];
8941
+ for (const _ref23 of Object.entries(conditions)) {
8942
+ var _ref24 = _slicedToArray(_ref23, 2);
8943
+ const condKey = _ref24[0];
8944
+ const condValue = _ref24[1];
8483
8945
  const propValue = mergedProps[condKey];
8484
8946
  const normalizedPropValue = propValue === true ? "true" : propValue === false ? "false" : propValue;
8485
8947
  if (Array.isArray(condValue)) {
@@ -8554,24 +9016,13 @@ function createSlots(config) {
8554
9016
  let allCss = "";
8555
9017
 
8556
9018
  // Generate base slot styles
8557
- for (const _ref23 of Object.entries(slots)) {
8558
- var _ref24 = _slicedToArray(_ref23, 2);
8559
- const slotName = _ref24[0];
8560
- const slotStyles = _ref24[1];
9019
+ for (const _ref25 of Object.entries(slots)) {
9020
+ var _ref26 = _slicedToArray(_ref25, 2);
9021
+ const slotName = _ref26[0];
9022
+ const slotStyles = _ref26[1];
8561
9023
  const slotClassName = "".concat(componentName, "__").concat(slotName);
8562
9024
  const selector = ".".concat(slotClassName);
8563
- let styleObj = {};
8564
- if (typeof slotStyles === "string") {
8565
- styleObj[selector] = processTokens(slotStyles);
8566
- } else if (typeof slotStyles === "object") {
8567
- if (slotStyles._) {
8568
- styleObj[selector] = processTokens(slotStyles._);
8569
- }
8570
- const expanded = expandShorthands(slotStyles, selector);
8571
- Object.assign(styleObj, expanded);
8572
- const nested = processNestedStyles(slotStyles, selector);
8573
- Object.assign(styleObj, nested);
8574
- }
9025
+ const styleObj = buildStyleObj(slotStyles, selector);
8575
9026
  const css = twsx(styleObj, {
8576
9027
  inject: false
8577
9028
  });
@@ -8584,32 +9035,26 @@ function createSlots(config) {
8584
9035
 
8585
9036
  // Generate variant styles for each slot
8586
9037
  const variantSlotStyles = new Map();
8587
- for (const _ref25 of Object.entries(variants)) {
8588
- var _ref26 = _slicedToArray(_ref25, 2);
8589
- const variantKey = _ref26[0];
8590
- const variantOptions = _ref26[1];
8591
- for (const _ref27 of Object.entries(variantOptions)) {
8592
- var _ref28 = _slicedToArray(_ref27, 2);
8593
- const optionKey = _ref28[0];
8594
- const optionValue = _ref28[1];
8595
- if (typeof optionValue === "object" && !optionValue._) {
8596
- for (const _ref29 of Object.entries(optionValue)) {
8597
- var _ref30 = _slicedToArray(_ref29, 2);
8598
- const slotName = _ref30[0];
8599
- const slotStyles = _ref30[1];
9038
+ for (const _ref27 of Object.entries(variants)) {
9039
+ var _ref28 = _slicedToArray(_ref27, 2);
9040
+ const variantKey = _ref28[0];
9041
+ const variantOptions = _ref28[1];
9042
+ for (const _ref29 of Object.entries(variantOptions)) {
9043
+ var _ref30 = _slicedToArray(_ref29, 2);
9044
+ const optionKey = _ref30[0];
9045
+ const optionValue = _ref30[1];
9046
+ // optionValue may be a slot-keyed object: { root: '...', header: '...' }
9047
+ // Detect: it's an object, and its keys match slot names (not `_` / `tw` / raw CSS)
9048
+ const isSlotMap = typeof optionValue === "object" && optionValue !== null && !optionValue._ && !optionValue.tw && !extractRawCssProps(optionValue) && Object.keys(optionValue).some(k => slots[k]);
9049
+ if (isSlotMap) {
9050
+ for (const _ref31 of Object.entries(optionValue)) {
9051
+ var _ref32 = _slicedToArray(_ref31, 2);
9052
+ const slotName = _ref32[0];
9053
+ const slotStyles = _ref32[1];
8600
9054
  if (typeof slotStyles === "string" || typeof slotStyles === "object") {
8601
9055
  const variantClassName = "".concat(componentName, "__").concat(slotName, "--").concat(variantKey, "-").concat(optionKey);
8602
9056
  const selector = ".".concat(variantClassName);
8603
- let styleObj = {};
8604
- if (typeof slotStyles === "string") {
8605
- styleObj[selector] = processTokens(slotStyles);
8606
- } else {
8607
- if (slotStyles._) {
8608
- styleObj[selector] = processTokens(slotStyles._);
8609
- }
8610
- const expanded = expandShorthands(slotStyles, selector);
8611
- Object.assign(styleObj, expanded);
8612
- }
9057
+ const styleObj = buildStyleObj(slotStyles, selector);
8613
9058
  const css = twsx(styleObj, {
8614
9059
  inject: false
8615
9060
  });
@@ -8633,22 +9078,22 @@ function createSlots(config) {
8633
9078
  const rest = _objectWithoutProperties(compound, _excluded3);
8634
9079
 
8635
9080
  // Check if compound has slot-specific styles
8636
- for (const _ref31 of slotData.entries()) {
8637
- var _ref32 = _slicedToArray(_ref31, 1);
8638
- const slotName = _ref32[0];
8639
- if (rest[slotName] && typeof rest[slotName] === "string") {
9081
+ for (const _ref33 of slotData.entries()) {
9082
+ var _ref34 = _slicedToArray(_ref33, 1);
9083
+ const slotName = _ref34[0];
9084
+ const slotValue = rest[slotName];
9085
+ if (slotValue && (typeof slotValue === "string" || typeof slotValue === "object")) {
8640
9086
  const compoundClassName = "".concat(componentName, "__").concat(slotName, "--compound-").concat(i);
8641
9087
  const selector = ".".concat(compoundClassName);
8642
- const css = twsx({
8643
- [selector]: processTokens(rest[slotName])
8644
- }, {
9088
+ const styleObj = buildStyleObj(slotValue, selector);
9089
+ const css = twsx(styleObj, {
8645
9090
  inject: false
8646
9091
  });
8647
9092
  const conditions = {};
8648
- for (const _ref33 of Object.entries(rest)) {
8649
- var _ref34 = _slicedToArray(_ref33, 2);
8650
- const k = _ref34[0];
8651
- const v = _ref34[1];
9093
+ for (const _ref35 of Object.entries(rest)) {
9094
+ var _ref36 = _slicedToArray(_ref35, 2);
9095
+ const k = _ref36[0];
9096
+ const v = _ref36[1];
8652
9097
  if (!slots[k]) conditions[k] = v;
8653
9098
  }
8654
9099
  variantSlotStyles.set("__compound__:".concat(i, ":").concat(slotName), {
@@ -8673,17 +9118,17 @@ function createSlots(config) {
8673
9118
  let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
8674
9119
  const mergedProps = _objectSpread2(_objectSpread2({}, defaultVariants), props);
8675
9120
  const result = {};
8676
- for (const _ref35 of slotData.entries()) {
8677
- var _ref36 = _slicedToArray(_ref35, 2);
8678
- const slotName = _ref36[0];
8679
- const data = _ref36[1];
9121
+ for (const _ref37 of slotData.entries()) {
9122
+ var _ref38 = _slicedToArray(_ref37, 2);
9123
+ const slotName = _ref38[0];
9124
+ const data = _ref38[1];
8680
9125
  const classes = [data.className];
8681
9126
 
8682
9127
  // Add variant classes for this slot
8683
- for (const _ref37 of Object.entries(mergedProps)) {
8684
- var _ref38 = _slicedToArray(_ref37, 2);
8685
- const variantKey = _ref38[0];
8686
- const variantValue = _ref38[1];
9128
+ for (const _ref39 of Object.entries(mergedProps)) {
9129
+ var _ref40 = _slicedToArray(_ref39, 2);
9130
+ const variantKey = _ref40[0];
9131
+ const variantValue = _ref40[1];
8687
9132
  if (variantValue === undefined || variantValue === null) continue;
8688
9133
  const normalizedValue = variantValue === true ? "true" : variantValue === false ? "false" : variantValue;
8689
9134
  const key = "".concat(variantKey, ":").concat(normalizedValue, ":").concat(slotName);
@@ -8694,18 +9139,18 @@ function createSlots(config) {
8694
9139
  }
8695
9140
 
8696
9141
  // Check compound variants for this slot
8697
- for (const _ref39 of variantSlotStyles.entries()) {
8698
- var _ref40 = _slicedToArray(_ref39, 2);
8699
- const key = _ref40[0];
8700
- const data = _ref40[1];
9142
+ for (const _ref41 of variantSlotStyles.entries()) {
9143
+ var _ref42 = _slicedToArray(_ref41, 2);
9144
+ const key = _ref42[0];
9145
+ const data = _ref42[1];
8701
9146
  if (!key.startsWith("__compound__:") || !key.endsWith(":".concat(slotName))) continue;
8702
9147
  const conditions = data.conditions,
8703
9148
  className = data.className;
8704
9149
  let matches = true;
8705
- for (const _ref41 of Object.entries(conditions)) {
8706
- var _ref42 = _slicedToArray(_ref41, 2);
8707
- const condKey = _ref42[0];
8708
- const condValue = _ref42[1];
9150
+ for (const _ref43 of Object.entries(conditions)) {
9151
+ var _ref44 = _slicedToArray(_ref43, 2);
9152
+ const condKey = _ref44[0];
9153
+ const condValue = _ref44[1];
8709
9154
  const propValue = mergedProps[condKey];
8710
9155
  const normalizedPropValue = propValue === true ? "true" : propValue === false ? "false" : propValue;
8711
9156
  const normalizedCondValue = condValue === true ? "true" : condValue === false ? "false" : condValue;
@@ -8733,10 +9178,10 @@ function createSlots(config) {
8733
9178
  let slotOverrides = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
8734
9179
  const baseSlots = typeof props === "object" && !Array.isArray(props) && !("$$typeof" in props) ? slotsGenerator(props) : slotsGenerator();
8735
9180
  const result = {};
8736
- for (const _ref43 of Object.entries(baseSlots)) {
8737
- var _ref44 = _slicedToArray(_ref43, 2);
8738
- const slotName = _ref44[0];
8739
- const slotClasses = _ref44[1];
9181
+ for (const _ref45 of Object.entries(baseSlots)) {
9182
+ var _ref46 = _slicedToArray(_ref45, 2);
9183
+ const slotName = _ref46[0];
9184
+ const slotClasses = _ref46[1];
8740
9185
  result[slotName] = cx(slotClasses, slotOverrides[slotName]);
8741
9186
  }
8742
9187
  return result;
@@ -8906,17 +9351,17 @@ twsxClassName.setTheme = function (name) {
8906
9351
  // Apply theme tokens to CSS variables
8907
9352
  if (IS_BROWSER) {
8908
9353
  const root = document.documentElement;
8909
- for (const _ref45 of Object.entries(themes[name])) {
8910
- var _ref46 = _slicedToArray(_ref45, 2);
8911
- const key = _ref46[0];
8912
- const value = _ref46[1];
9354
+ for (const _ref47 of Object.entries(themes[name])) {
9355
+ var _ref48 = _slicedToArray(_ref47, 2);
9356
+ const key = _ref48[0];
9357
+ const value = _ref48[1];
8913
9358
  if (typeof value === "string") {
8914
9359
  root.style.setProperty("--".concat(key), value);
8915
9360
  } else if (typeof value === "object") {
8916
- for (const _ref47 of Object.entries(value)) {
8917
- var _ref48 = _slicedToArray(_ref47, 2);
8918
- const subKey = _ref48[0];
8919
- const subValue = _ref48[1];
9361
+ for (const _ref49 of Object.entries(value)) {
9362
+ var _ref50 = _slicedToArray(_ref49, 2);
9363
+ const subKey = _ref50[0];
9364
+ const subValue = _ref50[1];
8920
9365
  root.style.setProperty("--".concat(key, "-").concat(subKey), subValue);
8921
9366
  }
8922
9367
  }