@kbach/react 0.2.3 → 0.2.4

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.mts CHANGED
@@ -142,14 +142,29 @@ declare function useTheme(): ThemeContextValue;
142
142
 
143
143
  interface ThemeProviderProps {
144
144
  children: ReactNode;
145
- /** Default mode on first render. Falls back to persisted value, then 'system'. */
145
+ /** Initial mode. Falls back to persisted value, then 'system'. */
146
146
  defaultMode?: ThemeMode;
147
+ /**
148
+ * Explicit color scheme override for native with `defaultMode="system"`.
149
+ *
150
+ * On some Android devices the system scheme is not detected on startup
151
+ * (the `appearanceChanged` event only fires on *changes*, not on launch when
152
+ * the device was already dark). Pass `useColorScheme()` from `react-native`
153
+ * here to guarantee correct detection:
154
+ *
155
+ * ```tsx
156
+ * import { useColorScheme } from 'react-native';
157
+ * const scheme = useColorScheme();
158
+ * <ThemeProvider defaultMode="system" colorScheme={scheme}>…</ThemeProvider>
159
+ * ```
160
+ */
161
+ colorScheme?: 'light' | 'dark' | null;
147
162
  /** Override the config (useful for per-tree config). Defaults to global getConfig(). */
148
163
  config?: FrameworkConfig;
149
- /** Disable persistence to localStorage / AsyncStorage */
164
+ /** Disable persistence to localStorage */
150
165
  disablePersistence?: boolean;
151
166
  }
