@umituz/react-native-design-system 4.23.83 → 4.23.84

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 (23) hide show
  1. package/package.json +1 -1
  2. package/src/atoms/input/hooks/useInputState.ts +2 -4
  3. package/src/image/presentation/components/editor/text-editor/TextTransformTab.tsx +40 -152
  4. package/src/image/presentation/components/editor/text-editor/components/TransformButtonRow.tsx +124 -0
  5. package/src/media/domain/utils/FileValidator.ts +156 -0
  6. package/src/media/infrastructure/services/MediaPickerService.ts +18 -57
  7. package/src/media/infrastructure/utils/PermissionManager.ts +92 -0
  8. package/src/media/presentation/hooks/useMedia.ts +5 -4
  9. package/src/molecules/alerts/AlertBanner.tsx +9 -25
  10. package/src/molecules/alerts/AlertInline.tsx +4 -23
  11. package/src/molecules/alerts/AlertModal.tsx +4 -11
  12. package/src/molecules/alerts/AlertToast.tsx +14 -13
  13. package/src/molecules/alerts/utils/alertUtils.ts +133 -0
  14. package/src/molecules/calendar/infrastructure/storage/CalendarStore.ts +65 -25
  15. package/src/molecules/countdown/hooks/useCountdown.ts +13 -5
  16. package/src/molecules/swipe-actions/domain/entities/SwipeAction.ts +15 -123
  17. package/src/molecules/swipe-actions/domain/utils/swipeActionHelpers.ts +109 -0
  18. package/src/molecules/swipe-actions/domain/utils/swipeActionValidator.ts +54 -0
  19. package/src/molecules/swipe-actions/presentation/components/SwipeActionButton.tsx +10 -5
  20. package/src/tanstack/domain/utils/MetricsCalculator.ts +103 -0
  21. package/src/tanstack/infrastructure/monitoring/DevMonitor.ts +35 -29
  22. package/src/timezone/infrastructure/utils/SimpleCache.ts +24 -2
  23. package/src/molecules/alerts/utils/alertToastHelpers.ts +0 -70
@@ -2,7 +2,6 @@
2
2
  * Swipe Actions Domain - Entity Layer
3
3
  *
4
4
  * Core swipe action types and configurations.
5
- * Defines pre-built action types, colors, icons, and utilities.
6
5
  *
7
6
  * @domain swipe-actions
8
7
  * @layer domain/entities
@@ -61,53 +60,6 @@ export interface SwipeableConfig {
61
60
  friction?: number;
62
61
  }
63
62
 
64
- /**
65
- * Pre-built action type configurations
66
- */
67
- export const ACTION_PRESETS: Record<Exclude<SwipeActionType, 'custom'>, {
68
- label: string;
69
- icon: IconName;
70
- colorKey: 'error' | 'success' | 'primary' | 'secondary' | 'warning' | 'textSecondary';
71
- hapticsIntensity: 'Light' | 'Medium' | 'Heavy';
72
- }> = {
73
- delete: {
74
- label: 'Delete',
75
- icon: 'Trash2',
76
- colorKey: 'error',
77
- hapticsIntensity: 'Heavy',
78
- },
79
- archive: {
80
- label: 'Archive',
81
- icon: 'Archive',
82
- colorKey: 'success',
83
- hapticsIntensity: 'Medium',
84
- },
85
- edit: {
86
- label: 'Edit',
87
- icon: 'Pencil',
88
- colorKey: 'primary',
89
- hapticsIntensity: 'Light',
90
- },
91
- share: {
92
- label: 'Share',
93
- icon: 'Share2',
94
- colorKey: 'secondary',
95
- hapticsIntensity: 'Light',
96
- },
97
- favorite: {
98
- label: 'Favorite',
99
- icon: 'Heart',
100
- colorKey: 'warning',
101
- hapticsIntensity: 'Light',
102
- },
103
- more: {
104
- label: 'More',
105
- icon: 'MoveHorizontal',
106
- colorKey: 'textSecondary',
107
- hapticsIntensity: 'Light',
108
- },
109
- };
110
-
111
63
  /**
112
64
  * Default swipe configuration
113
65
  */
@@ -117,78 +69,18 @@ export const DEFAULT_SWIPE_CONFIG: Required<Omit<SwipeableConfig, 'leftActions'
117
69
  friction: 2,
118
70
  };
119
71
 
