@kbach/react 0.5.60 → 0.5.62

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.
@@ -7,7 +7,7 @@ import {
7
7
  isNative,
8
8
  isWeb,
9
9
  subscribeGlobalWidth
10
- } from "./chunk-NP4FVE77.mjs";
10
+ } from "./chunk-BRCQK5DA.mjs";
11
11
 
12
12
  // src/core/darkModeStore.ts
13
13
  var KEY = "__kbach_dark_store__";
@@ -407,7 +407,6 @@ function hasInteractiveBuckets(resolved) {
407
407
  }
408
408
  return false;
409
409
  }
410
- var EMPTY_BREAKPOINTS2 = /* @__PURE__ */ new Set();
411
410
 
412
411
  // src/InteractiveWrapper.tsx
413
412
  function chain(original, extra) {
@@ -495,9 +494,10 @@ var InteractiveWrapper = forwardRef(
495
494
  ...checked !== void 0 ? { checked } : {},
496
495
  style: finalStyle,
497
496
  ...!isNative && className ? { className } : {},
498
- // onPressIn / onPressOut are React Native-only.
499
- // On web, onPointerDown/Up drive the pressed state instead (covers mouse + touch).
500
- ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
497
+ // On web, onPointerDown/Up drive the wrapper's own pressed state (covers mouse + touch),
498
+ // but onPressIn/onPressOut are still forwarded unchanged — react-native-web components
499
+ // (and any component that accepts both prop names) depend on receiving them directly.
500
+ ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
501
501
  onMouseEnter: handleMouseEnter,
502
502
  onMouseLeave: handleMouseLeave,
503
503
  onFocus: handleFocus,
@@ -517,7 +517,6 @@ export {
517
517
  useConditionalWidth,
518
518
  hasResponsiveBuckets,
519
519
  hasInteractiveBuckets,
520
- EMPTY_BREAKPOINTS2,
521
520
  registerWebElement,
522
521
  getWebTag,
523
522
  transformToWebProps,
@@ -1151,10 +1151,12 @@ var RESOLVERS = {
1151
1151
  const color = resolveColor(value, colors, isArbitrary);
1152
1152
  return color ? { backgroundColor: color } : null;
1153
1153
  },
1154
- "bg-opacity": ({ value }, _) => {
1154
+ "bg-opacity": ({ value, isArbitrary }, _) => {
1155
1155
  if (!getEffectiveIsWeb()) return null;
1156
- const v = parseFloat(value) / 100;
1157
- return isNaN(v) ? null : { "--bg-opacity": v };
1156
+ const n = parseFloat(value);
1157
+ if (isNaN(n)) return null;
1158
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1159
+ return { "--bg-opacity": v };
1158
1160
  },
1159
1161
  // ── Text ───────────────────────────────────────────────────────────────────
1160
1162
  text: ({ value, isArbitrary }, { colors, fontSize }) => {
@@ -1169,10 +1171,12 @@ var RESOLVERS = {
1169
1171
  const color = resolveColor(value, colors, false);
1170
1172
  return color ? { color } : null;
1171
1173
  },
1172
- "text-opacity": ({ value }, _) => {
1174
+ "text-opacity": ({ value, isArbitrary }, _) => {
1173
1175
  if (!getEffectiveIsWeb()) return null;
1174
- const v = parseFloat(value) / 100;
1175
- return isNaN(v) ? null : { "--text-opacity": v };
1176
+ const n = parseFloat(value);
1177
+ if (isNaN(n)) return null;
1178
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1179
+ return { "--text-opacity": v };
1176
1180
  },
1177
1181
  // ── Padding ────────────────────────────────────────────────────────────────
1178
1182
  p: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2073,9 +2077,9 @@ var RESOLVERS = {
2073
2077
  const n = parseFloat(value);
2074
2078
  return { flexShrink: isNaN(n) ? 1 : n };
2075
2079
  },
2076
- order: ({ value, isArbitrary }, _) => {
2077
- const n = parseInt(value);
2078
- return isNaN(n) ? null : { order: n };
2080
+ order: ({ value, negative }, _) => {
2081
+ const n = parseInt(value, 10);
2082
+ return isNaN(n) ? null : { order: negative ? -n : n };
2079
2083
  },
2080
2084
  // ── Gap ────────────────────────────────────────────────────────────────────
2081
2085
  gap: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2292,10 +2296,17 @@ var RESOLVERS = {
2292
2296
  const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
2293
2297
  const DEFAULT_RING_WIDTH = 3;
2294
2298
  const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
2295
- const offsetWidth = !isArbitrary ? value in offsetTokens ? offsetTokens[value] : null : parseFloat(value);
2296
- if (offsetWidth === null || isNaN(offsetWidth)) return null;
2299
+ let offsetWidth;
2300
+ if (!isArbitrary) {
2301
+ offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
2302
+ } else {
2303
+ offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
2304
+ }
2305
+ if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
2306
+ const isZero = offsetWidth === 0 || offsetWidth === "0";
2307
+ const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
2297
2308
  return {
2298
- 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}`
2309
+ boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
2299
2310
  };
2300
2311
  },
2301
2312
  // ── Space between ─────────────────────────────────────────────────────────
@@ -1,12 +1,12 @@
1
1
  import {
2
- EMPTY_BREAKPOINTS2 as EMPTY_BREAKPOINTS,
2
+ EMPTY_BREAKPOINTS,
3
3
  InteractiveWrapper,
4
4
  getWebTag,
5
5
  hasResponsiveBuckets,
6
6
  transformToWebProps,
7
7
  useConditionalWidth,
8
8
  useGlobalDarkMode
9
- } from "./chunk-2MVCYYH5.mjs";
9
+ } from "./chunk-5MX3E4OL.mjs";
10
10
  import {
11
11
  flatten,
12
12
  getActiveBreakpoints,
@@ -22,7 +22,7 @@ import {
22
22
  normalizeClassString,
23
23
  onConfigChange,
24
24
  resolve
25
- } from "./chunk-NP4FVE77.mjs";
25
+ } from "./chunk-BRCQK5DA.mjs";
26
26
 
27
27
  // src/jsx-runtime.tsx
28
28
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -187,7 +187,7 @@ function processElement(type, rawProps, key, isStaticChildren) {
187
187
  ...userStyle2 !== void 0 ? { style: userStyle2 } : {}
188
188
  }, key);
189
189
  }
190
- if (classStr && !__kbachStyles && /^(__[^\s]+\s*)+$/.test(classStr.trim())) {
190
+ if (classStr && !__kbachStyles && /^(__[A-Za-z0-9_]+\s*)+$/.test(classStr.trim())) {
191
191
  const { style: userStyle2, ...passProps2 } = omitConsumed(workingProps);
192
192
  return makeElement(isStaticChildren, effectiveType, {
193
193
  ...passProps2,
package/dist/index.js CHANGED
@@ -1326,10 +1326,12 @@ var RESOLVERS = {
1326
1326
  const color = resolveColor(value, colors, isArbitrary);
1327
1327
  return color ? { backgroundColor: color } : null;
1328
1328
  },
1329
- "bg-opacity": ({ value }, _) => {
1329
+ "bg-opacity": ({ value, isArbitrary }, _) => {
1330
1330
  if (!getEffectiveIsWeb()) return null;
1331
- const v = parseFloat(value) / 100;
1332
- return isNaN(v) ? null : { "--bg-opacity": v };
1331
+ const n = parseFloat(value);
1332
+ if (isNaN(n)) return null;
1333
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1334
+ return { "--bg-opacity": v };
1333
1335
  },
1334
1336
  // ── Text ───────────────────────────────────────────────────────────────────
1335
1337
  text: ({ value, isArbitrary }, { colors, fontSize }) => {
@@ -1344,10 +1346,12 @@ var RESOLVERS = {
1344
1346
  const color = resolveColor(value, colors, false);
1345
1347
  return color ? { color } : null;
1346
1348
  },
1347
- "text-opacity": ({ value }, _) => {
1349
+ "text-opacity": ({ value, isArbitrary }, _) => {
1348
1350
  if (!getEffectiveIsWeb()) return null;
1349
- const v = parseFloat(value) / 100;
1350
- return isNaN(v) ? null : { "--text-opacity": v };
1351
+ const n = parseFloat(value);
1352
+ if (isNaN(n)) return null;
1353
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1354
+ return { "--text-opacity": v };
1351
1355
  },
1352
1356
  // ── Padding ────────────────────────────────────────────────────────────────
1353
1357
  p: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2248,9 +2252,9 @@ var RESOLVERS = {
2248
2252
  const n = parseFloat(value);
2249
2253
  return { flexShrink: isNaN(n) ? 1 : n };
2250
2254
  },
2251
- order: ({ value, isArbitrary }, _) => {
2252
- const n = parseInt(value);
2253
- return isNaN(n) ? null : { order: n };
2255
+ order: ({ value, negative }, _) => {
2256
+ const n = parseInt(value, 10);
2257
+ return isNaN(n) ? null : { order: negative ? -n : n };
2254
2258
  },
2255
2259
  // ── Gap ────────────────────────────────────────────────────────────────────
2256
2260
  gap: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2467,10 +2471,17 @@ var RESOLVERS = {
2467
2471
  const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
2468
2472
  const DEFAULT_RING_WIDTH = 3;
2469
2473
  const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
2470
- const offsetWidth = !isArbitrary ? value in offsetTokens ? offsetTokens[value] : null : parseFloat(value);
2471
- if (offsetWidth === null || isNaN(offsetWidth)) return null;
2474
+ let offsetWidth;
2475
+ if (!isArbitrary) {
2476
+ offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
2477
+ } else {
2478
+ offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
2479
+ }
2480
+ if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
2481
+ const isZero = offsetWidth === 0 || offsetWidth === "0";
2482
+ const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
2472
2483
  return {
2473
- 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}`
2484
+ boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
2474
2485
  };
2475
2486
  },
2476
2487
  // ── Space between ─────────────────────────────────────────────────────────
@@ -4013,7 +4024,9 @@ function styled(Component, baseClasses = "") {
4013
4024
  ...isWeb && combined ? { className: normalizeClassString(combined) } : {},
4014
4025
  // Only attach state-tracking handlers when interactive modifiers are present.
4015
4026
  // Always forward user-provided handlers to avoid silently swallowing them.
4016
- ...isWeb ? hasInteractive ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPointerDown, onPointerUp, onPointerLeave } : hasInteractive ? { onPressIn: handlePressIn, onPressOut: handlePressOut } : { onPressIn, onPressOut },
4027
+ // onPressIn/onPressOut are forwarded on web too (not just native) since
4028
+ // react-native-web components rely on receiving them directly.
4029
+ ...isWeb ? hasInteractive ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPointerDown, onPointerUp, onPointerLeave, onPressIn, onPressOut } : hasInteractive ? { onPressIn: handlePressIn, onPressOut: handlePressOut } : { onPressIn, onPressOut },
4017
4030
  onMouseEnter: hasInteractive ? handleMouseEnter : onMouseEnter,
4018
4031
  onMouseLeave: hasInteractive ? handleMouseLeave : onMouseLeave,
4019
4032
  onFocus: hasInteractive ? handleFocus : onFocus,
@@ -4162,9 +4175,10 @@ var InteractiveWrapper = (0, import_react10.forwardRef)(
4162
4175
  ...checked !== void 0 ? { checked } : {},
4163
4176
  style: finalStyle,
4164
4177
  ...!isNative && className ? { className } : {},
4165
- // onPressIn / onPressOut are React Native-only.
4166
- // On web, onPointerDown/Up drive the pressed state instead (covers mouse + touch).
4167
- ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
4178
+ // On web, onPointerDown/Up drive the wrapper's own pressed state (covers mouse + touch),
4179
+ // but onPressIn/onPressOut are still forwarded unchanged — react-native-web components
4180
+ // (and any component that accepts both prop names) depend on receiving them directly.
4181
+ ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
4168
4182
  onMouseEnter: handleMouseEnter,
4169
4183
  onMouseLeave: handleMouseLeave,
4170
4184
  onFocus: handleFocus,
package/dist/index.mjs CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  useConditionalWidth,
12
12
  useGlobalDarkMode,
13
13
  useGlobalWidth
14
- } from "./chunk-2MVCYYH5.mjs";
14
+ } from "./chunk-5MX3E4OL.mjs";
15
15
  import {
16
16
  __require,
17
17
  buildConfig,
@@ -33,7 +33,7 @@ import {
33
33
  syncGlobalScreens,
34
34
  syncGlobalWidth,
35
35
  updateConfig
36
- } from "./chunk-NP4FVE77.mjs";
36
+ } from "./chunk-BRCQK5DA.mjs";
37
37
 
38
38
  // src/context.tsx
39
39
  import { createContext, useContext } from "react";
@@ -501,7 +501,9 @@ function styled(Component, baseClasses = "") {
501
501
  ...isWeb && combined ? { className: normalizeClassString(combined) } : {},
502
502
  // Only attach state-tracking handlers when interactive modifiers are present.
503
503
  // Always forward user-provided handlers to avoid silently swallowing them.
504
- ...isWeb ? hasInteractive ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPointerDown, onPointerUp, onPointerLeave } : hasInteractive ? { onPressIn: handlePressIn, onPressOut: handlePressOut } : { onPressIn, onPressOut },
504
+ // onPressIn/onPressOut are forwarded on web too (not just native) since
505
+ // react-native-web components rely on receiving them directly.
506
+ ...isWeb ? hasInteractive ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPointerDown, onPointerUp, onPointerLeave, onPressIn, onPressOut } : hasInteractive ? { onPressIn: handlePressIn, onPressOut: handlePressOut } : { onPressIn, onPressOut },
505
507
  onMouseEnter: hasInteractive ? handleMouseEnter : onMouseEnter,
506
508
  onMouseLeave: hasInteractive ? handleMouseLeave : onMouseLeave,
507
509
  onFocus: hasInteractive ? handleFocus : onFocus,
@@ -1219,10 +1219,12 @@ var RESOLVERS = {
1219
1219
  const color = resolveColor(value, colors, isArbitrary);
1220
1220
  return color ? { backgroundColor: color } : null;
1221
1221
  },
1222
- "bg-opacity": ({ value }, _) => {
1222
+ "bg-opacity": ({ value, isArbitrary }, _) => {
1223
1223
  if (!getEffectiveIsWeb()) return null;
1224
- const v = parseFloat(value) / 100;
1225
- return isNaN(v) ? null : { "--bg-opacity": v };
1224
+ const n = parseFloat(value);
1225
+ if (isNaN(n)) return null;
1226
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1227
+ return { "--bg-opacity": v };
1226
1228
  },
1227
1229
  // ── Text ───────────────────────────────────────────────────────────────────
1228
1230
  text: ({ value, isArbitrary }, { colors, fontSize }) => {
@@ -1237,10 +1239,12 @@ var RESOLVERS = {
1237
1239
  const color = resolveColor(value, colors, false);
1238
1240
  return color ? { color } : null;
1239
1241
  },
1240
- "text-opacity": ({ value }, _) => {
1242
+ "text-opacity": ({ value, isArbitrary }, _) => {
1241
1243
  if (!getEffectiveIsWeb()) return null;
1242
- const v = parseFloat(value) / 100;
1243
- return isNaN(v) ? null : { "--text-opacity": v };
1244
+ const n = parseFloat(value);
1245
+ if (isNaN(n)) return null;
1246
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1247
+ return { "--text-opacity": v };
1244
1248
  },
1245
1249
  // ── Padding ────────────────────────────────────────────────────────────────
1246
1250
  p: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2141,9 +2145,9 @@ var RESOLVERS = {
2141
2145
  const n = parseFloat(value);
2142
2146
  return { flexShrink: isNaN(n) ? 1 : n };
2143
2147
  },
2144
- order: ({ value, isArbitrary }, _) => {
2145
- const n = parseInt(value);
2146
- return isNaN(n) ? null : { order: n };
2148
+ order: ({ value, negative }, _) => {
2149
+ const n = parseInt(value, 10);
2150
+ return isNaN(n) ? null : { order: negative ? -n : n };
2147
2151
  },
2148
2152
  // ── Gap ────────────────────────────────────────────────────────────────────
2149
2153
  gap: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2360,10 +2364,17 @@ var RESOLVERS = {
2360
2364
  const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
2361
2365
  const DEFAULT_RING_WIDTH = 3;
2362
2366
  const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
2363
- const offsetWidth = !isArbitrary ? value in offsetTokens ? offsetTokens[value] : null : parseFloat(value);
2364
- if (offsetWidth === null || isNaN(offsetWidth)) return null;
2367
+ let offsetWidth;
2368
+ if (!isArbitrary) {
2369
+ offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
2370
+ } else {
2371
+ offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
2372
+ }
2373
+ if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
2374
+ const isZero = offsetWidth === 0 || offsetWidth === "0";
2375
+ const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
2365
2376
  return {
2366
- 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}`
2377
+ boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
2367
2378
  };
2368
2379
  },
2369
2380
  // ── Space between ─────────────────────────────────────────────────────────
@@ -3196,7 +3207,6 @@ function hasResponsiveBuckets(resolved) {
3196
3207
  }
3197
3208
  return false;
3198
3209
  }
3199
- var EMPTY_BREAKPOINTS2 = /* @__PURE__ */ new Set();
3200
3210
 
3201
3211
  // src/InteractiveWrapper.tsx
3202
3212
  function chain(original, extra) {
@@ -3284,9 +3294,10 @@ var InteractiveWrapper = (0, import_react3.forwardRef)(
3284
3294
  ...checked !== void 0 ? { checked } : {},
3285
3295
  style: finalStyle,
3286
3296
  ...!isNative && className ? { className } : {},
3287
- // onPressIn / onPressOut are React Native-only.
3288
- // On web, onPointerDown/Up drive the pressed state instead (covers mouse + touch).
3289
- ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3297
+ // On web, onPointerDown/Up drive the wrapper's own pressed state (covers mouse + touch),
3298
+ // but onPressIn/onPressOut are still forwarded unchanged — react-native-web components
3299
+ // (and any component that accepts both prop names) depend on receiving them directly.
3300
+ ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3290
3301
  onMouseEnter: handleMouseEnter,
3291
3302
  onMouseLeave: handleMouseLeave,
3292
3303
  onFocus: handleFocus,
@@ -3304,7 +3315,7 @@ var DarkWrapper = import_react4.default.forwardRef(
3304
3315
  const isDark = useGlobalDarkMode();
3305
3316
  const needsWidth = hasResponsiveBuckets(resolvedStyle);
3306
3317
  const width = useConditionalWidth(needsWidth);
3307
- const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS2;
3318
+ const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
3308
3319
  const screens = getGlobalScreens();
3309
3320
  const isNonStringComponent = typeof Component !== "string";
3310
3321
  const computedStyle = (0, import_react4.useMemo)(() => {
@@ -3728,7 +3739,7 @@ function processElement(type, rawProps, key, isStaticChildren) {
3728
3739
  ...userStyle2 !== void 0 ? { style: userStyle2 } : {}
3729
3740
  }, key);
3730
3741
  }
3731
- if (classStr && !__kbachStyles && /^(__[^\s]+\s*)+$/.test(classStr.trim())) {
3742
+ if (classStr && !__kbachStyles && /^(__[A-Za-z0-9_]+\s*)+$/.test(classStr.trim())) {
3732
3743
  const { style: userStyle2, ...passProps2 } = omitConsumed(workingProps);
3733
3744
  return makeElement(isStaticChildren, effectiveType, {
3734
3745
  ...passProps2,
@@ -2,9 +2,9 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-LU2QNVYU.mjs";
6
- import "./chunk-2MVCYYH5.mjs";
7
- import "./chunk-NP4FVE77.mjs";
5
+ } from "./chunk-MZKQ7H67.mjs";
6
+ import "./chunk-5MX3E4OL.mjs";
7
+ import "./chunk-BRCQK5DA.mjs";
8
8
 
9
9
  // src/jsx-dev-runtime.tsx
10
10
  function jsxDEV(type, props, key, isStaticChildren, source, self) {
@@ -1220,10 +1220,12 @@ var RESOLVERS = {
1220
1220
  const color = resolveColor(value, colors, isArbitrary);
1221
1221
  return color ? { backgroundColor: color } : null;
1222
1222
  },
1223
- "bg-opacity": ({ value }, _) => {
1223
+ "bg-opacity": ({ value, isArbitrary }, _) => {
1224
1224
  if (!getEffectiveIsWeb()) return null;
1225
- const v = parseFloat(value) / 100;
1226
- return isNaN(v) ? null : { "--bg-opacity": v };
1225
+ const n = parseFloat(value);
1226
+ if (isNaN(n)) return null;
1227
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1228
+ return { "--bg-opacity": v };
1227
1229
  },
1228
1230
  // ── Text ───────────────────────────────────────────────────────────────────
1229
1231
  text: ({ value, isArbitrary }, { colors, fontSize }) => {
@@ -1238,10 +1240,12 @@ var RESOLVERS = {
1238
1240
  const color = resolveColor(value, colors, false);
1239
1241
  return color ? { color } : null;
1240
1242
  },
1241
- "text-opacity": ({ value }, _) => {
1243
+ "text-opacity": ({ value, isArbitrary }, _) => {
1242
1244
  if (!getEffectiveIsWeb()) return null;
1243
- const v = parseFloat(value) / 100;
1244
- return isNaN(v) ? null : { "--text-opacity": v };
1245
+ const n = parseFloat(value);
1246
+ if (isNaN(n)) return null;
1247
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1248
+ return { "--text-opacity": v };
1245
1249
  },
1246
1250
  // ── Padding ────────────────────────────────────────────────────────────────
1247
1251
  p: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2142,9 +2146,9 @@ var RESOLVERS = {
2142
2146
  const n = parseFloat(value);
2143
2147
  return { flexShrink: isNaN(n) ? 1 : n };
2144
2148
  },
2145
- order: ({ value, isArbitrary }, _) => {
2146
- const n = parseInt(value);
2147
- return isNaN(n) ? null : { order: n };
2149
+ order: ({ value, negative }, _) => {
2150
+ const n = parseInt(value, 10);
2151
+ return isNaN(n) ? null : { order: negative ? -n : n };
2148
2152
  },
2149
2153
  // ── Gap ────────────────────────────────────────────────────────────────────
2150
2154
  gap: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2361,10 +2365,17 @@ var RESOLVERS = {
2361
2365
  const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
2362
2366
  const DEFAULT_RING_WIDTH = 3;
2363
2367
  const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
2364
- const offsetWidth = !isArbitrary ? value in offsetTokens ? offsetTokens[value] : null : parseFloat(value);
2365
- if (offsetWidth === null || isNaN(offsetWidth)) return null;
2368
+ let offsetWidth;
2369
+ if (!isArbitrary) {
2370
+ offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
2371
+ } else {
2372
+ offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
2373
+ }
2374
+ if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
2375
+ const isZero = offsetWidth === 0 || offsetWidth === "0";
2376
+ const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
2366
2377
  return {
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}`
2378
+ boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
2368
2379
  };
2369
2380
  },
2370
2381
  // ── Space between ─────────────────────────────────────────────────────────
@@ -3197,7 +3208,6 @@ function hasResponsiveBuckets(resolved) {
3197
3208
  }
3198
3209
  return false;
3199
3210
  }
3200
- var EMPTY_BREAKPOINTS2 = /* @__PURE__ */ new Set();
3201
3211
 
3202
3212
  // src/InteractiveWrapper.tsx
3203
3213
  function chain(original, extra) {
@@ -3285,9 +3295,10 @@ var InteractiveWrapper = (0, import_react3.forwardRef)(
3285
3295
  ...checked !== void 0 ? { checked } : {},
3286
3296
  style: finalStyle,
3287
3297
  ...!isNative && className ? { className } : {},
3288
- // onPressIn / onPressOut are React Native-only.
3289
- // On web, onPointerDown/Up drive the pressed state instead (covers mouse + touch).
3290
- ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3298
+ // On web, onPointerDown/Up drive the wrapper's own pressed state (covers mouse + touch),
3299
+ // but onPressIn/onPressOut are still forwarded unchanged — react-native-web components
3300
+ // (and any component that accepts both prop names) depend on receiving them directly.
3301
+ ...!isNative ? { onPointerDown: handlePointerDown, onPointerUp: handlePointerUp, onPointerLeave: handlePointerLeave, onPointerCancel: handlePointerLeave, onPressIn, onPressOut } : { onPressIn: handlePressIn, onPressOut: handlePressOut },
3291
3302
  onMouseEnter: handleMouseEnter,
3292
3303
  onMouseLeave: handleMouseLeave,
3293
3304
  onFocus: handleFocus,
@@ -3305,7 +3316,7 @@ var DarkWrapper = import_react4.default.forwardRef(
3305
3316
  const isDark = useGlobalDarkMode();
3306
3317
  const needsWidth = hasResponsiveBuckets(resolvedStyle);
3307
3318
  const width = useConditionalWidth(needsWidth);
3308
- const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS2;
3319
+ const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
3309
3320
  const screens = getGlobalScreens();
3310
3321
  const isNonStringComponent = typeof Component !== "string";
3311
3322
  const computedStyle = (0, import_react4.useMemo)(() => {
@@ -3734,7 +3745,7 @@ function processElement(type, rawProps, key, isStaticChildren) {
3734
3745
  ...userStyle2 !== void 0 ? { style: userStyle2 } : {}
3735
3746
  }, key);
3736
3747
  }
3737
- if (classStr && !__kbachStyles && /^(__[^\s]+\s*)+$/.test(classStr.trim())) {
3748
+ if (classStr && !__kbachStyles && /^(__[A-Za-z0-9_]+\s*)+$/.test(classStr.trim())) {
3738
3749
  const { style: userStyle2, ...passProps2 } = omitConsumed(workingProps);
3739
3750
  return makeElement(isStaticChildren, effectiveType, {
3740
3751
  ...passProps2,
@@ -3,11 +3,11 @@ import {
3
3
  _invalidateDefaultFontCache,
4
4
  jsx,
5
5
  jsxs
6
- } from "./chunk-LU2QNVYU.mjs";
6
+ } from "./chunk-MZKQ7H67.mjs";
7
7
  import {
8
8
  registerWebElement
9
- } from "./chunk-2MVCYYH5.mjs";
10
- import "./chunk-NP4FVE77.mjs";
9
+ } from "./chunk-5MX3E4OL.mjs";
10
+ import "./chunk-BRCQK5DA.mjs";
11
11
  export {
12
12
  Fragment,
13
13
  _invalidateDefaultFontCache,
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/vite-plugin.ts
@@ -25,6 +35,7 @@ __export(vite_plugin_exports, {
25
35
  module.exports = __toCommonJS(vite_plugin_exports);
26
36
  var import_fs = require("fs");
27
37
  var import_path = require("path");
38
+ var import_node_process = __toESM(require("process"));
28
39
 
29
40
  // src/core/platform.ts
30
41
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
@@ -1073,10 +1084,12 @@ var RESOLVERS = {
1073
1084
  const color = resolveColor(value, colors, isArbitrary);
1074
1085
  return color ? { backgroundColor: color } : null;
1075
1086
  },
1076
- "bg-opacity": ({ value }, _) => {
1087
+ "bg-opacity": ({ value, isArbitrary }, _) => {
1077
1088
  if (!getEffectiveIsWeb()) return null;
1078
- const v = parseFloat(value) / 100;
1079
- return isNaN(v) ? null : { "--bg-opacity": v };
1089
+ const n = parseFloat(value);
1090
+ if (isNaN(n)) return null;
1091
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1092
+ return { "--bg-opacity": v };
1080
1093
  },
1081
1094
  // ── Text ───────────────────────────────────────────────────────────────────
1082
1095
  text: ({ value, isArbitrary }, { colors, fontSize }) => {
@@ -1091,10 +1104,12 @@ var RESOLVERS = {
1091
1104
  const color = resolveColor(value, colors, false);
1092
1105
  return color ? { color } : null;
1093
1106
  },
1094
- "text-opacity": ({ value }, _) => {
1107
+ "text-opacity": ({ value, isArbitrary }, _) => {
1095
1108
  if (!getEffectiveIsWeb()) return null;
1096
- const v = parseFloat(value) / 100;
1097
- return isNaN(v) ? null : { "--text-opacity": v };
1109
+ const n = parseFloat(value);
1110
+ if (isNaN(n)) return null;
1111
+ const v = isArbitrary ? n > 1 ? n / 100 : n : n / 100;
1112
+ return { "--text-opacity": v };
1098
1113
  },
1099
1114
  // ── Padding ────────────────────────────────────────────────────────────────
1100
1115
  p: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -1995,9 +2010,9 @@ var RESOLVERS = {
1995
2010
  const n = parseFloat(value);
1996
2011
  return { flexShrink: isNaN(n) ? 1 : n };
1997
2012
  },
1998
- order: ({ value, isArbitrary }, _) => {
1999
- const n = parseInt(value);
2000
- return isNaN(n) ? null : { order: n };
2013
+ order: ({ value, negative }, _) => {
2014
+ const n = parseInt(value, 10);
2015
+ return isNaN(n) ? null : { order: negative ? -n : n };
2001
2016
  },
2002
2017
  // ── Gap ────────────────────────────────────────────────────────────────────
2003
2018
  gap: ({ value, negative, isArbitrary }, { spacing }) => {
@@ -2214,10 +2229,17 @@ var RESOLVERS = {
2214
2229
  const DEFAULT_RING_COLOR = "rgba(59, 130, 246, 0.5)";
2215
2230
  const DEFAULT_RING_WIDTH = 3;
2216
2231
  const offsetTokens = { "0": 0, "1": 1, "2": 2, "4": 4, "8": 8 };
2217
- const offsetWidth = !isArbitrary ? value in offsetTokens ? offsetTokens[value] : null : parseFloat(value);
2218
- if (offsetWidth === null || isNaN(offsetWidth)) return null;
2232
+ let offsetWidth;
2233
+ if (!isArbitrary) {
2234
+ offsetWidth = value in offsetTokens ? offsetTokens[value] : null;
2235
+ } else {
2236
+ offsetWidth = /^-?\d+(\.\d+)?$/.test(value) ? parseFloat(value) : value;
2237
+ }
2238
+ if (offsetWidth === null || typeof offsetWidth === "number" && isNaN(offsetWidth)) return null;
2239
+ const isZero = offsetWidth === 0 || offsetWidth === "0";
2240
+ const offsetCss = typeof offsetWidth === "number" ? `${offsetWidth}px` : offsetWidth;
2219
2241
  return {
2220
- 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}`
2242
+ boxShadow: isZero ? `0 0 0 ${DEFAULT_RING_WIDTH}px ${DEFAULT_RING_COLOR}` : `0 0 0 ${offsetCss} #fff, 0 0 0 calc(${offsetCss} + ${DEFAULT_RING_WIDTH}px) ${DEFAULT_RING_COLOR}`
2221
2243
  };
2222
2244
  },
2223
2245
  // ── Space between ─────────────────────────────────────────────────────────
@@ -2917,9 +2939,10 @@ var customVariants = new Proxy(
2917
2939
  );
2918
2940
 
2919
2941
  // src/vite-plugin.ts
2942
+ var process2 = import_node_process.default;
2920
2943
  function normPath(p) {
2921
2944
  const fwd = p.replace(/\\/g, "/");
2922
- return process.platform === "win32" ? fwd.toLowerCase() : fwd;
2945
+ return process2.platform === "win32" ? fwd.toLowerCase() : fwd;
2923
2946
  }
2924
2947
  setCSSGenMode(true);
2925
2948
  var KBACH_START = "/* kbach:start */";
@@ -3159,7 +3182,7 @@ function kbach(userConfigOrOptions) {
3159
3182
  const screenKeys = Object.keys(cfg.theme.screens ?? {});
3160
3183
  const responsivePattern = screenKeys.length ? screenKeys.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") : "sm|md|lg|xl|2xl";
3161
3184
  const responsiveRe = new RegExp(`^(${responsivePattern}):`);
3162
- let root = process.cwd();
3185
+ let root = process2.cwd();
3163
3186
  let mainCSSFile = null;
3164
3187
  const fileTokens = /* @__PURE__ */ new Map();
3165
3188
  const tokenCSS = /* @__PURE__ */ new Map();
@@ -4,11 +4,13 @@ import {
4
4
  generateClassCSS,
5
5
  setCSSGenMode,
6
6
  splitClassTokens
7
- } from "./chunk-NP4FVE77.mjs";
7
+ } from "./chunk-BRCQK5DA.mjs";
8
8
 
9
9
  // src/vite-plugin.ts
10
10
  import { readFileSync, writeFileSync, readdirSync, statSync } from "fs";
11
11
  import { join } from "path";
12
+ import processImport from "process";
13
+ var process = processImport;
12
14
  function normPath(p) {
13
15
  const fwd = p.replace(/\\/g, "/");
14
16
  return process.platform === "win32" ? fwd.toLowerCase() : fwd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.5.60",
3
+ "version": "0.5.62",
4
4
  "description": "React / React Native components and hooks for the Kbach framework",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./dist/index.js",