@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,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";
|