@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.
Files changed (77) hide show
  1. package/dist/firebase.d.ts +10 -0
  2. package/dist/firebase.js +10 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.js +25 -0
  5. package/dist/src/api/ApiContext.d.ts +52 -0
  6. package/dist/src/api/ApiContext.js +67 -0
  7. package/dist/src/api/index.d.ts +2 -0
  8. package/dist/src/api/index.js +1 -0
  9. package/dist/src/app/SudobilityAppRN.d.ts +29 -0
  10. package/dist/src/app/SudobilityAppRN.js +37 -0
  11. package/dist/src/app/SudobilityAppRNWithFirebaseAuth.d.ts +13 -0
  12. package/dist/src/app/SudobilityAppRNWithFirebaseAuth.js +12 -0
  13. package/dist/src/app/index.d.ts +4 -0
  14. package/dist/src/app/index.js +2 -0
  15. package/dist/src/components/footer/AppFooter.d.ts +21 -0
  16. package/dist/src/components/footer/AppFooter.js +72 -0
  17. package/dist/src/components/footer/index.d.ts +2 -0
  18. package/dist/src/components/footer/index.js +1 -0
  19. package/dist/src/components/header/AppHeader.d.ts +28 -0
  20. package/dist/src/components/header/AppHeader.js +79 -0
  21. package/dist/src/components/header/index.d.ts +2 -0
  22. package/dist/src/components/header/index.js +1 -0
  23. package/dist/src/components/layout/AppScreenLayout.d.ts +20 -0
  24. package/dist/src/components/layout/AppScreenLayout.js +41 -0
  25. package/dist/src/components/layout/index.d.ts +2 -0
  26. package/dist/src/components/layout/index.js +1 -0
  27. package/dist/src/components/pages/AppTextScreen.d.ts +16 -0
  28. package/dist/src/components/pages/AppTextScreen.js +96 -0
  29. package/dist/src/components/pages/LoginScreen.d.ts +26 -0
  30. package/dist/src/components/pages/LoginScreen.js +183 -0
  31. package/dist/src/components/pages/index.d.ts +4 -0
  32. package/dist/src/components/pages/index.js +2 -0
  33. package/dist/src/components/settings/AppearanceSettings.d.ts +13 -0
  34. package/dist/src/components/settings/AppearanceSettings.js +106 -0
  35. package/dist/src/components/settings/LanguagePicker.d.ts +15 -0
  36. package/dist/src/components/settings/LanguagePicker.js +100 -0
  37. package/dist/src/components/settings/SettingsListScreen.d.ts +15 -0
  38. package/dist/src/components/settings/SettingsListScreen.js +82 -0
  39. package/dist/src/components/settings/index.d.ts +6 -0
  40. package/dist/src/components/settings/index.js +3 -0
  41. package/dist/src/components/subscription/SafeSubscriptionContext.d.ts +13 -0
  42. package/dist/src/components/subscription/SafeSubscriptionContext.js +15 -0
  43. package/dist/src/components/subscription/SubscriptionScreen.d.ts +36 -0
  44. package/dist/src/components/subscription/SubscriptionScreen.js +188 -0
  45. package/dist/src/components/subscription/index.d.ts +4 -0
  46. package/dist/src/components/subscription/index.js +2 -0
  47. package/dist/src/components/toast/ToastProvider.d.ts +20 -0
  48. package/dist/src/components/toast/ToastProvider.js +87 -0
  49. package/dist/src/components/toast/index.d.ts +2 -0
  50. package/dist/src/components/toast/index.js +1 -0
  51. package/dist/src/constants/index.d.ts +1 -0
  52. package/dist/src/constants/index.js +1 -0
  53. package/dist/src/constants/languages.d.ts +18 -0
  54. package/dist/src/constants/languages.js +48 -0
  55. package/dist/src/hooks/index.d.ts +2 -0
  56. package/dist/src/hooks/index.js +1 -0
  57. package/dist/src/hooks/useResponsive.d.ts +11 -0
  58. package/dist/src/hooks/useResponsive.js +14 -0
  59. package/dist/src/i18n/index.d.ts +31 -0
  60. package/dist/src/i18n/index.js +78 -0
  61. package/dist/src/theme/ThemeContext.d.ts +34 -0
  62. package/dist/src/theme/ThemeContext.js +66 -0
  63. package/dist/src/theme/colors.d.ts +55 -0
  64. package/dist/src/theme/colors.js +69 -0
  65. package/dist/src/theme/index.d.ts +7 -0
  66. package/dist/src/theme/index.js +4 -0
  67. package/dist/src/theme/spacing.d.ts +16 -0
  68. package/dist/src/theme/spacing.js +15 -0
  69. package/dist/src/theme/typography.d.ts +24 -0
  70. package/dist/src/theme/typography.js +34 -0
  71. package/dist/src/types.d.ts +152 -0
  72. package/dist/src/types.js +27 -0
  73. package/dist/src/utils/index.d.ts +1 -0
  74. package/dist/src/utils/index.js +1 -0
  75. package/dist/src/utils/styles.d.ts +23 -0
  76. package/dist/src/utils/styles.js +25 -0
  77. package/package.json +94 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Firebase Auth dependent components
