@kbach/react 0.5.38 → 0.5.40

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.
@@ -673,6 +673,7 @@ function resolveSizing(value, spacing, isArbitrary) {
673
673
  if (raw !== void 0) return raw;
674
674
  if (/^\d+\/\d+$/.test(value)) {
675
675
  const [num, den] = value.split("/").map(Number);
676
+ if (!den) return null;
676
677
  return `${(num / den * 100).toFixed(6)}%`;
677
678
  }
678
679
  return null;
@@ -2187,10 +2188,10 @@ function resolveUtility(parsed, theme) {
2187
2188
  if (!parsed.value) {
2188
2189
  if (parsed.utility in PLUGIN_STANDALONE) return PLUGIN_STANDALONE[parsed.utility] ?? null;
2189
2190
  if (parsed.utility === "grd" || parsed.utility === "grid") {
2190
- return { display: "grid" };
2191
+ return getEffectiveIsWeb() ? { display: "grid" } : null;
2191
2192
  }
2192
2193
  if (parsed.utility === "inline-grid") {
2193
- return { display: "inline-grid" };
2194
+ return getEffectiveIsWeb() ? { display: "inline-grid" } : null;
2194
2195
  }
2195
2196
  if (parsed.utility in getStandalone()) return getStandalone()[parsed.utility] ?? null;
2196
2197
  }
@@ -2203,685 +2204,129 @@ var PLUGIN_RESOLVERS = {};
2203
2204
  function clearPluginUtilities() {
2204
2205
  for (const key of Object.keys(PLUGIN_STANDALONE)) delete PLUGIN_STANDALONE[key];
2205
2206
  for (const key of Object.keys(PLUGIN_RESOLVERS)) delete PLUGIN_RESOLVERS[key];
2207
+ _sortedPrefixes = null;
2208
+ _standaloneNames = null;
2206
2209
  }
2207
2210
  function getPluginStandaloneMap() {
2208
2211
  return PLUGIN_STANDALONE;
2209
2212
  }
2213
+ var _sortedPrefixes = null;
2214
+ var _standaloneNames = null;
2215
+ function getBuiltinUtilityPrefixes() {
2216
+ if (!_sortedPrefixes) {
2217
+ const all = [.../* @__PURE__ */ new Set([...Object.keys(RESOLVERS), ...Object.keys(PLUGIN_RESOLVERS)])];
2218
+ _sortedPrefixes = all.sort((a, b) => b.length - a.length);
2219
+ }
2220
+ return _sortedPrefixes;
2221
+ }
2222
+ function getBuiltinStandaloneNames() {
2223
+ if (!_standaloneNames) {
2224
+ _standaloneNames = /* @__PURE__ */ new Set([...Object.keys(getStandalone()), ...Object.keys(PLUGIN_STANDALONE)]);
2225
+ }
2226
+ return _standaloneNames;
2227
+ }
2210
2228
 
2211
- // src/core/parser.ts
2212
- var PLUGIN_MODIFIERS = /* @__PURE__ */ new Set();
2213
- function registerModifier(name) {
2214
- PLUGIN_MODIFIERS.add(name);
2229
+ // src/core/registry.ts
2230
+ var BUILTIN_MODIFIERS = {
2231
+ // ── Mode ─────────────────────────────────────────────────────────────────
2232
+ dark: { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
2233
+ "not-light": { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
2234
+ light: { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
2235
+ "not-dark": { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
2236
+ // ── Interactive — JS state + CSS pseudo ───────────────────────────────────
2237
+ hover: { pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
2238
+ "not-hover": { pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
2239
+ focus: { pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
2240
+ "not-focus": { pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
2241
+ active: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
2242
+ "not-active": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
2243
+ pressed: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
2244
+ "not-pressed": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
2245
+ disabled: { pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
2246
+ "not-disabled": { pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
2247
+ checked: { pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
2248
+ "not-checked": { pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
2249
+ visited: { pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
2250
+ "not-visited": { pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
2251
+ placeholder: { pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
2252
+ // ── CSS-only pseudo-classes (structural) ──────────────────────────────────
2253
+ first: { pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
2254
+ last: { pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
2255
+ odd: { pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
2256
+ even: { pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
2257
+ only: { pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
2258
+ "focus-within": { pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
2259
+ "focus-visible": { pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
2260
+ // ── CSS-only pseudo-elements ───────────────────────────────────────────────
2261
+ before: { pseudo: "::before", jsBehavior: "css-only" },
2262
+ after: { pseudo: "::after", jsBehavior: "css-only" },
2263
+ selection: { pseudo: "::selection", jsBehavior: "css-only" },
2264
+ "first-letter": { pseudo: "::first-letter", jsBehavior: "css-only" },
2265
+ "first-line": { pseudo: "::first-line", jsBehavior: "css-only" },
2266
+ marker: { pseudo: "::marker", jsBehavior: "css-only" },
2267
+ // ── Group / peer ancestor selectors (CSS-only) ─────────────────────────────
2268
+ "group-hover": { ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
2269
+ "group-focus": { ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
2270
+ "peer-hover": { ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
2271
+ "peer-focus": { ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
2272
+ // ── Responsive — both CSS (@media min-width) and JS (breakpoints set) ──────
2273
+ sm: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
2274
+ md: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
2275
+ lg: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
2276
+ xl: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
2277
+ "2xl": { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
2278
+ // ── Print media (CSS-only) ─────────────────────────────────────────────────
2279
+ print: { mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
2280
+ // ── Orientation / accessibility media (CSS-only) ───────────────────────────
2281
+ landscape: { mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
2282
+ portrait: { mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
2283
+ "motion-reduce": { mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
2284
+ "motion-safe": { mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
2285
+ "contrast-more": { mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
2286
+ "contrast-less": { mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
2287
+ // ── Directionality (CSS-only) ──────────────────────────────────────────────
2288
+ rtl: { dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
2289
+ ltr: { dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
2290
+ };
2291
+ var _pluginModifiers = {};
2292
+ var _allNames = null;
2293
+ var _interactiveNames = null;
2294
+ var _modeNames = null;
2295
+ var _responsiveNames = null;
2296
+ function _invalidate() {
2297
+ _allNames = null;
2298
+ _interactiveNames = null;
2299
+ _modeNames = null;
2300
+ _responsiveNames = null;
2301
+ }
2302
+ function registerModifier(name, def) {
2303
+ _pluginModifiers[name] = def;
2304
+ _invalidate();
2215
2305
  }
2216
2306
  function clearPluginModifiers() {
2217
- PLUGIN_MODIFIERS.clear();
2307
+ for (const k of Object.keys(_pluginModifiers)) delete _pluginModifiers[k];
2308
+ _invalidate();
2218
2309
  }
2219
- var MODIFIERS = /* @__PURE__ */ new Set([
2220
- // Theme
2221
- "dark",
2222
- "light",
2223
- "not-dark",
2224
- "not-light",
2225
- // Interaction
2226
- "hover",
2227
- "focus",
2228
- "active",
2229
- "visited",
2230
- "disabled",
2231
- "checked",
2232
- "pressed",
2233
- "placeholder",
2234
- "focus-within",
2235
- "focus-visible",
2236
- // Negated interaction
2237
- "not-hover",
2238
- "not-focus",
2239
- "not-active",
2240
- "not-visited",
2241
- "not-disabled",
2242
- "not-checked",
2243
- "not-pressed",
2244
- // Structural
2245
- "first",
2246
- "last",
2247
- "odd",
2248
- "even",
2249
- "only",
2250
- // Group / peer
2251
- "group-hover",
2252
- "group-focus",
2253
- "peer-hover",
2254
- "peer-focus",
2255
- // Responsive (handled separately but accepted)
2256
- "sm",
2257
- "md",
2258
- "lg",
2259
- "xl",
2260
- "2xl",
2261
- // Pseudo-elements (CSS-injection only; matchesMods returns false for these)
2262
- "before",
2263
- "after",
2264
- "selection",
2265
- "first-letter",
2266
- "first-line",
2267
- "marker",
2268
- // Print media modifier
2269
- "print",
2270
- // Orientation media modifiers (CSS-injection only)
2271
- "landscape",
2272
- "portrait",
2273
- // Accessibility media modifiers (CSS-injection only)
2274
- "motion-reduce",
2275
- "motion-safe",
2276
- "contrast-more",
2277
- "contrast-less",
2278
- // Directionality modifiers (CSS-injection only)
2279
- "rtl",
2280
- "ltr"
2281
- ]);
2282
- var UTILITY_PREFIXES = [
2283
- // Multi-word flex
2284
- "flex-row-reverse",
2285
- "flex-col-reverse",
2286
- "flex-row",
2287
- "flex-col",
2288
- "flex-wrap-reverse",
2289
- "flex-wrap",
2290
- "flex-nowrap",
2291
- "flex-shrink-0",
2292
- "flex-shrink",
2293
- "flex-grow-0",
2294
- "flex-grow",
2295
- "items-start",
2296
- "items-end",
2297
- "items-center",
2298
- "items-baseline",
2299
- "items-stretch",
2300
- "justify-start",
2301
- "justify-end",
2302
- "justify-center",
2303
- "justify-between",
2304
- "justify-around",
2305
- "justify-evenly",
2306
- "content-start",
2307
- "content-end",
2308
- "content-center",
2309
- "content-between",
2310
- "content-around",
2311
- "content-evenly",
2312
- "self-start",
2313
- "self-end",
2314
- "self-center",
2315
- "self-auto",
2316
- "self-stretch",
2317
- "text-left",
2318
- "text-right",
2319
- "text-center",
2320
- "text-justify",
2321
- "font-thin",
2322
- "font-extralight",
2323
- "font-light",
2324
- "font-normal",
2325
- "font-medium",
2326
- "font-semibold",
2327
- "font-bold",
2328
- "font-extrabold",
2329
- "font-black",
2330
- "overflow-hidden",
2331
- "overflow-visible",
2332
- "overflow-scroll",
2333
- "overflow-auto",
2334
- "overflow-x-hidden",
2335
- "overflow-x-scroll",
2336
- "overflow-x-auto",
2337
- "overflow-y-hidden",
2338
- "overflow-y-scroll",
2339
- "overflow-y-auto",
2340
- "object-contain",
2341
- "object-cover",
2342
- "object-fill",
2343
- "object-none",
2344
- "object-scale-down",
2345
- "border-solid",
2346
- "border-dashed",
2347
- "border-dotted",
2348
- "border-none",
2349
- "border-t",
2350
- "border-r",
2351
- "border-b",
2352
- "border-l",
2353
- "rounded-tl",
2354
- "rounded-tr",
2355
- "rounded-bl",
2356
- "rounded-br",
2357
- "rounded-t",
2358
- "rounded-r",
2359
- "rounded-b",
2360
- "rounded-l",
2361
- "list-none",
2362
- "list-disc",
2363
- "list-decimal",
2364
- "cursor-auto",
2365
- "cursor-default",
2366
- "cursor-pointer",
2367
- "cursor-wait",
2368
- "cursor-text",
2369
- "cursor-move",
2370
- "cursor-not-allowed",
2371
- "select-none",
2372
- "select-text",
2373
- "select-all",
2374
- "select-auto",
2375
- "pointer-events-none",
2376
- "pointer-events-auto",
2377
- "whitespace-normal",
2378
- "whitespace-nowrap",
2379
- "whitespace-pre-wrap",
2380
- "whitespace-pre-line",
2381
- "whitespace-pre",
2382
- "break-normal",
2383
- "break-words",
2384
- "break-all",
2385
- "break-keep",
2386
- "bg-clip-border",
2387
- "bg-clip-padding",
2388
- "bg-clip-content",
2389
- "bg-clip-text",
2390
- "bg-gradient-to",
2391
- "resize-none",
2392
- "resize-y",
2393
- "resize-x",
2394
- "box-border",
2395
- "box-content",
2396
- "gap-x",
2397
- "gap-y",
2398
- "inset-x",
2399
- "inset-y",
2400
- "divide-x",
2401
- "divide-y",
2402
- "space-x",
2403
- "space-y",
2404
- "translate-x",
2405
- "translate-y",
2406
- "scale-x",
2407
- "scale-y",
2408
- "skew-x",
2409
- "skew-y",
2410
- // Transform origin (single prefix, value carries direction)
2411
- "origin",
2412
- "min-w",
2413
- "min-h",
2414
- "max-w",
2415
- "max-h",
2416
- "ring-offset",
2417
- "bg-opacity",
2418
- "text-opacity",
2419
- "border-opacity",
2420
- // Grid placement
2421
- "col-span",
2422
- "col-start",
2423
- "col-end",
2424
- "row-span",
2425
- "row-start",
2426
- "row-end",
2427
- "grid-cols",
2428
- "grid-rows",
2429
- "grid-flow",
2430
- "auto-cols",
2431
- "auto-rows",
2432
- // Grid alignment
2433
- "place-items",
2434
- "place-content",
2435
- "place-self",
2436
- "justify-items",
2437
- "justify-self",
2438
- // Backdrop filters (longer than 'backdrop' alone)
2439
- "backdrop-blur",
2440
- "backdrop-brightness",
2441
- "backdrop-contrast",
2442
- "backdrop-grayscale",
2443
- "backdrop-hue-rotate",
2444
- "backdrop-invert",
2445
- "backdrop-opacity",
2446
- "backdrop-saturate",
2447
- "backdrop-sepia",
2448
- "backdrop-filter",
2449
- // Filters
2450
- "drop-shadow",
2451
- "hue-rotate",
2452
- "text-shadow",
2453
- "underline-offset",
2454
- "outline-offset",
2455
- "will-change",
2456
- "mix-blend",
2457
- "bg-blend",
2458
- "decoration",
2459
- "perspective",
2460
- "tint",
2461
- "animate",
2462
- // Single-word prefixes last
2463
- "appearance-none",
2464
- "outline-none",
2465
- "outline",
2466
- "inline-flex",
2467
- "inline-block",
2468
- "inline-grid",
2469
- "italic",
2470
- "non-italic",
2471
- "underline",
2472
- "overline",
2473
- "line-through",
2474
- "no-underline",
2475
- "uppercase",
2476
- "lowercase",
2477
- "capitalize",
2478
- "normal-case",
2479
- "antialiased",
2480
- "subpixel-antialiased",
2481
- "overflow-ellipsis",
2482
- "truncate",
2483
- "sr-only",
2484
- "not-sr-only",
2485
- "relative",
2486
- "absolute",
2487
- "fixed",
2488
- "sticky",
2489
- "static",
2490
- "visible",
2491
- "invisible",
2492
- "hidden",
2493
- "contents",
2494
- "flow-root",
2495
- "block",
2496
- "inline",
2497
- "flex",
2498
- "grid",
2499
- "resize",
2500
- "appearance",
2501
- "border",
2502
- "rounded",
2503
- "shadow",
2504
- "size",
2505
- "opacity",
2506
- "leading",
2507
- "tracking",
2508
- "line-clamp",
2509
- "basis",
2510
- "grow",
2511
- "shrink",
2512
- "order",
2513
- "delay",
2514
- "duration",
2515
- "scale",
2516
- "rotate",
2517
- "aspect",
2518
- "columns",
2519
- "ring",
2520
- "gap",
2521
- "inset",
2522
- "filter",
2523
- "transform",
2524
- "blur",
2525
- "brightness",
2526
- "contrast",
2527
- "grayscale",
2528
- "invert",
2529
- "saturate",
2530
- "sepia",
2531
- "bg",
2532
- "text",
2533
- "font",
2534
- "caret",
2535
- "accent",
2536
- "from",
2537
- "via",
2538
- "to",
2539
- "divide",
2540
- "space",
2541
- "transition",
2542
- "px",
2543
- "py",
2544
- "pt",
2545
- "pr",
2546
- "pb",
2547
- "pl",
2548
- "p",
2549
- "mx",
2550
- "my",
2551
- "mt",
2552
- "mr",
2553
- "mb",
2554
- "ml",
2555
- "m",
2556
- "w",
2557
- "h",
2558
- "top",
2559
- "right",
2560
- "bottom",
2561
- "left",
2562
- "z",
2563
- "col",
2564
- "row"
2565
- ];
2566
- var SORTED_PREFIXES = [...new Set(UTILITY_PREFIXES)].sort((a, b) => b.length - a.length);
2567
- var STANDALONE_UTILITIES = /* @__PURE__ */ new Set([
2568
- // Display
2569
- "flex",
2570
- "block",
2571
- "inline-block",
2572
- "inline",
2573
- "grid",
2574
- "inline-flex",
2575
- "inline-grid",
2576
- "grd",
2577
- "hidden",
2578
- "contents",
2579
- "flow-root",
2580
- // Position
2581
- "relative",
2582
- "absolute",
2583
- "fixed",
2584
- "sticky",
2585
- "static",
2586
- // Visibility
2587
- "visible",
2588
- "invisible",
2589
- // Typography
2590
- "uppercase",
2591
- "lowercase",
2592
- "capitalize",
2593
- "normal-case",
2594
- "italic",
2595
- "non-italic",
2596
- "underline",
2597
- "overline",
2598
- "line-through",
2599
- "no-underline",
2600
- "truncate",
2601
- "antialiased",
2602
- "sr-only",
2603
- "not-sr-only",
2604
- // Font variant numeric
2605
- "normal-nums",
2606
- "ordinal",
2607
- "slashed-zero",
2608
- "lining-nums",
2609
- "oldstyle-nums",
2610
- "proportional-nums",
2611
- "tabular-nums",
2612
- "diagonal-fractions",
2613
- "stacked-fractions",
2614
- // Flexbox
2615
- "flex-row",
2616
- "flex-col",
2617
- "flex-row-reverse",
2618
- "flex-col-reverse",
2619
- "flex-wrap",
2620
- "flex-wrap-reverse",
2621
- "flex-nowrap",
2622
- "flex-shrink",
2623
- "flex-shrink-0",
2624
- "flex-grow",
2625
- "flex-grow-0",
2626
- "items-start",
2627
- "items-end",
2628
- "items-center",
2629
- "items-baseline",
2630
- "items-stretch",
2631
- "justify-start",
2632
- "justify-end",
2633
- "justify-center",
2634
- "justify-between",
2635
- "justify-around",
2636
- "justify-evenly",
2637
- "content-start",
2638
- "content-end",
2639
- "content-center",
2640
- "content-between",
2641
- "content-around",
2642
- "content-evenly",
2643
- "content-stretch",
2644
- "self-start",
2645
- "self-end",
2646
- "self-center",
2647
- "self-auto",
2648
- "self-stretch",
2649
- "self-baseline",
2650
- // Text align
2651
- "text-left",
2652
- "text-right",
2653
- "text-center",
2654
- "text-justify",
2655
- // Font weight shortcuts
2656
- "font-thin",
2657
- "font-extralight",
2658
- "font-light",
2659
- "font-normal",
2660
- "font-medium",
2661
- "font-semibold",
2662
- "font-bold",
2663
- "font-extrabold",
2664
- "font-black",
2665
- // Overflow
2666
- "overflow-hidden",
2667
- "overflow-visible",
2668
- "overflow-scroll",
2669
- "overflow-auto",
2670
- "overflow-x-hidden",
2671
- "overflow-x-scroll",
2672
- "overflow-x-auto",
2673
- "overflow-y-hidden",
2674
- "overflow-y-scroll",
2675
- "overflow-y-auto",
2676
- // Object fit
2677
- "object-contain",
2678
- "object-cover",
2679
- "object-fill",
2680
- "object-none",
2681
- "object-scale-down",
2682
- // Object position
2683
- "object-center",
2684
- "object-top",
2685
- "object-bottom",
2686
- "object-left",
2687
- "object-right",
2688
- "object-left-top",
2689
- "object-left-bottom",
2690
- "object-right-top",
2691
- "object-right-bottom",
2692
- // Border
2693
- "border-solid",
2694
- "border-dashed",
2695
- "border-dotted",
2696
- "border-none",
2697
- "border-t",
2698
- "border-r",
2699
- "border-b",
2700
- "border-l",
2701
- "border-collapse",
2702
- "border-separate",
2703
- // Lists
2704
- "list-none",
2705
- "list-disc",
2706
- "list-decimal",
2707
- "list-inside",
2708
- "list-outside",
2709
- // Cursor / select
2710
- "cursor-auto",
2711
- "cursor-default",
2712
- "cursor-pointer",
2713
- "cursor-wait",
2714
- "cursor-text",
2715
- "cursor-move",
2716
- "cursor-not-allowed",
2717
- "select-none",
2718
- "select-text",
2719
- "select-all",
2720
- "select-auto",
2721
- "pointer-events-none",
2722
- "pointer-events-auto",
2723
- // Whitespace / word break
2724
- "whitespace-normal",
2725
- "whitespace-nowrap",
2726
- "whitespace-pre",
2727
- "whitespace-pre-wrap",
2728
- "whitespace-pre-line",
2729
- "break-normal",
2730
- "break-words",
2731
- "break-all",
2732
- // Background clip
2733
- "bg-clip-border",
2734
- "bg-clip-padding",
2735
- "bg-clip-content",
2736
- "bg-clip-text",
2737
- // Background size
2738
- "bg-auto",
2739
- "bg-cover",
2740
- "bg-contain",
2741
- // Background position
2742
- "bg-center",
2743
- "bg-top",
2744
- "bg-bottom",
2745
- "bg-left",
2746
- "bg-right",
2747
- "bg-left-top",
2748
- "bg-left-bottom",
2749
- "bg-right-top",
2750
- "bg-right-bottom",
2751
- // Background repeat
2752
- "bg-repeat",
2753
- "bg-no-repeat",
2754
- "bg-repeat-x",
2755
- "bg-repeat-y",
2756
- "bg-repeat-round",
2757
- "bg-repeat-space",
2758
- // Background attachment
2759
- "bg-fixed",
2760
- "bg-local",
2761
- "bg-scroll",
2762
- // Background image
2763
- "bg-none",
2764
- // Box sizing
2765
- "box-border",
2766
- "box-content",
2767
- // Resize
2768
- "resize",
2769
- "resize-none",
2770
- "resize-y",
2771
- "resize-x",
2772
- // Outline
2773
- "appearance-none",
2774
- "outline-none",
2775
- "outline",
2776
- // Table
2777
- "table",
2778
- "table-auto",
2779
- "table-fixed",
2780
- "caption-top",
2781
- "caption-bottom",
2782
- // CSS filters (standalone = default/full effect)
2783
- "grayscale",
2784
- "invert",
2785
- "sepia",
2786
- // Isolation
2787
- "isolate",
2788
- "isolation-auto",
2789
- // Backface visibility (both platforms)
2790
- "backface-visible",
2791
- "backface-hidden",
2792
- // Divide none
2793
- "divide-none",
2794
- // Group / peer markers (no-op style; needed so isKnownUtility recognises them)
2795
- "group",
2796
- "peer",
2797
- // Text-wrap (web-only)
2798
- "text-wrap",
2799
- "text-nowrap",
2800
- "text-balance",
2801
- "text-pretty",
2802
- // Screen sizing
2803
- "w-screen",
2804
- "min-h-screen",
2805
- "max-h-screen",
2806
- "min-w-screen",
2807
- "max-w-screen",
2808
- // max-w named container sizes (Tailwind compat)
2809
- "max-w-none",
2810
- "max-w-xs",
2811
- "max-w-sm",
2812
- "max-w-md",
2813
- "max-w-lg",
2814
- "max-w-xl",
2815
- "max-w-2xl",
2816
- "max-w-3xl",
2817
- "max-w-4xl",
2818
- "max-w-5xl",
2819
- "max-w-6xl",
2820
- "max-w-7xl",
2821
- "max-w-prose",
2822
- // Extended cursors (web-only)
2823
- "cursor-grab",
2824
- "cursor-grabbing",
2825
- "cursor-zoom-in",
2826
- "cursor-zoom-out",
2827
- "cursor-crosshair",
2828
- "cursor-help",
2829
- "cursor-none",
2830
- // Overflow clip (web-only)
2831
- "overflow-clip",
2832
- "overflow-x-clip",
2833
- "overflow-y-clip",
2834
- // Scroll behavior (web-only)
2835
- "scroll-smooth",
2836
- "scroll-auto",
2837
- // Float & clear (web-only)
2838
- "float-left",
2839
- "float-right",
2840
- "float-start",
2841
- "float-end",
2842
- "float-none",
2843
- "clear-left",
2844
- "clear-right",
2845
- "clear-both",
2846
- "clear-start",
2847
- "clear-end",
2848
- "clear-none",
2849
- // Vertical align (web-only)
2850
- "align-baseline",
2851
- "align-top",
2852
- "align-middle",
2853
- "align-bottom",
2854
- "align-text-top",
2855
- "align-text-bottom",
2856
- "align-sub",
2857
- "align-super",
2858
- // Touch action (web-only)
2859
- "touch-auto",
2860
- "touch-none",
2861
- "touch-pan-x",
2862
- "touch-pan-y",
2863
- "touch-pan-left",
2864
- "touch-pan-right",
2865
- "touch-pan-up",
2866
- "touch-pan-down",
2867
- "touch-pinch-zoom",
2868
- "touch-manipulation"
2869
- ]);
2310
+ function getModifier(name) {
2311
+ return BUILTIN_MODIFIERS[name] ?? _pluginModifiers[name];
2312
+ }
2313
+ function isKnownModifier(name) {
2314
+ return name in BUILTIN_MODIFIERS || name in _pluginModifiers;
2315
+ }
2316
+
2317
+ // src/core/parser.ts
2870
2318
  function parseClass(className) {
2871
2319
  const trimmed = className.trim();
2872
2320
  if (!trimmed) return null;
2873
2321
  const modifiers = [];
2874
2322
  let remaining = trimmed;
2875
- for (let i = 0; i < 3; i++) {
2323
+ while (true) {
2876
2324
  const colonIdx = findOuterColon(remaining);
2877
2325
  if (colonIdx === -1) break;
2878
2326
  const candidate = remaining.slice(0, colonIdx);
2879
- if (MODIFIERS.has(candidate) || PLUGIN_MODIFIERS.has(candidate)) {
2880
- modifiers.push(candidate);
2881
- remaining = remaining.slice(colonIdx + 1);
2882
- } else {
2883
- break;
2884
- }
2327
+ if (!isKnownModifier(candidate)) break;
2328
+ modifiers.push(candidate);
2329
+ remaining = remaining.slice(colonIdx + 1);
2885
2330
  }
2886
2331
  let important = false;
2887
2332
  if (remaining.startsWith("!") && remaining.length > 1) {
@@ -2899,10 +2344,10 @@ function parseClass(className) {
2899
2344
  const value = remaining.slice(bracketStart + 2, -1).replace(/_/g, " ");
2900
2345
  return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
2901
2346
  }
2902
- if (STANDALONE_UTILITIES.has(remaining)) {
2347
+ if (getBuiltinStandaloneNames().has(remaining)) {
2903
2348
  return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
2904
2349
  }
2905
- for (const prefix of SORTED_PREFIXES) {
2350
+ for (const prefix of getBuiltinUtilityPrefixes()) {
2906
2351
  if (remaining === prefix) {
2907
2352
  return { original: trimmed, modifiers, negative, important, utility: prefix, value: "", isArbitrary: false };
2908
2353
  }
@@ -2997,7 +2442,11 @@ var LRUCache = class {
2997
2442
  return this;
2998
2443
  }
2999
2444
  has(key) {
3000
- return this.cache.has(key);
2445
+ if (!this.cache.has(key)) return false;
2446
+ const value = this.cache.get(key);
2447
+ this.cache.delete(key);
2448
+ this.cache.set(key, value);
2449
+ return true;
3001
2450
  }
3002
2451
  delete(key) {
3003
2452
  return this.cache.delete(key);
@@ -3011,12 +2460,12 @@ var LRUCache = class {
3011
2460
  };
3012
2461
 
3013
2462
  // src/core/resolver.ts
3014
- var styleCache = new LRUCache(1e4);
3015
2463
  var FONT_KEY = "__kbach_default_font__";
3016
2464
  function setDefaultFontFamily(font) {
3017
2465
  globalThis[FONT_KEY] = font;
3018
2466
  }
3019
2467
  var _styleEl = null;
2468
+ var _injectedRules = new LRUCache(5e4);
3020
2469
  function getStyleEl() {
3021
2470
  if (_styleEl) return _styleEl;
3022
2471
  _styleEl = document.createElement("style");
@@ -3042,156 +2491,20 @@ function injectGlobalStyles(theme) {
3042
2491
  }
3043
2492
  getGlobalStyleEl().textContent = rules.join("\n");
3044
2493
  }
3045
- var MODIFIER_TO_PSEUDO = {
3046
- hover: ":hover",
3047
- focus: ":focus",
3048
- "focus-within": ":focus-within",
3049
- "focus-visible": ":focus-visible",
3050
- active: ":active",
3051
- pressed: ":active",
3052
- disabled: ":disabled",
3053
- checked: ":checked",
3054
- visited: ":visited",
3055
- placeholder: "::placeholder",
3056
- first: ":first-child",
3057
- last: ":last-child",
3058
- odd: ":nth-child(odd)",
3059
- even: ":nth-child(even)",
3060
- only: ":only-child",
3061
- "not-hover": ":not(:hover)",
3062
- "not-focus": ":not(:focus)",
3063
- "not-active": ":not(:active)",
3064
- "not-pressed": ":not(:active)",
3065
- "not-disabled": ":not(:disabled)",
3066
- "not-checked": ":not(:checked)",
3067
- "not-visited": ":not(:visited)",
3068
- // Pseudo-elements (CSS-injection only; never applied as inline styles)
3069
- before: "::before",
3070
- after: "::after",
3071
- selection: "::selection",
3072
- "first-letter": "::first-letter",
3073
- "first-line": "::first-line",
3074
- marker: "::marker"
3075
- };
3076
- var GROUP_PEER_PREFIX = {
3077
- "group-hover": ".group:hover",
3078
- "group-focus": ".group:focus",
3079
- "peer-hover": ".peer:hover ~",
3080
- "peer-focus": ".peer:focus ~"
3081
- };
3082
- var MODE_MODS = /* @__PURE__ */ new Set(["dark", "light", "not-dark", "not-light"]);
3083
- var RESPONSIVE_MODS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
3084
- var PRINT_MODS = /* @__PURE__ */ new Set(["print"]);
3085
- var MEDIA_MODS = {
3086
- landscape: "(orientation: landscape)",
3087
- portrait: "(orientation: portrait)",
3088
- "motion-reduce": "(prefers-reduced-motion: reduce)",
3089
- "motion-safe": "(prefers-reduced-motion: no-preference)",
3090
- "contrast-more": "(prefers-contrast: more)",
3091
- "contrast-less": "(prefers-contrast: less)"
3092
- };
3093
- var DIR_MODS = {
3094
- rtl: '[dir="rtl"]',
3095
- ltr: '[dir="ltr"]'
3096
- };
3097
2494
  function buildDivideDecls(styles) {
3098
2495
  const parts = [];
3099
2496
  if ("__divideX" in styles) {
3100
2497
  const w = Number(styles.__divideX);
3101
- parts.push(`border-left-width: ${w}px`);
3102
- parts.push("border-right-width: 0px");
2498
+ parts.push(`border-left-width: ${w}px`, "border-right-width: 0px");
3103
2499
  }
3104
2500
  if ("__divideY" in styles) {
3105
2501
  const w = Number(styles.__divideY);
3106
- parts.push(`border-top-width: ${w}px`);
3107
- parts.push("border-bottom-width: 0px");
2502
+ parts.push(`border-top-width: ${w}px`, "border-bottom-width: 0px");
3108
2503
  }
3109
2504
  if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}`);
3110
2505
  if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}`);
3111
2506
  return parts.join("; ");
3112
2507
  }
3113
- function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
3114
- const rules = [];
3115
- if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
3116
- rules.push(styles.__keyframe);
3117
- }
3118
- const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
3119
- const escaped = escapeCSSSelector(cls);
3120
- const childSuffix = isDivide ? " > * + *" : "";
3121
- if (bucketKey === "base") {
3122
- const baseCssDecls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
3123
- if (!baseCssDecls) return rules;
3124
- rules.push(`.${escaped}${childSuffix} { ${baseCssDecls} }`);
3125
- return rules;
3126
- }
3127
- const mods = bucketKey.split(":");
3128
- const responsiveMods = mods.filter((m) => RESPONSIVE_MODS.has(m));
3129
- const nonResponsiveMods = mods.filter((m) => !RESPONSIVE_MODS.has(m));
3130
- const hasDark = nonResponsiveMods.includes("dark") || nonResponsiveMods.includes("not-light");
3131
- const hasLight = nonResponsiveMods.includes("light") || nonResponsiveMods.includes("not-dark");
3132
- const hasPrint = nonResponsiveMods.includes("print");
3133
- const mediaMods = nonResponsiveMods.filter((m) => m in MEDIA_MODS);
3134
- const dirMods = nonResponsiveMods.filter((m) => m in DIR_MODS);
3135
- const ancestorMods = nonResponsiveMods.filter((m) => m in GROUP_PEER_PREFIX);
3136
- const pseudoMods = nonResponsiveMods.filter(
3137
- (m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX) && !PRINT_MODS.has(m) && !(m in MEDIA_MODS) && !(m in DIR_MODS)
3138
- );
3139
- const pseudoSuffix = pseudoMods.map((p) => MODIFIER_TO_PSEUDO[p] ?? `:${p}`).join("");
3140
- const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
3141
- const ancestorPrefix = ancestorMods.length ? ancestorMods.map((m) => GROUP_PEER_PREFIX[m]).join(" ") + " " : "";
3142
- const dirPrefix = dirMods.length ? dirMods.map((m) => DIR_MODS[m]).join(" ") + " " : "";
3143
- const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
3144
- const CSS_ONLY_PSEUDOS = /* @__PURE__ */ new Set([
3145
- "first",
3146
- "last",
3147
- "odd",
3148
- "even",
3149
- "only",
3150
- "focus-within",
3151
- "focus-visible"
3152
- ]);
3153
- const needsImportant = important || hasPrint || mediaMods.length > 0 || dirMods.length > 0 || ancestorMods.length > 0 || pseudoMods.some((m) => CSS_ONLY_PSEUDOS.has(m));
3154
- const cssDecls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
3155
- if (!cssDecls) return rules;
3156
- let rule;
3157
- if (hasDark) {
3158
- if (darkMode === "media") {
3159
- rule = `@media (prefers-color-scheme: dark) { ${selector} { ${cssDecls} } }`;
3160
- } else if (darkMode === "class") {
3161
- rule = `.dark ${selector} { ${cssDecls} }`;
3162
- } else {
3163
- rule = `[data-theme="dark"] ${selector} { ${cssDecls} }`;
3164
- }
3165
- } else if (hasLight) {
3166
- if (darkMode === "media") {
3167
- rule = `@media (prefers-color-scheme: light) { ${selector} { ${cssDecls} } }`;
3168
- } else if (darkMode === "class") {
3169
- rule = `:not(.dark) ${selector} { ${cssDecls} }`;
3170
- } else {
3171
- rule = `[data-theme="light"] ${selector} { ${cssDecls} }`;
3172
- }
3173
- } else {
3174
- rule = `${selector} { ${cssDecls} }`;
3175
- }
3176
- if (hasPrint) rule = `@media print { ${rule} }`;
3177
- for (const m of mediaMods) rule = `@media ${MEDIA_MODS[m]} { ${rule} }`;
3178
- if (responsiveMods.length > 0) {
3179
- const minWidth = Math.max(...responsiveMods.map((m) => screens[m] ?? 0));
3180
- if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
3181
- }
3182
- rules.push(rule);
3183
- return rules;
3184
- }
3185
- function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
3186
- const rules = [];
3187
- for (const parsed of parseClasses(classString)) {
3188
- const styles = resolveUtility(parsed, theme);
3189
- if (!styles) continue;
3190
- const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
3191
- rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
3192
- }
3193
- return rules.join("\n");
3194
- }
3195
2508
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3196
2509
  "shadowColor",
3197
2510
  "shadowOffset",
@@ -3201,13 +2514,10 @@ var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3201
2514
  "includeFontPadding",
3202
2515
  "textAlignVertical",
3203
2516
  "writingDirection",
3204
- // Text shadow native props — web uses the textShadow CSS shorthand instead
3205
2517
  "textShadowColor",
3206
2518
  "textShadowOffset",
3207
2519
  "textShadowRadius",
3208
- // tintColor is native-only (Image/icon tinting)
3209
2520
  "tintColor",
3210
- // Internal markers — handled specially, never serialized as CSS props
3211
2521
  "__divideX",
3212
2522
  "__divideY",
3213
2523
  "__divideColor",
@@ -3249,8 +2559,7 @@ function styleValueToCSS(styles, forceImportant = false) {
3249
2559
  const imp = forceImportant || prop === "display" && (cssVal === "grid" || cssVal === "inline-grid") || prop === "position" && (cssVal === "sticky" || cssVal === "fixed" || cssVal === "static") ? " !important" : "";
3250
2560
  if (prop in RN_SHORTHAND_EXPAND) {
3251
2561
  const [p1, p2] = RN_SHORTHAND_EXPAND[prop];
3252
- parts.push(`${p1}: ${cssVal}${imp}`);
3253
- parts.push(`${p2}: ${cssVal}${imp}`);
2562
+ parts.push(`${p1}: ${cssVal}${imp}`, `${p2}: ${cssVal}${imp}`);
3254
2563
  continue;
3255
2564
  }
3256
2565
  parts.push(`${camelToKebab(prop)}: ${cssVal}${imp}`);
@@ -3260,6 +2569,85 @@ function styleValueToCSS(styles, forceImportant = false) {
3260
2569
  function camelToKebab(str) {
3261
2570
  return str.replace(/([A-Z])/g, "-$1").toLowerCase();
3262
2571
  }
2572
+ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
2573
+ const rules = [];
2574
+ if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
2575
+ rules.push(styles.__keyframe);
2576
+ }
2577
+ const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
2578
+ const escaped = escapeCSSSelector(cls);
2579
+ const childSuffix = isDivide ? " > * + *" : "";
2580
+ if (bucketKey === "base") {
2581
+ const decls2 = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
2582
+ if (!decls2) return rules;
2583
+ rules.push(`.${escaped}${childSuffix} { ${decls2} }`);
2584
+ return rules;
2585
+ }
2586
+ const mods = bucketKey.split(":");
2587
+ let darkScheme;
2588
+ let needsImportant = important;
2589
+ const pseudoParts = [];
2590
+ const ancestorParts = [];
2591
+ const dirParts = [];
2592
+ const mediaWrappers = [];
2593
+ let minWidth = 0;
2594
+ for (const mod of mods) {
2595
+ const def = getModifier(mod);
2596
+ if (!def) continue;
2597
+ if (def.darkScheme) darkScheme = def.darkScheme;
2598
+ if (def.pseudo) pseudoParts.push(def.pseudo);
2599
+ if (def.ancestorSelector) {
2600
+ ancestorParts.push(def.ancestorSelector);
2601
+ needsImportant = true;
2602
+ }
2603
+ if (def.dirSelector) {
2604
+ dirParts.push(def.dirSelector);
2605
+ needsImportant = true;
2606
+ }
2607
+ if (def.mediaQuery) {
2608
+ mediaWrappers.push(`@media ${def.mediaQuery}`);
2609
+ needsImportant = true;
2610
+ }
2611
+ if (def.isResponsive) {
2612
+ const w = screens[mod] ?? 0;
2613
+ if (w > minWidth) minWidth = w;
2614
+ }
2615
+ if (def.forcesImportant) needsImportant = true;
2616
+ }
2617
+ const pseudoSuffix = pseudoParts.join("");
2618
+ const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
2619
+ const ancestorPrefix = ancestorParts.join("");
2620
+ const dirPrefix = dirParts.join("");
2621
+ const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
2622
+ const decls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
2623
+ if (!decls) return rules;
2624
+ let rule;
2625
+ if (darkScheme === "dark") {
2626
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: dark) { ${selector} { ${decls} } }`;
2627
+ else if (darkMode === "class") rule = `.dark ${selector} { ${decls} }`;
2628
+ else rule = `[data-theme="dark"] ${selector} { ${decls} }`;
2629
+ } else if (darkScheme === "light") {
2630
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: light) { ${selector} { ${decls} } }`;
2631
+ else if (darkMode === "class") rule = `:not(.dark) ${selector} { ${decls} }`;
2632
+ else rule = `[data-theme="light"] ${selector} { ${decls} }`;
2633
+ } else {
2634
+ rule = `${selector} { ${decls} }`;
2635
+ }
2636
+ for (const mw of mediaWrappers) rule = `${mw} { ${rule} }`;
2637
+ if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
2638
+ rules.push(rule);
2639
+ return rules;
2640
+ }
2641
+ function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
2642
+ const rules = [];
2643
+ for (const parsed of parseClasses(classString)) {
2644
+ const styles = resolveUtility(parsed, theme);
2645
+ if (!styles) continue;
2646
+ const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
2647
+ rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
2648
+ }
2649
+ return rules.join("\n");
2650
+ }
3263
2651
 
3264
2652
  // src/core/config.ts
3265
2653
  function deepMerge(base, override) {
@@ -3294,14 +2682,24 @@ function resolveOneRef(ref, colors) {
3294
2682
  return entry[m[2]] ?? null;
3295
2683
  }
3296
2684
  function resolveColorRefs(colors) {
2685
+ const MAX_DEPTH = 5;
2686
+ function resolveChain(raw) {
2687
+ let current = raw;
2688
+ for (let i = 0; i < MAX_DEPTH; i++) {
2689
+ const next = resolveOneRef(current, colors);
2690
+ if (!next || next === current) break;
2691
+ current = next;
2692
+ }
2693
+ return current;
2694
+ }
3297
2695
  const out = {};
3298
2696
  for (const [key, val] of Object.entries(colors)) {
3299
2697
  if (typeof val === "string") {
3300
- out[key] = resolveOneRef(val, colors) ?? val;
2698
+ out[key] = resolveChain(val);
3301
2699
  } else {
3302
2700
  const shades = {};
3303
2701
  for (const [shade, hex] of Object.entries(val)) {
3304
- shades[shade] = resolveOneRef(hex, colors) ?? hex;
2702
+ shades[shade] = resolveChain(hex);
3305
2703
  }
3306
2704
  out[key] = shades;
3307
2705
  }
@@ -3349,15 +2747,26 @@ function buildConfig(userConfig) {
3349
2747
  injectGlobalStyles(resolved.theme);
3350
2748
  return resolved;
3351
2749
  }
2750
+ function _selectorToModifierDef(selector) {
2751
+ const s = selector.trim();
2752
+ if (s.startsWith("@media ")) {
2753
+ return { mediaQuery: s.slice(7), jsBehavior: "css-only", forcesImportant: true };
2754
+ }
2755
+ if (s.startsWith("::") || s.startsWith(":")) {
2756
+ return { pseudo: s, jsBehavior: "css-only", forcesImportant: true };
2757
+ }
2758
+ return { ancestorSelector: s.endsWith(" ") ? s : `${s} `, jsBehavior: "css-only", forcesImportant: true };
2759
+ }
3352
2760
  function makePluginAPI(theme) {
3353
2761
  const standalone = getPluginStandaloneMap();
3354
2762
  return {
3355
2763
  addUtility(name, styles) {
3356
2764
  standalone[name] = styles;
3357
2765
  },
3358
- addVariant(name, selector) {
3359
- customVariants[name] = selector;
3360
- registerModifier(name);
2766
+ addVariant(name, selectorOrDef) {
2767
+ const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
2768
+ customVariants[name] = typeof selectorOrDef === "string" ? selectorOrDef : name;
2769
+ registerModifier(name, def);
3361
2770
  },
3362
2771
  theme(path, defaultValue) {
3363
2772
  const parts = path.replace(/\[([^\]]+)\]/g, ".$1").split(".");
@@ -3418,12 +2827,18 @@ function classifyToken(token) {
3418
2827
  return "Utilities";
3419
2828
  }
3420
2829
  function buildColorVarMap(theme, usedCSS) {
2830
+ const usedHexValues = /* @__PURE__ */ new Set();
2831
+ const hexRe = /#[0-9a-fA-F]{3,8}\b/g;
2832
+ let hm;
2833
+ while ((hm = hexRe.exec(usedCSS)) !== null) usedHexValues.add(hm[0].toLowerCase());
3421
2834
  const map = /* @__PURE__ */ new Map();
3422
2835
  for (const [name, shades] of Object.entries(theme.colors ?? {})) {
3423
2836
  const entries = typeof shades === "string" ? [[name, shades]] : Object.entries(shades).map(([s, v]) => [`${name}-${s}`, v]);
3424
2837
  for (const [fullName, val] of entries) {
3425
- if (typeof val === "string" && /^#[0-9a-fA-F]{3,8}$/.test(val) && usedCSS.includes(val)) {
3426
- map.set(val, `--color-${fullName}`);
2838
+ if (typeof val === "string" && /^#[0-9a-fA-F]{3,8}$/.test(val)) {
2839
+ if (usedHexValues.has(val.toLowerCase())) {
2840
+ map.set(val, `--color-${fullName}`);
2841
+ }
3427
2842
  }
3428
2843
  }
3429
2844
  }
@@ -3503,6 +2918,37 @@ function toNumericScreens(screens) {
3503
2918
  }
3504
2919
  return out;
3505
2920
  }
2921
+ function extractClassStrings(code) {
2922
+ const found = /* @__PURE__ */ new Set();
2923
+ const simpleRe = /(?:className|kb)=["']([^"']+)["']/g;
2924
+ let m;
2925
+ while ((m = simpleRe.exec(code)) !== null) pushTokens(m[1], found);
2926
+ const exprLiteralRe = /(?:className|kb)=\{["'`]([^"'`}]+)["'`]\}/g;
2927
+ while ((m = exprLiteralRe.exec(code)) !== null) pushTokens(m[1], found);
2928
+ const ternaryBlockRe = /(?:className|kb)=\{([^}]{1,500})\}/g;
2929
+ while ((m = ternaryBlockRe.exec(code)) !== null) {
2930
+ const block = m[1];
2931
+ const innerStrings = block.match(/["'`]([^"'`]{1,300})["'`]/g) ?? [];
2932
+ for (const s of innerStrings) pushTokens(s.slice(1, -1), found);
2933
+ }
2934
+ const clsxRe = /(?:clsx|cn|classnames)\(([^)]{1,1000})\)/g;
2935
+ while ((m = clsxRe.exec(code)) !== null) {
2936
+ const block = m[1];
2937
+ const innerStrings = block.match(/["'`]([^"'`]{1,300})["'`]/g) ?? [];
2938
+ for (const s of innerStrings) pushTokens(s.slice(1, -1), found);
2939
+ }
2940
+ const templateRe = /`([^`]{1,2000})`/g;
2941
+ while ((m = templateRe.exec(code)) !== null) {
2942
+ const staticParts = m[1].replace(/\$\{[^}]*\}/g, " ");
2943
+ pushTokens(staticParts, found);
2944
+ }
2945
+ return [...found];
2946
+ }
2947
+ function pushTokens(str, into) {
2948
+ for (const tok of splitClassTokens(str)) {
2949
+ if (tok) into.add(tok);
2950
+ }
2951
+ }
3506
2952
  function scanDir(dir, onFile) {
3507
2953
  try {
3508
2954
  for (const entry of (0, import_fs.readdirSync)(dir)) {
@@ -3511,41 +2957,49 @@ function scanDir(dir, onFile) {
3511
2957
  try {
3512
2958
  const st = (0, import_fs.statSync)(full);
3513
2959
  if (st.isDirectory()) scanDir(full, onFile);
3514
- else if (/\.(tsx?|jsx?)$/.test(entry)) onFile((0, import_fs.readFileSync)(full, "utf-8"));
2960
+ else if (/\.(tsx?|jsx?)$/.test(entry)) onFile(full, (0, import_fs.readFileSync)(full, "utf-8"));
3515
2961
  } catch {
3516
2962
  }
3517
2963
  }
3518
2964
  } catch {
3519
2965
  }
3520
2966
  }
3521
- function extractClassStrings(code) {
3522
- const found = [];
3523
- const re = /(?:className|kb)=(?:["']([^"']+)["']|\{["']([^"']+)["']\})/g;
3524
- let m;
3525
- while ((m = re.exec(code)) !== null) {
3526
- const val = m[1] ?? m[2];
3527
- if (val) found.push(val);
3528
- }
3529
- return found;
3530
- }
3531
2967
  function kbach(userConfig) {
3532
2968
  const cfg = buildConfig(userConfig ?? {});
3533
2969
  const screens = toNumericScreens(cfg.theme.screens ?? {});
3534
2970
  let root = process.cwd();
3535
2971
  let mainCSSFile = null;
3536
- function generateCSS() {
3537
- const tokenCSS = /* @__PURE__ */ new Map();
2972
+ const fileTokens = /* @__PURE__ */ new Map();
2973
+ const tokenCSS = /* @__PURE__ */ new Map();
2974
+ function processFile(filePath, code) {
2975
+ const tokens = /* @__PURE__ */ new Set();
2976
+ for (const cls of extractClassStrings(code)) {
2977
+ for (const tok of splitClassTokens(cls)) {
2978
+ tokens.add(tok);
2979
+ if (!tokenCSS.has(tok)) {
2980
+ tokenCSS.set(tok, generateClassCSS(tok, cfg.theme, cfg.darkMode, screens));
2981
+ }
2982
+ }
2983
+ }
2984
+ fileTokens.set(filePath, tokens);
2985
+ }
2986
+ function buildTokenCSSView() {
2987
+ const active = /* @__PURE__ */ new Set();
2988
+ for (const tokens of fileTokens.values()) for (const t of tokens) active.add(t);
2989
+ const view = /* @__PURE__ */ new Map();
2990
+ for (const tok of active) {
2991
+ const css = tokenCSS.get(tok);
2992
+ if (css !== void 0) view.set(tok, css);
2993
+ }
2994
+ return view;
2995
+ }
2996
+ function initialScan() {
3538
2997
  for (const dir of ["src", "app", "pages", "components", "views", "layouts"]) {
3539
- scanDir((0, import_path.join)(root, dir), (code) => {
3540
- for (const cls of extractClassStrings(code))
3541
- for (const token of splitClassTokens(cls))
3542
- if (!tokenCSS.has(token)) {
3543
- const css = generateClassCSS(token, cfg.theme, cfg.darkMode, screens);
3544
- tokenCSS.set(token, css);
3545
- }
3546
- });
2998
+ scanDir((0, import_path.join)(root, dir), processFile);
3547
2999
  }
3548
- return formatKbachCSS(tokenCSS, cfg.theme);
3000
+ }
3001
+ function generateCSS() {
3002
+ return formatKbachCSS(buildTokenCSSView(), cfg.theme);
3549
3003
  }
3550
3004
  return {
3551
3005
  name: "kbach",
@@ -3555,10 +3009,16 @@ function kbach(userConfig) {
3555
3009
  },
3556
3010
  buildStart() {
3557
3011
  mainCSSFile = findMainCSSFile(root);
3012
+ initialScan();
3558
3013
  if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
3559
3014
  },
3560
3015
  handleHotUpdate({ file }) {
3561
3016
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
3017
+ try {
3018
+ processFile(file, (0, import_fs.readFileSync)(file, "utf-8"));
3019
+ } catch {
3020
+ fileTokens.delete(file);
3021
+ }
3562
3022
  if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
3563
3023
  }
3564
3024
  };