@umituz/react-native-design-system 1.15.0 → 2.0.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.
Files changed (87) hide show
  1. package/package.json +26 -19
  2. package/src/atoms/AtomicAvatar.tsx +161 -0
  3. package/src/atoms/AtomicButton.tsx +241 -0
  4. package/src/atoms/AtomicChip.tsx +226 -0
  5. package/src/atoms/AtomicDatePicker.tsx +255 -0
  6. package/src/atoms/AtomicFab.tsx +99 -0
  7. package/src/atoms/AtomicIcon.tsx +149 -0
  8. package/src/atoms/AtomicInput.tsx +308 -0
  9. package/src/atoms/AtomicPicker.tsx +310 -0
  10. package/src/atoms/AtomicProgress.tsx +149 -0
  11. package/src/atoms/AtomicText.tsx +55 -0
  12. package/src/atoms/__tests__/AtomicButton.test.tsx +107 -0
  13. package/src/atoms/__tests__/AtomicIcon.test.tsx +110 -0
  14. package/src/atoms/__tests__/AtomicInput.test.tsx +195 -0
  15. package/src/atoms/datepicker/components/DatePickerButton.tsx +112 -0
  16. package/src/atoms/datepicker/components/DatePickerModal.tsx +143 -0
  17. package/src/atoms/fab/styles/fabStyles.ts +98 -0
  18. package/src/atoms/fab/types/index.ts +88 -0
  19. package/src/atoms/index.ts +70 -0
  20. package/src/atoms/input/hooks/useInputState.ts +63 -0
  21. package/src/atoms/input/styles/inputStylesHelper.ts +120 -0
  22. package/src/atoms/picker/components/PickerChips.tsx +57 -0
  23. package/src/atoms/picker/components/PickerModal.tsx +214 -0
  24. package/src/atoms/picker/styles/pickerStyles.ts +223 -0
  25. package/src/atoms/picker/types/index.ts +42 -0
  26. package/src/index.ts +133 -56
  27. package/src/molecules/ConfirmationModal.tsx +42 -0
  28. package/src/molecules/ConfirmationModalContent.tsx +87 -0
  29. package/src/molecules/ConfirmationModalMain.tsx +91 -0
  30. package/src/molecules/FormField.tsx +155 -0
  31. package/src/molecules/IconContainer.tsx +79 -0
  32. package/src/molecules/ListItem.tsx +35 -0
  33. package/src/molecules/ScreenHeader.tsx +171 -0
  34. package/src/molecules/SearchBar.tsx +198 -0
  35. package/src/molecules/confirmation-modal/components.tsx +94 -0
  36. package/src/molecules/confirmation-modal/index.ts +7 -0
  37. package/src/molecules/confirmation-modal/styles/confirmationModalStyles.ts +133 -0
  38. package/src/molecules/confirmation-modal/types/index.ts +41 -0
  39. package/src/molecules/confirmation-modal/useConfirmationModal.ts +50 -0
  40. package/src/molecules/index.ts +19 -0
  41. package/src/molecules/listitem/index.ts +6 -0
  42. package/src/molecules/listitem/styles/listItemStyles.ts +37 -0
  43. package/src/molecules/listitem/types/index.ts +21 -0
  44. package/src/organisms/AppHeader.tsx +136 -0
  45. package/src/organisms/FormContainer.tsx +169 -0
  46. package/src/organisms/ScreenLayout.tsx +183 -0
  47. package/src/organisms/index.ts +31 -0
  48. package/src/responsive/config.ts +139 -0
  49. package/src/responsive/deviceDetection.ts +155 -0
  50. package/src/responsive/gridUtils.ts +79 -0
  51. package/src/responsive/index.ts +52 -0
  52. package/src/responsive/platformConstants.ts +98 -0
  53. package/src/responsive/responsive.ts +61 -0
  54. package/src/responsive/responsiveLayout.ts +137 -0
  55. package/src/responsive/responsiveSizing.ts +134 -0
  56. package/src/responsive/useResponsive.ts +140 -0
  57. package/src/responsive/validation.ts +158 -0
  58. package/src/theme/core/BaseTokens.ts +42 -0
  59. package/src/theme/core/ColorPalette.ts +29 -0
  60. package/src/theme/core/CustomColors.ts +122 -0
  61. package/src/theme/core/NavigationTheme.ts +72 -0
  62. package/src/theme/core/TokenFactory.ts +103 -0
  63. package/src/theme/core/colors/ColorUtils.ts +53 -0
  64. package/src/theme/core/colors/DarkColors.ts +146 -0
  65. package/src/theme/core/colors/LightColors.ts +146 -0
  66. package/src/theme/core/constants/DesignConstants.ts +31 -0
  67. package/src/theme/core/themes.ts +118 -0
  68. package/src/theme/core/tokens/BaseTokens.ts +144 -0
  69. package/src/theme/core/tokens/Borders.ts +43 -0
  70. package/src/theme/core/tokens/Sizes.ts +51 -0
  71. package/src/theme/core/tokens/Spacing.ts +38 -0
  72. package/src/theme/core/tokens/Typography.ts +143 -0
  73. package/src/theme/hooks/useAppDesignTokens.ts +45 -0
  74. package/src/theme/hooks/useCommonStyles.ts +248 -0
  75. package/src/theme/hooks/useThemedStyles.ts +68 -0
  76. package/src/theme/index.ts +94 -0
  77. package/src/theme/infrastructure/globalThemeStore.ts +69 -0
  78. package/src/theme/infrastructure/storage/ThemeStorage.ts +93 -0
  79. package/src/theme/infrastructure/stores/themeStore.ts +109 -0
  80. package/src/typography/__tests__/colorValidationUtils.test.ts +180 -0
  81. package/src/typography/__tests__/textColorUtils.test.ts +185 -0
  82. package/src/typography/__tests__/textStyleUtils.test.ts +168 -0
  83. package/src/typography/domain/entities/TypographyTypes.ts +88 -0
  84. package/src/typography/index.ts +53 -0
  85. package/src/typography/presentation/utils/colorValidationUtils.ts +133 -0
  86. package/src/typography/presentation/utils/textColorUtils.ts +205 -0
  87. package/src/typography/presentation/utils/textStyleUtils.ts +159 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Tests for text color utilities
