@umituz/react-native-design-system 2.9.67 → 2.9.69
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.9.
|
|
3
|
+
"version": "2.9.69",
|
|
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",
|
|
@@ -52,13 +52,17 @@ export const CircularMenu: React.FC<CircularMenuProps> = ({
|
|
|
52
52
|
{ ...actions[0], position: getBottomRowPosition("left") }, // Text to Image (Bottom Left)
|
|
53
53
|
{ ...actions[2], position: getBottomRowPosition("right") }, // Image to Video (Bottom Right)
|
|
54
54
|
];
|
|
55
|
+
} else if (actions.length === 2) {
|
|
56
|
+
// 2 items: place on bottom left and right of close button
|
|
57
|
+
return [
|
|
58
|
+
{ ...actions[0], position: getBottomRowPosition("left") },
|
|
59
|
+
{ ...actions[1], position: getBottomRowPosition("right") },
|
|
60
|
+
];
|
|
55
61
|
} else {
|
|
56
|
-
// Default:
|
|
57
|
-
// This is a fallback if actions change.
|
|
58
|
-
// For now, implementing simple distribute:
|
|
62
|
+
// Default: distribute items - top row first, then bottom
|
|
59
63
|
const topCount = Math.min(actions.length, 2);
|
|
60
64
|
const bottomCount = Math.max(0, actions.length - 2);
|
|
61
|
-
|
|
65
|
+
|
|
62
66
|
const mapped = [];
|
|
63
67
|
// Top row
|
|
64
68
|
for (let i = 0; i < topCount; i++) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* OfflineBanner Component
|
|
3
3
|
*
|
|
4
4
|
* Displays a banner when the device is offline.
|
|
5
|
+
* Respects safe area insets for proper display on all devices.
|
|
5
6
|
* Simple conditional rendering - NO animations per CLAUDE.md
|
|
6
7
|
*
|
|
7
8
|
* @example
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
|
|
23
24
|
import React, { memo } from 'react';
|
|
24
25
|
import { View, StyleSheet, type ViewStyle, type TextStyle } from 'react-native';
|
|
25
|
-
import {
|
|
26
|
+
import { useSafeAreaInsets } from '../../../safe-area';
|
|
27
|
+
import { AtomicText, AtomicIcon } from '../../../atoms';
|
|
26
28
|
|
|
27
29
|
export interface OfflineBannerProps {
|
|
28
30
|
/** Whether the banner is visible */
|
|
@@ -33,53 +35,58 @@ export interface OfflineBannerProps {
|
|
|
33
35
|
backgroundColor?: string;
|
|
34
36
|
/** Text color */
|
|
35
37
|
textColor?: string;
|
|
36
|
-
/** Icon
|
|
37
|
-
|
|
38
|
+
/** Icon name from design system icons */
|
|
39
|
+
iconName?: string;
|
|
38
40
|
/** Position of the banner */
|
|
39
41
|
position?: 'top' | 'bottom';
|
|
40
42
|
/** Custom container style */
|
|
41
43
|
style?: ViewStyle;
|
|
42
44
|
/** Custom text style */
|
|
43
45
|
textStyle?: TextStyle;
|
|
44
|
-
/** Height of the banner */
|
|
45
|
-
height?: number;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const CONTENT_HEIGHT = 44;
|
|
49
|
+
const HORIZONTAL_PADDING = 16;
|
|
50
|
+
const ICON_SIZE = 18;
|
|
49
51
|
|
|
50
52
|
export const OfflineBanner: React.FC<OfflineBannerProps> = memo(({
|
|
51
53
|
visible,
|
|
52
54
|
message = 'No internet connection',
|
|
53
|
-
backgroundColor = '#
|
|
55
|
+
backgroundColor = '#DC2626',
|
|
54
56
|
textColor = '#FFFFFF',
|
|
55
|
-
|
|
57
|
+
iconName = 'wifi-off',
|
|
56
58
|
position = 'top',
|
|
57
59
|
style,
|
|
58
60
|
textStyle,
|
|
59
|
-
height = DEFAULT_HEIGHT,
|
|
60
61
|
}) => {
|
|
61
|
-
|
|
62
|
+
const insets = useSafeAreaInsets();
|
|
63
|
+
|
|
62
64
|
if (!visible) {
|
|
63
65
|
return null;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
const
|
|
68
|
+
const isTop = position === 'top';
|
|
69
|
+
const safeAreaPadding = isTop ? insets.top : insets.bottom;
|
|
67
70
|
|
|
68
71
|
return (
|
|
69
72
|
<View
|
|
70
73
|
style={[
|
|
71
74
|
styles.container,
|
|
72
|
-
|
|
73
|
-
{
|
|
75
|
+
isTop ? styles.positionTop : styles.positionBottom,
|
|
76
|
+
{
|
|
77
|
+
backgroundColor,
|
|
78
|
+
paddingTop: isTop ? safeAreaPadding : 0,
|
|
79
|
+
paddingBottom: isTop ? 0 : safeAreaPadding,
|
|
80
|
+
},
|
|
74
81
|
style,
|
|
75
82
|
]}
|
|
76
83
|
>
|
|
77
84
|
<View style={styles.content}>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
<AtomicIcon
|
|
86
|
+
name={iconName}
|
|
87
|
+
customSize={ICON_SIZE}
|
|
88
|
+
customColor={textColor}
|
|
89
|
+
/>
|
|
83
90
|
<AtomicText
|
|
84
91
|
style={[styles.message, { color: textColor }, textStyle]}
|
|
85
92
|
numberOfLines={1}
|
|
@@ -100,19 +107,22 @@ const styles = StyleSheet.create({
|
|
|
100
107
|
right: 0,
|
|
101
108
|
zIndex: 9999,
|
|
102
109
|
},
|
|
110
|
+
positionTop: {
|
|
111
|
+
top: 0,
|
|
112
|
+
},
|
|
113
|
+
positionBottom: {
|
|
114
|
+
bottom: 0,
|
|
115
|
+
},
|
|
103
116
|
content: {
|
|
104
|
-
|
|
117
|
+
height: CONTENT_HEIGHT,
|
|
105
118
|
flexDirection: 'row',
|
|
106
119
|
alignItems: 'center',
|
|
107
120
|
justifyContent: 'center',
|
|
108
|
-
paddingHorizontal:
|
|
121
|
+
paddingHorizontal: HORIZONTAL_PADDING,
|
|
109
122
|
gap: 8,
|
|
110
123
|
},
|
|
111
|
-
icon: {
|
|
112
|
-
fontSize: 16,
|
|
113
|
-
},
|
|
114
124
|
message: {
|
|
115
125
|
fontSize: 14,
|
|
116
|
-
fontWeight: '
|
|
126
|
+
fontWeight: '600',
|
|
117
127
|
},
|
|
118
128
|
});
|