@praxiis/ui 0.0.1

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 (187) hide show
  1. package/dist/index.d.mts +52556 -0
  2. package/dist/index.d.ts +52556 -0
  3. package/dist/index.js +8753 -0
  4. package/dist/index.mjs +8777 -0
  5. package/package.json +70 -0
  6. package/src/__test-utils__/index.tsx +39 -0
  7. package/src/components/CalendarStrip/CalendarStrip.helpers.ts +106 -0
  8. package/src/components/CalendarStrip/CalendarStrip.tsx +83 -0
  9. package/src/components/CalendarStrip/CalendarStrip.types.ts +133 -0
  10. package/src/components/CalendarStrip/DayCard/DayCard.helpers.ts +44 -0
  11. package/src/components/CalendarStrip/DayCard/DayCard.tsx +71 -0
  12. package/src/components/CalendarStrip/DayCard/DayCard.types.ts +134 -0
  13. package/src/components/CalendarStrip/DayCard/index.ts +2 -0
  14. package/src/components/CalendarStrip/DayCard/useDayCardLogic.ts +45 -0
  15. package/src/components/CalendarStrip/index.ts +9 -0
  16. package/src/components/CalendarStrip/useCalendarStripLogic.ts +53 -0
  17. package/src/components/EmptyState/EmptyState.helpers.ts +104 -0
  18. package/src/components/EmptyState/EmptyState.tsx +205 -0
  19. package/src/components/EmptyState/EmptyState.types.ts +213 -0
  20. package/src/components/EmptyState/index.ts +44 -0
  21. package/src/components/EmptyState/useEmptyStateLogic.ts +131 -0
  22. package/src/components/Header/Header.helpers.ts +93 -0
  23. package/src/components/Header/Header.tsx +185 -0
  24. package/src/components/Header/Header.types.ts +153 -0
  25. package/src/components/Header/index.ts +44 -0
  26. package/src/components/Header/useHeaderLogic.ts +146 -0
  27. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.helpers.ts +50 -0
  28. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.tsx +78 -0
  29. package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.types.ts +99 -0
  30. package/src/components/ScheduleItem/ScheduleItem/index.ts +16 -0
  31. package/src/components/ScheduleItem/ScheduleItem/useScheduleItemLogic.ts +31 -0
  32. package/src/components/ScheduleItem/index.ts +15 -0
  33. package/src/components/index.ts +40 -0
  34. package/src/core/index.ts +34 -0
  35. package/src/core/restyle/RestyleThemeProviderWrapper.tsx +31 -0
  36. package/src/core/restyle/index.ts +38 -0
  37. package/src/core/restyle/restylePresetRegistry.ts +195 -0
  38. package/src/core/restyle/restyleTheme.ts +1352 -0
  39. package/src/core/restyle/restyleTypes.ts +8 -0
  40. package/src/core/restyle/useRestyleTheme.ts +10 -0
  41. package/src/hooks/animations/index.ts +3 -0
  42. package/src/hooks/animations/useAnimatedValue.ts +10 -0
  43. package/src/hooks/animations/useEntranceAnimation.ts +106 -0
  44. package/src/hooks/animations/usePulseAnimation.ts +63 -0
  45. package/src/hooks/index.ts +30 -0
  46. package/src/hooks/useReducedMotion.ts +60 -0
  47. package/src/i18n/index.ts +2 -0
  48. package/src/i18n/labels/en.ts +120 -0
  49. package/src/i18n/labels/es.ts +120 -0
  50. package/src/i18n/labels/index.ts +6 -0
  51. package/src/i18n/labels/types.ts +165 -0
  52. package/src/index.tsx +215 -0
  53. package/src/primitives/actions/Button/Button.helpers.ts +243 -0
  54. package/src/primitives/actions/Button/Button.tsx +198 -0
  55. package/src/primitives/actions/Button/Button.types.ts +207 -0
  56. package/src/primitives/actions/Button/index.ts +41 -0
  57. package/src/primitives/actions/Button/useButtonLogic.ts +160 -0
  58. package/src/primitives/actions/IconButton/IconButton.helpers.ts +235 -0
  59. package/src/primitives/actions/IconButton/IconButton.tsx +177 -0
  60. package/src/primitives/actions/IconButton/IconButton.types.ts +273 -0
  61. package/src/primitives/actions/IconButton/index.ts +30 -0
  62. package/src/primitives/actions/IconButton/useIconButtonLogic.ts +172 -0
  63. package/src/primitives/actions/index.ts +20 -0
  64. package/src/primitives/content/Avatar/Avatar.helpers.ts +177 -0
  65. package/src/primitives/content/Avatar/Avatar.tsx +199 -0
  66. package/src/primitives/content/Avatar/Avatar.types.ts +222 -0
  67. package/src/primitives/content/Avatar/index.ts +46 -0
  68. package/src/primitives/content/Avatar/useAvatarLogic.ts +149 -0
  69. package/src/primitives/content/Badge/Badge.helpers.ts +175 -0
  70. package/src/primitives/content/Badge/Badge.tsx +174 -0
  71. package/src/primitives/content/Badge/Badge.types.ts +223 -0
  72. package/src/primitives/content/Badge/index.ts +40 -0
  73. package/src/primitives/content/Badge/useBadgeLogic.ts +128 -0
  74. package/src/primitives/content/Card/Card.helpers.ts +27 -0
  75. package/src/primitives/content/Card/Card.tsx +123 -0
  76. package/src/primitives/content/Card/Card.types.ts +95 -0
  77. package/src/primitives/content/Card/index.ts +20 -0
  78. package/src/primitives/content/Card/useCardLogic.ts +48 -0
  79. package/src/primitives/content/Chip/Chip.helpers.ts +304 -0
  80. package/src/primitives/content/Chip/Chip.tsx +205 -0
  81. package/src/primitives/content/Chip/Chip.types.ts +234 -0
  82. package/src/primitives/content/Chip/index.ts +47 -0
  83. package/src/primitives/content/Chip/useChipLogic.ts +167 -0
  84. package/src/primitives/content/Icon/Icon.helpers.ts +54 -0
  85. package/src/primitives/content/Icon/Icon.tsx +110 -0
  86. package/src/primitives/content/Icon/Icon.types.ts +95 -0
  87. package/src/primitives/content/Icon/index.ts +20 -0
  88. package/src/primitives/content/Icon/useIconLogic.ts +73 -0
  89. package/src/primitives/content/index.ts +45 -0
  90. package/src/primitives/feedback/ProgressBar/ProgressBar.helpers.ts +122 -0
  91. package/src/primitives/feedback/ProgressBar/ProgressBar.tsx +154 -0
  92. package/src/primitives/feedback/ProgressBar/ProgressBar.types.ts +178 -0
  93. package/src/primitives/feedback/ProgressBar/index.ts +17 -0
  94. package/src/primitives/feedback/ProgressBar/useProgressBarLogic.ts +120 -0
  95. package/src/primitives/feedback/Skeleton/Skeleton.helpers.ts +145 -0
  96. package/src/primitives/feedback/Skeleton/Skeleton.tsx +155 -0
  97. package/src/primitives/feedback/Skeleton/Skeleton.types.ts +223 -0
  98. package/src/primitives/feedback/Skeleton/index.ts +44 -0
  99. package/src/primitives/feedback/Skeleton/useSkeletonLogic.ts +125 -0
  100. package/src/primitives/feedback/Spinner/Spinner.helpers.ts +40 -0
  101. package/src/primitives/feedback/Spinner/Spinner.tsx +105 -0
  102. package/src/primitives/feedback/Spinner/Spinner.types.ts +114 -0
  103. package/src/primitives/feedback/Spinner/index.ts +18 -0
  104. package/src/primitives/feedback/Spinner/useSpinnerLogic.ts +84 -0
  105. package/src/primitives/feedback/Toast/Toast.helpers.ts +163 -0
  106. package/src/primitives/feedback/Toast/Toast.tsx +190 -0
  107. package/src/primitives/feedback/Toast/Toast.types.ts +270 -0
  108. package/src/primitives/feedback/Toast/ToastContext.tsx +96 -0
  109. package/src/primitives/feedback/Toast/ToastProvider.tsx +241 -0
  110. package/src/primitives/feedback/Toast/index.ts +59 -0
  111. package/src/primitives/feedback/Toast/useToastLogic.ts +112 -0
  112. package/src/primitives/feedback/index.ts +45 -0
  113. package/src/primitives/index.ts +158 -0
  114. package/src/primitives/inputs/Checkbox/Checkbox.helpers.ts +132 -0
  115. package/src/primitives/inputs/Checkbox/Checkbox.tsx +150 -0
  116. package/src/primitives/inputs/Checkbox/Checkbox.types.ts +106 -0
  117. package/src/primitives/inputs/Checkbox/index.ts +30 -0
  118. package/src/primitives/inputs/Checkbox/useCheckboxLogic.ts +121 -0
  119. package/src/primitives/inputs/RadioButton/RadioButton.helpers.ts +123 -0
  120. package/src/primitives/inputs/RadioButton/RadioButton.tsx +159 -0
  121. package/src/primitives/inputs/RadioButton/RadioButton.types.ts +106 -0
  122. package/src/primitives/inputs/RadioButton/index.ts +25 -0
  123. package/src/primitives/inputs/RadioButton/useRadioButtonLogic.ts +117 -0
  124. package/src/primitives/inputs/SegmentedControl/SegmentedControl.helpers.ts +174 -0
  125. package/src/primitives/inputs/SegmentedControl/SegmentedControl.tsx +224 -0
  126. package/src/primitives/inputs/SegmentedControl/SegmentedControl.types.ts +187 -0
  127. package/src/primitives/inputs/SegmentedControl/index.ts +39 -0
  128. package/src/primitives/inputs/SegmentedControl/useSegmentedControlLogic.ts +151 -0
  129. package/src/primitives/inputs/SelectSheet/SelectSheet.helpers.ts +147 -0
  130. package/src/primitives/inputs/SelectSheet/SelectSheet.tsx +247 -0
  131. package/src/primitives/inputs/SelectSheet/SelectSheet.types.ts +196 -0
  132. package/src/primitives/inputs/SelectSheet/SelectSheetOption.tsx +177 -0
  133. package/src/primitives/inputs/SelectSheet/index.ts +48 -0
  134. package/src/primitives/inputs/SelectSheet/useSelectSheetLogic.ts +309 -0
  135. package/src/primitives/inputs/Switch/Switch.helpers.ts +109 -0
  136. package/src/primitives/inputs/Switch/Switch.tsx +191 -0
  137. package/src/primitives/inputs/Switch/Switch.types.ts +154 -0
  138. package/src/primitives/inputs/Switch/index.ts +40 -0
  139. package/src/primitives/inputs/Switch/useSwitchLogic.ts +192 -0
  140. package/src/primitives/inputs/TextInput/TextInput.helpers.ts +206 -0
  141. package/src/primitives/inputs/TextInput/TextInput.tsx +392 -0
  142. package/src/primitives/inputs/TextInput/TextInput.types.ts +216 -0
  143. package/src/primitives/inputs/TextInput/index.ts +37 -0
  144. package/src/primitives/inputs/TextInput/useTextInputLogic.ts +195 -0
  145. package/src/primitives/inputs/index.ts +52 -0
  146. package/src/primitives/layout/AnimatedBox.tsx +44 -0
  147. package/src/primitives/layout/Box.tsx +71 -0
  148. package/src/primitives/layout/Divider/Divider.helpers.ts +115 -0
  149. package/src/primitives/layout/Divider/Divider.tsx +139 -0
  150. package/src/primitives/layout/Divider/Divider.types.ts +178 -0
  151. package/src/primitives/layout/Divider/index.ts +24 -0
  152. package/src/primitives/layout/Divider/useDividerLogic.ts +109 -0
  153. package/src/primitives/layout/FlatList.tsx +66 -0
  154. package/src/primitives/layout/Pressable.tsx +74 -0
  155. package/src/primitives/layout/ScrollView.tsx +63 -0
  156. package/src/primitives/layout/Stack.tsx +69 -0
  157. package/src/primitives/layout/index.ts +40 -0
  158. package/src/primitives/navigation/index.ts +6 -0
  159. package/src/primitives/overlays/Modal/Modal.helpers.ts +31 -0
  160. package/src/primitives/overlays/Modal/Modal.tsx +264 -0
  161. package/src/primitives/overlays/Modal/Modal.types.ts +193 -0
  162. package/src/primitives/overlays/Modal/index.ts +43 -0
  163. package/src/primitives/overlays/Modal/useModalLogic.ts +103 -0
  164. package/src/primitives/overlays/index.ts +12 -0
  165. package/src/primitives/typography/Text.tsx +51 -0
  166. package/src/primitives/typography/index.ts +1 -0
  167. package/src/provider/DesignSystemContext.ts +22 -0
  168. package/src/provider/DesignSystemProvider.tsx +121 -0
  169. package/src/provider/index.ts +7 -0
  170. package/src/providers/ThemeProvider/createTheme.ts +304 -0
  171. package/src/providers/ThemeProvider/defaultTheme.ts +70 -0
  172. package/src/providers/ThemeProvider/index.ts +34 -0
  173. package/src/providers/ThemeProvider/types.ts +249 -0
  174. package/src/providers/index.ts +29 -0
  175. package/src/tokens/colors.ts +371 -0
  176. package/src/tokens/index.ts +145 -0
  177. package/src/tokens/motion.ts +176 -0
  178. package/src/tokens/radii.ts +82 -0
  179. package/src/tokens/scales.ts +588 -0
  180. package/src/tokens/shadows.ts +190 -0
  181. package/src/tokens/spacing.ts +140 -0
  182. package/src/tokens/tokens.json +207 -0
  183. package/src/tokens/typography.ts +251 -0
  184. package/src/types.ts +50 -0
  185. package/src/utils/accessibility.ts +169 -0
  186. package/src/utils/index.ts +25 -0
  187. package/src/utils/platform.ts +72 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Avatar Component Types