3
+ */
4
+
5
+ import { getTextColor } from '../presentation/utils/textColorUtils';
6
+ import type { ColorVariant } from '../domain/entities/TypographyTypes';
7
+
8
+ import type { DesignTokens } from '@umituz/react-native-design-system-theme';
9
+
10
+ // Mock design tokens for testing
11
+ const mockTokens: DesignTokens = {
12
+ colors: {
13
+ textPrimary: '#000000',
14
+ textSecondary: '#666666',
15
+ textTertiary: '#999999',
16
+ textDisabled: '#CCCCCC',
17
+ textInverse: '#FFFFFF',
18
+ onSurface: '#000000',
19
+ onBackground: '#000000',
20
+ onPrimary: '#FFFFFF',
21
+ onSecondary: '#FFFFFF',
22
+ onSuccess: '#FFFFFF',
23
+ onError: '#FFFFFF',
24
+ onWarning: '#000000',
25
+ onInfo: '#FFFFFF',
26
+ success: '#4CAF50',
27
+ error: '#F44336',
28
+ warning: '#FF9800',
29
+ info: '#2196F3',
30
+ primary: '#2196F3',
31
+ secondary: '#FF9800',
32
+ tertiary: '#9C27B0',
33
+ surface: '#FFFFFF',
34
+ surfaceVariant: '#F5F5F5',
35
+ background: '#FFFFFF',
36
+ },
37
+ typography: {
38
+ displayLarge: { fontSize: 57, fontWeight: '400' },
39
+ displayMedium: { fontSize: 45, fontWeight: '400' },
40
+ displaySmall: { fontSize: 36, fontWeight: '400' },
41
+ headlineLarge: { fontSize: 32, fontWeight: '400' },
42
+ headlineMedium: { fontSize: 28, fontWeight: '400' },
43
+ headlineSmall: { fontSize: 24, fontWeight: '400' },
44
+ titleLarge: { fontSize: 22, fontWeight: '500' },
45
+ titleMedium: { fontSize: 16, fontWeight: '500' },
46
+ titleSmall: { fontSize: 14, fontWeight: '500' },
47
+ bodyLarge: { fontSize: 16, fontWeight: '400' },
48
+ bodyMedium: { fontSize: 14, fontWeight: '400' },
49
+ bodySmall: { fontSize: 12, fontWeight: '400' },
50
+ labelLarge: { fontSize: 14, fontWeight: '500' },
51
+ labelMedium: { fontSize: 12, fontWeight: '500' },
52
+ labelSmall: { fontSize: 11, fontWeight: '500' },
53
+ },
54
+ spacing: {},
55
+ shadows: {},
56
+ borderRadius: {},
57
+ iconSizes: {},
58
+ opacity: {},
59
+ avatarSizes: {},
60
+ borders: {},
61
+ };
62
+
63
+
64
+
65
+ describe('getTextColor', () => {
66
+ test('should throw error when tokens is null', () => {
67
+ expect(() => getTextColor('textPrimary', null as any)).toThrow(
68
+ 'Invalid design tokens: tokens and tokens.colors are required'
69
+ );
70
+ });
71
+
72
+ test('should throw error when tokens is undefined', () => {
73
+ expect(() => getTextColor('textPrimary', undefined as any)).toThrow(
74
+ 'Invalid design tokens: tokens and tokens.colors are required'
75
+ );
76
+ });
77
+
78
+ test('should throw error when tokens.colors is null', () => {
79
+ expect(() => getTextColor('textPrimary', { colors: null } as any)).toThrow(
80
+ 'Invalid design tokens: tokens and tokens.colors are required'
81
+ );
82
+ });
83
+
84
+ test('should return default textPrimary when color is undefined', () => {
85
+ const result = getTextColor(undefined, mockTokens);
86
+ expect(result).toBe('#000000');
87
+ });
88
+
89
+ test('should return custom color as-is when not a variant', () => {
90
+ const customColor = '#FF5722';
91
+ const result = getTextColor(customColor, mockTokens);
92
+ expect(result).toBe(customColor);
93
+ });
94
+
95
+ test('should map textPrimary variant correctly', () => {
96
+ const result = getTextColor('textPrimary', mockTokens);
97
+ expect(result).toBe('#000000');
98
+ });
99
+
100
+ test('should map textSecondary variant correctly', () => {
101
+ const result = getTextColor('textSecondary', mockTokens);
102
+ expect(result).toBe('#666666');
103
+ });
104
+
105
+ test('should map semantic colors correctly', () => {
106
+ expect(getTextColor('success', mockTokens)).toBe('#4CAF50');
107
+ expect(getTextColor('error', mockTokens)).toBe('#F44336');
108
+ expect(getTextColor('warning', mockTokens)).toBe('#FF9800');
109
+ expect(getTextColor('info', mockTokens)).toBe('#2196F3');
110
+ });
111
+
112
+ test('should map on-colors correctly', () => {
113
+ expect(getTextColor('onPrimary', mockTokens)).toBe('#FFFFFF');
114
+ expect(getTextColor('onError', mockTokens)).toBe('#FFFFFF');
115
+ });
116
+
117
+ test('should handle legacy variants correctly', () => {
118
+ expect(getTextColor('primary', mockTokens)).toBe('#000000'); // Maps to textPrimary
119
+ expect(getTextColor('secondary', mockTokens)).toBe('#666666'); // Maps to textSecondary
120
+ expect(getTextColor('surfaceVariant', mockTokens)).toBe('#666666'); // Maps to textSecondary
121
+ });
122
+
123
+ test('should handle empty string', () => {
124
+ const result = getTextColor('', mockTokens);
125
+ expect(result).toBe('#000000');
126
+ });
127
+
128
+ test('should handle hex color strings', () => {
129
+ const hexColor = '#RRGGBB';
130
+ const result = getTextColor(hexColor, mockTokens);
131
+ expect(result).toBe(hexColor);
132
+ });
133
+
134
+ test('should handle rgb color strings', () => {
135
+ const rgbColor = 'rgb(255, 0, 0)';
136
+ const result = getTextColor(rgbColor, mockTokens);
137
+ expect(result).toBe(rgbColor);
138
+ });
139
+
140
+ test('should return custom color as-is when not a variant', () => {
141
+ const customColor = 'unknownVariant';
142
+ const result = getTextColor(customColor, mockTokens);
143
+ expect(result).toBe(customColor);
144
+ });
145
+
146
+
147
+
148
+
149
+ });
150
+
151
+ describe('ColorVariant validation', () => {
152
+ test('should validate all defined color variants', () => {
153
+ const validVariants: ColorVariant[] = [
154
+ 'textPrimary',
155
+ 'textSecondary',
156
+ 'textTertiary',
157
+ 'textDisabled',
158
+ 'textInverse',
159
+ 'onSurface',
160
+ 'onBackground',
161
+ 'onPrimary',
162
+ 'onSecondary',
163
+ 'onSuccess',
164
+ 'onError',
165
+ 'onWarning',
166
+ 'onInfo',
167
+ 'success',
168
+ 'error',
169
+ 'warning',
170
+ 'info',
171
+ 'primary',
172
+ 'secondary',
173
+ 'tertiary',
174
+ 'disabled',
175
+ 'inverse',
176
+ 'surfaceVariant',
177
+ ];
178
+
179
+ validVariants.forEach(variant => {
180
+ const result = getTextColor(variant, mockTokens);
181
+ expect(typeof result).toBe('string');
182
+ expect(result.length).toBeGreaterThan(0);
183
+ });
184
+ });
185
+ });
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Tests for typography style utilities
3
+ */
4
+
5
+ import { getTextStyle, isTextStyleVariant, getAllTextStyleVariants } from '../presentation/utils/textStyleUtils';
6
+ import type { TextStyleVariant } from '../domain/entities/TypographyTypes';
7
+ import type { DesignTokens } from '@umituz/react-native-design-system-theme';
8
+
9
+ const mockTokens: DesignTokens = {
10
+ colors: {
11
+ textPrimary: '#000000',
12
+ textSecondary: '#666666',
13
+ textTertiary: '#999999',
14
+ textDisabled: '#CCCCCC',
15
+ textInverse: '#FFFFFF',
16
+ onSurface: '#000000',
17
+ onBackground: '#000000',
18
+ onPrimary: '#FFFFFF',
19
+ onSecondary: '#FFFFFF',
20
+ onSuccess: '#FFFFFF',
21
+ onError: '#FFFFFF',
22
+ onWarning: '#000000',
23
+ onInfo: '#FFFFFF',
24
+ success: '#4CAF50',
25
+ error: '#F44336',
26
+ warning: '#FF9800',
27
+ info: '#2196F3',
28
+ primary: '#2196F3',
29
+ secondary: '#FF9800',
30
+ tertiary: '#9C27B0',
31
+ surface: '#FFFFFF',
32
+ surfaceVariant: '#F5F5F5',
33
+ background: '#FFFFFF',
34
+ },
35
+ typography: {
36
+ displayLarge: { fontSize: 57, fontWeight: '400' },
37
+ displayMedium: { fontSize: 45, fontWeight: '400' },
38
+ displaySmall: { fontSize: 36, fontWeight: '400' },
39
+ headlineLarge: { fontSize: 32, fontWeight: '400' },
40
+ headlineMedium: { fontSize: 28, fontWeight: '400' },
41
+ headlineSmall: { fontSize: 24, fontWeight: '400' },
42
+ titleLarge: { fontSize: 22, fontWeight: '500' },
43
+ titleMedium: { fontSize: 16, fontWeight: '500' },
44
+ titleSmall: { fontSize: 14, fontWeight: '500' },
45
+ bodyLarge: { fontSize: 16, fontWeight: '400' },
46
+ bodyMedium: { fontSize: 14, fontWeight: '400' },
47
+ bodySmall: { fontSize: 12, fontWeight: '400' },
48
+ labelLarge: { fontSize: 14, fontWeight: '500' },
49
+ labelMedium: { fontSize: 12, fontWeight: '500' },
50
+ labelSmall: { fontSize: 11, fontWeight: '500' },
51
+ },
52
+ spacing: {},
53
+ shadows: {},
54
+ borderRadius: {},
55
+ iconSizes: {},
56
+ opacity: {},
57
+ avatarSizes: {},
58
+ borders: {},
59
+ };
60
+
61
+ describe('getTextStyle', () => {
62
+ test('should throw error when tokens is null', () => {
63
+ expect(() => getTextStyle('bodyLarge', null as any)).toThrow(
64
+ 'Invalid design tokens: tokens and tokens.typography are required'
65
+ );
66
+ });
67
+
68
+ test('should throw error when tokens is undefined', () => {
69
+ expect(() => getTextStyle('bodyLarge', undefined as any)).toThrow(
70
+ 'Invalid design tokens: tokens and tokens.typography are required'
71
+ );
72
+ });
73
+
74
+ test('should throw error when tokens.typography is null', () => {
75
+ expect(() => getTextStyle('bodyLarge', { typography: null } as any)).toThrow(
76
+ 'Invalid design tokens: tokens and tokens.typography are required'
77
+ );
78
+ });
79
+
80
+ test('should return correct style for displayLarge', () => {
81
+ const result = getTextStyle('displayLarge', mockTokens);
82
+ expect(result).toEqual({ fontSize: 57, fontWeight: '400' });
83
+ });
84
+
85
+ test('should return correct style for headlineMedium', () => {
86
+ const result = getTextStyle('headlineMedium', mockTokens);
87
+ expect(result).toEqual({ fontSize: 28, fontWeight: '400' });
88
+ });
89
+
90
+ test('should return correct style for titleSmall', () => {
91
+ const result = getTextStyle('titleSmall', mockTokens);
92
+ expect(result).toEqual({ fontSize: 14, fontWeight: '500' });
93
+ });
94
+
95
+ test('should return correct style for bodyMedium', () => {
96
+ const result = getTextStyle('bodyMedium', mockTokens);
97
+ expect(result).toEqual({ fontSize: 14, fontWeight: '400' });
98
+ });
99
+
100
+ test('should return correct style for labelSmall', () => {
101
+ const result = getTextStyle('labelSmall', mockTokens);
102
+ expect(result).toEqual({ fontSize: 11, fontWeight: '500' });
103
+ });
104
+
105
+ test('should return fallback style for unknown variant', () => {
106
+ const result = getTextStyle('unknownVariant' as TextStyleVariant, mockTokens);
107
+ expect(result).toEqual({ fontSize: 16, fontWeight: '400' }); // bodyLarge fallback
108
+ });
109
+ });
110
+
111
+ describe('isTextStyleVariant', () => {
112
+ test('should return true for valid variants', () => {
113
+ expect(isTextStyleVariant('displayLarge')).toBe(true);
114
+ expect(isTextStyleVariant('headlineMedium')).toBe(true);
115
+ expect(isTextStyleVariant('titleSmall')).toBe(true);
116
+ expect(isTextStyleVariant('bodyMedium')).toBe(true);
117
+ expect(isTextStyleVariant('labelSmall')).toBe(true);
118
+ });
119
+
120
+ test('should return false for invalid variants', () => {
121
+ expect(isTextStyleVariant('invalid')).toBe(false);
122
+ expect(isTextStyleVariant('display')).toBe(false);
123
+ expect(isTextStyleVariant('')).toBe(false);
124
+ expect(isTextStyleVariant('body')).toBe(false);
125
+ });
126
+ });
127
+
128
+ describe('getAllTextStyleVariants', () => {
129
+ test('should return all text style variants', () => {
130
+ const variants = getAllTextStyleVariants();
131
+
132
+ expect(variants).toHaveLength(15);
133
+ expect(variants).toContain('displayLarge');
134
+ expect(variants).toContain('displayMedium');
135
+ expect(variants).toContain('displaySmall');
136
+ expect(variants).toContain('headlineLarge');
137
+ expect(variants).toContain('headlineMedium');
138
+ expect(variants).toContain('headlineSmall');
139
+ expect(variants).toContain('titleLarge');
140
+ expect(variants).toContain('titleMedium');
141
+ expect(variants).toContain('titleSmall');
142
+ expect(variants).toContain('bodyLarge');
143
+ expect(variants).toContain('bodyMedium');
144
+ expect(variants).toContain('bodySmall');
145
+ expect(variants).toContain('labelLarge');
146
+ expect(variants).toContain('labelMedium');
147
+ expect(variants).toContain('labelSmall');
148
+ });
149
+
150
+ test('should return readonly array', () => {
151
+ const variants = getAllTextStyleVariants();
152
+ expect(Array.isArray(variants)).toBe(true);
153
+ });
154
+ });
155
+
156
+ describe('TextStyleVariant validation', () => {
157
+ test('should validate all defined text style variants', () => {
158
+ const validVariants: TextStyleVariant[] = getAllTextStyleVariants();
159
+
160
+ validVariants.forEach(variant => {
161
+ const result = getTextStyle(variant, mockTokens);
162
+ expect(result).toHaveProperty('fontSize');
163
+ expect(result).toHaveProperty('fontWeight');
164
+ expect(typeof result.fontSize).toBe('number');
165
+ expect(typeof result.fontWeight).toBe('string');
166
+ });
167
+ });
168
+ });
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Typography Types - Material Design 3 Text Style Variants
3
+ *
4
+ * This file defines all typography-related types for React Native applications.
5
+ * These types are used by components like AtomicText to ensure type-safe typography usage.
6
+ *
7
+ * @fileoverview Provides type definitions for Material Design 3 typography system
8
+ * @author Ümit UZ <umit@umituz.com>
9
+ * @since 1.0.0
10
+ * @version 1.2.0
11
+ */
12
+
13
+ /**
14
+ * Material Design 3 Text Style Variants
15
+ *
16
+ * These variants correspond to Material Design 3 typography scale:
17
+ * - Display: Largest text (57px, 45px, 36px)
18
+ * - Headline: Section headers (32px, 28px, 24px)
19
+ * - Title: Card titles, list headers (22px, 16px, 14px)
20
+ * - Body: Main content text (16px, 14px, 12px)
21
+ * - Label: UI labels, buttons (14px, 12px, 11px)
22
+ */
23
+ export type TextStyleVariant =
24
+ | 'displayLarge'
25
+ | 'displayMedium'
26
+ | 'displaySmall'
27
+ | 'headlineLarge'
28
+ | 'headlineMedium'
29
+ | 'headlineSmall'
30
+ | 'titleLarge'
31
+ | 'titleMedium'
32
+ | 'titleSmall'
33
+ | 'bodyLarge'
34
+ | 'bodyMedium'
35
+ | 'bodySmall'
36
+ | 'labelLarge'
37
+ | 'labelMedium'
38
+ | 'labelSmall';
39
+
40
+ /**
41
+ * Material Design 3 Text Color Variants
42
+ *
43
+ * TEXT COLORS (for text on surfaces):
44
+ * - textPrimary, textSecondary, textTertiary: General text colors
45
+ * - onSurface, onBackground: Text on surface/background
46
+ *
47
+ * ON COLORS (for text on colored backgrounds):
48
+ * - onPrimary, onSecondary: Text on primary/secondary colored backgrounds
49
+ * - onSuccess, onError, onWarning, onInfo: Text on semantic colored backgrounds
50
+ *
51
+ * SEMANTIC COLORS (can be used as text colors):
52
+ * - success, error, warning, info: Semantic colors (can be text or background)
53
+ *
54
+ * NOTE: 'primary' and 'secondary' are BACKGROUND colors, not text colors.
55
+ * Use 'onPrimary'/'onSecondary' for text on colored backgrounds, or
56
+ * 'textPrimary'/'textSecondary' for general text.
57
+ */
58
+ export type ColorVariant =
59
+ // General text colors (Material Design 3)
60
+ | 'textPrimary'
61
+ | 'textSecondary'
62
+ | 'textTertiary'
63
+ | 'textDisabled'
64
+ | 'textInverse'
65
+ // Text on surfaces (Material Design 3)
66
+ | 'onSurface'
67
+ | 'onBackground'
68
+ // Text on colored backgrounds (Material Design 3)
69
+ | 'onPrimary'
70
+ | 'onSecondary'
71
+ | 'onSuccess'
72
+ | 'onError'
73
+ | 'onWarning'
74
+ | 'onInfo'
75
+ // Semantic colors (can be used as text)
76
+ | 'success'
77
+ | 'error'
78
+ | 'warning'
79
+ | 'info'
80
+ // Legacy support (deprecated - use textPrimary/textSecondary instead)
81
+ | 'primary'
82
+ | 'secondary'
83
+ | 'tertiary'
84
+ | 'disabled'
85
+ | 'inverse'
86
+ // Legacy: surfaceVariant is a background color, maps to textSecondary
87
+ | 'surfaceVariant';
88
+
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @umituz/react-native-design-system-typography - Public API
3
+ *
4
+ * Typography types and utilities for React Native applications
5
+ * Material Design 3 text styles and color variants
6
+ *
7
+ * This package provides:
8
+ * - Typography type definitions (TextStyleVariant, ColorVariant)
9
+ * - Text color utility functions
10
+ * - Type-safe typography helpers
11
+ *
12
+ * Usage:
13
+ * import { TextStyleVariant, ColorVariant, getTextColor } from '@umituz/react-native-design-system-typography';
14
+ */
15
+
16
+ // =============================================================================
17
+ // DOMAIN LAYER - Entities (Types)
18
+ // =============================================================================
19
+
20
+ export type {
21
+ TextStyleVariant,
22
+ ColorVariant,
23
+ } from './domain/entities/TypographyTypes';
24
+
25
+ // =============================================================================
26
+ // PRESENTATION LAYER - Utilities
27
+ // =============================================================================
28
+
29
+ export {
30
+ getTextColor,
31
+ } from './presentation/utils/textColorUtils';
32
+
33
+ export {
34
+ getTextStyle,
35
+ isTextStyleVariant,
36
+ getAllTextStyleVariants,
37
+ clearTypographyCache,
38
+ } from './presentation/utils/textStyleUtils';
39
+
40
+ export {
41
+ clearColorCache,
42
+ } from './presentation/utils/textColorUtils';
43
+
44
+ export {
45
+ isValidHexColor,
46
+ isValidRgbColor,
47
+ isValidHslColor,
48
+ isValidNamedColor,
49
+ isValidColor,
50
+ getColorFormat,
51
+ normalizeColor,
52
+ } from './presentation/utils/colorValidationUtils';
53
+
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Color Validation Utilities
3
+ *
4
+ * Helper functions for validating color formats and values.
5
+ * These utilities ensure color strings are in valid formats.
6
+ *
7
+ * @fileoverview Provides color validation utilities
8
+ * @author Ümit UZ <umit@umituz.com>
9
+ * @since 1.2.0
10
+ * @version 1.2.0
11
+ */
12
+
13
+ /**
14
+ * Regular expressions for color format validation
15
+ */
16
+ const COLOR_PATTERNS = {
17
+ // #RGB, #RRGGBB
18
+ hex: /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/,
19
+ // rgb(R, G, B), rgba(R, G, B, A)
20
+ rgb: /^rgba?\(\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*,\s*(\d{1,3}%?)\s*(?:,\s*([01]?\.?\d*)\s*)?\)$/,
21
+ // hsl(H, S, L), hsla(H, S, L, A)
22
+ hsl: /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}%)\s*,\s*(\d{1,3}%)\s*(?:,\s*([01]?\.?\d*)\s*)?\)$/,
23
+ // CSS color names (limited to common ones)
24
+ named: /^(red|blue|green|yellow|orange|purple|pink|brown|black|white|gray|grey|transparent|inherit|initial|unset|currentcolor)$/i,
25
+ };
26
+
27
+ /**
28
+ * Check if a string is a valid hex color
29
+ *
30
+ * @param color - Color string to validate
31
+ * @returns True if valid hex color
32
+ */
33
+ export function isValidHexColor(color: string): boolean {
34
+ return COLOR_PATTERNS.hex.test(color);
35
+ }
36
+
37
+ /**
38
+ * Check if a string is a valid RGB/RGBA color
39
+ *
40
+ * @param color - Color string to validate
41
+ * @returns True if valid RGB/RGBA color
42
+ */
43
+ export function isValidRgbColor(color: string): boolean {
44
+ if (!COLOR_PATTERNS.rgb.test(color)) {
45
+ return false;
46
+ }
47
+
48
+ // Additional validation for RGB values
49
+ const match = color.match(/\d+/g);
50
+ if (!match || match.length < 3) return false;
51
+
52
+ const [r, g, b] = match.map(Number);
53
+ return r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
54
+ }
55
+
56
+ /**
57
+ * Check if a string is a valid HSL/HSLA color
58
+ *
59
+ * @param color - Color string to validate
60
+ * @returns True if valid HSL/HSLA color
61
+ */
62
+ export function isValidHslColor(color: string): boolean {
63
+ if (!COLOR_PATTERNS.hsl.test(color)) {
64
+ return false;
65
+ }
66
+
67
+ // Additional validation for HSL values
68
+ const match = color.match(/\d+/g);
69
+ if (!match || match.length < 3) return false;
70
+
71
+ const [h, s, l] = match.map(Number);
72
+ return h >= 0 && h <= 360 && s >= 0 && s <= 100 && l >= 0 && l <= 100;
73
+ }
74
+
75
+ /**
76
+ * Check if a string is a valid CSS named color
77
+ *
78
+ * @param color - Color string to validate
79
+ * @returns True if valid CSS named color
80
+ */
81
+ export function isValidNamedColor(color: string): boolean {
82
+ return COLOR_PATTERNS.named.test(color);
83
+ }
84
+
85
+ /**
86
+ * Check if a string is a valid color in any supported format
87
+ *
88
+ * @param color - Color string to validate
89
+ * @returns True if valid color in any format
90
+ */
91
+ export function isValidColor(color: string): boolean {
92
+ return isValidHexColor(color) ||
93
+ isValidRgbColor(color) ||
94
+ isValidHslColor(color) ||
95
+ isValidNamedColor(color);
96
+ }
97
+
98
+ /**
99
+ * Get the format of a color string
100
+ *
101
+ * @param color - Color string to analyze
102
+ * @returns Color format or 'unknown' if not recognized
103
+ */
104
+ export function getColorFormat(color: string): 'hex' | 'rgb' | 'hsl' | 'named' | 'unknown' {
105
+ if (isValidHexColor(color)) return 'hex';
106
+ if (isValidRgbColor(color)) return 'rgb';
107
+ if (isValidHslColor(color)) return 'hsl';
108
+ if (isValidNamedColor(color)) return 'named';
109
+ return 'unknown';
110
+ }
111
+
112
+ /**
113
+ * Normalize a color string to a consistent format
114
+ *
115
+ * @param color - Color string to normalize
116
+ * @returns Normalized color string
117
+ */
118
+ export function normalizeColor(color: string): string {
119
+ if (!isValidColor(color)) {
120
+ return color;
121
+ }
122
+
123
+ // Convert 3-digit hex to 6-digit
124
+ if (isValidHexColor(color) && color.length === 4) {
125
+ const r = color[1];
126
+ const g = color[2];
127
+ const b = color[3];
128
+ return `#${r}${r}${g}${g}${b}${b}`;
129
+ }
130
+
131
+ // Convert to lowercase for consistency
132
+ return color.toLowerCase();
133
+ }