@kbach/react 0.5.38 → 0.5.41

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.
@@ -28,12 +28,13 @@ var import_path = require("path");
28
28
 
29
29
  // src/core/platform.ts
30
30
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
31
+ var isNative = !isWeb && (typeof globalThis.HermesInternal !== "undefined" || typeof globalThis.__fbBatchedBridge !== "undefined" || typeof navigator !== "undefined" && navigator.product === "ReactNative");
31
32
  var _cssGenMode = false;
32
33
  function setCSSGenMode(on) {
33
34
  _cssGenMode = on;
34
35
  }
35
36
  function getEffectiveIsWeb() {
36
- return isWeb || _cssGenMode;
37
+ return isWeb || _cssGenMode || !isNative;
37
38
  }
38
39
  function toNativeValue(raw) {
39
40
  if (/^-?\d+(\.\d+)?px$/.test(raw)) return parseFloat(raw);
@@ -673,6 +674,7 @@ function resolveSizing(value, spacing, isArbitrary) {
673
674
  if (raw !== void 0) return raw;
674
675
  if (/^\d+\/\d+$/.test(value)) {
675
676
  const [num, den] = value.split("/").map(Number);
677
+ if (!den) return null;
676
678
  return `${(num / den * 100).toFixed(6)}%`;
677
679
  }
678
680
  return null;
@@ -2187,10 +2189,10 @@ function resolveUtility(parsed, theme) {
2187
2189
  if (!parsed.value) {
2188
2190
  if (parsed.utility in PLUGIN_STANDALONE) return PLUGIN_STANDALONE[parsed.utility] ?? null;
2189
2191
  if (parsed.utility === "grd" || parsed.utility === "grid") {
2190
- return { display: "grid" };
2192
+ return getEffectiveIsWeb() ? { display: "grid" } : null;
2191
2193
  }
2192
2194
  if (parsed.utility === "inline-grid") {
2193
- return { display: "inline-grid" };
2195
+ return getEffectiveIsWeb() ? { display: "inline-grid" } : null;
2194
2196
  }
2195
2197
  if (parsed.utility in getStandalone()) return getStandalone()[parsed.utility] ?? null;
2196
2198
  }
@@ -2203,685 +2205,129 @@ var PLUGIN_RESOLVERS = {};
2203
2205
  function clearPluginUtilities() {
2204
2206
  for (const key of Object.keys(PLUGIN_STANDALONE)) delete PLUGIN_STANDALONE[key];
2205
2207
  for (const key of Object.keys(PLUGIN_RESOLVERS)) delete PLUGIN_RESOLVERS[key];
2208
+ _sortedPrefixes = null;
2209
+ _standaloneNames = null;
2206
2210
  }
2207
2211
  function getPluginStandaloneMap() {
2208
2212
  return PLUGIN_STANDALONE;
2209
2213
  }
2214
+ var _sortedPrefixes = null;
2215
+ var _standaloneNames = null;
2216
+ function getBuiltinUtilityPrefixes() {
2217
+ if (!_sortedPrefixes) {
2218
+ const all = [.../* @__PURE__ */ new Set([...Object.keys(RESOLVERS), ...Object.keys(PLUGIN_RESOLVERS)])];
2219
+ _sortedPrefixes = all.sort((a, b) => b.length - a.length);
2220
+ }
2221
+ return _sortedPrefixes;
2222
+ }
2223
+ function getBuiltinStandaloneNames() {
2224
+ if (!_standaloneNames) {
2225
+ _standaloneNames = /* @__PURE__ */ new Set([...Object.keys(getStandalone()), ...Object.keys(PLUGIN_STANDALONE)]);
2226
+ }
2227
+ return _standaloneNames;
2228
+ }
2210
2229
 
2211
- // src/core/parser.ts
2212
- var PLUGIN_MODIFIERS = /* @__PURE__ */ new Set();
2213
- function registerModifier(name) {
2214
- PLUGIN_MODIFIERS.add(name);
2230
+ // src/core/registry.ts
2231
+ var BUILTIN_MODIFIERS = {
2232
+ // ── Mode ─────────────────────────────────────────────────────────────────
2233
+ dark: { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
2234
+ "not-light": { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
2235
+ light: { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
2236
+ "not-dark": { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
2237
+ // ── Interactive — JS state + CSS pseudo ───────────────────────────────────
2238
+ hover: { pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
2239
+ "not-hover": { pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
2240
+ focus: { pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
2241
+ "not-focus": { pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
2242
+ active: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
2243
+ "not-active": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
2244
+ pressed: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
2245
+ "not-pressed": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
2246
+ disabled: { pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
2247
+ "not-disabled": { pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
2248
+ checked: { pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
2249
+ "not-checked": { pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
2250
+ visited: { pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
2251
+ "not-visited": { pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
2252
+ placeholder: { pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
2253
+ // ── CSS-only pseudo-classes (structural) ──────────────────────────────────
2254
+ first: { pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
2255
+ last: { pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
2256
+ odd: { pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
2257
+ even: { pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
2258
+ only: { pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
2259
+ "focus-within": { pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
2260
+ "focus-visible": { pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
2261
+ // ── CSS-only pseudo-elements ───────────────────────────────────────────────
2262
+ before: { pseudo: "::before", jsBehavior: "css-only" },
2263
+ after: { pseudo: "::after", jsBehavior: "css-only" },
2264
+ selection: { pseudo: "::selection", jsBehavior: "css-only" },
2265
+ "first-letter": { pseudo: "::first-letter", jsBehavior: "css-only" },
2266
+ "first-line": { pseudo: "::first-line", jsBehavior: "css-only" },
2267
+ marker: { pseudo: "::marker", jsBehavior: "css-only" },
2268
+ // ── Group / peer ancestor selectors (CSS-only) ─────────────────────────────
2269
+ "group-hover": { ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
2270
+ "group-focus": { ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
2271
+ "peer-hover": { ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
2272
+ "peer-focus": { ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
2273
+ // ── Responsive — both CSS (@media min-width) and JS (breakpoints set) ──────
2274
+ sm: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
2275
+ md: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
2276
+ lg: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
2277
+ xl: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
2278
+ "2xl": { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
2279
+ // ── Print media (CSS-only) ─────────────────────────────────────────────────
2280
+ print: { mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
2281
+ // ── Orientation / accessibility media (CSS-only) ───────────────────────────
2282
+ landscape: { mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
2283
+ portrait: { mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
2284
+ "motion-reduce": { mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
2285
+ "motion-safe": { mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
2286
+ "contrast-more": { mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
2287
+ "contrast-less": { mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
2288
+ // ── Directionality (CSS-only) ──────────────────────────────────────────────
2289
+ rtl: { dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
2290
+ ltr: { dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
2291
+ };
2292
+ var _pluginModifiers = {};
2293
+ var _allNames = null;
2294
+ var _interactiveNames = null;
2295
+ var _modeNames = null;
2296
+ var _responsiveNames = null;
2297
+ function _invalidate() {
2298
+ _allNames = null;
2299
+ _interactiveNames = null;
2300
+ _modeNames = null;
2301
+ _responsiveNames = null;
2302
+ }
2303
+ function registerModifier(name, def) {
2304
+ _pluginModifiers[name] = def;
2305
+ _invalidate();
2215
2306
  }
2216
2307
  function clearPluginModifiers() {
2217
- PLUGIN_MODIFIERS.clear();
2308
+ for (const k of Object.keys(_pluginModifiers)) delete _pluginModifiers[k];
2309
+ _invalidate();
2218
2310
  }
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
- ]);
2311
+ function getModifier(name) {
2312
+ return BUILTIN_MODIFIERS[name] ?? _pluginModifiers[name];
2313
+ }
2314
+ function isKnownModifier(name) {
2315
+ return name in BUILTIN_MODIFIERS || name in _pluginModifiers;
2316
+ }
2317
+
2318
+ // src/core/parser.ts
2870
2319
  function parseClass(className) {
2871
2320
  const trimmed = className.trim();
2872
2321
  if (!trimmed) return null;
2873
2322
  const modifiers = [];
2874
2323
  let remaining = trimmed;
2875
- for (let i = 0; i < 3; i++) {
2324
+ while (true) {
2876
2325
  const colonIdx = findOuterColon(remaining);
2877
2326
  if (colonIdx === -1) break;
2878
2327
  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
- }
2328
+ if (!isKnownModifier(candidate)) break;
2329
+ modifiers.push(candidate);
2330
+ remaining = remaining.slice(colonIdx + 1);
2885
2331
  }
2886
2332
  let important = false;
2887
2333
  if (remaining.startsWith("!") && remaining.length > 1) {
@@ -2899,10 +2345,10 @@ function parseClass(className) {
2899
2345
  const value = remaining.slice(bracketStart + 2, -1).replace(/_/g, " ");
2900
2346
  return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
2901
2347
  }
2902
- if (STANDALONE_UTILITIES.has(remaining)) {
2348
+ if (getBuiltinStandaloneNames().has(remaining)) {
2903
2349
  return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
2904
2350
  }
2905
- for (const prefix of SORTED_PREFIXES) {
2351
+ for (const prefix of getBuiltinUtilityPrefixes()) {
2906
2352
  if (remaining === prefix) {
2907
2353
  return { original: trimmed, modifiers, negative, important, utility: prefix, value: "", isArbitrary: false };
2908
2354
  }
@@ -2997,7 +2443,11 @@ var LRUCache = class {
2997
2443
  return this;
2998
2444
  }
2999
2445
  has(key) {
3000
- return this.cache.has(key);
2446
+ if (!this.cache.has(key)) return false;
2447
+ const value = this.cache.get(key);
2448
+ this.cache.delete(key);
2449
+ this.cache.set(key, value);
2450
+ return true;
3001
2451
  }
3002
2452
  delete(key) {
3003
2453
  return this.cache.delete(key);
@@ -3011,12 +2461,12 @@ var LRUCache = class {
3011
2461
  };
3012
2462
 
3013
2463
  // src/core/resolver.ts
3014
- var styleCache = new LRUCache(1e4);
3015
2464
  var FONT_KEY = "__kbach_default_font__";
3016
2465
  function setDefaultFontFamily(font) {
3017
2466
  globalThis[FONT_KEY] = font;
3018
2467
  }
3019
2468
  var _styleEl = null;
2469
+ var _injectedRules = new LRUCache(5e4);
3020
2470
  function getStyleEl() {
3021
2471
  if (_styleEl) return _styleEl;
3022
2472
  _styleEl = document.createElement("style");
@@ -3042,156 +2492,20 @@ function injectGlobalStyles(theme) {
3042
2492
  }
3043
2493
  getGlobalStyleEl().textContent = rules.join("\n");
3044
2494
  }
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
2495
  function buildDivideDecls(styles) {
3098
2496
  const parts = [];
3099
2497
  if ("__divideX" in styles) {
3100
2498
  const w = Number(styles.__divideX);
3101
- parts.push(`border-left-width: ${w}px`);
3102
- parts.push("border-right-width: 0px");
2499
+ parts.push(`border-left-width: ${w}px`, "border-right-width: 0px");
3103
2500
  }
3104
2501
  if ("__divideY" in styles) {
3105
2502
  const w = Number(styles.__divideY);
3106
- parts.push(`border-top-width: ${w}px`);
3107
- parts.push("border-bottom-width: 0px");
2503
+ parts.push(`border-top-width: ${w}px`, "border-bottom-width: 0px");
3108
2504
  }
3109
2505
  if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}`);
3110
2506
  if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}`);
3111
2507
  return parts.join("; ");
3112
2508
  }
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
2509
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3196
2510
  "shadowColor",
3197
2511
  "shadowOffset",
@@ -3201,13 +2515,10 @@ var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3201
2515
  "includeFontPadding",
3202
2516
  "textAlignVertical",
3203
2517
  "writingDirection",
3204
- // Text shadow native props — web uses the textShadow CSS shorthand instead
3205
2518
  "textShadowColor",
3206
2519
  "textShadowOffset",
3207
2520
  "textShadowRadius",
3208
- // tintColor is native-only (Image/icon tinting)
3209
2521
  "tintColor",
3210
- // Internal markers — handled specially, never serialized as CSS props
3211
2522
  "__divideX",
3212
2523
  "__divideY",
3213
2524
  "__divideColor",
@@ -3249,8 +2560,7 @@ function styleValueToCSS(styles, forceImportant = false) {
3249
2560
  const imp = forceImportant || prop === "display" && (cssVal === "grid" || cssVal === "inline-grid") || prop === "position" && (cssVal === "sticky" || cssVal === "fixed" || cssVal === "static") ? " !important" : "";
3250
2561
  if (prop in RN_SHORTHAND_EXPAND) {
3251
2562
  const [p1, p2] = RN_SHORTHAND_EXPAND[prop];
3252
- parts.push(`${p1}: ${cssVal}${imp}`);
3253
- parts.push(`${p2}: ${cssVal}${imp}`);
2563
+ parts.push(`${p1}: ${cssVal}${imp}`, `${p2}: ${cssVal}${imp}`);
3254
2564
  continue;
3255
2565
  }
3256
2566
  parts.push(`${camelToKebab(prop)}: ${cssVal}${imp}`);
@@ -3260,6 +2570,85 @@ function styleValueToCSS(styles, forceImportant = false) {
3260
2570
  function camelToKebab(str) {
3261
2571
  return str.replace(/([A-Z])/g, "-$1").toLowerCase();
3262
2572
  }
2573
+ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
2574
+ const rules = [];
2575
+ if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
2576
+ rules.push(styles.__keyframe);
2577
+ }
2578
+ const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
2579
+ const escaped = escapeCSSSelector(cls);
2580
+ const childSuffix = isDivide ? " > * + *" : "";
2581
+ if (bucketKey === "base") {
2582
+ const decls2 = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
2583
+ if (!decls2) return rules;
2584
+ rules.push(`.${escaped}${childSuffix} { ${decls2} }`);
2585
+ return rules;
2586
+ }
2587
+ const mods = bucketKey.split(":");
2588
+ let darkScheme;
2589
+ let needsImportant = important;
2590
+ const pseudoParts = [];
2591
+ const ancestorParts = [];
2592
+ const dirParts = [];
2593
+ const mediaWrappers = [];
2594
+ let minWidth = 0;
2595
+ for (const mod of mods) {
2596
+ const def = getModifier(mod);
2597
+ if (!def) continue;
2598
+ if (def.darkScheme) darkScheme = def.darkScheme;
2599
+ if (def.pseudo) pseudoParts.push(def.pseudo);
2600
+ if (def.ancestorSelector) {
2601
+ ancestorParts.push(def.ancestorSelector);
2602
+ needsImportant = true;
2603
+ }
2604
+ if (def.dirSelector) {
2605
+ dirParts.push(def.dirSelector);
2606
+ needsImportant = true;
2607
+ }
2608
+ if (def.mediaQuery) {
2609
+ mediaWrappers.push(`@media ${def.mediaQuery}`);
2610
+ needsImportant = true;
2611
+ }
2612
+ if (def.isResponsive) {
2613
+ const w = screens[mod] ?? 0;
2614
+ if (w > minWidth) minWidth = w;
2615
+ }
2616
+ if (def.forcesImportant) needsImportant = true;
2617
+ }
2618
+ const pseudoSuffix = pseudoParts.join("");
2619
+ const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
2620
+ const ancestorPrefix = ancestorParts.join("");
2621
+ const dirPrefix = dirParts.join("");
2622
+ const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
2623
+ const decls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
2624
+ if (!decls) return rules;
2625
+ let rule;
2626
+ if (darkScheme === "dark") {
2627
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: dark) { ${selector} { ${decls} } }`;
2628
+ else if (darkMode === "class") rule = `.dark ${selector} { ${decls} }`;
2629
+ else rule = `[data-theme="dark"] ${selector} { ${decls} }`;
2630
+ } else if (darkScheme === "light") {
2631
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: light) { ${selector} { ${decls} } }`;
2632
+ else if (darkMode === "class") rule = `:not(.dark) ${selector} { ${decls} }`;
2633
+ else rule = `[data-theme="light"] ${selector} { ${decls} }`;
2634
+ } else {
2635
+ rule = `${selector} { ${decls} }`;
2636
+ }
2637
+ for (const mw of mediaWrappers) rule = `${mw} { ${rule} }`;
2638
+ if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
2639
+ rules.push(rule);
2640
+ return rules;
2641
+ }
2642
+ function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
2643
+ const rules = [];
2644
+ for (const parsed of parseClasses(classString)) {
2645
+ const styles = resolveUtility(parsed, theme);
2646
+ if (!styles) continue;
2647
+ const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
2648
+ rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
2649
+ }
2650
+ return rules.join("\n");
2651
+ }
3263
2652
 
3264
2653
  // src/core/config.ts
3265
2654
  function deepMerge(base, override) {
@@ -3294,14 +2683,24 @@ function resolveOneRef(ref, colors) {
3294
2683
  return entry[m[2]] ?? null;
3295
2684
  }
3296
2685
  function resolveColorRefs(colors) {
2686
+ const MAX_DEPTH = 5;
2687
+ function resolveChain(raw) {
2688
+ let current = raw;
2689
+ for (let i = 0; i < MAX_DEPTH; i++) {
2690
+ const next = resolveOneRef(current, colors);
2691
+ if (!next || next === current) break;
2692
+ current = next;
2693
+ }
2694
+ return current;
2695
+ }
3297
2696
  const out = {};
3298
2697
  for (const [key, val] of Object.entries(colors)) {
3299
2698
  if (typeof val === "string") {
3300
- out[key] = resolveOneRef(val, colors) ?? val;
2699
+ out[key] = resolveChain(val);
3301
2700
  } else {
3302
2701
  const shades = {};
3303
2702
  for (const [shade, hex] of Object.entries(val)) {
3304
- shades[shade] = resolveOneRef(hex, colors) ?? hex;
2703
+ shades[shade] = resolveChain(hex);
3305
2704
  }
3306
2705
  out[key] = shades;
3307
2706
  }
@@ -3349,15 +2748,26 @@ function buildConfig(userConfig) {
3349
2748
  injectGlobalStyles(resolved.theme);
3350
2749
  return resolved;
3351
2750
  }
2751
+ function _selectorToModifierDef(selector) {
2752
+ const s = selector.trim();
2753
+ if (s.startsWith("@media ")) {
2754
+ return { mediaQuery: s.slice(7), jsBehavior: "css-only", forcesImportant: true };
2755
+ }
2756
+ if (s.startsWith("::") || s.startsWith(":")) {
2757
+ return { pseudo: s, jsBehavior: "css-only", forcesImportant: true };
2758
+ }
2759
+ return { ancestorSelector: s.endsWith(" ") ? s : `${s} `, jsBehavior: "css-only", forcesImportant: true };
2760
+ }
3352
2761
  function makePluginAPI(theme) {
3353
2762
  const standalone = getPluginStandaloneMap();
3354
2763
  return {
3355
2764
  addUtility(name, styles) {
3356
2765
  standalone[name] = styles;
3357
2766
  },
3358
- addVariant(name, selector) {
3359
- customVariants[name] = selector;
3360
- registerModifier(name);
2767
+ addVariant(name, selectorOrDef) {
2768
+ const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
2769
+ customVariants[name] = typeof selectorOrDef === "string" ? selectorOrDef : name;
2770
+ registerModifier(name, def);
3361
2771
  },
3362
2772
  theme(path, defaultValue) {
3363
2773
  const parts = path.replace(/\[([^\]]+)\]/g, ".$1").split(".");
@@ -3418,12 +2828,18 @@ function classifyToken(token) {
3418
2828
  return "Utilities";
3419
2829
  }
3420
2830
  function buildColorVarMap(theme, usedCSS) {
2831
+ const usedHexValues = /* @__PURE__ */ new Set();
2832
+ const hexRe = /#[0-9a-fA-F]{3,8}\b/g;
2833
+ let hm;
2834
+ while ((hm = hexRe.exec(usedCSS)) !== null) usedHexValues.add(hm[0].toLowerCase());
3421
2835
  const map = /* @__PURE__ */ new Map();
3422
2836
  for (const [name, shades] of Object.entries(theme.colors ?? {})) {
3423
2837
  const entries = typeof shades === "string" ? [[name, shades]] : Object.entries(shades).map(([s, v]) => [`${name}-${s}`, v]);
3424
2838
  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}`);
2839
+ if (typeof val === "string" && /^#[0-9a-fA-F]{3,8}$/.test(val)) {
2840
+ if (usedHexValues.has(val.toLowerCase())) {
2841
+ map.set(val, `--color-${fullName}`);
2842
+ }
3427
2843
  }
3428
2844
  }
3429
2845
  }
@@ -3503,6 +2919,37 @@ function toNumericScreens(screens) {
3503
2919
  }
3504
2920
  return out;
3505
2921
  }
2922
+ function extractClassStrings(code) {
2923
+ const found = /* @__PURE__ */ new Set();
2924
+ const simpleRe = /(?:className|kb)=["']([^"']+)["']/g;
2925
+ let m;
2926
+ while ((m = simpleRe.exec(code)) !== null) pushTokens(m[1], found);
2927
+ const exprLiteralRe = /(?:className|kb)=\{["'`]([^"'`}]+)["'`]\}/g;
2928
+ while ((m = exprLiteralRe.exec(code)) !== null) pushTokens(m[1], found);
2929
+ const ternaryBlockRe = /(?:className|kb)=\{([^}]{1,500})\}/g;
2930
+ while ((m = ternaryBlockRe.exec(code)) !== null) {
2931
+ const block = m[1];
2932
+ const innerStrings = block.match(/["'`]([^"'`]{1,300})["'`]/g) ?? [];
2933
+ for (const s of innerStrings) pushTokens(s.slice(1, -1), found);
2934
+ }
2935
+ const clsxRe = /(?:clsx|cn|classnames)\(([^)]{1,1000})\)/g;
2936
+ while ((m = clsxRe.exec(code)) !== null) {
2937
+ const block = m[1];
2938
+ const innerStrings = block.match(/["'`]([^"'`]{1,300})["'`]/g) ?? [];
2939
+ for (const s of innerStrings) pushTokens(s.slice(1, -1), found);
2940
+ }
2941
+ const templateRe = /`([^`]{1,2000})`/g;
2942
+ while ((m = templateRe.exec(code)) !== null) {
2943
+ const staticParts = m[1].replace(/\$\{[^}]*\}/g, " ");
2944
+ pushTokens(staticParts, found);
2945
+ }
2946
+ return [...found];
2947
+ }
2948
+ function pushTokens(str, into) {
2949
+ for (const tok of splitClassTokens(str)) {
2950
+ if (tok) into.add(tok);
2951
+ }
2952
+ }
3506
2953
  function scanDir(dir, onFile) {
3507
2954
  try {
3508
2955
  for (const entry of (0, import_fs.readdirSync)(dir)) {
@@ -3511,41 +2958,49 @@ function scanDir(dir, onFile) {
3511
2958
  try {
3512
2959
  const st = (0, import_fs.statSync)(full);
3513
2960
  if (st.isDirectory()) scanDir(full, onFile);
3514
- else if (/\.(tsx?|jsx?)$/.test(entry)) onFile((0, import_fs.readFileSync)(full, "utf-8"));
2961
+ else if (/\.(tsx?|jsx?)$/.test(entry)) onFile(full, (0, import_fs.readFileSync)(full, "utf-8"));
3515
2962
  } catch {
3516
2963
  }
3517
2964
  }
3518
2965
  } catch {
3519
2966
  }
3520
2967
  }
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
2968
  function kbach(userConfig) {
3532
2969
  const cfg = buildConfig(userConfig ?? {});
3533
2970
  const screens = toNumericScreens(cfg.theme.screens ?? {});
3534
2971
  let root = process.cwd();
3535
2972
  let mainCSSFile = null;
3536
- function generateCSS() {
3537
- const tokenCSS = /* @__PURE__ */ new Map();
2973
+ const fileTokens = /* @__PURE__ */ new Map();
2974
+ const tokenCSS = /* @__PURE__ */ new Map();
2975
+ function processFile(filePath, code) {
2976
+ const tokens = /* @__PURE__ */ new Set();
2977
+ for (const cls of extractClassStrings(code)) {
2978
+ for (const tok of splitClassTokens(cls)) {
2979
+ tokens.add(tok);
2980
+ if (!tokenCSS.has(tok)) {
2981
+ tokenCSS.set(tok, generateClassCSS(tok, cfg.theme, cfg.darkMode, screens));
2982
+ }
2983
+ }
2984
+ }
2985
+ fileTokens.set(filePath, tokens);
2986
+ }
2987
+ function buildTokenCSSView() {
2988
+ const active = /* @__PURE__ */ new Set();
2989
+ for (const tokens of fileTokens.values()) for (const t of tokens) active.add(t);
2990
+ const view = /* @__PURE__ */ new Map();
2991
+ for (const tok of active) {
2992
+ const css = tokenCSS.get(tok);
2993
+ if (css !== void 0) view.set(tok, css);
2994
+ }
2995
+ return view;
2996
+ }
2997
+ function initialScan() {
3538
2998
  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
- });
2999
+ scanDir((0, import_path.join)(root, dir), processFile);
3547
3000
  }
3548
- return formatKbachCSS(tokenCSS, cfg.theme);
3001
+ }
3002
+ function generateCSS() {
3003
+ return formatKbachCSS(buildTokenCSSView(), cfg.theme);
3549
3004
  }
3550
3005
  return {
3551
3006
  name: "kbach",
@@ -3555,10 +3010,16 @@ function kbach(userConfig) {
3555
3010
  },
3556
3011
  buildStart() {
3557
3012
  mainCSSFile = findMainCSSFile(root);
3013
+ initialScan();
3558
3014
  if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
3559
3015
  },
3560
3016
  handleHotUpdate({ file }) {
3561
3017
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
3018
+ try {
3019
+ processFile(file, (0, import_fs.readFileSync)(file, "utf-8"));
3020
+ } catch {
3021
+ fileTokens.delete(file);
3022
+ }
3562
3023
  if (mainCSSFile) writeKbachToFile(mainCSSFile, generateCSS());
3563
3024
  }
3564
3025
  };