@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.
@@ -1,21 +1,37 @@
1
1
  import {
2
+ EMPTY_BREAKPOINTS,
2
3
  InteractiveWrapper,
3
4
  flatten,
5
+ getActiveBreakpoints,
4
6
  getConfig,
5
7
  isWeb,
6
8
  resolve,
9
+ useConditionalWidth,
7
10
  useGlobalDarkMode
8
- } from "./chunk-ADRZPFQC.mjs";
11
+ } from "./chunk-6YT4ECUI.mjs";
9
12
 
10
13
  // src/jsx-runtime.tsx
11
14
  import { jsx as _jsx, jsxs as _jsxs, Fragment } from "react/jsx-runtime";
12
15
 
13
16
  // src/DarkWrapper.tsx
14
17
  import React from "react";
18
+ var RESPONSIVE_MODS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
19
+ function hasResponsiveBuckets(resolved) {
20
+ for (const key of Object.keys(resolved)) {
21
+ if (key === "base") continue;
22
+ for (const mod of key.split(":")) {
23
+ if (RESPONSIVE_MODS.has(mod)) return true;
24
+ }
25
+ }
26
+ return false;
27
+ }
15
28
  var DarkWrapper = React.forwardRef(
16
29
  function DarkWrapper2({ Component, resolvedStyle, style: styleProp, children, ...rest }, ref) {
17
30
  const isDark = useGlobalDarkMode();
18
- const computedStyle = flatten(resolvedStyle, isDark);
31
+ const needsWidth = !isWeb && hasResponsiveBuckets(resolvedStyle);
32
+ const width = useConditionalWidth(needsWidth);
33
+ const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
34
+ const computedStyle = flatten(resolvedStyle, isDark, {}, breakpoints);
19
35
  const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
20
36
  const props = { ref, ...rest, style: finalStyle };
21
37
  return Array.isArray(children) ? React.createElement(Component, props, ...children) : React.createElement(Component, props, children);
@@ -24,14 +40,56 @@ var DarkWrapper = React.forwardRef(
24
40
  DarkWrapper.displayName = "Kbach.DarkWrapper";
25
41
 
26
42
  // src/jsx-runtime.tsx
27
- var MODE_BUCKET_RE = /^(not-)?(dark|light)(:(not-)?(dark|light))*$/;
28
- function hasInteractiveBuckets(resolved) {
29
- return Object.keys(resolved).some((key) => {
30
- if (key === "base") return false;
31
- if (/^(sm|md|lg|xl|2xl)$/.test(key)) return false;
32
- if (MODE_BUCKET_RE.test(key)) return false;
33
- return true;
34
- });
43
+ var INTERACTIVE_MODS = /* @__PURE__ */ new Set([
44
+ "hover",
45
+ "not-hover",
46
+ "focus",
47
+ "not-focus",
48
+ "active",
49
+ "not-active",
50
+ "pressed",
51
+ "not-pressed",
52
+ "disabled",
53
+ "not-disabled",
54
+ "checked",
55
+ "not-checked",
56
+ "visited",
57
+ "not-visited",
58
+ "placeholder",
59
+ "focus-within",
60
+ "focus-visible",
61
+ "group-hover",
62
+ "group-focus",
63
+ "peer-hover",
64
+ "peer-focus",
65
+ "first",
66
+ "last",
67
+ "odd",
68
+ "even",
69
+ "only"
70
+ ]);
71
+ var RESPONSIVE_MODS2 = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
72
+ var MODE_MODS_JSX = /* @__PURE__ */ new Set(["dark", "light", "not-dark", "not-light"]);
73
+ function bucketMods(resolved) {
74
+ let interactive = false;
75
+ let modeOrResponsive = false;
76
+ for (const key of Object.keys(resolved)) {
77
+ if (key === "base") continue;
78
+ const parts = key.split(":");
79
+ for (const mod of parts) {
80
+ if (INTERACTIVE_MODS.has(mod)) {
81
+ interactive = true;
82
+ break;
83
+ }
84
+ }
85
+ for (const mod of parts) {
86
+ if (MODE_MODS_JSX.has(mod) || RESPONSIVE_MODS2.has(mod)) {
87
+ modeOrResponsive = true;
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ return { interactive, modeOrResponsive };
35
93
  }
36
94
  var CONSUMED_PROPS = /* @__PURE__ */ new Set(["className", "kb", "__kbachStyles", "__kbachClasses"]);
37
95
  function omitConsumed(props) {
@@ -59,7 +117,8 @@ function processElement(type, rawProps, key, isStaticChildren) {
59
117
  const config = getConfig();
60
118
  const resolved = __kbachStyles ?? (classStr ? resolve(classStr, config.theme, config.darkMode) : {});
61
119
  const { style: userStyle, ...passProps } = omitConsumed(rawProps);
62
- if (hasInteractiveBuckets(resolved)) {
120
+ const { interactive, modeOrResponsive } = bucketMods(resolved);
121
+ if (interactive) {
63
122
  return _jsx(InteractiveWrapper, {
64
123
  Component: type,
65
124
  resolvedStyle: resolved,
@@ -68,10 +127,7 @@ function processElement(type, rawProps, key, isStaticChildren) {
68
127
  ...passProps
69
128
  }, key);
70
129
  }
71
- const hasModeVariants = Object.keys(resolved).some(
72
- (k) => k !== "base" && MODE_BUCKET_RE.test(k)
73
- );
74
- if (hasModeVariants) {
130
+ if (modeOrResponsive) {
75
131
  return _jsx(DarkWrapper, {
76
132
  Component: type,
77
133
  resolvedStyle: resolved,
@@ -1838,6 +1838,48 @@ var LRUCache = class {
1838
1838
  }
1839
1839
  };
1840
1840
 
1841
+ // src/core/responsiveStore.ts
1842
+ var RESPONSIVE_KEY = "__kbach_responsive__";
1843
+ function getStore() {
1844
+ const g = globalThis;
1845
+ if (!g[RESPONSIVE_KEY]) {
1846
+ g[RESPONSIVE_KEY] = { width: 0, screens: {}, listeners: /* @__PURE__ */ new Set() };
1847
+ }
1848
+ return g[RESPONSIVE_KEY];
1849
+ }
1850
+ function syncGlobalWidth(width) {
1851
+ getStore().width = width;
1852
+ }
1853
+ function syncGlobalScreens(screens) {
1854
+ getStore().screens = screens;
1855
+ }
1856
+ function getGlobalScreens() {
1857
+ return getStore().screens;
1858
+ }
1859
+ function setGlobalWidth(width) {
1860
+ const store = getStore();
1861
+ if (store.width === width) return;
1862
+ store.width = width;
1863
+ for (const l of store.listeners) l(width);
1864
+ }
1865
+ function getGlobalWidth() {
1866
+ return getStore().width;
1867
+ }
1868
+ function subscribeGlobalWidth(listener) {
1869
+ const store = getStore();
1870
+ store.listeners.add(listener);
1871
+ return () => store.listeners.delete(listener);
1872
+ }
1873
+ function getActiveBreakpoints(width) {
1874
+ const store = getStore();
1875
+ const w = width ?? store.width;
1876
+ const active = /* @__PURE__ */ new Set();
1877
+ for (const [name, minW] of Object.entries(store.screens)) {
1878
+ if (typeof minW === "number" && w >= minW) active.add(name);
1879
+ }
1880
+ return active;
1881
+ }
1882
+
1841
1883
  // src/core/resolver.ts
1842
1884
  var styleCache = new LRUCache(1e4);
1843
1885
  var _styleEl = null;
@@ -1888,6 +1930,7 @@ var GROUP_PEER_PREFIX = {
1888
1930
  "peer-focus": ".peer:focus ~"
1889
1931
  };
1890
1932
  var MODE_MODS = /* @__PURE__ */ new Set(["dark", "light", "not-dark", "not-light"]);
1933
+ var RESPONSIVE_MODS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
1891
1934
  function injectClassRule(cls, bucketKey, styles, darkMode) {
1892
1935
  const cssDecls = styleValueToCSS(styles);
1893
1936
  if (!cssDecls) return;
@@ -1897,10 +1940,12 @@ function injectClassRule(cls, bucketKey, styles, darkMode) {
1897
1940
  return;
1898
1941
  }
1899
1942
  const mods = bucketKey.split(":");
1900
- const hasDark = mods.includes("dark") || mods.includes("not-light");
1901
- const hasLight = mods.includes("light") || mods.includes("not-dark");
1902
- const ancestorMods = mods.filter((m) => m in GROUP_PEER_PREFIX);
1903
- const pseudoMods = mods.filter((m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX));
1943
+ const responsiveMods = mods.filter((m) => RESPONSIVE_MODS.has(m));
1944
+ const nonResponsiveMods = mods.filter((m) => !RESPONSIVE_MODS.has(m));
1945
+ const hasDark = nonResponsiveMods.includes("dark") || nonResponsiveMods.includes("not-light");
1946
+ const hasLight = nonResponsiveMods.includes("light") || nonResponsiveMods.includes("not-dark");
1947
+ const ancestorMods = nonResponsiveMods.filter((m) => m in GROUP_PEER_PREFIX);
1948
+ const pseudoMods = nonResponsiveMods.filter((m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX));
1904
1949
  const pseudoSuffix = pseudoMods.map((p) => MODIFIER_TO_PSEUDO[p] ?? `:${p}`).join("");
1905
1950
  const elementSelector = `.${escaped}${pseudoSuffix}`;
1906
1951
  const ancestorPrefix = ancestorMods.length ? ancestorMods.map((m) => GROUP_PEER_PREFIX[m]).join(" ") + " " : "";
@@ -1925,6 +1970,13 @@ function injectClassRule(cls, bucketKey, styles, darkMode) {
1925
1970
  } else {
1926
1971
  rule = `${selector} { ${cssDecls} }`;
1927
1972
  }
1973
+ if (responsiveMods.length > 0) {
1974
+ const screens = getGlobalScreens();
1975
+ const minWidth = Math.max(...responsiveMods.map((m) => screens[m] ?? 0));
1976
+ if (minWidth > 0) {
1977
+ rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
1978
+ }
1979
+ }
1928
1980
  injectRule(rule);
1929
1981
  }
1930
1982
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
@@ -1993,18 +2045,18 @@ function resolve(classString, theme, darkMode = "attribute") {
1993
2045
  }
1994
2046
  return result;
1995
2047
  }
1996
- function flatten(resolved, isDark, state = {}) {
2048
+ function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new Set()) {
1997
2049
  const result = { ...resolved.base ?? {} };
1998
2050
  for (const [key, styles] of Object.entries(resolved)) {
1999
2051
  if (key === "base" || !styles) continue;
2000
2052
  const mods = key.split(":");
2001
- if (matchesMods(mods, isDark, state)) {
2053
+ if (matchesMods(mods, isDark, state, breakpoints)) {
2002
2054
  Object.assign(result, styles);
2003
2055
  }
2004
2056
  }
2005
2057
  return result;
2006
2058
  }
2007
- function matchesMods(mods, isDark, state) {
2059
+ function matchesMods(mods, isDark, state, breakpoints) {
2008
2060
  return mods.every((mod) => {
2009
2061
  switch (mod) {
2010
2062
  case "dark":
@@ -2042,6 +2094,12 @@ function matchesMods(mods, isDark, state) {
2042
2094
  return !state.visited;
2043
2095
  case "placeholder":
2044
2096
  return !!state.placeholder;
2097
+ case "sm":
2098
+ case "md":
2099
+ case "lg":
2100
+ case "xl":
2101
+ case "2xl":
2102
+ return breakpoints.has(mod);
2045
2103
  default:
2046
2104
  return false;
2047
2105
  }
@@ -2201,7 +2259,7 @@ var customVariants = new Proxy(
2201
2259
 
2202
2260
  // src/core/darkModeStore.ts
2203
2261
  var KEY = "__kbach_dark_store__";
2204
- function getStore() {
2262
+ function getStore2() {
2205
2263
  const g = globalThis;
2206
2264
  if (!g[KEY]) {
2207
2265
  g[KEY] = { isDark: false, lastNotified: false, subscribers: /* @__PURE__ */ new Set() };
@@ -2209,20 +2267,20 @@ function getStore() {
2209
2267
  return g[KEY];
2210
2268
  }
2211
2269
  function syncGlobalDarkMode(isDark) {
2212
- getStore().isDark = isDark;
2270
+ getStore2().isDark = isDark;
2213
2271
  }
2214
2272
  function setGlobalDarkMode(isDark) {
2215
- const store = getStore();
2273
+ const store = getStore2();
2216
2274
  store.isDark = isDark;
2217
2275
  if (store.lastNotified === isDark) return;
2218
2276
  store.lastNotified = isDark;
2219
2277
  for (const sub of store.subscribers) sub();
2220
2278
  }
2221
2279
  function getGlobalDarkMode() {
2222
- return getStore().isDark;
2280
+ return getStore2().isDark;
2223
2281
  }
2224
2282
  function subscribeGlobalDarkMode(callback) {
2225
- const store = getStore();
2283
+ const store = getStore2();
2226
2284
  store.subscribers.add(callback);
2227
2285
  return () => store.subscribers.delete(callback);
2228
2286
  }
@@ -2244,13 +2302,47 @@ function useGlobalDarkMode() {
2244
2302
  }
2245
2303
 
2246
2304
  // src/InteractiveWrapper.tsx
2247
- import React2, { forwardRef, useState, useCallback, useMemo } from "react";
2305
+ import React3, { forwardRef, useState, useCallback, useMemo } from "react";
2306
+
2307
+ // src/useGlobalWidth.ts
2308
+ import React2 from "react";
2309
+ var useSyncExternalStore2 = React2.useSyncExternalStore ?? function useSyncExternalStoreFallback2(subscribe, getSnapshot, _getServerSnapshot) {
2310
+ const [, forceUpdate] = React2.useReducer((n) => n + 1, 0);
2311
+ React2.useEffect(() => subscribe(forceUpdate), [subscribe]);
2312
+ return getSnapshot();
2313
+ };
2314
+ var NOOP_SUB = (_) => () => {
2315
+ };
2316
+ var ZERO_SNAP = () => 0;
2317
+ var EMPTY_BREAKPOINTS = /* @__PURE__ */ new Set();
2318
+ function useGlobalWidth() {
2319
+ return useSyncExternalStore2(subscribeGlobalWidth, getGlobalWidth, ZERO_SNAP);
2320
+ }
2321
+ function useConditionalWidth(active) {
2322
+ return useSyncExternalStore2(
2323
+ active ? subscribeGlobalWidth : NOOP_SUB,
2324
+ active ? getGlobalWidth : ZERO_SNAP,
2325
+ ZERO_SNAP
2326
+ );
2327
+ }
2328
+
2329
+ // src/InteractiveWrapper.tsx
2248
2330
  function chain(original, extra) {
2249
2331
  return (...args) => {
2250
2332
  original?.(...args);
2251
2333
  extra();
2252
2334
  };
2253
2335
  }
2336
+ var RESPONSIVE_MODS2 = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
2337
+ function hasResponsiveBuckets(resolved) {
2338
+ for (const key of Object.keys(resolved)) {
2339
+ if (key === "base") continue;
2340
+ for (const mod of key.split(":")) {
2341
+ if (RESPONSIVE_MODS2.has(mod)) return true;
2342
+ }
2343
+ }
2344
+ return false;
2345
+ }
2254
2346
  var InteractiveWrapper = forwardRef(
2255
2347
  function InteractiveWrapper2({
2256
2348
  Component,
@@ -2266,6 +2358,9 @@ var InteractiveWrapper = forwardRef(
2266
2358
  ...rest
2267
2359
  }, ref) {
2268
2360
  const isDark = useGlobalDarkMode();
2361
+ const needsWidth = !isWeb && hasResponsiveBuckets(resolvedStyle);
2362
+ const width = useConditionalWidth(needsWidth);
2363
+ const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
2269
2364
  const [pressed, setPressed] = useState(false);
2270
2365
  const [hovered, setHovered] = useState(false);
2271
2366
  const [focused, setFocused] = useState(false);
@@ -2276,8 +2371,9 @@ var InteractiveWrapper = forwardRef(
2276
2371
  const handleFocus = useCallback(chain(onFocus, () => setFocused(true)), [onFocus]);
2277
2372
  const handleBlur = useCallback(chain(onBlur, () => setFocused(false)), [onBlur]);
2278
2373
  const computedStyle = useMemo(
2279
- () => flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused }),
2280
- [resolvedStyle, isDark, pressed, hovered, focused]
2374
+ () => flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused }, breakpoints),
2375
+ [resolvedStyle, isDark, pressed, hovered, focused, width]
2376
+ // eslint-disable-line react-hooks/exhaustive-deps
2281
2377
  );
2282
2378
  const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
2283
2379
  const { children, ...restWithoutChildren } = rest;
@@ -2293,7 +2389,7 @@ var InteractiveWrapper = forwardRef(
2293
2389
  onFocus: handleFocus,
2294
2390
  onBlur: handleBlur
2295
2391
  };
2296
- return Array.isArray(children) ? React2.createElement(Component, componentProps, ...children) : React2.createElement(Component, componentProps, children);
2392
+ return Array.isArray(children) ? React3.createElement(Component, componentProps, ...children) : React3.createElement(Component, componentProps, children);
2297
2393
  }
2298
2394
  );
2299
2395
  InteractiveWrapper.displayName = "Kbach.InteractiveWrapper";
@@ -2305,6 +2401,10 @@ export {
2305
2401
  isWeb,
2306
2402
  parseClass,
2307
2403
  parseClasses,
2404
+ syncGlobalWidth,
2405
+ syncGlobalScreens,
2406
+ setGlobalWidth,
2407
+ getActiveBreakpoints,
2308
2408
  resolve,
2309
2409
  flatten,
2310
2410
  getConfig,
@@ -2314,6 +2414,9 @@ export {
2314
2414
  initConfig,
2315
2415
  syncGlobalDarkMode,
2316
2416
  setGlobalDarkMode,
2417
+ EMPTY_BREAKPOINTS,
2418
+ useGlobalWidth,
2419
+ useConditionalWidth,
2317
2420
  useGlobalDarkMode,
2318
2421
  InteractiveWrapper
2319
2422
  };
package/dist/index.d.mts CHANGED
@@ -100,9 +100,11 @@ declare function resolve(classString: string, theme: ThemeConfig, darkMode?: 'at
100
100
  * Flatten a ResolvedStyle into a single StyleValue for the given runtime state.
101
101
  * Used by useStyles() and styled().
102
102
  *
103
- * @param resolved Output of resolve()
104
- * @param isDark Whether dark mode is currently active
105
- * @param state Interaction state flags
103
+ * @param resolved Output of resolve()
104
+ * @param isDark Whether dark mode is currently active
105
+ * @param state Interaction state flags
106
+ * @param breakpoints Active breakpoint names (sm, md, lg, xl, 2xl). On web,
107
+ * pass an empty Set — CSS @media rules handle responsive.
106
108
  */
107
109
  declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
108
110
  hover?: boolean;
@@ -113,7 +115,7 @@ declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
113
115
  checked?: boolean;
114
116
  visited?: boolean;
115
117
  placeholder?: boolean;
116
- }): StyleValue;
118
+ }, breakpoints?: Set<string>): StyleValue;
117
119
 
118
120
  /**
119
121
  * Load, merge, and cache the resolved config.
@@ -185,12 +187,19 @@ interface ThemeProviderProps {
185
187
  * ```
186
188
  */
187
189
  colorScheme?: 'light' | 'dark' | null;
190
+ /**
191
+ * Current window/screen width in pixels for responsive breakpoints.
192
+ * On web this is read from `window.innerWidth` automatically.
193
+ * When importing `ThemeProvider` from `@kbach/native` this is provided
194
+ * automatically from `useWindowDimensions()`.
195
+ */
196
+ windowWidth?: number;
188
197
  /** Override the config (useful for per-tree config). Defaults to global getConfig(). */
189
198
  config?: FrameworkConfig;
190
199
  /** Disable persistence to localStorage */
191
200
  disablePersistence?: boolean;
192
201
  }
193
- declare function ThemeProvider({ children, defaultMode, colorScheme, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
202
+ declare function ThemeProvider({ children, defaultMode, colorScheme, windowWidth: windowWidthProp, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
194
203
 
195
204
  type ToggleVariant = 'button' | 'switch' | 'icon-button';
196
205
  interface ThemeToggleProps {
@@ -281,6 +290,26 @@ declare function useResolvedStyle(classString: string | string[]): ResolvedStyle
281
290
  */
282
291
  declare function useGlobalDarkMode(): boolean;
283
292
 
293
+ /**
294
+ * Returns the name of the currently active breakpoint — the largest breakpoint
295
+ * whose min-width the window satisfies, or `'xs'` when below all breakpoints.
296
+ *
297
+ * ```ts
298
+ * const bp = useBreakpoint(); // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
299
+ * ```
300
+ */
301
+ declare function useBreakpoint(): string;
302
+ /**
303
+ * Returns a record of boolean flags for each breakpoint — `true` when the
304
+ * window width satisfies that breakpoint's min-width threshold.
305
+ *
306
+ * ```ts
307
+ * const { sm, md, lg } = useResponsive();
308
+ * const padding = lg ? 32 : sm ? 16 : 8;
309
+ * ```
310
+ */
311
+ declare function useResponsive(): Record<string, boolean>;
312
+
284
313
  interface InteractiveWrapperProps {
285
314
  /** The real component to render (View, TouchableOpacity, div, a third-party button…) */
286
315
  Component: React__default.ComponentType<any> | string;
@@ -342,4 +371,4 @@ declare function kb(classString: string, isDark?: boolean): StyleValue | string;
342
371
  */
343
372
  declare function cx(...classes: Array<string | false | null | undefined>): string;
344
373
 
345
- export { type ColorScale, type ColorsAPI, type FrameworkConfig, type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type ParsedClass, type PluginAPI, type ResolvedConfig, type ResolvedStyle, type StyleValue, type StyledProps, type ThemeConfig, ThemeContext, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, buildConfig, cx, defaultColors, defaultTheme, flatten, getConfig, initConfig, kb, parseClass, parseClasses, resolve, styled, updateConfig, useColors, useGlobalDarkMode, useIsDark, useResolvedStyle, useStyles, useTheme, wrapColors };
374
+ export { type ColorScale, type ColorsAPI, type FrameworkConfig, type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type ParsedClass, type PluginAPI, type ResolvedConfig, type ResolvedStyle, type StyleValue, type StyledProps, type ThemeConfig, ThemeContext, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, buildConfig, cx, defaultColors, defaultTheme, flatten, getConfig, initConfig, kb, parseClass, parseClasses, resolve, styled, updateConfig, useBreakpoint, useColors, useGlobalDarkMode, useIsDark, useResolvedStyle, useResponsive, useStyles, useTheme, wrapColors };
package/dist/index.d.ts CHANGED
@@ -100,9 +100,11 @@ declare function resolve(classString: string, theme: ThemeConfig, darkMode?: 'at
100
100
  * Flatten a ResolvedStyle into a single StyleValue for the given runtime state.
101
101
  * Used by useStyles() and styled().
102
102
  *
103
- * @param resolved Output of resolve()
104
- * @param isDark Whether dark mode is currently active
105
- * @param state Interaction state flags
103
+ * @param resolved Output of resolve()
104
+ * @param isDark Whether dark mode is currently active
105
+ * @param state Interaction state flags
106
+ * @param breakpoints Active breakpoint names (sm, md, lg, xl, 2xl). On web,
107
+ * pass an empty Set — CSS @media rules handle responsive.
106
108
  */
107
109
  declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
108
110
  hover?: boolean;
@@ -113,7 +115,7 @@ declare function flatten(resolved: ResolvedStyle, isDark: boolean, state?: {
113
115
  checked?: boolean;
114
116
  visited?: boolean;
115
117
  placeholder?: boolean;
116
- }): StyleValue;
118
+ }, breakpoints?: Set<string>): StyleValue;
117
119
 
118
120
  /**
119
121
  * Load, merge, and cache the resolved config.
@@ -185,12 +187,19 @@ interface ThemeProviderProps {
185
187
  * ```
186
188
  */
187
189
  colorScheme?: 'light' | 'dark' | null;
190
+ /**
191
+ * Current window/screen width in pixels for responsive breakpoints.
192
+ * On web this is read from `window.innerWidth` automatically.
193
+ * When importing `ThemeProvider` from `@kbach/native` this is provided
194
+ * automatically from `useWindowDimensions()`.
195
+ */
196
+ windowWidth?: number;
188
197
  /** Override the config (useful for per-tree config). Defaults to global getConfig(). */
189
198
  config?: FrameworkConfig;
190
199
  /** Disable persistence to localStorage */
191
200
  disablePersistence?: boolean;
192
201
  }
193
- declare function ThemeProvider({ children, defaultMode, colorScheme, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
202
+ declare function ThemeProvider({ children, defaultMode, colorScheme, windowWidth: windowWidthProp, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
194
203
 
195
204
  type ToggleVariant = 'button' | 'switch' | 'icon-button';
196
205
  interface ThemeToggleProps {
@@ -281,6 +290,26 @@ declare function useResolvedStyle(classString: string | string[]): ResolvedStyle
281
290
  */
282
291
  declare function useGlobalDarkMode(): boolean;
283
292
 
293
+ /**
294
+ * Returns the name of the currently active breakpoint — the largest breakpoint
295
+ * whose min-width the window satisfies, or `'xs'` when below all breakpoints.
296
+ *
297
+ * ```ts
298
+ * const bp = useBreakpoint(); // 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
299
+ * ```
300
+ */
301
+ declare function useBreakpoint(): string;
302
+ /**
303
+ * Returns a record of boolean flags for each breakpoint — `true` when the
304
+ * window width satisfies that breakpoint's min-width threshold.
305
+ *
306
+ * ```ts
307
+ * const { sm, md, lg } = useResponsive();
308
+ * const padding = lg ? 32 : sm ? 16 : 8;
309
+ * ```
310
+ */
311
+ declare function useResponsive(): Record<string, boolean>;
312
+
284
313
  interface InteractiveWrapperProps {
285
314
  /** The real component to render (View, TouchableOpacity, div, a third-party button…) */
286
315
  Component: React__default.ComponentType<any> | string;
@@ -342,4 +371,4 @@ declare function kb(classString: string, isDark?: boolean): StyleValue | string;
342
371
  */
343
372
  declare function cx(...classes: Array<string | false | null | undefined>): string;
344
373
 
345
- export { type ColorScale, type ColorsAPI, type FrameworkConfig, type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type ParsedClass, type PluginAPI, type ResolvedConfig, type ResolvedStyle, type StyleValue, type StyledProps, type ThemeConfig, ThemeContext, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, buildConfig, cx, defaultColors, defaultTheme, flatten, getConfig, initConfig, kb, parseClass, parseClasses, resolve, styled, updateConfig, useColors, useGlobalDarkMode, useIsDark, useResolvedStyle, useStyles, useTheme, wrapColors };
374
+ export { type ColorScale, type ColorsAPI, type FrameworkConfig, type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type ParsedClass, type PluginAPI, type ResolvedConfig, type ResolvedStyle, type StyleValue, type StyledProps, type ThemeConfig, ThemeContext, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, buildConfig, cx, defaultColors, defaultTheme, flatten, getConfig, initConfig, kb, parseClass, parseClasses, resolve, styled, updateConfig, useBreakpoint, useColors, useGlobalDarkMode, useIsDark, useResolvedStyle, useResponsive, useStyles, useTheme, wrapColors };