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