@umituz/react-native-design-system 1.1.3 → 1.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "Universal design system for React Native apps - Domain-Driven Design architecture with Material Design 3 components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Icon Library Configuration
3
+ *
4
+ * 🔧 SINGLE SOURCE OF TRUTH FOR ICON LIBRARY SELECTION
5
+ *
6
+ * To change icon library:
7
+ * 1. Update package.json with new library
8
+ * 2. Change CURRENT_LIBRARY below
9
+ * 3. Create adapter if needed (infrastructure/adapters/)
10
+ * 4. Done! All apps automatically use new library
11
+ *
12
+ * @example
13
+ * // Switch to Material Icons:
14
+ * export const CURRENT_LIBRARY: IconLibraryType = 'material';
15
+ */
16
+
17
+ export type IconLibraryType = 'lucide' | 'material' | 'fontawesome' | 'ionicons';
18
+
19
+ /**
20
+ * 🔧 CHANGE THIS TO SWITCH ICON LIBRARY
21
+ */
22
+ export const CURRENT_LIBRARY: IconLibraryType = 'lucide';
23
+
24
+ /**
25
+ * Icon Library Configuration
26
+ */
27
+ export const ICON_LIBRARY_CONFIG = {
28
+ /**
29
+ * Current icon library in use
30
+ */
31
+ library: CURRENT_LIBRARY,
32
+
33
+ /**
34
+ * Default icon size (in pixels)
35
+ */
36
+ defaultSize: 24,
37
+
38
+ /**
39
+ * Default stroke width for outline icons
40
+ */
41
+ defaultStrokeWidth: 2,
42
+
43
+ /**
44
+ * Library metadata
45
+ */
46
+ libraries: {
47
+ lucide: {
48
+ name: 'Lucide',
49
+ package: 'lucide-react-native',
50
+ version: '^0.468.0',
51
+ iconCount: 1639,
52
+ type: 'outline',
53
+ adapter: 'LucideAdapter',
54
+ },
55
+ material: {
56
+ name: 'Material Icons',
57
+ package: '@expo/vector-icons',
58
+ version: '^14.0.0',
59
+ iconCount: 2000,
60
+ type: 'filled',
61
+ adapter: 'MaterialAdapter',
62
+ },
63
+ fontawesome: {
64
+ name: 'Font Awesome',
65
+ package: '@expo/vector-icons',
66
+ version: '^14.0.0',
67
+ iconCount: 1500,
68
+ type: 'solid',
69
+ adapter: 'FontAwesomeAdapter',
70
+ },
71
+ ionicons: {
72
+ name: 'Ionicons',
73
+ package: '@expo/vector-icons',
74
+ version: '^14.0.0',
75
+ iconCount: 1300,
76
+ type: 'outline',
77
+ adapter: 'IoniconsAdapter',
78
+ },
79
+ },
80
+ } as const;
81
+
82
+ /**
83
+ * Get current library metadata
84
+ */
85
+ export const getCurrentLibrary = () => {
86
+ return ICON_LIBRARY_CONFIG.libraries[CURRENT_LIBRARY];
87
+ };
88
+
89
+ /**
90
+ * Type-safe library check
91
+ * Factory uses Lucide icons only
92
+ */
93
+ export const isLucideLibrary = () => true;
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Icons Domain - Entities
3
+ *
4
+ * Core icon types and interfaces for the App Factory.
5
+ * Provides unified access to Lucide icons (design-system) + Expo vector icons.
6
+ *
7
+ * @domain icons
8
+ * @layer domain
9
+ */
10
+
11
+ /**
12
+ * Icon library types
13
+ * - lucide: Lucide React Native icons (already in design-system/AtomicIcon)
14
+ * - material: Material Design icons (@expo/vector-icons)
15
+ * - fontawesome: FontAwesome icons (@expo/vector-icons)
16
+ * - ionicons: Ionicons (@expo/vector-icons)
17
+ */
18
+ export enum IconLibrary {
19
+ LUCIDE = 'lucide',
20
+ MATERIAL = 'material',
21
+ FONTAWESOME = 'fontawesome',
22
+ IONICONS = 'ionicons',
23
+ }
24
+
25
+ /**
26
+ * Icon category for organization
27
+ */
28
+ export enum IconCategory {
29
+ ALL = 'all',
30
+ NAVIGATION = 'navigation',
31
+ ACTION = 'action',
32
+ SOCIAL = 'social',
33
+ COMMUNICATION = 'communication',
34
+ MEDIA = 'media',
35
+ BUSINESS = 'business',
36
+ WEATHER = 'weather',
37
+ SYMBOLS = 'symbols',
38
+ EMOJI = 'emoji',
39
+ }
40
+
41
+ /**
42
+ * Icon metadata for registry
43
+ */
44
+ export interface IconMetadata {
45
+ name: string;
46
+ library: IconLibrary;
47
+ category: IconCategory;
48
+ tags: string[];
49
+ searchTerms: string[];
50
+ }
51
+
52
+ /**
53
+ * Icon registry interface
54
+ */
55
+ export interface IIconRegistry {
56
+ /**
57
+ * Get all icons in the library
58
+ */
59
+ getAllIcons(): IconMetadata[];
60
+
61
+ /**
62
+ * Get icons by category
63
+ */
64
+ getIconsByCategory(category: IconCategory): IconMetadata[];
65
+
66
+ /**
67
+ * Search icons by query
68
+ */
69
+ searchIcons(query: string): IconMetadata[];
70
+
71
+ /**
72
+ * Get icon metadata by name
73
+ */
74
+ getIconMetadata(name: string): IconMetadata | null;
75
+ }
76
+
77
+ /**
78
+ * Icon picker configuration
79
+ */
80
+ export interface IconPickerConfig {
81
+ libraries: IconLibrary[];
82
+ categories: IconCategory[];
83
+ showSearch: boolean;
84
+ multiSelect: boolean;
85
+ maxSelections?: number;
86
+ onSelect: (icons: IconMetadata[]) => void;
87
+ onCancel?: () => void;
88
+ }
89
+
90
+ /**
91
+ * Icon constants
92
+ */
93
+ export const ICON_CONSTANTS = {
94
+ DEFAULT_SIZE: 24,
95
+ DEFAULT_COLOR: 'onSurface',
96
+ DEFAULT_LIBRARY: IconLibrary.LUCIDE,
97
+ MAX_SEARCH_RESULTS: 50,
98
+ } as const;
99
+
100
+ /**
101
+ * Icon utility functions
102
+ */
103
+ export const IconUtils = {
104
+ /**
105
+ * Normalize icon name for search
106
+ */
107
+ normalizeIconName: (name: string): string => {
108
+ return name.toLowerCase().replace(/[^a-z0-9]/g, '');
109
+ },
110
+
111
+ /**
112
+ * Match search query against icon metadata
113
+ */
114
+ matchesSearch: (icon: IconMetadata, query: string): boolean => {
115
+ const normalizedQuery = IconUtils.normalizeIconName(query);
116
+ const normalizedName = IconUtils.normalizeIconName(icon.name);
117
+ const normalizedTags = icon.tags.map(tag => IconUtils.normalizeIconName(tag));
118
+ const normalizedTerms = icon.searchTerms.map(term => IconUtils.normalizeIconName(term));
119
+
120
+ return (
121
+ normalizedName.includes(normalizedQuery) ||
122
+ normalizedTags.some(tag => tag.includes(normalizedQuery)) ||
123
+ normalizedTerms.some(term => term.includes(normalizedQuery))
124
+ );
125
+ },
126
+
127
+ /**
128
+ * Filter icons by category
129
+ */
130
+ filterByCategory: (icons: IconMetadata[], category: IconCategory): IconMetadata[] => {
131
+ if (category === IconCategory.ALL) {
132
+ return icons;
133
+ }
134
+ return icons.filter(icon => icon.category === category);
135
+ },
136
+
137
+ /**
138
+ * Sort icons alphabetically
139
+ */
140
+ sortByName: (icons: IconMetadata[]): IconMetadata[] => {
141
+ return [...icons].sort((a, b) => a.name.localeCompare(b.name));
142
+ },
143
+ };
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Icon Adapter Interface
3
+ *
4
+ * Universal interface that all icon library adapters must implement.
5
+ * This allows seamless switching between icon libraries.
6
+ *
7
+ * @example
8
+ * // Implementing for a new library:
9
+ * export const MyLibraryAdapter: IIconAdapter = {
10
+ * getIconComponent: (name) => MyIcons[name],
11
+ * getIconSize: (size) => sizeMap[size],
12
+ * getIconColor: (color, tokens) => colorMap[color],
13
+ * getAllIcons: () => Object.keys(MyIcons),
14
+ * };
15
+ */
16
+
17
+ import type { DesignTokens } from '@umituz/react-native-design-system';
18
+
19
+ export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
20
+ export type IconColor =
21
+ | 'primary'
22
+ | 'secondary'
23
+ | 'success'
24
+ | 'warning'
25
+ | 'error'
26
+ | 'info'
27
+ | 'onSurface'
28
+ | 'surfaceVariant'
29
+ | 'onPrimary'
30
+ | 'onSecondary'
31
+ | 'textInverse';
32
+
33
+ /**
34
+ * Icon Adapter Interface
35
+ * All icon library adapters must implement this interface
36
+ */
37
+ export interface IIconAdapter {
38
+ /**
39
+ * Get the icon component for a given icon name
40
+ * @param name - Icon name (library-specific)
41
+ * @returns Icon component or null if not found
42
+ */
43
+ getIconComponent: (name: string) => any | null;
44
+
45
+ /**
46
+ * Convert semantic size to pixel size
47
+ * @param size - Semantic size (xs, sm, md, lg, xl, xxl)
48
+ * @param customSize - Optional custom pixel size
49
+ * @returns Pixel size
50
+ */
51
+ getIconSize: (size: IconSize, customSize?: number) => number;
52
+
53
+ /**
54
+ * Convert semantic color to hex color
55
+ * @param color - Semantic color name
56
+ * @param tokens - Design tokens for theme colors
57
+ * @param customColor - Optional custom hex color
58
+ * @returns Hex color string
59
+ */
60
+ getIconColor: (
61
+ color: IconColor,
62
+ tokens: DesignTokens,
63
+ customColor?: string
64
+ ) => string;
65
+
66
+ /**
67
+ * Get all available icon names for this library
68
+ * @returns Array of icon names
69
+ */
70
+ getAllIcons: () => string[];
71
+
72
+ /**
73
+ * Check if an icon exists in the library
74
+ * @param name - Icon name to check
75
+ * @returns True if icon exists
76
+ */
77
+ hasIcon: (name: string) => boolean;
78
+
79
+ /**
80
+ * Get default stroke width for outline icons
81
+ * @returns Stroke width number
82
+ */
83
+ getStrokeWidth?: () => number;
84
+ }
85
+
86
+ /**
87
+ * Icon Props - Universal props for Icon component
88
+ */
89
+ export interface IconProps {
90
+ /**
91
+ * Icon name (library-specific)
92
+ */
93
+ name: string;
94
+
95
+ /**
96
+ * Icon size preset
97
+ */
98
+ size?: IconSize;
99
+
100
+ /**
101
+ * Custom pixel size (overrides size preset)
102
+ */
103
+ customSize?: number;
104
+
105
+ /**
106
+ * Semantic color
107
+ */
108
+ color?: IconColor;
109
+
110
+ /**
111
+ * Custom hex color (overrides semantic color)
112
+ */
113
+ customColor?: string;
114
+
115
+ /**
116
+ * Stroke width for outline icons
117
+ */
118
+ strokeWidth?: number;
119
+
120
+ /**
121
+ * Background circle for icon
122
+ */
123
+ withBackground?: boolean;
124
+
125
+ /**
126
+ * Background color
127
+ */
128
+ backgroundColor?: string;
129
+
130
+ /**
131
+ * Accessibility label
132
+ */
133
+ accessibilityLabel?: string;
134
+
135
+ /**
136
+ * Test ID
137
+ */
138
+ testID?: string;
139
+
140
+ /**
141
+ * Custom styles
142
+ */
143
+ style?: any;
144
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Icons Domain - Centralized Icon System
3
+ *
4
+ * 🎯 SINGLE SOURCE OF TRUTH FOR ALL ICONS
5
+ *
6
+ * Universal icon library system with easy library switching.
7
+ * Change icon library = change one config file!
8
+ *
9
+ * @domain icons
10
+ * @enabled true (All apps)
11
+ *
12
+ * ARCHITECTURE:
13
+ * ```
14
+ * domains/icons/
15
+ * ├── domain/
16
+ * │ ├── config/
17
+ * │ │ └── IconLibraryConfig.ts 🔧 Change library here!
18
+ * │ └── interfaces/
19
+ * │ └── IIconAdapter.ts Interface for adapters
20
+ * ├── infrastructure/
21
+ * │ └── adapters/
22
+ * │ ├── LucideAdapter.ts Current: Lucide (1,639 icons)
23
+ * │ ├── MaterialAdapter.ts Future: Material Icons
24
+ * │ └── FontAwesomeAdapter.ts Future: Font Awesome
25
+ * └── presentation/
26
+ * └── components/
27
+ * └── Icon.tsx Universal Icon component
28
+ * ```
29
+ *
30
+ * USAGE:
31
+ * ```typescript
32
+ * import { Icon } from '@domains/icons';
33
+ *
34
+ * // Basic usage
35
+ * <Icon name="Settings" size="md" color="primary" />
36
+ *
37
+ * // Custom size and color
38
+ * <Icon name="Heart" customSize={32} customColor="#FF0000" />
39
+ *
40
+ * // With background
41
+ * <Icon name="Info" size="lg" withBackground backgroundColor="#667eea" />
42
+ * ```
43
+ *
44
+ * 🔧 TO CHANGE ICON LIBRARY:
45
+ *
46
+ * Step 1: Update package.json
47
+ * ```json
48
+ * {
49
+ * "dependencies": {
50
+ * "new-icon-library": "^1.0.0"
51
+ * }
52
+ * }
53
+ * ```
54
+ *
55
+ * Step 2: Change CURRENT_LIBRARY in domain/config/IconLibraryConfig.ts
56
+ * ```typescript
57
+ * export const CURRENT_LIBRARY: IconLibraryType = 'material'; // Changed!
58
+ * ```
59
+ *
60
+ * Step 3: Create adapter (if needed)
61
+ * ```typescript
62
+ * // infrastructure/adapters/MaterialAdapter.ts
63
+ * export const MaterialAdapter: IIconAdapter = {
64
+ * getIconComponent: (name) => MaterialIcons[name],
65
+ * // ... implement interface
66
+ * };
67
+ * ```
68
+ *
69
+ * Step 4: Done! All apps use new library automatically ✅
70
+ *
71
+ * CURRENT LIBRARY: Lucide (1,639 icons)
72
+ * @see https://lucide.dev/icons/
73
+ *
74
+ * DEPENDENCIES:
75
+ * - lucide-react-native: ^0.468.0 (Current library)
76
+ */
77
+
78
+ // ============================================================================
79
+ // PRESENTATION LAYER - Universal Icon Component
80
+ // ============================================================================
81
+
82
+ export { Icon } from './presentation/components/Icon';
83
+ export type {
84
+ IconProps,
85
+ IconSize,
86
+ IconColor,
87
+ IconName,
88
+ } from './presentation/components/Icon';
89
+
90
+ // ============================================================================
91
+ // DOMAIN LAYER - Configuration & Interfaces
92
+ // ============================================================================
93
+
94
+ export {
95
+ CURRENT_LIBRARY,
96
+ ICON_LIBRARY_CONFIG,
97
+ getCurrentLibrary,
98
+ isLucideLibrary,
99
+ } from './domain/config/IconLibraryConfig';
100
+ export type { IconLibraryType } from './domain/config/IconLibraryConfig';
101
+
102
+ export type { IIconAdapter } from './domain/interfaces/IIconAdapter';
103
+
104
+ // ============================================================================
105
+ // INFRASTRUCTURE LAYER - Adapters
106
+ // ============================================================================
107
+
108
+ export { LucideAdapter } from './infrastructure/adapters/LucideAdapter';
109
+ export type { LucideIconName } from './infrastructure/adapters/LucideAdapter';
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Lucide Icon Library Adapter
3
+ *
4
+ * Adapter for lucide-react-native library (1,639 icons).
5
+ * Implements IIconAdapter interface for seamless library switching.
6
+ *
7
+ * @library lucide-react-native
8
+ * @version ^0.468.0
9
+ * @icons 1,639
10
+ * @type outline
11
+ *
12
+ * @see https://lucide.dev/icons/
13
+ */
14
+
15
+ import { icons } from 'lucide-react-native';
16
+ import type { IIconAdapter, IconSize, IconColor } from '../../domain/interfaces/IIconAdapter';
17
+ import type { DesignTokens } from '@umituz/react-native-design-system';
18
+
19
+ /**
20
+ * Size mapping: Semantic → Pixels
21
+ */
22
+ const SIZE_MAP: Record<IconSize, number> = {
23
+ xs: 16,
24
+ sm: 20,
25
+ md: 24,
26
+ lg: 28,
27
+ xl: 32,
28
+ xxl: 40,
29
+ };
30
+
31
+ /**
32
+ * Lucide Adapter Implementation
33
+ */
34
+ export const LucideAdapter: IIconAdapter = {
35
+ /**
36
+ * Get Lucide icon component by name
37
+ */
38
+ getIconComponent: (name: string) => {
39
+ const IconComponent = icons[name as keyof typeof icons];
40
+ if (!IconComponent) {
41
+ console.warn(`[LucideAdapter] Icon "${name}" not found in Lucide library`);
42
+ return null;
43
+ }
44
+ return IconComponent;
45
+ },
46
+
47
+ /**
48
+ * Get icon size in pixels
49
+ */
50
+ getIconSize: (size: IconSize, customSize?: number) => {
51
+ return customSize || SIZE_MAP[size];
52
+ },
53
+
54
+ /**
55
+ * Get icon color from theme
56
+ */
57
+ getIconColor: (color: IconColor, tokens: DesignTokens, customColor?: string) => {
58
+ if (customColor) return customColor;
59
+
60
+ const colorMap: Record<IconColor, string> = {
61
+ primary: tokens.colors.primary,
62
+ secondary: tokens.colors.secondary,
63
+ success: tokens.colors.success,
64
+ warning: tokens.colors.warning,
65
+ error: tokens.colors.error,
66
+ info: tokens.colors.info,
67
+ onSurface: tokens.colors.onSurface,
68
+ surfaceVariant: tokens.colors.surfaceVariant,
69
+ onPrimary: tokens.colors.onPrimary,
70
+ onSecondary: tokens.colors.onSecondary,
71
+ textInverse: tokens.colors.textInverse,
72
+ };
73
+
74
+ return colorMap[color];
75
+ },
76
+
77
+ /**
78
+ * Get all available Lucide icon names
79
+ */
80
+ getAllIcons: () => {
81
+ return Object.keys(icons);
82
+ },
83
+
84
+ /**
85
+ * Check if icon exists in Lucide library
86
+ */
87
+ hasIcon: (name: string) => {
88
+ return name in icons;
89
+ },
90
+
91
+ /**
92
+ * Default stroke width for Lucide outline icons
93
+ */
94
+ getStrokeWidth: () => 2,
95
+ };
96
+
97
+ /**
98
+ * Lucide icon names type (for TypeScript autocomplete)
99
+ */
100
+ export type LucideIconName = keyof typeof icons;
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Icons Domain - Expo Vector Icons Registry
3
+ *
4
+ * Registry for @expo/vector-icons (Material, FontAwesome, Ionicons).
5
+ * Provides metadata and search capabilities for 1000+ icons.
6
+ *
7
+ * @domain icons
8
+ * @layer infrastructure
9
+ */
10
+
11
+ import type { IIconRegistry, IconMetadata } from '@domains/icons/domain/entities/Icon';
12
+ import { IconLibrary, IconCategory } from '@domains/icons/domain/entities/Icon';
13
+
14
+ /**
15
+ * Expo vector icons registry
16
+ * Maps common Material Design, FontAwesome, and Ionicons
17
+ */
18
+ export class ExpoIconRegistry implements IIconRegistry {
19
+ private icons: IconMetadata[] = [
20
+ // Navigation icons (Material Design)
21
+ {
22
+ name: 'home',
23
+ library: IconLibrary.MATERIAL,
24
+ category: IconCategory.NAVIGATION,
25
+ tags: ['house', 'main', 'start'],
26
+ searchTerms: ['home', 'house', 'main', 'dashboard'],
27
+ },
28
+ {
29
+ name: 'arrow-back',
30
+ library: IconLibrary.MATERIAL,
31
+ category: IconCategory.NAVIGATION,
32
+ tags: ['back', 'previous', 'return'],
33
+ searchTerms: ['arrow', 'back', 'previous', 'navigate'],
34
+ },
35
+ {
36
+ name: 'menu',
37
+ library: IconLibrary.MATERIAL,
38
+ category: IconCategory.NAVIGATION,
39
+ tags: ['hamburger', 'drawer', 'navigation'],
40
+ searchTerms: ['menu', 'hamburger', 'navigation', 'drawer'],
41
+ },
42
+ {
43
+ name: 'search',
44
+ library: IconLibrary.MATERIAL,
45
+ category: IconCategory.ACTION,
46
+ tags: ['find', 'lookup', 'query'],
47
+ searchTerms: ['search', 'find', 'lookup', 'magnify'],
48
+ },
49
+
50
+ // Action icons (Material Design)
51
+ {
52
+ name: 'add',
53
+ library: IconLibrary.MATERIAL,
54
+ category: IconCategory.ACTION,
55
+ tags: ['plus', 'create', 'new'],
56
+ searchTerms: ['add', 'plus', 'create', 'new'],
57
+ },
58
+ {
59
+ name: 'delete',
60
+ library: IconLibrary.MATERIAL,
61
+ category: IconCategory.ACTION,
62
+ tags: ['remove', 'trash', 'bin'],
63
+ searchTerms: ['delete', 'remove', 'trash', 'garbage'],
64
+ },
65
+ {
66
+ name: 'edit',
67
+ library: IconLibrary.MATERIAL,
68
+ category: IconCategory.ACTION,
69
+ tags: ['pencil', 'modify', 'update'],
70
+ searchTerms: ['edit', 'pencil', 'modify', 'write'],
71
+ },
72
+ {
73
+ name: 'settings',
74
+ library: IconLibrary.MATERIAL,
75
+ category: IconCategory.ACTION,
76
+ tags: ['gear', 'preferences', 'config'],
77
+ searchTerms: ['settings', 'gear', 'preferences', 'options'],
78
+ },
79
+ {
80
+ name: 'favorite',
81
+ library: IconLibrary.MATERIAL,
82
+ category: IconCategory.ACTION,
83
+ tags: ['heart', 'like', 'love'],
84
+ searchTerms: ['favorite', 'heart', 'like', 'love'],
85
+ },
86
+
87
+ // Social icons (FontAwesome)
88
+ {
89
+ name: 'facebook',
90
+ library: IconLibrary.FONTAWESOME,
91
+ category: IconCategory.SOCIAL,
92
+ tags: ['fb', 'social', 'network'],
93
+ searchTerms: ['facebook', 'fb', 'social', 'meta'],
94
+ },
95
+ {
96
+ name: 'twitter',
97
+ library: IconLibrary.FONTAWESOME,
98
+ category: IconCategory.SOCIAL,
99
+ tags: ['x', 'social', 'tweet'],
100
+ searchTerms: ['twitter', 'x', 'social', 'tweet'],
101
+ },
102
+ {
103
+ name: 'instagram',
104
+ library: IconLibrary.FONTAWESOME,
105
+ category: IconCategory.SOCIAL,
106
+ tags: ['ig', 'social', 'photo'],
107
+ searchTerms: ['instagram', 'ig', 'social', 'photo'],
108
+ },
109
+
110
+ // Communication icons (Ionicons)
111
+ {
112
+ name: 'mail',
113
+ library: IconLibrary.IONICONS,
114
+ category: IconCategory.COMMUNICATION,
115
+ tags: ['email', 'message', 'envelope'],
116
+ searchTerms: ['mail', 'email', 'message', 'contact'],
117
+ },
118
+ {
119
+ name: 'call',
120
+ library: IconLibrary.IONICONS,
121
+ category: IconCategory.COMMUNICATION,
122
+ tags: ['phone', 'telephone', 'dial'],
123
+ searchTerms: ['call', 'phone', 'telephone', 'dial'],
124
+ },
125
+ {
126
+ name: 'notifications',
127
+ library: IconLibrary.IONICONS,
128
+ category: IconCategory.COMMUNICATION,
129
+ tags: ['bell', 'alert', 'reminder'],
130
+ searchTerms: ['notifications', 'bell', 'alert', 'reminder'],
131
+ },
132
+
133
+ // Media icons (Material Design)
134
+ {
135
+ name: 'camera',
136
+ library: IconLibrary.MATERIAL,
137
+ category: IconCategory.MEDIA,
138
+ tags: ['photo', 'picture', 'snapshot'],
139
+ searchTerms: ['camera', 'photo', 'picture', 'image'],
140
+ },
141
+ {
142
+ name: 'image',
143
+ library: IconLibrary.MATERIAL,
144
+ category: IconCategory.MEDIA,
145
+ tags: ['photo', 'picture', 'gallery'],
146
+ searchTerms: ['image', 'photo', 'picture', 'gallery'],
147
+ },
148
+ {
149
+ name: 'videocam',
150
+ library: IconLibrary.MATERIAL,
151
+ category: IconCategory.MEDIA,
152
+ tags: ['video', 'camera', 'record'],
153
+ searchTerms: ['video', 'camera', 'record', 'film'],
154
+ },
155
+ ];
156
+
157
+ getAllIcons(): IconMetadata[] {
158
+ return this.icons;
159
+ }
160
+
161
+ getIconsByCategory(category: IconCategory): IconMetadata[] {
162
+ if (category === IconCategory.ALL) {
163
+ return this.icons;
164
+ }
165
+ return this.icons.filter(icon => icon.category === category);
166
+ }
167
+
168
+ searchIcons(query: string): IconMetadata[] {
169
+ if (!query.trim()) {
170
+ return this.icons;
171
+ }
172
+
173
+ const normalizedQuery = query.toLowerCase().replace(/[^a-z0-9]/g, '');
174
+
175
+ return this.icons.filter(icon => {
176
+ const normalizedName = icon.name.toLowerCase().replace(/[^a-z0-9]/g, '');
177
+ const normalizedTags = icon.tags.map(tag => tag.toLowerCase().replace(/[^a-z0-9]/g, ''));
178
+ const normalizedTerms = icon.searchTerms.map(term => term.toLowerCase().replace(/[^a-z0-9]/g, ''));
179
+
180
+ return (
181
+ normalizedName.includes(normalizedQuery) ||
182
+ normalizedTags.some(tag => tag.includes(normalizedQuery)) ||
183
+ normalizedTerms.some(term => term.includes(normalizedQuery))
184
+ );
185
+ });
186
+ }
187
+
188
+ getIconMetadata(name: string): IconMetadata | null {
189
+ return this.icons.find(icon => icon.name === name) || null;
190
+ }
191
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Universal Icon Component
3
+ *
4
+ * 🎯 SINGLE ICON COMPONENT FOR ALL APPS
5
+ *
6
+ * Automatically uses the icon library configured in IconLibraryConfig.
7
+ * Change library = change config, no code changes needed!
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * import { Icon } from '@domains/icons';
12
+ *
13
+ * // Basic usage
14
+ * <Icon name="Settings" size="md" color="primary" />
15
+ *
16
+ * // Custom size and color
17
+ * <Icon name="Heart" customSize={32} customColor="#FF0000" />
18
+ *
19
+ * // With background
20
+ * <Icon name="Info" size="lg" withBackground backgroundColor="#667eea" />
21
+ * ```
22
+ *
23
+ * 🔧 To change icon library:
24
+ * 1. Update CURRENT_LIBRARY in domain/config/IconLibraryConfig.ts
25
+ * 2. Done! All apps use new library automatically
26
+ */
27
+
28
+ import React from 'react';
29
+ import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
30
+ import { useAppDesignTokens } from '../../../../presentation/hooks/useAppDesignTokens';
31
+ import { CURRENT_LIBRARY } from '../../domain/config/IconLibraryConfig';
32
+ import { LucideAdapter } from '../../infrastructure/adapters/LucideAdapter';
33
+ import type { IconProps } from '../../domain/interfaces/IIconAdapter';
34
+
35
+ /**
36
+ * Get adapter based on current library configuration
37
+ */
38
+ const getAdapter = () => {
39
+ switch (CURRENT_LIBRARY) {
40
+ case 'lucide':
41
+ return LucideAdapter;
42
+ // Future: Add more adapters here
43
+ // case 'material':
44
+ // return MaterialAdapter;
45
+ // case 'fontawesome':
46
+ // return FontAwesomeAdapter;
47
+ default:
48
+ return LucideAdapter;
49
+ }
50
+ };
51
+
52
+ /**
53
+ * Universal Icon Component
54
+ */
55
+ export const Icon: React.FC<IconProps> = ({
56
+ name,
57
+ size = 'md',
58
+ customSize,
59
+ color = 'onSurface',
60
+ customColor,
61
+ strokeWidth,
62
+ withBackground = false,
63
+ backgroundColor,
64
+ accessibilityLabel,
65
+ testID,
66
+ style,
67
+ }) => {
68
+ const tokens = useAppDesignTokens();
69
+ const adapter = getAdapter();
70
+
71
+ // Get icon component from adapter
72
+ const IconComponent = adapter.getIconComponent(name);
73
+
74
+ if (!IconComponent) {
75
+ return null;
76
+ }
77
+
78
+ // Calculate icon size
79
+ const iconSize = adapter.getIconSize(size, customSize);
80
+
81
+ // Get icon color from theme
82
+ const iconColor = adapter.getIconColor(color, tokens, customColor);
83
+
84
+ // Get stroke width (for outline icons)
85
+ const iconStrokeWidth = strokeWidth || adapter.getStrokeWidth?.() || 2;
86
+
87
+ // Container size (slightly larger than icon)
88
+ const containerSize = iconSize + 8;
89
+
90
+ const containerStyles: StyleProp<ViewStyle> = [
91
+ withBackground && {
92
+ width: containerSize,
93
+ height: containerSize,
94
+ borderRadius: containerSize / 2,
95
+ backgroundColor: backgroundColor || tokens.colors.surfaceVariant,
96
+ justifyContent: 'center',
97
+ alignItems: 'center',
98
+ },
99
+ style,
100
+ ];
101
+
102
+ const IconElement = (
103
+ <IconComponent
104
+ size={iconSize}
105
+ color={iconColor}
106
+ strokeWidth={iconStrokeWidth}
107
+ accessibilityLabel={accessibilityLabel || `${name} icon`}
108
+ testID={testID}
109
+ />
110
+ );
111
+
112
+ if (withBackground) {
113
+ return (
114
+ <View style={containerStyles} testID={`${testID}-container`}>
115
+ {IconElement}
116
+ </View>
117
+ );
118
+ }
119
+
120
+ return IconElement;
121
+ };
122
+
123
+ /**
124
+ * Export icon types for convenience
125
+ */
126
+ export type { IconProps } from '../../domain/interfaces/IIconAdapter';
127
+ export { type IconSize, type IconColor } from '../../domain/interfaces/IIconAdapter';
128
+
129
+ /**
130
+ * Export current library's icon names for TypeScript autocomplete
131
+ */
132
+ export type { LucideIconName as IconName } from '../../infrastructure/adapters/LucideAdapter';
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Icons Domain - useIconLibrary Hook
3
+ *
4
+ * React hook for accessing icon libraries (Lucide + Expo vector icons).
5
+ * Provides search, filter, and metadata access for all available icons.
6
+ *
7
+ * @domain icons
8
+ * @layer presentation
9
+ */
10
+
11
+ import { useMemo, useState, useCallback } from 'react';
12
+ import type { IconMetadata } from '@domains/icons/domain/entities/Icon';
13
+ import { IconLibrary, IconCategory, IconUtils, ICON_CONSTANTS } from '@domains/icons/domain/entities/Icon';
14
+ import { ExpoIconRegistry } from '@domains/icons/infrastructure/registries/ExpoIconRegistry';
15
+
16
+ /**
17
+ * Hook for icon library access and search
18
+ *
19
+ * @example
20
+ * const { icons, searchIcons, filterByCategory } = useIconLibrary();
21
+ *
22
+ * // Search icons
23
+ * const results = searchIcons('home');
24
+ *
25
+ * // Filter by category
26
+ * const navIcons = filterByCategory(IconCategory.NAVIGATION);
27
+ */
28
+ export const useIconLibrary = (defaultLibrary: IconLibrary = ICON_CONSTANTS.DEFAULT_LIBRARY) => {
29
+ const [selectedLibrary, setSelectedLibrary] = useState<IconLibrary>(defaultLibrary);
30
+ const [selectedCategory, setSelectedCategory] = useState<IconCategory>(IconCategory.ALL);
31
+
32
+ // Initialize registry
33
+ const registry = useMemo(() => new ExpoIconRegistry(), []);
34
+
35
+ /**
36
+ * Get all icons from the selected library
37
+ */
38
+ const icons = useMemo(() => {
39
+ const allIcons = registry.getAllIcons();
40
+ return selectedLibrary === IconLibrary.LUCIDE
41
+ ? [] // Lucide icons are in design-system/AtomicIcon
42
+ : allIcons.filter(icon => icon.library === selectedLibrary);
43
+ }, [registry, selectedLibrary]);
44
+
45
+ /**
46
+ * Get icons filtered by category
47
+ */
48
+ const iconsByCategory = useMemo(() => {
49
+ return IconUtils.filterByCategory(icons, selectedCategory);
50
+ }, [icons, selectedCategory]);
51
+
52
+ /**
53
+ * Search icons by query
54
+ */
55
+ const searchIcons = useCallback(
56
+ (query: string): IconMetadata[] => {
57
+ if (!query.trim()) {
58
+ return iconsByCategory;
59
+ }
60
+
61
+ const results = registry.searchIcons(query);
62
+ const filteredResults = selectedLibrary === IconLibrary.LUCIDE
63
+ ? results
64
+ : results.filter(icon => icon.library === selectedLibrary);
65
+
66
+ return IconUtils.filterByCategory(filteredResults, selectedCategory)
67
+ .slice(0, ICON_CONSTANTS.MAX_SEARCH_RESULTS);
68
+ },
69
+ [registry, selectedLibrary, selectedCategory, iconsByCategory]
70
+ );
71
+
72
+ /**
73
+ * Filter icons by category
74
+ */
75
+ const filterByCategory = useCallback(
76
+ (category: IconCategory): IconMetadata[] => {
77
+ return IconUtils.filterByCategory(icons, category);
78
+ },
79
+ [icons]
80
+ );
81
+
82
+ /**
83
+ * Get icon metadata by name
84
+ */
85
+ const getIconMetadata = useCallback(
86
+ (name: string): IconMetadata | null => {
87
+ return registry.getIconMetadata(name);
88
+ },
89
+ [registry]
90
+ );
91
+
92
+ /**
93
+ * Get all available categories
94
+ */
95
+ const availableCategories = useMemo(() => {
96
+ return Object.values(IconCategory);
97
+ }, []);
98
+
99
+ /**
100
+ * Get all available libraries
101
+ */
102
+ const availableLibraries = useMemo(() => {
103
+ return Object.values(IconLibrary);
104
+ }, []);
105
+
106
+ /**
107
+ * Switch library
108
+ */
109
+ const switchLibrary = useCallback((library: IconLibrary) => {
110
+ setSelectedLibrary(library);
111
+ }, []);
112
+
113
+ /**
114
+ * Switch category
115
+ */
116
+ const switchCategory = useCallback((category: IconCategory) => {
117
+ setSelectedCategory(category);
118
+ }, []);
119
+
120
+ return {
121
+ // Current state
122
+ selectedLibrary,
123
+ selectedCategory,
124
+ icons: iconsByCategory,
125
+
126
+ // Search & filter
127
+ searchIcons,
128
+ filterByCategory,
129
+ getIconMetadata,
130
+
131
+ // Library & category management
132
+ switchLibrary,
133
+ switchCategory,
134
+ availableCategories,
135
+ availableLibraries,
136
+
137
+ // Constants
138
+ IconLibrary,
139
+ IconCategory,
140
+ };
141
+ };
package/src/index.ts CHANGED
@@ -351,3 +351,15 @@ export {
351
351
  export {
352
352
  useDesignSystemTheme,
353
353
  } from './infrastructure/theme/globalThemeStore';
354
+
355
+ // =============================================================================
356
+ // ICONS DOMAIN - Universal Icon System
357
+ // =============================================================================
358
+
359
+ export {
360
+ Icon,
361
+ type IconProps,
362
+ type IconSize,
363
+ type IconColor,
364
+ type IconName,
365
+ } from './domains/icons/presentation/components/Icon';
@@ -1,132 +1,41 @@
1
1
  /**
2
- * AtomicIcon - Design System Icon Component
2
+ * AtomicIcon - Atomic Design System Icon Component
3
3
  *
4
- * Universal icon component using Lucide icons.
5
- * Provides semantic color mappings and size presets.
4
+ * Wrapper for the universal Icon component from @domains/icons
5
+ * Provides backward compatibility with AtomicIcon naming convention
6
+ * while leveraging the full power of the icons domain architecture.
6
7
  */
7
8
 
8
9
  import React from 'react';
9
- import type { ViewStyle } from 'react-native';
10
- import * as LucideIcons from 'lucide-react-native';
11
- import { useAppDesignTokens } from '../hooks/useAppDesignTokens';
12
-
13
- /**
14
- * Icon size presets
15
- */
16
- export type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';
17
-
18
- /**
19
- * Semantic color tokens
20
- */
21
- export type IconColor =
22
- | 'primary'
23
- | 'secondary'
24
- | 'error'
25
- | 'warning'
26
- | 'success'
27
- | 'info'
28
- | 'onPrimary'
29
- | 'onSurface'
30
- | 'textPrimary'
31
- | 'textSecondary'
32
- | 'textDisabled';
33
-
34
- /**
35
- * Icon component props
36
- */
37
- export interface IconProps {
38
- /** Icon name from Lucide icon set (PascalCase) */
39
- name: string;
40
- /** Semantic color token */
41
- color?: IconColor;
42
- /** Size preset */
43
- size?: IconSize;
44
- /** Custom size override (pixels) */
45
- customSize?: number;
46
- /** Custom color override (hex) */
47
- customColor?: string;
48
- /** Optional style */
49
- style?: ViewStyle;
50
- /** Optional test ID */
51
- testID?: string;
52
- /** Legacy prop support: icon (alias for name) */
53
- icon?: string;
54
- }
55
-
56
- /**
57
- * Icon name type (all Lucide icon names as string)
58
- */
59
- export type IconName = string;
60
-
61
- /**
62
- * Size mapping (pixels)
63
- */
64
- const sizeMap: Record<IconSize, number> = {
65
- xs: 16,
66
- sm: 20,
67
- md: 24,
68
- lg: 28,
69
- xl: 32,
70
- xxl: 48,
71
- };
10
+ import { Icon } from '../../domains/icons/presentation/components/Icon';
11
+ import type { IconProps, IconSize, IconColor } from '../../domains/icons/domain/interfaces/IIconAdapter';
12
+ import type { LucideIconName } from '../../domains/icons/infrastructure/adapters/LucideAdapter';
72
13
 
73
14
  /**
74
15
  * AtomicIcon Component
75
16
  *
76
- * Universal icon component with theme integration
17
+ * @example
18
+ * ```tsx
19
+ * import { AtomicIcon } from '@umituz/react-native-design-system';
20
+ *
21
+ * // Basic usage
22
+ * <AtomicIcon name="Settings" size="md" color="primary" />
23
+ *
24
+ * // Custom size and color
25
+ * <AtomicIcon name="Heart" customSize={32} customColor="#FF0000" />
26
+ *
27
+ * // With background
28
+ * <AtomicIcon name="Info" size="lg" withBackground backgroundColor="#667eea" />
29
+ * ```
77
30
  */
78
- export const AtomicIcon: React.FC<IconProps> = ({
79
- name,
80
- icon, // Legacy support
81
- color = 'textPrimary',
82
- size = 'md',
83
- customSize,
84
- customColor,
85
- style,
86
- testID,
87
- }) => {
88
- const tokens = useAppDesignTokens();
89
-
90
- // Support legacy 'icon' prop (fallback to 'name')
91
- const iconName = name || icon || '';
92
-
93
- // Get icon component from Lucide
94
- const IconComponent = (LucideIcons as any)[iconName];
95
-
96
- if (!IconComponent) {
97
- console.warn(`Icon "${iconName}" not found in Lucide icon set`);
98
- return null;
99
- }
100
-
101
- // Resolve color from semantic token
102
- const resolveColor = (): string => {
103
- if (customColor) return customColor;
104
-
105
- const colorMap: Record<IconColor, string> = {
106
- primary: tokens.colors.primary,
107
- secondary: tokens.colors.secondary,
108
- error: tokens.colors.error,
109
- warning: tokens.colors.warning,
110
- success: tokens.colors.success,
111
- info: tokens.colors.info,
112
- onPrimary: tokens.colors.onPrimary,
113
- onSurface: tokens.colors.onSurface,
114
- textPrimary: tokens.colors.textPrimary,
115
- textSecondary: tokens.colors.textSecondary,
116
- textDisabled: tokens.colors.textDisabled,
117
- };
118
-
119
- return colorMap[color];
120
- };
121
-
122
- // Resolve size
123
- const iconSize = customSize || sizeMap[size];
124
-
125
- return <IconComponent color={resolveColor()} size={iconSize} style={style} testID={testID} />;
31
+ export const AtomicIcon: React.FC<IconProps> = (props) => {
32
+ return <Icon {...props} />;
126
33
  };
127
34
 
128
- // Re-export types for backward compatibility
35
+ /**
36
+ * Re-export types with Atomic naming convention
37
+ */
129
38
  export type AtomicIconProps = IconProps;
130
39
  export type AtomicIconSize = IconSize;
131
40
  export type AtomicIconColor = IconColor;
132
- export type AtomicIconName = IconName;
41
+ export type AtomicIconName = LucideIconName;