@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,95 @@
|
|
|
1
|
+
import { BoxProps, ResponsiveValue, VariantProps } from "@shopify/restyle";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
import { AccessibilityState, GestureResponderEvent, PressableProps, StyleProp, ViewStyle } from "react-native";
|
|
4
|
+
import { RestyleTheme } from "../../../core/restyle";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Visual variant for the Card component.
|
|
8
|
+
*
|
|
9
|
+
* - `outlined`: Card with border and background
|
|
10
|
+
* - `flat`: Card with background only, no border
|
|
11
|
+
*/
|
|
12
|
+
export type CardVariant = Exclude<
|
|
13
|
+
keyof RestyleTheme["cardVariants"],
|
|
14
|
+
"defaults"
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export type BaseCardProps = VariantProps<RestyleTheme, "cardVariants", "variant"> &
|
|
18
|
+
BoxProps<RestyleTheme> &
|
|
19
|
+
PressableProps;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Props for the Card component.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Basic usage
|
|
26
|
+
* <Card>
|
|
27
|
+
* <Text>Card content</Text>
|
|
28
|
+
* </Card>
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Pressable card
|
|
32
|
+
* <Card
|
|
33
|
+
* variant="outlined"
|
|
34
|
+
* onPress={handlePress}
|
|
35
|
+
* accessibilityLabel="Product card"
|
|
36
|
+
* >
|
|
37
|
+
* <Text>Tap to view details</Text>
|
|
38
|
+
* </Card>
|
|
39
|
+
*/
|
|
40
|
+
export interface CardProps extends Omit<BaseCardProps, "variant"> {
|
|
41
|
+
children?: ReactNode;
|
|
42
|
+
/** Visual variant of the card (supports responsive values) */
|
|
43
|
+
variant?: ResponsiveValue<CardVariant, RestyleTheme["breakpoints"]>;
|
|
44
|
+
/** Whether the card is disabled (only applies when onPress is provided) */
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/** Container style overrides */
|
|
47
|
+
style?: StyleProp<ViewStyle>;
|
|
48
|
+
/** Test ID for testing */
|
|
49
|
+
testID?: string;
|
|
50
|
+
/** Accessibility label */
|
|
51
|
+
accessibilityLabel?: string;
|
|
52
|
+
/** Accessibility hint */
|
|
53
|
+
accessibilityHint?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parameters for generating card accessibility props.
|
|
58
|
+
*/
|
|
59
|
+
export interface CardA11yParams {
|
|
60
|
+
/** Label for screen readers (required for pressable cards) */
|
|
61
|
+
accessibilityLabel?: string;
|
|
62
|
+
/** Whether the card is disabled */
|
|
63
|
+
disabled: boolean;
|
|
64
|
+
/** Press handler (presence determines if card is pressable) */
|
|
65
|
+
onPress?: ((event: GestureResponderEvent) => void) | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Accessibility props returned by getCardA11y.
|
|
70
|
+
*/
|
|
71
|
+
export interface CardA11yProps {
|
|
72
|
+
accessibilityRole?: "button" | "none";
|
|
73
|
+
accessibilityLabel?: string;
|
|
74
|
+
accessibilityState?: AccessibilityState;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Parameters for the useCardLogic hook.
|
|
79
|
+
*/
|
|
80
|
+
export interface UseCardLogicParams {
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
onPress?: ((event: GestureResponderEvent) => void) | null;
|
|
83
|
+
accessibilityLabel?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Return value from the useCardLogic hook.
|
|
88
|
+
*/
|
|
89
|
+
export interface UseCardLogicReturn {
|
|
90
|
+
isDisabled: boolean;
|
|
91
|
+
isPressable: boolean;
|
|
92
|
+
opacity: number;
|
|
93
|
+
handlePress: (event: GestureResponderEvent) => void;
|
|
94
|
+
a11yProps: CardA11yProps;
|
|
95
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card Module
|
|
3
|
+
*
|
|
4
|
+
* Molecule component for content grouping with optional press behavior.
|
|
5
|
+
*
|
|
6
|
+
* ## Variants
|
|
7
|
+
* - `outlined`: Border with background (default)
|
|
8
|
+
* - `flat`: Background only, no border
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* import { Card } from "@/design-system/primitives/content/Card";
|
|
12
|
+
*
|
|
13
|
+
* <Card padding="lg" onPress={handlePress} accessibilityLabel="View details">
|
|
14
|
+
* <Text>Card content</Text>
|
|
15
|
+
* </Card>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export { Card } from "./Card";
|
|
19
|
+
export type { CardProps, CardVariant } from "./Card.types";
|
|
20
|
+
export * from "./Card.a11y";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
|
+
import { GestureResponderEvent } from "react-native";
|
|
3
|
+
import { getCardA11y } from "./Card.a11y";
|
|
4
|
+
import { UseCardLogicParams, UseCardLogicReturn } from "./Card.types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Orchestrates Card rendering logic and state management.
|
|
8
|
+
*
|
|
9
|
+
* Handles:
|
|
10
|
+
* - Pressable state determination
|
|
11
|
+
* - Disabled state management
|
|
12
|
+
* - Opacity calculation for disabled state
|
|
13
|
+
* - Press handler with disabled check
|
|
14
|
+
* - Accessibility props generation
|
|
15
|
+
*
|
|
16
|
+
* @param params - Configuration object for card behavior
|
|
17
|
+
* @returns Computed values for rendering Card
|
|
18
|
+
*/
|
|
19
|
+
export function useCardLogic({
|
|
20
|
+
disabled = false,
|
|
21
|
+
onPress,
|
|
22
|
+
accessibilityLabel,
|
|
23
|
+
}: UseCardLogicParams): UseCardLogicReturn {
|
|
24
|
+
const isPressable = !!onPress;
|
|
25
|
+
const isDisabled = isPressable && disabled;
|
|
26
|
+
const opacity = isDisabled ? 0.5 : 1;
|
|
27
|
+
|
|
28
|
+
const handlePress = useCallback(
|
|
29
|
+
(event: GestureResponderEvent) => {
|
|
30
|
+
if (isDisabled || !onPress) return;
|
|
31
|
+
onPress(event);
|
|
32
|
+
},
|
|
33
|
+
[isDisabled, onPress],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const a11yProps = useMemo(
|
|
37
|
+
() => getCardA11y({ accessibilityLabel, disabled: isDisabled, onPress }),
|
|
38
|
+
[accessibilityLabel, isDisabled, onPress],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
isDisabled,
|
|
43
|
+
isPressable,
|
|
44
|
+
opacity,
|
|
45
|
+
handlePress,
|
|
46
|
+
a11yProps,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip Component Helpers
|
|
3
|
+
*
|
|
4
|
+
* Pure functions for computing Chip styles, sizes, and colors.
|
|
5
|
+
* All calculations are derived from the centralized scales.ts token file.
|
|
6
|
+
*
|
|
7
|
+
* ## Size Scale
|
|
8
|
+
* | Size | Height | Icon | Text Variant | Padding |
|
|
9
|
+
* |------|--------|-------|--------------|---------|
|
|
10
|
+
* | sm | 24px | xs | captionSmall | xs (4px)|
|
|
11
|
+
* | md | 32px | sm | labelSmall | sm (8px)|
|
|
12
|
+
* | lg | 40px | md | labelMedium | md (12px)|
|
|
13
|
+
*
|
|
14
|
+
* ## Color Support
|
|
15
|
+
* Accepts any theme color token. Preset configurations exist for semantic colors:
|
|
16
|
+
* - accentPrimary, accentSecondary
|
|
17
|
+
* - feedbackSuccess, feedbackWarning, feedbackError, feedbackInfo
|
|
18
|
+
*
|
|
19
|
+
* Any other theme color will use sensible defaults for filled/outlined variants.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { RestyleColor } from "../../../types";
|
|
23
|
+
import { IconSize } from "../Icon";
|
|
24
|
+
import {
|
|
25
|
+
ChipColorTokens,
|
|
26
|
+
ChipSize,
|
|
27
|
+
ChipStyleResult,
|
|
28
|
+
ChipTextVariant,
|
|
29
|
+
ChipVariant,
|
|
30
|
+
ResolveChipStyleParams,
|
|
31
|
+
} from "./Chip.types";
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// THEME VARIANT KEY MAPPING
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Theme variant key mapping.
|
|
39
|
+
* Maps component variant names to theme variant keys.
|
|
40
|
+
*/
|
|
41
|
+
type ThemeVariantKey = "filled" | "outlined";
|
|
42
|
+
|
|
43
|
+
const VARIANT_TO_THEME_KEY: Record<ChipVariant, ThemeVariantKey> = {
|
|
44
|
+
filled: "filled",
|
|
45
|
+
outlined: "outlined",
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get theme variant key from component variant.
|
|
50
|
+
*
|
|
51
|
+
* @param variant - The component variant
|
|
52
|
+
* @returns The theme variant key
|
|
53
|
+
*/
|
|
54
|
+
export function getThemeVariantKey(variant: ChipVariant): ThemeVariantKey {
|
|
55
|
+
return VARIANT_TO_THEME_KEY[variant];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// SIZE RESOLUTION
|
|
60
|
+
// =============================================================================
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Chip icon size mapping.
|
|
64
|
+
*
|
|
65
|
+
* | Chip Size | Icon Size |
|
|
66
|
+
* |-----------|-----------|
|
|
67
|
+
* | sm | xs (12px) |
|
|
68
|
+
* | md | sm (16px) |
|
|
69
|
+
* | lg | md (20px) |
|
|
70
|
+
*/
|
|
71
|
+
export const CHIP_ICON_SIZE: Record<ChipSize, IconSize> = {
|
|
72
|
+
sm: "xs",
|
|
73
|
+
md: "sm",
|
|
74
|
+
lg: "md",
|
|
75
|
+
} as const;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Chip text variant mapping.
|
|
79
|
+
*
|
|
80
|
+
* | Chip Size | Text Variant |
|
|
81
|
+
* |-----------|--------------|
|
|
82
|
+
* | sm | captionSmall |
|
|
83
|
+
* | md | labelSmall |
|
|
84
|
+
* | lg | labelMedium |
|
|
85
|
+
*/
|
|
86
|
+
export const CHIP_TEXT_VARIANT: Record<ChipSize, ChipTextVariant> = {
|
|
87
|
+
sm: "captionSmall",
|
|
88
|
+
md: "labelSmall",
|
|
89
|
+
lg: "labelMedium",
|
|
90
|
+
} as const;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get icon size based on chip size.
|
|
94
|
+
*
|
|
95
|
+
* @param size - The chip size
|
|
96
|
+
* @returns The icon size key
|
|
97
|
+
*/
|
|
98
|
+
export function getChipIconSize(size: ChipSize): IconSize {
|
|
99
|
+
return CHIP_ICON_SIZE[size];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get text variant based on chip size.
|
|
104
|
+
*
|
|
105
|
+
* @param size - The chip size
|
|
106
|
+
* @returns The text variant for Text
|
|
107
|
+
*/
|
|
108
|
+
export function getChipTextVariant(size: ChipSize): ChipTextVariant {
|
|
109
|
+
return CHIP_TEXT_VARIANT[size];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// COLOR RESOLUTION
|
|
114
|
+
// =============================================================================
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Preset color configurations for common semantic colors.
|
|
118
|
+
* These provide optimized backgrounds and text colors.
|
|
119
|
+
*/
|
|
120
|
+
const PRESET_COLORS: Record<string, ChipColorTokens> = {
|
|
121
|
+
accentPrimary: {
|
|
122
|
+
filled: "accentPrimary",
|
|
123
|
+
accent: "accentPrimary",
|
|
124
|
+
filledText: "textInverse",
|
|
125
|
+
accentText: "accentPrimary",
|
|
126
|
+
},
|
|
127
|
+
accentSecondary: {
|
|
128
|
+
filled: "accentSecondary",
|
|
129
|
+
accent: "accentSecondary",
|
|
130
|
+
filledText: "textInverse",
|
|
131
|
+
accentText: "accentSecondary",
|
|
132
|
+
},
|
|
133
|
+
feedbackSuccess: {
|
|
134
|
+
filled: "feedbackSuccess",
|
|
135
|
+
accent: "feedbackSuccess",
|
|
136
|
+
filledText: "textInverse",
|
|
137
|
+
accentText: "feedbackSuccessDark",
|
|
138
|
+
},
|
|
139
|
+
feedbackWarning: {
|
|
140
|
+
filled: "feedbackWarning",
|
|
141
|
+
accent: "feedbackWarning",
|
|
142
|
+
filledText: "textPrimary",
|
|
143
|
+
accentText: "feedbackWarningDark",
|
|
144
|
+
},
|
|
145
|
+
feedbackError: {
|
|
146
|
+
filled: "feedbackError",
|
|
147
|
+
accent: "feedbackError",
|
|
148
|
+
filledText: "textInverse",
|
|
149
|
+
accentText: "feedbackErrorDark",
|
|
150
|
+
},
|
|
151
|
+
feedbackInfo: {
|
|
152
|
+
filled: "feedbackInfo",
|
|
153
|
+
accent: "feedbackInfo",
|
|
154
|
+
filledText: "textInverse",
|
|
155
|
+
accentText: "feedbackInfoDark",
|
|
156
|
+
},
|
|
157
|
+
} as const;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get color tokens for a chip color.
|
|
161
|
+
* Uses preset configurations for semantic colors, or generates tokens for any theme color.
|
|
162
|
+
*
|
|
163
|
+
* @param color - Any theme color token
|
|
164
|
+
* @returns Color tokens for the chip
|
|
165
|
+
*/
|
|
166
|
+
export function getChipColorTokens(color: RestyleColor): ChipColorTokens {
|
|
167
|
+
// Check if we have a preset for this color
|
|
168
|
+
if (color in PRESET_COLORS) {
|
|
169
|
+
return PRESET_COLORS[color];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// For any other color, use it directly with sensible defaults
|
|
173
|
+
return {
|
|
174
|
+
filled: color,
|
|
175
|
+
accent: color,
|
|
176
|
+
filledText: "textInverse",
|
|
177
|
+
accentText: color,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get text color based on variant, color, and state.
|
|
183
|
+
*
|
|
184
|
+
* | Variant | Normal | Selected | Disabled |
|
|
185
|
+
* |----------|--------------|--------------|--------------|
|
|
186
|
+
* | filled | textInverse | textInverse | textDisabled |
|
|
187
|
+
* | outlined | accent color | textInverse | textDisabled |
|
|
188
|
+
*
|
|
189
|
+
* @param variant - Visual variant
|
|
190
|
+
* @param color - Any theme color token
|
|
191
|
+
* @param selected - Whether chip is selected
|
|
192
|
+
* @param disabled - Whether chip is disabled
|
|
193
|
+
* @returns Computed text color token
|
|
194
|
+
*/
|
|
195
|
+
export function getChipTextColor(
|
|
196
|
+
variant: ChipVariant,
|
|
197
|
+
color: RestyleColor,
|
|
198
|
+
selected: boolean,
|
|
199
|
+
disabled: boolean
|
|
200
|
+
): RestyleColor {
|
|
201
|
+
if (disabled) {
|
|
202
|
+
return "textDisabled";
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const tokens = getChipColorTokens(color);
|
|
206
|
+
|
|
207
|
+
// When selected (for outlined), use filled text color
|
|
208
|
+
if (selected && variant !== "filled") {
|
|
209
|
+
return tokens.filledText;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (variant === "filled") {
|
|
213
|
+
return tokens.filledText;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return tokens.accentText;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get icon color based on variant, color, and state.
|
|
221
|
+
* Follows the same logic as text color for visual consistency.
|
|
222
|
+
*
|
|
223
|
+
* @param variant - Visual variant
|
|
224
|
+
* @param color - Any theme color token
|
|
225
|
+
* @param selected - Whether chip is selected
|
|
226
|
+
* @param disabled - Whether chip is disabled
|
|
227
|
+
* @returns Computed icon color token
|
|
228
|
+
*/
|
|
229
|
+
export function getChipIconColor(
|
|
230
|
+
variant: ChipVariant,
|
|
231
|
+
color: RestyleColor,
|
|
232
|
+
selected: boolean,
|
|
233
|
+
disabled: boolean
|
|
234
|
+
): RestyleColor {
|
|
235
|
+
return getChipTextColor(variant, color, selected, disabled);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// =============================================================================
|
|
239
|
+
// STYLE RESOLUTION
|
|
240
|
+
// =============================================================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Resolve dynamic style properties for the Chip container.
|
|
244
|
+
*
|
|
245
|
+
* Static styles (borderRadius, padding) come from theme variants.
|
|
246
|
+
* This function handles dynamic state-based values:
|
|
247
|
+
* - backgroundColor based on variant, color, and selected state
|
|
248
|
+
* - borderColor based on variant and color
|
|
249
|
+
* - opacity based on disabled state
|
|
250
|
+
*
|
|
251
|
+
* Returns token keys instead of resolved hex values to let Restyle handle resolution.
|
|
252
|
+
*
|
|
253
|
+
* @param params - Resolution parameters
|
|
254
|
+
* @returns Computed style object with token keys
|
|
255
|
+
*/
|
|
256
|
+
export function resolveChipStyle(
|
|
257
|
+
params: Omit<ResolveChipStyleParams, "theme">
|
|
258
|
+
): ChipStyleResult {
|
|
259
|
+
const { variant, color, selected, disabled } = params;
|
|
260
|
+
|
|
261
|
+
const tokens = getChipColorTokens(color);
|
|
262
|
+
|
|
263
|
+
let backgroundColor: RestyleColor | "transparent";
|
|
264
|
+
let borderColor: RestyleColor | "transparent";
|
|
265
|
+
let borderWidth: number;
|
|
266
|
+
|
|
267
|
+
if (disabled) {
|
|
268
|
+
switch (variant) {
|
|
269
|
+
case "filled":
|
|
270
|
+
backgroundColor = "interactiveDisabled";
|
|
271
|
+
borderColor = "transparent";
|
|
272
|
+
borderWidth = 0;
|
|
273
|
+
break;
|
|
274
|
+
case "outlined":
|
|
275
|
+
backgroundColor = selected ? "interactiveDisabled" : "transparent";
|
|
276
|
+
borderColor = "borderDefault";
|
|
277
|
+
borderWidth = 1;
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
backgroundColor = "interactiveDisabled";
|
|
281
|
+
borderColor = "transparent";
|
|
282
|
+
borderWidth = 0;
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
switch (variant) {
|
|
286
|
+
case "filled":
|
|
287
|
+
backgroundColor = tokens.filled;
|
|
288
|
+
borderColor = "transparent";
|
|
289
|
+
borderWidth = 0;
|
|
290
|
+
break;
|
|
291
|
+
case "outlined":
|
|
292
|
+
backgroundColor = selected ? tokens.filled : "transparent";
|
|
293
|
+
borderColor = tokens.accent;
|
|
294
|
+
borderWidth = 1;
|
|
295
|
+
break;
|
|
296
|
+
default:
|
|
297
|
+
backgroundColor = tokens.filled;
|
|
298
|
+
borderColor = "transparent";
|
|
299
|
+
borderWidth = 0;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return { backgroundColor, borderColor, borderWidth, opacity: 1 };
|
|
304
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chip Component
|
|
3
|
+
*
|
|
4
|
+
* @description Compact element for tags, filters, and selections - Atom
|
|
5
|
+
*
|
|
6
|
+
* Chip displays compact elements used for tags, categories, filters,
|
|
7
|
+
* and selection groups. Supports interactive (selectable/dismissible)
|
|
8
|
+
* and static display modes.
|
|
9
|
+
*
|
|
10
|
+
* ## Size Scale
|
|
11
|
+
* | Size | Height | Icon | Text Variant | Padding |
|
|
12
|
+
* |------|--------|-------|--------------|---------|
|
|
13
|
+
* | sm | 24px | xs | captionSmall | xs (4px)|
|
|
14
|
+
* | md | 32px | sm | labelSmall | sm (8px)|
|
|
15
|
+
* | lg | 40px | md | labelMedium | md (12px)|
|
|
16
|
+
*
|
|
17
|
+
* ## Variants
|
|
18
|
+
* - `filled`: Solid background (default)
|
|
19
|
+
* - `outlined`: Border only, transparent background
|
|
20
|
+
*
|
|
21
|
+
* ## Features
|
|
22
|
+
* - Responsive size prop (phone/tablet breakpoints)
|
|
23
|
+
* - Optional leading icon
|
|
24
|
+
* - Selectable with visual feedback
|
|
25
|
+
* - Dismissible with close button
|
|
26
|
+
* - Five color options (primary, secondary, success, warning, error)
|
|
27
|
+
* - Full accessibility support
|
|
28
|
+
* - Memoized for performance
|
|
29
|
+
*
|
|
30
|
+
* @see Chip.types.ts - Type definitions
|
|
31
|
+
* @see Chip.helpers.ts - Pure calculation functions
|
|
32
|
+
* @see Chip.a11y.ts - Accessibility prop generation
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Basic tag
|
|
36
|
+
* <Chip label="JavaScript" />
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* // Selectable chip
|
|
40
|
+
* <Chip
|
|
41
|
+
* label="Option A"
|
|
42
|
+
* onPress={() => setSelected(!selected)}
|
|
43
|
+
* selected={selected}
|
|
44
|
+
* variant="outlined"
|
|
45
|
+
* />
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Dismissible filter chip
|
|
49
|
+
* <Chip
|
|
50
|
+
* label="Category: Tech"
|
|
51
|
+
* iconName="filter-list"
|
|
52
|
+
* onDelete={() => removeFilter()}
|
|
53
|
+
* color="primary"
|
|
54
|
+
* />
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Status chip
|
|
58
|
+
* <Chip
|
|
59
|
+
* label="Active"
|
|
60
|
+
* variant="outlined"
|
|
61
|
+
* color="success"
|
|
62
|
+
* size="sm"
|
|
63
|
+
* />
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
import {
|
|
67
|
+
backgroundColor,
|
|
68
|
+
border,
|
|
69
|
+
createRestyleComponent,
|
|
70
|
+
createVariant,
|
|
71
|
+
layout,
|
|
72
|
+
spacing,
|
|
73
|
+
spacingShorthand,
|
|
74
|
+
} from "@shopify/restyle";
|
|
75
|
+
import React, { memo, useCallback } from "react";
|
|
76
|
+
import { Pressable } from "react-native";
|
|
77
|
+
import { RestyleTheme } from "../../../core/restyle";
|
|
78
|
+
import { BaseThemeColor, RestyleColor } from "../../../types";
|
|
79
|
+
import { IconButton } from "../../actions/IconButton";
|
|
80
|
+
import { Text } from "../../typography";
|
|
81
|
+
import { Icon } from "../Icon";
|
|
82
|
+
import { BaseChipProps, ChipProps } from "./Chip.types";
|
|
83
|
+
import { useChipLogic } from "./useChipLogic";
|
|
84
|
+
|
|
85
|
+
/** Narrow extended color tokens for Restyle interop (safe at runtime). */
|
|
86
|
+
const asBase = (c: RestyleColor | "transparent") => c as BaseThemeColor;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Base container with Restyle variant support.
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
const BaseChipContainer = createRestyleComponent<BaseChipProps, RestyleTheme>(
|
|
93
|
+
[
|
|
94
|
+
createVariant({ themeKey: "chipVariants" }),
|
|
95
|
+
createVariant({ themeKey: "chipSizes", property: "size" }),
|
|
96
|
+
backgroundColor,
|
|
97
|
+
border,
|
|
98
|
+
layout,
|
|
99
|
+
spacing,
|
|
100
|
+
spacingShorthand,
|
|
101
|
+
],
|
|
102
|
+
Pressable,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
function ChipComponent({
|
|
106
|
+
label,
|
|
107
|
+
onPress,
|
|
108
|
+
onDelete,
|
|
109
|
+
variant = "filled",
|
|
110
|
+
size = "md",
|
|
111
|
+
color = "accentPrimary",
|
|
112
|
+
selected = false,
|
|
113
|
+
disabled = false,
|
|
114
|
+
iconName,
|
|
115
|
+
testID,
|
|
116
|
+
accessibilityHint,
|
|
117
|
+
accessibilityLabel,
|
|
118
|
+
style,
|
|
119
|
+
...rest
|
|
120
|
+
}: ChipProps) {
|
|
121
|
+
const {
|
|
122
|
+
themeVariantKey,
|
|
123
|
+
textVariant,
|
|
124
|
+
textColor,
|
|
125
|
+
iconSize,
|
|
126
|
+
iconColor,
|
|
127
|
+
containerStyle,
|
|
128
|
+
a11yProps,
|
|
129
|
+
isInteractive,
|
|
130
|
+
showDeleteIcon,
|
|
131
|
+
deleteIconColor,
|
|
132
|
+
deleteHint,
|
|
133
|
+
} = useChipLogic({
|
|
134
|
+
label,
|
|
135
|
+
variant,
|
|
136
|
+
size,
|
|
137
|
+
color,
|
|
138
|
+
selected,
|
|
139
|
+
disabled,
|
|
140
|
+
onPress,
|
|
141
|
+
onDelete,
|
|
142
|
+
accessibilityLabel,
|
|
143
|
+
accessibilityHint,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const handlePress = useCallback(() => {
|
|
147
|
+
if (!disabled && onPress) {
|
|
148
|
+
onPress();
|
|
149
|
+
}
|
|
150
|
+
}, [disabled, onPress]);
|
|
151
|
+
|
|
152
|
+
const handleDelete = useCallback(() => {
|
|
153
|
+
if (!disabled && onDelete) {
|
|
154
|
+
onDelete();
|
|
155
|
+
}
|
|
156
|
+
}, [disabled, onDelete]);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<BaseChipContainer
|
|
160
|
+
variant={themeVariantKey}
|
|
161
|
+
size={size}
|
|
162
|
+
onPress={isInteractive ? handlePress : undefined}
|
|
163
|
+
disabled={disabled}
|
|
164
|
+
testID={testID}
|
|
165
|
+
flexDirection="row"
|
|
166
|
+
alignItems="center"
|
|
167
|
+
justifyContent="center"
|
|
168
|
+
gap="xs"
|
|
169
|
+
backgroundColor={asBase(containerStyle.backgroundColor)}
|
|
170
|
+
borderColor={asBase(containerStyle.borderColor)}
|
|
171
|
+
borderWidth={containerStyle.borderWidth}
|
|
172
|
+
opacity={containerStyle.opacity}
|
|
173
|
+
style={style}
|
|
174
|
+
{...a11yProps}
|
|
175
|
+
{...rest}
|
|
176
|
+
>
|
|
177
|
+
{iconName && (
|
|
178
|
+
<Icon
|
|
179
|
+
name={iconName}
|
|
180
|
+
size={iconSize}
|
|
181
|
+
color={asBase(iconColor)}
|
|
182
|
+
accessibilityLabel={iconName}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
<Text variant={textVariant} color={asBase(textColor)}>
|
|
186
|
+
{label}
|
|
187
|
+
</Text>
|
|
188
|
+
{showDeleteIcon && (
|
|
189
|
+
<IconButton
|
|
190
|
+
iconName="close"
|
|
191
|
+
onPress={handleDelete}
|
|
192
|
+
variant="ghost"
|
|
193
|
+
size="sm"
|
|
194
|
+
disabled={disabled}
|
|
195
|
+
color={asBase(deleteIconColor)}
|
|
196
|
+
accessibilityLabel={`Remove ${label}`}
|
|
197
|
+
accessibilityHint={deleteHint}
|
|
198
|
+
/>
|
|
199
|
+
)}
|
|
200
|
+
</BaseChipContainer>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const Chip = memo(ChipComponent);
|
|
205
|
+
Chip.displayName = "Chip";
|