@umituz/react-native-design-system 2.1.7 → 2.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "2.1.7",
3
+ "version": "2.2.0",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { Text, StyleProp, TextStyle } from 'react-native';
3
- import { useAppDesignTokens } from '../theme';
3
+ import { useAppDesignTokens, useResponsiveDesignTokens } from '../theme';
4
4
  import type { TextStyleVariant, ColorVariant } from '../typography';
5
5
  import { getTextColor } from '../typography';
6
6
 
@@ -13,6 +13,8 @@ export interface AtomicTextProps {
13
13
  textAlign?: 'auto' | 'left' | 'right' | 'center' | 'justify';
14
14
  style?: StyleProp<TextStyle>;
15
15
  testID?: string;
16
+ /** Enable responsive font sizing (scales based on device) */
17
+ responsive?: boolean;
16
18
  }
17
19
 
18
20
  export const AtomicText: React.FC<AtomicTextProps> = ({
@@ -24,8 +26,13 @@ export const AtomicText: React.FC<AtomicTextProps> = ({
24
26
  textAlign,
25
27
  style,
26
28
  testID,
29
+ responsive = false,
27
30
  }) => {
28
- const tokens = useAppDesignTokens();
31
+ const staticTokens = useAppDesignTokens();
32
+ const responsiveTokens = useResponsiveDesignTokens();
33
+
34
+ // Use responsive tokens if enabled, otherwise use static
35
+ const tokens = responsive ? responsiveTokens : staticTokens;
29
36
 
30
37
  // Get typography style from tokens
31
38
  const typographyStyle = (tokens.typography as Record<string, any>)[type];
@@ -33,10 +40,16 @@ export const AtomicText: React.FC<AtomicTextProps> = ({
33
40
  // Get color from tokens or use custom color using utility function
34
41
  const resolvedColor = getTextColor(color, tokens);
35
42
 
43
+ // Use responsive font size if enabled and available
44
+ const fontSize = responsive && typographyStyle.responsiveFontSize
45
+ ? typographyStyle.responsiveFontSize
46
+ : typographyStyle.fontSize;
47
+
36
48
  const textStyle: StyleProp<TextStyle> = [
37
49
  typographyStyle,
38
50
  {
39
51
  color: resolvedColor,
52
+ ...(fontSize && { fontSize }),
40
53
  ...(textAlign && { textAlign }),
41
54
  },
42
55
  style,
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@
18
18
 
19
19
  export {
20
20
  useAppDesignTokens,
21
+ useResponsiveDesignTokens,
21
22
  useCommonStyles,
22
23
  useDesignSystemTheme,
23
24
  useTheme,
@@ -33,6 +34,7 @@ export {
33
34
  typography,
34
35
  borders,
35
36
  createDesignTokens,
37
+ createResponsiveDesignTokens,
36
38
  lightTheme,
37
39
  darkTheme,
38
40
  createResponsiveValue,
@@ -51,6 +53,10 @@ export {
51
53
  type AvatarSizes,
52
54
  type ComponentSizes,
53
55
  type DesignTokens,
56
+ type ResponsiveDesignTokens,
57
+ type ResponsiveSpacing,
58
+ type ResponsiveTypography,
59
+ type ResponsiveBorderRadius,
54
60
  type Theme,
55
61
  type ExtendedColorPalette,
56
62
  type NavigationTheme,
@@ -177,7 +183,13 @@ export {
177
183
  ConfirmationModal,
178
184
  useConfirmationModal,
179
185
  StepProgress,
186
+ Grid,
187
+ List,
188
+ Container,
180
189
  type BaseModalProps,
190
+ type GridProps,
191
+ type ListProps,
192
+ type ContainerProps,
181
193
  } from './molecules';
182
194
 
183
195
  // =============================================================================
@@ -188,6 +200,8 @@ export {
188
200
  ScreenLayout,
189
201
  AppHeader,
190
202
  FormContainer,
203
+ FormLayout,
204
+ type FormLayoutProps,
191
205
  } from './organisms';
192
206
 
193
207
  // =============================================================================
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Container - Max-Width Content Container (Molecule)
3
+ *
4
+ * Centers content with responsive max-width based on device
5
+ * Prevents content from being too wide on tablets
6
+ */
7
+
8
+ import React, { useMemo } from 'react';
9
+ import { View, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
10
+ import { useResponsive } from '../../responsive';
11
+ import { useResponsiveDesignTokens } from '../../theme';
12
+
13
+ export interface ContainerProps {
14
+ /** Container content */
15
+ children: React.ReactNode;
16
+
17
+ /** Maximum width (default: responsive based on device) */
18
+ maxWidth?: number;
19
+
20
+ /** Horizontal padding (uses responsive tokens) */
21
+ padding?: boolean;
22
+
23
+ /** Center content horizontally */
24
+ center?: boolean;
25
+
26
+ /** Container style */
27
+ style?: StyleProp<ViewStyle>;
28
+
29
+ /** Test ID */
30
+ testID?: string;
31
+ }
32
+
33
+ /**
34
+ * Responsive container with max-width
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <Container maxWidth={600} padding center>
39
+ * <Text>Centered content with max width</Text>
40
+ * </Container>
41
+ * ```
42
+ */
43
+ export const Container: React.FC<ContainerProps> = ({
44
+ children,
45
+ maxWidth,
46
+ padding = true,
47
+ center = true,
48
+ style,
49
+ testID,
50
+ }) => {
51
+ const { maxContentWidth } = useResponsive();
52
+ const tokens = useResponsiveDesignTokens();
53
+
54
+ const containerWidth = maxWidth || maxContentWidth;
55
+
56
+ const styles = useMemo(
57
+ () =>
58
+ StyleSheet.create({
59
+ container: {
60
+ width: '100%',
61
+ maxWidth: containerWidth,
62
+ ...(center && { alignSelf: 'center' }),
63
+ ...(padding && {
64
+ paddingHorizontal: tokens.spacing.screenPadding,
65
+ }),
66
+ },
67
+ }),
68
+ [containerWidth, center, padding, tokens.spacing.screenPadding]
69
+ );
70
+
71
+ return (
72
+ <View style={[styles.container, style]} testID={testID}>
73
+ {children}
74
+ </View>
75
+ );
76
+ };
@@ -0,0 +1 @@
1
+ export { Container, type ContainerProps } from './Container';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Grid - Responsive Grid Layout (Molecule)
3
+ *
4
+ * Automatic responsive grid that adjusts columns based on device
5
+ * Uses design system responsive utilities
6
+ */
7
+
8
+ import React, { useMemo } from 'react';
9
+ import { View, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
10
+ import { useResponsive } from '../../responsive';
11
+ import { useResponsiveDesignTokens } from '../../theme';
12
+
13
+ export interface GridProps {
14
+ /** Grid items to render */
15
+ children: React.ReactNode;
16
+
17
+ /** Number of columns on mobile (default: 2) */
18
+ mobileColumns?: number;
19
+
20
+ /** Number of columns on tablet (default: 4) */
21
+ tabletColumns?: number;
22
+
23
+ /** Gap between grid items (uses design tokens spacing) */
24
+ gap?: number;
25
+
26
+ /** Container style */
27
+ style?: StyleProp<ViewStyle>;
28
+
29
+ /** Test ID for testing */
30
+ testID?: string;
31
+ }
32
+
33
+ /**
34
+ * Responsive grid component
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <Grid mobileColumns={2} tabletColumns={4} gap={16}>
39
+ * <Card />
40
+ * <Card />
41
+ * <Card />
42
+ * </Grid>
43
+ * ```
44
+ */
45
+ export const Grid: React.FC<GridProps> = ({
46
+ children,
47
+ mobileColumns = 2,
48
+ tabletColumns = 4,
49
+ gap,
50
+ style,
51
+ testID,
52
+ }) => {
53
+ const { gridColumns, spacingMultiplier } = useResponsive();
54
+ const tokens = useResponsiveDesignTokens();
55
+
56
+ // Calculate responsive columns
57
+ const columns = gridColumns || (mobileColumns && tabletColumns
58
+ ? undefined
59
+ : mobileColumns);
60
+
61
+ // Use responsive gap or default
62
+ const responsiveGap = gap ? gap * spacingMultiplier : tokens.spacing.md;
63
+
64
+ const styles = useMemo(
65
+ () =>
66
+ StyleSheet.create({
67
+ container: {
68
+ flexDirection: 'row',
69
+ flexWrap: 'wrap',
70
+ gap: responsiveGap,
71
+ },
72
+ }),
73
+ [responsiveGap]
74
+ );
75
+
76
+ // Convert children to array for mapping
77
+ const childArray = React.Children.toArray(children);
78
+
79
+ return (
80
+ <View style={[styles.container, style]} testID={testID}>
81
+ {childArray.map((child, index) => (
82
+ <View
83
+ key={index}
84
+ style={{
85
+ flex: columns ? 1 / columns - 0.01 : undefined,
86
+ minWidth: columns ? `${100 / columns - 1}%` : undefined,
87
+ }}
88
+ >
89
+ {child}
90
+ </View>
91
+ ))}
92
+ </View>
93
+ );
94
+ };
@@ -0,0 +1 @@
1
+ export { Grid, type GridProps } from './Grid';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * List - Responsive List Wrapper (Molecule)
3
+ *
4
+ * FlatList wrapper with responsive item sizing and built-in pull-to-refresh
5
+ * Uses design system responsive utilities
6
+ */
7
+
8
+ import React from 'react';
9
+ import { FlatList, RefreshControl, type FlatListProps, type ListRenderItem } from 'react-native';
10
+ import { useResponsiveDesignTokens } from '../../theme';
11
+
12
+ export interface ListProps<T> extends Omit<FlatListProps<T>, 'renderItem'> {
13
+ /** Data array */
14
+ data: readonly T[] | null | undefined;
15
+
16
+ /** Render function for each item */
17
+ renderItem: ListRenderItem<T>;
18
+
19
+ /** Pull-to-refresh handler */
20
+ onRefresh?: () => void;
21
+
22
+ /** Refreshing state */
23
+ refreshing?: boolean;
24
+
25
+ /** Key extractor (required for proper list performance) */
26
+ keyExtractor: (item: T, index: number) => string;
27
+
28
+ /** Content container padding (uses responsive tokens) */
29
+ contentPadding?: boolean;
30
+ }
31
+
32
+ /**
33
+ * Responsive list component with pull-to-refresh
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * <List
38
+ * data={items}
39
+ * renderItem={({ item }) => <ItemCard item={item} />}
40
+ * keyExtractor={(item) => item.id}
41
+ * onRefresh={handleRefresh}
42
+ * refreshing={isRefreshing}
43
+ * contentPadding
44
+ * />
45
+ * ```
46
+ */
47
+ export const List = <T,>({
48
+ data,
49
+ renderItem,
50
+ onRefresh,
51
+ refreshing = false,
52
+ keyExtractor,
53
+ contentPadding = false,
54
+ ...rest
55
+ }: ListProps<T>) => {
56
+ const tokens = useResponsiveDesignTokens();
57
+
58
+ return (
59
+ <FlatList
60
+ data={data}
61
+ renderItem={renderItem}
62
+ keyExtractor={keyExtractor}
63
+ refreshControl={
64
+ onRefresh ? (
65
+ <RefreshControl
66
+ refreshing={refreshing}
67
+ onRefresh={onRefresh}
68
+ tintColor={tokens.colors.primary}
69
+ colors={[tokens.colors.primary]}
70
+ />
71
+ ) : undefined
72
+ }
73
+ contentContainerStyle={
74
+ contentPadding
75
+ ? {
76
+ paddingHorizontal: tokens.spacing.screenPadding,
77
+ paddingBottom: tokens.spacing.lg,
78
+ }
79
+ : undefined
80
+ }
81
+ showsVerticalScrollIndicator={false}
82
+ {...rest}
83
+ />
84
+ );
85
+ };
@@ -0,0 +1 @@
1
+ export { List, type ListProps } from './List';
@@ -22,3 +22,8 @@ export type {
22
22
  // Divider
23
23
  export * from './Divider';
24
24
  export * from "./StepProgress";
25
+
26
+ // Responsive Components
27
+ export { Grid, type GridProps } from './Grid';
28
+ export { List, type ListProps } from './List';
29
+ export { Container, type ContainerProps } from './Container';
@@ -0,0 +1,117 @@
1
+ /**
2
+ * FormLayout - Responsive Form Container
3
+ *
4
+ * Organism for creating responsive forms with consistent spacing
5
+ * Automatically handles keyboard avoidance and scrolling
6
+ */
7
+
8
+ import React, { useMemo } from 'react';
9
+ import { View, ScrollView, KeyboardAvoidingView, StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
10
+ import { useResponsiveDesignTokens } from '../../theme';
11
+ import { useResponsive } from '../../responsive';
12
+
13
+ export interface FormLayoutProps {
14
+ /** Form fields and content */
15
+ children: React.ReactNode;
16
+
17
+ /** Footer content (e.g., submit button) */
18
+ footer?: React.ReactNode;
19
+
20
+ /** Form container style */
21
+ style?: StyleProp<ViewStyle>;
22
+
23
+ /** Disable keyboard avoiding behavior */
24
+ disableKeyboardAvoid?: boolean;
25
+
26
+ /** Disable scroll */
27
+ disableScroll?: boolean;
28
+
29
+ /** Test ID */
30
+ testID?: string;
31
+ }
32
+
33
+ /**
34
+ * Responsive form layout with keyboard avoidance
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * <FormLayout
39
+ * footer={<AtomicButton title="Submit" onPress={handleSubmit} />}
40
+ * >
41
+ * <FormField label="Name" value={name} onChangeText={setName} />
42
+ * <FormField label="Email" value={email} onChangeText={setEmail} />
43
+ * </FormLayout>
44
+ * ```
45
+ */
46
+ export const FormLayout: React.FC<FormLayoutProps> = ({
47
+ children,
48
+ footer,
49
+ style,
50
+ disableKeyboardAvoid = false,
51
+ disableScroll = false,
52
+ testID,
53
+ }) => {
54
+ const tokens = useResponsiveDesignTokens();
55
+ const { insets } = useResponsive();
56
+
57
+ const styles = useMemo(
58
+ () =>
59
+ StyleSheet.create({
60
+ container: {
61
+ flex: 1,
62
+ },
63
+ scrollContent: {
64
+ flexGrow: 1,
65
+ paddingHorizontal: tokens.spacing.screenPadding,
66
+ paddingTop: tokens.spacing.md,
67
+ paddingBottom: tokens.spacing.xl,
68
+ },
69
+ formContent: {
70
+ gap: tokens.spacing.lg,
71
+ },
72
+ footer: {
73
+ paddingHorizontal: tokens.spacing.screenPadding,
74
+ paddingBottom: Math.max(insets.bottom, tokens.spacing.md),
75
+ paddingTop: tokens.spacing.md,
76
+ backgroundColor: tokens.colors.surface,
77
+ borderTopWidth: 1,
78
+ borderTopColor: tokens.colors.border,
79
+ },
80
+ }),
81
+ [tokens, insets.bottom]
82
+ );
83
+
84
+ const content = (
85
+ <View style={styles.formContent} testID={testID}>
86
+ {children}
87
+ </View>
88
+ );
89
+
90
+ const scrollableContent = disableScroll ? (
91
+ <View style={styles.scrollContent}>{content}</View>
92
+ ) : (
93
+ <ScrollView
94
+ style={styles.container}
95
+ contentContainerStyle={styles.scrollContent}
96
+ keyboardShouldPersistTaps="handled"
97
+ showsVerticalScrollIndicator={false}
98
+ >
99
+ {content}
100
+ </ScrollView>
101
+ );
102
+
103
+ const mainContent = disableKeyboardAvoid ? (
104
+ scrollableContent
105
+ ) : (
106
+ <KeyboardAvoidingView style={styles.container} behavior="padding">
107
+ {scrollableContent}
108
+ </KeyboardAvoidingView>
109
+ );
110
+
111
+ return (
112
+ <View style={[styles.container, style]}>
113
+ {mainContent}
114
+ {footer && <View style={styles.footer}>{footer}</View>}
115
+ </View>
116
+ );
117
+ };
@@ -0,0 +1 @@
1
+ export { FormLayout, type FormLayoutProps } from './FormLayout';
@@ -14,18 +14,22 @@
14
14
  export { AppHeader } from './AppHeader';
15
15
  export { ScreenLayout } from './ScreenLayout';
16
16
  export { FormContainer } from './FormContainer';
17
+ export { FormLayout } from './FormLayout';
17
18
 
18
19
  // Type exports
19
20
  export type { AppHeaderProps } from './AppHeader';
20
21
  export type { ScreenLayoutProps } from './ScreenLayout';
21
22
  export type { FormContainerProps } from './FormContainer';
23
+ export type { FormLayoutProps } from './FormLayout';
22
24
 
23
25
  // Union type for all organism props (used for type narrowing)
24
26
  import type { AppHeaderProps } from './AppHeader';
25
27
  import type { ScreenLayoutProps } from './ScreenLayout';
26
28
  import type { FormContainerProps } from './FormContainer';
29
+ import type { FormLayoutProps } from './FormLayout';
27
30
 
28
- export type OrganismComponentProps =
31
+ export type OrganismComponentProps =
29
32
  | { type: 'AppHeader'; props: AppHeaderProps }
30
33
  | { type: 'ScreenLayout'; props: ScreenLayoutProps }
31
- | { type: 'FormContainer'; props: FormContainerProps };
34
+ | { type: 'FormContainer'; props: FormContainerProps }
35
+ | { type: 'FormLayout'; props: FormLayoutProps };
@@ -0,0 +1,266 @@
1
+ /**
2
+ * RESPONSIVE TOKEN FACTORY
3
+ *
4
+ * ✅ Extends base TokenFactory with responsive capabilities
5
+ * ✅ Device-aware spacing, typography, and sizing
6
+ * ✅ Automatically scales all tokens based on device type
7
+ * ✅ Backward compatible with existing token system
8
+ *
9
+ * @module ResponsiveTokenFactory
10
+ */
11
+
12
+ import { BASE_TOKENS } from './BaseTokens';
13
+ import { createDesignTokens, type DesignTokens, type ThemeMode } from './TokenFactory';
14
+ import { type CustomThemeColors } from './CustomColors';
15
+
16
+ // =============================================================================
17
+ // RESPONSIVE DESIGN TOKENS TYPE
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Responsive spacing tokens that scale based on device
22
+ */
23
+ export type ResponsiveSpacing = {
24
+ // Base Spacing Scale (scales with spacingMultiplier)
25
+ xs: number;
26
+ sm: number;
27
+ md: number;
28
+ lg: number;
29
+ xl: number;
30
+ xxl: number;
31
+ xxxl: number;
32
+
33
+ // Semantic Spacing (scales with device)
34
+ screenPadding: number;
35
+ cardPadding: number;
36
+ buttonPadding: number;
37
+ inputPadding: number;
38
+ sectionSpacing: number;
39
+
40
+ // Icon Sizes (scales with device)
41
+ iconSizeSmall: number;
42
+ iconSizeMedium: number;
43
+ iconSizeLarge: number;
44
+ iconSizeXLarge: number;
45
+ iconSizeHero: number;
46
+
47
+ // Component Heights (scales with device)
48
+ buttonHeight: number;
49
+ inputHeight: number;
50
+ appBarHeight: number;
51
+ tabBarHeight: number;
52
+ };
53
+
54
+ /**
55
+ * Responsive typography tokens that scale based on device
56
+ */
57
+ export type ResponsiveTypography = typeof BASE_TOKENS.typography & {
58
+ // Each typography level gets responsive fontSize
59
+ displayLarge: typeof BASE_TOKENS.typography.displayLarge & { responsiveFontSize: number };
60
+ displayMedium: typeof BASE_TOKENS.typography.displayMedium & { responsiveFontSize: number };
61
+ displaySmall: typeof BASE_TOKENS.typography.displaySmall & { responsiveFontSize: number };
62
+ headlineLarge: typeof BASE_TOKENS.typography.headlineLarge & { responsiveFontSize: number };
63
+ headlineMedium: typeof BASE_TOKENS.typography.headlineMedium & { responsiveFontSize: number };
64
+ headlineSmall: typeof BASE_TOKENS.typography.headlineSmall & { responsiveFontSize: number };
65
+ titleLarge: typeof BASE_TOKENS.typography.titleLarge & { responsiveFontSize: number };
66
+ titleMedium: typeof BASE_TOKENS.typography.titleMedium & { responsiveFontSize: number };
67
+ titleSmall: typeof BASE_TOKENS.typography.titleSmall & { responsiveFontSize: number };
68
+ bodyLarge: typeof BASE_TOKENS.typography.bodyLarge & { responsiveFontSize: number };
69
+ bodyMedium: typeof BASE_TOKENS.typography.bodyMedium & { responsiveFontSize: number };
70
+ bodySmall: typeof BASE_TOKENS.typography.bodySmall & { responsiveFontSize: number };
71
+ labelLarge: typeof BASE_TOKENS.typography.labelLarge & { responsiveFontSize: number };
72
+ labelMedium: typeof BASE_TOKENS.typography.labelMedium & { responsiveFontSize: number };
73
+ labelSmall: typeof BASE_TOKENS.typography.labelSmall & { responsiveFontSize: number };
74
+ };
75
+
76
+ /**
77
+ * Responsive border radius tokens that scale based on device
78
+ */
79
+ export type ResponsiveBorderRadius = {
80
+ none: number;
81
+ xs: number;
82
+ sm: number;
83
+ md: number;
84
+ lg: number;
85
+ xl: number;
86
+ xxl: number;
87
+ full: number;
88
+ };
89
+
90
+ /**
91
+ * Complete responsive design tokens
92
+ * Extends base DesignTokens with responsive capabilities
93
+ */
94
+ export type ResponsiveDesignTokens = Omit<DesignTokens, 'spacing' | 'typography' | 'borderRadius'> & {
95
+ spacing: ResponsiveSpacing;
96
+ typography: ResponsiveTypography;
97
+ borderRadius: ResponsiveBorderRadius;
98
+
99
+ // Original base tokens (for backward compatibility)
100
+ baseSpacing: typeof BASE_TOKENS.spacing;
101
+ baseTypography: typeof BASE_TOKENS.typography;
102
+ baseBorderRadius: typeof BASE_TOKENS.borders.radius;
103
+
104
+ // Responsive multiplier value
105
+ spacingMultiplier: number;
106
+ };
107
+
108
+ // =============================================================================
109
+ // RESPONSIVE TOKEN FACTORY FUNCTION
110
+ // =============================================================================
111
+
112
+ /**
113
+ * Create responsive design tokens for a specific theme mode
114
+ *
115
+ * @param mode - Theme mode ('light' or 'dark')
116
+ * @param spacingMultiplier - Device-based spacing multiplier (from useResponsive)
117
+ * @param getFontSize - Function to get responsive font size (from useResponsive)
118
+ * @param customColors - Optional custom colors to override default colors
119
+ * @returns Complete responsive design tokens object
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const { spacingMultiplier, getFontSize } = useResponsive();
124
+ * const tokens = createResponsiveDesignTokens('light', spacingMultiplier, getFontSize);
125
+ *
126
+ * // Use in components
127
+ * <View style={{ padding: tokens.spacing.md }}> // Auto-scales: 16px * 1.2 = 19.2px on tablet
128
+ * <Text style={{ fontSize: tokens.typography.bodyLarge.responsiveFontSize }}>
129
+ * Hello!
130
+ * </Text>
131
+ * </View>
132
+ * ```
133
+ */
134
+ export const createResponsiveDesignTokens = (
135
+ mode: ThemeMode,
136
+ spacingMultiplier: number,
137
+ getFontSize: (baseFontSize: number) => number,
138
+ customColors?: CustomThemeColors,
139
+ ): ResponsiveDesignTokens => {
140
+ // Get base tokens from existing factory
141
+ const baseTokens = createDesignTokens(mode, customColors);
142
+
143
+ // Create responsive spacing (multiply all base spacing values)
144
+ const responsiveSpacing: ResponsiveSpacing = {
145
+ // Base Spacing Scale
146
+ xs: BASE_TOKENS.spacing.xs * spacingMultiplier,
147
+ sm: BASE_TOKENS.spacing.sm * spacingMultiplier,
148
+ md: BASE_TOKENS.spacing.md * spacingMultiplier,
149
+ lg: BASE_TOKENS.spacing.lg * spacingMultiplier,
150
+ xl: BASE_TOKENS.spacing.xl * spacingMultiplier,
151
+ xxl: BASE_TOKENS.spacing.xxl * spacingMultiplier,
152
+ xxxl: BASE_TOKENS.spacing.xxxl * spacingMultiplier,
153
+
154
+ // Semantic Spacing
155
+ screenPadding: BASE_TOKENS.spacing.screenPadding * spacingMultiplier,
156
+ cardPadding: BASE_TOKENS.spacing.cardPadding * spacingMultiplier,
157
+ buttonPadding: BASE_TOKENS.spacing.buttonPadding * spacingMultiplier,
158
+ inputPadding: BASE_TOKENS.spacing.inputPadding * spacingMultiplier,
159
+ sectionSpacing: BASE_TOKENS.spacing.sectionSpacing * spacingMultiplier,
160
+
161
+ // Icon Sizes
162
+ iconSizeSmall: Math.round(BASE_TOKENS.spacing.iconSizeSmall * spacingMultiplier),
163
+ iconSizeMedium: Math.round(BASE_TOKENS.spacing.iconSizeMedium * spacingMultiplier),
164
+ iconSizeLarge: Math.round(BASE_TOKENS.spacing.iconSizeLarge * spacingMultiplier),
165
+ iconSizeXLarge: Math.round(BASE_TOKENS.spacing.iconSizeXLarge * spacingMultiplier),
166
+ iconSizeHero: Math.round(BASE_TOKENS.spacing.iconSizeHero * spacingMultiplier),
167
+
168
+ // Component Heights
169
+ buttonHeight: Math.round(BASE_TOKENS.spacing.buttonHeight * spacingMultiplier),
170
+ inputHeight: Math.round(BASE_TOKENS.spacing.inputHeight * spacingMultiplier),
171
+ appBarHeight: Math.round(BASE_TOKENS.spacing.appBarHeight * spacingMultiplier),
172
+ tabBarHeight: Math.round(BASE_TOKENS.spacing.tabBarHeight * spacingMultiplier),
173
+ };
174
+
175
+ // Create responsive typography (add responsiveFontSize to each level)
176
+ const responsiveTypography: ResponsiveTypography = {
177
+ displayLarge: {
178
+ ...BASE_TOKENS.typography.displayLarge,
179
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.displayLarge.fontSize!),
180
+ },
181
+ displayMedium: {
182
+ ...BASE_TOKENS.typography.displayMedium,
183
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.displayMedium.fontSize!),
184
+ },
185
+ displaySmall: {
186
+ ...BASE_TOKENS.typography.displaySmall,
187
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.displaySmall.fontSize!),
188
+ },
189
+ headlineLarge: {
190
+ ...BASE_TOKENS.typography.headlineLarge,
191
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.headlineLarge.fontSize!),
192
+ },
193
+ headlineMedium: {
194
+ ...BASE_TOKENS.typography.headlineMedium,
195
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.headlineMedium.fontSize!),
196
+ },
197
+ headlineSmall: {
198
+ ...BASE_TOKENS.typography.headlineSmall,
199
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.headlineSmall.fontSize!),
200
+ },
201
+ titleLarge: {
202
+ ...BASE_TOKENS.typography.titleLarge,
203
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.titleLarge.fontSize!),
204
+ },
205
+ titleMedium: {
206
+ ...BASE_TOKENS.typography.titleMedium,
207
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.titleMedium.fontSize!),
208
+ },
209
+ titleSmall: {
210
+ ...BASE_TOKENS.typography.titleSmall,
211
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.titleSmall.fontSize!),
212
+ },
213
+ bodyLarge: {
214
+ ...BASE_TOKENS.typography.bodyLarge,
215
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.bodyLarge.fontSize!),
216
+ },
217
+ bodyMedium: {
218
+ ...BASE_TOKENS.typography.bodyMedium,
219
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.bodyMedium.fontSize!),
220
+ },
221
+ bodySmall: {
222
+ ...BASE_TOKENS.typography.bodySmall,
223
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.bodySmall.fontSize!),
224
+ },
225
+ labelLarge: {
226
+ ...BASE_TOKENS.typography.labelLarge,
227
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.labelLarge.fontSize!),
228
+ },
229
+ labelMedium: {
230
+ ...BASE_TOKENS.typography.labelMedium,
231
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.labelMedium.fontSize!),
232
+ },
233
+ labelSmall: {
234
+ ...BASE_TOKENS.typography.labelSmall,
235
+ responsiveFontSize: getFontSize(BASE_TOKENS.typography.labelSmall.fontSize!),
236
+ },
237
+ } as ResponsiveTypography;
238
+
239
+ // Create responsive border radius
240
+ const responsiveBorderRadius: ResponsiveBorderRadius = {
241
+ none: 0,
242
+ xs: Math.round(BASE_TOKENS.borders.radius.xs * spacingMultiplier),
243
+ sm: Math.round(BASE_TOKENS.borders.radius.sm * spacingMultiplier),
244
+ md: Math.round(BASE_TOKENS.borders.radius.md * spacingMultiplier),
245
+ lg: Math.round(BASE_TOKENS.borders.radius.lg * spacingMultiplier),
246
+ xl: Math.round(BASE_TOKENS.borders.radius.xl * spacingMultiplier),
247
+ xxl: Math.round(BASE_TOKENS.borders.radius.xxl * spacingMultiplier),
248
+ full: 9999, // Always full circle
249
+ };
250
+
251
+ // Return complete responsive tokens
252
+ return {
253
+ ...baseTokens,
254
+ spacing: responsiveSpacing,
255
+ typography: responsiveTypography,
256
+ borderRadius: responsiveBorderRadius,
257
+
258
+ // Keep original base tokens for backward compatibility
259
+ baseSpacing: BASE_TOKENS.spacing,
260
+ baseTypography: BASE_TOKENS.typography,
261
+ baseBorderRadius: BASE_TOKENS.borders.radius,
262
+
263
+ // Store multiplier for reference
264
+ spacingMultiplier,
265
+ };
266
+ };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * useResponsiveDesignTokens Hook
3
+ *
4
+ * ✅ Combines theme system + responsive utilities
5
+ * ✅ Returns device-aware design tokens
6
+ * ✅ Auto-updates on theme changes, orientation changes, screen resize
7
+ * ✅ Drop-in replacement for useAppDesignTokens with responsive capabilities
8
+ *
9
+ * @module useResponsiveDesignTokens
10
+ */
11
+
12
+ import { useMemo } from 'react';
13
+ import { useDesignSystemTheme } from '../infrastructure/globalThemeStore';
14
+ import { createResponsiveDesignTokens, type ResponsiveDesignTokens } from '../core/ResponsiveTokenFactory';
15
+ import { useResponsive } from '../../responsive/useResponsive';
16
+
17
+ /**
18
+ * Hook for responsive design tokens
19
+ *
20
+ * Returns complete design tokens with automatic responsive scaling based on device type.
21
+ * All spacing, typography, and border radius values automatically scale for tablets and large phones.
22
+ *
23
+ * @returns ResponsiveDesignTokens - Complete tokens with responsive spacing, typography, borders
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { useResponsiveDesignTokens } from '@umituz/react-native-design-system';
28
+ *
29
+ * const MyComponent = () => {
30
+ * const tokens = useResponsiveDesignTokens();
31
+ *
32
+ * return (
33
+ * <View style={{
34
+ * padding: tokens.spacing.md, // Auto-scales: 16px on phone, 19.2px on tablet
35
+ * borderRadius: tokens.borderRadius.lg, // Auto-scales based on device
36
+ * }}>
37
+ * <Text style={{
38
+ * fontSize: tokens.typography.bodyLarge.responsiveFontSize, // Responsive font
39
+ * color: tokens.colors.textPrimary, // Theme-aware color
40
+ * }}>
41
+ * Hello World!
42
+ * </Text>
43
+ * </View>
44
+ * );
45
+ * };
46
+ * ```
47
+ *
48
+ * @example Using backward-compatible base tokens
49
+ * ```typescript
50
+ * const tokens = useResponsiveDesignTokens();
51
+ *
52
+ * // Use responsive tokens (recommended)
53
+ * const padding = tokens.spacing.md; // 16px * spacingMultiplier
54
+ *
55
+ * // Use original base tokens (backward compatibility)
56
+ * const basePadding = tokens.baseSpacing.md; // Always 16px
57
+ * ```
58
+ *
59
+ * @example Manual responsive calculation
60
+ * ```typescript
61
+ * const tokens = useResponsiveDesignTokens();
62
+ *
63
+ * // Custom responsive value
64
+ * const customPadding = 20 * tokens.spacingMultiplier; // 20px * 1.2 = 24px on tablet
65
+ * ```
66
+ */
67
+ export const useResponsiveDesignTokens = (): ResponsiveDesignTokens => {
68
+ // Get current theme mode and custom colors from theme store
69
+ const { themeMode, customColors } = useDesignSystemTheme();
70
+
71
+ // Get responsive utilities
72
+ const { spacingMultiplier, getFontSize } = useResponsive();
73
+
74
+ // Create and memoize responsive tokens
75
+ // Recalculates when: theme changes, screen size changes, orientation changes
76
+ const responsiveTokens = useMemo(
77
+ () => createResponsiveDesignTokens(themeMode, spacingMultiplier, getFontSize, customColors),
78
+ [themeMode, spacingMultiplier, getFontSize, customColors]
79
+ );
80
+
81
+ return responsiveTokens;
82
+ };
@@ -55,11 +55,24 @@ export {
55
55
  type DesignTokens,
56
56
  } from './core/TokenFactory';
57
57
 
58
+ // =============================================================================
59
+ // RESPONSIVE TOKEN FACTORY
60
+ // =============================================================================
61
+
62
+ export {
63
+ createResponsiveDesignTokens,
64
+ type ResponsiveDesignTokens,
65
+ type ResponsiveSpacing,
66
+ type ResponsiveTypography,
67
+ type ResponsiveBorderRadius,
68
+ } from './core/ResponsiveTokenFactory';
69
+
58
70
  // =============================================================================
59
71
  // HOOKS
60
72
  // =============================================================================
61
73
 
62
74
  export { useAppDesignTokens } from './hooks/useAppDesignTokens';
75
+ export { useResponsiveDesignTokens } from './hooks/useResponsiveDesignTokens';
63
76
  export { useDesignSystemTheme } from './infrastructure/globalThemeStore';
64
77
  export { useTheme } from './infrastructure/stores/themeStore';
65
78
  export { useThemedStyles, useThemedStyleSheet } from './hooks/useThemedStyles';