3
+ *
4
+ * Type definitions for the Avatar component and its related hooks/helpers.
5
+ * All types are explicitly exported for external consumption.
6
+ *
7
+ * @see Avatar.tsx - Component implementation
8
+ */
9
+
10
+ import { BoxProps, ResponsiveValue } from "@shopify/restyle";
11
+ import { ImageSourcePropType, ViewProps } from "react-native";
12
+ import { RestyleTheme } from "../../../core/restyle";
13
+ import { RestyleColor } from "../../../types";
14
+
15
+ // =============================================================================
16
+ // VARIANT TYPES
17
+ // =============================================================================
18
+
19
+ /**
20
+ * Size preset for the Avatar component.
21
+ * Derived from theme avatarSizes variant.
22
+ *
23
+ * - `sm`: 32×32 - Compact lists, comments
24
+ * - `md`: 40×40 - Standard avatar (default)
25
+ * - `lg`: 56×56 - Profile headers, featured users
26
+ */
27
+ export type AvatarSize = Exclude<keyof RestyleTheme["avatarSizes"], "defaults">;
28
+
29
+ /**
30
+ * Status indicator for the Avatar component.
31
+ *
32
+ * - `online`: Green dot - user is active
33
+ * - `offline`: Gray dot - user is inactive
34
+ * - `busy`: Red dot - do not disturb
35
+ * - `away`: Yellow dot - user is away
36
+ * - `none`: No status indicator (default)
37
+ */
38
+ export type AvatarStatus = "online" | "offline" | "busy" | "away" | "none";
39
+
40
+ // =============================================================================
41
+ // COMPONENT PROPS
42
+ // =============================================================================
43
+
44
+ /** Base props combining Restyle Box props with ViewProps */
45
+ export type BaseAvatarProps = BoxProps<RestyleTheme> & ViewProps;
46
+
47
+ /**
48
+ * Base props for the Avatar container.
49
+ * @internal
50
+ */
51
+ export type BaseAvatarContainerProps = BoxProps<RestyleTheme> & ViewProps;
52
+
53
+ /**
54
+ * Props for the Avatar component.
55
+ *
56
+ * @example
57
+ * // Image avatar
58
+ * <Avatar source={{ uri: "https://example.com/avatar.jpg" }} />
59
+ *
60
+ * @example
61
+ * // Initials fallback
62
+ * <Avatar name="John Doe" />
63
+ *
64
+ * @example
65
+ * // With status indicator
66
+ * <Avatar source={avatarUrl} status="online" />
67
+ *
68
+ * @example
69
+ * // Different sizes
70
+ * <Avatar name="JD" size="lg" />
71
+ */
72
+ export interface AvatarProps extends Omit<BaseAvatarProps, "width" | "height" | "backgroundColor"> {
73
+ /**
74
+ * Image source for the avatar.
75
+ * Falls back to initials if not provided or fails to load.
76
+ */
77
+ source?: ImageSourcePropType;
78
+
79
+ /**
80
+ * User's name for generating initials fallback.
81
+ * First letter of first and last name are used (e.g., "John Doe" → "JD").
82
+ */
83
+ name?: string;
84
+
85
+ /**
86
+ * Size preset (supports responsive values).
87
+ * @default "md"
88
+ */
89
+ size?: ResponsiveValue<AvatarSize, RestyleTheme["breakpoints"]>;
90
+
91
+ /**
92
+ * Status indicator to display.
93
+ * @default "none"
94
+ */
95
+ status?: AvatarStatus;
96
+
97
+ /**
98
+ * Background color for initials fallback.
99
+ * @default "accentPrimary"
100
+ */
101
+ backgroundColor?: RestyleColor;
102
+
103
+ /**
104
+ * Text color for initials.
105
+ * @default "textInverse"
106
+ */
107
+ initialsColor?: RestyleColor;
108
+
109
+ /**
110
+ * Accessibility label for the avatar.
111
+ * Defaults to name if provided.
112
+ */
113
+ accessibilityLabel?: string;
114
+
115
+ /** Test ID for testing frameworks */
116
+ testID?: string;
117
+ }
118
+
119
+ // =============================================================================
120
+ // HOOK TYPES
121
+ // =============================================================================
122
+
123
+ /**
124
+ * Parameters for the useAvatarLogic hook.
125
+ */
126
+ export interface UseAvatarLogicParams {
127
+ source?: ImageSourcePropType;
128
+ name?: string;
129
+ size: ResponsiveValue<AvatarSize, RestyleTheme["breakpoints"]>;
130
+ status: AvatarStatus;
131
+ backgroundColor: RestyleColor;
132
+ initialsColor: RestyleColor;
133
+ accessibilityLabel?: string;
134
+ }
135
+
136
+ /**
137
+ * Return value from the useAvatarLogic hook.
138
+ */
139
+ export interface UseAvatarLogicReturn {
140
+ /** Resolved size value */
141
+ resolvedSize: AvatarSize;
142
+ /** Computed avatar dimensions */
143
+ dimensions: AvatarDimensions;
144
+ /** Whether to show image or initials */
145
+ showImage: boolean;
146
+ /** Generated initials from name */
147
+ initials: string;
148
+ /** Status indicator color */
149
+ statusColor: RestyleColor | null;
150
+ /** Status indicator dimensions */
151
+ statusDimensions: StatusDimensions | null;
152
+ /** Accessibility props */
153
+ a11yProps: AvatarA11yProps;
154
+ /** Handler for image load error */
155
+ onImageError: () => void;
156
+ }
157
+
158
+ // =============================================================================
159
+ // HELPER TYPES
160
+ // =============================================================================
161
+
162
+ /**
163
+ * Dimensions configuration for avatar sizes.
164
+ */
165
+ export interface AvatarDimensions {
166
+ size: number;
167
+ fontSize: number;
168
+ borderRadius: number;
169
+ }
170
+
171
+ /**
172
+ * Dimensions for status indicator by avatar size.
173
+ */
174
+ export interface StatusDimensions {
175
+ size: number;
176
+ borderWidth: number;
177
+ offset: number;
178
+ }
179
+
180
+ /**
181
+ * Size configuration map.
182
+ */
183
+ export type AvatarSizeConfig = Record<AvatarSize, AvatarDimensions>;
184
+
185
+ /**
186
+ * Status indicator configuration map.
187
+ */
188
+ export type StatusSizeConfig = Record<AvatarSize, StatusDimensions>;
189
+
190
+ /**
191
+ * Status color mapping.
192
+ */
193
+ export type StatusColorMap = Record<Exclude<AvatarStatus, "none">, RestyleColor>;
194
+
195
+ // =============================================================================
196
+ // ACCESSIBILITY TYPES
197
+ // =============================================================================
198
+
199
+ /**
200
+ * Parameters for generating avatar accessibility props.
201
+ */
202
+ export interface AvatarA11yParams {
203
+ /** User's name or custom label */
204
+ name?: string;
205
+ /** Custom accessibility label */
206
+ accessibilityLabel?: string;
207
+ /** Current status */
208
+ status: AvatarStatus;
209
+ /** Pre-translated fallback label */
210
+ fallbackLabel: string;
211
+ /** Pre-translated status labels */
212
+ statusLabels: Record<Exclude<AvatarStatus, "none">, string>;
213
+ }
214
+
215
+ /**
216
+ * Accessibility props returned by getAvatarA11y.
217
+ */
218
+ export interface AvatarA11yProps {
219
+ accessible: boolean;
220
+ accessibilityRole: "image";
221
+ accessibilityLabel: string;
222
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Avatar Component
3
+ *
4
+ * @description Profile images with fallback initials and status indicators
5
+ *
6
+ * @example
7
+ * import { Avatar } from "@/design-system";
8
+ *
9
+ * // Image avatar
10
+ * <Avatar source={{ uri: "https://..." }} name="John Doe" />
11
+ *
12
+ * // Initials fallback
13
+ * <Avatar name="John Doe" />
14
+ *
15
+ * // With status
16
+ * <Avatar name="Jane" status="online" />
17
+ */
18
+
19
+ export { Avatar } from "./Avatar";
20
+ export type {
21
+ AvatarA11yParams,
22
+ AvatarA11yProps,
23
+ AvatarDimensions,
24
+ AvatarProps,
25
+ AvatarSize,
26
+ AvatarSizeConfig,
27
+ AvatarStatus,
28
+ BaseAvatarContainerProps,
29
+ BaseAvatarProps,
30
+ StatusColorMap,
31
+ StatusDimensions,
32
+ StatusSizeConfig,
33
+ UseAvatarLogicParams,
34
+ UseAvatarLogicReturn,
35
+ } from "./Avatar.types";
36
+ export {
37
+ AVATAR_SIZE_CONFIG,
38
+ getAvatarDimensions,
39
+ getInitials,
40
+ getStatusColor,
41
+ getStatusDimensions,
42
+ STATUS_COLORS,
43
+ STATUS_SIZE_CONFIG,
44
+ } from "./Avatar.helpers";
45
+ export { getAvatarA11y } from "./Avatar.a11y";
46
+ export { useAvatarLogic } from "./useAvatarLogic";
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Avatar Logic Hook
3
+ *
4
+ * Extracts all computational logic from the Avatar component.
5
+ * Returns memoized values for optimal render performance.
6
+ *
7
+ * Responsibilities:
8
+ * - Resolve responsive size prop
9
+ * - Calculate dimensions based on size
10
+ * - Generate initials from name
11
+ * - Handle image load errors
12
+ * - Provide accessibility props
13
+ *
14
+ * @see Avatar.tsx - Component consuming this hook
15
+ * @see Avatar.helpers.ts - Pure calculation functions
16
+ */
17
+
18
+ import { useDesignSystem } from "../../../provider";
19
+ import { useResponsiveProp } from "@shopify/restyle";
20
+ import { useCallback, useMemo, useState } from "react";
21
+ import { getAvatarA11y } from "./Avatar.a11y";
22
+ import {
23
+ getAvatarDimensions,
24
+ getInitials,
25
+ getStatusColor,
26
+ getStatusDimensions,
27
+ } from "./Avatar.helpers";
28
+ import { AvatarSize, UseAvatarLogicParams, UseAvatarLogicReturn } from "./Avatar.types";
29
+
30
+ /**
31
+ * Orchestrates Avatar rendering logic and state management.
32
+ *
33
+ * Handles:
34
+ * - Responsive size resolution
35
+ * - Dimension calculation (width, height, border radius)
36
+ * - Image vs initials display logic
37
+ * - Initials generation from name
38
+ * - Image error handling (fallback to initials)
39
+ * - Status indicator color and dimensions
40
+ * - Accessibility props generation
41
+ *
42
+ * @param params - Configuration object for avatar behavior
43
+ * @param params.source - Image source (local or remote)
44
+ * @param params.name - User name (for initials fallback)
45
+ * @param params.size - Size variant ('xs' | 'sm' | 'md' | 'lg' | 'xl')
46
+ * @param params.status - Status indicator ('none' | 'online' | 'offline' | 'busy' | 'away')
47
+ * @param params.backgroundColor - Theme color token for initials background
48
+ * @param params.initialsColor - Theme color token for initials text
49
+ * @param params.accessibilityLabel - Custom a11y label
50
+ *
51
+ * @returns Computed values for rendering Avatar
52
+ * @returns {string} resolvedSize - Resolved size variant
53
+ * @returns {object} dimensions - Width, height, border radius
54
+ * @returns {boolean} showImage - Whether to display image or initials
55
+ * @returns {string} initials - Generated initials (1-2 chars)
56
+ * @returns {string} statusColor - Status indicator color token
57
+ * @returns {object} statusDimensions - Status indicator dimensions
58
+ * @returns {object} a11yProps - Accessibility props
59
+ * @returns {function} onImageError - Image error handler
60
+ *
61
+ * @performance This hook uses useMemo() for expensive calculations
62
+ *
63
+ * @example
64
+ * const {
65
+ * dimensions,
66
+ * showImage,
67
+ * initials,
68
+ * statusColor,
69
+ * statusDimensions,
70
+ * a11yProps,
71
+ * onImageError,
72
+ * } = useAvatarLogic({
73
+ * source: { uri: "https://..." },
74
+ * name: "John Doe",
75
+ * size: "md",
76
+ * status: "online",
77
+ * backgroundColor: "accentPrimary",
78
+ * initialsColor: "textInverse",
79
+ * });
80
+ */
81
+ export function useAvatarLogic({
82
+ source,
83
+ name,
84
+ size,
85
+ status,
86
+ backgroundColor,
87
+ initialsColor,
88
+ accessibilityLabel,
89
+ }: UseAvatarLogicParams): UseAvatarLogicReturn {
90
+ const { labels: t } = useDesignSystem();
91
+
92
+ // Track image load errors
93
+ const [imageError, setImageError] = useState(false);
94
+
95
+ // Resolve responsive size
96
+ const resolvedSize = (useResponsiveProp(size) ?? "md") as AvatarSize;
97
+
98
+ // Calculate dimensions
99
+ const dimensions = getAvatarDimensions(resolvedSize);
100
+
101
+ // Determine if we should show image or initials
102
+ const showImage = !!source && !imageError;
103
+
104
+ // Generate initials
105
+ const initials = getInitials(name);
106
+
107
+ // Get status color
108
+ const statusColor = getStatusColor(status);
109
+
110
+ // Get status dimensions
111
+ const statusDimensions = status !== "none" ? getStatusDimensions(resolvedSize) : null;
112
+
113
+ // Handle image load error
114
+ const onImageError = useCallback(() => {
115
+ setImageError(true);
116
+ }, []);
117
+
118
+ // Build translated status labels
119
+ const statusLabels = useMemo(() => ({
120
+ online: t.designSystem.avatar.statusOnline,
121
+ offline: t.designSystem.avatar.statusOffline,
122
+ busy: t.designSystem.avatar.statusBusy,
123
+ away: t.designSystem.avatar.statusAway,
124
+ }), [t]);
125
+
126
+ // Accessibility props
127
+ const a11yProps = useMemo(
128
+ () =>
129
+ getAvatarA11y({
130
+ name,
131
+ accessibilityLabel,
132
+ status,
133
+ fallbackLabel: t.designSystem.avatar.fallbackLabel,
134
+ statusLabels,
135
+ }),
136
+ [name, accessibilityLabel, status, t, statusLabels]
137
+ );
138
+
139
+ return {
140
+ resolvedSize,
141
+ dimensions,
142
+ showImage,
143
+ initials,
144
+ statusColor,
145
+ statusDimensions,
146
+ a11yProps,
147
+ onImageError,
148
+ };
149
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Badge Component Helpers
3
+ *
4
+ * Pure functions for calculating badge dimensions and color styles.
5
+ * All values follow 4px/8px grid system for consistency.
6
+ *
7
+ * ## Size Scale
8
+ * | Size | Height | Min Width | Dot Size | Use Case |
9
+ * |------|--------|-----------|----------|----------|
10
+ * | sm | 16px | 16px | 6px | Inline indicators |
11
+ * | md | 20px | 20px | 8px | Standard (default) |
12
+ * | lg | 24px | 24px | 10px | Prominent badges |
13
+ *
14
+ * ## Color Variants
15
+ * - `filled`: Solid background, inverse text
16
+ * - `outlined`: Border only, transparent background
17
+ */
18
+
19
+ import {
20
+ BadgeColorStyles,
21
+ BadgeDimensions,
22
+ BadgeSize,
23
+ BadgeSizeConfig,
24
+ BadgeVariant,
25
+ } from "./Badge.types";
26
+ import { RestyleColor } from "../../../types";
27
+
28
+ // =============================================================================
29
+ // TYPOGRAPHY & DOT SIZE MAPPINGS
30
+ // =============================================================================
31
+
32
+ /**
33
+ * Map badge size to typography variant for label text.
34
+ *
35
+ * | Size | Typography |
36
+ * |------|----------------|
37
+ * | sm | captionSmall |
38
+ * | md | caption |
39
+ * | lg | labelSmall |
40
+ */
41
+ export const BADGE_TYPOGRAPHY: Record<
42
+ BadgeSize,
43
+ "captionSmall" | "caption" | "labelSmall"
44
+ > = {
45
+ sm: "captionSmall",
46
+ md: "caption",
47
+ lg: "labelSmall",
48
+ };
49
+
50
+ /**
51
+ * Map badge size to dot indicator dimensions.
52
+ *
53
+ * | Size | Dot Size |
54
+ * |------|----------|
55
+ * | sm | 6px |
56
+ * | md | 8px |
57
+ * | lg | 10px |
58
+ */
59
+ export const BADGE_DOT_SIZE: Record<BadgeSize, number> = {
60
+ sm: 6,
61
+ md: 8,
62
+ lg: 10,
63
+ };
64
+
65
+ /**
66
+ * Size configuration for badge dimensions.
67
+ * Following 4px/8px grid system.
68
+ */
69
+ export const BADGE_SIZE_CONFIG: BadgeSizeConfig = {
70
+ sm: {
71
+ height: 16,
72
+ minWidth: 16,
73
+ paddingHorizontal: 4,
74
+ borderRadius: 8,
75
+ dotSize: 6,
76
+ fontSize: 10,
77
+ },
78
+ md: {
79
+ height: 20,
80
+ minWidth: 20,
81
+ paddingHorizontal: 6,
82
+ borderRadius: 10,
83
+ dotSize: 8,
84
+ fontSize: 12,
85
+ },
86
+ lg: {
87
+ height: 24,
88
+ minWidth: 24,
89
+ paddingHorizontal: 8,
90
+ borderRadius: 12,
91
+ dotSize: 10,
92
+ fontSize: 14,
93
+ },
94
+ } as const;
95
+
96
+ /**
97
+ * Get color styles for a badge based on variant and color token.
98
+ * Works with any RestyleColor — no preset lookup needed.
99
+ *
100
+ * @param variant - Badge variant
101
+ * @param color - Any theme color token
102
+ * @returns Color styles for the badge
103
+ *
104
+ * @example
105
+ * getBadgeColorStyles("filled", "feedbackSuccess")
106
+ * // { backgroundColor: "feedbackSuccess", textColor: "textInverse", ... }
107
+ */
108
+ export function getBadgeColorStyles(
109
+ variant: BadgeVariant,
110
+ color: RestyleColor,
111
+ ): BadgeColorStyles {
112
+ if (variant === "outlined") {
113
+ return {
114
+ backgroundColor: "transparent",
115
+ textColor: color,
116
+ borderColor: color,
117
+ borderWidth: 1,
118
+ };
119
+ }
120
+
121
+ // filled (default)
122
+ return {
123
+ backgroundColor: color,
124
+ textColor: "textInverse",
125
+ borderColor: "transparent",
126
+ borderWidth: 0,
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Get dimensions for a badge based on size.
132
+ *
133
+ * @param size - Badge size preset
134
+ * @returns Badge dimensions
135
+ *
136
+ * @example
137
+ * getBadgeDimensions("md")
138
+ * // { height: 20, minWidth: 20, paddingHorizontal: 6, ... }
139
+ */
140
+ export function getBadgeDimensions(size: BadgeSize): BadgeDimensions {
141
+ return BADGE_SIZE_CONFIG[size];
142
+ }
143
+
144
+ /**
145
+ * Format the display text for a badge.
146
+ * Handles max value truncation for numeric labels.
147
+ *
148
+ * @param label - The label value
149
+ * @param max - Maximum numeric value before truncation
150
+ * @returns Formatted display string
151
+ *
152
+ * @example
153
+ * formatBadgeLabel(5, 99)
154
+ * // "5"
155
+ *
156
+ * @example
157
+ * formatBadgeLabel(100, 99)
158
+ * // "99+"
159
+ *
160
+ * @example
161
+ * formatBadgeLabel("New", 99)
162
+ * // "New"
163
+ */
164
+ export function formatBadgeLabel(
165
+ label: string | number | undefined,
166
+ max: number
167
+ ): string {
168
+ if (label === undefined || label === null) return "";
169
+
170
+ if (typeof label === "number") {
171
+ return label > max ? `${max}+` : String(label);
172
+ }
173
+
174
+ return String(label);
175
+ }