@kbach/react 0.5.57 → 0.5.59

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.
@@ -2,14 +2,14 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-UJBMEM6N.mjs";
6
- import "./chunk-VWEYYCBW.mjs";
7
- import "./chunk-JBV2R655.mjs";
5
+ } from "./chunk-HRNOI54V.mjs";
6
+ import "./chunk-2MVCYYH5.mjs";
7
+ import "./chunk-NP4FVE77.mjs";
8
8
 
9
9
  // src/jsx-dev-runtime.tsx
10
10
  function jsxDEV(type, props, key, isStaticChildren, source, self) {
11
11
  const element = (isStaticChildren ? jsxs : jsx)(type, props, key);
12
- if (source && element && typeof element === "object" && "_source" in Object.getPrototypeOf(element ?? {})) {
12
+ if (source && element && typeof element === "object") {
13
13
  element._source = source;
14
14
  element._self = self;
15
15
  }
@@ -480,14 +480,15 @@ var defaultTheme = {
480
480
  normal: 1.5,
481
481
  relaxed: 1.625,
482
482
  loose: 2,
483
- 3: 12,
484
- 4: 16,
485
- 5: 20,
486
- 6: 24,
487
- 7: 28,
488
- 8: 32,
489
- 9: 36,
490
- 10: 40
483
+ // Pixel values stored as strings; styleValueToCSS passes them through, toNativeValue strips the unit
484
+ 3: "12px",
485
+ 4: "16px",
486
+ 5: "20px",
487
+ 6: "24px",
488
+ 7: "28px",
489
+ 8: "32px",
490
+ 9: "36px",
491
+ 10: "40px"
491
492
  },
492
493
  letterSpacing: {
493
494
  tighter: -0.8,
@@ -508,9 +509,12 @@ var defaultTheme = {
508
509
  },
509
510
  flex: {
510
511
  1: 1,
511
- auto: 1,
512
- initial: 0,
513
- none: 0
512
+ auto: "auto",
513
+ // CSS: flex: auto = 1 1 auto; native: mapped to 1 in resolver
514
+ initial: "initial",
515
+ // CSS: flex: initial = 0 1 auto; native: mapped to 1
516
+ none: "none"
517
+ // CSS: flex: none = 0 0 auto; native: mapped to 0
514
518
  },
515
519
  shadow: {
516
520
  sm: {
@@ -580,6 +584,7 @@ var defaultTheme = {
580
584
  var LRUCache = class {
581
585
  constructor(capacity = 1e4) {
582
586
  this.capacity = capacity;
587
+ if (capacity <= 0) throw new Error("LRUCache: capacity must be a positive integer");
583
588
  this.cache = /* @__PURE__ */ new Map();
584
589
  }
585
590
  get(key) {
@@ -599,11 +604,7 @@ var LRUCache = class {
599
604
  return this;
600
605
  }
601
606
  has(key) {
602
- if (!this.cache.has(key)) return false;
603
- const value = this.cache.get(key);
604
- this.cache.delete(key);
605
- this.cache.set(key, value);
606
- return true;
607
+ return this.cache.has(key);
607
608
  }
608
609
  delete(key) {
609
610
  return this.cache.delete(key);
@@ -618,7 +619,7 @@ var LRUCache = class {
618
619
 
619
620
  // src/core/platform.ts
620
621
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
621
- var isNative = !isWeb && (typeof globalThis.HermesInternal !== "undefined" || typeof globalThis.__fbBatchedBridge !== "undefined" || typeof navigator !== "undefined" && navigator.product === "ReactNative");
622
+ var isNative = !isWeb && (typeof globalThis.HermesInternal !== "undefined" || typeof globalThis.__fbBatchedBridge !== "undefined" || typeof navigator !== "undefined" && navigator.product === "ReactNative" || typeof globalThis.__REACT_NATIVE__ !== "undefined");
622
623
  var _cssGenMode = false;
623
624
  function getEffectiveIsWeb() {
624
625
  return isWeb || _cssGenMode || !isNative;
@@ -631,7 +632,7 @@ function toNativeValue(raw) {
631
632
  return raw;
632
633
  }
633
634
  function escapeCSSSelector(cls) {
634
- return cls.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
635
+ return cls.replace(/[ !"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
635
636
  }
636
637
 
637
638
  // src/core/registry.ts
@@ -708,6 +709,10 @@ function _invalidate() {
708
709
  _responsiveNames = null;
709
710
  }
710
711
  function registerModifier(name, def) {
712
+ if (process.env.NODE_ENV !== "production" && name in BUILTIN_MODIFIERS) {
713
+ console.warn(`[kbach] registerModifier: "${name}" is a built-in modifier and cannot be overridden. Use a different name.`);
714
+ return;
715
+ }
711
716
  _pluginModifiers[name] = def;
712
717
  _invalidate();
713
718
  }
@@ -789,7 +794,7 @@ function resolveColor(value, colors, isArbitrary) {
789
794
  }
790
795
  if (!hex) return null;
791
796
  if (!opacityPart) {
792
- if (!isWeb && hex.startsWith("#") && hex.length === 9) {
797
+ if (!getEffectiveIsWeb() && hex.startsWith("#") && hex.length === 9) {
793
798
  return hexToRgba(hex, Math.round(parseInt(hex.slice(7, 9), 16) / 255 * 1e3) / 1e3);
794
799
  }
795
800
  return hex;
@@ -823,7 +828,10 @@ function resolveSpacing(value, negative, spacing, isArbitrary) {
823
828
  const resolved = getEffectiveIsWeb() ? value : toNativeValue(value);
824
829
  if (negative) {
825
830
  if (typeof resolved === "number") return -resolved;
826
- if (typeof resolved === "string" && /^\d/.test(resolved)) return `-${resolved}`;
831
+ if (typeof resolved === "string") {
832
+ if (/^\d/.test(resolved)) return `-${resolved}`;
833
+ if (/^(calc|var|min|max|clamp|env)\s*\(/.test(resolved)) return `calc(-1 * (${resolved}))`;
834
+ }
827
835
  }
828
836
  return resolved;
829
837
  }
@@ -1329,7 +1337,11 @@ var RESOLVERS = {
1329
1337
  const color = resolveColor(value, colors, false);
1330
1338
  if (color) return { borderColor: color };
1331
1339
  const w = borderWidth[value] ?? spacing[value];
1332
- if (w !== void 0) return { borderWidth: typeof w === "number" ? w : parseFloat(String(w)) };
1340
+ if (w !== void 0) {
1341
+ const numW = typeof w === "number" ? w : parseFloat(String(w));
1342
+ if (isNaN(numW)) return null;
1343
+ return { borderWidth: numW };
1344
+ }
1333
1345
  return null;
1334
1346
  },
1335
1347
  "border-t": ({ value, isArbitrary }, { colors, borderWidth }) => {
@@ -2032,7 +2044,7 @@ var RESOLVERS = {
2032
2044
  },
2033
2045
  // ── Tint color (native-only, for Image and icon components) ──────────────
2034
2046
  tint: ({ value, isArbitrary }, { colors }) => {
2035
- if (isWeb) return null;
2047
+ if (getEffectiveIsWeb()) return null;
2036
2048
  const color = resolveColor(value, colors, isArbitrary);
2037
2049
  return color ? { tintColor: color } : null;
2038
2050
  },
@@ -2104,7 +2116,15 @@ var RESOLVERS = {
2104
2116
  const v = parseFloat(value);
2105
2117
  return isNaN(v) ? null : { flex: v };
2106
2118
  }
2107
- if (value in flex) return { flex: flex[value] };
2119
+ if (value in flex) {
2120
+ const v = flex[value];
2121
+ if (typeof v === "string" && !getEffectiveIsWeb()) {
2122
+ if (v === "auto" || v === "initial") return { flex: 1 };
2123
+ if (v === "none") return { flex: 0 };
2124
+ return null;
2125
+ }
2126
+ return { flex: v };
2127
+ }
2108
2128
  const n = parseFloat(value);
2109
2129
  return isNaN(n) ? null : { flex: n };
2110
2130
  },
@@ -2207,7 +2227,9 @@ var RESOLVERS = {
2207
2227
  leading: ({ value, isArbitrary }, { lineHeight }) => {
2208
2228
  if (isArbitrary) return { lineHeight: getEffectiveIsWeb() ? value : toNativeValue(value) };
2209
2229
  const v = lineHeight[value];
2210
- return v !== void 0 ? { lineHeight: v } : null;
2230
+ if (v === void 0) return null;
2231
+ if (typeof v === "string" && !getEffectiveIsWeb()) return { lineHeight: toNativeValue(v) };
2232
+ return { lineHeight: v };
2211
2233
  },
2212
2234
  // ── Letter spacing ─────────────────────────────────────────────────────────
2213
2235
  tracking: ({ value, isArbitrary }, { letterSpacing }) => {
@@ -2283,7 +2305,7 @@ var RESOLVERS = {
2283
2305
  transition: ({ value }) => {
2284
2306
  if (!getEffectiveIsWeb()) return null;
2285
2307
  const presets = {
2286
- "": "color 150ms, background-color 150ms, border-color 150ms, opacity 150ms, box-shadow 150ms",
2308
+ "": "color 150ms, background-color 150ms, border-color 150ms, text-decoration-color 150ms, fill 150ms, stroke 150ms, opacity 150ms, box-shadow 150ms, transform 150ms, filter 150ms, backdrop-filter 150ms",
2287
2309
  all: "all 150ms",
2288
2310
  none: "none",
2289
2311
  colors: "color 150ms, background-color 150ms, border-color 150ms",
@@ -2296,11 +2318,13 @@ var RESOLVERS = {
2296
2318
  },
2297
2319
  duration: ({ value, isArbitrary }) => {
2298
2320
  if (!getEffectiveIsWeb()) return null;
2321
+ if (!isArbitrary && isNaN(parseFloat(value))) return null;
2299
2322
  const ms = isArbitrary ? value : `${value}ms`;
2300
2323
  return { transitionDuration: ms };
2301
2324
  },
2302
2325
  delay: ({ value, isArbitrary }) => {
2303
2326
  if (!getEffectiveIsWeb()) return null;
2327
+ if (!isArbitrary && isNaN(parseFloat(value))) return null;
2304
2328
  const ms = isArbitrary ? value : `${value}ms`;
2305
2329
  return { transitionDelay: ms };
2306
2330
  },
@@ -2343,14 +2367,20 @@ var RESOLVERS = {
2343
2367
  boxShadow: offsetWidth === 0 ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetWidth}px #fff, 0 0 0 ${offsetWidth + DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}`
2344
2368
  };
2345
2369
  },
2346
- // ── Space between (uses CSS gap or margin fallback) ────────────────────────
2370
+ // ── Space between ─────────────────────────────────────────────────────────
2371
+ // On web: emits __spaceX/__spaceY markers → resolver generates > * + * CSS rules.
2372
+ // On native (RN 0.71+): uses columnGap/rowGap directly.
2347
2373
  "space-x": ({ value, negative, isArbitrary }, { spacing }) => {
2348
2374
  const v = resolveSpacing(value, negative, spacing, isArbitrary);
2349
- return v !== null ? { columnGap: v } : null;
2375
+ if (v === null) return null;
2376
+ if (getEffectiveIsWeb()) return { __spaceX: v };
2377
+ return { columnGap: v };
2350
2378
  },
2351
2379
  "space-y": ({ value, negative, isArbitrary }, { spacing }) => {
2352
2380
  const v = resolveSpacing(value, negative, spacing, isArbitrary);
2353
- return v !== null ? { rowGap: v } : null;
2381
+ if (v === null) return null;
2382
+ if (getEffectiveIsWeb()) return { __spaceY: v };
2383
+ return { rowGap: v };
2354
2384
  }
2355
2385
  };
2356
2386
  function resolveUtility(parsed, theme) {
@@ -2416,12 +2446,28 @@ function parseClass(className) {
2416
2446
  negative = true;
2417
2447
  remaining = remaining.slice(1);
2418
2448
  }
2419
- const bracketStart = remaining.lastIndexOf("-[");
2420
- if (bracketStart > 0 && remaining.endsWith("]")) {
2421
- const utility = remaining.slice(0, bracketStart);
2422
- const value = remaining.slice(bracketStart + 2, -1).replace(/_/g, " ");
2449
+ let bracketDepth = 0;
2450
+ let bracketStart = -1;
2451
+ for (let i = remaining.length - 1; i >= 0; i--) {
2452
+ if (remaining[i] === "]") bracketDepth++;
2453
+ else if (remaining[i] === "[") {
2454
+ bracketDepth--;
2455
+ if (bracketDepth === 0) {
2456
+ bracketStart = i;
2457
+ break;
2458
+ }
2459
+ }
2460
+ }
2461
+ if (bracketStart > 0 && remaining[bracketStart - 1] === "-" && remaining.endsWith("]")) {
2462
+ const utility = remaining.slice(0, bracketStart - 1);
2463
+ const value = remaining.slice(bracketStart + 1, -1).replace(/_/g, " ");
2423
2464
  return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
2424
2465
  }
2466
+ if (remaining.endsWith("]") && bracketStart === -1) {
2467
+ if (process.env.NODE_ENV !== "production") {
2468
+ console.warn(`[kbach] Malformed class string: "${trimmed}" \u2014 unbalanced brackets`);
2469
+ }
2470
+ }
2425
2471
  if (remaining.startsWith("[") && remaining.endsWith("]")) {
2426
2472
  const value = remaining.slice(1, -1).replace(/_/g, " ");
2427
2473
  return { original: trimmed, modifiers, negative, important, utility: "", value, isArbitrary: true };
@@ -2456,6 +2502,7 @@ function splitClassTokens(classString) {
2456
2502
  const tokens = [];
2457
2503
  let current = "";
2458
2504
  let depth = 0;
2505
+ let parenDepth = 0;
2459
2506
  for (let i = 0; i < classString.length; i++) {
2460
2507
  const ch = classString[i];
2461
2508
  if (ch === "[") {
@@ -2468,8 +2515,18 @@ function splitClassTokens(classString) {
2468
2515
  current += ch;
2469
2516
  continue;
2470
2517
  }
2518
+ if (ch === "(") {
2519
+ parenDepth++;
2520
+ current += ch;
2521
+ continue;
2522
+ }
2523
+ if (ch === ")") {
2524
+ parenDepth--;
2525
+ current += ch;
2526
+ continue;
2527
+ }
2471
2528
  if (/\s/.test(ch)) {
2472
- if (depth === 0) {
2529
+ if (depth === 0 && parenDepth === 0) {
2473
2530
  if (current) {
2474
2531
  tokens.push(current);
2475
2532
  current = "";
@@ -2601,7 +2658,8 @@ function injectRule(rule) {
2601
2658
  if (_injectedRules.has(rule)) return;
2602
2659
  _injectedRules.set(rule, true);
2603
2660
  try {
2604
- getStyleEl().sheet?.insertRule(rule, getStyleEl().sheet.cssRules.length);
2661
+ const sheet = getStyleEl().sheet;
2662
+ if (sheet) sheet.insertRule(rule, sheet.cssRules.length);
2605
2663
  } catch {
2606
2664
  }
2607
2665
  }
@@ -2617,24 +2675,41 @@ function injectGlobalStyles(theme) {
2617
2675
  if (typeof document === "undefined" || isRuntimeCSSDisabled()) return;
2618
2676
  const rules = [BASE_RESET];
2619
2677
  const ff = theme.fontFamily;
2678
+ if (!ff) return;
2620
2679
  if (ff.sans && ff.sans !== "System") {
2621
2680
  const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
2622
2681
  rules.push(`body { font-family: ${family}; }`);
2623
2682
  }
2624
2683
  getGlobalStyleEl().textContent = rules.join("\n");
2625
2684
  }
2626
- function buildDivideDecls(styles) {
2685
+ function buildDivideDecls(styles, forceImportant) {
2686
+ const imp = forceImportant ? " !important" : "";
2627
2687
  const parts = [];
2628
2688
  if ("__divideX" in styles) {
2629
2689
  const w = Number(styles.__divideX);
2630
- parts.push(`border-left-width: ${w}px`, "border-right-width: 0px");
2690
+ parts.push(`border-left-width: ${w}px${imp}`, `border-right-width: 0px${imp}`);
2631
2691
  }
2632
2692
  if ("__divideY" in styles) {
2633
2693
  const w = Number(styles.__divideY);
2634
- parts.push(`border-top-width: ${w}px`, "border-bottom-width: 0px");
2694
+ parts.push(`border-top-width: ${w}px${imp}`, `border-bottom-width: 0px${imp}`);
2695
+ }
2696
+ if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}${imp}`);
2697
+ if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}${imp}`);
2698
+ return parts.join("; ");
2699
+ }
2700
+ function buildSpaceDecls(styles, forceImportant) {
2701
+ const imp = forceImportant ? " !important" : "";
2702
+ const parts = [];
2703
+ if ("__spaceX" in styles) {
2704
+ const v = styles.__spaceX;
2705
+ const val = typeof v === "number" ? `${v}px` : String(v);
2706
+ parts.push(`margin-left: ${val}${imp}`);
2707
+ }
2708
+ if ("__spaceY" in styles) {
2709
+ const v = styles.__spaceY;
2710
+ const val = typeof v === "number" ? `${v}px` : String(v);
2711
+ parts.push(`margin-top: ${val}${imp}`);
2635
2712
  }
2636
- if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}`);
2637
- if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}`);
2638
2713
  return parts.join("; ");
2639
2714
  }
2640
2715
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
@@ -2654,7 +2729,9 @@ var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
2654
2729
  "__divideY",
2655
2730
  "__divideColor",
2656
2731
  "__divideStyle",
2657
- "__keyframe"
2732
+ "__keyframe",
2733
+ "__spaceX",
2734
+ "__spaceY"
2658
2735
  ]);
2659
2736
  var CSS_UNITLESS = /* @__PURE__ */ new Set([
2660
2737
  "opacity",
@@ -2707,10 +2784,12 @@ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens
2707
2784
  rules.push(styles.__keyframe);
2708
2785
  }
2709
2786
  const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
2787
+ const isSpace = "__spaceX" in styles || "__spaceY" in styles;
2788
+ const isChildCombinator = isDivide || isSpace;
2710
2789
  const escaped = escapeCSSSelector(cls);
2711
- const childSuffix = isDivide ? " > * + *" : "";
2790
+ const childSuffix = isChildCombinator ? " > * + *" : "";
2712
2791
  if (bucketKey === "base") {
2713
- const decls2 = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
2792
+ const decls2 = isDivide ? buildDivideDecls(styles, important) : isSpace ? buildSpaceDecls(styles, important) : styleValueToCSS(styles, important);
2714
2793
  if (!decls2) return rules;
2715
2794
  rules.push(`.${escaped}${childSuffix} { ${decls2} }`);
2716
2795
  return rules;
@@ -2751,7 +2830,7 @@ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens
2751
2830
  const ancestorPrefix = ancestorParts.join("");
2752
2831
  const dirPrefix = dirParts.join("");
2753
2832
  const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
2754
- const decls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
2833
+ const decls = isDivide ? buildDivideDecls(styles, needsImportant) : isSpace ? buildSpaceDecls(styles, needsImportant) : styleValueToCSS(styles, needsImportant);
2755
2834
  if (!decls) return rules;
2756
2835
  let rule;
2757
2836
  if (darkScheme === "dark") {
@@ -2780,11 +2859,11 @@ function resolve(classString, theme, darkMode = "attribute") {
2780
2859
  const cached = cache.get(cacheKey);
2781
2860
  if (cached) return cached;
2782
2861
  const result = {};
2783
- const onWeb = typeof document !== "undefined";
2862
+ const onWeb = isWeb;
2784
2863
  for (const parsed of parseClasses(classString)) {
2785
2864
  const styles = resolveUtility(parsed, theme);
2786
2865
  if (!styles) {
2787
- if (process.env.NODE_ENV !== "production" && !parsed.isArbitrary && !isKnownUtility(parsed.utility)) {
2866
+ if (process.env.NODE_ENV !== "production" && !parsed.isArbitrary && !isKnownUtility(parsed.utility) && !parsed.original.startsWith("__")) {
2788
2867
  console.warn(`[kbach] Unknown utility "${parsed.utility}" in class "${parsed.original}"`);
2789
2868
  }
2790
2869
  continue;
@@ -2917,19 +2996,24 @@ function buildConfig(userConfig) {
2917
2996
  theme = deepMerge(theme, userConfig.theme);
2918
2997
  }
2919
2998
  if (userConfig.extend) {
2920
- const { theme: nestedTheme, ...directKeys } = userConfig.extend;
2999
+ const extendConfig = userConfig.extend;
3000
+ const { theme: nestedTheme, ...directKeys } = extendConfig;
2921
3001
  const extSources = [];
2922
3002
  if (nestedTheme) extSources.push(nestedTheme);
2923
3003
  if (Object.keys(directKeys).length) extSources.push(directKeys);
2924
3004
  for (const ext of extSources) {
2925
3005
  for (const [key, value] of Object.entries(ext)) {
3006
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3007
+ if (process.env.NODE_ENV !== "production") {
3008
+ console.warn(`[kbach] config.extend.${key} must be a plain object, got ${typeof value}. Skipping.`);
3009
+ }
3010
+ continue;
3011
+ }
2926
3012
  if (value !== null && typeof value === "object" && !Array.isArray(value)) {
2927
3013
  theme[key] = deepMerge(
2928
3014
  theme[key] ?? {},
2929
3015
  value
2930
3016
  );
2931
- } else if (value !== void 0) {
2932
- theme[key] = value;
2933
3017
  }
2934
3018
  }
2935
3019
  }
@@ -2940,8 +3024,10 @@ function buildConfig(userConfig) {
2940
3024
  theme,
2941
3025
  plugins: userConfig.plugins ?? []
2942
3026
  };
2943
- clearPluginUtilities();
2944
- clearPluginModifiers();
3027
+ if (userConfig.plugins !== void 0) {
3028
+ clearPluginUtilities();
3029
+ clearPluginModifiers();
3030
+ }
2945
3031
  const _store = getConfigStore();
2946
3032
  for (const k of Object.keys(_store.customVariants)) delete _store.customVariants[k];
2947
3033
  const pluginAPI = makePluginAPI(resolved.theme);
@@ -2959,7 +3045,7 @@ function _selectorToModifierDef(selector) {
2959
3045
  if (s.startsWith("@media ")) {
2960
3046
  return { mediaQuery: s.slice(7), jsBehavior: "css-only", forcesImportant: true };
2961
3047
  }
2962
- if (s.startsWith("::") || s.startsWith(":")) {
3048
+ if (s.startsWith("::") || s.startsWith(":") && !s.includes(" ") && !s.includes("&") && !s.includes("(")) {
2963
3049
  return { pseudo: s, jsBehavior: "css-only", forcesImportant: true };
2964
3050
  }
2965
3051
  return { ancestorSelector: s.endsWith(" ") ? s : `${s} `, jsBehavior: "css-only", forcesImportant: true };
@@ -2972,8 +3058,8 @@ function makePluginAPI(theme) {
2972
3058
  },
2973
3059
  addVariant(name, selectorOrDef) {
2974
3060
  const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
2975
- const selector = typeof selectorOrDef === "string" ? selectorOrDef : selectorOrDef.pseudo ?? selectorOrDef.mediaQuery ?? selectorOrDef.ancestorSelector ?? name;
2976
- customVariants[name] = selector;
3061
+ const selector = typeof selectorOrDef === "string" ? selectorOrDef : selectorOrDef.pseudo ?? selectorOrDef.mediaQuery ?? selectorOrDef.ancestorSelector ?? null;
3062
+ if (selector !== null && selector !== name) customVariants[name] = selector;
2977
3063
  registerModifier(name, def);
2978
3064
  },
2979
3065
  theme(path, defaultValue) {
@@ -2990,6 +3076,11 @@ function makePluginAPI(theme) {
2990
3076
  }
2991
3077
  };
2992
3078
  }
3079
+ function onConfigChange(listener) {
3080
+ const store = getConfigStore();
3081
+ store.listeners.add(listener);
3082
+ return () => store.listeners.delete(listener);
3083
+ }
2993
3084
  var customVariants = new Proxy(
2994
3085
  {},
2995
3086
  {
@@ -3016,7 +3107,7 @@ var KEY = "__kbach_dark_store__";
3016
3107
  function getStore2() {
3017
3108
  const g = globalThis;
3018
3109
  if (!g[KEY]) {
3019
- g[KEY] = { isDark: false, lastNotified: false, subscribers: /* @__PURE__ */ new Set() };
3110
+ g[KEY] = { isDark: false, subscribers: /* @__PURE__ */ new Set() };
3020
3111
  }
3021
3112
  return g[KEY];
3022
3113
  }
@@ -3148,10 +3239,11 @@ var InteractiveWrapper = (0, import_react3.forwardRef)(
3148
3239
  const handleMouseLeave = (0, import_react3.useCallback)(chain(onMouseLeave, () => setHovered(false)), [onMouseLeave]);
3149
3240
  const handleFocus = (0, import_react3.useCallback)(chain(onFocus, () => setFocused(true)), [onFocus]);
3150
3241
  const handleBlur = (0, import_react3.useCallback)(chain(onBlur, () => setFocused(false)), [onBlur]);
3242
+ const { children, disabled, checked, ...restForComponent } = rest;
3151
3243
  const computedStyle = (0, import_react3.useMemo)(
3152
3244
  () => {
3153
3245
  if (isWeb) return {};
3154
- const s = flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused, disabled: !!rest.disabled, checked: !!rest.checked }, breakpoints);
3246
+ const s = flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused, disabled: !!disabled, checked: !!checked }, breakpoints);
3155
3247
  delete s.__divideX;
3156
3248
  delete s.__divideY;
3157
3249
  delete s.__divideColor;
@@ -3182,20 +3274,20 @@ var InteractiveWrapper = (0, import_react3.forwardRef)(
3182
3274
  }
3183
3275
  return s;
3184
3276
  },
3185
- [resolvedStyle, isDark, pressed, hovered, focused, width]
3186
- // eslint-disable-line react-hooks/exhaustive-deps
3277
+ [resolvedStyle, isDark, pressed, hovered, focused, width, disabled, checked]
3187
3278
  );
3188
3279
  const skipComputedInline = isWeb || !isNative && typeof Component === "string";
3189
3280
  const finalStyle = skipComputedInline ? styleProp ?? void 0 : styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
3190
- const { children, ...restWithoutChildren } = rest;
3191
3281
  const componentProps = {
3192
3282
  ref,
3193
- ...restWithoutChildren,
3283
+ ...restForComponent,
3284
+ ...disabled !== void 0 ? { disabled } : {},
3285
+ ...checked !== void 0 ? { checked } : {},
3194
3286
  style: finalStyle,
3195
3287
  ...!isNative && className ? { className } : {},
3196
3288
  // onPressIn / onPressOut are React Native-only.
3197
3289
  // On web, onPointerDown/Up drive the pressed state instead (covers mouse + touch).
3198
- ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3290
+ ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3199
3291
  onMouseEnter: handleMouseEnter,
3200
3292
  onMouseLeave: handleMouseLeave,
3201
3293
  onFocus: handleFocus,
@@ -3214,6 +3306,7 @@ var DarkWrapper = import_react4.default.forwardRef(
3214
3306
  const needsWidth = hasResponsiveBuckets(resolvedStyle);
3215
3307
  const width = useConditionalWidth(needsWidth);
3216
3308
  const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS2;
3309
+ const screens = getGlobalScreens();
3217
3310
  const isNonStringComponent = typeof Component !== "string";
3218
3311
  const computedStyle = (0, import_react4.useMemo)(() => {
3219
3312
  if (isWeb) return {};
@@ -3221,7 +3314,7 @@ var DarkWrapper = import_react4.default.forwardRef(
3221
3314
  stripInternalMarkers(s);
3222
3315
  if (isNonStringComponent) stripWebOnlyProps(s);
3223
3316
  return s;
3224
- }, [resolvedStyle, isDark, width, isNonStringComponent]);
3317
+ }, [resolvedStyle, isDark, width, screens, isNonStringComponent]);
3225
3318
  const skipComputedInline = isWeb || !isNative && typeof Component === "string";
3226
3319
  const finalStyle = skipComputedInline ? styleProp ?? void 0 : styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
3227
3320
  const props = { ref, ...rest, style: finalStyle };
@@ -3296,8 +3389,8 @@ function getWebTag(type, props) {
3296
3389
  _cache.set(obj, null);
3297
3390
  return null;
3298
3391
  }
3299
- if (name === "TextInput" && props) {
3300
- const multiline = props.multiline === true || Number(props.numberOfLines) > 1;
3392
+ if (name === "TextInput") {
3393
+ const multiline = !!props && (props.multiline === true || Number(props.numberOfLines) > 1);
3301
3394
  return multiline ? "textarea" : "input";
3302
3395
  }
3303
3396
  if (_cache.has(obj)) return _cache.get(obj);
@@ -3334,8 +3427,7 @@ var _rnOnlyProps = /* @__PURE__ */ new Set([
3334
3427
  "shouldRasterizeIOS",
3335
3428
  "focusable",
3336
3429
  "hasTVPreferredFocus",
3337
- "pointerEvents",
3338
- // RN and HTML values differ
3430
+ // 'pointerEvents' is handled in transformToWebProps (mapped to CSS style)
3339
3431
  // Text
3340
3432
  "selectable",
3341
3433
  "allowFontScaling",
@@ -3446,6 +3538,7 @@ function transformToWebProps(originalName, tag, props) {
3446
3538
  const isTextInput = originalName === "TextInput";
3447
3539
  const isImage = originalName === "Image" || originalName === "ImageBackground";
3448
3540
  const isScrollable = originalName === "ScrollView" || originalName === "FlatList" || originalName === "SectionList";
3541
+ let pendingStyle = null;
3449
3542
  for (const [k, v] of Object.entries(props)) {
3450
3543
  if (_rnOnlyProps.has(k)) continue;
3451
3544
  if (k === "onPress") {
@@ -3490,10 +3583,11 @@ function transformToWebProps(originalName, tag, props) {
3490
3583
  }
3491
3584
  }
3492
3585
  if (isScrollable && k === "horizontal") {
3493
- if (v) {
3494
- const existing = out.style ?? {};
3495
- out.style = { display: "flex", flexDirection: "row", overflowX: "auto", ...existing };
3496
- }
3586
+ if (v) pendingStyle = { display: "flex", flexDirection: "row", overflowX: "auto" };
3587
+ continue;
3588
+ }
3589
+ if (k === "pointerEvents") {
3590
+ if (v === "none" || v === "auto") pendingStyle = { ...pendingStyle ?? {}, pointerEvents: v };
3497
3591
  continue;
3498
3592
  }
3499
3593
  if (isImage) {
@@ -3516,7 +3610,7 @@ function transformToWebProps(originalName, tag, props) {
3516
3610
  out.style = { ...existing, objectFit: v };
3517
3611
  continue;
3518
3612
  }
3519
- if (k === "alt" || k === "defaultSource") continue;
3613
+ if (k === "defaultSource") continue;
3520
3614
  }
3521
3615
  if (k === "style") {
3522
3616
  if (Array.isArray(v)) {
@@ -3528,6 +3622,9 @@ function transformToWebProps(originalName, tag, props) {
3528
3622
  }
3529
3623
  out[k] = v;
3530
3624
  }
3625
+ if (pendingStyle) {
3626
+ out.style = out.style ? { ...pendingStyle, ...out.style } : pendingStyle;
3627
+ }
3531
3628
  if (isPressable && !out.role) out.role = "button";
3532
3629
  if (isImage && tag === "img" && out.alt == null) out.alt = "";
3533
3630
  return out;
@@ -3540,6 +3637,7 @@ var _lastFontVersion = -1;
3540
3637
  function _invalidateDefaultFontCache() {
3541
3638
  _defaultFontVersion++;
3542
3639
  }
3640
+ onConfigChange(_invalidateDefaultFontCache);
3543
3641
  function getCachedDefaultFont() {
3544
3642
  if (_lastFontVersion !== _defaultFontVersion) {
3545
3643
  _cachedDefaultFont = getDefaultFontFamily();
@@ -3615,7 +3713,7 @@ function stripWebOnlyInlineProps(s) {
3615
3713
  }
3616
3714
  }
3617
3715
  function processElement(type, rawProps, key, isStaticChildren) {
3618
- if (typeof type === "symbol") return makeElement(isStaticChildren, type, rawProps ?? {}, key);
3716
+ if (type === null || typeof type === "symbol") return makeElement(isStaticChildren, type, rawProps ?? {}, key);
3619
3717
  const webTag = isWeb ? getWebTag(type, rawProps ?? void 0) : null;
3620
3718
  const effectiveType = webTag ?? type;
3621
3719
  const originalName = webTag ? type?.displayName ?? type?.name : void 0;
@@ -3631,6 +3729,14 @@ function processElement(type, rawProps, key, isStaticChildren) {
3631
3729
  ...userStyle2 !== void 0 ? { style: userStyle2 } : {}
3632
3730
  }, key);
3633
3731
  }
3732
+ if (classStr && !__kbachStyles && /^(__[^\s]+\s*)+$/.test(classStr.trim())) {
3733
+ const { style: userStyle2, ...passProps2 } = omitConsumed(workingProps);
3734
+ return makeElement(isStaticChildren, effectiveType, {
3735
+ ...passProps2,
3736
+ className: classStr,
3737
+ ...userStyle2 !== void 0 ? { style: userStyle2 } : {}
3738
+ }, key);
3739
+ }
3634
3740
  if (!classStr && !__kbachStyles) {
3635
3741
  if (isWeb) return makeElement(isStaticChildren, effectiveType, omitConsumed(workingProps), key);
3636
3742
  const defaultFont = getCachedDefaultFont();
@@ -3673,7 +3779,7 @@ function processElement(type, rawProps, key, isStaticChildren) {
3673
3779
  }
3674
3780
  return makeElement(isStaticChildren, effectiveType, {
3675
3781
  ...passProps,
3676
- style: finalStyle,
3782
+ ...finalStyle !== void 0 ? { style: finalStyle } : {},
3677
3783
  ...!isNative && classStr ? { className: normalizeClassString(classStr) } : {}
3678
3784
  }, key);
3679
3785
  }
@@ -3,11 +3,11 @@ import {
3
3
  _invalidateDefaultFontCache,
4
4
  jsx,
5
5
  jsxs
6
- } from "./chunk-UJBMEM6N.mjs";
6
+ } from "./chunk-HRNOI54V.mjs";
7
7
  import {
8
8
  registerWebElement
9
- } from "./chunk-VWEYYCBW.mjs";
10
- import "./chunk-JBV2R655.mjs";
9
+ } from "./chunk-2MVCYYH5.mjs";
10
+ import "./chunk-NP4FVE77.mjs";
11
11
  export {
12
12
  Fragment,
13
13
  _invalidateDefaultFontCache,
@@ -44,7 +44,7 @@ interface ModifierDef {
44
44
 
45
45
  type ThemeMode = 'light' | 'dark' | 'system';
46
46
  interface StyleValue {
47
- [key: string]: string | number | undefined | null | StyleValue | unknown[];
47
+ [key: string]: string | number | undefined | null | StyleValue | StyleValue[];
48
48
  }
49
49
  interface ParsedClass {
50
50
  /** The original class string, e.g. "dark:hover:bg-[#fff]" */
@@ -83,11 +83,16 @@ interface ThemeConfig {
83
83
  lineHeight: Record<string, number | string>;
84
84
  letterSpacing: Record<string, number | string>;
85
85
  zIndex: Record<string, number | string>;
86
- flex: Record<string, number>;
86
+ flex: Record<string, number | string>;
87
87
  shadow: Record<string, StyleValue>;
88
88
  screens: Record<string, string | number>;
89
89
  [key: string]: unknown;
90
90
  }
91
+ /**
92
+ * 'class' — toggles .dark class on <html>
93
+ * 'media' — uses prefers-color-scheme media query
94
+ * 'attribute' — uses data-theme="dark" attribute on <html>
95
+ */
91
96
  type DarkMode = 'attribute' | 'class' | 'media';
92
97
  interface PluginAPI {
93
98
  addUtility(name: string, styles: StyleValue): void;