@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,174 @@
1
+ /**
2
+ * Badge Component
3
+ *
4
+ * @description Status indicators, notification counts, and labels - Atom
5
+ *
6
+ * Badge displays small pieces of information like counts, statuses, or labels.
7
+ * Supports multiple sizes, variants, and colors with dot mode for compact
8
+ * status indicators.
9
+ *
10
+ * ## Size Scale
11
+ * | Size | Height | Min Width | Dot Size | Use Case |
12
+ * |------|--------|-----------|----------|----------|
13
+ * | sm | 16px | 16px | 6px | Inline indicators |
14
+ * | md | 20px | 20px | 8px | Standard (default) |
15
+ * | lg | 24px | 24px | 10px | Prominent badges |
16
+ *
17
+ * ## Variants
18
+ * - `filled`: Solid background (default)
19
+ * - `outlined`: Border only
20
+ *
21
+ * ## Colors
22
+ * - `primary`: Primary accent
23
+ * - `success`: Green
24
+ * - `warning`: Yellow/amber
25
+ * - `error`: Red
26
+ * - `info`: Blue
27
+ *
28
+ * ## Features
29
+ * - Three size presets with responsive support
30
+ * - Three visual variants
31
+ * - Five color options
32
+ * - Dot mode for status indicators
33
+ * - Max value truncation for counts (e.g., "99+")
34
+ * - Theme-aware colors via Restyle
35
+ * - Accessible with proper labels
36
+ * - Memoized for performance
37
+ * - Spreads rest props for composability (marginBottom, flex, etc.)
38
+ *
39
+ * @see Badge.types.ts - Type definitions
40
+ * @see Badge.helpers.ts - Dimension and color calculations
41
+ * @see Badge.a11y.ts - Accessibility props
42
+ *
43
+ * @example
44
+ * // Simple text badge
45
+ * <Badge label="New" />
46
+ *
47
+ * @example
48
+ * // Notification count
49
+ * <Badge label={5} color="error" />
50
+ *
51
+ * @example
52
+ * // Count with max
53
+ * <Badge label={150} max={99} /> // Shows "99+"
54
+ *
55
+ * @example
56
+ * // Dot status indicator
57
+ * <Badge dot color="success" />
58
+ *
59
+ * @example
60
+ * // Soft variant
61
+ * <Badge label="Sale" variant="outlined" color="error" />
62
+ *
63
+ * @example
64
+ * // With margin (composable via rest props)
65
+ * <Badge label="New" marginRight="sm" />
66
+ */
67
+
68
+ import {
69
+ backgroundColor,
70
+ border,
71
+ createRestyleComponent,
72
+ createVariant,
73
+ layout,
74
+ spacing,
75
+ spacingShorthand,
76
+ } from "@shopify/restyle";
77
+ import React, { memo } from "react";
78
+ import { RestyleTheme } from "../../../core/restyle";
79
+ import { BaseThemeColor } from "../../../types";
80
+ import { Box } from "../../layout";
81
+ import { Text } from "../../typography";
82
+ import { BADGE_DOT_SIZE, BADGE_TYPOGRAPHY } from "./Badge.helpers";
83
+ import { BadgeProps, BaseBadgeProps } from "./Badge.types";
84
+ import { useBadgeLogic } from "./useBadgeLogic";
85
+
86
+ /**
87
+ * Base Badge container with Restyle variant support.
88
+ * Uses createRestyleComponent with createVariant for theme-driven styling.
89
+ * Box is passed as the base component for atomic primacy compliance.
90
+ * @internal
91
+ */
92
+ const BaseBadgeContainer = createRestyleComponent<BaseBadgeProps, RestyleTheme>(
93
+ [
94
+ createVariant({ themeKey: "badgeVariants" }),
95
+ createVariant({ themeKey: "badgeSizes", property: "size" }),
96
+ backgroundColor,
97
+ border,
98
+ layout,
99
+ spacing,
100
+ spacingShorthand,
101
+ ],
102
+ Box,
103
+ );
104
+
105
+ function BadgeComponent({
106
+ label,
107
+ size = "md",
108
+ variant = "filled",
109
+ color = "accentPrimary",
110
+ dot = false,
111
+ max = 99,
112
+ accessibilityLabel,
113
+ testID,
114
+ style,
115
+ ...rest
116
+ }: BadgeProps) {
117
+ const { resolvedSize, displayText, colorStyles, a11yProps } = useBadgeLogic({
118
+ label,
119
+ size,
120
+ variant,
121
+ color,
122
+ dot,
123
+ max,
124
+ accessibilityLabel,
125
+ });
126
+
127
+ // Dot mode: render small circle
128
+ if (dot) {
129
+ const dotDimension = BADGE_DOT_SIZE[resolvedSize];
130
+ return (
131
+ <BaseBadgeContainer
132
+ variant={variant}
133
+ testID={testID}
134
+ width={dotDimension}
135
+ height={dotDimension}
136
+ minWidth={undefined}
137
+ backgroundColor={colorStyles.backgroundColor as BaseThemeColor}
138
+ borderWidth={colorStyles.borderWidth}
139
+ borderColor={colorStyles.borderColor as BaseThemeColor}
140
+ style={style}
141
+ {...a11yProps}
142
+ {...rest}
143
+ />
144
+ );
145
+ }
146
+
147
+ // Text/count badge
148
+ return (
149
+ <BaseBadgeContainer
150
+ variant={variant}
151
+ size={size}
152
+ testID={testID}
153
+ backgroundColor={colorStyles.backgroundColor as BaseThemeColor}
154
+ borderWidth={colorStyles.borderWidth}
155
+ borderColor={colorStyles.borderColor as BaseThemeColor}
156
+ style={style}
157
+ {...a11yProps}
158
+ {...rest}
159
+ >
160
+ <Text
161
+ variant={BADGE_TYPOGRAPHY[resolvedSize]}
162
+ color={colorStyles.textColor as BaseThemeColor}
163
+ fontWeight="600"
164
+ includeFontPadding={false}
165
+ textAlignVertical="center"
166
+ >
167
+ {displayText}
168
+ </Text>
169
+ </BaseBadgeContainer>
170
+ );
171
+ }
172
+
173
+ export const Badge = memo(BadgeComponent);
174
+ Badge.displayName = "Badge";
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Badge Component Types
3
+ *
4
+ * Type definitions for the Badge component and its related hooks/helpers.
5
+ * All types are explicitly exported for external consumption.
6
+ *
7
+ * @see Badge.tsx - Component implementation
8
+ */
9
+
10
+ import { BoxProps, ResponsiveValue, VariantProps } from "@shopify/restyle";
11
+ import { StyleProp, ViewProps, ViewStyle } 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 Badge component.
21
+ *
22
+ * - `sm`: 16px height - Compact indicators
23
+ * - `md`: 20px height - Standard badge (default)
24
+ * - `lg`: 24px height - Prominent badges
25
+ */
26
+ export type BadgeSize = Exclude<keyof RestyleTheme["badgeSizes"], "defaults">;
27
+
28
+ /**
29
+ * Visual variant for the Badge component.
30
+ *
31
+ * - `filled`: Solid background color
32
+ * - `outlined`: Border with transparent background
33
+ */
34
+ export type BadgeVariant = Exclude<keyof RestyleTheme["badgeVariants"], "defaults">;
35
+
36
+ // =============================================================================
37
+ // RESTYLE PROP TYPES
38
+ // =============================================================================
39
+
40
+ type BadgeVariantProps = VariantProps<RestyleTheme, "badgeVariants">;
41
+ type BadgeSizeProps = VariantProps<RestyleTheme, "badgeSizes", "size">;
42
+
43
+ /** Base props combining Restyle Box props with ViewProps and variant props */
44
+ export type BaseBadgeProps = BadgeVariantProps &
45
+ BadgeSizeProps &
46
+ BoxProps<RestyleTheme> &
47
+ ViewProps;
48
+
49
+ // =============================================================================
50
+ // COMPONENT PROPS
51
+ // =============================================================================
52
+
53
+ /**
54
+ * Props for the Badge component.
55
+ *
56
+ * @example
57
+ * // Text badge
58
+ * <Badge label="New" />
59
+ *
60
+ * @example
61
+ * // Count badge
62
+ * <Badge label={5} />
63
+ *
64
+ * @example
65
+ * // Dot mode (status indicator)
66
+ * <Badge dot color="success" />
67
+ *
68
+ * @example
69
+ * // Different variants
70
+ * <Badge label="Sale" variant="outlined" color="error" />
71
+ *
72
+ * @example
73
+ * // With spacing props (composable)
74
+ * <Badge label="New" marginRight="sm" />
75
+ */
76
+ export interface BadgeProps extends Omit<BaseBadgeProps, "variant" | "width" | "height"> {
77
+ /**
78
+ * Text or number to display in the badge.
79
+ * Ignored when `dot` is true.
80
+ */
81
+ label?: string | number;
82
+
83
+ /**
84
+ * Size preset (supports responsive values).
85
+ * @default "md"
86
+ */
87
+ size?: ResponsiveValue<BadgeSize, RestyleTheme["breakpoints"]>;
88
+
89
+ /**
90
+ * Visual variant.
91
+ * @default "filled"
92
+ */
93
+ variant?: ResponsiveValue<BadgeVariant, RestyleTheme["breakpoints"]>;
94
+
95
+ /**
96
+ * Color token.
97
+ * @default "accentPrimary"
98
+ */
99
+ color?: RestyleColor;
100
+
101
+ /**
102
+ * When true, displays a small dot without text.
103
+ * Useful for status indicators.
104
+ * @default false
105
+ */
106
+ dot?: boolean;
107
+
108
+ /**
109
+ * Maximum number to display before showing "+".
110
+ * Only applies to numeric labels.
111
+ * @default 99
112
+ */
113
+ max?: number;
114
+
115
+ /**
116
+ * Accessibility label for the badge.
117
+ */
118
+ accessibilityLabel?: string;
119
+
120
+ /** Test ID for testing frameworks */
121
+ testID?: string;
122
+
123
+ /** Custom style overrides */
124
+ style?: StyleProp<ViewStyle>;
125
+ }
126
+
127
+ // =============================================================================
128
+ // HOOK TYPES
129
+ // =============================================================================
130
+
131
+ /**
132
+ * Parameters for the useBadgeLogic hook.
133
+ */
134
+ export interface UseBadgeLogicParams {
135
+ label?: string | number;
136
+ size: ResponsiveValue<BadgeSize, RestyleTheme["breakpoints"]>;
137
+ variant: ResponsiveValue<BadgeVariant, RestyleTheme["breakpoints"]>;
138
+ color: RestyleColor;
139
+ dot: boolean;
140
+ max: number;
141
+ accessibilityLabel?: string;
142
+ }
143
+
144
+ /**
145
+ * Return value from the useBadgeLogic hook.
146
+ */
147
+ export interface UseBadgeLogicReturn {
148
+ /** Resolved size value */
149
+ resolvedSize: BadgeSize;
150
+ /** Computed badge dimensions */
151
+ dimensions: BadgeDimensions;
152
+ /** Formatted display text */
153
+ displayText: string;
154
+ /** Style values for variant+color combo */
155
+ colorStyles: BadgeColorStyles;
156
+ /** Accessibility props */
157
+ a11yProps: BadgeA11yProps;
158
+ }
159
+
160
+ // =============================================================================
161
+ // HELPER TYPES
162
+ // =============================================================================
163
+
164
+ /**
165
+ * Dimensions configuration for badge sizes.
166
+ */
167
+ export interface BadgeDimensions {
168
+ height: number;
169
+ minWidth: number;
170
+ paddingHorizontal: number;
171
+ borderRadius: number;
172
+ dotSize: number;
173
+ fontSize: number;
174
+ }
175
+
176
+ /**
177
+ * Size configuration map.
178
+ */
179
+ export type BadgeSizeConfig = Record<BadgeSize, BadgeDimensions>;
180
+
181
+ /**
182
+ * Color styles for badge rendering.
183
+ */
184
+ export interface BadgeColorStyles {
185
+ backgroundColor: RestyleColor;
186
+ textColor: RestyleColor;
187
+ borderColor: RestyleColor;
188
+ borderWidth: number;
189
+ }
190
+
191
+
192
+ // =============================================================================
193
+ // ACCESSIBILITY TYPES
194
+ // =============================================================================
195
+
196
+ /**
197
+ * Parameters for generating badge accessibility props.
198
+ */
199
+ export interface BadgeA11yParams {
200
+ /** Badge label */
201
+ label?: string | number;
202
+ /** Whether dot mode is enabled */
203
+ dot: boolean;
204
+ /** Badge color */
205
+ color: RestyleColor;
206
+ /** Custom accessibility label */
207
+ accessibilityLabel?: string;
208
+ /** Pre-translated fallback label */
209
+ fallbackLabel: string;
210
+ /** Pre-translated status indicator label */
211
+ statusIndicatorLabel: string;
212
+ /** Pre-translated color labels */
213
+ colorLabels: Record<string, string>;
214
+ }
215
+
216
+ /**
217
+ * Accessibility props returned by getBadgeA11y.
218
+ */
219
+ export interface BadgeA11yProps {
220
+ accessible: boolean;
221
+ accessibilityRole: "text";
222
+ accessibilityLabel: string;
223
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Badge Component
3
+ *
4
+ * @description Status indicators, notification counts, and labels
5
+ *
6
+ * @example
7
+ * import { Badge } from "@/design-system";
8
+ *
9
+ * // Text badge
10
+ * <Badge label="New" />
11
+ *
12
+ * // Count badge
13
+ * <Badge label={5} color="error" />
14
+ *
15
+ * // Dot status indicator
16
+ * <Badge dot color="success" />
17
+ */
18
+
19
+ export { Badge } from "./Badge";
20
+ export type {
21
+ BadgeA11yParams,
22
+ BadgeA11yProps,
23
+ BadgeColorStyles,
24
+ BadgeDimensions,
25
+ BadgeProps,
26
+ BadgeSize,
27
+ BadgeSizeConfig,
28
+ BadgeVariant,
29
+ BaseBadgeProps,
30
+ UseBadgeLogicParams,
31
+ UseBadgeLogicReturn,
32
+ } from "./Badge.types";
33
+ export {
34
+ BADGE_SIZE_CONFIG,
35
+ formatBadgeLabel,
36
+ getBadgeColorStyles,
37
+ getBadgeDimensions,
38
+ } from "./Badge.helpers";
39
+ export { getBadgeA11y } from "./Badge.a11y";
40
+ export { useBadgeLogic } from "./useBadgeLogic";
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Badge Logic Hook
3
+ *
4
+ * Extracts all computational logic from the Badge component.
5
+ * Returns memoized values for optimal render performance.
6
+ *
7
+ * Responsibilities:
8
+ * - Resolve responsive size prop
9
+ * - Calculate dimensions based on size
10
+ * - Format display text with max truncation
11
+ * - Compute color styles based on variant+color
12
+ * - Provide accessibility props
13
+ *
14
+ * @see Badge.tsx - Component consuming this hook
15
+ * @see Badge.helpers.ts - Pure calculation functions
16
+ */
17
+
18
+ import { useDesignSystem } from "../../../provider";
19
+ import { useResponsiveProp } from "@shopify/restyle";
20
+ import { useMemo } from "react";
21
+ import { getBadgeA11y } from "./Badge.a11y";
22
+ import {
23
+ formatBadgeLabel,
24
+ getBadgeColorStyles,
25
+ getBadgeDimensions,
26
+ } from "./Badge.helpers";
27
+ import { BadgeSize, BadgeVariant, UseBadgeLogicParams, UseBadgeLogicReturn } from "./Badge.types";
28
+
29
+ /**
30
+ * Orchestrates Badge rendering logic and state management.
31
+ *
32
+ * Handles:
33
+ * - Responsive size and variant resolution
34
+ * - Dimension calculation (min height, padding, font size)
35
+ * - Label formatting with max truncation (e.g., "99+" for values > 99)
36
+ * - Color style computation (background, text, border)
37
+ * - Dot mode support (empty badge)
38
+ * - Accessibility props generation
39
+ *
40
+ * @param params - Configuration object for badge behavior
41
+ * @param params.label - Badge content (text or number)
42
+ * @param params.size - Size variant ('sm' | 'md' | 'lg')
43
+ * @param params.variant - Visual variant ('filled' | 'outlined')
44
+ * @param params.color - Semantic color ('primary' | 'success' | 'warning' | 'error' | 'neutral')
45
+ * @param params.dot - Whether to show as dot (no label)
46
+ * @param params.max - Maximum value before truncation (default: undefined = no limit)
47
+ * @param params.accessibilityLabel - Custom a11y label
48
+ *
49
+ * @returns Computed values for rendering Badge
50
+ * @returns {string} resolvedSize - Resolved size variant
51
+ * @returns {object} dimensions - Min height, padding, font size
52
+ * @returns {string} displayText - Formatted display text (e.g., "99+")
53
+ * @returns {object} colorStyles - Background, text, border colors
54
+ * @returns {object} a11yProps - Accessibility props
55
+ *
56
+ * @performance This hook uses useMemo() for expensive calculations
57
+ *
58
+ * @example
59
+ * const {
60
+ * dimensions,
61
+ * displayText,
62
+ * colorStyles,
63
+ * a11yProps,
64
+ * } = useBadgeLogic({
65
+ * label: "New",
66
+ * size: "md",
67
+ * variant: "filled",
68
+ * color: "primary",
69
+ * dot: false,
70
+ * max: 99,
71
+ * });
72
+ */
73
+ export function useBadgeLogic({
74
+ label,
75
+ size,
76
+ variant,
77
+ color,
78
+ dot,
79
+ max,
80
+ accessibilityLabel,
81
+ }: UseBadgeLogicParams): UseBadgeLogicReturn {
82
+ const { labels: t } = useDesignSystem();
83
+
84
+ // Resolve responsive size
85
+ const resolvedSize = (useResponsiveProp(size) ?? "md") as BadgeSize;
86
+ const resolvedVariant = (useResponsiveProp(variant) ?? "filled") as BadgeVariant;
87
+
88
+ // Calculate dimensions
89
+ const dimensions = getBadgeDimensions(resolvedSize);
90
+
91
+ // Format display text
92
+ const displayText = dot ? "" : formatBadgeLabel(label, max);
93
+
94
+ // Get color styles
95
+ const colorStyles = getBadgeColorStyles(resolvedVariant, color);
96
+
97
+ // Build translated color labels
98
+ const colorLabels = useMemo(() => ({
99
+ accentPrimary: t.designSystem.badge.colorPrimary,
100
+ feedbackSuccess: t.designSystem.badge.colorSuccess,
101
+ feedbackWarning: t.designSystem.badge.colorWarning,
102
+ feedbackError: t.designSystem.badge.colorError,
103
+ feedbackInfo: t.designSystem.badge.colorInfo,
104
+ }), [t]);
105
+
106
+ // Accessibility props
107
+ const a11yProps = useMemo(
108
+ () =>
109
+ getBadgeA11y({
110
+ label,
111
+ dot,
112
+ color,
113
+ accessibilityLabel,
114
+ fallbackLabel: t.designSystem.badge.fallbackLabel,
115
+ statusIndicatorLabel: t.designSystem.badge.statusIndicator,
116
+ colorLabels,
117
+ }),
118
+ [label, dot, color, accessibilityLabel, t, colorLabels]
119
+ );
120
+
121
+ return {
122
+ resolvedSize,
123
+ dimensions,
124
+ displayText,
125
+ colorStyles,
126
+ a11yProps,
127
+ };
128
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Card Component Helpers
3
+ *
4
+ * Pure functions for Card variant and style resolution.
5
+ *
6
+ * ## Variants
7
+ * | Variant | Background | Border |
8
+ * |----------|-------------------|--------|
9
+ * | outlined | backgroundSecondary | Yes |
10
+ * | flat | backgroundSecondary | No |
11
+ */
12
+
13
+ import { CardVariant } from "./Card.types";
14
+
15
+ /**
16
+ * Get card variant with default fallback.
17
+ *
18
+ * @param variant - The card variant
19
+ * @returns The resolved card variant (defaults to "outlined")
20
+ *
21
+ * @example
22
+ * getCardVariant(undefined) // "outlined"
23
+ * getCardVariant("flat") // "flat"
24
+ */
25
+ export function getCardVariant(variant?: CardVariant): CardVariant {
26
+ return variant || "outlined";
27
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Card Component
3
+ *
4
+ * @description Content container with optional pressable behavior - Molecule
5
+ *
6
+ * Card provides a contained area for grouping related content.
7
+ * Combines layout, theming, and optional press handling.
8
+ * The Card sizes to fit its content.
9
+ *
10
+ * ## Variants
11
+ * - `outlined`: Border with background (default)
12
+ * - `flat`: Background only, no border
13
+ *
14
+ * ## Visual Properties
15
+ * - Border radius: lg (16px) from theme
16
+ * - Background: backgroundSecondary from theme
17
+ *
18
+ * ## Pressable Behavior
19
+ * When `onPress` is provided:
20
+ * - Card becomes a button for accessibility
21
+ * - Disabled state reduces opacity
22
+ * - accessibilityLabel is required
23
+ *
24
+ * ## Features
25
+ * - Full Restyle Box props support
26
+ * - Optional pressable behavior
27
+ * - Full accessibility support
28
+ * - Memoized for performance
29
+ *
30
+ * @see Card.types.ts - Type definitions
31
+ * @see Card.helpers.ts - Variant resolution
32
+ * @see Card.a11y.ts - Accessibility prop generation
33
+ *
34
+ * @example
35
+ * // Basic usage
36
+ * <Card>
37
+ * <Text>Card content</Text>
38
+ * </Card>
39
+ *
40
+ * @example
41
+ * // Pressable card
42
+ * <Card
43
+ * variant="outlined"
44
+ * onPress={handlePress}
45
+ * accessibilityLabel="Product card"
46
+ * >
47
+ * <Text>Tap to view details</Text>
48
+ * </Card>
49
+ *
50
+ * @example
51
+ * // Flat variant
52
+ * <Card variant="flat">
53
+ * <Text>Card content</Text>
54
+ * </Card>
55
+ */
56
+
57
+ import {
58
+ backgroundColor,
59
+ border,
60
+ createRestyleComponent,
61
+ createVariant,
62
+ layout,
63
+ spacing,
64
+ spacingShorthand,
65
+ } from "@shopify/restyle";
66
+ import React, { memo } from "react";
67
+ import { Pressable } from "react-native";
68
+ import { RestyleTheme } from "../../../core/restyle";
69
+ import { CardProps } from "./Card.types";
70
+ import { useCardLogic } from "./useCardLogic";
71
+
72
+ /**
73
+ * Base container with Restyle variant support.
74
+ * @internal
75
+ */
76
+ const BaseCardContainer = createRestyleComponent<CardProps, RestyleTheme>(
77
+ [
78
+ createVariant({ themeKey: "cardVariants", property: "variant" }),
79
+ backgroundColor,
80
+ border,
81
+ layout,
82
+ spacing,
83
+ spacingShorthand,
84
+ ],
85
+ Pressable,
86
+ );
87
+
88
+ function CardComponent({
89
+ children,
90
+ variant = "outlined",
91
+ disabled = false,
92
+ style,
93
+ testID,
94
+ onPress,
95
+ accessibilityLabel,
96
+ accessibilityHint,
97
+ ...rest
98
+ }: CardProps) {
99
+ const { isDisabled, isPressable, opacity, handlePress, a11yProps } = useCardLogic({
100
+ disabled,
101
+ onPress,
102
+ accessibilityLabel,
103
+ });
104
+
105
+ return (
106
+ <BaseCardContainer
107
+ variant={variant}
108
+ onPress={isPressable ? handlePress : undefined}
109
+ disabled={isDisabled}
110
+ testID={testID}
111
+ accessibilityHint={accessibilityHint}
112
+ opacity={opacity}
113
+ style={style}
114
+ {...a11yProps}
115
+ {...rest}
116
+ >
117
+ {children}
118
+ </BaseCardContainer>
119
+ );
120
+ }
121
+
122
+ export const Card = memo(CardComponent);
123
+ Card.displayName = "Card";