@kbach/react-native 1.0.0-beta.14 → 1.0.0-beta.15

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.d.ts DELETED
@@ -1,83 +0,0 @@
1
- export { C as ColorEntry, a as ColorScale, b as ColorsAPI, c as ContainerConfig, K as KbachConfig, T as ThemeConfig, d as ThemeMode, e as ThemeProvider, f as ThemeProviderProps, g as ThemeState, h as applyKbachConfig, i as defaultTheme, j as getGlobalDarkMode, k as getGlobalThemeMode, l as getTheme, r as resolveKbachConfig, s as setGlobalThemeMode, m as setTheme, n as subscribeGlobalDarkMode, t as toggleGlobalDarkMode, u as useColors, o as useTheme } from './useColors-C6jyCLuG.js';
2
- import 'react';
3
-
4
- type StyleValue = string | number | {
5
- width: number;
6
- height: number;
7
- };
8
- interface StyleObject {
9
- [key: string]: StyleValue;
10
- }
11
- /**
12
- * Calls the Rust engine via the KbachModule TurboModule (see
13
- * apps/native-sandbox/android/.../KbachModule.kt and
14
- * packages/core-engine/src/resolve_style.rs) and returns a plain style
15
- * object ready for RN's `style` prop. Synchronous — no async init step,
16
- * unlike the web/WASM path, since JSI-backed TurboModule methods are
17
- * available as soon as the module is loaded.
18
- *
19
- * Reads `getGlobalDarkMode()` (darkModeStore.ts) fresh on every call (no
20
- * caching) so `dark:` resolves correctly whenever this runs. That store —
21
- * not a direct `Appearance.getColorScheme()` read, which this function
22
- * used prior to `<ThemeProvider>` support — is what makes an explicit
23
- * `setGlobalThemeMode('dark')`/`toggle()` override actually affect
24
- * rendering; the store itself falls back to tracking `Appearance` live
25
- * whenever the mode is `'system'` (its own default), so nothing regresses
26
- * for apps that never touch the override API at all. This function itself
27
- * has no subscription of its own, so nothing re-renders just because the
28
- * store's value changed — call `useTheme()` (its `isDark`) somewhere in
29
- * the tree for that, NOT React Native's own `useColorScheme()`, which only
30
- * reflects the raw OS setting and would miss an explicit override entirely.
31
- *
32
- * Phase 11 originally shipped with live in-place theme switching unverified
33
- * (a `uiMode` toggle triggered a re-render but `Appearance.getColorScheme()`
34
- * kept returning a stale value). Root-caused in Phase 12 while debugging an
35
- * unrelated `active:` failure: `apps/native-sandbox` has its own separate
36
- * `node_modules/react-native` (excluded from the npm workspace since Phase
37
- * 5), while `packages/react-native` resolved `react-native` hierarchically
38
- * up to a *different* copy at the repo root — two physical module
39
- * instances, so a `useColorScheme()` subscription and an
40
- * `Appearance.getColorScheme()` read were silently talking to two separate
41
- * copies of the Appearance module. Fixed by forcing a single instance via
42
- * `resolver.resolveRequest` in apps/native-sandbox/metro.config.js; live
43
- * theme switching (and `active:`, the bug that surfaced this) both verified
44
- * working after the fix — see Phase 12. Still relevant here: darkModeStore.ts
45
- * itself calls `Appearance.addChangeListener`, so the same dual-instance
46
- * failure mode would silently break the 'system' fallback path too if that
47
- * metro.config.js fix ever regressed.
48
- *
49
- * `pressed` gates the `active:` modifier — unlike `colorScheme`, there's no
50
- * system-level getter for "is this element currently pressed"; only RN's
51
- * `Pressable` ever knows this, so it's passed in directly by the caller
52
- * (jsx-runtime, from Pressable's own style-function callback) rather than
53
- * queried here. Defaults to `false` for every other element type.
54
- *
55
- * `width` gates `sm:`/`md:`/`lg:`/`xl:`/`2xl:` against the active theme's
56
- * `screens` scale (resolve_style.rs's `native_modifier_state`) — read fresh
57
- * from `Dimensions.get('window').width` on every call, the same "no
58
- * caching, no store" choice `colorScheme`/`pressed` already make, and for
59
- * the same reason: unlike dark mode there's no explicit-override concept to
60
- * preserve here (nobody manually overrides their screen width), so a plain
61
- * synchronous read is enough — no need for the subscribable store
62
- * darkModeStore.ts is for. As with `colorScheme`, this function has no
63
- * subscription of its own, so rotating/resizing the window doesn't
64
- * re-render anything by itself — call RN's own `useWindowDimensions()`
65
- * somewhere in the tree for that (same role `useColorScheme()` plays for
66
- * `dark:` in apps/native-sandbox/App.tsx).
67
- *
68
- * Falls back to `./jsEngine` (a pure-JS, no-WASM/no-native reimplementation
69
- * of this same resolution logic — see that directory's own doc comments)
70
- * when `KbachModule` isn't registered at all — Expo Go, which can never
71
- * load ANY custom native module (not even Expo's own Modules API), so the
72
- * TurboModule this file otherwise depends on simply doesn't exist there.
73
- * `TurboModuleRegistry.get` (not `.getEnforcing`, which throws) is what
74
- * makes this detectable at all — `get` returns `null`/`undefined` instead.
75
- * A real dev-client/CLI build always has the module registered, so this
76
- * fallback only ever activates in Expo Go itself; everywhere else behaves
77
- * exactly as before. The JS engine covers a strict subset of what the
78
- * native/WASM engines resolve (see jsEngine/resolveUtilityNative.ts) — an
79
- * intentional, documented parity gap, not a bug.
80
- */
81
- declare function resolveStyle(classString: string, pressed?: boolean): StyleObject;
82
-
83
- export { type StyleObject, resolveStyle };
@@ -1,15 +0,0 @@
1
- export { C as ColorEntry, a as ColorScale, b as ColorsAPI, c as ContainerConfig, K as KbachConfig, T as ThemeConfig, d as ThemeMode, e as ThemeProvider, f as ThemeProviderProps, g as ThemeState, h as applyKbachConfig, i as defaultTheme, j as getGlobalDarkMode, k as getGlobalThemeMode, l as getTheme, r as resolveKbachConfig, s as setGlobalThemeMode, m as setTheme, n as subscribeGlobalDarkMode, t as toggleGlobalDarkMode, u as useColors, o as useTheme } from './useColors-C6jyCLuG.js';
2
- import 'react';
3
-
4
- /**
5
- * Resolves `classString` to CSS via the WASM engine, injects every returned
6
- * rule into a shared `<style data-kbach-rn>` tag (cascade-order-safe — see
7
- * cssInjector.web.ts), and returns the class string to use as
8
- * `dataSet={{ kb: <returned value> }}`. MUST use the returned value, not the
9
- * original input — mode-aware color names (e.g. `bg-surface`) expand into a
10
- * literal light/dark pair, and the generated rules target that expanded
11
- * text, not the original.
12
- */
13
- declare function resolveClassName(classString: string): string;
14
-
15
- export { resolveClassName };
@@ -1,10 +0,0 @@
1
- import * as react from 'react';
2
- export { Fragment } from 'react';
3
-
4
- declare const jsxDEV: (type: unknown, props: Record<string, unknown> | null, key?: string, isStaticChildren?: boolean, source?: {
5
- fileName: string;
6
- lineNumber: number;
7
- columnNumber: number;
8
- }, self?: unknown) => react.ReactElement;
9
-
10
- export { jsxDEV };
@@ -1,10 +0,0 @@
1
- import * as react from 'react';
2
- export { Fragment } from 'react';
3
-
4
- declare const jsxDEV: (type: unknown, props: Record<string, unknown> | null, key?: string, isStaticChildren?: boolean, source?: {
5
- fileName: string;
6
- lineNumber: number;
7
- columnNumber: number;
8
- }, self?: unknown) => react.ReactElement;
9
-
10
- export { jsxDEV };
@@ -1,7 +0,0 @@
1
- import * as react from 'react';
2
- export { Fragment, JSX } from 'react';
3
-
4
- declare const jsx: (type: unknown, props: Record<string, unknown> | null, key?: string) => react.ReactElement;
5
- declare const jsxs: (type: unknown, props: Record<string, unknown> | null, key?: string) => react.ReactElement;
6
-
7
- export { jsx, jsxs };
@@ -1,7 +0,0 @@
1
- import * as react from 'react';
2
- export { Fragment, JSX } from 'react';
3
-
4
- declare const jsx: (type: unknown, props: Record<string, unknown> | null, key?: string) => react.ReactElement;
5
- declare const jsxs: (type: unknown, props: Record<string, unknown> | null, key?: string) => react.ReactElement;
6
-
7
- export { jsx, jsxs };
@@ -1,239 +0,0 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
3
-
4
- /**
5
- * A plain hex value (static — same in both modes), or a `{ light, dark }`
6
- * pair a caller sets manually in their own theme. Fully opt-in per color:
7
- * nothing here picks a "dark variant" automatically. Only `useColors()`
8
- * (a JS-value read, not a `className`) understands this shape — utility
9
- * CLASS resolution (`bg-blue-6`) on native/Expo Go stays plain-string-only,
10
- * same as it always was (dark mode for a CLASS is the separate `dark:`
11
- * modifier, gated live at resolve time — see `resolve_style.rs`); a
12
- * mode-aware entry referenced directly by a class name just doesn't
13
- * resolve there, mirroring `resolvers/color.rs`'s own `lookup_hex`
14
- * (`ColorValue::Plain` only, `ModeAware` -> `None`) exactly, same as it
15
- * would on the web engine too.
16
- */
17
- type ColorEntry = string | {
18
- light: string;
19
- dark: string;
20
- };
21
- /**
22
- * Real Tailwind's `theme.container` config, mirroring
23
- * `packages/core-engine/src/theme.rs`'s `ContainerConfig` exactly. `center`/
24
- * `padding` DO reach native now (unlike the max-width breakpoint ladder,
25
- * which is a `css.rs`-only concept with nothing to generate on native at
26
- * all) — `resolvers::layout::resolve`'s `"container"` arm is shared by both
27
- * dispatchers, and `margin`/`padding` are ordinary RN style properties.
28
- */
29
- interface ContainerConfig {
30
- center?: boolean;
31
- padding?: string;
32
- }
33
- interface ThemeConfig {
34
- colors: Record<string, ColorEntry>;
35
- spacing: Record<string, number>;
36
- screens: Record<string, number>;
37
- /**
38
- * e.g. "sans" -> "Inter, sans-serif". Optional, matching the Rust
39
- * engine's own `#[serde(default)]`. Write it as a real web-shaped
40
- * fallback stack even on this native-first package — native's own
41
- * resolver strips it down to a single bare name at resolve time (RN's
42
- * `fontFamily` prop can't take a fallback list — see
43
- * `resolvers/mod.rs`'s `first_font_name`), so the SAME config still
44
- * works unmodified on Expo Web, which needs the full stack.
45
- */
46
- fontFamily?: Record<string, string>;
47
- darkMode: 'attribute' | 'class' | 'media';
48
- /** Optional, matching `ContainerConfig`'s own `#[serde(default)]` on the Rust side. */
49
- container?: ContainerConfig;
50
- }
51
- declare const defaultTheme: ThemeConfig;
52
- declare function setTheme(theme: ThemeConfig): void;
53
- declare function getTheme(): ThemeConfig;
54
-
55
- /**
56
- * A `kbach.config.js`-style theme customization — same shape as
57
- * @kbach/react's `KbachConfig`, minus mode-aware `{ light, dark }` color
58
- * entries in `extend.colors` specifically: aliasing/opacity math here only
59
- * ever operates on plain hex (`brand: 'blue-6'`, `brandSoft: 'brand/30'`),
60
- * matching `jsEngine/resolvers/color.ts`'s `lookupHex`'s own Plain-only
61
- * convention — a reference to an EXISTING color that happens to be
62
- * mode-aware (`theme.colors` can hold those now, for `useColors()`; see
63
- * `theme.ts`'s own `ColorEntry` doc comment) just doesn't resolve as an
64
- * alias, falling through to "literal CSS value" the same way an unknown
65
- * name would. A config object goes in, a resolved `ThemeConfig` comes out,
66
- * via one PURE function (`resolveKbachConfig`) — no plugins, no
67
- * live-update store, nothing to keep "in sync."
68
- */
69
- interface KbachConfig {
70
- darkMode?: ThemeConfig['darkMode'];
71
- /**
72
- * REPLACES the named section of `defaultTheme` entirely — use `extend` to
73
- * add instead of replace. `container` isn't here (only under `extend`
74
- * below) — see @kbach/react's identical `KbachConfig.theme` doc comment
75
- * for why.
76
- */
77
- theme?: Partial<Pick<ThemeConfig, 'colors' | 'spacing' | 'screens' | 'fontFamily'>>;
78
- /** Merges INTO `defaultTheme` (or `theme` above, if also supplied) — the common case. */
79
- extend?: {
80
- /**
81
- * A value is either a literal hex color, or a REFERENCE to another
82
- * color name, optionally with an opacity suffix. Two things can be
83
- * referenced: a BUILT-IN palette color, always available regardless of
84
- * ordering (`accent: 'orange-5'`, `accentSoft: 'orange-5/50'`), or a
85
- * custom color defined EARLIER in this same object (`{ brand:
86
- * '#ff6b35', brandSoft: 'brand/30' }` — `brandSoft` resolves to
87
- * `brand`'s own value at 30% opacity). A string that doesn't match any
88
- * known color name is treated as a literal CSS value instead.
89
- */
90
- colors?: Record<string, string>;
91
- spacing?: Record<string, number>;
92
- screens?: Record<string, number>;
93
- /**
94
- * Named font stacks, e.g. `{ display: '"Cal Sans", sans-serif' }` —
95
- * adds to (or overrides one of) `defaultTheme.fontFamily`'s three
96
- * names. Write it as a real web-shaped fallback stack even though this
97
- * is the React Native package — native's own resolver strips it down
98
- * to a single bare name at resolve time (RN's `fontFamily` prop can't
99
- * take a fallback list), so the SAME config still works unmodified on
100
- * Expo Web, which needs the full stack.
101
- */
102
- fontFamily?: Record<string, string>;
103
- /** `{ center: true, padding: '2rem' }` — see `ContainerConfig`'s own doc comment. */
104
- container?: ContainerConfig;
105
- };
106
- }
107
- /** Merges a `KbachConfig` into `defaultTheme` — a pure function, no side effects. */
108
- declare function resolveKbachConfig(config: KbachConfig): ThemeConfig;
109
- /** `resolveKbachConfig()` + `setTheme()` in one call — the usual entry point from app code. */
110
- declare function applyKbachConfig(config: KbachConfig): ThemeConfig;
111
-
112
- /**
113
- * Native port of @kbach/react's darkModeStore.ts — same architecture (a
114
- * single module-level store is the real source of truth;
115
- * ThemeProvider/useTheme are a thin, OPTIONAL wrapper around it; every
116
- * function here works standalone with no provider mounted anywhere), with
117
- * two real platform differences from the web version:
118
- *
119
- * 1. No persistence. There's no React-Native-builtin equivalent of
120
- * localStorage — adding one would mean forcing a real native dependency
121
- * (e.g. @react-native-async-storage/async-storage) on every consumer,
122
- * even ones that don't want it. The mode always starts at 'system' on a
123
- * fresh app launch. If you want persistence, read your own storage at
124
- * startup (before your first render) and call setGlobalThemeMode() with
125
- * the result — same "seed once, no built-in write-back" shape as
126
- * seedDefaultMode() below, just driven by your own storage instead of
127
- * one this package picks for you.
128
- * 2. `applyToDom` below IS needed here, unlike what an earlier version of
129
- * this file's own comment claimed ("no DOM to apply the resolved mode
130
- * to") — that reasoning only holds for real native (Android/iOS), where
131
- * nativeBridge.ts's resolveStyle() reads getGlobalDarkMode() directly on
132
- * every call, no DOM involved at all. This file is ALSO used by Expo
133
- * Web, though (no `.web.ts` sibling — Metro has nothing to swap in), and
134
- * Expo Web resolves `dark:` classes to REAL CSS with `[data-theme=
135
- * "dark"]`-style selectors (see nativeBridge.web.ts) that only ever
136
- * match if something writes that attribute to the DOM — nothing did,
137
- * which is exactly why toggling the mode changed `useTheme()`'s own
138
- * state (a consumer reading `mode`/`isDark` directly, e.g. for a label,
139
- * updated correctly) while every `dark:`-prefixed style silently never
140
- * applied. `typeof document === 'undefined'` is what makes one function
141
- * safe on both platforms: real native's Hermes has no `document` global
142
- * at all (not even `undefined` as a defined-but-empty value — genuinely
143
- * unset, which `typeof` can check without throwing), so this always
144
- * no-ops there, while Expo Web's react-native-web renders into a real
145
- * browser DOM where it's needed.
146
- */
147
- type ThemeMode = 'light' | 'dark' | 'system';
148
- declare function getGlobalDarkMode(): boolean;
149
- declare function getGlobalThemeMode(): ThemeMode;
150
- /** Explicit user choice — takes priority over any later `<ThemeProvider defaultMode>` seed (see `seedDefaultMode` below). Not persisted; see this module's own doc comment. */
151
- declare function setGlobalThemeMode(nextMode: ThemeMode): void;
152
- declare function toggleGlobalDarkMode(): void;
153
- declare function subscribeGlobalDarkMode(listener: () => void): () => void;
154
-
155
- interface ThemeState {
156
- mode: ThemeMode;
157
- isDark: boolean;
158
- setMode: (mode: ThemeMode) => void;
159
- toggle: () => void;
160
- }
161
- /**
162
- * The one hook for reading and writing Kbach's dark-mode state. Reads
163
- * `darkModeStore.ts`'s global store directly via `useSyncExternalStore` —
164
- * that module-level store, not React Context, is the actual source of
165
- * truth (every provider used to just mirror it into a Context value), so
166
- * this works from ANY component, with or without a `<ThemeProvider>`
167
- * mounted anywhere in the tree. `<ThemeProvider>` still exists, but purely
168
- * as an optional convenience for seeding an app's initial `defaultMode` —
169
- * see its own doc comment. No server-snapshot argument (unlike
170
- * @kbach/react's web version) — React Native has no SSR concept at all,
171
- * so there's no third argument for `useSyncExternalStore` to need.
172
- */
173
- declare function useTheme(): ThemeState;
174
-
175
- interface ThemeProviderProps {
176
- children: ReactNode;
177
- /**
178
- * Applied once, on this provider's first mount, but ONLY if nothing has
179
- * made an explicit mode choice yet (see
180
- * `darkModeStore.ts::seedDefaultMode`) — an explicit prior choice always
181
- * wins over a component's own default. Unlike @kbach/react's web
182
- * version, there's no persisted value to check here — see
183
- * darkModeStore.ts's own doc comment on why this package doesn't persist
184
- * the mode across app launches.
185
- */
186
- defaultMode?: ThemeMode;
187
- }
188
- /**
189
- * Optional — `useTheme()` reads `darkModeStore.ts`'s global store directly
190
- * and works anywhere without this mounted at all. The only thing this
191
- * component does is seed that store's initial `defaultMode` once, for apps
192
- * that want to declare a startup default in JSX rather than calling
193
- * `setGlobalThemeMode()` imperatively before their first render. It
194
- * renders `children` as-is — no Context.Provider, since there's no value
195
- * left to distribute; `useTheme()` never reads from Context.
196
- *
197
- * Because the store is global, MULTIPLE mounted providers would each try
198
- * to seed the exact same store rather than getting their own scoped
199
- * state — mounting more than one is very likely a mistake, so this warns
200
- * once in dev.
201
- */
202
- declare function ThemeProvider({ children, defaultMode }: ThemeProviderProps): react.JSX.Element;
203
-
204
- interface ColorScale {
205
- /** `colors.blue[6]` -> raw value */
206
- readonly [shade: number]: string;
207
- /** `colors.blue['6/50']` -> shade 6 at 50% opacity */
208
- readonly [key: string]: string;
209
- }
210
- type ColorsAPI = {
211
- /** `colors.white`, `colors.blue` (a shade family), ... */
212
- readonly [name: string]: string | ColorScale;
213
- } & {
214
- /** Applies an opacity (0–100) to any color string this hook can return. */
215
- readonly alpha: (color: string, opacity?: number) => string;
216
- };
217
- /**
218
- * Resolved theme colors as real values — for anywhere you need an actual
219
- * color (a chart library prop, a raw SVG `fill`), not a `className`. Ported
220
- * from old-kbach's `useColors()`, adapted to this engine's flat
221
- * `"blue-6"`-keyed palette (`colors.blue[6]` looks up `"blue-6"`).
222
- *
223
- * Any color — a shade-family entry like `"blue-6"` or a standalone name —
224
- * can be defined in the theme as either a plain string (static, same in
225
- * both modes) or a `{ light, dark }` pair — fully manual, no automatic
226
- * shade-shifting or other assumption about what a "dark variant" should
227
- * be; see `resolveEntry`'s own doc comment for how a `{ light, dark }`
228
- * entry resolves on this platform specifically.
229
- *
230
- * ```ts
231
- * const colors = useColors();
232
- * colors.blue[6]; // "#2563eb" — static, same value in both modes
233
- * colors.blue['6/50']; // same, at 50% opacity
234
- * colors.brand; // resolves per isDark if defined as { light, dark }
235
- * ```
236
- */
237
- declare function useColors(): ColorsAPI;
238
-
239
- export { type ColorEntry as C, type KbachConfig as K, type ThemeConfig as T, type ColorScale as a, type ColorsAPI as b, type ContainerConfig as c, type ThemeMode as d, ThemeProvider as e, type ThemeProviderProps as f, type ThemeState as g, applyKbachConfig as h, defaultTheme as i, getGlobalDarkMode as j, getGlobalThemeMode as k, getTheme as l, setTheme as m, subscribeGlobalDarkMode as n, useTheme as o, resolveKbachConfig as r, setGlobalThemeMode as s, toggleGlobalDarkMode as t, useColors as u };