@umituz/react-native-design-system 4.25.74 → 4.25.76

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": "4.25.74",
3
+ "version": "4.25.76",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -215,9 +215,13 @@
215
215
  "react-native-gesture-handler": ">=2.20.0",
216
216
  "react-native-safe-area-context": ">=5.6.2",
217
217
  "zustand": ">=5.0.0",
218
- "@react-native-community/datetimepicker": ">=8.0.0"
218
+ "@react-native-community/datetimepicker": ">=8.0.0",
219
+ "react-native-keyboard-controller": ">=1.0.0"
219
220
  },
220
221
  "peerDependenciesMeta": {
222
+ "react-native-keyboard-controller": {
223
+ "optional": true
224
+ },
221
225
  "@react-navigation/native": {
222
226
  "optional": true
223
227
  },
@@ -1,21 +1,31 @@
1
1
  /**
2
2
  * ScreenLayout Component
3
- * Refactored: Extracted types, styles, and ContentWrapper
4
3
  */
5
4
 
6
5
  import React, { useMemo } from 'react';
7
- import { View, ScrollView } from 'react-native';
6
+ import { View, ScrollView, KeyboardAvoidingView, Platform } from 'react-native';
8
7
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
9
8
  import { useAppDesignTokens } from '../../theme';
10
9
  import { getScreenLayoutConfig } from '../../responsive/responsiveLayout';
11
- import { AtomicKeyboardAvoidingView } from '../../atoms';
12
10
  import { getScreenLayoutStyles } from './styles/screenLayoutStyles';
13
11
  import type { ScreenLayoutProps } from './types';
14
12
 
13
+ // Lazy-load react-native-keyboard-controller (optional peer dep).
14
+ // Falls back to React Native's built-in components when not installed.
15
+ let KCKeyboardAvoidingView: React.ComponentType<any> | null = null;
16
+ let KCKeyboardAwareScrollView: React.ComponentType<any> | null = null;
17
+ try {
18
+ const kc = require('react-native-keyboard-controller');
19
+ KCKeyboardAvoidingView = kc.KeyboardAvoidingView ?? null;
20
+ KCKeyboardAwareScrollView = kc.KeyboardAwareScrollView ?? null;
21
+ } catch {
22
+ // react-native-keyboard-controller not installed — using RN built-ins
23
+ }
24
+
15
25
  export const ScreenLayout: React.FC<ScreenLayoutProps> = (props: ScreenLayoutProps) => {
16
26
  const {
17
27
  children,
18
- scrollable = true,
28
+ scrollable = false,
19
29
  edges = ['top', 'bottom', 'left', 'right'],
20
30
  header,
21
31
  footer,
@@ -25,89 +35,94 @@ export const ScreenLayout: React.FC<ScreenLayoutProps> = (props: ScreenLayoutPro
25
35
  testID,
26
36
  hideScrollIndicator = false,
27
37
  keyboardAvoiding = false,
38
+ keyboardVerticalOffset = 0,
28
39
  maxWidth,
29
40
  refreshControl,
30
41
  } = props;
42
+
31
43
  const tokens = useAppDesignTokens();
32
44
  const insets = useSafeAreaInsets();
33
45
 
34
- // Get all responsive layout values from centralized config
35
- const layoutConfig = useMemo(
36
- () => getScreenLayoutConfig(insets),
37
- [insets]
38
- );
46
+ const layoutConfig = useMemo(() => getScreenLayoutConfig(insets), [insets]);
39
47
 
40
- // Use centralized layout config for consistency
41
48
  const finalMaxWidth = maxWidth || layoutConfig.maxContentWidth;
42
49
  const horizontalPadding = layoutConfig.horizontalPadding;
43
50
  const verticalPadding = layoutConfig.verticalPadding;
44
51
 
45
- // Pre-compute styles
46
52
  const styles = useMemo(
47
53
  () => getScreenLayoutStyles({ maxWidth: finalMaxWidth, horizontalPadding, verticalPadding }),
48
- [finalMaxWidth, horizontalPadding, verticalPadding]
54
+ [finalMaxWidth, horizontalPadding, verticalPadding],
49
55
  );
50
56
 
51
57
  const bgColor = backgroundColor || tokens.colors.backgroundPrimary;
52
-
53
- // Robust safe area handling
58
+
54
59
  const paddingTop = edges.includes('top') ? insets.top : 0;
55
60
  const paddingBottom = edges.includes('bottom') ? insets.bottom : 0;
56
61
  const paddingLeft = edges.includes('left') ? insets.left : 0;
57
62
  const paddingRight = edges.includes('right') ? insets.right : 0;
58
63
 
64
+ // Scroll component: prefer KeyboardAwareScrollView (keyboard-controller) over plain ScrollView.
65
+ // KeyboardAwareScrollView automatically keeps focused TextInput above the keyboard
66
+ // without needing a separate KeyboardAvoidingView wrapper.
67
+ const ScrollComponent = KCKeyboardAwareScrollView ?? ScrollView;
68
+
59
69
  const content = (
60
- <View style={[
61
- styles.responsiveWrapper,
62
- {
63
- paddingTop,
64
- paddingBottom: footer ? 0 : paddingBottom,
65
- paddingLeft,
66
- paddingRight,
67
- }
68
- ]}>
70
+ <View
71
+ style={[
72
+ styles.responsiveWrapper,
73
+ {
74
+ paddingTop,
75
+ paddingBottom: footer ? 0 : paddingBottom,
76
+ paddingLeft,
77
+ paddingRight,
78
+ },
79
+ ]}
80
+ >
69
81
  {header}
70
82
  {scrollable ? (
71
- <ScrollView
83
+ <ScrollComponent
72
84
  style={styles.scrollView}
73
85
  contentContainerStyle={[styles.scrollContent, contentContainerStyle]}
74
86
  showsVerticalScrollIndicator={!hideScrollIndicator}
75
87
  keyboardShouldPersistTaps="handled"
76
88
  refreshControl={refreshControl}
77
- nestedScrollEnabled
89
+ {...(KCKeyboardAwareScrollView ? { bottomOffset: 16 } : {})}
78
90
  >
79
91
  {children}
80
- </ScrollView>
92
+ </ScrollComponent>
81
93
  ) : (
82
- <View style={[styles.scrollView, styles.scrollContent, contentContainerStyle]}>
94
+ <View style={[styles.scrollView, contentContainerStyle]}>
83
95
  {children}
84
96
  </View>
85
97
  )}
86
- {footer && (
87
- <View style={{ paddingBottom }}>
88
- {footer}
89
- </View>
90
- )}
98
+ {footer && <View style={{ paddingBottom }}>{footer}</View>}
91
99
  </View>
92
100
  );
93
101
 
102
+ // Keyboard avoiding wrapper: prefer keyboard-controller's KAV (consistent iOS+Android)
103
+ // over React Native's built-in (iOS-only reliable).
104
+ // Only used when keyboardAvoiding={true} — screens that manage their own keyboard
105
+ // handling (e.g. ChatScreen) should NOT set this prop.
106
+ if (keyboardAvoiding) {
107
+ const KAV = KCKeyboardAvoidingView ?? KeyboardAvoidingView;
108
+ return (
109
+ <View style={[styles.container, { backgroundColor: bgColor }, containerStyle]} testID={testID}>
110
+ <KAV
111
+ style={styles.keyboardAvoidingView}
112
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
113
+ keyboardVerticalOffset={keyboardVerticalOffset}
114
+ >
115
+ {content}
116
+ </KAV>
117
+ </View>
118
+ );
119
+ }
120
+
94
121
  return (
95
- <View
96
- style={[styles.container, { backgroundColor: bgColor }, containerStyle]}
97
- testID={testID}
98
- >
99
- {keyboardAvoiding ? (
100
- <AtomicKeyboardAvoidingView style={styles.keyboardAvoidingView}>
101
- {content}
102
- </AtomicKeyboardAvoidingView>
103
- ) : (
104
- <View style={styles.keyboardAvoidingView}>
105
- {content}
106
- </View>
107
- )}
122
+ <View style={[styles.container, { backgroundColor: bgColor }, containerStyle]} testID={testID}>
123
+ <View style={styles.keyboardAvoidingView}>{content}</View>
108
124
  </View>
109
125
  );
110
126
  };
111
127
 
112
- // Re-export types for convenience
113
128
  export type { ScreenLayoutProps } from './types';
@@ -18,6 +18,7 @@ export interface ScreenLayoutProps {
18
18
  readonly testID?: string;
19
19
  readonly hideScrollIndicator?: boolean;
20
20
  readonly keyboardAvoiding?: boolean;
21
+ readonly keyboardVerticalOffset?: number;
21
22
  readonly accessibilityLabel?: string;
22
23
  readonly accessibilityHint?: string;
23
24
  readonly accessible?: boolean;