@umituz/react-native-design-system 2.6.62 → 2.6.65

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 (49) hide show
  1. package/package.json +1 -1
  2. package/src/atoms/AtomicIcon.tsx +2 -6
  3. package/src/atoms/AtomicIcon.types.ts +5 -0
  4. package/src/atoms/AtomicInput.tsx +34 -154
  5. package/src/atoms/AtomicPicker.tsx +31 -123
  6. package/src/atoms/index.ts +6 -4
  7. package/src/atoms/input/components/InputHelper.tsx +49 -0
  8. package/src/atoms/input/components/InputIcon.tsx +44 -0
  9. package/src/atoms/input/components/InputLabel.tsx +20 -0
  10. package/src/atoms/input/styles/inputStylesHelper.ts +1 -1
  11. package/src/atoms/input/types.ts +72 -0
  12. package/src/atoms/picker/hooks/usePickerState.ts +139 -0
  13. package/src/exports/atoms.ts +69 -0
  14. package/src/exports/device.ts +58 -0
  15. package/src/exports/layouts.ts +19 -0
  16. package/src/exports/molecules.ts +166 -0
  17. package/src/exports/organisms.ts +9 -0
  18. package/src/exports/responsive.ts +36 -0
  19. package/src/exports/safe-area.ts +6 -0
  20. package/src/exports/theme.ts +47 -0
  21. package/src/exports/typography.ts +22 -0
  22. package/src/exports/utilities.ts +6 -0
  23. package/src/exports/variants.ts +22 -0
  24. package/src/index.ts +11 -417
  25. package/src/molecules/avatar/Avatar.constants.ts +103 -0
  26. package/src/molecules/avatar/Avatar.types.ts +64 -0
  27. package/src/molecules/avatar/Avatar.utils.ts +8 -160
  28. package/src/molecules/calendar/index.ts +4 -9
  29. package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +101 -301
  30. package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts.bak +116 -0
  31. package/src/molecules/calendar/infrastructure/storage/CalendarStore.types.ts +64 -0
  32. package/src/molecules/calendar/infrastructure/storage/CalendarStore.utils.ts +56 -0
  33. package/src/molecules/calendar/infrastructure/storage/EventActions.ts +140 -0
  34. package/src/molecules/calendar/infrastructure/storage/NavigationActions.ts +118 -0
  35. package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +34 -0
  36. package/src/molecules/calendar/infrastructure/stores/useCalendarEvents.ts +168 -0
  37. package/src/molecules/calendar/infrastructure/stores/useCalendarNavigation.ts +47 -0
  38. package/src/molecules/calendar/infrastructure/stores/useCalendarView.ts +24 -0
  39. package/src/molecules/calendar/presentation/hooks/useCalendar.ts +7 -11
  40. package/src/responsive/compute/computeDeviceInfo.ts +22 -0
  41. package/src/responsive/compute/computeResponsivePositioning.ts +42 -0
  42. package/src/responsive/compute/computeResponsiveSizes.ts +48 -0
  43. package/src/responsive/padding/paddingUtils.ts +65 -0
  44. package/src/responsive/positioning/positioningUtils.ts +61 -0
  45. package/src/responsive/responsiveLayout.ts +11 -264
  46. package/src/responsive/screen/screenLayoutConfig.ts +38 -0
  47. package/src/responsive/tabbar/tabBarConfig.ts +88 -0
  48. package/src/responsive/types/responsiveTypes.ts +69 -0
  49. package/src/responsive/useResponsive.ts +69 -158
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Calendar Navigation Store
3
+ * Manages date navigation state (no persistence needed)
4
+ */
5
+
6
+ import { create } from 'zustand';
7
+
8
+ interface CalendarNavigationState {
9
+ readonly selectedDate: Date;
10
+ readonly currentMonth: Date;
11
+ }
12
+
13
+ interface CalendarNavigationActions {
14
+ readonly setSelectedDate: (date: Date) => void;
15
+ readonly goToToday: () => void;
16
+ readonly navigateMonth: (direction: 'prev' | 'next') => void;
17
+ readonly setCurrentMonth: (date: Date) => void;
18
+ }
19
+
20
+ type CalendarNavigationStore = CalendarNavigationState & CalendarNavigationActions;
21
+
22
+ export const useCalendarNavigation = create<CalendarNavigationStore>()((set) => ({
23
+ selectedDate: new Date(),
24
+ currentMonth: new Date(new Date().getFullYear(), new Date().getMonth(), 1),
25
+
26
+ setSelectedDate: (date) => set({ selectedDate: date }),
27
+
28
+ goToToday: () => {
29
+ const today = new Date();
30
+ set({
31
+ selectedDate: today,
32
+ currentMonth: new Date(today.getFullYear(), today.getMonth(), 1),
33
+ });
34
+ },
35
+
36
+ navigateMonth: (direction) => {
37
+ set((state) => {
38
+ const { currentMonth } = state;
39
+ const newMonth = direction === 'next' ? currentMonth.getMonth() + 1 : currentMonth.getMonth() - 1;
40
+ return {
41
+ currentMonth: new Date(currentMonth.getFullYear(), newMonth, 1),
42
+ };
43
+ });
44
+ },
45
+
46
+ setCurrentMonth: (date) => set({ currentMonth: new Date(date.getFullYear(), date.getMonth(), 1) }),
47
+ }));
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Calendar View Store
3
+ * Manages calendar view mode (no persistence needed)
4
+ */
5
+
6
+ import { create } from 'zustand';
7
+
8
+ export type CalendarViewMode = 'month' | 'week' | 'day' | 'list';
9
+
10
+ interface CalendarViewState {
11
+ readonly viewMode: CalendarViewMode;
12
+ }
13
+
14
+ interface CalendarViewActions {
15
+ readonly setViewMode: (mode: CalendarViewMode) => void;
16
+ }
17
+
18
+ type CalendarViewStore = CalendarViewState & CalendarViewActions;
19
+
20
+ export const useCalendarView = create<CalendarViewStore>()((set) => ({
21
+ viewMode: 'month',
22
+
23
+ setViewMode: (mode) => set({ viewMode: mode }),
24
+ }));
@@ -28,7 +28,6 @@
28
28
 
