@kbach/react-native 1.0.0-beta.2 → 1.0.0-beta.21

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.
Files changed (42) hide show
  1. package/README.md +253 -87
  2. package/android/build.gradle +36 -0
  3. package/android/src/main/AndroidManifest.xml +14 -0
  4. package/android/src/main/java/com/kbachnative/KbachModule.kt +83 -0
  5. package/android/src/main/java/com/kbachnative/KbachPackage.kt +54 -0
  6. package/android/src/main/jniLibs/arm64-v8a/libkbach_core_engine.so +0 -0
  7. package/android/src/main/jniLibs/x86_64/libkbach_core_engine.so +0 -0
  8. package/dist/chunk-AG7ZQ2K4.mjs +552 -0
  9. package/dist/chunk-OS7EPBH5.mjs +40 -0
  10. package/dist/chunk-TS2EEVOE.mjs +107 -0
  11. package/dist/darkModeStore.d.ts +58 -0
  12. package/dist/darkModeStore.js +112 -0
  13. package/dist/dynamicTokens.d.ts +36 -0
  14. package/dist/dynamicTokens.js +75 -0
  15. package/dist/index.d.ts +53 -102
  16. package/dist/index.js +1721 -385
  17. package/dist/index.web.d.ts +18 -0
  18. package/dist/index.web.js +436 -0
  19. package/dist/index.web.mjs +210 -0
  20. package/dist/jsx-dev-runtime.d.ts +3 -12
  21. package/dist/jsx-dev-runtime.js +1738 -343
  22. package/dist/jsx-dev-runtime.web.d.ts +10 -0
  23. package/dist/jsx-dev-runtime.web.js +270 -0
  24. package/dist/jsx-dev-runtime.web.mjs +29 -0
  25. package/dist/jsx-runtime.d.ts +3 -23
  26. package/dist/jsx-runtime.js +1729 -335
  27. package/dist/jsx-runtime.web.d.ts +7 -0
  28. package/dist/jsx-runtime.web.js +252 -0
  29. package/dist/{jsx-runtime.mjs → jsx-runtime.web.mjs} +2 -2
  30. package/dist/theme.d.ts +54 -0
  31. package/dist/{chunk-YHF3QLRL.mjs → theme.js} +94 -72
  32. package/dist/useDynamicToken-Dr15c88t.d.ts +160 -0
  33. package/package.json +62 -14
  34. package/react-native.config.js +29 -0
  35. package/specs/NativeKbachModule.ts +31 -0
  36. package/src/babel-plugin.js +74 -2
  37. package/dist/chunk-SVMYVXY6.mjs +0 -44
  38. package/dist/index.d.mts +0 -148
  39. package/dist/index.mjs +0 -80
  40. package/dist/jsx-dev-runtime.d.mts +0 -19
  41. package/dist/jsx-dev-runtime.mjs +0 -20
  42. package/dist/jsx-runtime.d.mts +0 -27