120
- /**
121
- * Swipe action utility functions
122
- */
123
- export class SwipeActionUtils {
124
- /**
125
- * Gets preset configuration for action type
126
- */
127
- static getPreset(type: SwipeActionType) {
128
- if (type === 'custom') {
129
- return null;
130
- }
131
- return ACTION_PRESETS[type];
132
- }
133
-
134
- /**
135
- * Validates swipe action configuration
136
- */
137
- static validateAction(action: SwipeActionConfig): boolean {
138
- // Must have onPress handler
139
- if (!action.onPress || typeof action.onPress !== 'function') {
140
- return false;
141
- }
142
-
143
- // Custom actions must have label, icon, and color
144
- if (action.type === 'custom') {
145
- return !!(action.label && action.icon && action.color);
146
- }
147
-
148
- return true;
149
- }
150
-
151
- /**
152
- * Gets action display label
153
- */
154
- static getLabel(action: SwipeActionConfig): string {
155
- if (action.label) {
156
- return action.label;
157
- }
158
-
159
- const preset = this.getPreset(action.type);
160
- return preset?.label || 'Action';
161
- }
162
-
163
- /**
164
- * Gets action icon name
165
- */
166
- static getIcon(action: SwipeActionConfig): IconName {
167
- if (action.icon) {
168
- return action.icon;
169
- }
170
-
171
- const preset = this.getPreset(action.type);
172
- return preset?.icon || 'MoveHorizontal';
173
- }
174
-
175
- /**
176
- * Gets action color key for theme
177
- */
178
- static getColorKey(action: SwipeActionConfig): string | null {
179
- if (action.color) {
180
- return null; // Use custom color
181
- }
182
-
183
- const preset = this.getPreset(action.type);
184
- return preset?.colorKey || null;
185
- }
186
-
187
- /**
188
- * Gets haptics intensity for action
189
- */
190
- static getHapticsIntensity(action: SwipeActionConfig): 'Light' | 'Medium' | 'Heavy' {
191
- const preset = this.getPreset(action.type);
192
- return preset?.hapticsIntensity || 'Light';
193
- }
194
- }
72
+ // Re-export utilities for backward compatibility
73
+ export {
74
+ ACTION_PRESETS,
75
+ getPreset,
76
+ getActionLabel,
77
+ getActionIcon,
78
+ getActionColorKey,
79
+ getHapticsIntensity,
80
+ } from '../utils/swipeActionHelpers';
81
+
82
+ export {
83
+ validateSwipeAction,
84
+ validateSwipeActions,
85
+ getValidationError,
86
+ } from '../utils/swipeActionValidator';
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Swipe Action Helpers
3
+ *
4
+ * Helper functions for swipe action styling and behavior.
5
+ */
6
+
7
+ import type { IconName } from '../../../../atoms/icon';
8
+ import type { SwipeActionType } from '../entities/SwipeAction';
9
+
10
+ /**
11
+ * Pre-built action type configurations
12
+ */
13
+ export const ACTION_PRESETS: Record<Exclude<SwipeActionType, 'custom'>, {
14
+ label: string;
15
+ icon: IconName;
16
+ colorKey: 'error' | 'success' | 'primary' | 'secondary' | 'warning' | 'textSecondary';
17
+ hapticsIntensity: 'Light' | 'Medium' | 'Heavy';
18
+ }> = {
19
+ delete: {
20
+ label: 'Delete',
21
+ icon: 'Trash2',
22
+ colorKey: 'error',
23
+ hapticsIntensity: 'Heavy',
24
+ },
25
+ archive: {
26
+ label: 'Archive',
27
+ icon: 'Archive',
28
+ colorKey: 'success',
29
+ hapticsIntensity: 'Medium',
30
+ },
31
+ edit: {
32
+ label: 'Edit',
33
+ icon: 'Pencil',
34
+ colorKey: 'primary',
35
+ hapticsIntensity: 'Light',
36
+ },
37
+ share: {
38
+ label: 'Share',
39
+ icon: 'Share2',
40
+ colorKey: 'secondary',
41
+ hapticsIntensity: 'Light',
42
+ },
43
+ favorite: {
44
+ label: 'Favorite',
45
+ icon: 'Heart',
46
+ colorKey: 'warning',
47
+ hapticsIntensity: 'Light',
48
+ },
49
+ more: {
50
+ label: 'More',
51
+ icon: 'MoveHorizontal',
52
+ colorKey: 'textSecondary',
53
+ hapticsIntensity: 'Light',
54
+ },
55
+ };
56
+
57
+ /**
58
+ * Gets preset configuration for action type
59
+ */
60
+ export function getPreset(type: SwipeActionType) {
61
+ if (type === 'custom') {
62
+ return null;
63
+ }
64
+ return ACTION_PRESETS[type];
65
+ }
66
+
67
+ /**
68
+ * Gets action display label
69
+ */
70
+ export function getActionLabel(action: { type: SwipeActionType; label?: string }): string {
71
+ if (action.label) {
72
+ return action.label;
73
+ }
74
+
75
+ const preset = getPreset(action.type);
76
+ return preset?.label || 'Action';
77
+ }
78
+
79
+ /**
80
+ * Gets action icon name
81
+ */
82
+ export function getActionIcon(action: { type: SwipeActionType; icon?: IconName }): IconName {
83
+ if (action.icon) {
84
+ return action.icon;
85
+ }
86
+
87
+ const preset = getPreset(action.type);
88
+ return preset?.icon || 'MoveHorizontal';
89
+ }
90
+
91
+ /**
92
+ * Gets action color key for theme
93
+ */
94
+ export function getActionColorKey(action: { type: SwipeActionType; color?: string }): string | null {
95
+ if (action.color) {
96
+ return null; // Use custom color
97
+ }
98
+
99
+ const preset = getPreset(action.type);
100
+ return preset?.colorKey || null;
101
+ }
102
+
103
+ /**
104
+ * Gets haptics intensity for action
105
+ */
106
+ export function getHapticsIntensity(action: { type: SwipeActionType; enableHaptics?: boolean }): 'Light' | 'Medium' | 'Heavy' {
107
+ const preset = getPreset(action.type);
108
+ return preset?.hapticsIntensity || 'Light';
109
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Swipe Action Validator
3
+ *
4
+ * Validation functions for swipe action configurations.
5
+ */
6
+
7
+ import type { SwipeActionConfig } from '../entities/SwipeAction';
8
+
9
+ /**
10
+ * Validates swipe action configuration
11
+ */
12
+ export function validateSwipeAction(action: SwipeActionConfig): boolean {
13
+ // Must have onPress handler
14
+ if (!action.onPress || typeof action.onPress !== 'function') {
15
+ return false;
16
+ }
17
+
18
+ // Custom actions must have label, icon, and color
19
+ if (action.type === 'custom') {
20
+ return !!(action.label && action.icon && action.color);
21
+ }
22
+
23
+ return true;
24
+ }
25
+
26
+ /**
27
+ * Validates multiple swipe actions
28
+ */
29
+ export function validateSwipeActions(actions: SwipeActionConfig[]): boolean {
30
+ return actions.every(validateSwipeAction);
31
+ }
32
+
33
+ /**
34
+ * Gets validation error message for an action
35
+ */
36
+ export function getValidationError(action: SwipeActionConfig): string | null {
37
+ if (!action.onPress || typeof action.onPress !== 'function') {
38
+ return 'Action must have an onPress handler';
39
+ }
40
+
41
+ if (action.type === 'custom') {
42
+ if (!action.label) {
43
+ return 'Custom action must have a label';
44
+ }
45
+ if (!action.icon) {
46
+ return 'Custom action must have an icon';
47
+ }
48
+ if (!action.color) {
49
+ return 'Custom action must have a color';
50
+ }
51
+ }
52
+
53
+ return null;
54
+ }
@@ -14,7 +14,12 @@ import { AtomicText, AtomicIcon } from '../../../../atoms';
14
14
  import { useAppDesignTokens } from '../../../../theme/hooks/useAppDesignTokens';
15
15
  import { HapticService } from '../../../../haptics';
16
16
  import type { SwipeActionConfig } from '../../domain/entities/SwipeAction';
17
- import { SwipeActionUtils } from '../../domain/entities/SwipeAction';
17
+ import {
18
+ getActionLabel,
19
+ getActionIcon,
20
+ getActionColorKey,
21
+ getHapticsIntensity,
22
+ } from '../../domain/entities/SwipeAction';
18
23
 
19
24
  /**
20
25
  * SwipeActionButton component props
@@ -58,9 +63,9 @@ export const SwipeActionButton: React.FC<SwipeActionButtonProps> = ({
58
63
  const tokens = useAppDesignTokens();
59
64
 
60
65
  // Get action properties
61
- const label = SwipeActionUtils.getLabel(action);
62
- const iconName = SwipeActionUtils.getIcon(action);
63
- const colorKey = SwipeActionUtils.getColorKey(action);
66
+ const label = getActionLabel(action);
67
+ const iconName = getActionIcon(action);
68
+ const colorKey = getActionColorKey(action);
64
69
  const customColor = action.color;
65
70
  const enableHaptics = action.enableHaptics !== false;
66
71
 
@@ -83,7 +88,7 @@ export const SwipeActionButton: React.FC<SwipeActionButtonProps> = ({
83
88
  const handlePress = async () => {
84
89
  // Trigger haptic feedback
85
90
  if (enableHaptics) {
86
- const intensity = SwipeActionUtils.getHapticsIntensity(action);
91
+ const intensity = getHapticsIntensity(action);
87
92
  await HapticService.impact(intensity);
88
93
  }
89
94
 
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Metrics Calculator
3
+ *
4
+ * Calculates query performance metrics for monitoring.
5
+ */
6
+
7
+ import type { Query } from '@tanstack/react-query';
8
+ import type { QueryMetrics, DevMonitorOptions } from '../../infrastructure/monitoring/DevMonitor.types';
9
+
10
+ /**
11
+ * Metrics calculator for query performance
12
+ */
13
+ export class MetricsCalculator {
14
+ /**
15
+ * Gets unique key string for query
16
+ */
17
+ static getQueryKeyString(queryKey: readonly unknown[]): string {
18
+ return JSON.stringify(queryKey);
19
+ }
20
+
21
+ /**
22
+ * Calculates fetch time for a query
23
+ */
24
+ static calculateFetchTime(query: Query): number {
25
+ return Date.now() - (query.state.dataUpdatedAt ?? Date.now());
26
+ }
27
+
28
+ /**
29
+ * Creates initial metrics for a query
30
+ */
31
+ static createInitialMetrics(query: Query): QueryMetrics {
32
+ return {
33
+ queryKey: query.queryKey,
34
+ fetchCount: 0,
35
+ totalFetchTime: 0,
36
+ averageFetchTime: 0,
37
+ slowFetchCount: 0,
38
+ lastFetchTime: null,
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Updates metrics with new fetch data
44
+ */
45
+ static updateMetrics(
46
+ current: QueryMetrics,
47
+ fetchTime: number
48
+ ): QueryMetrics {
49
+ const newFetchCount = current.fetchCount + 1;
50
+ const newTotalFetchTime = current.totalFetchTime + fetchTime;
51
+
52
+ return {
53
+ ...current,
54
+ fetchCount: newFetchCount,
55
+ totalFetchTime: newTotalFetchTime,
56
+ averageFetchTime: newTotalFetchTime / newFetchCount,
57
+ lastFetchTime: fetchTime,
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Checks if fetch time exceeds slow query threshold
63
+ */
64
+ static isSlowQuery(fetchTime: number, threshold: number): boolean {
65
+ return fetchTime > threshold;
66
+ }
67
+
68
+ /**
69
+ * Increments slow fetch count if query is slow
70
+ */
71
+ static incrementSlowCountIfNeeded(
72
+ metrics: QueryMetrics,
73
+ fetchTime: number,
74
+ threshold: number
75
+ ): QueryMetrics {
76
+ if (this.isSlowQuery(fetchTime, threshold)) {
77
+ return {
78
+ ...metrics,
79
+ slowFetchCount: metrics.slowFetchCount + 1,
80
+ };
81
+ }
82
+ return metrics;
83
+ }
84
+
85
+ /**
86
+ * Calculates complete metrics for a query
87
+ */
88
+ static calculateQueryMetrics(
89
+ query: Query,
90
+ currentMetrics: QueryMetrics | null,
91
+ options: Required<DevMonitorOptions>
92
+ ): QueryMetrics {
93
+ const fetchTime = this.calculateFetchTime(query);
94
+ const baseMetrics = currentMetrics ?? this.createInitialMetrics(query);
95
+ const updatedMetrics = this.updateMetrics(baseMetrics, fetchTime);
96
+
97
+ return this.incrementSlowCountIfNeeded(
98
+ updatedMetrics,
99
+ fetchTime,
100
+ options.slowQueryThreshold
101
+ );
102
+ }
103
+ }
@@ -9,12 +9,14 @@
9
9
  import type { Query, QueryClient } from '@tanstack/react-query';
10
10
  import type { QueryMetrics, CacheStats, DevMonitorOptions } from './DevMonitor.types';
11
11
  import { DevMonitorLogger } from './DevMonitorLogger';
12
+ import { MetricsCalculator } from '../../domain/utils/MetricsCalculator';
12
13
 
13
14
  class DevMonitorClass {
14
15
  private metrics: Map<string, QueryMetrics> = new Map();
15
16
  private queryClient: QueryClient | null = null;
16
17
  private options: Required<DevMonitorOptions>;
17
18
  private statsInterval: ReturnType<typeof setInterval> | null = null;
19
+ private cacheSubscription: (() => void) | null = null;
18
20
  private isEnabled: boolean;
19
21
 
20
22
  constructor(options: DevMonitorOptions = {}) {
@@ -38,37 +40,22 @@ class DevMonitorClass {
38
40
  this.startStatsLogging();
39
41
  }
40
42
 
41
- private getQueryKeyString(queryKey: readonly unknown[]): string {
42
- return JSON.stringify(queryKey);
43
- }
44
-
45
43
  private trackQuery(query: Query): void {
46
44
  if (!this.isEnabled) return;
47
45
 
48
- const queryKeyString = this.getQueryKeyString(query.queryKey);
49
-
50
- if (!this.metrics.has(queryKeyString)) {
51
- this.metrics.set(queryKeyString, {
52
- queryKey: query.queryKey,
53
- fetchCount: 0,
54
- totalFetchTime: 0,
55
- averageFetchTime: 0,
56
- slowFetchCount: 0,
57
- lastFetchTime: null,
58
- });
59
- }
60
-
61
- const metrics = this.metrics.get(queryKeyString)!;
62
- const fetchTime = Date.now() - (query.state.dataUpdatedAt ?? Date.now());
46
+ const queryKeyString = MetricsCalculator.getQueryKeyString(query.queryKey);
47
+ const currentMetrics = this.metrics.get(queryKeyString) ?? null;
48
+ const updatedMetrics = MetricsCalculator.calculateQueryMetrics(
49
+ query,
50
+ currentMetrics,
51
+ this.options
52
+ );
63
53
 
64
- metrics.fetchCount++;
65
- metrics.totalFetchTime += fetchTime;
66
- metrics.averageFetchTime = metrics.totalFetchTime / metrics.fetchCount;
67
- metrics.lastFetchTime = fetchTime;
54
+ this.metrics.set(queryKeyString, updatedMetrics);
68
55
 
69
- if (fetchTime > this.options.slowQueryThreshold) {
70
- metrics.slowFetchCount++;
71
- if (this.options.enableLogging) {
56
+ if (this.options.enableLogging && updatedMetrics.slowFetchCount > 0) {
57
+ const fetchTime = MetricsCalculator.calculateFetchTime(query);
58
+ if (MetricsCalculator.isSlowQuery(fetchTime, this.options.slowQueryThreshold)) {
72
59
  DevMonitorLogger.logSlowQuery(queryKeyString, fetchTime);
73
60
  }
74
61
  }
@@ -80,8 +67,13 @@ class DevMonitorClass {
80
67
  attach(queryClient: QueryClient): void {
81
68
  if (!this.isEnabled) return;
82
69
 
70
+ // Detach from previous client if attached
71
+ if (this.cacheSubscription) {
72
+ this.detach();
73
+ }
74
+
83
75
  this.queryClient = queryClient;
84
- queryClient.getQueryCache().subscribe((event) => {
76
+ this.cacheSubscription = queryClient.getQueryCache().subscribe((event) => {
85
77
  if (event.query) {
86
78
  this.trackQuery(event.query as Query);
87
79
  }
@@ -92,6 +84,20 @@ class DevMonitorClass {
92
84
  }
93
85
  }
94
86
 
87
+ /**
88
+ * Detach monitor from query client
89
+ */
90
+ detach(): void {
91
+ if (!this.isEnabled) return;
92
+
93
+ if (this.cacheSubscription) {
94
+ this.cacheSubscription();
95
+ this.cacheSubscription = null;
96
+ }
97
+
98
+ this.queryClient = null;
99
+ }
100
+
95
101
  /**
96
102
  * Get all query metrics
97
103
  */
@@ -105,7 +111,7 @@ class DevMonitorClass {
105
111
  */
106
112
  getQueryMetrics(queryKey: readonly unknown[]): QueryMetrics | undefined {
107
113
  if (!this.isEnabled) return undefined;
108
- const queryKeyString = this.getQueryKeyString(queryKey);
114
+ const queryKeyString = MetricsCalculator.getQueryKeyString(queryKey);
109
115
  return this.metrics.get(queryKeyString);
110
116
  }
111
117
 
@@ -179,9 +185,9 @@ class DevMonitorClass {
179
185
  */
180
186
  reset(): void {
181
187
  if (!this.isEnabled) return;
188
+ this.detach();
182
189
  this.stopStatsLogging();
183
190
  this.clear();
184
- this.queryClient = null;
185
191
  if (this.options.enableLogging) {
186
192
  DevMonitorLogger.logReset();
187
193
  }
@@ -13,10 +13,22 @@ interface CacheEntry<T> {
13
13
  export class SimpleCache<T> {
14
14
  private cache = new Map<string, CacheEntry<T>>();
15
15
  private defaultTTL: number;
16
+ private cleanupTimeout: ReturnType<typeof setTimeout> | null = null;
16
17
 
17
18
  constructor(defaultTTL: number = 60000) {
18
19
  this.defaultTTL = defaultTTL;
19
- this.cleanup();
20
+ this.scheduleCleanup();
21
+ }
22
+
23
+ /**
24
+ * Destroy the cache and stop cleanup timer
25
+ */
26
+ destroy(): void {
27
+ if (this.cleanupTimeout) {
28
+ clearTimeout(this.cleanupTimeout);
29
+ this.cleanupTimeout = null;
30
+ }
31
+ this.cache.clear();
20
32
  }
21
33
 
22
34
  set(key: string, value: T, ttl?: number): void {
@@ -58,7 +70,17 @@ export class SimpleCache<T> {
58
70
  this.cache.delete(key);
59
71
  }
60
72
  }
73
+ }
74
+
75
+ private scheduleCleanup(): void {
76
+ if (this.cleanupTimeout) {
77
+ clearTimeout(this.cleanupTimeout);
78
+ }
79
+
80
+ this.cleanup();
61
81
 
62
- setTimeout(() => this.cleanup(), 60000);
82
+ this.cleanupTimeout = setTimeout(() => {
83
+ this.scheduleCleanup();
84
+ }, 60000);
63
85
  }
64
86
  }
@@ -1,70 +0,0 @@
1
- /**
2
- * Alert Toast Helper Functions
3
- * Style and color helpers for alert toast component
4
- */
5
-
6
- import { AlertType } from '../AlertTypes';
7
- import type { DesignTokens } from '../../../theme';
8
- import type { StyleProp, ViewStyle } from 'react-native';
9
-
10
- /**
11
- * Gets background color for alert type
12
- *
13
- * @param type - Alert type
14
- * @param tokens - Design tokens
15
- * @returns Background color string
16
- */
17
- export function getAlertBackgroundColor(type: AlertType, tokens: DesignTokens): string {
18
- const colors = {
19
- [AlertType.SUCCESS]: tokens.colors.success,
20
- [AlertType.ERROR]: tokens.colors.error,
21
- [AlertType.WARNING]: tokens.colors.warning,
22
- [AlertType.INFO]: tokens.colors.info,
23
- };
24
- return colors[type] || tokens.colors.backgroundSecondary;
25
- }
26
-
27
- /**
28
- * Gets action button style
29
- *
30
- * @param style - Button style type
31
- * @param tokens - Design tokens
32
- * @returns Style object
33
- */
34
- export function getActionButtonStyle(
35
- style: 'primary' | 'secondary' | 'destructive' | undefined,
36
- tokens: DesignTokens
37
- ): StyleProp<ViewStyle> {
38
- if (style === 'secondary') {
39
- return {
40
- backgroundColor: undefined,
41
- borderWidth: 1,
42
- borderColor: tokens.colors.textInverse,
43
- };
44
- }
45
-
46
- const colors = {
47
- primary: tokens.colors.backgroundPrimary,
48
- destructive: tokens.colors.error,
49
- };
50
- return { backgroundColor: colors[style as keyof typeof colors] || tokens.colors.backgroundSecondary };
51
- }
52
-
53
- /**
54
- * Gets action text color
55
- *
56
- * @param style - Button style type
57
- * @param tokens - Design tokens
58
- * @returns Text color string
59
- */
60
- export function getActionTextColor(
61
- style: 'primary' | 'secondary' | 'destructive' | undefined,
62
- tokens: DesignTokens
63
- ): string {
64
- return style === 'primary' ? tokens.colors.textPrimary : tokens.colors.textInverse;
65
- }
66
-
67
- /**
68
- * Default toast duration in milliseconds
69
- */
70
- export const DEFAULT_TOAST_DURATION = 3000;