152
- declare function ThemeProvider({ children, defaultMode, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
167
+ declare function ThemeProvider({ children, defaultMode, colorScheme: colorSchemeProp, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
153
168
 
154
169
  type ToggleVariant = 'button' | 'switch' | 'icon-button';
155
170
  interface ThemeToggleProps {
package/dist/index.d.ts CHANGED
@@ -142,14 +142,29 @@ declare function useTheme(): ThemeContextValue;
142
142
 
143
143
  interface ThemeProviderProps {
144
144
  children: ReactNode;
145
- /** Default mode on first render. Falls back to persisted value, then 'system'. */
145
+ /** Initial mode. Falls back to persisted value, then 'system'. */
146
146
  defaultMode?: ThemeMode;
147
+ /**
148
+ * Explicit color scheme override for native with `defaultMode="system"`.
149
+ *
150
+ * On some Android devices the system scheme is not detected on startup
151
+ * (the `appearanceChanged` event only fires on *changes*, not on launch when
152
+ * the device was already dark). Pass `useColorScheme()` from `react-native`
153
+ * here to guarantee correct detection:
154
+ *
155
+ * ```tsx
156
+ * import { useColorScheme } from 'react-native';
157
+ * const scheme = useColorScheme();
158
+ * <ThemeProvider defaultMode="system" colorScheme={scheme}>…</ThemeProvider>
159
+ * ```
160
+ */
161
+ colorScheme?: 'light' | 'dark' | null;
147
162
  /** Override the config (useful for per-tree config). Defaults to global getConfig(). */
148
163
  config?: FrameworkConfig;
149
- /** Disable persistence to localStorage / AsyncStorage */
164
+ /** Disable persistence to localStorage */
150
165
  disablePersistence?: boolean;
151
166
  }
152
- declare function ThemeProvider({ children, defaultMode, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
167
+ declare function ThemeProvider({ children, defaultMode, colorScheme: colorSchemeProp, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
153
168
 
154
169
  type ToggleVariant = 'button' | 'switch' | 'icon-button';
155
170
  interface ThemeToggleProps {
package/dist/index.js CHANGED
@@ -2098,13 +2098,16 @@ function applyWebTheme(resolvedMode, strategy) {
2098
2098
  function ThemeProvider({
2099
2099
  children,
2100
2100
  defaultMode = "system",
2101
+ colorScheme: colorSchemeProp,
2101
2102
  config: configOverride,
2102
2103
  disablePersistence = false
2103
2104
  }) {
2104
2105
  const [resolvedConfig, setResolvedConfig] = (0, import_react2.useState)(
2105
2106
  () => configOverride ? buildConfig(configOverride) : getConfig()
2106
2107
  );
2107
- const nativeScheme = _useColorScheme?.();
2108
+ const [nativeSchemeFallback, setNativeSchemeFallback] = (0, import_react2.useState)(null);
2109
+ const hookScheme = _useColorScheme?.();
2110
+ const nativeScheme = colorSchemeProp !== void 0 ? colorSchemeProp ?? null : hookScheme ?? nativeSchemeFallback;
2108
2111
  const [webScheme, setWebScheme] = (0, import_react2.useState)(() => {
2109
2112
  if (isWeb && typeof window !== "undefined") {
2110
2113
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -2129,6 +2132,18 @@ function ThemeProvider({
2129
2132
  const resolvedMode = mode === "system" ? systemScheme : mode;
2130
2133
  const isDark = resolvedMode === "dark";
2131
2134
  syncGlobalDarkMode(isDark);
2135
+ (0, import_react2.useEffect)(() => {
2136
+ if (isWeb) return;
2137
+ try {
2138
+ const { TurboModuleRegistry } = require("react-native");
2139
+ const native = TurboModuleRegistry?.get?.("Appearance");
2140
+ const scheme = native?.getColorScheme?.();
2141
+ if (scheme === "dark" || scheme === "light") {
2142
+ setNativeSchemeFallback(scheme);
2143
+ }
2144
+ } catch {
2145
+ }
2146
+ }, []);
2132
2147
  (0, import_react2.useEffect)(() => {
2133
2148
  applyWebTheme(resolvedMode, resolvedConfig.darkMode);
2134
2149
  setGlobalDarkMode(isDark);
package/dist/index.mjs CHANGED
@@ -72,13 +72,16 @@ function applyWebTheme(resolvedMode, strategy) {
72
72
  function ThemeProvider({
73
73
  children,
74
74
  defaultMode = "system",
75
+ colorScheme: colorSchemeProp,
75
76
  config: configOverride,
76
77
  disablePersistence = false
77
78
  }) {
78
79
  const [resolvedConfig, setResolvedConfig] = useState(
79
80
  () => configOverride ? buildConfig(configOverride) : getConfig()
80
81
  );
81
- const nativeScheme = _useColorScheme?.();
82
+ const [nativeSchemeFallback, setNativeSchemeFallback] = useState(null);
83
+ const hookScheme = _useColorScheme?.();
84
+ const nativeScheme = colorSchemeProp !== void 0 ? colorSchemeProp ?? null : hookScheme ?? nativeSchemeFallback;
82
85
  const [webScheme, setWebScheme] = useState(() => {
83
86
  if (isWeb && typeof window !== "undefined") {
84
87
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -103,6 +106,18 @@ function ThemeProvider({
103
106
  const resolvedMode = mode === "system" ? systemScheme : mode;
104
107
  const isDark = resolvedMode === "dark";
105
108
  syncGlobalDarkMode(isDark);
109
+ useEffect(() => {
110
+ if (isWeb) return;
111
+ try {
112
+ const { TurboModuleRegistry } = __require("react-native");
113
+ const native = TurboModuleRegistry?.get?.("Appearance");
114
+ const scheme = native?.getColorScheme?.();
115
+ if (scheme === "dark" || scheme === "light") {
116
+ setNativeSchemeFallback(scheme);
117
+ }
118
+ } catch {
119
+ }
120
+ }, []);
106
121
  useEffect(() => {
107
122
  applyWebTheme(resolvedMode, resolvedConfig.darkMode);
108
123
  setGlobalDarkMode(isDark);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "React / React Native components and hooks for the Kbach framework",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./dist/index.js",