3
+ *
4
+ * These components require Firebase auth to be set up.
5
+ * Import from '@sudobility/building_blocks_rn/firebase' to use these.
6
+ */
7
+ export { SudobilityAppRNWithFirebaseAuth } from './src/app/SudobilityAppRNWithFirebaseAuth';
8
+ export type { SudobilityAppRNWithFirebaseAuthProps } from './src/app/SudobilityAppRNWithFirebaseAuth';
9
+ export { ApiProvider, ApiContext, useApi, useApiSafe, } from './src/api/ApiContext';
10
+ export type { ApiContextValue, ApiProviderProps, NetworkClient, } from './src/api/ApiContext';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Firebase Auth dependent components
3
+ *
4
+ * These components require Firebase auth to be set up.
5
+ * Import from '@sudobility/building_blocks_rn/firebase' to use these.
6
+ */
7
+ // App wrappers with Firebase auth
8
+ export { SudobilityAppRNWithFirebaseAuth } from './src/app/SudobilityAppRNWithFirebaseAuth';
9
+ // API context
10
+ export { ApiProvider, ApiContext, useApi, useApiSafe, } from './src/api/ApiContext';
@@ -0,0 +1,21 @@
1
+ export * from './src/components/header';
2
+ export * from './src/components/footer';
3
+ export * from './src/components/layout';
4
+ export * from './src/components/settings';
5
+ export * from './src/components/pages';
6
+ export { SudobilityAppRN } from './src/app/SudobilityAppRN';
7
+ export type { SudobilityAppRNProps } from './src/app/SudobilityAppRN';
8
+ export { SafeSubscriptionContext, STUB_SUBSCRIPTION_VALUE, useSafeSubscription, } from './src/components/subscription/SafeSubscriptionContext';
9
+ export type { SubscriptionContextValue } from './src/components/subscription/SafeSubscriptionContext';
10
+ export { SubscriptionScreen } from './src/components/subscription/SubscriptionScreen';
11
+ export type { SubscriptionScreenProps, SubscriptionPackage, } from './src/components/subscription/SubscriptionScreen';
12
+ export * from './src/theme';
13
+ export * from './src/constants';
14
+ export * from './src/types';
15
+ export { createThemedStyles } from './src/utils';
16
+ export { useResponsive } from './src/hooks';
17
+ export type { ResponsiveInfo } from './src/hooks';
18
+ export { ToastProvider, useToast } from './src/components/toast';
19
+ export type { Toast, ToastType } from './src/components/toast';
20
+ export { initializeI18nRN, getI18n, i18n } from './src/i18n';
21
+ export type { I18nConfig } from './src/i18n';
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ // Core components (no auth dependency)
2
+ export * from './src/components/header';
3
+ export * from './src/components/footer';
4
+ export * from './src/components/layout';
5
+ export * from './src/components/settings';
6
+ export * from './src/components/pages';
7
+ // App wrapper without auth dependency
8
+ export { SudobilityAppRN } from './src/app/SudobilityAppRN';
9
+ // Subscription components without auth dependency
10
+ export { SafeSubscriptionContext, STUB_SUBSCRIPTION_VALUE, useSafeSubscription, } from './src/components/subscription/SafeSubscriptionContext';
11
+ export { SubscriptionScreen } from './src/components/subscription/SubscriptionScreen';
12
+ // Theme
13
+ export * from './src/theme';
14
+ // Constants
15
+ export * from './src/constants';
16
+ // Types
17
+ export * from './src/types';
18
+ // Utils
19
+ export { createThemedStyles } from './src/utils';
20
+ // Hooks
21
+ export { useResponsive } from './src/hooks';
22
+ // Toast
23
+ export { ToastProvider, useToast } from './src/components/toast';
24
+ // i18n
25
+ export { initializeI18nRN, getI18n, i18n } from './src/i18n';
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ export interface NetworkClient {
3
+ request: <T>(url: string, options?: RequestInit) => Promise<T>;
4
+ get: <T>(url: string, options?: Omit<RequestInit, 'method' | 'body'>) => Promise<T>;
5
+ post: <T>(url: string, body?: unknown, options?: Omit<RequestInit, 'method'>) => Promise<T>;
6
+ put: <T>(url: string, body?: unknown, options?: Omit<RequestInit, 'method'>) => Promise<T>;
7
+ delete: <T>(url: string, options?: Omit<RequestInit, 'method' | 'body'>) => Promise<T>;
8
+ }
9
+ export interface ApiContextValue {
10
+ /** Network client for making API requests */
11
+ networkClient: NetworkClient;
12
+ /** Base URL for API calls */
13
+ baseUrl: string;
14
+ /** Authentication token (null if not logged in) */
15
+ token: string | null;
16
+ /** User ID (null if not logged in) */
17
+ userId: string | null;
18
+ /** Whether the context is ready */
19
+ isReady: boolean;
20
+ /** Whether authentication is loading */
21
+ isLoading: boolean;
22
+ /** Refresh the auth token */
23
+ refreshToken?: () => Promise<string | null>;
24
+ }
25
+ declare const ApiContext: React.Context<ApiContextValue | null>;
26
+ export interface ApiProviderProps {
27
+ children: React.ReactNode;
28
+ /** Base URL for API calls */
29
+ baseUrl: string;
30
+ /** Authentication token */
31
+ token: string | null;
32
+ /** User ID */
33
+ userId: string | null;
34
+ /** Whether auth state is determined */
35
+ isReady: boolean;
36
+ /** Whether auth is loading */
37
+ isLoading: boolean;
38
+ /** Optional custom network client */
39
+ networkClient?: NetworkClient;
40
+ /** Optional token refresh function */
41
+ refreshToken?: () => Promise<string | null>;
42
+ }
43
+ export declare function ApiProvider({ children, baseUrl, token, userId, isReady, isLoading, networkClient, refreshToken, }: ApiProviderProps): import("react/jsx-runtime").JSX.Element;
44
+ /**
45
+ * Hook to access API context. Throws if not within an ApiProvider.
46
+ */
47
+ export declare function useApi(): ApiContextValue;
48
+ /**
49
+ * Safely access API context. Returns null if not within an ApiProvider.
50
+ */
51
+ export declare function useApiSafe(): ApiContextValue | null;
52
+ export { ApiContext };
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo } from 'react';
3
+ const ApiContext = createContext(null);
4
+ function createDefaultNetworkClient() {
5
+ async function makeRequest(url, options) {
6
+ const response = await fetch(url, {
7
+ headers: { 'Content-Type': 'application/json', ...options?.headers },
8
+ ...options,
9
+ });
10
+ const json = await response.json();
11
+ return json;
12
+ }
13
+ return {
14
+ request: makeRequest,
15
+ get: (url, options) => makeRequest(url, { ...options, method: 'GET' }),
16
+ post: (url, body, options) => makeRequest(url, {
17
+ ...options,
18
+ method: 'POST',
19
+ body: body ? JSON.stringify(body) : undefined,
20
+ }),
21
+ put: (url, body, options) => makeRequest(url, {
22
+ ...options,
23
+ method: 'PUT',
24
+ body: body ? JSON.stringify(body) : undefined,
25
+ }),
26
+ delete: (url, options) => makeRequest(url, { ...options, method: 'DELETE' }),
27
+ };
28
+ }
29
+ export function ApiProvider({ children, baseUrl, token, userId, isReady, isLoading, networkClient, refreshToken, }) {
30
+ const defaultClient = useMemo(() => createDefaultNetworkClient(), []);
31
+ const value = useMemo(() => ({
32
+ networkClient: networkClient ?? defaultClient,
33
+ baseUrl,
34
+ token,
35
+ userId,
36
+ isReady,
37
+ isLoading,
38
+ refreshToken,
39
+ }), [
40
+ networkClient,
41
+ defaultClient,
42
+ baseUrl,
43
+ token,
44
+ userId,
45
+ isReady,
46
+ isLoading,
47
+ refreshToken,
48
+ ]);
49
+ return _jsx(ApiContext.Provider, { value: value, children: children });
50
+ }
51
+ /**
52
+ * Hook to access API context. Throws if not within an ApiProvider.
53
+ */
54
+ export function useApi() {
55
+ const context = useContext(ApiContext);
56
+ if (!context) {
57
+ throw new Error('useApi must be used within an ApiProvider');
58
+ }
59
+ return context;
60
+ }
61
+ /**
62
+ * Safely access API context. Returns null if not within an ApiProvider.
63
+ */
64
+ export function useApiSafe() {
65
+ return useContext(ApiContext);
66
+ }
67
+ export { ApiContext };
@@ -0,0 +1,2 @@
1
+ export { ApiProvider, ApiContext, useApi, useApiSafe } from './ApiContext';
2
+ export type { ApiContextValue, ApiProviderProps, NetworkClient, } from './ApiContext';
@@ -0,0 +1 @@
1
+ export { ApiProvider, ApiContext, useApi, useApiSafe } from './ApiContext';
@@ -0,0 +1,29 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { i18n as I18nInstance } from 'i18next';
3
+ import { Theme } from '../types';
4
+ export interface SudobilityAppRNProps {
5
+ children: ReactNode;
6
+ /** Pre-configured i18n instance */
7
+ i18n?: I18nInstance;
8
+ /** Optional custom ThemeProvider wrapper */
9
+ ThemeProviderComponent?: ComponentType<{
10
+ children: ReactNode;
11
+ }>;
12
+ /** Optional custom ToastProvider wrapper */
13
+ ToastProviderComponent?: ComponentType<{
14
+ children: ReactNode;
15
+ }>;
16
+ /** Query client provider (e.g., from @tanstack/react-query) */
17
+ QueryClientProvider?: ComponentType<{
18
+ children: ReactNode;
19
+ }>;
20
+ /** Optional additional providers to wrap around children */
21
+ AppProviders?: ComponentType<{
22
+ children: ReactNode;
23
+ }>;
24
+ /** Initial theme */
25
+ initialTheme?: Theme;
26
+ /** Storage key prefix for persisted settings */
27
+ storageKeyPrefix?: string;
28
+ }
29
+ export declare function SudobilityAppRN({ children, i18n, ThemeProviderComponent, ToastProviderComponent, QueryClientProvider, AppProviders, initialTheme, storageKeyPrefix, }: SudobilityAppRNProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
3
+ import { I18nextProvider } from 'react-i18next';
4
+ import { ThemeProvider } from '../theme/ThemeContext';
5
+ import { ToastProvider } from '../components/toast/ToastProvider';
6
+ export function SudobilityAppRN({ children, i18n, ThemeProviderComponent, ToastProviderComponent, QueryClientProvider, AppProviders, initialTheme, storageKeyPrefix, }) {
7
+ let content = _jsx(_Fragment, { children: children });
8
+ // Wrap with additional providers (innermost)
9
+ if (AppProviders) {
10
+ content = _jsx(AppProviders, { children: content });
11
+ }
12
+ // Toast
13
+ if (ToastProviderComponent) {
14
+ content = _jsx(ToastProviderComponent, { children: content });
15
+ }
16
+ else {
17
+ content = _jsx(ToastProvider, { children: content });
18
+ }
19
+ // Query client
20
+ if (QueryClientProvider) {
21
+ content = _jsx(QueryClientProvider, { children: content });
22
+ }
23
+ // Theme
24
+ if (ThemeProviderComponent) {
25
+ content = _jsx(ThemeProviderComponent, { children: content });
26
+ }
27
+ else {
28
+ content = (_jsx(ThemeProvider, { initialTheme: initialTheme, storageKeyPrefix: storageKeyPrefix, children: content }));
29
+ }
30
+ // i18n
31
+ if (i18n) {
32
+ content = _jsx(I18nextProvider, { i18n: i18n, children: content });
33
+ }
34
+ // SafeArea (outermost)
35
+ content = _jsx(SafeAreaProvider, { children: content });
36
+ return content;
37
+ }
@@ -0,0 +1,13 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { SudobilityAppRNProps } from './SudobilityAppRN';
3
+ export interface SudobilityAppRNWithFirebaseAuthProps extends SudobilityAppRNProps {
4
+ /** Firebase auth provider component */
5
+ AuthProvider: ComponentType<{
6
+ children: ReactNode;
7
+ }>;
8
+ /** API provider component (wraps children with auth-aware API context) */
9
+ ApiProviderComponent?: ComponentType<{
10
+ children: ReactNode;
11
+ }>;
12
+ }
13
+ export declare function SudobilityAppRNWithFirebaseAuth({ children, AuthProvider, ApiProviderComponent, ...appProps }: SudobilityAppRNWithFirebaseAuthProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { SudobilityAppRN } from './SudobilityAppRN';
3
+ export function SudobilityAppRNWithFirebaseAuth({ children, AuthProvider, ApiProviderComponent, ...appProps }) {
4
+ let content = _jsx(_Fragment, { children: children });
5
+ // API provider (innermost of auth stack)
6
+ if (ApiProviderComponent) {
7
+ content = _jsx(ApiProviderComponent, { children: content });
8
+ }
9
+ // Auth provider
10
+ content = _jsx(AuthProvider, { children: content });
11
+ return _jsx(SudobilityAppRN, { ...appProps, children: content });
12
+ }
@@ -0,0 +1,4 @@
1
+ export { SudobilityAppRN } from './SudobilityAppRN';
2
+ export type { SudobilityAppRNProps } from './SudobilityAppRN';
3
+ export { SudobilityAppRNWithFirebaseAuth } from './SudobilityAppRNWithFirebaseAuth';
4
+ export type { SudobilityAppRNWithFirebaseAuthProps } from './SudobilityAppRNWithFirebaseAuth';
@@ -0,0 +1,2 @@
1
+ export { SudobilityAppRN } from './SudobilityAppRN';
2
+ export { SudobilityAppRNWithFirebaseAuth } from './SudobilityAppRNWithFirebaseAuth';
@@ -0,0 +1,21 @@
1
+ import type { StyleProp, ViewStyle } from 'react-native';
2
+ import type { FooterLinkItem, AnalyticsTrackingParams } from '../../types';
3
+ export interface AppFooterProps {
4
+ /** App version string */
5
+ version?: string;
6
+ /** Copyright year */
7
+ copyrightYear?: string;
8
+ /** Company name */
9
+ companyName: string;
10
+ /** Company URL (opened via Linking) */
11
+ companyUrl?: string;
12
+ /** Rights text (default: "All rights reserved.") */
13
+ rightsText?: string;
14
+ /** Footer links (Privacy, Terms, etc.) */
15
+ links?: FooterLinkItem[];
16
+ /** Custom style */
17
+ style?: StyleProp<ViewStyle>;
18
+ /** Analytics tracking */
19
+ onTrack?: (params: AnalyticsTrackingParams) => void;
20
+ }
21
+ export declare function AppFooter({ version, copyrightYear, companyName, companyUrl, rightsText, links, style, onTrack, }: AppFooterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,72 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { View, Text, Pressable, Linking } from 'react-native';
4
+ import { createThemedStyles } from '../../utils/styles';
5
+ export function AppFooter({ version, copyrightYear, companyName, companyUrl, rightsText = 'All rights reserved.', links, style, onTrack, }) {
6
+ const styles = useStyles();
7
+ const handleLinkPress = (link) => {
8
+ onTrack?.({
9
+ eventType: 'link_click',
10
+ componentName: 'AppFooter',
11
+ label: 'footer_link_clicked',
12
+ params: { link_label: link.label },
13
+ });
14
+ if (link.onPress) {
15
+ link.onPress();
16
+ }
17
+ else if (link.url) {
18
+ Linking.openURL(link.url);
19
+ }
20
+ };
21
+ const handleCompanyPress = () => {
22
+ if (companyUrl) {
23
+ Linking.openURL(companyUrl);
24
+ }
25
+ };
26
+ return (_jsxs(View, { style: [styles.container, style], children: [_jsxs(View, { style: styles.topRow, children: [version && _jsxs(Text, { style: styles.versionText, children: ["v", version] }), _jsxs(Text, { style: styles.copyrightText, children: [copyrightYear ? `\u00A9 ${copyrightYear} ` : '', companyUrl ? (_jsx(Text, { style: styles.companyLink, onPress: handleCompanyPress, children: companyName })) : (companyName), '. ', rightsText] })] }), links && links.length > 0 && (_jsx(View, { style: styles.linksRow, children: links.map((link, index) => (_jsxs(React.Fragment, { children: [index > 0 && _jsx(Text, { style: styles.separator, children: '\u00B7' }), _jsx(Pressable, { onPress: () => handleLinkPress(link), children: _jsx(Text, { style: styles.linkText, children: link.label }) })] }, link.label))) }))] }));
27
+ }
28
+ const useStyles = createThemedStyles(colors => ({
29
+ container: {
30
+ paddingHorizontal: 16,
31
+ paddingVertical: 12,
32
+ borderTopWidth: 1,
33
+ borderTopColor: colors.border,
34
+ backgroundColor: colors.card,
35
+ },
36
+ topRow: {
37
+ flexDirection: 'row',
38
+ alignItems: 'center',
39
+ justifyContent: 'center',
40
+ gap: 8,
41
+ flexWrap: 'wrap',
42
+ },
43
+ versionText: {
44
+ fontSize: 12,
45
+ color: colors.textMuted,
46
+ },
47
+ copyrightText: {
48
+ fontSize: 12,
49
+ color: colors.textSecondary,
50
+ textAlign: 'center',
51
+ },
52
+ companyLink: {
53
+ color: colors.primary,
54
+ textDecorationLine: 'underline',
55
+ },
56
+ linksRow: {
57
+ flexDirection: 'row',
58
+ alignItems: 'center',
59
+ justifyContent: 'center',
60
+ marginTop: 8,
61
+ gap: 8,
62
+ flexWrap: 'wrap',
63
+ },
64
+ separator: {
65
+ color: colors.textMuted,
66
+ fontSize: 12,
67
+ },
68
+ linkText: {
69
+ fontSize: 12,
70
+ color: colors.textSecondary,
71
+ },
72
+ }));
@@ -0,0 +1,2 @@
1
+ export { AppFooter } from './AppFooter';
2
+ export type { AppFooterProps } from './AppFooter';
@@ -0,0 +1 @@
1
+ export { AppFooter } from './AppFooter';
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+ import type { MenuItemConfig, LogoConfig } from '../../types';
4
+ export interface AppHeaderProps {
5
+ /** Logo configuration */
6
+ logo: LogoConfig;
7
+ /** Menu items (shown as icon buttons on the right) */
8
+ menuItems?: MenuItemConfig[];
9
+ /** Optional left section (e.g., back button) */
10
+ renderLeft?: () => React.ReactNode;
11
+ /** Optional right section (e.g., profile icon, account button) */
12
+ renderRight?: () => React.ReactNode;
13
+ /** Custom style */
14
+ style?: StyleProp<ViewStyle>;
15
+ }
16
+ export declare function AppHeader({ logo, menuItems, renderLeft, renderRight, style, }: AppHeaderProps): import("react/jsx-runtime").JSX.Element;
17
+ /**
18
+ * Create React Navigation screen options from header config.
19
+ * Useful for integrating AppHeader into a navigation stack.
20
+ */
21
+ export declare function createAppHeaderOptions(config: {
22
+ logo: LogoConfig;
23
+ menuItems?: MenuItemConfig[];
24
+ renderRight?: () => React.ReactNode;
25
+ }): {
26
+ headerTitle: () => import("react/jsx-runtime").JSX.Element;
27
+ headerRight: (() => import("react/jsx-runtime").JSX.Element) | undefined;
28
+ };
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { View, Text, Image, Pressable, StyleSheet } from 'react-native';
3
+ import { useTheme } from '../../theme/ThemeContext';
4
+ export function AppHeader({ logo, menuItems, renderLeft, renderRight, style, }) {
5
+ const { colors } = useTheme();
6
+ return (_jsxs(View, { style: [
7
+ styles.container,
8
+ { backgroundColor: colors.card, borderBottomColor: colors.border },
9
+ style,
10
+ ], children: [_jsx(View, { style: styles.leftSection, children: renderLeft ? (renderLeft()) : (_jsxs(Pressable, { onPress: logo.onPress, style: styles.logoContainer, children: [logo.source && (_jsx(Image, { source: logo.source, style: styles.logoImage, resizeMode: 'contain' })), _jsx(Text, { style: [styles.appName, { color: colors.text }], children: logo.appName })] })) }), _jsxs(View, { style: styles.rightSection, children: [menuItems
11
+ ?.filter(item => item.show !== false)
12
+ .map(item => {
13
+ const IconComponent = item.icon;
14
+ return (_jsx(Pressable, { onPress: item.onPress, style: styles.menuButton, accessibilityLabel: item.label, children: _jsx(IconComponent, { size: 22, color: colors.textSecondary }) }, item.id));
15
+ }), renderRight?.()] })] }));
16
+ }
17
+ /**
18
+ * Create React Navigation screen options from header config.
19
+ * Useful for integrating AppHeader into a navigation stack.
20
+ */
21
+ export function createAppHeaderOptions(config) {
22
+ return {
23
+ headerTitle: () => (_jsxs(View, { style: styles.logoContainer, children: [config.logo.source && (_jsx(Image, { source: config.logo.source, style: styles.logoImage, resizeMode: 'contain' })), _jsx(Text, { style: styles.headerTitle, children: config.logo.appName })] })),
24
+ headerRight: config.renderRight
25
+ ? () => _jsx(View, { style: styles.headerRightNav, children: config.renderRight() })
26
+ : undefined,
27
+ };
28
+ }
29
+ const styles = StyleSheet.create({
30
+ container: {
31
+ flexDirection: 'row',
32
+ alignItems: 'center',
33
+ justifyContent: 'space-between',
34
+ paddingHorizontal: 16,
35
+ paddingVertical: 12,
36
+ borderBottomWidth: StyleSheet.hairlineWidth,
37
+ },
38
+ leftSection: {
39
+ flexDirection: 'row',
40
+ alignItems: 'center',
41
+ flex: 1,
42
+ },
43
+ rightSection: {
44
+ flexDirection: 'row',
45
+ alignItems: 'center',
46
+ gap: 8,
47
+ },
48
+ logoContainer: {
49
+ flexDirection: 'row',
50
+ alignItems: 'center',
51
+ gap: 8,
52
+ },
53
+ logoImage: {
54
+ width: 28,
55
+ height: 28,
56
+ },
57
+ appName: {
58
+ fontSize: 18,
59
+ fontWeight: '600',
60
+ },
61
+ menuButton: {
62
+ padding: 8,
63
+ borderRadius: 8,
64
+ minWidth: 44,
65
+ minHeight: 44,
66
+ alignItems: 'center',
67
+ justifyContent: 'center',
68
+ },
69
+ headerTitle: {
70
+ fontSize: 18,
71
+ fontWeight: '600',
72
+ },
73
+ headerRightNav: {
74
+ flexDirection: 'row',
75
+ alignItems: 'center',
76
+ gap: 4,
77
+ marginRight: 8,
78
+ },
79
+ });
@@ -0,0 +1,2 @@
1
+ export { AppHeader, createAppHeaderOptions } from './AppHeader';
2
+ export type { AppHeaderProps } from './AppHeader';
@@ -0,0 +1 @@
1
+ export { AppHeader, createAppHeaderOptions } from './AppHeader';
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+ export interface AppScreenLayoutProps {
4
+ children: React.ReactNode;
5
+ /** Optional header component (rendered above scroll content) */
6
+ header?: React.ReactNode;
7
+ /** Optional footer component (rendered below scroll content) */
8
+ footer?: React.ReactNode;
9
+ /** Whether to wrap content in a ScrollView (default: true) */
10
+ scrollable?: boolean;
11
+ /** Content padding */
12
+ contentPadding?: 'none' | 'sm' | 'md' | 'lg';
13
+ /** Background variant */
14
+ background?: 'default' | 'white';
15
+ /** Custom container style */
16
+ style?: StyleProp<ViewStyle>;
17
+ /** Custom content style */
18
+ contentStyle?: StyleProp<ViewStyle>;
19
+ }
20
+ export declare function AppScreenLayout({ children, header, footer, scrollable, contentPadding, background, style, contentStyle, }: AppScreenLayoutProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { View, ScrollView } from 'react-native';
3
+ import { SafeAreaView } from 'react-native-safe-area-context';
4
+ import { createThemedStyles } from '../../utils/styles';
5
+ const paddingMap = {
6
+ none: 0,
7
+ sm: 8,
8
+ md: 16,
9
+ lg: 24,
10
+ };
11
+ export function AppScreenLayout({ children, header, footer, scrollable = true, contentPadding = 'md', background = 'default', style, contentStyle, }) {
12
+ const styles = useStyles();
13
+ const backgroundStyle = background === 'white' ? styles.bgWhite : styles.bgDefault;
14
+ const padding = paddingMap[contentPadding];
15
+ const content = (_jsx(View, { style: [
16
+ { paddingHorizontal: padding, flex: scrollable ? undefined : 1 },
17
+ contentStyle,
18
+ ], children: children }));
19
+ return (_jsxs(SafeAreaView, { style: [styles.container, backgroundStyle, style], edges: ['top', 'left', 'right'], children: [header, scrollable ? (_jsx(ScrollView, { style: styles.scrollView, contentContainerStyle: styles.scrollContent, keyboardShouldPersistTaps: 'handled', children: content })) : (_jsx(View, { style: styles.fixedContent, children: content })), footer] }));
20
+ }
21
+ const useStyles = createThemedStyles(colors => ({
22
+ container: {
23
+ flex: 1,
24
+ },
25
+ bgDefault: {
26
+ backgroundColor: colors.background,
27
+ },
28
+ bgWhite: {
29
+ backgroundColor: colors.card,
30
+ },
31
+ scrollView: {
32
+ flex: 1,
33
+ },
34
+ scrollContent: {
35
+ flexGrow: 1,
36
+ paddingBottom: 16,
37
+ },
38
+ fixedContent: {
39
+ flex: 1,
40
+ },
41
+ }));
@@ -0,0 +1,2 @@
1
+ export { AppScreenLayout } from './AppScreenLayout';
2
+ export type { AppScreenLayoutProps } from './AppScreenLayout';
@@ -0,0 +1 @@
1
+ export { AppScreenLayout } from './AppScreenLayout';
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+ import type { TextPageContent } from '../../types';
4
+ export interface AppTextScreenProps {
5
+ /** Structured text content (same data type as web) */
6
+ text: TextPageContent;
7
+ /** Last updated date override */
8
+ lastUpdatedDate?: string;
9
+ /** Optional screen wrapper component */
10
+ ScreenWrapper?: React.ComponentType<{
11
+ children: React.ReactNode;
12
+ }>;
13
+ /** Custom style */
14
+ style?: StyleProp<ViewStyle>;
15
+ }
16
+ export declare function AppTextScreen({ text, lastUpdatedDate, ScreenWrapper, style, }: AppTextScreenProps): import("react/jsx-runtime").JSX.Element;