@kbach/react 0.3.4 → 0.3.5

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.
package/dist/index.js CHANGED
@@ -47,10 +47,12 @@ __export(index_exports, {
47
47
  resolve: () => resolve,
48
48
  styled: () => styled,
49
49
  updateConfig: () => updateConfig,
50
+ useBreakpoint: () => useBreakpoint,
50
51
  useColors: () => useColors,
51
52
  useGlobalDarkMode: () => useGlobalDarkMode,
52
53
  useIsDark: () => useIsDark,
53
54
  useResolvedStyle: () => useResolvedStyle,
55
+ useResponsive: () => useResponsive,
54
56
  useStyles: () => useStyles,
55
57
  useTheme: () => useTheme,
56
58
  wrapColors: () => wrapColors
@@ -1966,6 +1968,48 @@ function getPluginStandaloneMap() {
1966
1968
  return PLUGIN_STANDALONE;
1967
1969
  }
1968
1970
 
1971
+ // src/core/responsiveStore.ts
1972
+ var RESPONSIVE_KEY = "__kbach_responsive__";
1973
+ function getStore() {
1974
+ const g = globalThis;
1975
+ if (!g[RESPONSIVE_KEY]) {
1976
+ g[RESPONSIVE_KEY] = { width: 0, screens: {}, listeners: /* @__PURE__ */ new Set() };
1977
+ }
1978
+ return g[RESPONSIVE_KEY];
1979
+ }
1980
+ function syncGlobalWidth(width) {
1981
+ getStore().width = width;
1982
+ }
1983
+ function syncGlobalScreens(screens) {
1984
+ getStore().screens = screens;
1985
+ }
1986
+ function getGlobalScreens() {
1987
+ return getStore().screens;
1988
+ }
1989
+ function setGlobalWidth(width) {
1990
+ const store = getStore();
1991
+ if (store.width === width) return;
1992
+ store.width = width;
1993
+ for (const l of store.listeners) l(width);
1994
+ }
1995
+ function getGlobalWidth() {
1996
+ return getStore().width;
1997
+ }
1998
+ function subscribeGlobalWidth(listener) {
1999
+ const store = getStore();
2000
+ store.listeners.add(listener);
2001
+ return () => store.listeners.delete(listener);
2002
+ }
2003
+ function getActiveBreakpoints(width) {
2004
+ const store = getStore();
2005
+ const w = width ?? store.width;
2006
+ const active = /* @__PURE__ */ new Set();
2007
+ for (const [name, minW] of Object.entries(store.screens)) {
2008
+ if (typeof minW === "number" && w >= minW) active.add(name);
2009
+ }
2010
+ return active;
2011
+ }
2012
+
1969
2013
  // src/core/resolver.ts
1970
2014
  var styleCache = new LRUCache(1e4);
1971
2015
  var _styleEl = null;
@@ -2016,6 +2060,7 @@ var GROUP_PEER_PREFIX = {
2016
2060
  "peer-focus": ".peer:focus ~"
2017
2061
  };
2018
2062
  var MODE_MODS = /* @__PURE__ */ new Set(["dark", "light", "not-dark", "not-light"]);
2063
+ var RESPONSIVE_MODS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
2019
2064
  function injectClassRule(cls, bucketKey, styles, darkMode) {
2020
2065
  const cssDecls = styleValueToCSS(styles);
2021
2066
  if (!cssDecls) return;
@@ -2025,10 +2070,12 @@ function injectClassRule(cls, bucketKey, styles, darkMode) {
2025
2070
  return;
2026
2071
  }
2027
2072
  const mods = bucketKey.split(":");
2028
- const hasDark = mods.includes("dark") || mods.includes("not-light");
2029
- const hasLight = mods.includes("light") || mods.includes("not-dark");
2030
- const ancestorMods = mods.filter((m) => m in GROUP_PEER_PREFIX);
2031
- const pseudoMods = mods.filter((m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX));
2073
+ const responsiveMods = mods.filter((m) => RESPONSIVE_MODS.has(m));
2074
+ const nonResponsiveMods = mods.filter((m) => !RESPONSIVE_MODS.has(m));
2075
+ const hasDark = nonResponsiveMods.includes("dark") || nonResponsiveMods.includes("not-light");
2076
+ const hasLight = nonResponsiveMods.includes("light") || nonResponsiveMods.includes("not-dark");
2077
+ const ancestorMods = nonResponsiveMods.filter((m) => m in GROUP_PEER_PREFIX);
2078
+ const pseudoMods = nonResponsiveMods.filter((m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX));
2032
2079
  const pseudoSuffix = pseudoMods.map((p) => MODIFIER_TO_PSEUDO[p] ?? `:${p}`).join("");
2033
2080
  const elementSelector = `.${escaped}${pseudoSuffix}`;
2034
2081
  const ancestorPrefix = ancestorMods.length ? ancestorMods.map((m) => GROUP_PEER_PREFIX[m]).join(" ") + " " : "";
@@ -2053,6 +2100,13 @@ function injectClassRule(cls, bucketKey, styles, darkMode) {
2053
2100
  } else {
2054
2101
  rule = `${selector} { ${cssDecls} }`;
2055
2102
  }
2103
+ if (responsiveMods.length > 0) {
2104
+ const screens = getGlobalScreens();
2105
+ const minWidth = Math.max(...responsiveMods.map((m) => screens[m] ?? 0));
2106
+ if (minWidth > 0) {
2107
+ rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
2108
+ }
2109
+ }
2056
2110
  injectRule(rule);
2057
2111
  }
2058
2112
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
@@ -2121,18 +2175,18 @@ function resolve(classString, theme, darkMode = "attribute") {
2121
2175
  }
2122
2176
  return result;
2123
2177
  }
2124
- function flatten(resolved, isDark, state = {}) {
2178
+ function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new Set()) {
2125
2179
  const result = { ...resolved.base ?? {} };
2126
2180
  for (const [key, styles] of Object.entries(resolved)) {
2127
2181
  if (key === "base" || !styles) continue;
2128
2182
  const mods = key.split(":");
2129
- if (matchesMods(mods, isDark, state)) {
2183
+ if (matchesMods(mods, isDark, state, breakpoints)) {
2130
2184
  Object.assign(result, styles);
2131
2185
  }
2132
2186
  }
2133
2187
  return result;
2134
2188
  }
2135
- function matchesMods(mods, isDark, state) {
2189
+ function matchesMods(mods, isDark, state, breakpoints) {
2136
2190
  return mods.every((mod) => {
2137
2191
  switch (mod) {
2138
2192
  case "dark":
@@ -2170,6 +2224,12 @@ function matchesMods(mods, isDark, state) {
2170
2224
  return !state.visited;
2171
2225
  case "placeholder":
2172
2226
  return !!state.placeholder;
2227
+ case "sm":
2228
+ case "md":
2229
+ case "lg":
2230
+ case "xl":
2231
+ case "2xl":
2232
+ return breakpoints.has(mod);
2173
2233
  default:
2174
2234
  return false;
2175
2235
  }
@@ -2329,7 +2389,7 @@ var customVariants = new Proxy(
2329
2389
 
2330
2390
  // src/core/darkModeStore.ts
2331
2391
  var KEY = "__kbach_dark_store__";
2332
- function getStore() {
2392
+ function getStore2() {
2333
2393
  const g = globalThis;
2334
2394
  if (!g[KEY]) {
2335
2395
  g[KEY] = { isDark: false, lastNotified: false, subscribers: /* @__PURE__ */ new Set() };
@@ -2337,20 +2397,20 @@ function getStore() {
2337
2397
  return g[KEY];
2338
2398
  }
2339
2399
  function syncGlobalDarkMode(isDark) {
2340
- getStore().isDark = isDark;
2400
+ getStore2().isDark = isDark;
2341
2401
  }
2342
2402
  function setGlobalDarkMode(isDark) {
2343
- const store = getStore();
2403
+ const store = getStore2();
2344
2404
  store.isDark = isDark;
2345
2405
  if (store.lastNotified === isDark) return;
2346
2406
  store.lastNotified = isDark;
2347
2407
  for (const sub of store.subscribers) sub();
2348
2408
  }
2349
2409
  function getGlobalDarkMode() {
2350
- return getStore().isDark;
2410
+ return getStore2().isDark;
2351
2411
  }
2352
2412
  function subscribeGlobalDarkMode(callback) {
2353
- const store = getStore();
2413
+ const store = getStore2();
2354
2414
  store.subscribers.add(callback);
2355
2415
  return () => store.subscribers.delete(callback);
2356
2416
  }
@@ -2386,12 +2446,36 @@ function ThemeProvider({
2386
2446
  children,
2387
2447
  defaultMode = "system",
2388
2448
  colorScheme,
2449
+ windowWidth: windowWidthProp,
2389
2450
  config: configOverride,
2390
2451
  disablePersistence = false
2391
2452
  }) {
2392
2453
  const [resolvedConfig, setResolvedConfig] = (0, import_react3.useState)(
2393
2454
  () => configOverride ? buildConfig(configOverride) : getConfig()
2394
2455
  );
2456
+ const [webWidth, setWebWidth] = (0, import_react3.useState)(
2457
+ () => isWeb && typeof window !== "undefined" ? window.innerWidth : 0
2458
+ );
2459
+ const effectiveWidth = windowWidthProp ?? (isWeb ? webWidth : 0);
2460
+ syncGlobalWidth(effectiveWidth);
2461
+ syncGlobalScreens(resolvedConfig.theme.screens);
2462
+ (0, import_react3.useEffect)(() => {
2463
+ if (!isWeb || typeof window === "undefined") return;
2464
+ let raf = 0;
2465
+ const update = () => {
2466
+ cancelAnimationFrame(raf);
2467
+ raf = requestAnimationFrame(() => {
2468
+ const w = window.innerWidth;
2469
+ setWebWidth(w);
2470
+ setGlobalWidth(w);
2471
+ });
2472
+ };
2473
+ window.addEventListener("resize", update);
2474
+ return () => {
2475
+ window.removeEventListener("resize", update);
2476
+ cancelAnimationFrame(raf);
2477
+ };
2478
+ }, []);
2395
2479
  const [webScheme, setWebScheme] = (0, import_react3.useState)(() => {
2396
2480
  if (isWeb && typeof window !== "undefined") {
2397
2481
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -2660,33 +2744,59 @@ function styled(Component, baseClasses = "") {
2660
2744
  }
2661
2745
 
2662
2746
  // src/useStyles.ts
2663
- var import_react6 = require("react");
2747
+ var import_react7 = require("react");
2748
+
2749
+ // src/useGlobalWidth.ts
2750
+ var import_react6 = __toESM(require("react"));
2751
+ var useSyncExternalStore = import_react6.default.useSyncExternalStore ?? function useSyncExternalStoreFallback(subscribe, getSnapshot, _getServerSnapshot) {
2752
+ const [, forceUpdate] = import_react6.default.useReducer((n) => n + 1, 0);
2753
+ import_react6.default.useEffect(() => subscribe(forceUpdate), [subscribe]);
2754
+ return getSnapshot();
2755
+ };
2756
+ var NOOP_SUB = (_) => () => {
2757
+ };
2758
+ var ZERO_SNAP = () => 0;
2759
+ var EMPTY_BREAKPOINTS = /* @__PURE__ */ new Set();
2760
+ function useGlobalWidth() {
2761
+ return useSyncExternalStore(subscribeGlobalWidth, getGlobalWidth, ZERO_SNAP);
2762
+ }
2763
+ function useConditionalWidth(active) {
2764
+ return useSyncExternalStore(
2765
+ active ? subscribeGlobalWidth : NOOP_SUB,
2766
+ active ? getGlobalWidth : ZERO_SNAP,
2767
+ ZERO_SNAP
2768
+ );
2769
+ }
2770
+
2771
+ // src/useStyles.ts
2664
2772
  function useStyles(classString, state = {}) {
2665
2773
  const { isDark, config } = useTheme();
2774
+ const width = useGlobalWidth();
2775
+ const breakpoints = isWeb ? EMPTY_BREAKPOINTS : getActiveBreakpoints(width);
2666
2776
  const normalised = Array.isArray(classString) ? classString.join(" ") : classString;
2667
- return (0, import_react6.useMemo)(() => {
2777
+ return (0, import_react7.useMemo)(() => {
2668
2778
  const resolved = resolve(normalised, config.theme, config.darkMode);
2669
- return flatten(resolved, isDark, state);
2670
- }, [normalised, isDark, config, state.hover, state.focus, state.pressed, state.active, state.disabled, state.checked, state.visited, state.placeholder]);
2779
+ return flatten(resolved, isDark, state, breakpoints);
2780
+ }, [normalised, isDark, config, width, state.hover, state.focus, state.pressed, state.active, state.disabled, state.checked, state.visited, state.placeholder]);
2671
2781
  }
2672
2782
  function useResolvedStyle(classString) {
2673
2783
  const { config } = useTheme();
2674
2784
  const normalised = Array.isArray(classString) ? classString.join(" ") : classString;
2675
- return (0, import_react6.useMemo)(
2785
+ return (0, import_react7.useMemo)(
2676
2786
  () => resolve(normalised, config.theme, config.darkMode),
2677
2787
  [normalised, config]
2678
2788
  );
2679
2789
  }
2680
2790
 
2681
2791
  // src/useGlobalDarkMode.ts
2682
- var import_react7 = __toESM(require("react"));
2683
- var useSyncExternalStore = import_react7.default.useSyncExternalStore ?? function useSyncExternalStoreFallback(subscribe, getSnapshot, _getServerSnapshot) {
2684
- const [, forceUpdate] = import_react7.default.useReducer((n) => n + 1, 0);
2685
- import_react7.default.useEffect(() => subscribe(forceUpdate), [subscribe]);
2792
+ var import_react8 = __toESM(require("react"));
2793
+ var useSyncExternalStore2 = import_react8.default.useSyncExternalStore ?? function useSyncExternalStoreFallback2(subscribe, getSnapshot, _getServerSnapshot) {
2794
+ const [, forceUpdate] = import_react8.default.useReducer((n) => n + 1, 0);
2795
+ import_react8.default.useEffect(() => subscribe(forceUpdate), [subscribe]);
2686
2796
  return getSnapshot();
2687
2797
  };
2688
2798
  function useGlobalDarkMode() {
2689
- return useSyncExternalStore(
2799
+ return useSyncExternalStore2(
2690
2800
  subscribeGlobalDarkMode,
2691
2801
  getGlobalDarkMode,
2692
2802
  () => false
@@ -2694,15 +2804,47 @@ function useGlobalDarkMode() {
2694
2804
  );
2695
2805
  }
2696
2806
 
2807
+ // src/useBreakpoint.ts
2808
+ function useBreakpoint() {
2809
+ const { config } = useTheme();
2810
+ const width = useGlobalWidth();
2811
+ const screens = config.theme.screens;
2812
+ const sorted = Object.entries(screens).filter(([, v]) => typeof v === "number").sort(([, a], [, b]) => b - a);
2813
+ for (const [name, minW] of sorted) {
2814
+ if (width >= minW) return name;
2815
+ }
2816
+ return "xs";
2817
+ }
2818
+ function useResponsive() {
2819
+ const { config } = useTheme();
2820
+ const width = useGlobalWidth();
2821
+ const screens = config.theme.screens;
2822
+ const result = {};
2823
+ for (const [name, minW] of Object.entries(screens)) {
2824
+ if (typeof minW === "number") result[name] = width >= minW;
2825
+ }
2826
+ return result;
2827
+ }
2828
+
2697
2829
  // src/InteractiveWrapper.tsx
2698
- var import_react8 = __toESM(require("react"));
2830
+ var import_react9 = __toESM(require("react"));
2699
2831
  function chain(original, extra) {
2700
2832
  return (...args) => {
2701
2833
  original?.(...args);
2702
2834
  extra();
2703
2835
  };
2704
2836
  }
2705
- var InteractiveWrapper = (0, import_react8.forwardRef)(
2837
+ var RESPONSIVE_MODS2 = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
2838
+ function hasResponsiveBuckets(resolved) {
2839
+ for (const key of Object.keys(resolved)) {
2840
+ if (key === "base") continue;
2841
+ for (const mod of key.split(":")) {
2842
+ if (RESPONSIVE_MODS2.has(mod)) return true;
2843
+ }
2844
+ }
2845
+ return false;
2846
+ }
2847
+ var InteractiveWrapper = (0, import_react9.forwardRef)(
2706
2848
  function InteractiveWrapper2({
2707
2849
  Component,
2708
2850
  resolvedStyle,
@@ -2717,18 +2859,22 @@ var InteractiveWrapper = (0, import_react8.forwardRef)(
2717
2859
  ...rest
2718
2860
  }, ref) {
2719
2861
  const isDark = useGlobalDarkMode();
2720
- const [pressed, setPressed] = (0, import_react8.useState)(false);
2721
- const [hovered, setHovered] = (0, import_react8.useState)(false);
2722
- const [focused, setFocused] = (0, import_react8.useState)(false);
2723
- const handlePressIn = (0, import_react8.useCallback)(chain(onPressIn, () => setPressed(true)), [onPressIn]);
2724
- const handlePressOut = (0, import_react8.useCallback)(chain(onPressOut, () => setPressed(false)), [onPressOut]);
2725
- const handleMouseEnter = (0, import_react8.useCallback)(chain(onMouseEnter, () => setHovered(true)), [onMouseEnter]);
2726
- const handleMouseLeave = (0, import_react8.useCallback)(chain(onMouseLeave, () => setHovered(false)), [onMouseLeave]);
2727
- const handleFocus = (0, import_react8.useCallback)(chain(onFocus, () => setFocused(true)), [onFocus]);
2728
- const handleBlur = (0, import_react8.useCallback)(chain(onBlur, () => setFocused(false)), [onBlur]);
2729
- const computedStyle = (0, import_react8.useMemo)(
2730
- () => flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused }),
2731
- [resolvedStyle, isDark, pressed, hovered, focused]
2862
+ const needsWidth = !isWeb && hasResponsiveBuckets(resolvedStyle);
2863
+ const width = useConditionalWidth(needsWidth);
2864
+ const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
2865
+ const [pressed, setPressed] = (0, import_react9.useState)(false);
2866
+ const [hovered, setHovered] = (0, import_react9.useState)(false);
2867
+ const [focused, setFocused] = (0, import_react9.useState)(false);
2868
+ const handlePressIn = (0, import_react9.useCallback)(chain(onPressIn, () => setPressed(true)), [onPressIn]);
2869
+ const handlePressOut = (0, import_react9.useCallback)(chain(onPressOut, () => setPressed(false)), [onPressOut]);
2870
+ const handleMouseEnter = (0, import_react9.useCallback)(chain(onMouseEnter, () => setHovered(true)), [onMouseEnter]);
2871
+ const handleMouseLeave = (0, import_react9.useCallback)(chain(onMouseLeave, () => setHovered(false)), [onMouseLeave]);
2872
+ const handleFocus = (0, import_react9.useCallback)(chain(onFocus, () => setFocused(true)), [onFocus]);
2873
+ const handleBlur = (0, import_react9.useCallback)(chain(onBlur, () => setFocused(false)), [onBlur]);
2874
+ const computedStyle = (0, import_react9.useMemo)(
2875
+ () => flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused }, breakpoints),
2876
+ [resolvedStyle, isDark, pressed, hovered, focused, width]
2877
+ // eslint-disable-line react-hooks/exhaustive-deps
2732
2878
  );
2733
2879
  const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
2734
2880
  const { children, ...restWithoutChildren } = rest;
@@ -2744,7 +2890,7 @@ var InteractiveWrapper = (0, import_react8.forwardRef)(
2744
2890
  onFocus: handleFocus,
2745
2891
  onBlur: handleBlur
2746
2892
  };
2747
- return Array.isArray(children) ? import_react8.default.createElement(Component, componentProps, ...children) : import_react8.default.createElement(Component, componentProps, children);
2893
+ return Array.isArray(children) ? import_react9.default.createElement(Component, componentProps, ...children) : import_react9.default.createElement(Component, componentProps, children);
2748
2894
  }
2749
2895
  );
2750
2896
  InteractiveWrapper.displayName = "Kbach.InteractiveWrapper";
@@ -2780,10 +2926,12 @@ function cx(...classes) {
2780
2926
  resolve,
2781
2927
  styled,
2782
2928
  updateConfig,
2929
+ useBreakpoint,
2783
2930
  useColors,
2784
2931
  useGlobalDarkMode,
2785
2932
  useIsDark,
2786
2933
  useResolvedStyle,
2934
+ useResponsive,
2787
2935
  useStyles,
2788
2936
  useTheme,
2789
2937
  wrapColors
package/dist/index.mjs CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
+ EMPTY_BREAKPOINTS,
2
3
  InteractiveWrapper,
3
4
  __require,
4
5
  buildConfig,
5
6
  defaultColors,
6
7
  defaultTheme,
7
8
  flatten,
9
+ getActiveBreakpoints,
8
10
  getConfig,
9
11
  initConfig,
10
12
  isWeb,
@@ -13,10 +15,14 @@ import {
13
15
  parseClasses,
14
16
  resolve,
15
17
  setGlobalDarkMode,
18
+ setGlobalWidth,
16
19
  syncGlobalDarkMode,
20
+ syncGlobalScreens,
21
+ syncGlobalWidth,
17
22
  updateConfig,
18
- useGlobalDarkMode
19
- } from "./chunk-ADRZPFQC.mjs";
23
+ useGlobalDarkMode,
24
+ useGlobalWidth
25
+ } from "./chunk-6YT4ECUI.mjs";
20
26
 
21
27
  // src/context.tsx
22
28
  import { createContext, useContext } from "react";
@@ -129,12 +135,36 @@ function ThemeProvider({
129
135
  children,
130
136
  defaultMode = "system",
131
137
  colorScheme,
138
+ windowWidth: windowWidthProp,
132
139
  config: configOverride,
133
140
  disablePersistence = false
134
141
  }) {
135
142
  const [resolvedConfig, setResolvedConfig] = useState(
136
143
  () => configOverride ? buildConfig(configOverride) : getConfig()
137
144
  );
145
+ const [webWidth, setWebWidth] = useState(
146
+ () => isWeb && typeof window !== "undefined" ? window.innerWidth : 0
147
+ );
148
+ const effectiveWidth = windowWidthProp ?? (isWeb ? webWidth : 0);
149
+ syncGlobalWidth(effectiveWidth);
150
+ syncGlobalScreens(resolvedConfig.theme.screens);
151
+ useEffect(() => {
152
+ if (!isWeb || typeof window === "undefined") return;
153
+ let raf = 0;
154
+ const update = () => {
155
+ cancelAnimationFrame(raf);
156
+ raf = requestAnimationFrame(() => {
157
+ const w = window.innerWidth;
158
+ setWebWidth(w);
159
+ setGlobalWidth(w);
160
+ });
161
+ };
162
+ window.addEventListener("resize", update);
163
+ return () => {
164
+ window.removeEventListener("resize", update);
165
+ cancelAnimationFrame(raf);
166
+ };
167
+ }, []);
138
168
  const [webScheme, setWebScheme] = useState(() => {
139
169
  if (isWeb && typeof window !== "undefined") {
140
170
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -411,11 +441,13 @@ function styled(Component, baseClasses = "") {
411
441
  import { useMemo as useMemo4 } from "react";
412
442
  function useStyles(classString, state = {}) {
413
443
  const { isDark, config } = useTheme();
444
+ const width = useGlobalWidth();
445
+ const breakpoints = isWeb ? EMPTY_BREAKPOINTS : getActiveBreakpoints(width);
414
446
  const normalised = Array.isArray(classString) ? classString.join(" ") : classString;
415
447
  return useMemo4(() => {
416
448
  const resolved = resolve(normalised, config.theme, config.darkMode);
417
- return flatten(resolved, isDark, state);
418
- }, [normalised, isDark, config, state.hover, state.focus, state.pressed, state.active, state.disabled, state.checked, state.visited, state.placeholder]);
449
+ return flatten(resolved, isDark, state, breakpoints);
450
+ }, [normalised, isDark, config, width, state.hover, state.focus, state.pressed, state.active, state.disabled, state.checked, state.visited, state.placeholder]);
419
451
  }
420
452
  function useResolvedStyle(classString) {
421
453
  const { config } = useTheme();
@@ -426,6 +458,28 @@ function useResolvedStyle(classString) {
426
458
  );
427
459
  }
428
460
 
461
+ // src/useBreakpoint.ts
462
+ function useBreakpoint() {
463
+ const { config } = useTheme();
464
+ const width = useGlobalWidth();
465
+ const screens = config.theme.screens;
466
+ const sorted = Object.entries(screens).filter(([, v]) => typeof v === "number").sort(([, a], [, b]) => b - a);
467
+ for (const [name, minW] of sorted) {
468
+ if (width >= minW) return name;
469
+ }
470
+ return "xs";
471
+ }
472
+ function useResponsive() {
473
+ const { config } = useTheme();
474
+ const width = useGlobalWidth();
475
+ const screens = config.theme.screens;
476
+ const result = {};
477
+ for (const [name, minW] of Object.entries(screens)) {
478
+ if (typeof minW === "number") result[name] = width >= minW;
479
+ }
480
+ return result;
481
+ }
482
+
429
483
  // src/kb.ts
430
484
  function kb(classString, isDark = false) {
431
485
  const config = getConfig();
@@ -456,10 +510,12 @@ export {
456
510
  resolve,
457
511
  styled,
458
512
  updateConfig,
513
+ useBreakpoint,
459
514
  useColors,
460
515
  useGlobalDarkMode,
461
516
  useIsDark,
462
517
  useResolvedStyle,
518
+ useResponsive,
463
519
  useStyles,
464
520
  useTheme,
465
521
  wrapColors