@kbach/react 0.6.39 → 0.6.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,7 +26,6 @@ __export(index_exports, {
26
26
  buildConfig: () => buildConfig,
27
27
  clearCache: () => clearCache,
28
28
  clearPluginModifiers: () => clearPluginModifiers,
29
- customVariants: () => customVariants,
30
29
  defaultColors: () => defaultColors,
31
30
  defaultTheme: () => defaultTheme,
32
31
  disableRuntimeCSS: () => disableRuntimeCSS,
@@ -89,6 +88,11 @@ module.exports = __toCommonJS(index_exports);
89
88
  function isModeAwareColor(v) {
90
89
  return typeof v === "object" && v !== null && "light" in v && "dark" in v;
91
90
  }
91
+ function splitColorShadeRef(ref) {
92
+ const lastDash = ref.lastIndexOf("-");
93
+ if (lastDash <= 0) return null;
94
+ return { name: ref.slice(0, lastDash), shade: ref.slice(lastDash + 1) };
95
+ }
92
96
 
93
97
  // src/core/platform.ts
94
98
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
@@ -165,64 +169,64 @@ var LRUCache = class {
165
169
  // src/core/registry.ts
166
170
  var BUILTIN_MODIFIERS = {
167
171
  // ── Mode ─────────────────────────────────────────────────────────────────
168
- dark: { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
169
- "not-light": { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
170
- light: { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
171
- "not-dark": { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
172
+ dark: { order: 60, darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
173
+ "not-light": { order: 60, darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
174
+ light: { order: 60, darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
175
+ "not-dark": { order: 60, darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
172
176
  // ── Interactive — JS state + CSS pseudo ───────────────────────────────────
173
- hover: { pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
174
- "not-hover": { pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
175
- focus: { pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
176
- "not-focus": { pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
177
- active: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
178
- "not-active": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
179
- pressed: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
180
- "not-pressed": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
181
- disabled: { pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
182
- "not-disabled": { pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
183
- checked: { pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
184
- "not-checked": { pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
185
- visited: { pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
186
- "not-visited": { pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
187
- placeholder: { pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
177
+ hover: { order: 10, pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
178
+ "not-hover": { order: 10, pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
179
+ focus: { order: 20, pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
180
+ "not-focus": { order: 20, pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
181
+ active: { order: 30, pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
182
+ "not-active": { order: 30, pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
183
+ pressed: { order: 30, pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
184
+ "not-pressed": { order: 30, pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
185
+ disabled: { order: 40, pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
186
+ "not-disabled": { order: 40, pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
187
+ checked: { order: 35, pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
188
+ "not-checked": { order: 35, pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
189
+ visited: { order: 5, pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
190
+ "not-visited": { order: 5, pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
191
+ placeholder: { order: 0, pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
188
192
  // ── CSS-only pseudo-classes (structural) ──────────────────────────────────
189
- first: { pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
190
- last: { pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
191
- odd: { pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
192
- even: { pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
193
- only: { pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
194
- "focus-within": { pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
195
- "focus-visible": { pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
193
+ first: { order: 0, pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
194
+ last: { order: 0, pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
195
+ odd: { order: 0, pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
196
+ even: { order: 0, pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
197
+ only: { order: 0, pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
198
+ "focus-within": { order: 15, pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
199
+ "focus-visible": { order: 25, pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
196
200
  // ── CSS-only pseudo-elements ───────────────────────────────────────────────
197
- before: { pseudo: "::before", jsBehavior: "css-only" },
198
- after: { pseudo: "::after", jsBehavior: "css-only" },
199
- selection: { pseudo: "::selection", jsBehavior: "css-only" },
200
- "first-letter": { pseudo: "::first-letter", jsBehavior: "css-only" },
201
- "first-line": { pseudo: "::first-line", jsBehavior: "css-only" },
202
- marker: { pseudo: "::marker", jsBehavior: "css-only" },
201
+ before: { order: 0, pseudo: "::before", jsBehavior: "css-only" },
202
+ after: { order: 0, pseudo: "::after", jsBehavior: "css-only" },
203
+ selection: { order: 0, pseudo: "::selection", jsBehavior: "css-only" },
204
+ "first-letter": { order: 0, pseudo: "::first-letter", jsBehavior: "css-only" },
205
+ "first-line": { order: 0, pseudo: "::first-line", jsBehavior: "css-only" },
206
+ marker: { order: 0, pseudo: "::marker", jsBehavior: "css-only" },
203
207
  // ── Group / peer ancestor selectors (CSS-only) ─────────────────────────────
204
- "group-hover": { ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
205
- "group-focus": { ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
206
- "peer-hover": { ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
207
- "peer-focus": { ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
208
+ "group-hover": { order: 10, ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
209
+ "group-focus": { order: 20, ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
210
+ "peer-hover": { order: 10, ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
211
+ "peer-focus": { order: 20, ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
208
212
  // ── Responsive — both CSS (@media min-width) and JS (breakpoints set) ──────
209
- sm: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
210
- md: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
211
- lg: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
212
- xl: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
213
- "2xl": { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
213
+ sm: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
214
+ md: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
215
+ lg: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
216
+ xl: { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
217
+ "2xl": { order: 50, isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
214
218
  // ── Print media (CSS-only) ─────────────────────────────────────────────────
215
- print: { mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
219
+ print: { order: 70, mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
216
220
  // ── Orientation / accessibility media (CSS-only) ───────────────────────────
217
- landscape: { mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
218
- portrait: { mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
219
- "motion-reduce": { mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
220
- "motion-safe": { mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
221
- "contrast-more": { mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
222
- "contrast-less": { mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
221
+ landscape: { order: 70, mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
222
+ portrait: { order: 70, mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
223
+ "motion-reduce": { order: 70, mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
224
+ "motion-safe": { order: 70, mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
225
+ "contrast-more": { order: 70, mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
226
+ "contrast-less": { order: 70, mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
223
227
  // ── Directionality (CSS-only) ──────────────────────────────────────────────
224
- rtl: { dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
225
- ltr: { dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
228
+ rtl: { order: 80, dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
229
+ ltr: { order: 80, dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
226
230
  };
227
231
  var _pluginModifiers = {};
228
232
  var _allNames = null;
@@ -259,6 +263,8 @@ function getNamedGroupPeerModifier(name) {
259
263
  const pseudo = trigger === "hover" ? ":hover" : ":focus";
260
264
  const combinator = kind === "group" ? " " : " ~ ";
261
265
  const def = {
266
+ // Matches the plain group-hover/group-focus/peer-hover/peer-focus order below.
267
+ order: trigger === "hover" ? 10 : 20,
262
268
  ancestorSelector: `.${kind}\\/${escapedName}${pseudo}${combinator}`,
263
269
  jsBehavior: "css-only",
264
270
  forcesImportant: true
@@ -297,6 +303,15 @@ function getResponsiveModifiers() {
297
303
  }
298
304
  return _responsiveNames;
299
305
  }
306
+ function getModifierOrder(bucketKey) {
307
+ if (bucketKey === "base") return -1;
308
+ let max = 0;
309
+ for (const mod of bucketKey.split(":")) {
310
+ const order = getModifier(mod)?.order ?? 0;
311
+ if (order > max) max = order;
312
+ }
313
+ return max;
314
+ }
300
315
  function matchModifier(name, isDark, state, breakpoints) {
301
316
  return getModifier(name)?.jsMatch?.(isDark, state, breakpoints) ?? false;
302
317
  }
@@ -319,13 +334,11 @@ function resolveColor(value, colors, isArbitrary) {
319
334
  else if (isModeAwareColor(entry)) hex = pickModeAwareFallback(entry);
320
335
  else if (typeof entry === "object" && "6" in entry) hex = pickModeAwareFallback(entry["6"]);
321
336
  } else {
322
- const lastDash = colorPart.lastIndexOf("-");
323
- if (lastDash > 0) {
324
- const colorName = colorPart.slice(0, lastDash);
325
- const shade = colorPart.slice(lastDash + 1);
326
- const scale = colors[colorName];
327
- if (scale && typeof scale === "object" && !isModeAwareColor(scale) && shade in scale) {
328
- const shadeVal = scale[shade];
337
+ const split = splitColorShadeRef(colorPart);
338
+ if (split) {
339
+ const scale = colors[split.name];
340
+ if (scale && typeof scale === "object" && !isModeAwareColor(scale) && split.shade in scale) {
341
+ const shadeVal = scale[split.shade];
329
342
  hex = shadeVal !== void 0 ? pickModeAwareFallback(shadeVal) : null;
330
343
  }
331
344
  }
@@ -466,6 +479,7 @@ function resolveSpacing(value, negative, spacing, isArbitrary) {
466
479
  if (negative) {
467
480
  if (typeof resolved === "number") return -resolved;
468
481
  if (typeof resolved === "string") {
482
+ if (resolved.startsWith("-")) return resolved.slice(1);
469
483
  if (/^\d/.test(resolved)) return `-${resolved}`;
470
484
  if (/^(calc|var|min|max|clamp|env)\s*\(/.test(resolved)) return `calc(-1 * (${resolved}))`;
471
485
  }
@@ -644,7 +658,7 @@ function makeBorderSideResolver(widthProp, colorProp) {
644
658
  if (!value) return { [widthProp]: 1 };
645
659
  if (isArbitrary) {
646
660
  const w2 = toNativeValue(value);
647
- if (typeof w2 === "number") return { [widthProp]: w2 };
661
+ if (typeof w2 === "number") return { [widthProp]: getEffectiveIsWeb() ? value : w2 };
648
662
  return { [colorProp]: value };
649
663
  }
650
664
  const color = resolveColor(value, colors, false);
@@ -665,7 +679,7 @@ var borderResolvers = {
665
679
  if (!value) return { borderWidth: borderWidth["DEFAULT"] ?? 1 };
666
680
  if (isArbitrary) {
667
681
  const w2 = toNativeValue(value);
668
- if (typeof w2 === "number") return { borderWidth: w2 };
682
+ if (typeof w2 === "number") return { borderWidth: getEffectiveIsWeb() ? value : w2 };
669
683
  return { borderColor: value };
670
684
  }
671
685
  const color = resolveColor(value, colors, false);
@@ -864,9 +878,9 @@ var filterResolvers = {
864
878
  const v = isArbitrary ? `contrast(${value})` : `contrast(${parseFloat(value) / 100})`;
865
879
  return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-contrast": v, filter: FILTER_COMPOSE };
866
880
  },
867
- grayscale: ({ value }) => {
881
+ grayscale: ({ value, isArbitrary }) => {
868
882
  if (!getEffectiveIsWeb()) return null;
869
- const v = value === "0" ? "grayscale(0)" : "grayscale(100%)";
883
+ const v = isArbitrary ? `grayscale(${value})` : value === "0" ? "grayscale(0)" : "grayscale(100%)";
870
884
  return { "--kb-grayscale": v, filter: FILTER_COMPOSE };
871
885
  },
872
886
  "hue-rotate": ({ value, negative, isArbitrary }) => {
@@ -875,9 +889,9 @@ var filterResolvers = {
875
889
  if (isNaN(parseFloat(deg)) && !isArbitrary) return null;
876
890
  return { "--kb-hue-rotate": `hue-rotate(${deg})`, filter: FILTER_COMPOSE };
877
891
  },
878
- invert: ({ value }) => {
892
+ invert: ({ value, isArbitrary }) => {
879
893
  if (!getEffectiveIsWeb()) return null;
880
- const v = value === "0" ? "invert(0)" : "invert(100%)";
894
+ const v = isArbitrary ? `invert(${value})` : value === "0" ? "invert(0)" : "invert(100%)";
881
895
  return { "--kb-invert": v, filter: FILTER_COMPOSE };
882
896
  },
883
897
  saturate: ({ value, isArbitrary }) => {
@@ -885,9 +899,9 @@ var filterResolvers = {
885
899
  const v = isArbitrary ? `saturate(${value})` : `saturate(${parseFloat(value) / 100})`;
886
900
  return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-saturate": v, filter: FILTER_COMPOSE };
887
901
  },
888
- sepia: ({ value }) => {
902
+ sepia: ({ value, isArbitrary }) => {
889
903
  if (!getEffectiveIsWeb()) return null;
890
- const v = value === "0" ? "sepia(0)" : "sepia(100%)";
904
+ const v = isArbitrary ? `sepia(${value})` : value === "0" ? "sepia(0)" : "sepia(100%)";
891
905
  return { "--kb-sepia": v, filter: FILTER_COMPOSE };
892
906
  },
893
907
  "drop-shadow": ({ value, isArbitrary }) => {
@@ -938,9 +952,10 @@ var filterResolvers = {
938
952
  const v = isArbitrary ? `contrast(${value})` : `contrast(${parseFloat(value) / 100})`;
939
953
  return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-contrast": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
940
954
  },
941
- "backdrop-grayscale": ({ value }) => {
955
+ "backdrop-grayscale": ({ value, isArbitrary }) => {
942
956
  if (!getEffectiveIsWeb()) return null;
943
- return { "--kb-backdrop-grayscale": value === "0" ? "grayscale(0)" : "grayscale(100%)", backdropFilter: BACKDROP_FILTER_COMPOSE };
957
+ const v = isArbitrary ? `grayscale(${value})` : value === "0" ? "grayscale(0)" : "grayscale(100%)";
958
+ return { "--kb-backdrop-grayscale": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
944
959
  },
945
960
  "backdrop-hue-rotate": ({ value, negative, isArbitrary }) => {
946
961
  if (!getEffectiveIsWeb()) return null;
@@ -948,9 +963,10 @@ var filterResolvers = {
948
963
  if (isNaN(parseFloat(deg)) && !isArbitrary) return null;
949
964
  return { "--kb-backdrop-hue-rotate": `hue-rotate(${deg})`, backdropFilter: BACKDROP_FILTER_COMPOSE };
950
965
  },
951
- "backdrop-invert": ({ value }) => {
966
+ "backdrop-invert": ({ value, isArbitrary }) => {
952
967
  if (!getEffectiveIsWeb()) return null;
953
- return { "--kb-backdrop-invert": value === "0" ? "invert(0)" : "invert(100%)", backdropFilter: BACKDROP_FILTER_COMPOSE };
968
+ const v = isArbitrary ? `invert(${value})` : value === "0" ? "invert(0)" : "invert(100%)";
969
+ return { "--kb-backdrop-invert": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
954
970
  },
955
971
  "backdrop-opacity": ({ value, isArbitrary }) => {
956
972
  if (!getEffectiveIsWeb()) return null;
@@ -962,9 +978,10 @@ var filterResolvers = {
962
978
  const v = isArbitrary ? `saturate(${value})` : `saturate(${parseFloat(value) / 100})`;
963
979
  return isNaN(parseFloat(value)) && !isArbitrary ? null : { "--kb-backdrop-saturate": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
964
980
  },
965
- "backdrop-sepia": ({ value }) => {
981
+ "backdrop-sepia": ({ value, isArbitrary }) => {
966
982
  if (!getEffectiveIsWeb()) return null;
967
- return { "--kb-backdrop-sepia": value === "0" ? "sepia(0)" : "sepia(100%)", backdropFilter: BACKDROP_FILTER_COMPOSE };
983
+ const v = isArbitrary ? `sepia(${value})` : value === "0" ? "sepia(0)" : "sepia(100%)";
984
+ return { "--kb-backdrop-sepia": v, backdropFilter: BACKDROP_FILTER_COMPOSE };
968
985
  },
969
986
  "backdrop-filter": ({ value, isArbitrary }) => {
970
987
  if (!getEffectiveIsWeb()) return null;
@@ -1034,8 +1051,8 @@ var filterResolvers = {
1034
1051
 
1035
1052
  // src/core/resolvers/layout.ts
1036
1053
  var _standalone = null;
1037
- function buildStandalone() {
1038
- const web = getEffectiveIsWeb();
1054
+ var _standaloneWeb = null;
1055
+ function buildStandalone(web) {
1039
1056
  return {
1040
1057
  // Display
1041
1058
  // React Native only supports display:'flex'|'none'. Setting 'flex' explicitly is
@@ -1050,7 +1067,6 @@ function buildStandalone() {
1050
1067
  "inline-block": { display: web ? "inline-block" : "flex" },
1051
1068
  inline: { display: web ? "inline" : "flex" },
1052
1069
  grid: web ? { display: "grid" } : null,
1053
- grd: web ? { display: "grid" } : null,
1054
1070
  "inline-flex": { display: web ? "inline-flex" : "flex" },
1055
1071
  "inline-grid": { display: web ? "inline-grid" : "flex" },
1056
1072
  hidden: { display: "none" },
@@ -1402,7 +1418,11 @@ function buildStandalone() {
1402
1418
  };
1403
1419
  }
1404
1420
  function getStandalone() {
1405
- if (!_standalone) _standalone = buildStandalone();
1421
+ const web = getEffectiveIsWeb();
1422
+ if (!_standalone || _standaloneWeb !== web) {
1423
+ _standalone = buildStandalone(web);
1424
+ _standaloneWeb = web;
1425
+ }
1406
1426
  return _standalone;
1407
1427
  }
1408
1428
  var layoutResolvers = {
@@ -3027,9 +3047,21 @@ function getDefaultFontFamily() {
3027
3047
  }
3028
3048
  var _styleEl = null;
3029
3049
  var _ruleIndexByKey = /* @__PURE__ */ new Map();
3050
+ var _sheetKeys = [];
3051
+ var _ruleOrderByKey = /* @__PURE__ */ new Map();
3052
+ function findInsertionIndex(order) {
3053
+ let lo = 0, hi = _sheetKeys.length;
3054
+ while (lo < hi) {
3055
+ const mid = lo + hi >>> 1;
3056
+ if (_ruleOrderByKey.get(_sheetKeys[mid]) > order) hi = mid;
3057
+ else lo = mid + 1;
3058
+ }
3059
+ return lo;
3060
+ }
3030
3061
  function evictInjectedRule(rule) {
3031
3062
  const idx = _ruleIndexByKey.get(rule);
3032
3063
  _ruleIndexByKey.delete(rule);
3064
+ _ruleOrderByKey.delete(rule);
3033
3065
  if (idx === void 0) return;
3034
3066
  const sheet = _styleEl?.sheet;
3035
3067
  if (!sheet) return;
@@ -3038,6 +3070,7 @@ function evictInjectedRule(rule) {
3038
3070
  } catch {
3039
3071
  return;
3040
3072
  }
3073
+ _sheetKeys.splice(idx, 1);
3041
3074
  for (const [key, i] of _ruleIndexByKey) {
3042
3075
  if (i > idx) _ruleIndexByKey.set(key, i - 1);
3043
3076
  }
@@ -3057,15 +3090,20 @@ function getStyleEl() {
3057
3090
  document.head.appendChild(_styleEl);
3058
3091
  return _styleEl;
3059
3092
  }
3060
- function injectRule(rule) {
3093
+ function injectRule(rule, order) {
3061
3094
  if (isRuntimeCSSDisabled()) return;
3062
3095
  if (_injectedRules.get(rule)) return;
3063
3096
  try {
3064
3097
  const sheet = getStyleEl().sheet;
3065
3098
  if (sheet) {
3066
- const idx = sheet.cssRules.length;
3099
+ const idx = findInsertionIndex(order);
3067
3100
  sheet.insertRule(rule, idx);
3101
+ _sheetKeys.splice(idx, 0, rule);
3102
+ for (const [key, i] of _ruleIndexByKey) {
3103
+ if (i >= idx) _ruleIndexByKey.set(key, i + 1);
3104
+ }
3068
3105
  _ruleIndexByKey.set(rule, idx);
3106
+ _ruleOrderByKey.set(rule, order);
3069
3107
  _injectedRules.set(rule, true);
3070
3108
  }
3071
3109
  } catch {
@@ -3257,9 +3295,10 @@ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens
3257
3295
  rules.push(rule);
3258
3296
  return rules;
3259
3297
  }
3260
- function injectClassRule(cls, bucketKey, styles, darkMode, important) {
3298
+ function injectClassRule(cls, bucketKey, styles, darkMode, important, order) {
3261
3299
  const cssRules = buildClassCSSRules(cls, bucketKey, styles, darkMode, important, getGlobalScreens());
3262
- for (const r of cssRules) injectRule(r);
3300
+ for (const r of cssRules) injectRule(r, order);
3301
+ return cssRules;
3263
3302
  }
3264
3303
  function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
3265
3304
  const rules = [];
@@ -3273,10 +3312,16 @@ function generateClassCSS(classString, theme, darkMode = "attribute", screens =
3273
3312
  }
3274
3313
  function resolve(classString, theme, darkMode = "attribute") {
3275
3314
  const cache = getThemeCache(theme);
3276
- const cacheKey = `${classString}::${darkMode}`;
3315
+ const cacheKey = `${classString}::${darkMode}::${getEffectiveIsWeb() ? "web" : "native"}`;
3277
3316
  const cached = cache.get(cacheKey);
3278
- if (cached) return cached;
3317
+ if (cached) {
3318
+ if (isWeb) {
3319
+ for (const { rule, order } of cached.rules) injectRule(rule, order);
3320
+ }
3321
+ return cached.result;
3322
+ }
3279
3323
  const result = {};
3324
+ const rules = [];
3280
3325
  const onWeb = isWeb;
3281
3326
  for (const parsed of parseClasses(expandModeAwareColorClasses(classString, theme.colors))) {
3282
3327
  const styles = resolveUtility(parsed, theme);
@@ -3290,10 +3335,13 @@ function resolve(classString, theme, darkMode = "attribute") {
3290
3335
  if (!result[bucketKey]) result[bucketKey] = {};
3291
3336
  Object.assign(result[bucketKey], styles);
3292
3337
  if (onWeb) {
3293
- injectClassRule(parsed.original, bucketKey, styles, darkMode, parsed.important);
3338
+ const order = getModifierOrder(bucketKey);
3339
+ for (const r of injectClassRule(parsed.original, bucketKey, styles, darkMode, parsed.important, order)) {
3340
+ rules.push({ rule: r, order });
3341
+ }
3294
3342
  }
3295
3343
  }
3296
- cache.set(cacheKey, result);
3344
+ cache.set(cacheKey, { result, rules });
3297
3345
  return result;
3298
3346
  }
3299
3347
  function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new Set()) {
@@ -3347,6 +3395,8 @@ function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new
3347
3395
  function clearCache() {
3348
3396
  _injectedRules.clear();
3349
3397
  _ruleIndexByKey.clear();
3398
+ _ruleOrderByKey.clear();
3399
+ _sheetKeys.length = 0;
3350
3400
  if (_styleEl) {
3351
3401
  _styleEl.remove();
3352
3402
  _styleEl = null;
@@ -3374,7 +3424,7 @@ function deepMerge(base, override) {
3374
3424
  }
3375
3425
  return result;
3376
3426
  }
3377
- var configStore = { resolved: null, listeners: /* @__PURE__ */ new Set(), customVariants: {} };
3427
+ var configStore = { resolved: null, listeners: /* @__PURE__ */ new Set() };
3378
3428
  function getConfig() {
3379
3429
  if (configStore.resolved) return configStore.resolved;
3380
3430
  configStore.resolved = buildConfig({});
@@ -3416,10 +3466,9 @@ function resolveColorRefs(colors) {
3416
3466
  const a = opacity > 1 ? opacity / 100 : opacity;
3417
3467
  return hexToRgba(baseHex, a);
3418
3468
  }
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);
3469
+ const split = splitColorShadeRef(ref);
3470
+ if (!split) return null;
3471
+ const { name, shade } = split;
3423
3472
  if (!/^\d+$/.test(shade)) return null;
3424
3473
  const entry = colors[name];
3425
3474
  if (!entry || typeof entry !== "object" || isModeAwareColor(entry)) return null;
@@ -3481,7 +3530,6 @@ function buildConfig(userConfig) {
3481
3530
  clearPluginUtilities();
3482
3531
  clearPluginModifiers();
3483
3532
  }
3484
- for (const k of Object.keys(configStore.customVariants)) delete configStore.customVariants[k];
3485
3533
  const pluginAPI = makePluginAPI(resolved.theme);
3486
3534
  for (const plugin of resolved.plugins) {
3487
3535
  plugin(pluginAPI);
@@ -3510,8 +3558,6 @@ function makePluginAPI(theme) {
3510
3558
  },
3511
3559
  addVariant(name, selectorOrDef) {
3512
3560
  const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
3513
- const selector = typeof selectorOrDef === "string" ? selectorOrDef : selectorOrDef.pseudo ?? selectorOrDef.mediaQuery ?? selectorOrDef.ancestorSelector ?? null;
3514
- if (selector !== null && selector !== name) customVariants[name] = selector;
3515
3561
  registerModifier(name, def);
3516
3562
  },
3517
3563
  theme(path, defaultValue) {
@@ -3544,7 +3590,6 @@ function initConfig(userConfig) {
3544
3590
  if (configStore._src === userConfig) return;
3545
3591
  updateConfig(userConfig);
3546
3592
  }
3547
- var customVariants = configStore.customVariants;
3548
3593
 
3549
3594
  // src/core/darkModeStore.ts
3550
3595
  var store2 = { isDark: false, notifiedIsDark: false, subscribers: /* @__PURE__ */ new Set() };
@@ -3572,7 +3617,6 @@ function subscribeGlobalDarkMode(callback) {
3572
3617
  buildConfig,
3573
3618
  clearCache,
3574
3619
  clearPluginModifiers,
3575
- customVariants,
3576
3620
  defaultColors,
3577
3621
  defaultTheme,
3578
3622
  disableRuntimeCSS,
package/dist/index.js CHANGED
@@ -184,6 +184,7 @@ var _mountedProviderCount = 0;
184
184
  var _warnedMultipleProviders = false;
185
185
  var _mountedConfigOverrideCount = 0;
186
186
  var _warnedConfigOverride = false;
187
+ var _warnedMediaModeToggle = false;
187
188
  function loadPersistedMode() {
188
189
  try {
189
190
  if (import_core2.isWeb) return localStorage.getItem(STORAGE_KEY);
@@ -262,6 +263,9 @@ function ThemeProvider({
262
263
  return () => {
263
264
  _mountedProviderCount--;
264
265
  if (configOverride) _mountedConfigOverrideCount--;
266
+ if (_prevConfigOverrideRef.current !== void 0 && _mountedProviderCount === 0) {
267
+ (0, import_core2.resetConfig)();
268
+ }
265
269
  };
266
270
  }, []);
267
271
  const [webWidth, setWebWidth] = (0, import_react5.useState)(0);
@@ -328,9 +332,15 @@ function ThemeProvider({
328
332
  return () => window.removeEventListener("storage", onStorage);
329
333
  }, [disablePersistence]);
330
334
  const setMode = (0, import_react5.useCallback)((next) => {
335
+ if (process.env.NODE_ENV !== "production" && import_core2.isWeb && resolvedConfig.darkMode === "media" && !_warnedMediaModeToggle) {
336
+ _warnedMediaModeToggle = true;
337
+ (0, import_core2.kbachWarn)(
338
+ 'setMode()/toggle() was called while darkMode is "media" \u2014 the resolved mode/isDark from useTheme()/useIsDark() will update, but the actual CSS stays driven by prefers-color-scheme and will not change to match. Use darkMode: "attribute" or "class" if the app needs manual toggling.'
339
+ );
340
+ }
331
341
  _setMode(next);
332
342
  if (!disablePersistence) persistMode(next);
333
- }, [disablePersistence]);
343
+ }, [disablePersistence, resolvedConfig.darkMode]);
334
344
  const toggle = (0, import_react5.useCallback)(() => {
335
345
  setMode(mode === "dark" || mode === "system" && systemScheme === "dark" ? "light" : "dark");
336
346
  }, [mode, systemScheme, setMode]);
@@ -499,6 +509,10 @@ function stripWebOnlyProps(s) {
499
509
  delete s.position;
500
510
  }
501
511
  }
512
+ function composeNativeStyle(computed, userStyle) {
513
+ if (!userStyle) return computed;
514
+ return Array.isArray(userStyle) ? [computed, ...userStyle] : [computed, userStyle];
515
+ }
502
516
 
503
517
  // src/web-substitute.ts
504
518
  var _rnToHtml = {
@@ -610,8 +624,9 @@ var _rnOnlyProps = /* @__PURE__ */ new Set([
610
624
  "lineBreakStrategyIOS",
611
625
  // TextInput
612
626
  "multiline",
613
- "resizeMode",
614
- // handled separately
627
+ // NOTE: 'resizeMode' (Image's prop, not TextInput's) deliberately does NOT
628
+ // go here — it's handled below in the isImage branch (mapped to CSS
629
+ // object-fit). Blacklisting it here would make that branch unreachable.
615
630
  "blurOnSubmit",
616
631
  "clearButtonMode",
617
632
  "clearTextOnFocus",
@@ -737,7 +752,7 @@ function transformToWebProps(originalName, tag, props) {
737
752
  continue;
738
753
  }
739
754
  if (k === "keyboardType") {
740
- if (!("type" in props) && !("secureTextEntry" in props)) {
755
+ if (!("type" in props) && !props.secureTextEntry) {
741
756
  const mapped = _keyboardTypeMap[v];
742
757
  if (mapped) out.type = mapped;
743
758
  }
@@ -753,7 +768,7 @@ function transformToWebProps(originalName, tag, props) {
753
768
  }
754
769
  }
755
770
  if (isScrollable && k === "horizontal") {
756
- if (v) pendingStyle = { display: "flex", flexDirection: "row", overflowX: "auto" };
771
+ if (v) pendingStyle = { ...pendingStyle ?? {}, display: "flex", flexDirection: "row", overflowX: "auto" };
757
772
  continue;
758
773
  }
759
774
  if (k === "pointerEvents") {
@@ -861,9 +876,10 @@ function styled(Component, baseClasses = "") {
861
876
  const needsWidth = hasResponsiveBuckets(resolved);
862
877
  const width = useConditionalWidth(needsWidth && !isWebPlatform);
863
878
  const breakpoints = needsWidth ? (0, import_core7.getActiveBreakpoints)(width) : EMPTY_BREAKPOINTS;
879
+ const screens = (0, import_core7.getGlobalScreens)();
864
880
  const computedStyle = (0, import_react6.useMemo)(
865
881
  () => isWebPlatform ? {} : (0, import_core7.flatten)(resolved, isDark, { pressed, hover: hovered, focus: focused, disabled, checked }, breakpoints),
866
- [resolved, isDark, pressed, hovered, focused, disabled, checked, width]
882
+ [resolved, isDark, pressed, hovered, focused, disabled, checked, width, screens]
867
883
  // eslint-disable-line react-hooks/exhaustive-deps
868
884
  );
869
885
  const webTag = isWebPlatform ? getWebTag(Component, rest) : null;
@@ -872,7 +888,7 @@ function styled(Component, baseClasses = "") {
872
888
  const compensation = getImpliedRNStyle(webTag, resolved.base);
873
889
  if (!compensation) return flatStyleProp;
874
890
  return flatStyleProp ? { ...compensation, ...flatStyleProp } : compensation;
875
- })() : styleProp ? Array.isArray(styleProp) ? [computedStyle, ...styleProp] : [computedStyle, styleProp] : computedStyle;
891
+ })() : composeNativeStyle(computedStyle, styleProp);
876
892
  const effectiveComponent = webTag ?? Component;
877
893
  const componentName2 = Component.displayName ?? Component.name ?? "";
878
894
  const effectiveRest = webTag && componentName2 ? transformToWebProps(componentName2, webTag, rest) : rest;
@@ -1012,6 +1028,7 @@ var InteractiveWrapper = (0, import_react9.forwardRef)(
1012
1028
  const needsWidth = hasResponsiveBuckets(resolvedStyle);
1013
1029
  const width = useConditionalWidth(needsWidth && !isWebPlatform);
1014
1030
  const breakpoints = needsWidth ? (0, import_core10.getActiveBreakpoints)(width) : EMPTY_BREAKPOINTS;
1031
+ const screens = (0, import_core10.getGlobalScreens)();
1015
1032
  const [pressed, setPressed] = (0, import_react9.useState)(false);
1016
1033
  const [hovered, setHovered] = (0, import_react9.useState)(false);
1017
1034
  const [focused, setFocused] = (0, import_react9.useState)(false);
@@ -1055,10 +1072,10 @@ var InteractiveWrapper = (0, import_react9.forwardRef)(
1055
1072
  if (isNonStringComponent) stripWebOnlyProps(s);
1056
1073
  return s;
1057
1074
  },
1058
- [resolvedStyle, isDark, pressed, hovered, focused, width, disabled, checked, isNonStringComponent]
1075
+ [resolvedStyle, isDark, pressed, hovered, focused, width, screens, disabled, checked, isNonStringComponent]
1059
1076
  );
1060
1077
  const skipComputedInline = isWebPlatform;
1061
- const finalStyle = skipComputedInline ? styleProp ?? void 0 : styleProp ? Array.isArray(styleProp) ? [computedStyle, ...styleProp] : [computedStyle, styleProp] : computedStyle;
1078
+ const finalStyle = skipComputedInline ? styleProp ?? void 0 : composeNativeStyle(computedStyle, styleProp);
1062
1079
  const componentProps = {
1063
1080
  ref,
1064
1081
  ...restForComponent,