@rific/auto-paper 0.10.3 → 0.11.0

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
@@ -6,6 +6,8 @@ import { AppbarHeaderProps, MD3Theme, BottomNavigationRoute, BottomNavigationPro
6
6
  export { AppbarHeaderProps, BottomNavigationProps, BottomNavigationRoute, ButtonProps, FABProps, ChipProps as PaperChipProps, DialogProps as PaperDialogProps, IconButtonProps as PaperIconButtonProps, MenuProps as PaperMenuProps, TextInputProps } from 'react-native-paper';
7
7
  import * as react from 'react';
8
8
  import react__default, { RefObject, ReactNode, ComponentType } from 'react';
9
+ import * as _rific_core from '@rific/core';
10
+ import { SettingsContextValue } from '@rific/core';
9
11
 
10
12
  declare function useBlur(override?: boolean): boolean;
11
13
 
@@ -227,53 +229,46 @@ type ThemeState = {
227
229
  color: string | TriadicPalette;
228
230
  harmony: ColorHarmony;
229
231
  };
230
- type PayloadAction<P> = {
231
- payload: P;
232
- type: string;
233
- };
234
232
  declare const themeActions: {
235
233
  initialize: {
236
- (payload: Partial<ThemeState>): PayloadAction<Partial<ThemeState>>;
234
+ (payload: Partial<ThemeState>): _rific_core.SettingsAction<Partial<ThemeState>>;
237
235
  type: string;
238
- match(action: {
236
+ match: (action: {
239
237
  type: string;
240
- }): action is PayloadAction<Partial<ThemeState>>;
238
+ }) => action is _rific_core.SettingsAction<Partial<ThemeState>>;
241
239
  };
242
- setAppearance: {
243
- (payload: ThemeAppearance): PayloadAction<ThemeAppearance>;
240
+ } & {
241
+ setColor: {
242
+ (payload: string | TriadicPalette): _rific_core.SettingsAction<string | TriadicPalette>;
244
243
  type: string;
245
- match(action: {
244
+ match: (action: {
246
245
  type: string;
247
- }): action is PayloadAction<ThemeAppearance>;
246
+ }) => action is _rific_core.SettingsAction<string | TriadicPalette>;
248
247
  };
249
- setBlur: {
250
- (payload: boolean): PayloadAction<boolean>;
248
+ setAppearance: {
249
+ (payload: ThemeAppearance): _rific_core.SettingsAction<ThemeAppearance>;
251
250
  type: string;
252
- match(action: {
251
+ match: (action: {
253
252
  type: string;
254
- }): action is PayloadAction<boolean>;
253
+ }) => action is _rific_core.SettingsAction<ThemeAppearance>;
255
254
  };
256
- setColor: {
257
- (payload: string | TriadicPalette): PayloadAction<string | TriadicPalette>;
255
+ setBlur: {
256
+ (payload: boolean): _rific_core.SettingsAction<boolean>;
258
257
  type: string;
259
- match(action: {
258
+ match: (action: {
260
259
  type: string;
261
- }): action is PayloadAction<string | TriadicPalette>;
260
+ }) => action is _rific_core.SettingsAction<boolean>;
262
261
  };
263
262
  setHarmony: {
264
- (payload: ColorHarmony): PayloadAction<ColorHarmony>;
263
+ (payload: ColorHarmony): _rific_core.SettingsAction<ColorHarmony>;
265
264
  type: string;
266
- match(action: {
265
+ match: (action: {
267
266
  type: string;
268
- }): action is PayloadAction<ColorHarmony>;
267
+ }) => action is _rific_core.SettingsAction<ColorHarmony>;
269
268
  };
270
269
  };
271
- declare function createThemeReducer(initialState?: Partial<ThemeState>): (state: ThemeState | undefined, action: {
272
- type: string;
273
- }) => ThemeState;
274
- declare const themeReducer: (state: ThemeState | undefined, action: {
275
- type: string;
276
- }) => ThemeState;
270
+ declare const themeReducer: _rific_core.SettingsReducer<ThemeState>;
271
+ declare const createThemeReducer: (overrideInitialState?: Partial<ThemeState> | undefined) => _rific_core.SettingsReducer<ThemeState>;
277
272
  declare const selectThemeAppearance: (state: ThemeState) => ThemeAppearance;
278
273
  declare const selectThemeBlur: (state: ThemeState) => boolean;
279
274
  declare const selectThemeColor: (state: ThemeState) => string | TriadicPalette;
@@ -287,11 +282,8 @@ type ThemeSettings = {
287
282
  harmony: ColorHarmony;
288
283
  };
289
284
  declare const defaultThemeSettings: ThemeSettings;
290
- type ThemeSettingsContextType = {
291
- settings: ThemeSettings;
292
- set: (patch: Partial<ThemeSettings>) => void;
293
- };
294
- declare const ThemeSettingsContext: react.Context<ThemeSettingsContextType>;
285
+ type ThemeSettingsContextType = SettingsContextValue<ThemeSettings>;
286
+ declare const ThemeSettingsContext: react.Context<SettingsContextValue<ThemeSettings>>;
295
287
 
296
288
  type NavBarContextType = {
297
289
  navigationBar?: ExpoNavigationBarModule;
@@ -322,11 +314,11 @@ type ProviderProps = {
322
314
  statusBarProps?: StatusBarProps;
323
315
  style?: StyleProp<ViewStyle>;
324
316
  };
325
- declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
317
+ declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
326
318
 
327
319
  declare const useAutoPaperTheme: () => AutoPaperTheme;
328
320
 
329
- declare const useThemeSettings: () => ThemeSettingsContextType;
321
+ declare const useThemeSettings: () => _rific_core.SettingsContextValue<ThemeSettings>;
330
322
 
331
323
  declare const getBlendedColor: (foreground: string, background: string, alpha: number) => string;
332
324
 
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ import { AppbarHeaderProps, MD3Theme, BottomNavigationRoute, BottomNavigationPro
6
6
  export { AppbarHeaderProps, BottomNavigationProps, BottomNavigationRoute, ButtonProps, FABProps, ChipProps as PaperChipProps, DialogProps as PaperDialogProps, IconButtonProps as PaperIconButtonProps, MenuProps as PaperMenuProps, TextInputProps } from 'react-native-paper';
7
7
  import * as react from 'react';
8
8
  import react__default, { RefObject, ReactNode, ComponentType } from 'react';
9
+ import * as _rific_core from '@rific/core';
10
+ import { SettingsContextValue } from '@rific/core';
9
11
 
10
12
  declare function useBlur(override?: boolean): boolean;
11
13
 
@@ -227,53 +229,46 @@ type ThemeState = {
227
229
  color: string | TriadicPalette;
228
230
  harmony: ColorHarmony;
229
231
  };
230
- type PayloadAction<P> = {
231
- payload: P;
232
- type: string;
233
- };
234
232
  declare const themeActions: {
235
233
  initialize: {
236
- (payload: Partial<ThemeState>): PayloadAction<Partial<ThemeState>>;
234
+ (payload: Partial<ThemeState>): _rific_core.SettingsAction<Partial<ThemeState>>;
237
235
  type: string;
238
- match(action: {
236
+ match: (action: {
239
237
  type: string;
240
- }): action is PayloadAction<Partial<ThemeState>>;
238
+ }) => action is _rific_core.SettingsAction<Partial<ThemeState>>;
241
239
  };
242
- setAppearance: {
243
- (payload: ThemeAppearance): PayloadAction<ThemeAppearance>;
240
+ } & {
241
+ setColor: {
242
+ (payload: string | TriadicPalette): _rific_core.SettingsAction<string | TriadicPalette>;
244
243
  type: string;
245
- match(action: {
244
+ match: (action: {
246
245
  type: string;
247
- }): action is PayloadAction<ThemeAppearance>;
246
+ }) => action is _rific_core.SettingsAction<string | TriadicPalette>;
248
247
  };
249
- setBlur: {
250
- (payload: boolean): PayloadAction<boolean>;
248
+ setAppearance: {
249
+ (payload: ThemeAppearance): _rific_core.SettingsAction<ThemeAppearance>;
251
250
  type: string;
252
- match(action: {
251
+ match: (action: {
253
252
  type: string;
254
- }): action is PayloadAction<boolean>;
253
+ }) => action is _rific_core.SettingsAction<ThemeAppearance>;
255
254
  };
256
- setColor: {
257
- (payload: string | TriadicPalette): PayloadAction<string | TriadicPalette>;
255
+ setBlur: {
256
+ (payload: boolean): _rific_core.SettingsAction<boolean>;
258
257
  type: string;
259
- match(action: {
258
+ match: (action: {
260
259
  type: string;
261
- }): action is PayloadAction<string | TriadicPalette>;
260
+ }) => action is _rific_core.SettingsAction<boolean>;
262
261
  };
263
262
  setHarmony: {
264
- (payload: ColorHarmony): PayloadAction<ColorHarmony>;
263
+ (payload: ColorHarmony): _rific_core.SettingsAction<ColorHarmony>;
265
264
  type: string;
266
- match(action: {
265
+ match: (action: {
267
266
  type: string;
268
- }): action is PayloadAction<ColorHarmony>;
267
+ }) => action is _rific_core.SettingsAction<ColorHarmony>;
269
268
  };
270
269
  };
271
- declare function createThemeReducer(initialState?: Partial<ThemeState>): (state: ThemeState | undefined, action: {
272
- type: string;
273
- }) => ThemeState;
274
- declare const themeReducer: (state: ThemeState | undefined, action: {
275
- type: string;
276
- }) => ThemeState;
270
+ declare const themeReducer: _rific_core.SettingsReducer<ThemeState>;
271
+ declare const createThemeReducer: (overrideInitialState?: Partial<ThemeState> | undefined) => _rific_core.SettingsReducer<ThemeState>;
277
272
  declare const selectThemeAppearance: (state: ThemeState) => ThemeAppearance;
278
273
  declare const selectThemeBlur: (state: ThemeState) => boolean;
279
274
  declare const selectThemeColor: (state: ThemeState) => string | TriadicPalette;
@@ -287,11 +282,8 @@ type ThemeSettings = {
287
282
  harmony: ColorHarmony;
288
283
  };
289
284
  declare const defaultThemeSettings: ThemeSettings;
290
- type ThemeSettingsContextType = {
291
- settings: ThemeSettings;
292
- set: (patch: Partial<ThemeSettings>) => void;
293
- };
294
- declare const ThemeSettingsContext: react.Context<ThemeSettingsContextType>;
285
+ type ThemeSettingsContextType = SettingsContextValue<ThemeSettings>;
286
+ declare const ThemeSettingsContext: react.Context<SettingsContextValue<ThemeSettings>>;
295
287
 
296
288
  type NavBarContextType = {
297
289
  navigationBar?: ExpoNavigationBarModule;
@@ -322,11 +314,11 @@ type ProviderProps = {
322
314
  statusBarProps?: StatusBarProps;
323
315
  style?: StyleProp<ViewStyle>;
324
316
  };
325
- declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
317
+ declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
326
318
 
327
319
  declare const useAutoPaperTheme: () => AutoPaperTheme;
328
320
 
329
- declare const useThemeSettings: () => ThemeSettingsContextType;
321
+ declare const useThemeSettings: () => _rific_core.SettingsContextValue<ThemeSettings>;
330
322
 
331
323
  declare const getBlendedColor: (foreground: string, background: string, alpha: number) => string;
332
324
 
package/dist/index.js CHANGED
@@ -81,10 +81,10 @@ __export(index_exports, {
81
81
  module.exports = __toCommonJS(index_exports);
82
82
 
83
83
  // src/BlurContext.tsx
84
- var import_react2 = require("react");
84
+ var import_react = require("react");
85
85
 
86
86
  // src/ThemeSettingsContext.ts
87
- var import_react = require("react");
87
+ var import_core = require("@rific/core");
88
88
  var defaultThemeSettings = {
89
89
  appearance: "system",
90
90
  blur: true,
@@ -92,15 +92,14 @@ var defaultThemeSettings = {
92
92
  color: "#6750a4",
93
93
  harmony: "split-complementary"
94
94
  };
95
- var ThemeSettingsContext = (0, import_react.createContext)({
96
- settings: defaultThemeSettings,
97
- set: () => {
98
- }
99
- });
95
+ var themeSettingsContext = (0, import_core.createSettingsContext)(defaultThemeSettings);
96
+ var ThemeSettingsContext = themeSettingsContext.Context;
97
+ var themeSettingsProvider = themeSettingsContext.Provider;
98
+ var useThemeSettingsInternal = themeSettingsContext.useSettings;
100
99
 
101
100
  // src/BlurContext.tsx
102
101
  function useBlur(override) {
103
- const { settings } = (0, import_react2.useContext)(ThemeSettingsContext);
102
+ const { settings } = (0, import_react.useContext)(ThemeSettingsContext);
104
103
  return override ?? settings.blur;
105
104
  }
106
105
 
@@ -109,10 +108,10 @@ var import_react_native = require("react-native");
109
108
  var import_react_native_paper = require("react-native-paper");
110
109
 
111
110
  // src/PaperDefaultsContext.tsx
112
- var import_react3 = require("react");
113
- var PaperDefaultsContext = (0, import_react3.createContext)({});
111
+ var import_react2 = require("react");
112
+ var PaperDefaultsContext = (0, import_react2.createContext)({});
114
113
  function usePaperDefaults() {
115
- return (0, import_react3.useContext)(PaperDefaultsContext);
114
+ return (0, import_react2.useContext)(PaperDefaultsContext);
116
115
  }
117
116
 
118
117
  // src/components/Appbar.tsx
@@ -151,8 +150,7 @@ var AppearancePicker = ({ value, onChange, showLabels = true, icons }) => {
151
150
  };
152
151
 
153
152
  // src/useThemeSettings.ts
154
- var import_react4 = require("react");
155
- var useThemeSettings = () => (0, import_react4.useContext)(ThemeSettingsContext);
153
+ var useThemeSettings = useThemeSettingsInternal;
156
154
 
157
155
  // src/components/AutoAppearancePicker.tsx
158
156
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -165,16 +163,16 @@ var AutoAppearancePicker = (props) => {
165
163
  var resolveSeedColor = (color) => typeof color === "string" ? color : color.primary;
166
164
 
167
165
  // src/components/PalettePicker.tsx
168
- var import_react11 = require("react");
166
+ var import_react9 = require("react");
169
167
  var import_react_native7 = require("react-native");
170
168
  var import_react_native_paper9 = require("react-native-paper");
171
169
 
172
170
  // src/useSwatchGrid.ts
173
- var import_react5 = require("react");
171
+ var import_react3 = require("react");
174
172
  var SWATCH_GRID_COLUMNS = 5;
175
173
  var SWATCH_GRID_GAP = 12;
176
174
  function useSwatchSize(fallback) {
177
- const [width, setWidth] = (0, import_react5.useState)(0);
175
+ const [width, setWidth] = (0, import_react3.useState)(0);
178
176
  const onLayout = ({ nativeEvent }) => setWidth(nativeEvent.layout.width);
179
177
  const size = width > 0 ? (width - SWATCH_GRID_GAP * (SWATCH_GRID_COLUMNS - 1)) / SWATCH_GRID_COLUMNS : fallback;
180
178
  return { onLayout, size };
@@ -494,23 +492,23 @@ function hslToHex(h, s, l) {
494
492
  }
495
493
 
496
494
  // src/components/ColorPicker.tsx
497
- var import_react10 = require("react");
495
+ var import_react8 = require("react");
498
496
  var import_react_native6 = require("react-native");
499
497
  var import_react_native_paper7 = require("react-native-paper");
500
498
 
501
499
  // src/components/Dialog.tsx
502
- var import_react9 = __toESM(require("react"));
500
+ var import_react7 = __toESM(require("react"));
503
501
  var import_react_native5 = require("react-native");
504
502
  var import_react_native_paper6 = require("react-native-paper");
505
503
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
506
504
 
507
505
  // src/ThemeProvider.tsx
508
- var import_react7 = require("react");
506
+ var import_react5 = require("react");
509
507
  var import_react_native3 = require("react-native");
510
508
  var import_react_native_paper4 = require("react-native-paper");
511
509
 
512
510
  // src/useComputedTheme.ts
513
- var import_react6 = require("react");
511
+ var import_react4 = require("react");
514
512
  var import_react_native2 = require("react-native");
515
513
  var import_react_native_paper3 = require("react-native-paper");
516
514
 
@@ -601,11 +599,11 @@ var SEMANTIC_BASE_COLORS = {
601
599
  danger: "#B00020"
602
600
  };
603
601
  function useComputedTheme(appearance, color, harmony = "split-complementary") {
604
- const [theme, setTheme] = (0, import_react6.useState)(null);
602
+ const [theme, setTheme] = (0, import_react4.useState)(null);
605
603
  const primaryInput = typeof color === "string" ? color : color.primary;
606
604
  const secondaryInput = typeof color === "string" ? null : color.secondary;
607
605
  const tertiaryInput = typeof color === "string" ? null : color.tertiary;
608
- const computeTheme = (0, import_react6.useCallback)(() => {
606
+ const computeTheme = (0, import_react4.useCallback)(() => {
609
607
  let resolved = appearance;
610
608
  if (resolved === "system") resolved = import_react_native2.Appearance.getColorScheme();
611
609
  if (resolved === "no-preference" || !resolved) resolved = "light";
@@ -667,10 +665,10 @@ function useComputedTheme(appearance, color, harmony = "split-complementary") {
667
665
  };
668
666
  setTheme(_theme);
669
667
  }, [appearance, primaryInput, secondaryInput, tertiaryInput, harmony]);
670
- (0, import_react6.useEffect)(() => {
668
+ (0, import_react4.useEffect)(() => {
671
669
  computeTheme();
672
670
  }, [computeTheme]);
673
- (0, import_react6.useEffect)(() => {
671
+ (0, import_react4.useEffect)(() => {
674
672
  const subscription = import_react_native2.Appearance.addChangeListener(computeTheme);
675
673
  return subscription.remove;
676
674
  }, [computeTheme]);
@@ -679,53 +677,43 @@ function useComputedTheme(appearance, color, harmony = "split-complementary") {
679
677
 
680
678
  // src/ThemeProvider.tsx
681
679
  var import_jsx_runtime4 = require("react/jsx-runtime");
682
- var NavBarContext = (0, import_react7.createContext)({});
683
- var useNavBarContext = () => (0, import_react7.useContext)(NavBarContext);
684
- var BlurModuleContext = (0, import_react7.createContext)(void 0);
685
- var useBlurModule = () => (0, import_react7.useContext)(BlurModuleContext);
686
- var ReanimatedModuleContext = (0, import_react7.createContext)(void 0);
687
- var useReanimatedModule = () => (0, import_react7.useContext)(ReanimatedModuleContext);
680
+ var NavBarContext = (0, import_react5.createContext)({});
681
+ var useNavBarContext = () => (0, import_react5.useContext)(NavBarContext);
682
+ var BlurModuleContext = (0, import_react5.createContext)(void 0);
683
+ var useBlurModule = () => (0, import_react5.useContext)(BlurModuleContext);
684
+ var ReanimatedModuleContext = (0, import_react5.createContext)(void 0);
685
+ var useReanimatedModule = () => (0, import_react5.useContext)(ReanimatedModuleContext);
688
686
  function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
689
- const [settings, setSettings] = (0, import_react7.useState)(() => ({ ...defaultThemeSettings, ...initialValue }));
690
- const set = (0, import_react7.useCallback)((patch) => {
691
- setSettings((prev) => ({ ...prev, ...patch }));
692
- }, []);
693
- const onChangeRef = (0, import_react7.useRef)(onChange);
694
- (0, import_react7.useEffect)(() => {
695
- onChangeRef.current = onChange;
696
- });
697
- const prevSettings = (0, import_react7.useRef)(settings);
698
- (0, import_react7.useEffect)(() => {
699
- if (prevSettings.current !== settings) {
700
- prevSettings.current = settings;
701
- onChangeRef.current?.(settings);
702
- }
703
- }, [settings]);
687
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeProviderBody, { defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style, children }) });
688
+ }
689
+ var ThemeSettingsProvider = themeSettingsProvider;
690
+ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
691
+ const { settings } = useThemeSettingsInternal();
704
692
  const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony);
705
- const theme = (0, import_react7.useMemo)(() => {
693
+ const theme = (0, import_react5.useMemo)(() => {
706
694
  if (!computedTheme) return null;
707
695
  if (!fontFamily) return computedTheme;
708
696
  return { ...computedTheme, fonts: (0, import_react_native_paper4.configureFonts)({ config: { fontFamily } }) };
709
697
  }, [computedTheme, fontFamily]);
710
- const called = (0, import_react7.useRef)(false);
711
- (0, import_react7.useEffect)(() => {
698
+ const called = (0, import_react5.useRef)(false);
699
+ (0, import_react5.useEffect)(() => {
712
700
  if (theme && !called.current) {
713
701
  called.current = true;
714
702
  onReady?.();
715
703
  }
716
704
  }, [theme, onReady]);
717
705
  if (!theme) return null;
718
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeSettingsContext.Provider, { value: { settings, set }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native_paper4.Provider, { theme, children: [
706
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native_paper4.Provider, { theme, children: [
719
707
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.StatusBar, { backgroundColor: theme.colors.background, barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
720
708
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) })
721
- ] }) });
709
+ ] });
722
710
  }
723
711
  var styles = import_react_native3.StyleSheet.create({
724
712
  flex: { flex: 1 }
725
713
  });
726
714
 
727
715
  // src/components/BlurView.tsx
728
- var import_react8 = require("react");
716
+ var import_react6 = require("react");
729
717
  var import_react_native4 = require("react-native");
730
718
  var import_react_native_paper5 = require("react-native-paper");
731
719
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -733,7 +721,7 @@ var ELEVATION_OPACITY = { 0: 0, 1: 0.05, 2: 0.08, 3: 0.11, 4: 0.12, 5: 0.14 };
733
721
  var VARIANT_TINT_OPACITY = { light: 0.12, dark: 0.18 };
734
722
  var BlurView = ({ blur = true, children, elevation, style, tintColor, tintOpacity, variant = "surface", ...props }) => {
735
723
  const { dark, colors } = (0, import_react_native_paper5.useTheme)();
736
- const { settings } = (0, import_react8.useContext)(ThemeSettingsContext);
724
+ const { settings } = (0, import_react6.useContext)(ThemeSettingsContext);
737
725
  const expoBlur = useBlurModule();
738
726
  const surfaceColor = variant === "surfaceVariant" ? colors.surfaceVariant : colors.surface;
739
727
  const variantColor = variant === "primary" ? colors.primary : variant === "secondary" ? colors.secondary : variant === "tertiary" ? colors.tertiary : variant === "error" ? colors.error : void 0;
@@ -763,12 +751,12 @@ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, di
763
751
  const { colors, isV3, roundness } = theme;
764
752
  const { scale } = theme.animation;
765
753
  const { bottom, left, right, top } = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
766
- const [opacity] = (0, import_react9.useState)(() => new import_react_native5.Animated.Value(visible ? 1 : 0));
767
- const [mounted, setMounted] = (0, import_react9.useState)(visible);
754
+ const [opacity] = (0, import_react7.useState)(() => new import_react_native5.Animated.Value(visible ? 1 : 0));
755
+ const [mounted, setMounted] = (0, import_react7.useState)(visible);
768
756
  if (visible && !mounted) {
769
757
  setMounted(true);
770
758
  }
771
- (0, import_react9.useEffect)(() => {
759
+ (0, import_react7.useEffect)(() => {
772
760
  if (visible) {
773
761
  import_react_native5.Animated.timing(opacity, { duration: scale * ANIMATION_DURATION, easing: import_react_native5.Easing.out(import_react_native5.Easing.cubic), toValue: 1, useNativeDriver: true }).start();
774
762
  } else {
@@ -777,7 +765,7 @@ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, di
777
765
  });
778
766
  }
779
767
  }, [visible, opacity, scale]);
780
- (0, import_react9.useEffect)(() => {
768
+ (0, import_react7.useEffect)(() => {
781
769
  if (!visible) return void 0;
782
770
  const onHardwareBackPress = () => {
783
771
  if (dismissable || dismissableBackButton) onDismiss?.();
@@ -787,14 +775,14 @@ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, di
787
775
  return () => subscription.remove();
788
776
  }, [dismissable, dismissableBackButton, onDismiss, visible]);
789
777
  if (!mounted) return null;
790
- const content = import_react9.default.Children.toArray(children).filter((child) => child != null && typeof child !== "boolean").map((child, i) => {
778
+ const content = import_react7.default.Children.toArray(children).filter((child) => child != null && typeof child !== "boolean").map((child, i) => {
791
779
  if (isV3) {
792
- if (i === 0 && import_react9.default.isValidElement(child) && child.type === import_react_native_paper6.Dialog.Content) {
793
- return import_react9.default.cloneElement(child, { style: [{ marginTop: 24 }, child.props.style] });
780
+ if (i === 0 && import_react7.default.isValidElement(child) && child.type === import_react_native_paper6.Dialog.Content) {
781
+ return import_react7.default.cloneElement(child, { style: [{ marginTop: 24 }, child.props.style] });
794
782
  }
795
783
  }
796
- if (i === 0 && import_react9.default.isValidElement(child) && child.type === import_react_native_paper6.Dialog.Content) {
797
- return import_react9.default.cloneElement(child, { style: [{ paddingTop: 24 }, child.props.style] });
784
+ if (i === 0 && import_react7.default.isValidElement(child) && child.type === import_react_native_paper6.Dialog.Content) {
785
+ return import_react7.default.cloneElement(child, { style: [{ paddingTop: 24 }, child.props.style] });
798
786
  }
799
787
  return child;
800
788
  });
@@ -843,7 +831,7 @@ var defaultColors = [
843
831
  var ColorPicker = ({ value, onChange, colors = defaultColors, blur: blurProp }) => {
844
832
  const blur = useBlur(blurProp);
845
833
  const { colors: themeColors } = (0, import_react_native_paper7.useTheme)();
846
- const [open, setOpen] = (0, import_react10.useState)(false);
834
+ const [open, setOpen] = (0, import_react8.useState)(false);
847
835
  const { onLayout, size } = useSwatchSize(SIZE);
848
836
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
849
837
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper7.TouchableRipple, { onPress: () => setOpen(true), style: [styles3.trigger, { backgroundColor: value }, getSwatchRing(value, false, themeColors.outlineVariant)], borderless: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper7.Icon, { source: "palette", size: 20, color: getContrastColor(value) }) }),
@@ -919,7 +907,7 @@ var Pie = ({ palette, weights = defaultWeights, size = SIZE2 }) => /* @__PURE__
919
907
  var PalettePicker = ({ value, onChange, harmony = "split-complementary", onHarmonyChange, weights, colors = defaultColors, blur: blurProp }) => {
920
908
  const blur = useBlur(blurProp);
921
909
  const { colors: themeColors } = (0, import_react_native_paper9.useTheme)();
922
- const [open, setOpen] = (0, import_react11.useState)(false);
910
+ const [open, setOpen] = (0, import_react9.useState)(false);
923
911
  const { onLayout, size } = useSwatchSize(SIZE2);
924
912
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
925
913
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.TouchableRipple, { onPress: () => setOpen(true), style: styles4.trigger, borderless: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native7.View, { style: styles4.triggerContent, children: [
@@ -969,7 +957,7 @@ var AutoPalettePicker = (props) => {
969
957
  };
970
958
 
971
959
  // src/components/BottomNavigation.tsx
972
- var import_react12 = require("react");
960
+ var import_react10 = require("react");
973
961
  var import_react_native8 = require("react-native");
974
962
  var import_react_native_paper10 = require("react-native-paper");
975
963
 
@@ -984,7 +972,7 @@ var import_jsx_runtime11 = require("react/jsx-runtime");
984
972
  function useNavigationBarSync() {
985
973
  const theme = (0, import_react_native_paper10.useTheme)();
986
974
  const { navigationBar, onNavBarChange } = useNavBarContext();
987
- (0, import_react12.useEffect)(() => {
975
+ (0, import_react10.useEffect)(() => {
988
976
  if (import_react_native8.Platform.OS !== "android") return;
989
977
  if (onNavBarChange) onNavBarChange(theme.colors.surface, theme.dark);
990
978
  else if (navigationBar) setNavigationBarStyle(navigationBar, theme.dark);
@@ -1057,50 +1045,34 @@ var styles5 = import_react_native9.StyleSheet.create({
1057
1045
  });
1058
1046
 
1059
1047
  // src/components/TextInput.tsx
1060
- var import_react13 = require("react");
1048
+ var import_react11 = require("react");
1061
1049
  var import_react_native_paper16 = require("react-native-paper");
1062
1050
  var import_jsx_runtime17 = require("react/jsx-runtime");
1063
- var TextInput = (0, import_react13.forwardRef)(function TextInput2(props, ref) {
1051
+ var TextInput = (0, import_react11.forwardRef)(function TextInput2(props, ref) {
1064
1052
  const defaults = usePaperDefaults();
1065
1053
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper16.TextInput, { ref, ...defaults.TextInput, ...props });
1066
1054
  });
1067
1055
 
1068
1056
  // src/redux/themeSlice.ts
1057
+ var import_core2 = require("@rific/core");
1069
1058
  var defaultInitialState = {
1070
1059
  appearance: "system",
1071
1060
  blur: true,
1072
1061
  color: "#6750a4",
1073
1062
  harmony: "split-complementary"
1074
1063
  };
1075
- var createAction = (type) => {
1076
- const actionCreator = (payload) => ({ payload, type });
1077
- actionCreator.type = type;
1078
- actionCreator.match = (action) => action.type === type;
1079
- return actionCreator;
1080
- };
1081
- var initialize = createAction("theme/initialize");
1082
- var setAppearance = createAction("theme/setAppearance");
1083
- var setBlur = createAction("theme/setBlur");
1084
- var setColor = createAction("theme/setColor");
1085
- var setHarmony = createAction("theme/setHarmony");
1086
- var themeActions = { initialize, setAppearance, setBlur, setColor, setHarmony };
1087
- var reduce = (state, action) => {
1088
- if (initialize.match(action)) return { ...state, ...action.payload };
1089
- if (setAppearance.match(action)) return { ...state, appearance: action.payload };
1090
- if (setBlur.match(action)) return { ...state, blur: action.payload };
1091
- if (setColor.match(action)) return { ...state, color: action.payload };
1092
- if (setHarmony.match(action)) return { ...state, harmony: action.payload };
1093
- return state;
1094
- };
1095
- function createThemeReducer(initialState) {
1096
- const initial = { ...defaultInitialState, ...initialState };
1097
- return (state = initial, action) => reduce(state, action);
1098
- }
1099
- var themeReducer = (state = defaultInitialState, action) => reduce(state, action);
1100
- var selectThemeAppearance = (state) => state.appearance;
1101
- var selectThemeBlur = (state) => state.blur;
1102
- var selectThemeColor = (state) => state.color;
1103
- var selectThemeHarmony = (state) => state.harmony;
1064
+ var themeSlice = (0, import_core2.createSettingsSlice)("theme", {
1065
+ initialState: defaultInitialState,
1066
+ initializeMode: "merge",
1067
+ selectors: ["appearance", "blur", "color", "harmony"]
1068
+ });
1069
+ var themeActions = themeSlice.actions;
1070
+ var themeReducer = themeSlice.reducer;
1071
+ var createThemeReducer = themeSlice.createReducer;
1072
+ var selectThemeAppearance = themeSlice.selectors.selectAppearance;
1073
+ var selectThemeBlur = themeSlice.selectors.selectBlur;
1074
+ var selectThemeColor = themeSlice.selectors.selectColor;
1075
+ var selectThemeHarmony = themeSlice.selectors.selectHarmony;
1104
1076
 
1105
1077
  // src/useTheme.ts
1106
1078
  var import_react_native_paper17 = require("react-native-paper");
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { useContext } from "react";
3
3
 
4
4
  // src/ThemeSettingsContext.ts
5
- import { createContext } from "react";
5
+ import { createSettingsContext } from "@rific/core";
6
6
  var defaultThemeSettings = {
7
7
  appearance: "system",
8
8
  blur: true,
@@ -10,11 +10,10 @@ var defaultThemeSettings = {
10
10
  color: "#6750a4",
11
11
  harmony: "split-complementary"
12
12
  };
13
- var ThemeSettingsContext = createContext({
14
- settings: defaultThemeSettings,
15
- set: () => {
16
- }
17
- });
13
+ var themeSettingsContext = createSettingsContext(defaultThemeSettings);
14
+ var ThemeSettingsContext = themeSettingsContext.Context;
15
+ var themeSettingsProvider = themeSettingsContext.Provider;
16
+ var useThemeSettingsInternal = themeSettingsContext.useSettings;
18
17
 
19
18
  // src/BlurContext.tsx
20
19
  function useBlur(override) {
@@ -27,8 +26,8 @@ import { StatusBar } from "react-native";
27
26
  import { Appbar as PaperAppbar, useTheme } from "react-native-paper";
28
27
 
29
28
  // src/PaperDefaultsContext.tsx
30
- import { createContext as createContext2, useContext as useContext2 } from "react";
31
- var PaperDefaultsContext = createContext2({});
29
+ import { createContext, useContext as useContext2 } from "react";
30
+ var PaperDefaultsContext = createContext({});
32
31
  function usePaperDefaults() {
33
32
  return useContext2(PaperDefaultsContext);
34
33
  }
@@ -69,8 +68,7 @@ var AppearancePicker = ({ value, onChange, showLabels = true, icons }) => {
69
68
  };
70
69
 
71
70
  // src/useThemeSettings.ts
72
- import { useContext as useContext3 } from "react";
73
- var useThemeSettings = () => useContext3(ThemeSettingsContext);
71
+ var useThemeSettings = useThemeSettingsInternal;
74
72
 
75
73
  // src/components/AutoAppearancePicker.tsx
76
74
  import { jsx as jsx3 } from "react/jsx-runtime";
@@ -83,7 +81,7 @@ var AutoAppearancePicker = (props) => {
83
81
  var resolveSeedColor = (color) => typeof color === "string" ? color : color.primary;
84
82
 
85
83
  // src/components/PalettePicker.tsx
86
- import { useState as useState6 } from "react";
84
+ import { useState as useState5 } from "react";
87
85
  import { StyleSheet as StyleSheet5, TouchableOpacity as TouchableOpacity2, View as View5 } from "react-native";
88
86
  import { Icon as Icon2, TouchableRipple as TouchableRipple2, useTheme as useTheme5 } from "react-native-paper";
89
87
 
@@ -412,18 +410,18 @@ function hslToHex(h, s, l) {
412
410
  }
413
411
 
414
412
  // src/components/ColorPicker.tsx
415
- import { useState as useState5 } from "react";
413
+ import { useState as useState4 } from "react";
416
414
  import { StyleSheet as StyleSheet4, TouchableOpacity, View as View4 } from "react-native";
417
415
  import { Icon, TouchableRipple, useTheme as useTheme4 } from "react-native-paper";
418
416
 
419
417
  // src/components/Dialog.tsx
420
- import React, { useEffect as useEffect3, useState as useState4 } from "react";
418
+ import React, { useEffect as useEffect3, useState as useState3 } from "react";
421
419
  import { Animated, BackHandler, Easing, Pressable, StyleSheet as StyleSheet3, View as View3 } from "react-native";
422
420
  import { Dialog as PaperDialog, Portal, useTheme as useTheme3 } from "react-native-paper";
423
421
  import { useSafeAreaInsets } from "react-native-safe-area-context";
424
422
 
425
423
  // src/ThemeProvider.tsx
426
- import { createContext as createContext3, useCallback as useCallback2, useContext as useContext4, useEffect as useEffect2, useMemo, useRef, useState as useState3 } from "react";
424
+ import { createContext as createContext2, useContext as useContext3, useEffect as useEffect2, useMemo, useRef } from "react";
427
425
  import { StatusBar as StatusBar2, StyleSheet, View } from "react-native";
428
426
  import { configureFonts, Provider as PaperProvider } from "react-native-paper";
429
427
 
@@ -597,28 +595,18 @@ function useComputedTheme(appearance, color, harmony = "split-complementary") {
597
595
 
598
596
  // src/ThemeProvider.tsx
599
597
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
600
- var NavBarContext = createContext3({});
601
- var useNavBarContext = () => useContext4(NavBarContext);
602
- var BlurModuleContext = createContext3(void 0);
603
- var useBlurModule = () => useContext4(BlurModuleContext);
604
- var ReanimatedModuleContext = createContext3(void 0);
605
- var useReanimatedModule = () => useContext4(ReanimatedModuleContext);
598
+ var NavBarContext = createContext2({});
599
+ var useNavBarContext = () => useContext3(NavBarContext);
600
+ var BlurModuleContext = createContext2(void 0);
601
+ var useBlurModule = () => useContext3(BlurModuleContext);
602
+ var ReanimatedModuleContext = createContext2(void 0);
603
+ var useReanimatedModule = () => useContext3(ReanimatedModuleContext);
606
604
  function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
607
- const [settings, setSettings] = useState3(() => ({ ...defaultThemeSettings, ...initialValue }));
608
- const set = useCallback2((patch) => {
609
- setSettings((prev) => ({ ...prev, ...patch }));
610
- }, []);
611
- const onChangeRef = useRef(onChange);
612
- useEffect2(() => {
613
- onChangeRef.current = onChange;
614
- });
615
- const prevSettings = useRef(settings);
616
- useEffect2(() => {
617
- if (prevSettings.current !== settings) {
618
- prevSettings.current = settings;
619
- onChangeRef.current?.(settings);
620
- }
621
- }, [settings]);
605
+ return /* @__PURE__ */ jsx4(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ jsx4(ThemeProviderBody, { defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style, children }) });
606
+ }
607
+ var ThemeSettingsProvider = themeSettingsProvider;
608
+ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
609
+ const { settings } = useThemeSettingsInternal();
622
610
  const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony);
623
611
  const theme = useMemo(() => {
624
612
  if (!computedTheme) return null;
@@ -633,17 +621,17 @@ function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navi
633
621
  }
634
622
  }, [theme, onReady]);
635
623
  if (!theme) return null;
636
- return /* @__PURE__ */ jsx4(ThemeSettingsContext.Provider, { value: { settings, set }, children: /* @__PURE__ */ jsxs2(PaperProvider, { theme, children: [
624
+ return /* @__PURE__ */ jsxs2(PaperProvider, { theme, children: [
637
625
  /* @__PURE__ */ jsx4(StatusBar2, { backgroundColor: theme.colors.background, barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
638
626
  /* @__PURE__ */ jsx4(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ jsx4(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ jsx4(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ jsx4(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ jsx4(View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) })
639
- ] }) });
627
+ ] });
640
628
  }
641
629
  var styles = StyleSheet.create({
642
630
  flex: { flex: 1 }
643
631
  });
644
632
 
645
633
  // src/components/BlurView.tsx
646
- import { useContext as useContext5 } from "react";
634
+ import { useContext as useContext4 } from "react";
647
635
  import { StyleSheet as StyleSheet2, View as View2 } from "react-native";
648
636
  import { useTheme as useTheme2 } from "react-native-paper";
649
637
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
@@ -651,7 +639,7 @@ var ELEVATION_OPACITY = { 0: 0, 1: 0.05, 2: 0.08, 3: 0.11, 4: 0.12, 5: 0.14 };
651
639
  var VARIANT_TINT_OPACITY = { light: 0.12, dark: 0.18 };
652
640
  var BlurView = ({ blur = true, children, elevation, style, tintColor, tintOpacity, variant = "surface", ...props }) => {
653
641
  const { dark, colors } = useTheme2();
654
- const { settings } = useContext5(ThemeSettingsContext);
642
+ const { settings } = useContext4(ThemeSettingsContext);
655
643
  const expoBlur = useBlurModule();
656
644
  const surfaceColor = variant === "surfaceVariant" ? colors.surfaceVariant : colors.surface;
657
645
  const variantColor = variant === "primary" ? colors.primary : variant === "secondary" ? colors.secondary : variant === "tertiary" ? colors.tertiary : variant === "error" ? colors.error : void 0;
@@ -681,8 +669,8 @@ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, di
681
669
  const { colors, isV3, roundness } = theme;
682
670
  const { scale } = theme.animation;
683
671
  const { bottom, left, right, top } = useSafeAreaInsets();
684
- const [opacity] = useState4(() => new Animated.Value(visible ? 1 : 0));
685
- const [mounted, setMounted] = useState4(visible);
672
+ const [opacity] = useState3(() => new Animated.Value(visible ? 1 : 0));
673
+ const [mounted, setMounted] = useState3(visible);
686
674
  if (visible && !mounted) {
687
675
  setMounted(true);
688
676
  }
@@ -761,7 +749,7 @@ var defaultColors = [
761
749
  var ColorPicker = ({ value, onChange, colors = defaultColors, blur: blurProp }) => {
762
750
  const blur = useBlur(blurProp);
763
751
  const { colors: themeColors } = useTheme4();
764
- const [open, setOpen] = useState5(false);
752
+ const [open, setOpen] = useState4(false);
765
753
  const { onLayout, size } = useSwatchSize(SIZE);
766
754
  return /* @__PURE__ */ jsxs5(Fragment2, { children: [
767
755
  /* @__PURE__ */ jsx7(TouchableRipple, { onPress: () => setOpen(true), style: [styles3.trigger, { backgroundColor: value }, getSwatchRing(value, false, themeColors.outlineVariant)], borderless: true, children: /* @__PURE__ */ jsx7(Icon, { source: "palette", size: 20, color: getContrastColor(value) }) }),
@@ -837,7 +825,7 @@ var Pie = ({ palette, weights = defaultWeights, size = SIZE2 }) => /* @__PURE__
837
825
  var PalettePicker = ({ value, onChange, harmony = "split-complementary", onHarmonyChange, weights, colors = defaultColors, blur: blurProp }) => {
838
826
  const blur = useBlur(blurProp);
839
827
  const { colors: themeColors } = useTheme5();
840
- const [open, setOpen] = useState6(false);
828
+ const [open, setOpen] = useState5(false);
841
829
  const { onLayout, size } = useSwatchSize(SIZE2);
842
830
  return /* @__PURE__ */ jsxs6(Fragment3, { children: [
843
831
  /* @__PURE__ */ jsx9(TouchableRipple2, { onPress: () => setOpen(true), style: styles4.trigger, borderless: true, children: /* @__PURE__ */ jsxs6(View5, { style: styles4.triggerContent, children: [
@@ -984,41 +972,25 @@ var TextInput = forwardRef(function TextInput2(props, ref) {
984
972
  });
985
973
 
986
974
  // src/redux/themeSlice.ts
975
+ import { createSettingsSlice } from "@rific/core";
987
976
  var defaultInitialState = {
988
977
  appearance: "system",
989
978
  blur: true,
990
979
  color: "#6750a4",
991
980
  harmony: "split-complementary"
992
981
  };
993
- var createAction = (type) => {
994
- const actionCreator = (payload) => ({ payload, type });
995
- actionCreator.type = type;
996
- actionCreator.match = (action) => action.type === type;
997
- return actionCreator;
998
- };
999
- var initialize = createAction("theme/initialize");
1000
- var setAppearance = createAction("theme/setAppearance");
1001
- var setBlur = createAction("theme/setBlur");
1002
- var setColor = createAction("theme/setColor");
1003
- var setHarmony = createAction("theme/setHarmony");
1004
- var themeActions = { initialize, setAppearance, setBlur, setColor, setHarmony };
1005
- var reduce = (state, action) => {
1006
- if (initialize.match(action)) return { ...state, ...action.payload };
1007
- if (setAppearance.match(action)) return { ...state, appearance: action.payload };
1008
- if (setBlur.match(action)) return { ...state, blur: action.payload };
1009
- if (setColor.match(action)) return { ...state, color: action.payload };
1010
- if (setHarmony.match(action)) return { ...state, harmony: action.payload };
1011
- return state;
1012
- };
1013
- function createThemeReducer(initialState) {
1014
- const initial = { ...defaultInitialState, ...initialState };
1015
- return (state = initial, action) => reduce(state, action);
1016
- }
1017
- var themeReducer = (state = defaultInitialState, action) => reduce(state, action);
1018
- var selectThemeAppearance = (state) => state.appearance;
1019
- var selectThemeBlur = (state) => state.blur;
1020
- var selectThemeColor = (state) => state.color;
1021
- var selectThemeHarmony = (state) => state.harmony;
982
+ var themeSlice = createSettingsSlice("theme", {
983
+ initialState: defaultInitialState,
984
+ initializeMode: "merge",
985
+ selectors: ["appearance", "blur", "color", "harmony"]
986
+ });
987
+ var themeActions = themeSlice.actions;
988
+ var themeReducer = themeSlice.reducer;
989
+ var createThemeReducer = themeSlice.createReducer;
990
+ var selectThemeAppearance = themeSlice.selectors.selectAppearance;
991
+ var selectThemeBlur = themeSlice.selectors.selectBlur;
992
+ var selectThemeColor = themeSlice.selectors.selectColor;
993
+ var selectThemeHarmony = themeSlice.selectors.selectHarmony;
1022
994
 
1023
995
  // src/useTheme.ts
1024
996
  import { useTheme as usePaperTheme } from "react-native-paper";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rific/auto-paper",
3
- "version": "0.10.3",
3
+ "version": "0.11.0",
4
4
  "description": "Adaptive react-native-paper theming: triadic palette from a seed color + system/light/dark appearance",
5
5
  "keywords": [
6
6
  "react-native",
@@ -72,6 +72,7 @@
72
72
  "@infinitetoken/jest-config": "^0.2.0",
73
73
  "@infinitetoken/tsconfig": "^0.3.0",
74
74
  "@reduxjs/toolkit": "^2.0.0",
75
+ "@rific/core": "^0.1.1",
75
76
  "@testing-library/dom": "^10.4.1",
76
77
  "@testing-library/react": "^16.0.0",
77
78
  "@types/jest": "^30.0.0",
@@ -93,6 +94,7 @@
93
94
  "typescript": "^6.0.3"
94
95
  },
95
96
  "peerDependencies": {
97
+ "@rific/core": ">=0.1.1",
96
98
  "expo-blur": ">=56.0.0",
97
99
  "expo-navigation-bar": ">=56.0.0",
98
100
  "react": ">=19.0.0",
@@ -1,4 +1,4 @@
1
- import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'
1
+ import { createContext, type ReactNode, useContext, useEffect, useMemo, useRef } from 'react'
2
2
  import { StatusBar, type StatusBarProps, type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native'
3
3
  import { configureFonts, Provider as PaperProvider } from 'react-native-paper'
4
4
 
@@ -6,7 +6,7 @@ import type { ExpoBlurModule } from './components/BlurView'
6
6
  import type { ReanimatedModule } from './components/Dialog'
7
7
  import type { ExpoNavigationBarModule } from './navigation-bar'
8
8
  import { type PaperDefaults, PaperDefaultsContext } from './PaperDefaultsContext'
9
- import { defaultThemeSettings, type ThemeSettings, ThemeSettingsContext } from './ThemeSettingsContext'
9
+ import { type ThemeSettings, themeSettingsProvider, useThemeSettingsInternal } from './ThemeSettingsContext'
10
10
  import { useComputedTheme } from './useComputedTheme'
11
11
 
12
12
  // expo-navigation-bar/expo-blur are no longer auto-detected via require() - Metro doesn't
@@ -47,24 +47,28 @@ export type ProviderProps = {
47
47
  style?: StyleProp<ViewStyle>
48
48
  }
49
49
 
50
+ // createSettingsContext's generated Provider only exposes `settings` to descendants (via its
51
+ // generated useSettings()) — it can't itself also compute the theme/gate mounting on it being
52
+ // ready, since that logic needs `settings` in scope. Provider (below) is just this thin outer
53
+ // wrapper for the settings half; ThemeProviderBody (an actual descendant, reached via
54
+ // useThemeSettingsInternal()) does all the theme-computation/gating work the single combined
55
+ // component used to do directly.
50
56
  export function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps) {
51
- const [settings, setSettings] = useState<ThemeSettings>(() => ({ ...defaultThemeSettings, ...initialValue }))
57
+ return (
58
+ <ThemeSettingsProvider initialValue={initialValue} onChange={onChange}>
59
+ <ThemeProviderBody defaults={defaults} expoBlur={expoBlur} fontFamily={fontFamily} navigationBar={navigationBar} onNavBarChange={onNavBarChange} onReady={onReady} reanimated={reanimated} statusBarProps={statusBarProps} style={style}>
60
+ {children}
61
+ </ThemeProviderBody>
62
+ </ThemeSettingsProvider>
63
+ )
64
+ }
52
65
 
53
- const set = useCallback((patch: Partial<ThemeSettings>) => {
54
- setSettings((prev) => ({ ...prev, ...patch }))
55
- }, [])
66
+ const ThemeSettingsProvider = themeSettingsProvider
56
67
 
57
- const onChangeRef = useRef(onChange)
58
- useEffect(() => {
59
- onChangeRef.current = onChange
60
- })
61
- const prevSettings = useRef(settings)
62
- useEffect(() => {
63
- if (prevSettings.current !== settings) {
64
- prevSettings.current = settings
65
- onChangeRef.current?.(settings)
66
- }
67
- }, [settings])
68
+ type ThemeProviderBodyProps = Omit<ProviderProps, 'initialValue' | 'onChange'>
69
+
70
+ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style }: ThemeProviderBodyProps) {
71
+ const { settings } = useThemeSettingsInternal()
68
72
 
69
73
  const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony)
70
74
  // Layered on top of useComputedTheme's own output rather than folded into it — that hook only
@@ -89,20 +93,18 @@ export function Provider({ children, defaults, expoBlur, fontFamily, initialValu
89
93
  if (!theme) return null
90
94
 
91
95
  return (
92
- <ThemeSettingsContext.Provider value={{ settings, set }}>
93
- <PaperProvider theme={theme}>
94
- <StatusBar backgroundColor={theme.colors.background} barStyle={theme.dark ? 'light-content' : 'dark-content'} {...statusBarProps} />
95
- <PaperDefaultsContext.Provider value={defaults ?? {}}>
96
- <NavBarContext.Provider value={{ navigationBar, onNavBarChange }}>
97
- <BlurModuleContext.Provider value={expoBlur}>
98
- <ReanimatedModuleContext.Provider value={reanimated}>
99
- <View style={[styles.flex, { backgroundColor: theme.colors.background }, style]}>{children}</View>
100
- </ReanimatedModuleContext.Provider>
101
- </BlurModuleContext.Provider>
102
- </NavBarContext.Provider>
103
- </PaperDefaultsContext.Provider>
104
- </PaperProvider>
105
- </ThemeSettingsContext.Provider>
96
+ <PaperProvider theme={theme}>
97
+ <StatusBar backgroundColor={theme.colors.background} barStyle={theme.dark ? 'light-content' : 'dark-content'} {...statusBarProps} />
98
+ <PaperDefaultsContext.Provider value={defaults ?? {}}>
99
+ <NavBarContext.Provider value={{ navigationBar, onNavBarChange }}>
100
+ <BlurModuleContext.Provider value={expoBlur}>
101
+ <ReanimatedModuleContext.Provider value={reanimated}>
102
+ <View style={[styles.flex, { backgroundColor: theme.colors.background }, style]}>{children}</View>
103
+ </ReanimatedModuleContext.Provider>
104
+ </BlurModuleContext.Provider>
105
+ </NavBarContext.Provider>
106
+ </PaperDefaultsContext.Provider>
107
+ </PaperProvider>
106
108
  )
107
109
  }
108
110
 
@@ -1,4 +1,4 @@
1
- import { createContext } from 'react'
1
+ import { createSettingsContext, type SettingsContextValue } from '@rific/core'
2
2
 
3
3
  import type { ThemeAppearance } from './useComputedTheme'
4
4
  import type { ColorHarmony, TriadicPalette } from './utils/getTriadicPalette'
@@ -19,12 +19,13 @@ export const defaultThemeSettings: ThemeSettings = {
19
19
  harmony: 'split-complementary'
20
20
  }
21
21
 
22
- export type ThemeSettingsContextType = {
23
- settings: ThemeSettings
24
- set: (patch: Partial<ThemeSettings>) => void
25
- }
22
+ export type ThemeSettingsContextType = SettingsContextValue<ThemeSettings>
23
+
24
+ // Single createSettingsContext() call, shared by ThemeProvider.tsx and useThemeSettings.ts (each
25
+ // just re-exports the relevant piece under its original name) so there's exactly one Context
26
+ // instance backing all three files, same as before this migration.
27
+ const themeSettingsContext = createSettingsContext<ThemeSettings>(defaultThemeSettings)
26
28
 
27
- export const ThemeSettingsContext = createContext<ThemeSettingsContextType>({
28
- settings: defaultThemeSettings,
29
- set: () => {}
30
- })
29
+ export const ThemeSettingsContext = themeSettingsContext.Context
30
+ export const themeSettingsProvider = themeSettingsContext.Provider
31
+ export const useThemeSettingsInternal = themeSettingsContext.useSettings
@@ -1,3 +1,5 @@
1
+ import { createSettingsSlice } from '@rific/core'
2
+
1
3
  import { ThemeAppearance } from '../useComputedTheme'
2
4
  import type { ColorHarmony, TriadicPalette } from '../utils/getTriadicPalette'
3
5
 
@@ -17,43 +19,20 @@ const defaultInitialState: ThemeState = {
17
19
  harmony: 'split-complementary'
18
20
  }
19
21
 
20
- // Hand-rolled slice (no @reduxjs/toolkit dependency). Action types and creator
21
- // behavior match the previous createSlice implementation exactly, so this works
22
- // with RTK stores, vanilla Redux, or any reducer-based state container.
23
- type PayloadAction<P> = { payload: P; type: string }
24
-
25
- const createAction = <P>(type: string) => {
26
- const actionCreator = (payload: P): PayloadAction<P> => ({ payload, type })
27
- actionCreator.type = type
28
- actionCreator.match = (action: { type: string }): action is PayloadAction<P> => action.type === type
29
- return actionCreator
30
- }
31
-
32
- const initialize = createAction<Partial<ThemeState>>('theme/initialize')
33
- const setAppearance = createAction<ThemeAppearance>('theme/setAppearance')
34
- const setBlur = createAction<boolean>('theme/setBlur')
35
- const setColor = createAction<string | TriadicPalette>('theme/setColor')
36
- const setHarmony = createAction<ColorHarmony>('theme/setHarmony')
37
-
38
- export const themeActions = { initialize, setAppearance, setBlur, setColor, setHarmony }
39
-
40
- const reduce = (state: ThemeState, action: { type: string }): ThemeState => {
41
- if (initialize.match(action)) return { ...state, ...action.payload }
42
- if (setAppearance.match(action)) return { ...state, appearance: action.payload }
43
- if (setBlur.match(action)) return { ...state, blur: action.payload }
44
- if (setColor.match(action)) return { ...state, color: action.payload }
45
- if (setHarmony.match(action)) return { ...state, harmony: action.payload }
46
- return state
47
- }
48
-
49
- export function createThemeReducer(initialState?: Partial<ThemeState>) {
50
- const initial = { ...defaultInitialState, ...initialState }
51
- return (state: ThemeState = initial, action: { type: string }): ThemeState => reduce(state, action)
52
- }
53
-
54
- export const themeReducer = (state: ThemeState = defaultInitialState, action: { type: string }): ThemeState => reduce(state, action)
55
-
56
- export const selectThemeAppearance = (state: ThemeState) => state.appearance
57
- export const selectThemeBlur = (state: ThemeState) => state.blur
58
- export const selectThemeColor = (state: ThemeState) => state.color
59
- export const selectThemeHarmony = (state: ThemeState) => state.harmony
22
+ const themeSlice = createSettingsSlice('theme', {
23
+ initialState: defaultInitialState,
24
+ initializeMode: 'merge' as const,
25
+ selectors: ['appearance', 'blur', 'color', 'harmony'] as const
26
+ })
27
+
28
+ export const themeActions = themeSlice.actions
29
+ export const themeReducer = themeSlice.reducer
30
+ export const createThemeReducer = themeSlice.createReducer
31
+
32
+ // This package's existing public selector names carry a `Theme` infix the factory's generic
33
+ // select${Field} naming doesn't produce - remapped explicitly rather than teaching the factory a
34
+ // one-off naming convention only this package wants.
35
+ export const selectThemeAppearance = themeSlice.selectors.selectAppearance
36
+ export const selectThemeBlur = themeSlice.selectors.selectBlur
37
+ export const selectThemeColor = themeSlice.selectors.selectColor
38
+ export const selectThemeHarmony = themeSlice.selectors.selectHarmony
@@ -1,5 +1,3 @@
1
- import { useContext } from 'react'
1
+ import { useThemeSettingsInternal } from './ThemeSettingsContext'
2
2
 
3
- import { ThemeSettingsContext } from './ThemeSettingsContext'
4
-
5
- export const useThemeSettings = () => useContext(ThemeSettingsContext)
3
+ export const useThemeSettings = useThemeSettingsInternal