@sudobility/building_blocks_rn 0.0.2
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/firebase.d.ts +10 -0
- package/dist/firebase.js +10 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +25 -0
- package/dist/src/api/ApiContext.d.ts +52 -0
- package/dist/src/api/ApiContext.js +67 -0
- package/dist/src/api/index.d.ts +2 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/app/SudobilityAppRN.d.ts +29 -0
- package/dist/src/app/SudobilityAppRN.js +37 -0
- package/dist/src/app/SudobilityAppRNWithFirebaseAuth.d.ts +13 -0
- package/dist/src/app/SudobilityAppRNWithFirebaseAuth.js +12 -0
- package/dist/src/app/index.d.ts +4 -0
- package/dist/src/app/index.js +2 -0
- package/dist/src/components/footer/AppFooter.d.ts +21 -0
- package/dist/src/components/footer/AppFooter.js +72 -0
- package/dist/src/components/footer/index.d.ts +2 -0
- package/dist/src/components/footer/index.js +1 -0
- package/dist/src/components/header/AppHeader.d.ts +28 -0
- package/dist/src/components/header/AppHeader.js +79 -0
- package/dist/src/components/header/index.d.ts +2 -0
- package/dist/src/components/header/index.js +1 -0
- package/dist/src/components/layout/AppScreenLayout.d.ts +20 -0
- package/dist/src/components/layout/AppScreenLayout.js +41 -0
- package/dist/src/components/layout/index.d.ts +2 -0
- package/dist/src/components/layout/index.js +1 -0
- package/dist/src/components/pages/AppTextScreen.d.ts +16 -0
- package/dist/src/components/pages/AppTextScreen.js +96 -0
- package/dist/src/components/pages/LoginScreen.d.ts +26 -0
- package/dist/src/components/pages/LoginScreen.js +183 -0
- package/dist/src/components/pages/index.d.ts +4 -0
- package/dist/src/components/pages/index.js +2 -0
- package/dist/src/components/settings/AppearanceSettings.d.ts +13 -0
- package/dist/src/components/settings/AppearanceSettings.js +106 -0
- package/dist/src/components/settings/LanguagePicker.d.ts +15 -0
- package/dist/src/components/settings/LanguagePicker.js +100 -0
- package/dist/src/components/settings/SettingsListScreen.d.ts +15 -0
- package/dist/src/components/settings/SettingsListScreen.js +82 -0
- package/dist/src/components/settings/index.d.ts +6 -0
- package/dist/src/components/settings/index.js +3 -0
- package/dist/src/components/subscription/SafeSubscriptionContext.d.ts +13 -0
- package/dist/src/components/subscription/SafeSubscriptionContext.js +15 -0
- package/dist/src/components/subscription/SubscriptionScreen.d.ts +36 -0
- package/dist/src/components/subscription/SubscriptionScreen.js +188 -0
- package/dist/src/components/subscription/index.d.ts +4 -0
- package/dist/src/components/subscription/index.js +2 -0
- package/dist/src/components/toast/ToastProvider.d.ts +20 -0
- package/dist/src/components/toast/ToastProvider.js +87 -0
- package/dist/src/components/toast/index.d.ts +2 -0
- package/dist/src/components/toast/index.js +1 -0
- package/dist/src/constants/index.d.ts +1 -0
- package/dist/src/constants/index.js +1 -0
- package/dist/src/constants/languages.d.ts +18 -0
- package/dist/src/constants/languages.js +48 -0
- package/dist/src/hooks/index.d.ts +2 -0
- package/dist/src/hooks/index.js +1 -0
- package/dist/src/hooks/useResponsive.d.ts +11 -0
- package/dist/src/hooks/useResponsive.js +14 -0
- package/dist/src/i18n/index.d.ts +31 -0
- package/dist/src/i18n/index.js +78 -0
- package/dist/src/theme/ThemeContext.d.ts +34 -0
- package/dist/src/theme/ThemeContext.js +66 -0
- package/dist/src/theme/colors.d.ts +55 -0
- package/dist/src/theme/colors.js +69 -0
- package/dist/src/theme/index.d.ts +7 -0
- package/dist/src/theme/index.js +4 -0
- package/dist/src/theme/spacing.d.ts +16 -0
- package/dist/src/theme/spacing.js +15 -0
- package/dist/src/theme/typography.d.ts +24 -0
- package/dist/src/theme/typography.js +34 -0
- package/dist/src/types.d.ts +152 -0
- package/dist/src/types.js +27 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +1 -0
- package/dist/src/utils/styles.d.ts +23 -0
- package/dist/src/utils/styles.js +25 -0
- package/package.json +94 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
|
|
3
|
+
import { useColorScheme } from 'react-native';
|
|
4
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
5
|
+
import { Theme } from '../types';
|
|
6
|
+
import { lightColors, darkColors } from './colors';
|
|
7
|
+
const THEME_STORAGE_KEY = '@building_blocks/theme';
|
|
8
|
+
const ThemeContext = createContext(null);
|
|
9
|
+
export function ThemeProvider({ children, initialTheme, storageKeyPrefix, }) {
|
|
10
|
+
const systemColorScheme = useColorScheme();
|
|
11
|
+
const [theme, setThemeState] = useState(initialTheme ?? Theme.SYSTEM);
|
|
12
|
+
const [loaded, setLoaded] = useState(false);
|
|
13
|
+
const storageKey = storageKeyPrefix
|
|
14
|
+
? `${storageKeyPrefix}/${THEME_STORAGE_KEY}`
|
|
15
|
+
: THEME_STORAGE_KEY;
|
|
16
|
+
// Load persisted theme on mount
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
AsyncStorage.getItem(storageKey).then(stored => {
|
|
19
|
+
if (stored && Object.values(Theme).includes(stored)) {
|
|
20
|
+
setThemeState(stored);
|
|
21
|
+
}
|
|
22
|
+
setLoaded(true);
|
|
23
|
+
});
|
|
24
|
+
}, [storageKey]);
|
|
25
|
+
const setTheme = useCallback((newTheme) => {
|
|
26
|
+
setThemeState(newTheme);
|
|
27
|
+
AsyncStorage.setItem(storageKey, newTheme);
|
|
28
|
+
}, [storageKey]);
|
|
29
|
+
const resolvedTheme = useMemo(() => {
|
|
30
|
+
if (theme === Theme.SYSTEM) {
|
|
31
|
+
return systemColorScheme === 'dark' ? 'dark' : 'light';
|
|
32
|
+
}
|
|
33
|
+
return theme === Theme.DARK ? 'dark' : 'light';
|
|
34
|
+
}, [theme, systemColorScheme]);
|
|
35
|
+
const colors = useMemo(() => (resolvedTheme === 'dark' ? darkColors : lightColors), [resolvedTheme]);
|
|
36
|
+
const value = useMemo(() => ({
|
|
37
|
+
theme,
|
|
38
|
+
resolvedTheme,
|
|
39
|
+
colors,
|
|
40
|
+
isDark: resolvedTheme === 'dark',
|
|
41
|
+
setTheme,
|
|
42
|
+
}), [theme, resolvedTheme, colors, setTheme]);
|
|
43
|
+
// Don't render children until we've loaded the persisted theme
|
|
44
|
+
if (!loaded) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return (_jsx(ThemeContext.Provider, { value: value, children: children }));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Hook to access theme context.
|
|
51
|
+
* Must be used within a ThemeProvider.
|
|
52
|
+
*/
|
|
53
|
+
export function useTheme() {
|
|
54
|
+
const context = useContext(ThemeContext);
|
|
55
|
+
if (!context) {
|
|
56
|
+
throw new Error('useTheme must be used within a ThemeProvider');
|
|
57
|
+
}
|
|
58
|
+
return context;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Safely access theme context.
|
|
62
|
+
* Returns null if not within a ThemeProvider.
|
|
63
|
+
*/
|
|
64
|
+
export function useThemeSafe() {
|
|
65
|
+
return useContext(ThemeContext);
|
|
66
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color palette for building_blocks_rn.
|
|
3
|
+
* Matches the web app's Tailwind color tokens.
|
|
4
|
+
*/
|
|
5
|
+
export declare const palette: {
|
|
6
|
+
readonly primary: {
|
|
7
|
+
readonly 50: "#eff6ff";
|
|
8
|
+
readonly 100: "#dbeafe";
|
|
9
|
+
readonly 200: "#bfdbfe";
|
|
10
|
+
readonly 300: "#93c5fd";
|
|
11
|
+
readonly 400: "#60a5fa";
|
|
12
|
+
readonly 500: "#3b82f6";
|
|
13
|
+
readonly 600: "#2563eb";
|
|
14
|
+
readonly 700: "#1d4ed8";
|
|
15
|
+
readonly 800: "#1e40af";
|
|
16
|
+
readonly 900: "#1e3a8a";
|
|
17
|
+
};
|
|
18
|
+
readonly gray: {
|
|
19
|
+
readonly 50: "#f9fafb";
|
|
20
|
+
readonly 100: "#f3f4f6";
|
|
21
|
+
readonly 200: "#e5e7eb";
|
|
22
|
+
readonly 300: "#d1d5db";
|
|
23
|
+
readonly 400: "#9ca3af";
|
|
24
|
+
readonly 500: "#6b7280";
|
|
25
|
+
readonly 600: "#4b5563";
|
|
26
|
+
readonly 700: "#374151";
|
|
27
|
+
readonly 800: "#1f2937";
|
|
28
|
+
readonly 900: "#111827";
|
|
29
|
+
};
|
|
30
|
+
readonly success: "#22c55e";
|
|
31
|
+
readonly error: "#ef4444";
|
|
32
|
+
readonly warning: "#f59e0b";
|
|
33
|
+
readonly info: "#3b82f6";
|
|
34
|
+
readonly white: "#ffffff";
|
|
35
|
+
readonly black: "#000000";
|
|
36
|
+
readonly transparent: "transparent";
|
|
37
|
+
};
|
|
38
|
+
export interface ThemeColors {
|
|
39
|
+
primary: string;
|
|
40
|
+
background: string;
|
|
41
|
+
card: string;
|
|
42
|
+
text: string;
|
|
43
|
+
textSecondary: string;
|
|
44
|
+
textMuted: string;
|
|
45
|
+
border: string;
|
|
46
|
+
notification: string;
|
|
47
|
+
surface: string;
|
|
48
|
+
surfaceSecondary: string;
|
|
49
|
+
error: string;
|
|
50
|
+
success: string;
|
|
51
|
+
warning: string;
|
|
52
|
+
info: string;
|
|
53
|
+
}
|
|
54
|
+
export declare const lightColors: ThemeColors;
|
|
55
|
+
export declare const darkColors: ThemeColors;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color palette for building_blocks_rn.
|
|
3
|
+
* Matches the web app's Tailwind color tokens.
|
|
4
|
+
*/
|
|
5
|
+
export const palette = {
|
|
6
|
+
primary: {
|
|
7
|
+
50: '#eff6ff',
|
|
8
|
+
100: '#dbeafe',
|
|
9
|
+
200: '#bfdbfe',
|
|
10
|
+
300: '#93c5fd',
|
|
11
|
+
400: '#60a5fa',
|
|
12
|
+
500: '#3b82f6',
|
|
13
|
+
600: '#2563eb',
|
|
14
|
+
700: '#1d4ed8',
|
|
15
|
+
800: '#1e40af',
|
|
16
|
+
900: '#1e3a8a',
|
|
17
|
+
},
|
|
18
|
+
gray: {
|
|
19
|
+
50: '#f9fafb',
|
|
20
|
+
100: '#f3f4f6',
|
|
21
|
+
200: '#e5e7eb',
|
|
22
|
+
300: '#d1d5db',
|
|
23
|
+
400: '#9ca3af',
|
|
24
|
+
500: '#6b7280',
|
|
25
|
+
600: '#4b5563',
|
|
26
|
+
700: '#374151',
|
|
27
|
+
800: '#1f2937',
|
|
28
|
+
900: '#111827',
|
|
29
|
+
},
|
|
30
|
+
success: '#22c55e',
|
|
31
|
+
error: '#ef4444',
|
|
32
|
+
warning: '#f59e0b',
|
|
33
|
+
info: '#3b82f6',
|
|
34
|
+
white: '#ffffff',
|
|
35
|
+
black: '#000000',
|
|
36
|
+
transparent: 'transparent',
|
|
37
|
+
};
|
|
38
|
+
export const lightColors = {
|
|
39
|
+
primary: palette.primary[600],
|
|
40
|
+
background: palette.gray[50],
|
|
41
|
+
card: palette.white,
|
|
42
|
+
text: palette.gray[900],
|
|
43
|
+
textSecondary: palette.gray[600],
|
|
44
|
+
textMuted: palette.gray[400],
|
|
45
|
+
border: palette.gray[200],
|
|
46
|
+
notification: palette.error,
|
|
47
|
+
surface: palette.white,
|
|
48
|
+
surfaceSecondary: palette.gray[100],
|
|
49
|
+
error: palette.error,
|
|
50
|
+
success: palette.success,
|
|
51
|
+
warning: palette.warning,
|
|
52
|
+
info: palette.info,
|
|
53
|
+
};
|
|
54
|
+
export const darkColors = {
|
|
55
|
+
primary: palette.primary[400],
|
|
56
|
+
background: palette.gray[900],
|
|
57
|
+
card: palette.gray[800],
|
|
58
|
+
text: palette.gray[50],
|
|
59
|
+
textSecondary: palette.gray[400],
|
|
60
|
+
textMuted: palette.gray[500],
|
|
61
|
+
border: palette.gray[700],
|
|
62
|
+
notification: palette.error,
|
|
63
|
+
surface: palette.gray[800],
|
|
64
|
+
surfaceSecondary: palette.gray[700],
|
|
65
|
+
error: palette.error,
|
|
66
|
+
success: palette.success,
|
|
67
|
+
warning: palette.warning,
|
|
68
|
+
info: palette.info,
|
|
69
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { palette, lightColors, darkColors } from './colors';
|
|
2
|
+
export type { ThemeColors } from './colors';
|
|
3
|
+
export { spacing } from './spacing';
|
|
4
|
+
export type { SpacingKey } from './spacing';
|
|
5
|
+
export { fontSizes, fontWeights, getFontSizeMultiplier } from './typography';
|
|
6
|
+
export { ThemeProvider, useTheme, useThemeSafe } from './ThemeContext';
|
|
7
|
+
export type { ThemeContextValue } from './ThemeContext';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spacing scale for consistent layout.
|
|
3
|
+
* Values in logical pixels.
|
|
4
|
+
*/
|
|
5
|
+
export declare const spacing: {
|
|
6
|
+
readonly xs: 4;
|
|
7
|
+
readonly sm: 8;
|
|
8
|
+
readonly md: 12;
|
|
9
|
+
readonly lg: 16;
|
|
10
|
+
readonly xl: 20;
|
|
11
|
+
readonly '2xl': 24;
|
|
12
|
+
readonly '3xl': 32;
|
|
13
|
+
readonly '4xl': 40;
|
|
14
|
+
readonly '5xl': 48;
|
|
15
|
+
};
|
|
16
|
+
export type SpacingKey = keyof typeof spacing;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FontSize } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Typography scale.
|
|
4
|
+
*/
|
|
5
|
+
export declare const fontSizes: {
|
|
6
|
+
readonly xs: 12;
|
|
7
|
+
readonly sm: 14;
|
|
8
|
+
readonly base: 16;
|
|
9
|
+
readonly lg: 18;
|
|
10
|
+
readonly xl: 20;
|
|
11
|
+
readonly '2xl': 24;
|
|
12
|
+
readonly '3xl': 30;
|
|
13
|
+
readonly '4xl': 36;
|
|
14
|
+
};
|
|
15
|
+
export declare const fontWeights: {
|
|
16
|
+
normal: "400";
|
|
17
|
+
medium: "500";
|
|
18
|
+
semibold: "600";
|
|
19
|
+
bold: "700";
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get font size scale multiplier based on FontSize setting.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getFontSizeMultiplier(fontSize: FontSize | string): number;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FontSize } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Typography scale.
|
|
4
|
+
*/
|
|
5
|
+
export const fontSizes = {
|
|
6
|
+
xs: 12,
|
|
7
|
+
sm: 14,
|
|
8
|
+
base: 16,
|
|
9
|
+
lg: 18,
|
|
10
|
+
xl: 20,
|
|
11
|
+
'2xl': 24,
|
|
12
|
+
'3xl': 30,
|
|
13
|
+
'4xl': 36,
|
|
14
|
+
};
|
|
15
|
+
export const fontWeights = {
|
|
16
|
+
normal: '400',
|
|
17
|
+
medium: '500',
|
|
18
|
+
semibold: '600',
|
|
19
|
+
bold: '700',
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Get font size scale multiplier based on FontSize setting.
|
|
23
|
+
*/
|
|
24
|
+
export function getFontSizeMultiplier(fontSize) {
|
|
25
|
+
switch (fontSize) {
|
|
26
|
+
case FontSize.SMALL:
|
|
27
|
+
return 0.875;
|
|
28
|
+
case FontSize.LARGE:
|
|
29
|
+
return 1.125;
|
|
30
|
+
case FontSize.MEDIUM:
|
|
31
|
+
default:
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for @sudobility/building_blocks_rn
|
|
3
|
+
*
|
|
4
|
+
* Mirrors @sudobility/building_blocks types where possible,
|
|
5
|
+
* adapted for React Native (style instead of className, onPress instead of href, etc.).
|
|
6
|
+
*/
|
|
7
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
8
|
+
export type { LanguageConfig } from './constants/languages';
|
|
9
|
+
/**
|
|
10
|
+
* Menu item configuration for AppHeader navigation.
|
|
11
|
+
* Adapted from web MenuItemConfig: icon accepts RN icon props, uses onPress instead of href.
|
|
12
|
+
*/
|
|
13
|
+
export interface MenuItemConfig {
|
|
14
|
+
/** Unique identifier for the menu item */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Display label */
|
|
17
|
+
label: string;
|
|
18
|
+
/** Icon component (RN style: accepts size and color) */
|
|
19
|
+
icon: ComponentType<{
|
|
20
|
+
size?: number;
|
|
21
|
+
color?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Route name for React Navigation */
|
|
24
|
+
routeName: string;
|
|
25
|
+
/** Optional route params */
|
|
26
|
+
routeParams?: Record<string, unknown>;
|
|
27
|
+
/** Optional: press handler (overrides routeName navigation) */
|
|
28
|
+
onPress?: () => void;
|
|
29
|
+
/** Optional: show only when condition is true */
|
|
30
|
+
show?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Logo configuration for AppHeader.
|
|
34
|
+
*/
|
|
35
|
+
export interface LogoConfig {
|
|
36
|
+
/** Logo image source (require() or { uri: string }) */
|
|
37
|
+
source?: number | {
|
|
38
|
+
uri: string;
|
|
39
|
+
};
|
|
40
|
+
/** App name to display next to logo */
|
|
41
|
+
appName: string;
|
|
42
|
+
/** Logo press handler (typically navigate to home) */
|
|
43
|
+
onPress?: () => void;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Footer link item.
|
|
47
|
+
* Uses onPress or url instead of href.
|
|
48
|
+
*/
|
|
49
|
+
export interface FooterLinkItem {
|
|
50
|
+
/** Display label */
|
|
51
|
+
label: string;
|
|
52
|
+
/** URL to open (via Linking.openURL) */
|
|
53
|
+
url?: string;
|
|
54
|
+
/** Route name for in-app navigation */
|
|
55
|
+
routeName?: string;
|
|
56
|
+
/** Optional press handler */
|
|
57
|
+
onPress?: () => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Max width options for layout.
|
|
61
|
+
* Maps to numeric pixel values in RN.
|
|
62
|
+
*/
|
|
63
|
+
export type MaxWidth = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '4xl' | '7xl' | 'full';
|
|
64
|
+
/**
|
|
65
|
+
* Content padding options.
|
|
66
|
+
*/
|
|
67
|
+
export type ContentPadding = 'none' | 'sm' | 'md' | 'lg';
|
|
68
|
+
/**
|
|
69
|
+
* Background variant options.
|
|
70
|
+
*/
|
|
71
|
+
export type BackgroundVariant = 'default' | 'white' | 'gradient';
|
|
72
|
+
export type AnalyticsEventType = 'button_click' | 'link_click' | 'navigation' | 'settings_change' | 'subscription_action' | 'page_view';
|
|
73
|
+
export interface AnalyticsTrackingParams {
|
|
74
|
+
eventType: AnalyticsEventType;
|
|
75
|
+
componentName: string;
|
|
76
|
+
label: string;
|
|
77
|
+
params?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
export interface AnalyticsTracker {
|
|
80
|
+
onTrack: (params: AnalyticsTrackingParams) => void;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Theme options (shared with web).
|
|
84
|
+
*/
|
|
85
|
+
export declare enum Theme {
|
|
86
|
+
LIGHT = "light",
|
|
87
|
+
DARK = "dark",
|
|
88
|
+
SYSTEM = "system"
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Font size options (shared with web).
|
|
92
|
+
*/
|
|
93
|
+
export declare enum FontSize {
|
|
94
|
+
SMALL = "small",
|
|
95
|
+
MEDIUM = "medium",
|
|
96
|
+
LARGE = "large"
|
|
97
|
+
}
|
|
98
|
+
export interface TextSection {
|
|
99
|
+
title: string;
|
|
100
|
+
content?: string;
|
|
101
|
+
items?: string[];
|
|
102
|
+
subsections?: TextSection[];
|
|
103
|
+
}
|
|
104
|
+
export interface TextPageContact {
|
|
105
|
+
title: string;
|
|
106
|
+
description: string;
|
|
107
|
+
info: string;
|
|
108
|
+
gdprNotice?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface TextPageContent {
|
|
111
|
+
title: string;
|
|
112
|
+
lastUpdated?: string;
|
|
113
|
+
sections: TextSection[];
|
|
114
|
+
contact?: TextPageContact;
|
|
115
|
+
}
|
|
116
|
+
export interface SettingsSectionConfig {
|
|
117
|
+
id: string;
|
|
118
|
+
icon?: ComponentType<{
|
|
119
|
+
size?: number;
|
|
120
|
+
color?: string;
|
|
121
|
+
}>;
|
|
122
|
+
label: string;
|
|
123
|
+
description?: string;
|
|
124
|
+
content: ReactNode;
|
|
125
|
+
}
|
|
126
|
+
export interface SubscriptionPageLabels {
|
|
127
|
+
title?: string;
|
|
128
|
+
subtitle?: string;
|
|
129
|
+
currentPlan?: string;
|
|
130
|
+
changePlan?: string;
|
|
131
|
+
purchase?: string;
|
|
132
|
+
restore?: string;
|
|
133
|
+
restoreDescription?: string;
|
|
134
|
+
monthly?: string;
|
|
135
|
+
yearly?: string;
|
|
136
|
+
lifetime?: string;
|
|
137
|
+
free?: string;
|
|
138
|
+
freePlanDescription?: string;
|
|
139
|
+
mostPopular?: string;
|
|
140
|
+
savePercent?: string;
|
|
141
|
+
perMonth?: string;
|
|
142
|
+
perYear?: string;
|
|
143
|
+
oneTime?: string;
|
|
144
|
+
features?: string;
|
|
145
|
+
currentlyActive?: string;
|
|
146
|
+
rateLimitsTitle?: string;
|
|
147
|
+
rateLimitsDescription?: string;
|
|
148
|
+
}
|
|
149
|
+
export interface SubscriptionPageFormatters {
|
|
150
|
+
formatPrice?: (price: number, currency: string) => string;
|
|
151
|
+
formatPeriod?: (period: string) => string;
|
|
152
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for @sudobility/building_blocks_rn
|
|
3
|
+
*
|
|
4
|
+
* Mirrors @sudobility/building_blocks types where possible,
|
|
5
|
+
* adapted for React Native (style instead of className, onPress instead of href, etc.).
|
|
6
|
+
*/
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Settings Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Theme options (shared with web).
|
|
12
|
+
*/
|
|
13
|
+
export var Theme;
|
|
14
|
+
(function (Theme) {
|
|
15
|
+
Theme["LIGHT"] = "light";
|
|
16
|
+
Theme["DARK"] = "dark";
|
|
17
|
+
Theme["SYSTEM"] = "system";
|
|
18
|
+
})(Theme || (Theme = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Font size options (shared with web).
|
|
21
|
+
*/
|
|
22
|
+
export var FontSize;
|
|
23
|
+
(function (FontSize) {
|
|
24
|
+
FontSize["SMALL"] = "small";
|
|
25
|
+
FontSize["MEDIUM"] = "medium";
|
|
26
|
+
FontSize["LARGE"] = "large";
|
|
27
|
+
})(FontSize || (FontSize = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createThemedStyles } from './styles';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createThemedStyles } from './styles';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ViewStyle, TextStyle, ImageStyle } from 'react-native';
|
|
2
|
+
import type { ThemeColors } from '../theme/colors';
|
|
3
|
+
type NamedStyles<T> = {
|
|
4
|
+
[P in keyof T]: ViewStyle | TextStyle | ImageStyle;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Create a hook that generates themed styles.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const useStyles = createThemedStyles((colors) => ({
|
|
12
|
+
* container: { backgroundColor: colors.background },
|
|
13
|
+
* text: { color: colors.text },
|
|
14
|
+
* }));
|
|
15
|
+
*
|
|
16
|
+
* function MyComponent() {
|
|
17
|
+
* const styles = useStyles();
|
|
18
|
+
* return <View style={styles.container}><Text style={styles.text}>Hello</Text></View>;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function createThemedStyles<T extends NamedStyles<T>>(factory: (colors: ThemeColors) => T): () => T;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import { useTheme } from '../theme/ThemeContext';
|
|
4
|
+
/**
|
|
5
|
+
* Create a hook that generates themed styles.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const useStyles = createThemedStyles((colors) => ({
|
|
10
|
+
* container: { backgroundColor: colors.background },
|
|
11
|
+
* text: { color: colors.text },
|
|
12
|
+
* }));
|
|
13
|
+
*
|
|
14
|
+
* function MyComponent() {
|
|
15
|
+
* const styles = useStyles();
|
|
16
|
+
* return <View style={styles.container}><Text style={styles.text}>Hello</Text></View>;
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function createThemedStyles(factory) {
|
|
21
|
+
return function useStyles() {
|
|
22
|
+
const { colors } = useTheme();
|
|
23
|
+
return useMemo(() => StyleSheet.create(factory(colors)), [colors]);
|
|
24
|
+
};
|
|
25
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sudobility/building_blocks_rn",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Higher-level shared UI building blocks for Sudobility React Native apps",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./firebase": {
|
|
16
|
+
"import": "./dist/firebase.js",
|
|
17
|
+
"require": "./dist/firebase.js",
|
|
18
|
+
"types": "./dist/firebase.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.build.json",
|
|
27
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
28
|
+
"clean": "rm -rf dist",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "echo 'No tests configured yet'",
|
|
31
|
+
"lint": "eslint . --ext ts,tsx --ignore-pattern 'dist' --ignore-pattern 'node_modules' --report-unused-disable-directives --max-warnings 0",
|
|
32
|
+
"lint:fix": "eslint . --ext ts,tsx --ignore-pattern 'dist' --ignore-pattern 'node_modules' --fix",
|
|
33
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
34
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\"",
|
|
35
|
+
"prepublishOnly": "bun run build"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
39
|
+
"react-native": ">=0.72.0",
|
|
40
|
+
"react-native-safe-area-context": ">=4.0.0",
|
|
41
|
+
"@react-navigation/native": ">=7.0.0",
|
|
42
|
+
"@react-navigation/native-stack": ">=7.0.0",
|
|
43
|
+
"i18next": "^23.0.0 || ^24.0.0 || ^25.0.0",
|
|
44
|
+
"react-i18next": "^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
45
|
+
"@react-native-async-storage/async-storage": ">=1.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"firebase": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"@tanstack/react-query": {
|
|
52
|
+
"optional": true
|
|
53
|
+
},
|
|
54
|
+
"react-native-purchases": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"react-native-localize": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"react-native-gesture-handler": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@sudobility/types": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@eslint/js": "^9.38.0",
|
|
69
|
+
"@typescript-eslint/eslint-plugin": "^8.44.1",
|
|
70
|
+
"@typescript-eslint/parser": "^8.44.1",
|
|
71
|
+
"eslint": "^9.38.0",
|
|
72
|
+
"eslint-config-prettier": "^10.1.8",
|
|
73
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
74
|
+
"eslint-plugin-react-hooks": "^7.0.0",
|
|
75
|
+
"eslint-plugin-react-refresh": "^0.4.0",
|
|
76
|
+
"prettier": "^3.6.2",
|
|
77
|
+
"@types/react": "~19.1.0",
|
|
78
|
+
"typescript": "~5.9.2",
|
|
79
|
+
"react": "19.1.0",
|
|
80
|
+
"react-native": "0.81.5",
|
|
81
|
+
"react-native-safe-area-context": "~5.6.0",
|
|
82
|
+
"@react-navigation/native": "^7.1.28",
|
|
83
|
+
"@react-navigation/native-stack": "^7.10.1",
|
|
84
|
+
"@react-native-async-storage/async-storage": "2.2.0",
|
|
85
|
+
"i18next": "^25.8.0",
|
|
86
|
+
"react-i18next": "^16.5.3",
|
|
87
|
+
"@tanstack/react-query": "^5.90.19",
|
|
88
|
+
"@sudobility/types": "^1.9.50"
|
|
89
|
+
},
|
|
90
|
+
"publishConfig": {
|
|
91
|
+
"access": "public"
|
|
92
|
+
},
|
|
93
|
+
"license": "BUSL-1.1"
|
|
94
|
+
}
|