29
29
  import { useMemo, useEffect } from 'react';
30
30
  import { useCalendarStore, type CalendarViewMode } from '../../infrastructure/storage/CalendarStore';
31
- import { CalendarService } from '../../infrastructure/services/CalendarService';
32
31
  import type { CalendarDay } from '../../domain/entities/CalendarDay.entity';
33
32
  import type { CalendarEvent } from '../../domain/entities/CalendarEvent.entity';
34
33
 
@@ -62,7 +61,6 @@ export interface UseCalendarReturn {
62
61
  setSelectedDate: (date: Date) => void;
63
62
  goToToday: () => void;
64
63
  navigateMonth: (direction: 'prev' | 'next') => void;
65
- navigateWeek: (direction: 'prev' | 'next') => void;
66
64
  setCurrentMonth: (date: Date) => void;
67
65
  setViewMode: (mode: CalendarViewMode) => void;
68
66
  getEventsForDate: (date: Date) => CalendarEvent[];
@@ -75,7 +73,7 @@ export interface UseCalendarReturn {
75
73
  /**
76
74
  * Main calendar hook
77
75
  */
78
- export const useCalendar = (): UseCalendarReturn => {
76
+ export const useCalendarPresentation = (): UseCalendarReturn => {
79
77
  const store = useCalendarStore();
80
78
  const {
81
79
  events,
@@ -92,13 +90,6 @@ export const useCalendar = (): UseCalendarReturn => {
92
90
  actions.loadEvents();
93
91
  }, []);
94
92
 
95
- // Generate calendar days for current month
96
- const days = useMemo(() => {
97
- const year = currentMonth.getFullYear();
98
- const month = currentMonth.getMonth();
99
- return CalendarService.getMonthDays(year, month, events);
100
- }, [currentMonth, events]);
101
-
102
93
  // Get events for selected date
103
94
  const selectedDateEvents = useMemo(() => {
104
95
  return actions.getEventsForDate(selectedDate);
@@ -112,7 +103,7 @@ export const useCalendar = (): UseCalendarReturn => {
112
103
  }, [currentMonth, events]);
113
104
 
114
105
  return {
115
- days,
106
+ days: store.days,
116
107
  events,
117
108
  selectedDate,
118
109
  currentMonth,
@@ -181,3 +172,8 @@ export const useCalendarEvents = () => {
181
172
  clearError,
182
173
  };
183
174
  };
175
+
176
+ // Re-export for convenience
177
+ export { useCalendar, useCalendarStore } from '../../infrastructure/storage/CalendarStore';
178
+ export type { CalendarViewMode } from '../../infrastructure/storage/CalendarStore';
179
+
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Device Info Computation
3
+ */
4
+
5
+ import { isSmallPhone, isTablet, isLandscape, getDeviceType, getSpacingMultiplier } from '../../device/detection';
6
+ import type { DeviceType } from '../../device/detection';
7
+
8
+ export interface ComputedDeviceInfo {
9
+ readonly isSmallDevice: boolean;
10
+ readonly isTabletDevice: boolean;
11
+ readonly isLandscapeDevice: boolean;
12
+ readonly deviceType: DeviceType;
13
+ readonly spacingMultiplier: number;
14
+ }
15
+
16
+ export const computeDeviceInfo = (): ComputedDeviceInfo => ({
17
+ isSmallDevice: isSmallPhone(),
18
+ isTabletDevice: isTablet(),
19
+ isLandscapeDevice: isLandscape(),
20
+ deviceType: getDeviceType(),
21
+ spacingMultiplier: getSpacingMultiplier(),
22
+ });
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Responsive Positioning Computation
3
+ */
4
+
5
+ import {
6
+ getResponsiveHorizontalPadding,
7
+ getResponsiveVerticalPadding,
8
+ getResponsiveBottomPosition,
9
+ getResponsiveFABPosition,
10
+ getScreenLayoutConfig,
11
+ getResponsiveTabBarConfig,
12
+ getResponsiveModalLayout,
13
+ getResponsiveBottomSheetLayout,
14
+ getResponsiveDialogLayout,
15
+ } from '../responsive';
16
+ import type { ResponsiveModalLayout, ResponsiveBottomSheetLayout, ResponsiveDialogLayout, ResponsiveTabBarConfig, ScreenLayoutConfig } from '../responsive';
17
+
18
+ export interface ComputedResponsivePositioning {
19
+ readonly horizontalPadding: number;
20
+ readonly verticalPadding: number;
21
+ readonly bottomPosition: number;
22
+ readonly fabPosition: { readonly bottom: number; readonly right: number };
23
+ readonly screenLayoutConfig: ScreenLayoutConfig;
24
+ readonly tabBarConfig: ResponsiveTabBarConfig;
25
+ readonly modalLayout: ResponsiveModalLayout;
26
+ readonly bottomSheetLayout: ResponsiveBottomSheetLayout;
27
+ readonly dialogLayout: ResponsiveDialogLayout;
28
+ }
29
+
30
+ export const computeResponsivePositioning = (
31
+ insets: { top: number; bottom: number; left: number; right: number }
32
+ ): ComputedResponsivePositioning => ({
33
+ horizontalPadding: getResponsiveHorizontalPadding(undefined, insets),
34
+ verticalPadding: getResponsiveVerticalPadding(insets),
35
+ bottomPosition: getResponsiveBottomPosition(undefined, insets),
36
+ fabPosition: getResponsiveFABPosition(insets),
37
+ screenLayoutConfig: getScreenLayoutConfig(insets),
38
+ tabBarConfig: getResponsiveTabBarConfig(insets),
39
+ modalLayout: getResponsiveModalLayout(),
40
+ bottomSheetLayout: getResponsiveBottomSheetLayout(),
41
+ dialogLayout: getResponsiveDialogLayout(),
42
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Responsive Sizes Computation
3
+ */
4
+
5
+ import {
6
+ getResponsiveLogoSize,
7
+ getResponsiveInputHeight,
8
+ getResponsiveIconContainerSize,
9
+ getResponsiveMaxWidth,
10
+ getResponsiveModalMaxHeight,
11
+ getResponsiveMinModalHeight,
12
+ getResponsiveGridColumns,
13
+ } from '../responsive';
14
+ import { getMinTouchTarget } from '../platformConstants';
15
+ import type { ComputedDeviceInfo } from './computeDeviceInfo';
16
+
17
+ export interface ComputedResponsiveSizes {
18
+ readonly logoSize: number;
19
+ readonly inputHeight: number;
20
+ readonly iconContainerSize: number;
21
+ readonly maxContentWidth: number;
22
+ readonly minTouchTarget: number;
23
+ readonly modalMaxHeight: string;
24
+ readonly modalMinHeight: number;
25
+ readonly gridColumns: number;
26
+ }
27
+
28
+ export const computeResponsiveSizes = (): ComputedResponsiveSizes => ({
29
+ logoSize: getResponsiveLogoSize(),
30
+ inputHeight: getResponsiveInputHeight(),
31
+ iconContainerSize: getResponsiveIconContainerSize(),
32
+ maxContentWidth: getResponsiveMaxWidth(),
33
+ minTouchTarget: getMinTouchTarget(),
34
+ modalMaxHeight: getResponsiveModalMaxHeight(),
35
+ modalMinHeight: getResponsiveMinModalHeight(),
36
+ gridColumns: getResponsiveGridColumns(),
37
+ });
38
+
39
+ export const computeOnboardingSizes = (
40
+ deviceInfo: ComputedDeviceInfo
41
+ ) => ({
42
+ onboardingIconSize: getResponsiveIconContainerSize(64),
43
+ onboardingIconMarginTop: deviceInfo.spacingMultiplier * 24,
44
+ onboardingIconMarginBottom: deviceInfo.spacingMultiplier * 16,
45
+ onboardingTitleMarginBottom: deviceInfo.spacingMultiplier * 16,
46
+ onboardingDescriptionMarginTop: deviceInfo.spacingMultiplier * 12,
47
+ onboardingTextPadding: deviceInfo.spacingMultiplier * 20,
48
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Padding Utilities
3
+ */
4
+
5
+ import { isTablet, isSmallPhone, getSpacingMultiplier } from '../../device/detection';
6
+ import { LAYOUT_CONSTANTS } from '../config';
7
+ import { validateNumber, validateSafeAreaInsets } from '../validation';
8
+
9
+ export const getResponsiveVerticalPadding = (
10
+ insets: { top?: number; bottom?: number } = { top: 0, bottom: 0 }
11
+ ): number => {
12
+ try {
13
+ validateSafeAreaInsets(insets);
14
+ const { top = 0 } = insets;
15
+ const isTabletDevice = isTablet();
16
+ const isSmall = isSmallPhone();
17
+ const spacingMultiplier = getSpacingMultiplier();
18
+
19
+ // Base padding adjusted by device type
20
+ let basePadding: number = LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
21
+ if (isTabletDevice) {
22
+ basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_TABLET;
23
+ } else if (isSmall) {
24
+ basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_SMALL;
25
+ }
26
+
27
+ // Apply spacing multiplier for consistency
28
+ const adjustedPadding = basePadding * spacingMultiplier;
29
+
30
+ // Ensure minimum padding respects safe area
31
+ return Math.max(adjustedPadding, top > 0 ? 8 : adjustedPadding);
32
+ } catch {
33
+ return LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
34
+ }
35
+ };
36
+
37
+ export const getResponsiveHorizontalPadding = (
38
+ basePadding: number = LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
39
+ insets: { left?: number; right?: number } = { left: 0, right: 0 }
40
+ ): number => {
41
+ try {
42
+ const validatedBasePadding = validateNumber(basePadding, 'basePadding', 0, 100);
43
+ validateSafeAreaInsets(insets);
44
+
45
+ const { left = 0, right = 0 } = insets;
46
+ const isTabletDevice = isTablet();
47
+
48
+ if (isTabletDevice) {
49
+ const tabletPadding = validatedBasePadding * LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
50
+ return Math.max(
51
+ tabletPadding,
52
+ left + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
53
+ right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
54
+ );
55
+ }
56
+
57
+ return Math.max(
58
+ validatedBasePadding,
59
+ left + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET,
60
+ right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
61
+ );
62
+ } catch {
63
+ return 16;
64
+ }
65
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Positioning Utilities
3
+ */
4
+
5
+ import { isTablet } from '../../device/detection';
6
+ import { LAYOUT_CONSTANTS } from '../config';
7
+ import { validateNumber, validateSafeAreaInsets } from '../validation';
8
+
9
+ export const getResponsiveBottomPosition = (
10
+ basePosition: number = LAYOUT_CONSTANTS.BOTTOM_POSITION_BASE,
11
+ insets: { bottom?: number } = { bottom: 0 }
12
+ ): number => {
13
+ try {
14
+ const validatedBasePosition = validateNumber(basePosition, 'basePosition', 0, 500);
15
+ validateSafeAreaInsets(insets);
16
+
17
+ const { bottom = 0 } = insets;
18
+ return Math.max(validatedBasePosition, bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET);
19
+ } catch {
20
+ return 32;
21
+ }
22
+ };
23
+
24
+ export const getResponsiveFABPosition = (
25
+ insets: { bottom?: number; right?: number } = { bottom: 0, right: 0 }
26
+ ): { bottom: number; right: number } => {
27
+ try {
28
+ validateSafeAreaInsets(insets);
29
+ const { bottom = 0, right = 0 } = insets;
30
+ const isTabletDevice = isTablet();
31
+
32
+ if (isTabletDevice) {
33
+ return {
34
+ bottom: Math.max(
35
+ LAYOUT_CONSTANTS.FAB_BOTTOM_TABLET,
36
+ bottom + LAYOUT_CONSTANTS.TAB_BAR_OFFSET
37
+ ),
38
+ right: Math.max(
39
+ LAYOUT_CONSTANTS.FAB_RIGHT_TABLET,
40
+ right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
41
+ ),
42
+ };
43
+ }
44
+
45
+ return {
46
+ bottom: Math.max(
47
+ LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
48
+ bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
49
+ ),
50
+ right: Math.max(
51
+ LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
52
+ right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
53
+ ),
54
+ };
55
+ } catch {
56
+ return {
57
+ bottom: LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
58
+ right: LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
59
+ };
60
+ }
61
+ };
@@ -1,270 +1,17 @@
1
1
  /**
2
- * Responsive Layout Utilities
3
- * Layout utilities for positioning and spacing.
2
+ * Responsive Layout Utilities - Barrel Export
4
3
  */
5
4
 
6
- import { isTablet, isSmallPhone, getSpacingMultiplier } from '../device/detection';
7
- import { LAYOUT_CONSTANTS, SIZE_CONSTRAINTS } from './config';
8
- import { validateNumber, validateSafeAreaInsets } from './validation';
5
+ // Screen layout
6
+ export { getScreenLayoutConfig } from './screen/screenLayoutConfig';
7
+ export type { ScreenLayoutConfig } from './screen/screenLayoutConfig';
9
8
 
10
- /**
11
- * Check if device is tablet-sized (for responsive layouts)
12
- * Uses expo-device based detection for accuracy
13
- */
14
- const checkIsTabletSize = (): boolean => isTablet();
15
-
16
- /**
17
- * Screen layout configuration for ScreenLayout component
18
- */
19
- export interface ScreenLayoutConfig {
20
- maxContentWidth: number | undefined;
21
- horizontalPadding: number;
22
- verticalPadding: number;
23
- spacingMultiplier: number;
24
- }
25
-
26
- /**
27
- * Get complete screen layout configuration
28
- * Returns all responsive values needed for ScreenLayout
29
- */
30
- export const getScreenLayoutConfig = (
31
- insets: { left?: number; right?: number; top?: number; bottom?: number } = {}
32
- ): ScreenLayoutConfig => {
33
- try {
34
- const isTabletDevice = checkIsTabletSize();
35
- const spacingMultiplier = getSpacingMultiplier();
36
-
37
- return {
38
- maxContentWidth: isTabletDevice ? SIZE_CONSTRAINTS.CONTENT_MAX_TABLET : undefined,
39
- horizontalPadding: getResponsiveHorizontalPadding(LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE, insets),
40
- verticalPadding: getResponsiveVerticalPadding(insets),
41
- spacingMultiplier,
42
- };
43
- } catch {
44
- return {
45
- maxContentWidth: undefined,
46
- horizontalPadding: LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
47
- verticalPadding: LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD,
48
- spacingMultiplier: LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD,
49
- };
50
- }
51
- };
52
-
53
- /**
54
- * Responsive vertical padding
55
- * Adjusts based on device type and safe area insets
56
- */
57
- export const getResponsiveVerticalPadding = (
58
- insets: { top?: number; bottom?: number } = { top: 0, bottom: 0 }
59
- ): number => {
60
- try {
61
- validateSafeAreaInsets(insets);
62
- const { top = 0 } = insets;
63
- const isTabletDevice = checkIsTabletSize();
64
- const isSmall = isSmallPhone();
65
- const spacingMultiplier = getSpacingMultiplier();
66
-
67
- // Base padding adjusted by device type
68
- let basePadding: number = LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
69
- if (isTabletDevice) {
70
- basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_TABLET;
71
- } else if (isSmall) {
72
- basePadding = LAYOUT_CONSTANTS.VERTICAL_PADDING_SMALL;
73
- }
74
-
75
- // Apply spacing multiplier for consistency
76
- const adjustedPadding = basePadding * spacingMultiplier;
77
-
78
- // Ensure minimum padding respects safe area
79
- return Math.max(adjustedPadding, top > 0 ? 8 : adjustedPadding);
80
- } catch {
81
- return LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD;
82
- }
83
- };
84
-
85
- /**
86
- * Responsive horizontal padding
87
- */
88
- export const getResponsiveHorizontalPadding = (
89
- basePadding: number = LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
90
- insets: { left?: number; right?: number } = { left: 0, right: 0 }
91
- ): number => {
92
- try {
93
- const validatedBasePadding = validateNumber(basePadding, 'basePadding', 0, 100);
94
- validateSafeAreaInsets(insets);
95
-
96
- const { left = 0, right = 0 } = insets;
97
- const isTabletDevice = checkIsTabletSize();
98
-
99
- if (isTabletDevice) {
100
- const tabletPadding = validatedBasePadding * LAYOUT_CONSTANTS.SPACING_MULTIPLIER_TABLET;
101
- return Math.max(
102
- tabletPadding,
103
- left + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
104
- right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
105
- );
106
- }
107
-
108
- return Math.max(
109
- validatedBasePadding,
110
- left + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET,
111
- right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
112
- );
113
- } catch {
114
- return 16;
115
- }
116
- };
117
-
118
- /**
119
- * Responsive bottom positioning
120
- */
121
- export const getResponsiveBottomPosition = (
122
- basePosition: number = LAYOUT_CONSTANTS.BOTTOM_POSITION_BASE,
123
- insets: { bottom?: number } = { bottom: 0 }
124
- ): number => {
125
- try {
126
- const validatedBasePosition = validateNumber(basePosition, 'basePosition', 0, 500);
127
- validateSafeAreaInsets(insets);
128
-
129
- const { bottom = 0 } = insets;
130
- return Math.max(validatedBasePosition, bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET);
131
- } catch {
132
- return 32;
133
- }
134
- };
135
-
136
- /**
137
- * Responsive FAB position
138
- */
139
- export const getResponsiveFABPosition = (
140
- insets: { bottom?: number; right?: number } = { bottom: 0, right: 0 }
141
- ): { bottom: number; right: number } => {
142
- try {
143
- validateSafeAreaInsets(insets);
144
- const { bottom = 0, right = 0 } = insets;
145
- const isTabletDevice = checkIsTabletSize();
146
-
147
- if (isTabletDevice) {
148
- return {
149
- bottom: Math.max(
150
- LAYOUT_CONSTANTS.FAB_BOTTOM_TABLET,
151
- bottom + LAYOUT_CONSTANTS.TAB_BAR_OFFSET
152
- ),
153
- right: Math.max(
154
- LAYOUT_CONSTANTS.FAB_RIGHT_TABLET,
155
- right + LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE
156
- ),
157
- };
158
- }
159
-
160
- return {
161
- bottom: Math.max(
162
- LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
163
- bottom + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
164
- ),
165
- right: Math.max(
166
- LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
167
- right + LAYOUT_CONSTANTS.SAFE_AREA_OFFSET
168
- ),
169
- };
170
- } catch {
171
- return {
172
- bottom: LAYOUT_CONSTANTS.TAB_BAR_OFFSET,
173
- right: LAYOUT_CONSTANTS.FAB_RIGHT_PHONE,
174
- };
175
- }
176
- };
177
-
178
- /**
179
- * Tab bar height constants
180
- */
181
- const TAB_BAR_CONSTANTS = {
182
- BASE_HEIGHT_PHONE: 60,
183
- BASE_HEIGHT_TABLET: 70,
184
- MIN_PADDING_BOTTOM: 8,
185
- MIN_PADDING_TOP: 8,
186
- ICON_SIZE_PHONE: 24,
187
- ICON_SIZE_TABLET: 28,
188
- FAB_SIZE_PHONE: 64,
189
- FAB_SIZE_TABLET: 72,
190
- FAB_OFFSET_Y_PHONE: -24,
191
- FAB_OFFSET_Y_TABLET: -28,
192
- } as const;
193
-
194
- /**
195
- * Responsive tab bar configuration
196
- */
197
- export interface ResponsiveTabBarConfig {
198
- height: number;
199
- paddingBottom: number;
200
- paddingTop: number;
201
- iconSize: number;
202
- fabSize: number;
203
- fabOffsetY: number;
204
- }
205
-
206
- /**
207
- * Get responsive tab bar height based on device and safe area
208
- */
209
- export const getResponsiveTabBarHeight = (
210
- insets: { bottom?: number } = { bottom: 0 }
211
- ): number => {
212
- try {
213
- validateSafeAreaInsets(insets);
214
- const { bottom = 0 } = insets;
215
- const isTabletDevice = checkIsTabletSize();
216
-
217
- const baseHeight = isTabletDevice
218
- ? TAB_BAR_CONSTANTS.BASE_HEIGHT_TABLET
219
- : TAB_BAR_CONSTANTS.BASE_HEIGHT_PHONE;
220
-
221
- const bottomPadding = Math.max(bottom, TAB_BAR_CONSTANTS.MIN_PADDING_BOTTOM);
222
-
223
- return baseHeight + bottomPadding;
224
- } catch {
225
- return TAB_BAR_CONSTANTS.BASE_HEIGHT_PHONE + TAB_BAR_CONSTANTS.MIN_PADDING_BOTTOM;
226
- }
227
- };
228
-
229
- /**
230
- * Get complete responsive tab bar configuration
231
- */
232
- export const getResponsiveTabBarConfig = (
233
- insets: { bottom?: number } = { bottom: 0 }
234
- ): ResponsiveTabBarConfig => {
235
- try {
236
- validateSafeAreaInsets(insets);
237
- const { bottom = 0 } = insets;
238
- const isTabletSize = checkIsTabletSize();
239
-
240
- const baseHeight = isTabletSize
241
- ? TAB_BAR_CONSTANTS.BASE_HEIGHT_TABLET
242
- : TAB_BAR_CONSTANTS.BASE_HEIGHT_PHONE;
9
+ // Padding utilities
10
+ export { getResponsiveVerticalPadding, getResponsiveHorizontalPadding } from './padding/paddingUtils';
243
11
 
244
- const paddingBottom = Math.max(bottom, TAB_BAR_CONSTANTS.MIN_PADDING_BOTTOM);
12
+ // Positioning utilities
13
+ export { getResponsiveBottomPosition, getResponsiveFABPosition } from './positioning/positioningUtils';
245
14
 
246
- return {
247
- height: baseHeight + paddingBottom,
248
- paddingBottom,
249
- paddingTop: TAB_BAR_CONSTANTS.MIN_PADDING_TOP,
250
- iconSize: isTabletSize
251
- ? TAB_BAR_CONSTANTS.ICON_SIZE_TABLET
252
- : TAB_BAR_CONSTANTS.ICON_SIZE_PHONE,
253
- fabSize: isTabletSize
254
- ? TAB_BAR_CONSTANTS.FAB_SIZE_TABLET
255
- : TAB_BAR_CONSTANTS.FAB_SIZE_PHONE,
256
- fabOffsetY: isTabletSize
257
- ? TAB_BAR_CONSTANTS.FAB_OFFSET_Y_TABLET
258
- : TAB_BAR_CONSTANTS.FAB_OFFSET_Y_PHONE,
259
- };
260
- } catch {
261
- return {
262
- height: TAB_BAR_CONSTANTS.BASE_HEIGHT_PHONE + TAB_BAR_CONSTANTS.MIN_PADDING_BOTTOM,
263
- paddingBottom: TAB_BAR_CONSTANTS.MIN_PADDING_BOTTOM,
264
- paddingTop: TAB_BAR_CONSTANTS.MIN_PADDING_TOP,
265
- iconSize: TAB_BAR_CONSTANTS.ICON_SIZE_PHONE,
266
- fabSize: TAB_BAR_CONSTANTS.FAB_SIZE_PHONE,
267
- fabOffsetY: TAB_BAR_CONSTANTS.FAB_OFFSET_Y_PHONE,
268
- };
269
- }
270
- };
15
+ // Tab bar configuration
16
+ export { getResponsiveTabBarHeight, getResponsiveTabBarConfig } from './tabbar/tabBarConfig';
17
+ export type { ResponsiveTabBarConfig } from './tabbar/tabBarConfig';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Screen Layout Configuration
3
+ */
4
+
5
+ import { isTablet, getSpacingMultiplier } from '../../device/detection';
6
+ import { LAYOUT_CONSTANTS, SIZE_CONSTRAINTS } from '../config';
7
+ import { getResponsiveHorizontalPadding } from '../padding/paddingUtils';
8
+ import { getResponsiveVerticalPadding } from '../padding/paddingUtils';
9
+
10
+ export interface ScreenLayoutConfig {
11
+ readonly maxContentWidth: number | undefined;
12
+ readonly horizontalPadding: number;
13
+ readonly verticalPadding: number;
14
+ readonly spacingMultiplier: number;
15
+ }
16
+
17
+ export const getScreenLayoutConfig = (
18
+ insets: { left?: number; right?: number; top?: number; bottom?: number } = {}
19
+ ): ScreenLayoutConfig => {
20
+ try {
21
+ const isTabletDevice = isTablet();
22
+ const spacingMultiplier = getSpacingMultiplier();
23
+
24
+ return {
25
+ maxContentWidth: isTabletDevice ? SIZE_CONSTRAINTS.CONTENT_MAX_TABLET : undefined,
26
+ horizontalPadding: getResponsiveHorizontalPadding(LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE, insets),
27
+ verticalPadding: getResponsiveVerticalPadding(insets),
28
+ spacingMultiplier,
29
+ };
30
+ } catch {
31
+ return {
32
+ maxContentWidth: undefined,
33
+ horizontalPadding: LAYOUT_CONSTANTS.HORIZONTAL_PADDING_BASE,
34
+ verticalPadding: LAYOUT_CONSTANTS.VERTICAL_PADDING_STANDARD,
35
+ spacingMultiplier: LAYOUT_CONSTANTS.SPACING_MULTIPLIER_STANDARD,
36
+ };
37
+ }
38
+ };