@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,125 @@
1
+ /**
2
+ * Skeleton Logic Hook
3
+ *
4
+ * Extracts all computational logic from the Skeleton component.
5
+ * Returns memoized values for optimal render performance.
6
+ *
7
+ * Responsibilities:
8
+ * - Resolve responsive size prop
9
+ * - Calculate dimensions based on variant and size
10
+ * - Manage pulse animation
11
+ * - Provide accessibility props
12
+ *
13
+ * @see Skeleton.tsx - Component consuming this hook
14
+ * @see Skeleton.helpers.ts - Pure calculation functions
15
+ */
16
+
17
+ import { useResponsiveProp } from "@shopify/restyle";
18
+ import { useMemo } from "react";
19
+ import { usePulseAnimation } from "../../../hooks/animations";
20
+ import { getSkeletonA11y } from "./Skeleton.a11y";
21
+ import {
22
+ getSkeletonBorderRadius,
23
+ getSkeletonDimensions,
24
+ SKELETON_ANIMATION,
25
+ } from "./Skeleton.helpers";
26
+ import { SkeletonSize, SkeletonVariant, UseSkeletonLogicParams, UseSkeletonLogicReturn } from "./Skeleton.types";
27
+
28
+ /**
29
+ * Orchestrates Skeleton rendering logic and state management.
30
+ *
31
+ * Handles:
32
+ * - Responsive size and variant resolution
33
+ * - Dimension calculation (width, height) with custom overrides
34
+ * - Border radius determination per variant
35
+ * - Pulse animation management (looping opacity)
36
+ * - Reduced motion support (disables animation)
37
+ * - Accessibility props generation
38
+ *
39
+ * @param params - Configuration object for skeleton behavior
40
+ * @param params.variant - Shape variant ('text' | 'circular' | 'rectangular')
41
+ * @param params.size - Size variant ('sm' | 'md' | 'lg')
42
+ * @param params.width - Custom width override (responsive)
43
+ * @param params.height - Custom height override (responsive)
44
+ * @param params.animation - Animation type ('pulse' | 'wave' | 'none')
45
+ * @param params.color - Theme color token for skeleton
46
+ * @param params.duration - Animation duration in ms (default: 1500)
47
+ *
48
+ * @returns Computed values for rendering Skeleton
49
+ * @returns {number} resolvedWidth - Computed width in pixels
50
+ * @returns {number} resolvedHeight - Computed height in pixels
51
+ * @returns {number} borderRadius - Border radius in pixels
52
+ * @returns {Animated.Value} animatedOpacity - Animated opacity (0.3-1.0)
53
+ * @returns {string} backgroundColor - Background color token
54
+ * @returns {object} a11yProps - Accessibility props
55
+ *
56
+ * @performance
57
+ * - Uses native driver for smooth 60fps animations
58
+ * - Respects reduced motion preferences for accessibility
59
+ * - Animation loop runs independently per component
60
+ *
61
+ * @example
62
+ * const {
63
+ * resolvedWidth,
64
+ * resolvedHeight,
65
+ * borderRadius,
66
+ * animatedOpacity,
67
+ * backgroundColor,
68
+ * } = useSkeletonLogic({
69
+ * variant: "text",
70
+ * size: "md",
71
+ * animation: "pulse",
72
+ * color: "specialSkeleton",
73
+ * duration: 1500,
74
+ * });
75
+ */
76
+ export function useSkeletonLogic({
77
+ variant,
78
+ size,
79
+ width: customWidth,
80
+ height: customHeight,
81
+ animation,
82
+ color,
83
+ duration,
84
+ }: UseSkeletonLogicParams): UseSkeletonLogicReturn {
85
+ // Resolve responsive size
86
+ const resolvedSize = (useResponsiveProp(size) ?? "md") as SkeletonSize;
87
+ const resolvedVariant = (useResponsiveProp(variant) ?? "text") as SkeletonVariant;
88
+ const resolvedCustomWidth = useResponsiveProp(customWidth);
89
+ const resolvedCustomHeight = useResponsiveProp(customHeight);
90
+
91
+ // Calculate dimensions
92
+ const { width: resolvedWidth, height: resolvedHeight } = useMemo(
93
+ () =>
94
+ getSkeletonDimensions({
95
+ variant: resolvedVariant,
96
+ size: resolvedSize,
97
+ customWidth: resolvedCustomWidth,
98
+ customHeight: resolvedCustomHeight,
99
+ }),
100
+ [resolvedVariant, resolvedSize, resolvedCustomWidth, resolvedCustomHeight]
101
+ );
102
+
103
+ // Get border radius for variant
104
+ const borderRadius = getSkeletonBorderRadius(resolvedVariant);
105
+
106
+ // Pulse animation (respects reduced motion via usePulseAnimation)
107
+ const animatedOpacity = usePulseAnimation({
108
+ duration,
109
+ minOpacity: SKELETON_ANIMATION.MIN_OPACITY,
110
+ maxOpacity: SKELETON_ANIMATION.MAX_OPACITY,
111
+ enabled: animation === "pulse",
112
+ });
113
+
114
+ // Accessibility props
115
+ const a11yProps = getSkeletonA11y({});
116
+
117
+ return {
118
+ resolvedWidth,
119
+ resolvedHeight,
120
+ borderRadius,
121
+ animatedOpacity,
122
+ backgroundColor: color,
123
+ a11yProps,
124
+ };
125
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Spinner Component Helpers
3
+ *
4
+ * Pure functions for mapping Spinner props to ActivityIndicator values.
5
+ *
6
+ * ## Size Mapping
7
+ * | Spinner Size | ActivityIndicator | Visual Size |
8
+ * |--------------|-------------------|-------------|
9
+ * | sm | "small" | ~20px |
10
+ * | lg | "large" | ~36px |
11
+ *
12
+ * Note: Exact pixel sizes vary by platform (iOS vs Android).
13
+ */
14
+
15
+ import { SpinnerSize } from "./Spinner.types";
16
+
17
+ /**
18
+ * Maps design system size tokens to ActivityIndicator size prop.
19
+ * @internal
20
+ */
21
+ const SPINNER_ACTIVITY_INDICATOR_SIZES: Record<SpinnerSize, "small" | "large"> = {
22
+ sm: "small",
23
+ lg: "large",
24
+ } as const;
25
+
26
+ /**
27
+ * Get ActivityIndicator size from Spinner size token.
28
+ *
29
+ * @param size - The spinner size variant (sm | lg)
30
+ * @returns The corresponding ActivityIndicator size
31
+ *
32
+ * @example
33
+ * getSpinnerActivityIndicatorSize("sm") // "small"
34
+ * getSpinnerActivityIndicatorSize("lg") // "large"
35
+ */
36
+ export function getSpinnerActivityIndicatorSize(
37
+ size: SpinnerSize
38
+ ): "small" | "large" {
39
+ return SPINNER_ACTIVITY_INDICATOR_SIZES[size] || SPINNER_ACTIVITY_INDICATOR_SIZES.sm;
40
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Spinner Component
3
+ *
4
+ * @description Loading indicator with theme integration - Atom
5
+ *
6
+ * Spinners provide visual feedback during asynchronous operations.
7
+ * Uses React Native's ActivityIndicator with theme-aware colors.
8
+ *
9
+ * ## Sizes
10
+ * | Size | Platform Mapping | Use Case |
11
+ * |------|------------------|----------|
12
+ * | sm | "small" | Inline loading, buttons |
13
+ * | lg | "large" | Full-screen loading, cards |
14
+ *
15
+ * ## Features
16
+ * - Two sizes: sm (small) and lg (large)
17
+ * - Responsive size support (phone/tablet breakpoints)
18
+ * - Theme-aware color tokens
19
+ * - Full accessibility support (progressbar role)
20
+ *
21
+ * @performance
22
+ * - Wrapped with React.memo() to prevent unnecessary re-renders
23
+ * - Uses useMemo() for color resolution from theme tokens
24
+ * - ActivityIndicator size mapped via constant-time lookup table
25
+ * - Native ActivityIndicator optimized by React Native for smooth animation
26
+ *
27
+ * @see Spinner.types.ts - Type definitions
28
+ * @see Spinner.helpers.ts - Size mapping functions
29
+ * @see Spinner.a11y.ts - Accessibility prop generation
30
+ *
31
+ * @example
32
+ * // Basic usage
33
+ * <Spinner />
34
+ *
35
+ * @example
36
+ * // Large with custom color
37
+ * <Spinner size="lg" color="feedbackSuccess" />
38
+ *
39
+ * @example
40
+ * // Responsive size
41
+ * <Spinner size={{ phone: "sm", tablet: "lg" }} />
42
+ *
43
+ * @example
44
+ * // With accessibility
45
+ * <Spinner accessibilityLabel="Loading your data" />
46
+ */
47
+
48
+ import {
49
+ createRestyleComponent,
50
+ createVariant,
51
+ layout,
52
+ spacing,
53
+ spacingShorthand,
54
+ } from "@shopify/restyle";
55
+ import React, { memo } from "react";
56
+ import { ActivityIndicator } from "react-native";
57
+ import { RestyleTheme } from "../../../core/restyle";
58
+ import { Box } from "../../layout";
59
+ import { BaseSpinnerProps, SpinnerProps } from "./Spinner.types";
60
+ import { useSpinnerLogic } from "./useSpinnerLogic";
61
+
62
+ /**
63
+ * Base Spinner container with Restyle variant support.
64
+ * @internal
65
+ */
66
+ const BaseSpinner = createRestyleComponent<BaseSpinnerProps, RestyleTheme>(
67
+ [
68
+ createVariant({ themeKey: "spinnerSizes", property: "size" }),
69
+ layout,
70
+ spacing,
71
+ spacingShorthand,
72
+ ],
73
+ Box,
74
+ );
75
+
76
+ function SpinnerComponent({
77
+ size = "sm",
78
+ color = "accentPrimary",
79
+ accessibilityLabel,
80
+ testID,
81
+ ...rest
82
+ }: SpinnerProps) {
83
+ const { resolvedSize, activityIndicatorSize, spinnerColor, a11yProps } =
84
+ useSpinnerLogic({
85
+ size,
86
+ color,
87
+ accessibilityLabel,
88
+ });
89
+
90
+ return (
91
+ <BaseSpinner
92
+ size={resolvedSize}
93
+ alignItems="center"
94
+ justifyContent="center"
95
+ testID={testID}
96
+ {...a11yProps}
97
+ {...rest}
98
+ >
99
+ <ActivityIndicator size={activityIndicatorSize} color={spinnerColor} />
100
+ </BaseSpinner>
101
+ );
102
+ }
103
+
104
+ export const Spinner = memo(SpinnerComponent);
105
+ Spinner.displayName = "Spinner";
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Spinner Component Types
3
+ *
4
+ * Type definitions for the Spinner component and its related hooks/helpers.
5
+ *
6
+ * @see Spinner.tsx - Component implementation
7
+ */
8
+
9
+ import { BoxProps, ResponsiveValue, VariantProps } from "@shopify/restyle";
10
+ import { ViewProps } from "react-native";
11
+ import { RestyleTheme } from "../../../core/restyle";
12
+ import { RestyleColor } from "../../../types";
13
+
14
+ /**
15
+ * Size variants for the Spinner.
16
+ * Derived from theme spinnerSizes.
17
+ * Maps to React Native ActivityIndicator sizes.
18
+ *
19
+ * - `sm`: "small" ActivityIndicator - for inline/button loading
20
+ * - `lg`: "large" ActivityIndicator - for full-screen/card loading
21
+ */
22
+ export type SpinnerSize = Exclude<
23
+ keyof RestyleTheme["spinnerSizes"],
24
+ "defaults"
25
+ >;
26
+
27
+ /** Restyle props for Spinner size variant */
28
+ type SpinnerSizeProps = VariantProps<RestyleTheme, "spinnerSizes", "size">;
29
+
30
+ /** Combined restyle props for base spinner */
31
+ export type BaseSpinnerProps = SpinnerSizeProps &
32
+ BoxProps<RestyleTheme> &
33
+ ViewProps;
34
+
35
+ /**
36
+ * Props for the Spinner component.
37
+ *
38
+ * @example
39
+ * <Spinner size="lg" color="accentPrimary" accessibilityLabel="Loading" />
40
+ *
41
+ * @example
42
+ * // Responsive size
43
+ * <Spinner size={{ phone: "sm", tablet: "lg" }} />
44
+ */
45
+ export interface SpinnerProps extends Omit<BaseSpinnerProps, "size"> {
46
+ /**
47
+ * Size of the spinner (supports responsive values).
48
+ * @default "sm"
49
+ */
50
+ size?: ResponsiveValue<SpinnerSize, RestyleTheme["breakpoints"]>;
51
+
52
+ /**
53
+ * Spinner color from theme palette.
54
+ * @default "accentPrimary"
55
+ */
56
+ color?: RestyleColor;
57
+
58
+ /**
59
+ * Accessibility label for screen readers.
60
+ * @default "Loading"
61
+ */
62
+ accessibilityLabel?: string;
63
+
64
+ /** Test ID for testing frameworks */
65
+ testID?: string;
66
+ }
67
+
68
+ /**
69
+ * Parameters for the useSpinnerLogic hook.
70
+ */
71
+ export interface UseSpinnerLogicParams {
72
+ size: ResponsiveValue<SpinnerSize, RestyleTheme["breakpoints"]>;
73
+ color: RestyleColor;
74
+ accessibilityLabel?: string;
75
+ }
76
+
77
+ /**
78
+ * Return value from the useSpinnerLogic hook.
79
+ */
80
+ export interface UseSpinnerLogicReturn {
81
+ /** Resolved size for restyle variant */
82
+ resolvedSize: SpinnerSize;
83
+ /** Mapped ActivityIndicator size ("small" | "large") */
84
+ activityIndicatorSize: "small" | "large";
85
+ /** Resolved hex color string */
86
+ spinnerColor: string;
87
+ /** Accessibility props */
88
+ a11yProps: SpinnerA11yProps;
89
+ }
90
+
91
+ /**
92
+ * Parameters for generating spinner accessibility props.
93
+ */
94
+ export interface SpinnerA11yParams {
95
+ /**
96
+ * Text description of what is loading.
97
+ */
98
+ accessibilityLabel?: string;
99
+
100
+ /**
101
+ * Pre-translated fallback label from i18n.
102
+ * Used when accessibilityLabel is not provided.
103
+ */
104
+ fallbackLabel: string;
105
+ }
106
+
107
+ /**
108
+ * Accessibility props returned by getSpinnerA11y.
109
+ */
110
+ export interface SpinnerA11yProps {
111
+ accessibilityLabel: string;
112
+ accessibilityRole: "progressbar";
113
+ accessibilityState: { busy: boolean };
114
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Spinner Module
3
+ *
4
+ * Atom component for displaying loading indicators with theme integration.
5
+ *
6
+ * @example
7
+ * import { Spinner } from "@/design-system/primitives/feedback/Spinner";
8
+ *
9
+ * <Spinner size="lg" color="accentPrimary" accessibilityLabel="Loading" />
10
+ */
11
+
12
+ export { Spinner } from "./Spinner";
13
+ export type {
14
+ SpinnerProps,
15
+ SpinnerSize,
16
+ BaseSpinnerProps,
17
+ } from "./Spinner.types";
18
+ export * from "./Spinner.a11y";
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Spinner Logic Hook
3
+ *
4
+ * Extracts all computational logic from the Spinner component.
5
+ * Returns memoized values for optimal render performance.
6
+ *
7
+ * Responsibilities:
8
+ * - Resolve responsive size prop
9
+ * - Map size token to ActivityIndicator size
10
+ * - Resolve color token to hex value
11
+ *
12
+ * @see Spinner.tsx - Component consuming this hook
13
+ * @see Spinner.helpers.ts - Pure calculation functions
14
+ */
15
+
16
+ import { useResponsiveProp } from "@shopify/restyle";
17
+ import { useMemo } from "react";
18
+ import { useDesignSystem } from "../../../provider";
19
+ import { useRestyleTheme } from "../../../core/restyle";
20
+ import { BaseThemeColor } from "../../../types";
21
+ import { getSpinnerA11y } from "./Spinner.a11y";
22
+ import { getSpinnerActivityIndicatorSize } from "./Spinner.helpers";
23
+ import { SpinnerSize, UseSpinnerLogicParams, UseSpinnerLogicReturn } from "./Spinner.types";
24
+
25
+ /**
26
+ * Orchestrates Spinner rendering logic and state management.
27
+ *
28
+ * Handles:
29
+ * - Responsive size resolution
30
+ * - Size mapping to ActivityIndicator size ('small' | 'large')
31
+ * - Color token resolution to hex value
32
+ * - Accessibility props generation
33
+ *
34
+ * @param params - Configuration object for spinner behavior
35
+ * @param params.size - Size variant ('sm' | 'md' | 'lg')
36
+ * @param params.color - Theme color token for spinner
37
+ * @param params.accessibilityLabel - Custom a11y label
38
+ *
39
+ * @returns Computed values for rendering Spinner
40
+ * @returns {string} resolvedSize - Resolved size variant
41
+ * @returns {string} activityIndicatorSize - RN ActivityIndicator size
42
+ * @returns {string} spinnerColor - Resolved hex color
43
+ * @returns {object} a11yProps - Accessibility props
44
+ *
45
+ * @performance This hook uses useMemo() for color resolution
46
+ *
47
+ * @example
48
+ * const { resolvedSize, activityIndicatorSize, spinnerColor } = useSpinnerLogic({
49
+ * size: "lg",
50
+ * color: "accentPrimary",
51
+ * });
52
+ *
53
+ * @example
54
+ * // With responsive size
55
+ * const { activityIndicatorSize, spinnerColor } = useSpinnerLogic({
56
+ * size: { phone: "sm", tablet: "lg" },
57
+ * color: "accentPrimary",
58
+ * });
59
+ */
60
+ export function useSpinnerLogic({
61
+ size,
62
+ color,
63
+ accessibilityLabel,
64
+ }: UseSpinnerLogicParams): UseSpinnerLogicReturn {
65
+ const { labels: t } = useDesignSystem();
66
+ const theme = useRestyleTheme();
67
+ const resolvedSize = (useResponsiveProp(size) ?? "sm") as SpinnerSize;
68
+
69
+ const activityIndicatorSize = getSpinnerActivityIndicatorSize(resolvedSize);
70
+
71
+ const spinnerColor = theme.colors[color as BaseThemeColor];
72
+
73
+ const a11yProps = useMemo(
74
+ () => getSpinnerA11y({ accessibilityLabel, fallbackLabel: t.designSystem.spinner.fallbackLabel }),
75
+ [accessibilityLabel, t.designSystem.spinner.fallbackLabel],
76
+ );
77
+
78
+ return {
79
+ resolvedSize,
80
+ activityIndicatorSize,
81
+ spinnerColor,
82
+ a11yProps,
83
+ };
84
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Toast Component Helpers
3
+ *
4
+ * Pure functions for mapping Toast props to style values.
5
+ *
6
+ * ## Variant Color Mapping
7
+ * | Variant | Background Token | Border Token | Icon Token |
8
+ * |---------|----------------------|----------------------|---------------------|
9
+ * | success | feedbackSuccessLight | feedbackSuccess | feedbackSuccessDark |
10
+ * | error | feedbackErrorLight | feedbackError | feedbackErrorDark |
11
+ * | warning | feedbackWarningLight | feedbackWarning | feedbackWarningDark |
12
+ * | info | feedbackInfoLight | feedbackInfo | feedbackInfoDark |
13
+ *
14
+ * @see Toast.types.ts - Type definitions
15
+ */
16
+
17
+ import { MaterialIconName, RestyleColor } from "../../../types";
18
+ import { ToastVariant } from "./Toast.types";
19
+
20
+ // =============================================================================
21
+ // VARIANT COLOR MAPPINGS
22
+ // =============================================================================
23
+
24
+ /**
25
+ * Background color tokens for each variant.
26
+ * @internal
27
+ */
28
+ const TOAST_BACKGROUND_COLORS: Record<ToastVariant, RestyleColor> = {
29
+ success: "feedbackSuccessLight",
30
+ error: "feedbackErrorLight",
31
+ warning: "feedbackWarningLight",
32
+ info: "feedbackInfoLight",
33
+ } as const;
34
+
35
+ /**
36
+ * Border color tokens for each variant.
37
+ * @internal
38
+ */
39
+ const TOAST_BORDER_COLORS: Record<ToastVariant, RestyleColor> = {
40
+ success: "feedbackSuccess",
41
+ error: "feedbackError",
42
+ warning: "feedbackWarning",
43
+ info: "feedbackInfo",
44
+ } as const;
45
+
46
+ /**
47
+ * Icon color tokens for each variant.
48
+ * @internal
49
+ */
50
+ const TOAST_ICON_COLORS: Record<ToastVariant, RestyleColor> = {
51
+ success: "feedbackSuccessDark",
52
+ error: "feedbackErrorDark",
53
+ warning: "feedbackWarningDark",
54
+ info: "feedbackInfoDark",
55
+ } as const;
56
+
57
+ /**
58
+ * Text color tokens for each variant.
59
+ * @internal
60
+ */
61
+ const TOAST_TEXT_COLORS: Record<ToastVariant, RestyleColor> = {
62
+ success: "feedbackSuccessDark",
63
+ error: "feedbackErrorDark",
64
+ warning: "feedbackWarningDark",
65
+ info: "feedbackInfoDark",
66
+ } as const;
67
+
68
+ /**
69
+ * Default icon for each variant.
70
+ * @internal
71
+ */
72
+ const TOAST_DEFAULT_ICONS: Record<ToastVariant, MaterialIconName> = {
73
+ success: "check-circle",
74
+ error: "error",
75
+ warning: "warning",
76
+ info: "info",
77
+ } as const;
78
+
79
+ // =============================================================================
80
+ // PUBLIC HELPERS
81
+ // =============================================================================
82
+
83
+ /**
84
+ * Get background color token for toast variant.
85
+ *
86
+ * @param variant - Toast variant
87
+ * @returns Background color token
88
+ *
89
+ * @example
90
+ * getToastBackgroundColor("success") // "feedbackSuccessLight"
91
+ */
92
+ export function getToastBackgroundColor(variant: ToastVariant): RestyleColor {
93
+ return TOAST_BACKGROUND_COLORS[variant] ?? TOAST_BACKGROUND_COLORS.info;
94
+ }
95
+
96
+ /**
97
+ * Get border color token for toast variant.
98
+ *
99
+ * @param variant - Toast variant
100
+ * @returns Border color token
101
+ *
102
+ * @example
103
+ * getToastBorderColor("error") // "feedbackError"
104
+ */
105
+ export function getToastBorderColor(variant: ToastVariant): RestyleColor {
106
+ return TOAST_BORDER_COLORS[variant] ?? TOAST_BORDER_COLORS.info;
107
+ }
108
+
109
+ /**
110
+ * Get icon color token for toast variant.
111
+ *
112
+ * @param variant - Toast variant
113
+ * @returns Icon color token
114
+ *
115
+ * @example
116
+ * getToastIconColor("warning") // "feedbackWarningDark"
117
+ */
118
+ export function getToastIconColor(variant: ToastVariant): RestyleColor {
119
+ return TOAST_ICON_COLORS[variant] ?? TOAST_ICON_COLORS.info;
120
+ }
121
+
122
+ /**
123
+ * Get text color token for toast variant.
124
+ *
125
+ * @param variant - Toast variant
126
+ * @returns Text color token
127
+ *
128
+ * @example
129
+ * getToastTextColor("info") // "feedbackInfoDark"
130
+ */
131
+ export function getToastTextColor(variant: ToastVariant): RestyleColor {
132
+ return TOAST_TEXT_COLORS[variant] ?? TOAST_TEXT_COLORS.info;
133
+ }
134
+
135
+ /**
136
+ * Get default icon for toast variant, or use custom icon if provided.
137
+ *
138
+ * @param variant - Toast variant
139
+ * @param customIcon - Optional custom icon override
140
+ * @returns Icon name to display
141
+ *
142
+ * @example
143
+ * getToastIcon("success") // "check-circle"
144
+ * getToastIcon("success", "thumb-up") // "thumb-up"
145
+ */
146
+ export function getToastIcon(
147
+ variant: ToastVariant,
148
+ customIcon?: MaterialIconName
149
+ ): MaterialIconName {
150
+ return customIcon ?? TOAST_DEFAULT_ICONS[variant] ?? TOAST_DEFAULT_ICONS.info;
151
+ }
152
+
153
+ /**
154
+ * Generate a unique ID for a toast.
155
+ *
156
+ * @returns Unique toast ID
157
+ *
158
+ * @example
159
+ * generateToastId() // "toast-1234567890-abc"
160
+ */
161
+ export function generateToastId(): string {
162
+ return `toast-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
163
+ }