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