@kbach/react 0.6.36 → 0.6.39

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.
@@ -1877,6 +1877,18 @@ var effectResolvers = {
1877
1877
  if (!isArbitrary && isNaN(parseFloat(value))) return null;
1878
1878
  const ms = isArbitrary ? value : `${value}ms`;
1879
1879
  return { transitionDelay: ms };
1880
+ },
1881
+ ease: ({ value, isArbitrary }) => {
1882
+ if (!getEffectiveIsWeb()) return null;
1883
+ if (isArbitrary) return { transitionTimingFunction: value };
1884
+ const presets = {
1885
+ linear: "linear",
1886
+ in: "cubic-bezier(0.4, 0, 1, 1)",
1887
+ out: "cubic-bezier(0, 0, 0.2, 1)",
1888
+ "in-out": "cubic-bezier(0.4, 0, 0.2, 1)"
1889
+ };
1890
+ const v = presets[value];
1891
+ return v !== void 0 ? { transitionTimingFunction: v } : null;
1880
1892
  }
1881
1893
  };
1882
1894
 
@@ -3269,30 +3281,51 @@ function getConfig() {
3269
3281
  configStore.resolved = buildConfig({});
3270
3282
  return configStore.resolved;
3271
3283
  }
3272
- function resolveOneRef(ref, colors) {
3273
- const lastDash = ref.lastIndexOf("-");
3274
- if (lastDash <= 0) return null;
3275
- const name = ref.slice(0, lastDash);
3276
- const shade = ref.slice(lastDash + 1);
3277
- if (!/^\d+$/.test(shade)) return null;
3278
- const entry = colors[name];
3279
- if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3280
- const target = entry[shade];
3281
- return typeof target === "string" ? target : null;
3282
- }
3283
3284
  function resolveColorRefs(colors) {
3284
3285
  const MAX_DEPTH = 5;
3285
- function resolveChain(raw) {
3286
+ function resolveChain(raw, side) {
3286
3287
  let current = raw;
3287
3288
  for (let i = 0; i < MAX_DEPTH; i++) {
3288
- const next = resolveOneRef(current, colors);
3289
+ const next = resolveOneRef(current, side);
3289
3290
  if (!next || next === current) break;
3290
3291
  current = next;
3291
3292
  }
3292
3293
  return current;
3293
3294
  }
3295
+ function resolveOneRef(ref, side) {
3296
+ const slashIdx = ref.indexOf("/");
3297
+ if (slashIdx > 0) {
3298
+ const baseName = ref.slice(0, slashIdx);
3299
+ const opacity = Number(ref.slice(slashIdx + 1));
3300
+ if (!Number.isFinite(opacity)) return null;
3301
+ let baseRef;
3302
+ const entry2 = colors[baseName];
3303
+ if (typeof entry2 === "string") {
3304
+ baseRef = entry2;
3305
+ } else if (isModeAwareColor(entry2)) {
3306
+ if (!side) return null;
3307
+ baseRef = entry2[side];
3308
+ } else if (entry2 && typeof entry2 === "object" && "6" in entry2) {
3309
+ const v = entry2["6"];
3310
+ baseRef = typeof v === "string" ? v : void 0;
3311
+ }
3312
+ if (baseRef === void 0) return null;
3313
+ const baseHex = resolveChain(baseRef, side);
3314
+ const a = opacity > 1 ? opacity / 100 : opacity;
3315
+ return hexToRgba(baseHex, a);
3316
+ }
3317
+ const lastDash = ref.lastIndexOf("-");
3318
+ if (lastDash <= 0) return null;
3319
+ const name = ref.slice(0, lastDash);
3320
+ const shade = ref.slice(lastDash + 1);
3321
+ if (!/^\d+$/.test(shade)) return null;
3322
+ const entry = colors[name];
3323
+ if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3324
+ const target = entry[shade];
3325
+ return typeof target === "string" ? target : null;
3326
+ }
3294
3327
  function resolveValue(val) {
3295
- return typeof val === "string" ? resolveChain(val) : { light: resolveChain(val.light), dark: resolveChain(val.dark) };
3328
+ return typeof val === "string" ? resolveChain(val, null) : { light: resolveChain(val.light, "light"), dark: resolveChain(val.dark, "dark") };
3296
3329
  }
3297
3330
  const out = {};
3298
3331
  for (const [key, val] of Object.entries(colors)) {
@@ -3547,11 +3580,21 @@ function registerWebElement(rnComponent, htmlTag) {
3547
3580
  _userMap.set(rnComponent, htmlTag);
3548
3581
  _cache.delete(rnComponent);
3549
3582
  }
3583
+ var _forwardRefOrMemoType = /* @__PURE__ */ new Set([
3584
+ /* @__PURE__ */ Symbol.for("react.forward_ref"),
3585
+ /* @__PURE__ */ Symbol.for("react.memo")
3586
+ ]);
3587
+ function looksLikeRealRNPrimitive(type) {
3588
+ const t = type.$$typeof;
3589
+ if (t !== void 0) return _forwardRefOrMemoType.has(t);
3590
+ return !!type.prototype?.isReactComponent;
3591
+ }
3550
3592
  function getWebTag(type, props) {
3551
3593
  if (typeof type === "string") return null;
3552
3594
  if (type === null || typeof type !== "function" && typeof type !== "object") return null;
3553
3595
  const obj = type;
3554
3596
  if (_userMap.has(obj)) return _userMap.get(obj);
3597
+ if (!looksLikeRealRNPrimitive(obj)) return null;
3555
3598
  const name = obj.displayName ?? obj.name;
3556
3599
  if (!name) {
3557
3600
  _cache.set(obj, null);
@@ -26,7 +26,7 @@ import {
26
26
  transformToWebProps,
27
27
  useConditionalGlobalDarkMode,
28
28
  useConditionalWidth
29
- } from "./chunk-ATZF2VI7.mjs";
29
+ } from "./chunk-NE4LAJXK.mjs";
30
30
 
31
31
  // src/jsx-runtime.tsx
32
32
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -1966,6 +1966,18 @@ var effectResolvers = {
1966
1966
  if (!isArbitrary && isNaN(parseFloat(value))) return null;
1967
1967
  const ms = isArbitrary ? value : `${value}ms`;
1968
1968
  return { transitionDelay: ms };
1969
+ },
1970
+ ease: ({ value, isArbitrary }) => {
1971
+ if (!getEffectiveIsWeb()) return null;
1972
+ if (isArbitrary) return { transitionTimingFunction: value };
1973
+ const presets = {
1974
+ linear: "linear",
1975
+ in: "cubic-bezier(0.4, 0, 1, 1)",
1976
+ out: "cubic-bezier(0, 0, 0.2, 1)",
1977
+ "in-out": "cubic-bezier(0.4, 0, 0.2, 1)"
1978
+ };
1979
+ const v = presets[value];
1980
+ return v !== void 0 ? { transitionTimingFunction: v } : null;
1969
1981
  }
1970
1982
  };
1971
1983
 
@@ -3371,30 +3383,51 @@ function getConfig() {
3371
3383
  function resetConfig() {
3372
3384
  configStore.resolved = null;
3373
3385
  }
3374
- function resolveOneRef(ref, colors) {
3375
- const lastDash = ref.lastIndexOf("-");
3376
- if (lastDash <= 0) return null;
3377
- const name = ref.slice(0, lastDash);
3378
- const shade = ref.slice(lastDash + 1);
3379
- if (!/^\d+$/.test(shade)) return null;
3380
- const entry = colors[name];
3381
- if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3382
- const target = entry[shade];
3383
- return typeof target === "string" ? target : null;
3384
- }
3385
3386
  function resolveColorRefs(colors) {
3386
3387
  const MAX_DEPTH = 5;
3387
- function resolveChain(raw) {
3388
+ function resolveChain(raw, side) {
3388
3389
  let current = raw;
3389
3390
  for (let i = 0; i < MAX_DEPTH; i++) {
3390
- const next = resolveOneRef(current, colors);
3391
+ const next = resolveOneRef(current, side);
3391
3392
  if (!next || next === current) break;
3392
3393
  current = next;
3393
3394
  }
3394
3395
  return current;
3395
3396
  }
3397
+ function resolveOneRef(ref, side) {
3398
+ const slashIdx = ref.indexOf("/");
3399
+ if (slashIdx > 0) {
3400
+ const baseName = ref.slice(0, slashIdx);
3401
+ const opacity = Number(ref.slice(slashIdx + 1));
3402
+ if (!Number.isFinite(opacity)) return null;
3403
+ let baseRef;
3404
+ const entry2 = colors[baseName];
3405
+ if (typeof entry2 === "string") {
3406
+ baseRef = entry2;
3407
+ } else if (isModeAwareColor(entry2)) {
3408
+ if (!side) return null;
3409
+ baseRef = entry2[side];
3410
+ } else if (entry2 && typeof entry2 === "object" && "6" in entry2) {
3411
+ const v = entry2["6"];
3412
+ baseRef = typeof v === "string" ? v : void 0;
3413
+ }
3414
+ if (baseRef === void 0) return null;
3415
+ const baseHex = resolveChain(baseRef, side);
3416
+ const a = opacity > 1 ? opacity / 100 : opacity;
3417
+ return hexToRgba(baseHex, a);
3418
+ }
3419
+ const lastDash = ref.lastIndexOf("-");
3420
+ if (lastDash <= 0) return null;
3421
+ const name = ref.slice(0, lastDash);
3422
+ const shade = ref.slice(lastDash + 1);
3423
+ if (!/^\d+$/.test(shade)) return null;
3424
+ const entry = colors[name];
3425
+ if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3426
+ const target = entry[shade];
3427
+ return typeof target === "string" ? target : null;
3428
+ }
3396
3429
  function resolveValue(val) {
3397
- return typeof val === "string" ? resolveChain(val) : { light: resolveChain(val.light), dark: resolveChain(val.dark) };
3430
+ return typeof val === "string" ? resolveChain(val, null) : { light: resolveChain(val.light, "light"), dark: resolveChain(val.dark, "dark") };
3398
3431
  }
3399
3432
  const out = {};
3400
3433
  for (const [key, val] of Object.entries(colors)) {
package/dist/index.js CHANGED
@@ -526,11 +526,21 @@ function registerWebElement(rnComponent, htmlTag) {
526
526
  _userMap.set(rnComponent, htmlTag);
527
527
  _cache.delete(rnComponent);
528
528
  }
529
+ var _forwardRefOrMemoType = /* @__PURE__ */ new Set([
530
+ /* @__PURE__ */ Symbol.for("react.forward_ref"),
531
+ /* @__PURE__ */ Symbol.for("react.memo")
532
+ ]);
533
+ function looksLikeRealRNPrimitive(type) {
534
+ const t = type.$$typeof;
535
+ if (t !== void 0) return _forwardRefOrMemoType.has(t);
536
+ return !!type.prototype?.isReactComponent;
537
+ }
529
538
  function getWebTag(type, props) {
530
539
  if (typeof type === "string") return null;
531
540
  if (type === null || typeof type !== "function" && typeof type !== "object") return null;
532
541
  const obj = type;
533
542
  if (_userMap.has(obj)) return _userMap.get(obj);
543
+ if (!looksLikeRealRNPrimitive(obj)) return null;
534
544
  const name = obj.displayName ?? obj.name;
535
545
  if (!name) {
536
546
  _cache.set(obj, null);
package/dist/index.mjs CHANGED
@@ -45,7 +45,7 @@ import {
45
45
  useGlobalDarkMode,
46
46
  useGlobalWidth,
47
47
  useSyncExternalStore
48
- } from "./chunk-ATZF2VI7.mjs";
48
+ } from "./chunk-NE4LAJXK.mjs";
49
49
 
50
50
  // src/context.tsx
51
51
  import { createContext, useContext } from "react";
@@ -319,11 +319,21 @@ var _rnToHtml = {
319
319
  };
320
320
  var _userMap = /* @__PURE__ */ new Map();
321
321
  var _cache = /* @__PURE__ */ new WeakMap();
322
+ var _forwardRefOrMemoType = /* @__PURE__ */ new Set([
323
+ /* @__PURE__ */ Symbol.for("react.forward_ref"),
324
+ /* @__PURE__ */ Symbol.for("react.memo")
325
+ ]);
326
+ function looksLikeRealRNPrimitive(type) {
327
+ const t = type.$$typeof;
328
+ if (t !== void 0) return _forwardRefOrMemoType.has(t);
329
+ return !!type.prototype?.isReactComponent;
330
+ }
322
331
  function getWebTag(type, props) {
323
332
  if (typeof type === "string") return null;
324
333
  if (type === null || typeof type !== "function" && typeof type !== "object") return null;
325
334
  const obj = type;
326
335
  if (_userMap.has(obj)) return _userMap.get(obj);
336
+ if (!looksLikeRealRNPrimitive(obj)) return null;
327
337
  const name = obj.displayName ?? obj.name;
328
338
  if (!name) {
329
339
  _cache.set(obj, null);
@@ -3,8 +3,8 @@ import {
3
3
  Fragment,
4
4
  jsx,
5
5
  jsxs
6
- } from "./chunk-YDLZI5J6.mjs";
7
- import "./chunk-ATZF2VI7.mjs";
6
+ } from "./chunk-Z4ZOGRZG.mjs";
7
+ import "./chunk-NE4LAJXK.mjs";
8
8
 
9
9
  // src/jsx-dev-runtime.tsx
10
10
  function jsxDEV(type, props, key, isStaticChildren, source, self) {
@@ -325,11 +325,21 @@ function registerWebElement(rnComponent, htmlTag) {
325
325
  _userMap.set(rnComponent, htmlTag);
326
326
  _cache.delete(rnComponent);
327
327
  }
328
+ var _forwardRefOrMemoType = /* @__PURE__ */ new Set([
329
+ /* @__PURE__ */ Symbol.for("react.forward_ref"),
330
+ /* @__PURE__ */ Symbol.for("react.memo")
331
+ ]);
332
+ function looksLikeRealRNPrimitive(type) {
333
+ const t = type.$$typeof;
334
+ if (t !== void 0) return _forwardRefOrMemoType.has(t);
335
+ return !!type.prototype?.isReactComponent;
336
+ }
328
337
  function getWebTag(type, props) {
329
338
  if (typeof type === "string") return null;
330
339
  if (type === null || typeof type !== "function" && typeof type !== "object") return null;
331
340
  const obj = type;
332
341
  if (_userMap.has(obj)) return _userMap.get(obj);
342
+ if (!looksLikeRealRNPrimitive(obj)) return null;
333
343
  const name = obj.displayName ?? obj.name;
334
344
  if (!name) {
335
345
  _cache.set(obj, null);
@@ -4,10 +4,10 @@ import {
4
4
  _invalidateDefaultFontCache,
5
5
  jsx,
6
6
  jsxs
7
- } from "./chunk-YDLZI5J6.mjs";
7
+ } from "./chunk-Z4ZOGRZG.mjs";
8
8
  import {
9
9
  registerWebElement
10
- } from "./chunk-ATZF2VI7.mjs";
10
+ } from "./chunk-NE4LAJXK.mjs";
11
11
  export {
12
12
  Fragment,
13
13
  _invalidateDefaultFontCache,
@@ -2319,6 +2319,18 @@ var effectResolvers = {
2319
2319
  if (!isArbitrary && isNaN(parseFloat(value))) return null;
2320
2320
  const ms = isArbitrary ? value : `${value}ms`;
2321
2321
  return { transitionDelay: ms };
2322
+ },
2323
+ ease: ({ value, isArbitrary }) => {
2324
+ if (!getEffectiveIsWeb()) return null;
2325
+ if (isArbitrary) return { transitionTimingFunction: value };
2326
+ const presets = {
2327
+ linear: "linear",
2328
+ in: "cubic-bezier(0.4, 0, 1, 1)",
2329
+ out: "cubic-bezier(0, 0, 0.2, 1)",
2330
+ "in-out": "cubic-bezier(0.4, 0, 0.2, 1)"
2331
+ };
2332
+ const v = presets[value];
2333
+ return v !== void 0 ? { transitionTimingFunction: v } : null;
2322
2334
  }
2323
2335
  };
2324
2336
 
@@ -3072,30 +3084,51 @@ function deepMerge(base, override) {
3072
3084
  return result;
3073
3085
  }
3074
3086
  var configStore = { resolved: null, listeners: /* @__PURE__ */ new Set(), customVariants: {} };
3075
- function resolveOneRef(ref, colors) {
3076
- const lastDash = ref.lastIndexOf("-");
3077
- if (lastDash <= 0) return null;
3078
- const name = ref.slice(0, lastDash);
3079
- const shade = ref.slice(lastDash + 1);
3080
- if (!/^\d+$/.test(shade)) return null;
3081
- const entry = colors[name];
3082
- if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3083
- const target = entry[shade];
3084
- return typeof target === "string" ? target : null;
3085
- }
3086
3087
  function resolveColorRefs(colors) {
3087
3088
  const MAX_DEPTH = 5;
3088
- function resolveChain(raw) {
3089
+ function resolveChain(raw, side) {
3089
3090
  let current = raw;
3090
3091
  for (let i = 0; i < MAX_DEPTH; i++) {
3091
- const next = resolveOneRef(current, colors);
3092
+ const next = resolveOneRef(current, side);
3092
3093
  if (!next || next === current) break;
3093
3094
  current = next;
3094
3095
  }
3095
3096
  return current;
3096
3097
  }
3098
+ function resolveOneRef(ref, side) {
3099
+ const slashIdx = ref.indexOf("/");
3100
+ if (slashIdx > 0) {
3101
+ const baseName = ref.slice(0, slashIdx);
3102
+ const opacity = Number(ref.slice(slashIdx + 1));
3103
+ if (!Number.isFinite(opacity)) return null;
3104
+ let baseRef;
3105
+ const entry2 = colors[baseName];
3106
+ if (typeof entry2 === "string") {
3107
+ baseRef = entry2;
3108
+ } else if (isModeAwareColor(entry2)) {
3109
+ if (!side) return null;
3110
+ baseRef = entry2[side];
3111
+ } else if (entry2 && typeof entry2 === "object" && "6" in entry2) {
3112
+ const v = entry2["6"];
3113
+ baseRef = typeof v === "string" ? v : void 0;
3114
+ }
3115
+ if (baseRef === void 0) return null;
3116
+ const baseHex = resolveChain(baseRef, side);
3117
+ const a = opacity > 1 ? opacity / 100 : opacity;
3118
+ return hexToRgba(baseHex, a);
3119
+ }
3120
+ const lastDash = ref.lastIndexOf("-");
3121
+ if (lastDash <= 0) return null;
3122
+ const name = ref.slice(0, lastDash);
3123
+ const shade = ref.slice(lastDash + 1);
3124
+ if (!/^\d+$/.test(shade)) return null;
3125
+ const entry = colors[name];
3126
+ if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3127
+ const target = entry[shade];
3128
+ return typeof target === "string" ? target : null;
3129
+ }
3097
3130
  function resolveValue(val) {
3098
- return typeof val === "string" ? resolveChain(val) : { light: resolveChain(val.light), dark: resolveChain(val.dark) };
3131
+ return typeof val === "string" ? resolveChain(val, null) : { light: resolveChain(val.light, "light"), dark: resolveChain(val.dark, "dark") };
3099
3132
  }
3100
3133
  const out = {};
3101
3134
  for (const [key, val] of Object.entries(colors)) {
@@ -2285,6 +2285,18 @@ var effectResolvers = {
2285
2285
  if (!isArbitrary && isNaN(parseFloat(value))) return null;
2286
2286
  const ms = isArbitrary ? value : `${value}ms`;
2287
2287
  return { transitionDelay: ms };
2288
+ },
2289
+ ease: ({ value, isArbitrary }) => {
2290
+ if (!getEffectiveIsWeb()) return null;
2291
+ if (isArbitrary) return { transitionTimingFunction: value };
2292
+ const presets = {
2293
+ linear: "linear",
2294
+ in: "cubic-bezier(0.4, 0, 1, 1)",
2295
+ out: "cubic-bezier(0, 0, 0.2, 1)",
2296
+ "in-out": "cubic-bezier(0.4, 0, 0.2, 1)"
2297
+ };
2298
+ const v = presets[value];
2299
+ return v !== void 0 ? { transitionTimingFunction: v } : null;
2288
2300
  }
2289
2301
  };
2290
2302
 
@@ -3038,30 +3050,51 @@ function deepMerge(base, override) {
3038
3050
  return result;
3039
3051
  }
3040
3052
  var configStore = { resolved: null, listeners: /* @__PURE__ */ new Set(), customVariants: {} };
3041
- function resolveOneRef(ref, colors) {
3042
- const lastDash = ref.lastIndexOf("-");
3043
- if (lastDash <= 0) return null;
3044
- const name = ref.slice(0, lastDash);
3045
- const shade = ref.slice(lastDash + 1);
3046
- if (!/^\d+$/.test(shade)) return null;
3047
- const entry = colors[name];
3048
- if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3049
- const target = entry[shade];
3050
- return typeof target === "string" ? target : null;
3051
- }
3052
3053
  function resolveColorRefs(colors) {
3053
3054
  const MAX_DEPTH = 5;
3054
- function resolveChain(raw) {
3055
+ function resolveChain(raw, side) {
3055
3056
  let current = raw;
3056
3057
  for (let i = 0; i < MAX_DEPTH; i++) {
3057
- const next = resolveOneRef(current, colors);
3058
+ const next = resolveOneRef(current, side);
3058
3059
  if (!next || next === current) break;
3059
3060
  current = next;
3060
3061
  }
3061
3062
  return current;
3062
3063
  }
3064
+ function resolveOneRef(ref, side) {
3065
+ const slashIdx = ref.indexOf("/");
3066
+ if (slashIdx > 0) {
3067
+ const baseName = ref.slice(0, slashIdx);
3068
+ const opacity = Number(ref.slice(slashIdx + 1));
3069
+ if (!Number.isFinite(opacity)) return null;
3070
+ let baseRef;
3071
+ const entry2 = colors[baseName];
3072
+ if (typeof entry2 === "string") {
3073
+ baseRef = entry2;
3074
+ } else if (isModeAwareColor(entry2)) {
3075
+ if (!side) return null;
3076
+ baseRef = entry2[side];
3077
+ } else if (entry2 && typeof entry2 === "object" && "6" in entry2) {
3078
+ const v = entry2["6"];
3079
+ baseRef = typeof v === "string" ? v : void 0;
3080
+ }
3081
+ if (baseRef === void 0) return null;
3082
+ const baseHex = resolveChain(baseRef, side);
3083
+ const a = opacity > 1 ? opacity / 100 : opacity;
3084
+ return hexToRgba(baseHex, a);
3085
+ }
3086
+ const lastDash = ref.lastIndexOf("-");
3087
+ if (lastDash <= 0) return null;
3088
+ const name = ref.slice(0, lastDash);
3089
+ const shade = ref.slice(lastDash + 1);
3090
+ if (!/^\d+$/.test(shade)) return null;
3091
+ const entry = colors[name];
3092
+ if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
3093
+ const target = entry[shade];
3094
+ return typeof target === "string" ? target : null;
3095
+ }
3063
3096
  function resolveValue(val) {
3064
- return typeof val === "string" ? resolveChain(val) : { light: resolveChain(val.light), dark: resolveChain(val.dark) };
3097
+ return typeof val === "string" ? resolveChain(val, null) : { light: resolveChain(val.light, "light"), dark: resolveChain(val.dark, "dark") };
3065
3098
  }
3066
3099
  const out = {};
3067
3100
  for (const [key, val] of Object.entries(colors)) {
package/kbach-react.md CHANGED
@@ -619,6 +619,7 @@ animate-spin / animate-ping / animate-pulse / animate-bounce / animate-none
619
619
  transition / transition-all/none/colors/opacity/shadow/transform
620
620
  duration-75/100/150/200/300/500/700/1000
621
621
  delay-75/100/150/200/300/500/700/1000
622
+ ease-linear/in/out/in-out ease-[cubic-bezier(...)]
622
623
  ```
623
624
 
624
625
  ### Cursor
@@ -740,17 +741,21 @@ extend: {
740
741
  surface: { light: '#ffffff', dark: '#111827' },
741
742
  // each side can itself be an alias — resolved independently
742
743
  accent: { light: 'blue-6', dark: 'blue-4' },
744
+ // or derived from another color at an opacity — 'name/opacity', resolved
745
+ // once here instead of only being computable at runtime via colors.alpha()
746
+ accentSoft: { light: 'accent/30', dark: 'accent/40' },
743
747
  },
744
748
  },
745
749
  },
746
750
  ```
747
751
 
748
752
  ```jsx
749
- <div className="bg-surface text-accent" />
750
- // equivalent to writing bg-white dark:bg-gray-9 text-blue-6 dark:text-blue-4 by hand
753
+ <div className="bg-surface text-accent hover:bg-accentSoft" />
754
+ // equivalent to writing bg-white dark:bg-gray-9 text-blue-6 dark:text-blue-4
755
+ // hover:bg-[rgba(...)] dark:hover:bg-[rgba(...)] by hand
751
756
  ```
752
757
 
753
- Works everywhere a color does — `useColors()` (returns the active side directly), opacity composition (`bg-surface/50`), and per-shade within a scale (`brand: { 6: { light: '#3b82f6', dark: '#60a5fa' } }`). An explicit `dark:`/`light:` modifier stacked on an already mode-aware color is not supported (falls back to the light side) — the whole point is not needing `dark:` for these.
758
+ Works everywhere a color does — `useColors()` (returns the active side directly), opacity composition (`bg-surface/50`), per-shade within a scale (`brand: { 6: { light: '#3b82f6', dark: '#60a5fa' } }`), and stacked under an explicit modifier (`dark:hover:bg-accent` correctly uses the dark side, still scoped to dark mode + hover — the modifier doesn't need to be there in the first place, but it's respected if it is).
754
759
 
755
760
  ### Runtime update
756
761
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.6.36",
3
+ "version": "0.6.39",
4
4
  "description": "React / React Native components and hooks for the Kbach framework",
5
5
  "repository": {
6
6
  "type": "git",