@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.
- package/dist/index.d.mts +52556 -0
- package/dist/index.d.ts +52556 -0
- package/dist/index.js +8753 -0
- package/dist/index.mjs +8777 -0
- package/package.json +70 -0
- package/src/__test-utils__/index.tsx +39 -0
- package/src/components/CalendarStrip/CalendarStrip.helpers.ts +106 -0
- package/src/components/CalendarStrip/CalendarStrip.tsx +83 -0
- package/src/components/CalendarStrip/CalendarStrip.types.ts +133 -0
- package/src/components/CalendarStrip/DayCard/DayCard.helpers.ts +44 -0
- package/src/components/CalendarStrip/DayCard/DayCard.tsx +71 -0
- package/src/components/CalendarStrip/DayCard/DayCard.types.ts +134 -0
- package/src/components/CalendarStrip/DayCard/index.ts +2 -0
- package/src/components/CalendarStrip/DayCard/useDayCardLogic.ts +45 -0
- package/src/components/CalendarStrip/index.ts +9 -0
- package/src/components/CalendarStrip/useCalendarStripLogic.ts +53 -0
- package/src/components/EmptyState/EmptyState.helpers.ts +104 -0
- package/src/components/EmptyState/EmptyState.tsx +205 -0
- package/src/components/EmptyState/EmptyState.types.ts +213 -0
- package/src/components/EmptyState/index.ts +44 -0
- package/src/components/EmptyState/useEmptyStateLogic.ts +131 -0
- package/src/components/Header/Header.helpers.ts +93 -0
- package/src/components/Header/Header.tsx +185 -0
- package/src/components/Header/Header.types.ts +153 -0
- package/src/components/Header/index.ts +44 -0
- package/src/components/Header/useHeaderLogic.ts +146 -0
- package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.helpers.ts +50 -0
- package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.tsx +78 -0
- package/src/components/ScheduleItem/ScheduleItem/ScheduleItem.types.ts +99 -0
- package/src/components/ScheduleItem/ScheduleItem/index.ts +16 -0
- package/src/components/ScheduleItem/ScheduleItem/useScheduleItemLogic.ts +31 -0
- package/src/components/ScheduleItem/index.ts +15 -0
- package/src/components/index.ts +40 -0
- package/src/core/index.ts +34 -0
- package/src/core/restyle/RestyleThemeProviderWrapper.tsx +31 -0
- package/src/core/restyle/index.ts +38 -0
- package/src/core/restyle/restylePresetRegistry.ts +195 -0
- package/src/core/restyle/restyleTheme.ts +1352 -0
- package/src/core/restyle/restyleTypes.ts +8 -0
- package/src/core/restyle/useRestyleTheme.ts +10 -0
- package/src/hooks/animations/index.ts +3 -0
- package/src/hooks/animations/useAnimatedValue.ts +10 -0
- package/src/hooks/animations/useEntranceAnimation.ts +106 -0
- package/src/hooks/animations/usePulseAnimation.ts +63 -0
- package/src/hooks/index.ts +30 -0
- package/src/hooks/useReducedMotion.ts +60 -0
- package/src/i18n/index.ts +2 -0
- package/src/i18n/labels/en.ts +120 -0
- package/src/i18n/labels/es.ts +120 -0
- package/src/i18n/labels/index.ts +6 -0
- package/src/i18n/labels/types.ts +165 -0
- package/src/index.tsx +215 -0
- package/src/primitives/actions/Button/Button.helpers.ts +243 -0
- package/src/primitives/actions/Button/Button.tsx +198 -0
- package/src/primitives/actions/Button/Button.types.ts +207 -0
- package/src/primitives/actions/Button/index.ts +41 -0
- package/src/primitives/actions/Button/useButtonLogic.ts +160 -0
- package/src/primitives/actions/IconButton/IconButton.helpers.ts +235 -0
- package/src/primitives/actions/IconButton/IconButton.tsx +177 -0
- package/src/primitives/actions/IconButton/IconButton.types.ts +273 -0
- package/src/primitives/actions/IconButton/index.ts +30 -0
- package/src/primitives/actions/IconButton/useIconButtonLogic.ts +172 -0
- package/src/primitives/actions/index.ts +20 -0
- package/src/primitives/content/Avatar/Avatar.helpers.ts +177 -0
- package/src/primitives/content/Avatar/Avatar.tsx +199 -0
- package/src/primitives/content/Avatar/Avatar.types.ts +222 -0
- package/src/primitives/content/Avatar/index.ts +46 -0
- package/src/primitives/content/Avatar/useAvatarLogic.ts +149 -0
- package/src/primitives/content/Badge/Badge.helpers.ts +175 -0
- package/src/primitives/content/Badge/Badge.tsx +174 -0
- package/src/primitives/content/Badge/Badge.types.ts +223 -0
- package/src/primitives/content/Badge/index.ts +40 -0
- package/src/primitives/content/Badge/useBadgeLogic.ts +128 -0
- package/src/primitives/content/Card/Card.helpers.ts +27 -0
- package/src/primitives/content/Card/Card.tsx +123 -0
- package/src/primitives/content/Card/Card.types.ts +95 -0
- package/src/primitives/content/Card/index.ts +20 -0
- package/src/primitives/content/Card/useCardLogic.ts +48 -0
- package/src/primitives/content/Chip/Chip.helpers.ts +304 -0
- package/src/primitives/content/Chip/Chip.tsx +205 -0
- package/src/primitives/content/Chip/Chip.types.ts +234 -0
- package/src/primitives/content/Chip/index.ts +47 -0
- package/src/primitives/content/Chip/useChipLogic.ts +167 -0
- package/src/primitives/content/Icon/Icon.helpers.ts +54 -0
- package/src/primitives/content/Icon/Icon.tsx +110 -0
- package/src/primitives/content/Icon/Icon.types.ts +95 -0
- package/src/primitives/content/Icon/index.ts +20 -0
- package/src/primitives/content/Icon/useIconLogic.ts +73 -0
- package/src/primitives/content/index.ts +45 -0
- package/src/primitives/feedback/ProgressBar/ProgressBar.helpers.ts +122 -0
- package/src/primitives/feedback/ProgressBar/ProgressBar.tsx +154 -0
- package/src/primitives/feedback/ProgressBar/ProgressBar.types.ts +178 -0
- package/src/primitives/feedback/ProgressBar/index.ts +17 -0
- package/src/primitives/feedback/ProgressBar/useProgressBarLogic.ts +120 -0
- package/src/primitives/feedback/Skeleton/Skeleton.helpers.ts +145 -0
- package/src/primitives/feedback/Skeleton/Skeleton.tsx +155 -0
- package/src/primitives/feedback/Skeleton/Skeleton.types.ts +223 -0
- package/src/primitives/feedback/Skeleton/index.ts +44 -0
- package/src/primitives/feedback/Skeleton/useSkeletonLogic.ts +125 -0
- package/src/primitives/feedback/Spinner/Spinner.helpers.ts +40 -0
- package/src/primitives/feedback/Spinner/Spinner.tsx +105 -0
- package/src/primitives/feedback/Spinner/Spinner.types.ts +114 -0
- package/src/primitives/feedback/Spinner/index.ts +18 -0
- package/src/primitives/feedback/Spinner/useSpinnerLogic.ts +84 -0
- package/src/primitives/feedback/Toast/Toast.helpers.ts +163 -0
- package/src/primitives/feedback/Toast/Toast.tsx +190 -0
- package/src/primitives/feedback/Toast/Toast.types.ts +270 -0
- package/src/primitives/feedback/Toast/ToastContext.tsx +96 -0
- package/src/primitives/feedback/Toast/ToastProvider.tsx +241 -0
- package/src/primitives/feedback/Toast/index.ts +59 -0
- package/src/primitives/feedback/Toast/useToastLogic.ts +112 -0
- package/src/primitives/feedback/index.ts +45 -0
- package/src/primitives/index.ts +158 -0
- package/src/primitives/inputs/Checkbox/Checkbox.helpers.ts +132 -0
- package/src/primitives/inputs/Checkbox/Checkbox.tsx +150 -0
- package/src/primitives/inputs/Checkbox/Checkbox.types.ts +106 -0
- package/src/primitives/inputs/Checkbox/index.ts +30 -0
- package/src/primitives/inputs/Checkbox/useCheckboxLogic.ts +121 -0
- package/src/primitives/inputs/RadioButton/RadioButton.helpers.ts +123 -0
- package/src/primitives/inputs/RadioButton/RadioButton.tsx +159 -0
- package/src/primitives/inputs/RadioButton/RadioButton.types.ts +106 -0
- package/src/primitives/inputs/RadioButton/index.ts +25 -0
- package/src/primitives/inputs/RadioButton/useRadioButtonLogic.ts +117 -0
- package/src/primitives/inputs/SegmentedControl/SegmentedControl.helpers.ts +174 -0
- package/src/primitives/inputs/SegmentedControl/SegmentedControl.tsx +224 -0
- package/src/primitives/inputs/SegmentedControl/SegmentedControl.types.ts +187 -0
- package/src/primitives/inputs/SegmentedControl/index.ts +39 -0
- package/src/primitives/inputs/SegmentedControl/useSegmentedControlLogic.ts +151 -0
- package/src/primitives/inputs/SelectSheet/SelectSheet.helpers.ts +147 -0
- package/src/primitives/inputs/SelectSheet/SelectSheet.tsx +247 -0
- package/src/primitives/inputs/SelectSheet/SelectSheet.types.ts +196 -0
- package/src/primitives/inputs/SelectSheet/SelectSheetOption.tsx +177 -0
- package/src/primitives/inputs/SelectSheet/index.ts +48 -0
- package/src/primitives/inputs/SelectSheet/useSelectSheetLogic.ts +309 -0
- package/src/primitives/inputs/Switch/Switch.helpers.ts +109 -0
- package/src/primitives/inputs/Switch/Switch.tsx +191 -0
- package/src/primitives/inputs/Switch/Switch.types.ts +154 -0
- package/src/primitives/inputs/Switch/index.ts +40 -0
- package/src/primitives/inputs/Switch/useSwitchLogic.ts +192 -0
- package/src/primitives/inputs/TextInput/TextInput.helpers.ts +206 -0
- package/src/primitives/inputs/TextInput/TextInput.tsx +392 -0
- package/src/primitives/inputs/TextInput/TextInput.types.ts +216 -0
- package/src/primitives/inputs/TextInput/index.ts +37 -0
- package/src/primitives/inputs/TextInput/useTextInputLogic.ts +195 -0
- package/src/primitives/inputs/index.ts +52 -0
- package/src/primitives/layout/AnimatedBox.tsx +44 -0
- package/src/primitives/layout/Box.tsx +71 -0
- package/src/primitives/layout/Divider/Divider.helpers.ts +115 -0
- package/src/primitives/layout/Divider/Divider.tsx +139 -0
- package/src/primitives/layout/Divider/Divider.types.ts +178 -0
- package/src/primitives/layout/Divider/index.ts +24 -0
- package/src/primitives/layout/Divider/useDividerLogic.ts +109 -0
- package/src/primitives/layout/FlatList.tsx +66 -0
- package/src/primitives/layout/Pressable.tsx +74 -0
- package/src/primitives/layout/ScrollView.tsx +63 -0
- package/src/primitives/layout/Stack.tsx +69 -0
- package/src/primitives/layout/index.ts +40 -0
- package/src/primitives/navigation/index.ts +6 -0
- package/src/primitives/overlays/Modal/Modal.helpers.ts +31 -0
- package/src/primitives/overlays/Modal/Modal.tsx +264 -0
- package/src/primitives/overlays/Modal/Modal.types.ts +193 -0
- package/src/primitives/overlays/Modal/index.ts +43 -0
- package/src/primitives/overlays/Modal/useModalLogic.ts +103 -0
- package/src/primitives/overlays/index.ts +12 -0
- package/src/primitives/typography/Text.tsx +51 -0
- package/src/primitives/typography/index.ts +1 -0
- package/src/provider/DesignSystemContext.ts +22 -0
- package/src/provider/DesignSystemProvider.tsx +121 -0
- package/src/provider/index.ts +7 -0
- package/src/providers/ThemeProvider/createTheme.ts +304 -0
- package/src/providers/ThemeProvider/defaultTheme.ts +70 -0
- package/src/providers/ThemeProvider/index.ts +34 -0
- package/src/providers/ThemeProvider/types.ts +249 -0
- package/src/providers/index.ts +29 -0
- package/src/tokens/colors.ts +371 -0
- package/src/tokens/index.ts +145 -0
- package/src/tokens/motion.ts +176 -0
- package/src/tokens/radii.ts +82 -0
- package/src/tokens/scales.ts +588 -0
- package/src/tokens/shadows.ts +190 -0
- package/src/tokens/spacing.ts +140 -0
- package/src/tokens/tokens.json +207 -0
- package/src/tokens/typography.ts +251 -0
- package/src/types.ts +50 -0
- package/src/utils/accessibility.ts +169 -0
- package/src/utils/index.ts +25 -0
- 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
|
+
}
|