@@ -0,0 +1,40 @@
1
+ import {
2
+ resolveClassName
3
+ } from "./chunk-AG7ZQ2K4.mjs";
4
+
5
+ // src/jsxRuntimeCoreWeb.ts
6
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { Fragment } from "react";
8
+ function makeElement(isStaticChildren, type, props, key) {
9
+ return (isStaticChildren ? _jsxs : _jsx)(type, props, key);
10
+ }
11
+ function processElement(resolveClassName2, type, rawProps, key, isStaticChildren) {
12
+ if (type === null || typeof type === "symbol" || !rawProps) {
13
+ return makeElement(isStaticChildren, type, rawProps ?? {}, key);
14
+ }
15
+ const { className: classStrRaw, dataSet: userDataSet, ...rest } = rawProps;
16
+ if (typeof classStrRaw !== "string") {
17
+ return makeElement(isStaticChildren, type, rawProps, key);
18
+ }
19
+ const resolved = resolveClassName2(classStrRaw);
20
+ const dataSet = { ...userDataSet, kb: resolved };
21
+ return makeElement(isStaticChildren, type, { ...rest, dataSet }, key);
22
+ }
23
+ function createJsxFunctionsWeb(resolveClassName2) {
24
+ function jsx2(type, props, key) {
25
+ return processElement(resolveClassName2, type, props, key, false);
26
+ }
27
+ function jsxs2(type, props, key) {
28
+ return processElement(resolveClassName2, type, props, key, true);
29
+ }
30
+ return { jsx: jsx2, jsxs: jsxs2 };
31
+ }
32
+
33
+ // src/jsx-runtime.web.tsx
34
+ var { jsx, jsxs } = createJsxFunctionsWeb(resolveClassName);
35
+
36
+ export {
37
+ Fragment,
38
+ jsx,
39
+ jsxs
40
+ };
@@ -0,0 +1,107 @@
1
+ import {
2
+ getTheme
3
+ } from "./chunk-AG7ZQ2K4.mjs";
4
+
5
+ // src/darkModeStore.ts
6
+ import { Appearance } from "react-native";
7
+ var listeners = /* @__PURE__ */ new Set();
8
+ function systemPrefersDark() {
9
+ return Appearance.getColorScheme() === "dark";
10
+ }
11
+ function resolveIsDark(m) {
12
+ return m === "system" ? systemPrefersDark() : m === "dark";
13
+ }
14
+ function applyToDom(dark) {
15
+ if (typeof document === "undefined") return;
16
+ const root = document.documentElement;
17
+ const strategy = getTheme().darkMode;
18
+ if (strategy === "class") {
19
+ root.classList.toggle("dark", dark);
20
+ root.classList.toggle("light", !dark);
21
+ } else if (strategy === "attribute") {
22
+ root.setAttribute("data-theme", dark ? "dark" : "light");
23
+ }
24
+ }
25
+ var mode = "system";
26
+ var isDark = resolveIsDark(mode);
27
+ applyToDom(isDark);
28
+ var hasExplicitChoice = false;
29
+ var subscription = Appearance.addChangeListener(({ colorScheme }) => {
30
+ if (mode !== "system") return;
31
+ isDark = colorScheme === "dark";
32
+ applyToDom(isDark);
33
+ notify();
34
+ });
35
+ function notify() {
36
+ for (const listener of listeners) listener();
37
+ }
38
+ function getGlobalDarkMode() {
39
+ return isDark;
40
+ }
41
+ function getGlobalThemeMode() {
42
+ return mode;
43
+ }
44
+ function setGlobalThemeMode(nextMode) {
45
+ mode = nextMode;
46
+ isDark = resolveIsDark(nextMode);
47
+ hasExplicitChoice = true;
48
+ applyToDom(isDark);
49
+ notify();
50
+ }
51
+ function toggleGlobalDarkMode() {
52
+ setGlobalThemeMode(isDark ? "light" : "dark");
53
+ }
54
+ function subscribeGlobalDarkMode(listener) {
55
+ listeners.add(listener);
56
+ return () => listeners.delete(listener);
57
+ }
58
+ function seedDefaultMode(fallback) {
59
+ if (hasExplicitChoice || mode === fallback) return;
60
+ mode = fallback;
61
+ isDark = resolveIsDark(fallback);
62
+ applyToDom(isDark);
63
+ notify();
64
+ }
65
+
66
+ // src/dynamicTokens.ts
67
+ var tokens = /* @__PURE__ */ new Map();
68
+ var listeners2 = /* @__PURE__ */ new Set();
69
+ var version = 0;
70
+ function applyToDom2(name, value) {
71
+ if (typeof document === "undefined") return;
72
+ document.documentElement.style.setProperty(`--${name}`, value);
73
+ }
74
+ function notify2() {
75
+ version++;
76
+ for (const listener of listeners2) listener();
77
+ }
78
+ function setDynamicToken(name, value) {
79
+ tokens.set(name, value);
80
+ applyToDom2(name, value);
81
+ notify2();
82
+ }
83
+ function getDynamicToken(name) {
84
+ return tokens.get(name);
85
+ }
86
+ function deleteDynamicToken(name) {
87
+ if (!tokens.delete(name)) return;
88
+ if (typeof document !== "undefined") document.documentElement.style.removeProperty(`--${name}`);
89
+ notify2();
90
+ }
91
+ function subscribeDynamicTokens(listener) {
92
+ listeners2.add(listener);
93
+ return () => listeners2.delete(listener);
94
+ }
95
+
96
+ export {
97
+ getGlobalDarkMode,
98
+ getGlobalThemeMode,
99
+ setGlobalThemeMode,
100
+ toggleGlobalDarkMode,
101
+ subscribeGlobalDarkMode,
102
+ seedDefaultMode,
103
+ setDynamicToken,
104
+ getDynamicToken,
105
+ deleteDynamicToken,
106
+ subscribeDynamicTokens
107
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Native port of @kbach/react's darkModeStore.ts — same architecture (a
3
+ * single module-level store is the real source of truth;
4
+ * ThemeProvider/useTheme are a thin, OPTIONAL wrapper around it; every
5
+ * function here works standalone with no provider mounted anywhere), with
6
+ * two real platform differences from the web version:
7
+ *
8
+ * 1. No persistence. There's no React-Native-builtin equivalent of
9
+ * localStorage — adding one would mean forcing a real native dependency
10
+ * (e.g. @react-native-async-storage/async-storage) on every consumer,
11
+ * even ones that don't want it. The mode always starts at 'system' on a
12
+ * fresh app launch. If you want persistence, read your own storage at
13
+ * startup (before your first render) and call setGlobalThemeMode() with
14
+ * the result — same "seed once, no built-in write-back" shape as
15
+ * seedDefaultMode() below, just driven by your own storage instead of
16
+ * one this package picks for you.
17
+ * 2. `applyToDom` below IS needed here, unlike what an earlier version of
18
+ * this file's own comment claimed ("no DOM to apply the resolved mode
19
+ * to") — that reasoning only holds for real native (Android/iOS), where
20
+ * nativeBridge.ts's resolveStyle() reads getGlobalDarkMode() directly on
21
+ * every call, no DOM involved at all. This file is ALSO used by Expo
22
+ * Web, though (no `.web.ts` sibling — Metro has nothing to swap in), and
23
+ * Expo Web resolves `dark:` classes to REAL CSS with `[data-theme=
24
+ * "dark"]`-style selectors (see nativeBridge.web.ts) that only ever
25
+ * match if something writes that attribute to the DOM — nothing did,
26
+ * which is exactly why toggling the mode changed `useTheme()`'s own
27
+ * state (a consumer reading `mode`/`isDark` directly, e.g. for a label,
28
+ * updated correctly) while every `dark:`-prefixed style silently never
29
+ * applied. `typeof document === 'undefined'` is what makes one function
30
+ * safe on both platforms: real native's Hermes has no `document` global
31
+ * at all (not even `undefined` as a defined-but-empty value — genuinely
32
+ * unset, which `typeof` can check without throwing), so this always
33
+ * no-ops there, while Expo Web's react-native-web renders into a real
34
+ * browser DOM where it's needed.
35
+ */
36
+ type ThemeMode = 'light' | 'dark' | 'system';
37
+ declare function getGlobalDarkMode(): boolean;
38
+ declare function getGlobalThemeMode(): ThemeMode;
39
+ /** Explicit user choice — takes priority over any later `<ThemeProvider defaultMode>` seed (see `seedDefaultMode` below). Not persisted; see this module's own doc comment. */
40
+ declare function setGlobalThemeMode(nextMode: ThemeMode): void;
41
+ declare function toggleGlobalDarkMode(): void;
42
+ declare function subscribeGlobalDarkMode(listener: () => void): () => void;
43
+ /**
44
+ * Applies `fallback` as the initial mode, but ONLY if nothing has made an
45
+ * explicit choice yet — called once by `<ThemeProvider defaultMode>` on
46
+ * mount, never exported for direct use elsewhere. Unlike the web store,
47
+ * there's no persisted-value check here (nothing to check); the only
48
+ * thing that can beat a seed is a `setGlobalThemeMode()` call that
49
+ * happened first (e.g. your own storage-restore logic run before the
50
+ * provider mounts).
51
+ */
52
+ declare function seedDefaultMode(fallback: ThemeMode): void;
53
+ /** Exported for tests only — resets every module-level field back to its as-if-just-imported state. */
54
+ declare function _resetForTests(): void;
55
+ /** Exported for tests only — removes the Appearance change subscription so a test's mock doesn't leak into the next one. */
56
+ declare function _unsubscribeForTests(): void;
57
+
58
+ export { type ThemeMode, _resetForTests, _unsubscribeForTests, getGlobalDarkMode, getGlobalThemeMode, seedDefaultMode, setGlobalThemeMode, subscribeGlobalDarkMode, toggleGlobalDarkMode };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/darkModeStore.ts
21
+ var darkModeStore_exports = {};
22
+ __export(darkModeStore_exports, {
23
+ _resetForTests: () => _resetForTests,
24
+ _unsubscribeForTests: () => _unsubscribeForTests,
25
+ getGlobalDarkMode: () => getGlobalDarkMode,
26
+ getGlobalThemeMode: () => getGlobalThemeMode,
27
+ seedDefaultMode: () => seedDefaultMode,
28
+ setGlobalThemeMode: () => setGlobalThemeMode,
29
+ subscribeGlobalDarkMode: () => subscribeGlobalDarkMode,
30
+ toggleGlobalDarkMode: () => toggleGlobalDarkMode
31
+ });
32
+ module.exports = __toCommonJS(darkModeStore_exports);
33
+ var import_react_native = require("react-native");
34
+ var import_theme = require("./theme");
35
+ var listeners = /* @__PURE__ */ new Set();
36
+ function systemPrefersDark() {
37
+ return import_react_native.Appearance.getColorScheme() === "dark";
38
+ }
39
+ function resolveIsDark(m) {
40
+ return m === "system" ? systemPrefersDark() : m === "dark";
41
+ }
42
+ function applyToDom(dark) {
43
+ if (typeof document === "undefined") return;
44
+ const root = document.documentElement;
45
+ const strategy = (0, import_theme.getTheme)().darkMode;
46
+ if (strategy === "class") {
47
+ root.classList.toggle("dark", dark);
48
+ root.classList.toggle("light", !dark);
49
+ } else if (strategy === "attribute") {
50
+ root.setAttribute("data-theme", dark ? "dark" : "light");
51
+ }
52
+ }
53
+ var mode = "system";
54
+ var isDark = resolveIsDark(mode);
55
+ applyToDom(isDark);
56
+ var hasExplicitChoice = false;
57
+ var subscription = import_react_native.Appearance.addChangeListener(({ colorScheme }) => {
58
+ if (mode !== "system") return;
59
+ isDark = colorScheme === "dark";
60
+ applyToDom(isDark);
61
+ notify();
62
+ });
63
+ function notify() {
64
+ for (const listener of listeners) listener();
65
+ }
66
+ function getGlobalDarkMode() {
67
+ return isDark;
68
+ }
69
+ function getGlobalThemeMode() {
70
+ return mode;
71
+ }
72
+ function setGlobalThemeMode(nextMode) {
73
+ mode = nextMode;
74
+ isDark = resolveIsDark(nextMode);
75
+ hasExplicitChoice = true;
76
+ applyToDom(isDark);
77
+ notify();
78
+ }
79
+ function toggleGlobalDarkMode() {
80
+ setGlobalThemeMode(isDark ? "light" : "dark");
81
+ }
82
+ function subscribeGlobalDarkMode(listener) {
83
+ listeners.add(listener);
84
+ return () => listeners.delete(listener);
85
+ }
86
+ function seedDefaultMode(fallback) {
87
+ if (hasExplicitChoice || mode === fallback) return;
88
+ mode = fallback;
89
+ isDark = resolveIsDark(fallback);
90
+ applyToDom(isDark);
91
+ notify();
92
+ }
93
+ function _resetForTests() {
94
+ mode = "system";
95
+ isDark = resolveIsDark(mode);
96
+ hasExplicitChoice = false;
97
+ listeners.clear();
98
+ }
99
+ function _unsubscribeForTests() {
100
+ subscription.remove();
101
+ }
102
+ // Annotate the CommonJS export names for ESM import in node:
103
+ 0 && (module.exports = {
104
+ _resetForTests,
105
+ _unsubscribeForTests,
106
+ getGlobalDarkMode,
107
+ getGlobalThemeMode,
108
+ seedDefaultMode,
109
+ setGlobalThemeMode,
110
+ subscribeGlobalDarkMode,
111
+ toggleGlobalDarkMode
112
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Cross-platform runtime-settable style values — the native counterpart to
3
+ * a real CSS custom property. Real `var(--sidebar-width)` already works on
4
+ * Expo Web today with ZERO code here (raw CSS text, resolved by the
5
+ * browser's own engine — see `jsxRuntimeCoreWeb.ts`, which does no
6
+ * className rewriting at all). Native has no such thing: RN's style system
7
+ * needs an actual JS-computed value at render time, so this module exists
8
+ * to give `var(--x)` an equivalent that works there too — same
9
+ * "module-level store is the real source of truth, no Context required"
10
+ * architecture as `darkModeStore.ts`, and `setDynamicToken` ALSO writes the
11
+ * real CSS custom property to the DOM when one exists (mirroring that
12
+ * file's own `applyToDom`), so a single call updates both platforms
13
+ * identically: instantly via native CSS reactivity on web, via this
14
+ * store's subscribers (see `jsxRuntimeCore.ts`'s `ReactiveElement`, which
15
+ * substitutes a registered token's current value into the className
16
+ * string before every resolve) on native.
17
+ *
18
+ * Deliberately ONE listener set shared by every token, not per-token
19
+ * subscriptions — same trade-off `darkModeStore.ts` already makes for
20
+ * "any relevant change re-renders every subscribed element" simplicity.
21
+ * An unrelated token's change still re-renders every subscribed element
22
+ * (there's no per-token filtering), but `substituteDynamicTokens` in
23
+ * `jsxRuntimeCore.ts` re-reads each token's CURRENT value fresh on every
24
+ * one of those re-renders, so the resolved style stays correct regardless
25
+ * — the redundant re-render is a cheap, accepted trade-off, not a bug.
26
+ */
27
+ /** `name` is the bare token name, WITHOUT the leading `--` (matching how `getDynamicToken`/`var(--name)` substitution both address it). */
28
+ declare function setDynamicToken(name: string, value: string): void;
29
+ declare function getDynamicToken(name: string): string | undefined;
30
+ declare function deleteDynamicToken(name: string): void;
31
+ declare function subscribeDynamicTokens(listener: () => void): () => void;
32
+ declare function getDynamicTokensVersion(): number;
33
+ /** Exported for tests only — resets every module-level field back to its as-if-just-imported state. */
34
+ declare function _resetForTests(): void;
35
+
36
+ export { _resetForTests, deleteDynamicToken, getDynamicToken, getDynamicTokensVersion, setDynamicToken, subscribeDynamicTokens };
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/dynamicTokens.ts
21
+ var dynamicTokens_exports = {};
22
+ __export(dynamicTokens_exports, {
23
+ _resetForTests: () => _resetForTests,
24
+ deleteDynamicToken: () => deleteDynamicToken,
25
+ getDynamicToken: () => getDynamicToken,
26
+ getDynamicTokensVersion: () => getDynamicTokensVersion,
27
+ setDynamicToken: () => setDynamicToken,
28
+ subscribeDynamicTokens: () => subscribeDynamicTokens
29
+ });
30
+ module.exports = __toCommonJS(dynamicTokens_exports);
31
+ var tokens = /* @__PURE__ */ new Map();
32
+ var listeners = /* @__PURE__ */ new Set();
33
+ var version = 0;
34
+ function applyToDom(name, value) {
35
+ if (typeof document === "undefined") return;
36
+ document.documentElement.style.setProperty(`--${name}`, value);
37
+ }
38
+ function notify() {
39
+ version++;
40
+ for (const listener of listeners) listener();
41
+ }
42
+ function setDynamicToken(name, value) {
43
+ tokens.set(name, value);
44
+ applyToDom(name, value);
45
+ notify();
46
+ }
47
+ function getDynamicToken(name) {
48
+ return tokens.get(name);
49
+ }
50
+ function deleteDynamicToken(name) {
51
+ if (!tokens.delete(name)) return;
52
+ if (typeof document !== "undefined") document.documentElement.style.removeProperty(`--${name}`);
53
+ notify();
54
+ }
55
+ function subscribeDynamicTokens(listener) {
56
+ listeners.add(listener);
57
+ return () => listeners.delete(listener);
58
+ }
59
+ function getDynamicTokensVersion() {
60
+ return version;
61
+ }
62
+ function _resetForTests() {
63
+ tokens.clear();
64
+ listeners.clear();
65
+ version = 0;
66
+ }
67
+ // Annotate the CommonJS export names for ESM import in node:
68
+ 0 && (module.exports = {
69
+ _resetForTests,
70
+ deleteDynamicToken,
71
+ getDynamicToken,
72
+ getDynamicTokensVersion,
73
+ setDynamicToken,
74
+ subscribeDynamicTokens
75
+ });
package/dist/index.d.ts CHANGED
@@ -1,19 +1,15 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
3
-
4
- interface ThemeConfig {
5
- /** Plain hex only, this pass — e.g. "blue-6" -> "#2563eb" */
6
- colors: Record<string, string>;
7
- spacing: Record<string, number>;
8
- screens: Record<string, number>;
9
- darkMode: 'attribute' | 'class' | 'media';
10
- }
11
- declare const defaultTheme: ThemeConfig;
12
- declare function setTheme(theme: ThemeConfig): void;
13
- declare function getTheme(): ThemeConfig;
1
+ export { ColorEntry, ContainerConfig, ThemeConfig, defaultTheme, getTheme, setTheme } from './theme';
2
+ export { C as ColorScale, a as ColorsAPI, K as KbachConfig, T as ThemeProvider, b as ThemeProviderProps, c as ThemeState, d as applyKbachConfig, r as resolveKbachConfig, u as useColors, e as useDynamicToken, f as useTheme } from './useDynamicToken-Dr15c88t.js';
3
+ export { ThemeMode, getGlobalDarkMode, getGlobalThemeMode, setGlobalThemeMode, subscribeGlobalDarkMode, toggleGlobalDarkMode } from './darkModeStore';
4
+ export { deleteDynamicToken, getDynamicToken, setDynamicToken, subscribeDynamicTokens } from './dynamicTokens';
5
+ import 'react';
14
6
 
7
+ type StyleValue = string | number | {
8
+ width: number;
9
+ height: number;
10
+ };
15
11
  interface StyleObject {
16
- [key: string]: string | number;
12
+ [key: string]: StyleValue;
17
13
  }
18
14
  /**
19
15
  * Calls the Rust engine via the KbachModule TurboModule (see
@@ -32,10 +28,9 @@ interface StyleObject {
32
28
  * whenever the mode is `'system'` (its own default), so nothing regresses
33
29
  * for apps that never touch the override API at all. This function itself
34
30
  * has no subscription of its own, so nothing re-renders just because the
35
- * store's value changed — call `useGlobalDarkMode()` (or consume
36
- * `useTheme()`'s `isDark`) somewhere in the tree for that, NOT React
37
- * Native's own `useColorScheme()`, which only reflects the raw OS setting
38
- * and would miss an explicit override entirely.
31
+ * store's value changed — call `useTheme()` (its `isDark`) somewhere in
32
+ * the tree for that, NOT React Native's own `useColorScheme()`, which only
33
+ * reflects the raw OS setting and would miss an explicit override entirely.
39
34
  *
40
35
  * Phase 11 originally shipped with live in-place theme switching unverified
41
36
  * (a `uiMode` toggle triggered a re-render but `Appearance.getColorScheme()`
@@ -59,90 +54,46 @@ interface StyleObject {
59
54
  * `Pressable` ever knows this, so it's passed in directly by the caller
60
55
  * (jsx-runtime, from Pressable's own style-function callback) rather than
61
56
  * queried here. Defaults to `false` for every other element type.
62
- */
63
- declare function resolveStyle(classString: string, pressed?: boolean): StyleObject;
64
-
65
- /**
66
- * Native port of @kbach/react's darkModeStore.ts — same architecture (a
67
- * single module-level store is the real source of truth;
68
- * ThemeProvider/useTheme are a thin, OPTIONAL wrapper around it; every
69
- * function here works standalone with no provider mounted anywhere), with
70
- * two real platform differences from the web version:
71
57
  *
72
- * 1. No persistence. There's no React-Native-builtin equivalent of
73
- * localStorage — adding one would mean forcing a real native dependency
74
- * (e.g. @react-native-async-storage/async-storage) on every consumer,
75
- * even ones that don't want it. The mode always starts at 'system' on a
76
- * fresh app launch. If you want persistence, read your own storage at
77
- * startup (before your first render) and call setGlobalThemeMode() with
78
- * the result — same "seed once, no built-in write-back" shape as
79
- * seedDefaultMode() below, just driven by your own storage instead of
80
- * one this package picks for you.
81
- * 2. No DOM to "apply" the resolved mode to. On web, applyToDom() flips a
82
- * class/attribute the generated CSS's `dark:` selectors match against.
83
- * On native there's no CSS at all — nativeBridge.ts's resolveStyle()
84
- * reads getGlobalDarkMode() directly on every call instead of querying
85
- * Appearance.getColorScheme() itself, which is what actually makes an
86
- * explicit override affect rendering (previously that function always
87
- * read the raw OS setting, so it had no way to reflect a user choice —
88
- * see nativeBridge.ts's own comment on this for why that's the one
89
- * genuinely fixed bug this change introduces, not just a new feature).
90
- */
91
- type ThemeMode = 'light' | 'dark' | 'system';
92
- declare function getGlobalDarkMode(): boolean;
93
- declare function getGlobalThemeMode(): ThemeMode;
94
- /** Explicit user choice — takes priority over any later `<ThemeProvider defaultMode>` seed (see `seedDefaultMode` below). Not persisted; see this module's own doc comment. */
95
- declare function setGlobalThemeMode(nextMode: ThemeMode): void;
96
- declare function toggleGlobalDarkMode(): void;
97
- declare function subscribeGlobalDarkMode(listener: () => void): () => void;
98
-
99
- /**
100
- * Reactive read of the global dark-mode store — works with or without a
101
- * `<ThemeProvider>` mounted anywhere in the tree, since it subscribes to
102
- * `darkModeStore.ts` directly. No server-snapshot argument (unlike
103
- * @kbach/react's web version) — React Native has no SSR concept at all,
104
- * so there's no third argument for `useSyncExternalStore` to need.
105
- */
106
- declare function useGlobalDarkMode(): boolean;
107
-
108
- interface ThemeProviderProps {
109
- children: ReactNode;
110
- /**
111
- * Applied once, on this provider's first mount, but ONLY if nothing has
112
- * made an explicit mode choice yet (see
113
- * `darkModeStore.ts::seedDefaultMode`) — an explicit prior choice always
114
- * wins over a component's own default. Unlike @kbach/react's web
115
- * version, there's no persisted value to check here — see
116
- * darkModeStore.ts's own doc comment on why this package doesn't persist
117
- * the mode across app launches.
118
- */
119
- defaultMode?: ThemeMode;
120
- }
121
- /**
122
- * Native port of @kbach/react's `ThemeProvider` — a thin, OPTIONAL React
123
- * Context wrapper around `darkModeStore.ts`'s single global store, not the
124
- * source of truth itself. Because the store is global, MULTIPLE mounted
125
- * providers share the exact same `mode`/`isDark` state rather than each
126
- * getting their own scoped value — mounting more than one is very likely a
127
- * mistake (each fighting over the same state via a different
128
- * `defaultMode`), so this warns once in dev, matching the web version's
129
- * identical guard.
130
- */
131
- declare function ThemeProvider({ children, defaultMode }: ThemeProviderProps): react.JSX.Element;
132
-
133
- interface ThemeContextValue {
134
- mode: ThemeMode;
135
- isDark: boolean;
136
- setMode: (mode: ThemeMode) => void;
137
- toggle: () => void;
138
- }
139
- /**
140
- * Requires a `<ThemeProvider>` ancestor — throws otherwise, since a
141
- * component that destructures `{ mode, setMode }` genuinely needs Context
142
- * (unlike a component that just wants the dark/light boolean, which should
143
- * reach for `useGlobalDarkMode()` instead and never needs a provider at
144
- * all).
58
+ * `width` gates `sm:`/`md:`/`lg:`/`xl:`/`2xl:` against the active theme's
59
+ * `screens` scale (resolve_style.rs's `native_modifier_state`) — read fresh
60
+ * from `Dimensions.get('window').width` on every call, the same "no
61
+ * caching, no store" choice `colorScheme`/`pressed` already make, and for
62
+ * the same reason: unlike dark mode there's no explicit-override concept to
63
+ * preserve here (nobody manually overrides their screen width), so a plain
64
+ * synchronous read is enough — no need for the subscribable store
65
+ * darkModeStore.ts is for. As with `colorScheme`, this function has no
66
+ * subscription of its own, so rotating/resizing the window doesn't
67
+ * re-render anything by itself — call RN's own `useWindowDimensions()`
68
+ * somewhere in the tree for that (same role `useColorScheme()` plays for
69
+ * `dark:` in apps/native-sandbox/App.tsx).
70
+ *
71
+ * Falls back to `./jsEngine` (a pure-JS, no-WASM/no-native reimplementation
72
+ * of this same resolution logic — see that directory's own doc comments)
73
+ * when `KbachModule` isn't registered at all — Expo Go, which can never
74
+ * load ANY custom native module (not even Expo's own Modules API), so the
75
+ * TurboModule this file otherwise depends on simply doesn't exist there.
76
+ * `TurboModuleRegistry.get` (not `.getEnforcing`, which throws) is what
77
+ * makes this detectable at all — `get` returns `null`/`undefined` instead.
78
+ * A real dev-client/CLI build always has the module registered, so this
79
+ * fallback only ever activates in Expo Go itself; everywhere else behaves
80
+ * exactly as before. The JS engine covers a strict subset of what the
81
+ * native/WASM engines resolve (see jsEngine/resolveUtilityNative.ts) — an
82
+ * intentional, documented parity gap, not a bug.
83
+ *
84
+ * An arbitrary value that couldn't be resolved to something RN's style
85
+ * system can actually use (an unreduced percentage/viewport-relative
86
+ * `calc()`, a raw `var(...)`, ...) is dropped from the returned style —
87
+ * never passed through as an invalid string — and surfaced via
88
+ * `console.warn` here (dev builds only, mirroring RN's own convention for
89
+ * this kind of non-fatal correctness warning) rather than failing
90
+ * silently. The native/JNI path embeds these under a `"__kbachWarnings"`
91
+ * key in the same JSON `resolve_style_json` already returns (see that
92
+ * function's own doc comment for why — reusing the one JSON round-trip
93
+ * rather than adding a second FFI call); the jsEngine fallback returns
94
+ * them directly via `resolveStyleJsWithWarnings`. Both paths converge here
95
+ * so call sites never need to know which engine actually resolved anything.
145
96
  */
146
- declare function useTheme(): ThemeContextValue;
97
+ declare function resolveStyle(classString: string, pressed?: boolean): StyleObject;
147
98
 
148
- export { type StyleObject, type ThemeConfig, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, defaultTheme, getGlobalDarkMode, getGlobalThemeMode, getTheme, resolveStyle, setGlobalThemeMode, setTheme, subscribeGlobalDarkMode, toggleGlobalDarkMode, useGlobalDarkMode, useTheme };
99
+ export { type StyleObject, resolveStyle };